|
Blender
V2.59
|
00001 /* 00002 * $Id: drawgpencil.c 36811 2011-05-21 08:56:37Z campbellbarton $ 00003 * 00004 * ***** BEGIN GPL LICENSE BLOCK ***** 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software Foundation, 00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 * 00020 * The Original Code is Copyright (C) 2008, Blender Foundation 00021 * This is a new part of Blender 00022 * 00023 * Contributor(s): Joshua Leung 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 */ 00027 00033 #include <stdio.h> 00034 #include <string.h> 00035 #include <stdlib.h> 00036 #include <stddef.h> 00037 #include <math.h> 00038 #include <float.h> 00039 00040 #include "BLO_sys_types.h" 00041 00042 #include "IMB_imbuf_types.h" 00043 00044 #include "BLI_math.h" 00045 #include "BLI_blenlib.h" 00046 #include "BLI_utildefines.h" 00047 00048 #include "DNA_gpencil_types.h" 00049 #include "DNA_scene_types.h" 00050 #include "DNA_screen_types.h" 00051 #include "DNA_space_types.h" 00052 #include "DNA_view3d_types.h" 00053 00054 #include "BKE_context.h" 00055 #include "BKE_global.h" 00056 #include "BKE_gpencil.h" 00057 00058 00059 00060 #include "WM_api.h" 00061 00062 #include "BIF_gl.h" 00063 #include "BIF_glutil.h" 00064 00065 #include "ED_gpencil.h" 00066 #include "ED_sequencer.h" 00067 #include "ED_view3d.h" 00068 00069 00070 #include "gpencil_intern.h" 00071 00072 /* ************************************************** */ 00073 /* GREASE PENCIL DRAWING */ 00074 00075 /* ----- General Defines ------ */ 00076 00077 /* flags for sflag */ 00078 typedef enum eDrawStrokeFlags { 00079 GP_DRAWDATA_NOSTATUS = (1<<0), /* don't draw status info */ 00080 GP_DRAWDATA_ONLY3D = (1<<1), /* only draw 3d-strokes */ 00081 GP_DRAWDATA_ONLYV2D = (1<<2), /* only draw 'canvas' strokes */ 00082 GP_DRAWDATA_ONLYI2D = (1<<3), /* only draw 'image' strokes */ 00083 GP_DRAWDATA_IEDITHACK = (1<<4), /* special hack for drawing strokes in Image Editor (weird coordinates) */ 00084 GP_DRAWDATA_NO_XRAY = (1<<5), /* dont draw xray in 3D view (which is default) */ 00085 } eDrawStrokeFlags; 00086 00087 00088 00089 /* thickness above which we should use special drawing */ 00090 #define GP_DRAWTHICKNESS_SPECIAL 3 00091 00092 /* ----- Tool Buffer Drawing ------ */ 00093 00094 /* draw stroke defined in buffer (simple ogl lines/points for now, as dotted lines) */ 00095 static void gp_draw_stroke_buffer (tGPspoint *points, int totpoints, short thickness, short dflag, short sflag) 00096 { 00097 tGPspoint *pt; 00098 int i; 00099 00100 /* error checking */ 00101 if ((points == NULL) || (totpoints <= 0)) 00102 return; 00103 00104 /* check if buffer can be drawn */ 00105 if (dflag & (GP_DRAWDATA_ONLY3D|GP_DRAWDATA_ONLYV2D)) 00106 return; 00107 00108 /* if drawing a single point, draw it larger */ 00109 if (totpoints == 1) { 00110 /* draw point */ 00111 glBegin(GL_POINTS); 00112 glVertex2f(points->x, points->y); 00113 glEnd(); 00114 } 00115 else if (sflag & GP_STROKE_ERASER) { 00116 /* don't draw stroke at all! */ 00117 } 00118 else { 00119 float oldpressure = 0.0f; 00120 00121 /* draw stroke curve */ 00122 if (G.f & G_DEBUG) setlinestyle(2); 00123 00124 glBegin(GL_LINE_STRIP); 00125 for (i=0, pt=points; i < totpoints && pt; i++, pt++) { 00126 /* if there was a significant pressure change, stop the curve, change the thickness of the stroke, 00127 * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP) 00128 */ 00129 if (fabsf(pt->pressure - oldpressure) > 0.2f) { 00130 glEnd(); 00131 glLineWidth(pt->pressure * thickness); 00132 glBegin(GL_LINE_STRIP); 00133 00134 /* need to roll-back one point to ensure that there are no gaps in the stroke */ 00135 if (i != 0) { 00136 pt--; 00137 glVertex2f(pt->x, pt->y); 00138 pt++; 00139 } 00140 /* now the point we want... */ 00141 glVertex2f(pt->x, pt->y); 00142 00143 oldpressure = pt->pressure; 00144 } 00145 else 00146 glVertex2f(pt->x, pt->y); 00147 } 00148 glEnd(); 00149 00150 if (G.f & G_DEBUG) setlinestyle(0); 00151 } 00152 } 00153 00154 /* ----- Existing Strokes Drawing (3D and Point) ------ */ 00155 00156 /* draw a given stroke - just a single dot (only one point) */ 00157 static void gp_draw_stroke_point (bGPDspoint *points, short thickness, short dflag, short sflag, int offsx, int offsy, int winx, int winy) 00158 { 00159 /* draw point */ 00160 if (sflag & GP_STROKE_3DSPACE) { 00161 glBegin(GL_POINTS); 00162 glVertex3f(points->x, points->y, points->z); 00163 glEnd(); 00164 } 00165 else { 00166 float co[2]; 00167 00168 /* get coordinates of point */ 00169 if (sflag & GP_STROKE_2DSPACE) { 00170 co[0]= points->x; 00171 co[1]= points->y; 00172 } 00173 else if (sflag & GP_STROKE_2DIMAGE) { 00174 co[0]= (points->x * winx) + offsx; 00175 co[1]= (points->y * winy) + offsy; 00176 } 00177 else { 00178 co[0]= (points->x / 100 * winx) + offsx; 00179 co[1]= (points->y / 100 * winy) + offsy; 00180 } 00181 00182 /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, simple dot looks ok 00183 * - also mandatory in if Image Editor 'image-based' dot 00184 */ 00185 if ( (thickness < GP_DRAWTHICKNESS_SPECIAL) || 00186 ((dflag & GP_DRAWDATA_IEDITHACK) && (sflag & GP_STROKE_2DSPACE)) ) 00187 { 00188 glBegin(GL_POINTS); 00189 glVertex2fv(co); 00190 glEnd(); 00191 } 00192 else 00193 { 00194 /* draw filled circle as is done in circf (but without the matrix push/pops which screwed things up) */ 00195 GLUquadricObj *qobj = gluNewQuadric(); 00196 00197 gluQuadricDrawStyle(qobj, GLU_FILL); 00198 00199 /* need to translate drawing position, but must reset after too! */ 00200 glTranslatef(co[0], co[1], 0.); 00201 gluDisk(qobj, 0.0, thickness, 32, 1); 00202 glTranslatef(-co[0], -co[1], 0.); 00203 00204 gluDeleteQuadric(qobj); 00205 } 00206 } 00207 } 00208 00209 /* draw a given stroke in 3d (i.e. in 3d-space), using simple ogl lines */ 00210 static void gp_draw_stroke_3d (bGPDspoint *points, int totpoints, short thickness, short debug) 00211 { 00212 bGPDspoint *pt; 00213 float oldpressure = 0.0f; 00214 int i; 00215 00216 /* draw stroke curve */ 00217 glBegin(GL_LINE_STRIP); 00218 for (i=0, pt=points; i < totpoints && pt; i++, pt++) { 00219 /* if there was a significant pressure change, stop the curve, change the thickness of the stroke, 00220 * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP) 00221 */ 00222 if (fabsf(pt->pressure - oldpressure) > 0.2f) { 00223 glEnd(); 00224 glLineWidth(pt->pressure * thickness); 00225 glBegin(GL_LINE_STRIP); 00226 00227 /* need to roll-back one point to ensure that there are no gaps in the stroke */ 00228 if (i != 0) { 00229 pt--; 00230 glVertex3f(pt->x, pt->y, pt->z); 00231 pt++; 00232 } 00233 /* now the point we want... */ 00234 glVertex3f(pt->x, pt->y, pt->z); 00235 00236 oldpressure = pt->pressure; 00237 } 00238 else 00239 glVertex3f(pt->x, pt->y, pt->z); 00240 } 00241 glEnd(); 00242 00243 /* draw debug points of curve on top? */ 00244 if (debug) { 00245 glBegin(GL_POINTS); 00246 for (i=0, pt=points; i < totpoints && pt; i++, pt++) 00247 glVertex3f(pt->x, pt->y, pt->z); 00248 glEnd(); 00249 } 00250 } 00251 00252 /* ----- Fancy 2D-Stroke Drawing ------ */ 00253 00254 /* draw a given stroke in 2d */ 00255 static void gp_draw_stroke (bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag, 00256 short debug, int offsx, int offsy, int winx, int winy) 00257 { 00258 /* otherwise thickness is twice that of the 3D view */ 00259 float thickness= (float)thickness_s * 0.5f; 00260 00261 /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, 'smooth' opengl lines look better 00262 * - 'smooth' opengl lines are also required if Image Editor 'image-based' stroke 00263 */ 00264 if ( (thickness < GP_DRAWTHICKNESS_SPECIAL) || 00265 ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) ) 00266 { 00267 bGPDspoint *pt; 00268 int i; 00269 00270 glBegin(GL_LINE_STRIP); 00271 for (i=0, pt=points; i < totpoints && pt; i++, pt++) { 00272 if (sflag & GP_STROKE_2DSPACE) { 00273 glVertex2f(pt->x, pt->y); 00274 } 00275 else if (sflag & GP_STROKE_2DIMAGE) { 00276 const float x= (pt->x * winx) + offsx; 00277 const float y= (pt->y * winy) + offsy; 00278 00279 glVertex2f(x, y); 00280 } 00281 else { 00282 const float x= (pt->x / 100 * winx) + offsx; 00283 const float y= (pt->y / 100 * winy) + offsy; 00284 00285 glVertex2f(x, y); 00286 } 00287 } 00288 glEnd(); 00289 } 00290 00291 /* tesselation code - draw stroke as series of connected quads with connection 00292 * edges rotated to minimise shrinking artifacts, and rounded endcaps 00293 */ 00294 else 00295 { 00296 bGPDspoint *pt1, *pt2; 00297 float pm[2]; 00298 int i; 00299 00300 glShadeModel(GL_FLAT); 00301 glBegin(GL_QUADS); 00302 00303 for (i=0, pt1=points, pt2=points+1; i < (totpoints-1); i++, pt1++, pt2++) { 00304 float s0[2], s1[2]; /* segment 'center' points */ 00305 float t0[2], t1[2]; /* tesselated coordinates */ 00306 float m1[2], m2[2]; /* gradient and normal */ 00307 float mt[2], sc[2]; /* gradient for thickness, point for end-cap */ 00308 float pthick; /* thickness at segment point */ 00309 00310 /* get x and y coordinates from points */ 00311 if (sflag & GP_STROKE_2DSPACE) { 00312 s0[0]= pt1->x; s0[1]= pt1->y; 00313 s1[0]= pt2->x; s1[1]= pt2->y; 00314 } 00315 else if (sflag & GP_STROKE_2DIMAGE) { 00316 s0[0]= (pt1->x * winx) + offsx; 00317 s0[1]= (pt1->y * winy) + offsy; 00318 s1[0]= (pt2->x * winx) + offsx; 00319 s1[1]= (pt2->y * winy) + offsy; 00320 } 00321 else { 00322 s0[0]= (pt1->x / 100 * winx) + offsx; 00323 s0[1]= (pt1->y / 100 * winy) + offsy; 00324 s1[0]= (pt2->x / 100 * winx) + offsx; 00325 s1[1]= (pt2->y / 100 * winy) + offsy; 00326 } 00327 00328 /* calculate gradient and normal - 'angle'=(ny/nx) */ 00329 m1[1]= s1[1] - s0[1]; 00330 m1[0]= s1[0] - s0[0]; 00331 normalize_v2(m1); 00332 m2[1]= -m1[0]; 00333 m2[0]= m1[1]; 00334 00335 /* always use pressure from first point here */ 00336 pthick= (pt1->pressure * thickness); 00337 00338 /* if the first segment, start of segment is segment's normal */ 00339 if (i == 0) { 00340 /* draw start cap first 00341 * - make points slightly closer to center (about halfway across) 00342 */ 00343 mt[0]= m2[0] * pthick * 0.5f; 00344 mt[1]= m2[1] * pthick * 0.5f; 00345 sc[0]= s0[0] - (m1[0] * pthick * 0.75f); 00346 sc[1]= s0[1] - (m1[1] * pthick * 0.75f); 00347 00348 t0[0]= sc[0] - mt[0]; 00349 t0[1]= sc[1] - mt[1]; 00350 t1[0]= sc[0] + mt[0]; 00351 t1[1]= sc[1] + mt[1]; 00352 00353 glVertex2fv(t0); 00354 glVertex2fv(t1); 00355 00356 /* calculate points for start of segment */ 00357 mt[0]= m2[0] * pthick; 00358 mt[1]= m2[1] * pthick; 00359 00360 t0[0]= s0[0] - mt[0]; 00361 t0[1]= s0[1] - mt[1]; 00362 t1[0]= s0[0] + mt[0]; 00363 t1[1]= s0[1] + mt[1]; 00364 00365 /* draw this line twice (first to finish off start cap, then for stroke) */ 00366 glVertex2fv(t1); 00367 glVertex2fv(t0); 00368 glVertex2fv(t0); 00369 glVertex2fv(t1); 00370 } 00371 /* if not the first segment, use bisector of angle between segments */ 00372 else { 00373 float mb[2]; /* bisector normal */ 00374 float athick, dfac; /* actual thickness, difference between thicknesses */ 00375 00376 /* calculate gradient of bisector (as average of normals) */ 00377 mb[0]= (pm[0] + m2[0]) / 2; 00378 mb[1]= (pm[1] + m2[1]) / 2; 00379 normalize_v2(mb); 00380 00381 /* calculate gradient to apply 00382 * - as basis, use just pthick * bisector gradient 00383 * - if cross-section not as thick as it should be, add extra padding to fix it 00384 */ 00385 mt[0]= mb[0] * pthick; 00386 mt[1]= mb[1] * pthick; 00387 athick= len_v2(mt); 00388 dfac= pthick - (athick * 2); 00389 if ( ((athick * 2.0f) < pthick) && (IS_EQF(athick, pthick)==0) ) 00390 { 00391 mt[0] += (mb[0] * dfac); 00392 mt[1] += (mb[1] * dfac); 00393 } 00394 00395 /* calculate points for start of segment */ 00396 t0[0]= s0[0] - mt[0]; 00397 t0[1]= s0[1] - mt[1]; 00398 t1[0]= s0[0] + mt[0]; 00399 t1[1]= s0[1] + mt[1]; 00400 00401 /* draw this line twice (once for end of current segment, and once for start of next) */ 00402 glVertex2fv(t1); 00403 glVertex2fv(t0); 00404 glVertex2fv(t0); 00405 glVertex2fv(t1); 00406 } 00407 00408 /* if last segment, also draw end of segment (defined as segment's normal) */ 00409 if (i == totpoints-2) { 00410 /* for once, we use second point's pressure (otherwise it won't be drawn) */ 00411 pthick= (pt2->pressure * thickness); 00412 00413 /* calculate points for end of segment */ 00414 mt[0]= m2[0] * pthick; 00415 mt[1]= m2[1] * pthick; 00416 00417 t0[0]= s1[0] - mt[0]; 00418 t0[1]= s1[1] - mt[1]; 00419 t1[0]= s1[0] + mt[0]; 00420 t1[1]= s1[1] + mt[1]; 00421 00422 /* draw this line twice (once for end of stroke, and once for endcap)*/ 00423 glVertex2fv(t1); 00424 glVertex2fv(t0); 00425 glVertex2fv(t0); 00426 glVertex2fv(t1); 00427 00428 00429 /* draw end cap as last step 00430 * - make points slightly closer to center (about halfway across) 00431 */ 00432 mt[0]= m2[0] * pthick * 0.5f; 00433 mt[1]= m2[1] * pthick * 0.5f; 00434 sc[0]= s1[0] + (m1[0] * pthick * 0.75f); 00435 sc[1]= s1[1] + (m1[1] * pthick * 0.75f); 00436 00437 t0[0]= sc[0] - mt[0]; 00438 t0[1]= sc[1] - mt[1]; 00439 t1[0]= sc[0] + mt[0]; 00440 t1[1]= sc[1] + mt[1]; 00441 00442 glVertex2fv(t1); 00443 glVertex2fv(t0); 00444 } 00445 00446 /* store stroke's 'natural' normal for next stroke to use */ 00447 copy_v2_v2(pm, m2); 00448 } 00449 00450 glEnd(); 00451 } 00452 00453 /* draw debug points of curve on top? (original stroke points) */ 00454 if (debug) { 00455 bGPDspoint *pt; 00456 int i; 00457 00458 glBegin(GL_POINTS); 00459 for (i=0, pt=points; i < totpoints && pt; i++, pt++) { 00460 if (sflag & GP_STROKE_2DSPACE) { 00461 glVertex2f(pt->x, pt->y); 00462 } 00463 else if (sflag & GP_STROKE_2DIMAGE) { 00464 const float x= (float)((pt->x * winx) + offsx); 00465 const float y= (float)((pt->y * winy) + offsy); 00466 00467 glVertex2f(x, y); 00468 } 00469 else { 00470 const float x= (float)(pt->x / 100 * winx) + offsx; 00471 const float y= (float)(pt->y / 100 * winy) + offsy; 00472 00473 glVertex2f(x, y); 00474 } 00475 } 00476 glEnd(); 00477 } 00478 } 00479 00480 /* ----- General Drawing ------ */ 00481 00482 /* draw a set of strokes */ 00483 static void gp_draw_strokes (bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag, 00484 short debug, short lthick, float color[4]) 00485 { 00486 bGPDstroke *gps; 00487 00488 /* set color first (may need to reset it again later too) */ 00489 glColor4fv(color); 00490 00491 for (gps= gpf->strokes.first; gps; gps= gps->next) { 00492 /* check if stroke can be drawn - checks here generally fall into pairs */ 00493 if ((dflag & GP_DRAWDATA_ONLY3D) && !(gps->flag & GP_STROKE_3DSPACE)) 00494 continue; 00495 if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE)) 00496 continue; 00497 if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE)) 00498 continue; 00499 if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE)) 00500 continue; 00501 if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE)) 00502 continue; 00503 if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE)) 00504 continue; 00505 if ((gps->points == NULL) || (gps->totpoints < 1)) 00506 continue; 00507 00508 /* check which stroke-drawer to use */ 00509 if (gps->totpoints == 1) 00510 gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy); 00511 else if (dflag & GP_DRAWDATA_ONLY3D) { 00512 const int no_xray= (dflag & GP_DRAWDATA_NO_XRAY); 00513 int mask_orig = 0; 00514 00515 if (no_xray) { 00516 glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig); 00517 glDepthMask(0); 00518 glEnable(GL_DEPTH_TEST); 00519 00520 /* first arg is normally rv3d->dist, but this isnt available here and seems to work quite well without */ 00521 bglPolygonOffset(1.0f, 1.0f); 00522 /* 00523 glEnable(GL_POLYGON_OFFSET_LINE); 00524 glPolygonOffset(-1.0f, -1.0f); 00525 */ 00526 } 00527 00528 gp_draw_stroke_3d(gps->points, gps->totpoints, lthick, debug); 00529 00530 if (no_xray) { 00531 glDepthMask(mask_orig); 00532 glDisable(GL_DEPTH_TEST); 00533 00534 bglPolygonOffset(0.0, 0.0); 00535 /* 00536 glDisable(GL_POLYGON_OFFSET_LINE); 00537 glPolygonOffset(0, 0); 00538 */ 00539 } 00540 } 00541 else if (gps->totpoints > 1) 00542 gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, offsx, offsy, winx, winy); 00543 } 00544 } 00545 00546 /* draw grease-pencil datablock */ 00547 static void gp_draw_data (bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag) 00548 { 00549 bGPDlayer *gpl; 00550 00551 /* reset line drawing style (in case previous user didn't reset) */ 00552 setlinestyle(0); 00553 00554 /* turn on smooth lines (i.e. anti-aliasing) */ 00555 glEnable(GL_LINE_SMOOTH); 00556 00557 /* turn on alpha-blending */ 00558 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 00559 glEnable(GL_BLEND); 00560 00561 /* loop over layers, drawing them */ 00562 for (gpl= gpd->layers.first; gpl; gpl= gpl->next) { 00563 bGPDframe *gpf; 00564 00565 short debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? 1 : 0; 00566 short lthick= gpl->thickness; 00567 float color[4], tcolor[4]; 00568 00569 /* don't draw layer if hidden */ 00570 if (gpl->flag & GP_LAYER_HIDE) 00571 continue; 00572 00573 /* get frame to draw */ 00574 gpf= gpencil_layer_getframe(gpl, cfra, 0); 00575 if (gpf == NULL) 00576 continue; 00577 00578 /* set color, stroke thickness, and point size */ 00579 glLineWidth(lthick); 00580 QUATCOPY(color, gpl->color); // just for copying 4 array elements 00581 QUATCOPY(tcolor, gpl->color); // additional copy of color (for ghosting) 00582 glColor4fv(color); 00583 glPointSize((float)(gpl->thickness + 2)); 00584 00585 /* apply xray layer setting */ 00586 if (gpl->flag & GP_LAYER_NO_XRAY) dflag |= GP_DRAWDATA_NO_XRAY; 00587 else dflag &= ~GP_DRAWDATA_NO_XRAY; 00588 00589 /* draw 'onionskins' (frame left + right) */ 00590 if (gpl->flag & GP_LAYER_ONIONSKIN) { 00591 /* drawing method - only immediately surrounding (gstep = 0), or within a frame range on either side (gstep > 0)*/ 00592 if (gpl->gstep) { 00593 bGPDframe *gf; 00594 float fac; 00595 00596 /* draw previous frames first */ 00597 for (gf=gpf->prev; gf; gf=gf->prev) { 00598 /* check if frame is drawable */ 00599 if ((gpf->framenum - gf->framenum) <= gpl->gstep) { 00600 /* alpha decreases with distance from curframe index */ 00601 fac= 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1)); 00602 tcolor[3] = color[3] * fac * 0.66f; 00603 gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor); 00604 } 00605 else 00606 break; 00607 } 00608 00609 /* now draw next frames */ 00610 for (gf= gpf->next; gf; gf=gf->next) { 00611 /* check if frame is drawable */ 00612 if ((gf->framenum - gpf->framenum) <= gpl->gstep) { 00613 /* alpha decreases with distance from curframe index */ 00614 fac= 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep + 1)); 00615 tcolor[3] = color[3] * fac * 0.66f; 00616 gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor); 00617 } 00618 else 00619 break; 00620 } 00621 00622 /* restore alpha */ 00623 glColor4fv(color); 00624 } 00625 else { 00626 /* draw the strokes for the ghost frames (at half of the alpha set by user) */ 00627 if (gpf->prev) { 00628 tcolor[3] = (color[3] / 7); 00629 gp_draw_strokes(gpf->prev, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor); 00630 } 00631 00632 if (gpf->next) { 00633 tcolor[3] = (color[3] / 4); 00634 gp_draw_strokes(gpf->next, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor); 00635 } 00636 00637 /* restore alpha */ 00638 glColor4fv(color); 00639 } 00640 } 00641 00642 /* draw the strokes already in active frame */ 00643 tcolor[3]= color[3]; 00644 gp_draw_strokes(gpf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor); 00645 00646 /* Check if may need to draw the active stroke cache, only if this layer is the active layer 00647 * that is being edited. (Stroke buffer is currently stored in gp-data) 00648 */ 00649 if ((G.f & G_GREASEPENCIL) && (gpl->flag & GP_LAYER_ACTIVE) && 00650 (gpf->flag & GP_FRAME_PAINT)) 00651 { 00652 /* Buffer stroke needs to be drawn with a different linestyle to help differentiate them from normal strokes. */ 00653 gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag); 00654 } 00655 } 00656 00657 /* turn off alpha blending, then smooth lines */ 00658 glDisable(GL_BLEND); // alpha blending 00659 glDisable(GL_LINE_SMOOTH); // smooth lines 00660 00661 /* restore initial gl conditions */ 00662 glLineWidth(1.0); 00663 glPointSize(1.0); 00664 glColor4f(0, 0, 0, 1); 00665 } 00666 00667 /* ----- Grease Pencil Sketches Drawing API ------ */ 00668 00669 // ............................ 00670 // XXX 00671 // We need to review the calls below, since they may be/are not that suitable for 00672 // the new ways that we intend to be drawing data... 00673 // ............................ 00674 00675 /* draw grease-pencil sketches to specified 2d-view that uses ibuf corrections */ 00676 void draw_gpencil_2dimage (bContext *C, ImBuf *ibuf) 00677 { 00678 ScrArea *sa= CTX_wm_area(C); 00679 ARegion *ar= CTX_wm_region(C); 00680 Scene *scene= CTX_data_scene(C); 00681 bGPdata *gpd; 00682 int offsx, offsy, sizex, sizey; 00683 int dflag = GP_DRAWDATA_NOSTATUS; 00684 00685 /* check that we have grease-pencil stuff to draw */ 00686 if (ELEM(NULL, sa, ibuf)) return; 00687 gpd= gpencil_data_get_active(C); // XXX 00688 if (gpd == NULL) return; 00689 00690 /* calculate rect */ 00691 switch (sa->spacetype) { 00692 case SPACE_IMAGE: /* image */ 00693 { 00694 00695 /* just draw using standard scaling (settings here are currently ignored anyways) */ 00696 // FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled 00697 offsx= 0; 00698 offsy= 0; 00699 sizex= ar->winx; 00700 sizey= ar->winy; 00701 00702 wmOrtho2(ar->v2d.cur.xmin, ar->v2d.cur.xmax, ar->v2d.cur.ymin, ar->v2d.cur.ymax); 00703 00704 dflag |= GP_DRAWDATA_ONLYV2D|GP_DRAWDATA_IEDITHACK; 00705 } 00706 break; 00707 00708 case SPACE_SEQ: /* sequence */ 00709 { 00710 SpaceSeq *sseq= (SpaceSeq *)sa->spacedata.first; 00711 float zoom, zoomx, zoomy; 00712 00713 /* calculate accessory values */ 00714 zoom= (float)(SEQ_ZOOM_FAC(sseq->zoom)); 00715 if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) { 00716 /* XXX sequencer zoom should store it? */ 00717 zoomx = zoom; // * (G.scene->r.xasp / G.scene->r.yasp); 00718 zoomy = zoom; 00719 } 00720 else 00721 zoomx = zoomy = zoom; 00722 00723 /* calculate transforms (Note: we use ibuf here, as we have it) */ 00724 sizex= (int)(zoomx * ibuf->x); 00725 sizey= (int)(zoomy * ibuf->y); 00726 offsx= (int)( (ar->winx-sizex)/2 + sseq->xof ); 00727 offsy= (int)( (ar->winy-sizey)/2 + sseq->yof ); 00728 00729 dflag |= GP_DRAWDATA_ONLYI2D; 00730 } 00731 break; 00732 00733 default: /* for spacetype not yet handled */ 00734 offsx= 0; 00735 offsy= 0; 00736 sizex= ar->winx; 00737 sizey= ar->winy; 00738 00739 dflag |= GP_DRAWDATA_ONLYI2D; 00740 break; 00741 } 00742 00743 00744 /* draw it! */ 00745 gp_draw_data(gpd, offsx, offsy, sizex, sizey, CFRA, dflag); 00746 } 00747 00748 /* draw grease-pencil sketches to specified 2d-view assuming that matrices are already set correctly 00749 * Note: this gets called twice - first time with onlyv2d=1 to draw 'canvas' strokes, second time with onlyv2d=0 for screen-aligned strokes 00750 */ 00751 void draw_gpencil_view2d (bContext *C, short onlyv2d) 00752 { 00753 ScrArea *sa= CTX_wm_area(C); 00754 ARegion *ar= CTX_wm_region(C); 00755 Scene *scene= CTX_data_scene(C); 00756 bGPdata *gpd; 00757 int dflag = 0; 00758 00759 /* check that we have grease-pencil stuff to draw */ 00760 if (sa == NULL) return; 00761 gpd= gpencil_data_get_active(C); // XXX 00762 if (gpd == NULL) return; 00763 00764 /* special hack for Image Editor */ 00765 // FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled 00766 if (sa->spacetype == SPACE_IMAGE) 00767 dflag |= GP_DRAWDATA_IEDITHACK; 00768 00769 /* draw it! */ 00770 if (onlyv2d) dflag |= (GP_DRAWDATA_ONLYV2D|GP_DRAWDATA_NOSTATUS); 00771 gp_draw_data(gpd, 0, 0, ar->winx, ar->winy, CFRA, dflag); 00772 } 00773 00774 /* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly 00775 * Note: this gets called twice - first time with only3d=1 to draw 3d-strokes, second time with only3d=0 for screen-aligned strokes 00776 */ 00777 00778 void draw_gpencil_view3d_ext (Scene *scene, View3D *v3d, ARegion *ar, short only3d) 00779 { 00780 bGPdata *gpd; 00781 int dflag = 0; 00782 rcti rect; 00783 RegionView3D *rv3d= ar->regiondata; 00784 00785 /* check that we have grease-pencil stuff to draw */ 00786 gpd= gpencil_data_get_active_v3d(scene); // XXX 00787 if (gpd == NULL) return; 00788 00789 /* when rendering to the offscreen buffer we dont want to 00790 * deal with the camera border, otherwise map the coords to the camera border. */ 00791 if ((rv3d->persp == RV3D_CAMOB) && !(G.f & G_RENDER_OGL)) { 00792 rctf rectf; 00793 ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &rectf, -1); /* negative shift */ 00794 BLI_copy_rcti_rctf(&rect, &rectf); 00795 } 00796 else { 00797 rect.xmin= 0; 00798 rect.ymin= 0; 00799 rect.xmax= ar->winx; 00800 rect.ymax= ar->winy; 00801 } 00802 00803 /* draw it! */ 00804 if (only3d) dflag |= (GP_DRAWDATA_ONLY3D|GP_DRAWDATA_NOSTATUS); 00805 00806 gp_draw_data(gpd, rect.xmin, rect.ymin, rect.xmax, rect.ymax, CFRA, dflag); 00807 } 00808 00809 void draw_gpencil_view3d (bContext *C, short only3d) 00810 { 00811 ARegion *ar= CTX_wm_region(C); 00812 View3D *v3d= CTX_wm_view3d(C); 00813 Scene *scene= CTX_data_scene(C); 00814 draw_gpencil_view3d_ext(scene, v3d, ar, only3d); 00815 } 00816 00817 /* ************************************************** */