Grease Pencil - Storyboarding Features (merge from GPencil_EditStrokes branch)
[blender.git] / source / blender / editors / gpencil / drawgpencil.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008, Blender Foundation
19  * This is a new part of Blender
20  *
21  * Contributor(s): Joshua Leung
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/gpencil/drawgpencil.c
27  *  \ingroup edgpencil
28  */
29
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <stddef.h>
34 #include <math.h>
35 #include <float.h>
36
37 #include "BLI_sys_types.h"
38
39 #include "BLI_math.h"
40 #include "BLI_utildefines.h"
41
42 #include "DNA_gpencil_types.h"
43 #include "DNA_scene_types.h"
44 #include "DNA_screen_types.h"
45 #include "DNA_space_types.h"
46 #include "DNA_view3d_types.h"
47 #include "DNA_userdef_types.h"
48
49 #include "BKE_context.h"
50 #include "BKE_global.h"
51 #include "BKE_gpencil.h"
52
53 #include "WM_api.h"
54
55 #include "BIF_gl.h"
56 #include "BIF_glutil.h"
57
58 #include "ED_gpencil.h"
59 #include "ED_view3d.h"
60
61 #include "UI_resources.h"
62
63 #include "gpencil_intern.h"
64
65 /* ************************************************** */
66 /* GREASE PENCIL DRAWING */
67
68 /* ----- General Defines ------ */
69
70 /* flags for sflag */
71 typedef enum eDrawStrokeFlags {
72         GP_DRAWDATA_NOSTATUS    = (1 << 0),   /* don't draw status info */
73         GP_DRAWDATA_ONLY3D      = (1 << 1),   /* only draw 3d-strokes */
74         GP_DRAWDATA_ONLYV2D     = (1 << 2),   /* only draw 'canvas' strokes */
75         GP_DRAWDATA_ONLYI2D     = (1 << 3),   /* only draw 'image' strokes */
76         GP_DRAWDATA_IEDITHACK   = (1 << 4),   /* special hack for drawing strokes in Image Editor (weird coordinates) */
77         GP_DRAWDATA_NO_XRAY     = (1 << 5),   /* don't draw xray in 3D view (which is default) */
78         GP_DRAWDATA_NO_ONIONS   = (1 << 6),       /* no onionskins should be drawn (for animation playback) */
79         GP_DRAWDATA_VOLUMETRIC  = (1 << 7),   /* draw strokes as "volumetric" circular billboards */
80         GP_DRAWDATA_FILL        = (1 << 8),   /* fill insides/bounded-regions of strokes */
81 } eDrawStrokeFlags;
82
83
84
85 /* thickness above which we should use special drawing */
86 #define GP_DRAWTHICKNESS_SPECIAL    3
87
88 /* ----- Tool Buffer Drawing ------ */
89
90 /* draw stroke defined in buffer (simple ogl lines/points for now, as dotted lines) */
91 static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickness, short dflag, short sflag)
92 {
93         tGPspoint *pt;
94         int i;
95         
96         /* error checking */
97         if ((points == NULL) || (totpoints <= 0))
98                 return;
99         
100         /* check if buffer can be drawn */
101         if (dflag & (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_ONLYV2D))
102                 return;
103         
104         /* if drawing a single point, draw it larger */
105         if (totpoints == 1) {
106                 /* draw point */
107                 glBegin(GL_POINTS);
108                 glVertex2iv(&points->x);
109                 glEnd();
110         }
111         else if (sflag & GP_STROKE_ERASER) {
112                 /* don't draw stroke at all! */
113         }
114         else {
115                 float oldpressure = points[0].pressure;
116                 
117                 /* draw stroke curve */
118                 if (G.debug & G_DEBUG) setlinestyle(2);
119
120                 glLineWidth(oldpressure * thickness);
121                 glBegin(GL_LINE_STRIP);
122
123                 for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
124                         /* if there was a significant pressure change, stop the curve, change the thickness of the stroke,
125                          * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP)
126                          */
127                         if (fabsf(pt->pressure - oldpressure) > 0.2f) {
128                                 glEnd();
129                                 glLineWidth(pt->pressure * thickness);
130                                 glBegin(GL_LINE_STRIP);
131                                 
132                                 /* need to roll-back one point to ensure that there are no gaps in the stroke */
133                                 if (i != 0) glVertex2iv(&(pt - 1)->x);
134
135                                 /* now the point we want... */
136                                 glVertex2iv(&pt->x);
137                                 
138                                 oldpressure = pt->pressure;
139                         }
140                         else
141                                 glVertex2iv(&pt->x);
142                 }
143                 glEnd();
144
145                 /* reset for predictable OpenGL context */
146                 glLineWidth(1.0f);
147                 
148                 if (G.debug & G_DEBUG) setlinestyle(0);
149         }
150 }
151
152 /* --------- 2D Stroke Drawing Helpers --------- */
153
154 /* helper function to calculate x-y drawing coordinates for 2D points */
155 static void gp_calc_2d_stroke_xy(bGPDspoint *pt, short sflag, int offsx, int offsy, int winx, int winy, float r_co[2])
156 {
157         if (sflag & GP_STROKE_2DSPACE) {
158                 r_co[0] = pt->x;
159                 r_co[1] = pt->y;
160         }
161         else if (sflag & GP_STROKE_2DIMAGE) {
162                 const float x = (float)((pt->x * winx) + offsx);
163                 const float y = (float)((pt->y * winy) + offsy);
164                 
165                 r_co[0] = x;
166                 r_co[1] = y;
167         }
168         else {
169                 const float x = (float)(pt->x / 100 * winx) + offsx;
170                 const float y = (float)(pt->y / 100 * winy) + offsy;
171                 
172                 r_co[0] = x;
173                 r_co[1] = y;
174         }
175 }
176
177 /* ----------- Volumetric Strokes --------------- */
178
179 /* draw a 2D buffer stroke in "volumetric" style
180  * NOTE: the stroke buffer doesn't have any coordinate offsets/transforms
181  */
182 static void gp_draw_stroke_volumetric_buffer(tGPspoint *points, int totpoints, short thickness, short dflag, short sflag)
183 {
184         GLUquadricObj *qobj = gluNewQuadric();
185         float modelview[4][4];
186         
187         tGPspoint *pt;
188         int i;
189         
190         /* error checking */
191         if ((points == NULL) || (totpoints <= 0))
192                 return;
193         
194         /* check if buffer can be drawn */
195         if (dflag & (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_ONLYV2D))
196                 return;
197         
198         /* get basic matrix - should be camera space (i.e "identity") */
199         glGetFloatv(GL_MODELVIEW_MATRIX, (float *)modelview);
200         
201         /* draw points */
202         glPushMatrix();
203         
204         for (i = 0, pt = points; i < totpoints; i++, pt++) {
205                 /* set the transformed position */
206                 // TODO: scale should change based on zoom level, which requires proper translation mult too!
207                 modelview[3][0] = pt->x;
208                 modelview[3][1] = pt->y;
209                 
210                 glLoadMatrixf((float *)modelview);
211                 
212                 /* draw the disk using the current state... */
213                 gluDisk(qobj, 0.0,  pt->pressure * thickness, 32, 1);
214                 
215                 
216                 modelview[3][0] = modelview[3][1] = 0.0f;
217         }
218         
219         glPopMatrix();
220         gluDeleteQuadric(qobj);
221 }
222
223 /* draw a 2D strokes in "volumetric" style */
224 static void gp_draw_stroke_volumetric_2d(bGPDspoint *points, int totpoints, short thickness, short dflag, short sflag,
225                                          int offsx, int offsy, int winx, int winy)
226 {
227         GLUquadricObj *qobj = gluNewQuadric();
228         float modelview[4][4];
229         float baseloc[3];
230         
231         bGPDspoint *pt;
232         int i;
233         
234         
235         /* get basic matrix */
236         glGetFloatv(GL_MODELVIEW_MATRIX, (float *)modelview);
237         copy_v3_v3(baseloc, modelview[3]);
238         
239         /* draw points */
240         glPushMatrix();
241         
242         for (i = 0, pt = points; i < totpoints; i++, pt++) {
243                 /* set the transformed position */
244                 float co[2];
245                 
246                 gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co);
247                 translate_m4(modelview, co[0], co[1], 0.0f);
248                 
249                 glLoadMatrixf((float *)modelview);
250                 
251                 /* draw the disk using the current state... */
252                 gluDisk(qobj, 0.0,  pt->pressure * thickness, 32, 1);
253                 
254                 /* restore matrix */
255                 copy_v3_v3(modelview[3], baseloc);
256         }
257         
258         glPopMatrix();
259         gluDeleteQuadric(qobj);
260 }
261
262 /* draw a 3D stroke in "volumetric" style */
263 static void gp_draw_stroke_volumetric_3d(bGPDspoint *points, int totpoints, short thickness, short dflag, short sflag)
264 {
265         GLUquadricObj *qobj = gluNewQuadric();
266         
267         float base_modelview[4][4], modelview[4][4];
268         float base_loc[3];
269         
270         bGPDspoint *pt;
271         int i;
272         
273         
274         /* Get the basic modelview matrix we use for performing calculations */
275         glGetFloatv(GL_MODELVIEW_MATRIX, (float *)base_modelview);
276         copy_v3_v3(base_loc, base_modelview[3]);
277         
278         /* Create the basic view-aligned billboard matrix we're going to actually draw qobj with:
279          * - We need to knock out the rotation so that we are 
280          *   simply left with a camera-facing billboard
281          * - The scale factors here are chosen so that the thickness
282          *   is relatively reasonable. Otherwise, it gets far too
283          *   large!
284          */
285         scale_m4_fl(modelview, 0.1f);
286         
287         /* draw each point as a disk... */
288         glPushMatrix();
289         
290         for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
291                 /* apply translation to base_modelview, so that the translated point is put in the right place */
292                 translate_m4(base_modelview, pt->x, pt->y, pt->z);
293                 
294                 /* copy the translation component to the billboard matrix we're going to use,
295                  * then reset the base matrix to the original values so that we can do the same
296                  * for the next point without accumulation/pollution effects
297                  */
298                 copy_v3_v3(modelview[3], base_modelview[3]); /* copy offset value */
299                 copy_v3_v3(base_modelview[3], base_loc);     /* restore */
300                 
301                 /* apply our billboard matrix for drawing... */
302                 glLoadMatrixf((float *)modelview);
303                 
304                 /* draw the disk using the current state... */
305                 gluDisk(qobj, 0.0,  pt->pressure * thickness, 32, 1);
306         }
307         
308         glPopMatrix();
309         gluDeleteQuadric(qobj);
310 }
311
312
313 /* --------------- Stroke Fills ----------------- */
314
315 /* draw fills for shapes */
316 static void gp_draw_stroke_fill(bGPDspoint *points, int totpoints, short thickness, short dflag, short sflag,
317                                 int offsx, int offsy, int winx, int winy)
318 {
319         bGPDspoint *pt;
320         int i;
321         
322         BLI_assert(totpoints >= 3);
323         
324         /* As an initial implementation, we use the OpenGL filled polygon drawing 
325          * here since it's the easiest option to implement for this case. It does
326          * come with limitations (notably for concave shapes), though it shouldn't
327          * be much of an issue in most cases.
328          */
329         glBegin(GL_POLYGON);
330         
331         for (i = 0, pt = points; i < totpoints; i++, pt++) {
332                 if (sflag & GP_STROKE_3DSPACE) {
333                         glVertex3fv(&pt->x);
334                 }
335                 else {
336                         float co[2];
337                         
338                         gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co);
339                         glVertex2fv(co);
340                 }
341         }
342         
343         glEnd();
344 }
345
346 /* ----- Existing Strokes Drawing (3D and Point) ------ */
347
348 /* draw a given stroke - just a single dot (only one point) */
349 static void gp_draw_stroke_point(bGPDspoint *points, short thickness, short dflag, short sflag,
350                                  int offsx, int offsy, int winx, int winy)
351 {
352         /* draw point */
353         if (sflag & GP_STROKE_3DSPACE) {
354                 glBegin(GL_POINTS);
355                 glVertex3fv(&points->x);
356                 glEnd();
357         }
358         else {
359                 float co[2];
360                 
361                 /* get coordinates of point */
362                 gp_calc_2d_stroke_xy(points, sflag, offsx, offsy, winx, winy, co);
363                 
364                 /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, simple dot looks ok
365                  *  - also mandatory in if Image Editor 'image-based' dot
366                  */
367                 if ((thickness < GP_DRAWTHICKNESS_SPECIAL) ||
368                     ((dflag & GP_DRAWDATA_IEDITHACK) && (sflag & GP_STROKE_2DSPACE)))
369                 {
370                         glBegin(GL_POINTS);
371                         glVertex2fv(co);
372                         glEnd();
373                 }
374                 else {
375                         /* draw filled circle as is done in circf (but without the matrix push/pops which screwed things up) */
376                         GLUquadricObj *qobj = gluNewQuadric(); 
377                         
378                         gluQuadricDrawStyle(qobj, GLU_FILL); 
379                         
380                         /* need to translate drawing position, but must reset after too! */
381                         glTranslatef(co[0], co[1], 0.0);
382                         gluDisk(qobj, 0.0,  thickness, 32, 1); 
383                         glTranslatef(-co[0], -co[1], 0.0);
384                         
385                         gluDeleteQuadric(qobj);
386                 }
387         }
388 }
389
390 /* draw a given stroke in 3d (i.e. in 3d-space), using simple ogl lines */
391 static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness, bool debug, short sflag)
392 {
393         bGPDspoint *pt;
394         float curpressure = points[0].pressure;
395         int i;
396         
397         /* draw stroke curve */
398         glLineWidth(curpressure * thickness);
399         glBegin(GL_LINE_STRIP);
400         for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
401                 /* if there was a significant pressure change, stop the curve, change the thickness of the stroke,
402                  * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP)
403                  * Note: we want more visible levels of pressures when thickness is bigger.
404                  */
405                 if (fabsf(pt->pressure - curpressure) > 0.2f / (float)thickness) {
406                         glEnd();
407                         curpressure = pt->pressure;
408                         glLineWidth(curpressure * thickness);
409                         glBegin(GL_LINE_STRIP);
410                         
411                         /* need to roll-back one point to ensure that there are no gaps in the stroke */
412                         if (i != 0) glVertex3fv(&(pt - 1)->x);
413                         
414                         /* now the point we want... */
415                         glVertex3fv(&pt->x);
416                 }
417                 else {
418                         glVertex3fv(&pt->x);
419                 }
420         }
421         glEnd();
422         
423         /* draw debug points of curve on top? */
424         /* XXX: for now, we represent "selected" strokes in the same way as debug, which isn't used anymore */
425         if (debug) {
426                 glBegin(GL_POINTS);
427                 for (i = 0, pt = points; i < totpoints && pt; i++, pt++)
428                         glVertex3fv(&pt->x);
429                 glEnd();
430         }
431 }
432
433 /* ----- Fancy 2D-Stroke Drawing ------ */
434
435 /* draw a given stroke in 2d */
436 static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag,
437                               bool debug, int offsx, int offsy, int winx, int winy)
438 {
439         /* otherwise thickness is twice that of the 3D view */
440         float thickness = (float)thickness_s * 0.5f;
441
442         /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, 'smooth' opengl lines look better
443          *  - 'smooth' opengl lines are also required if Image Editor 'image-based' stroke
444          */
445         if ((thickness < GP_DRAWTHICKNESS_SPECIAL) ||
446             ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)))
447         {
448                 bGPDspoint *pt;
449                 int i;
450                 
451                 glBegin(GL_LINE_STRIP);
452                 for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
453                         float co[2];
454                         
455                         gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co);
456                         glVertex2fv(co);
457                 }
458                 glEnd();
459         }
460         
461         /* tessellation code - draw stroke as series of connected quads with connection
462          * edges rotated to minimize shrinking artifacts, and rounded endcaps
463          */
464         else {
465                 bGPDspoint *pt1, *pt2;
466                 float pm[2];
467                 int i;
468                 
469                 glShadeModel(GL_FLAT);
470                 glBegin(GL_QUADS);
471                 
472                 for (i = 0, pt1 = points, pt2 = points + 1; i < (totpoints - 1); i++, pt1++, pt2++) {
473                         float s0[2], s1[2];     /* segment 'center' points */
474                         float t0[2], t1[2];     /* tessellated coordinates */
475                         float m1[2], m2[2];     /* gradient and normal */
476                         float mt[2], sc[2];     /* gradient for thickness, point for end-cap */
477                         float pthick;           /* thickness at segment point */
478                         
479                         /* get x and y coordinates from points */
480                         gp_calc_2d_stroke_xy(pt1, sflag, offsx, offsy, winx, winy, s0);
481                         gp_calc_2d_stroke_xy(pt2, sflag, offsx, offsy, winx, winy, s1);
482                         
483                         /* calculate gradient and normal - 'angle'=(ny/nx) */
484                         m1[1] = s1[1] - s0[1];
485                         m1[0] = s1[0] - s0[0];
486                         normalize_v2(m1);
487                         m2[1] = -m1[0];
488                         m2[0] = m1[1];
489                         
490                         /* always use pressure from first point here */
491                         pthick = (pt1->pressure * thickness);
492                         
493                         /* if the first segment, start of segment is segment's normal */
494                         if (i == 0) {
495                                 /* draw start cap first 
496                                  *      - make points slightly closer to center (about halfway across) 
497                                  */
498                                 mt[0] = m2[0] * pthick * 0.5f;
499                                 mt[1] = m2[1] * pthick * 0.5f;
500                                 sc[0] = s0[0] - (m1[0] * pthick * 0.75f);
501                                 sc[1] = s0[1] - (m1[1] * pthick * 0.75f);
502                                 
503                                 t0[0] = sc[0] - mt[0];
504                                 t0[1] = sc[1] - mt[1];
505                                 t1[0] = sc[0] + mt[0];
506                                 t1[1] = sc[1] + mt[1];
507                                 
508                                 glVertex2fv(t0);
509                                 glVertex2fv(t1);
510                                 
511                                 /* calculate points for start of segment */
512                                 mt[0] = m2[0] * pthick;
513                                 mt[1] = m2[1] * pthick;
514                                 
515                                 t0[0] = s0[0] - mt[0];
516                                 t0[1] = s0[1] - mt[1];
517                                 t1[0] = s0[0] + mt[0];
518                                 t1[1] = s0[1] + mt[1];
519                                 
520                                 /* draw this line twice (first to finish off start cap, then for stroke) */
521                                 glVertex2fv(t1);
522                                 glVertex2fv(t0);
523                                 glVertex2fv(t0);
524                                 glVertex2fv(t1);
525                         }
526                         /* if not the first segment, use bisector of angle between segments */
527                         else {
528                                 float mb[2];         /* bisector normal */
529                                 float athick, dfac;  /* actual thickness, difference between thicknesses */
530                                 
531                                 /* calculate gradient of bisector (as average of normals) */
532                                 mb[0] = (pm[0] + m2[0]) / 2;
533                                 mb[1] = (pm[1] + m2[1]) / 2;
534                                 normalize_v2(mb);
535                                 
536                                 /* calculate gradient to apply 
537                                  *  - as basis, use just pthick * bisector gradient
538                                  *      - if cross-section not as thick as it should be, add extra padding to fix it
539                                  */
540                                 mt[0] = mb[0] * pthick;
541                                 mt[1] = mb[1] * pthick;
542                                 athick = len_v2(mt);
543                                 dfac = pthick - (athick * 2);
544                                 
545                                 if (((athick * 2.0f) < pthick) && (IS_EQF(athick, pthick) == 0)) {
546                                         mt[0] += (mb[0] * dfac);
547                                         mt[1] += (mb[1] * dfac);
548                                 }
549                                 
550                                 /* calculate points for start of segment */
551                                 t0[0] = s0[0] - mt[0];
552                                 t0[1] = s0[1] - mt[1];
553                                 t1[0] = s0[0] + mt[0];
554                                 t1[1] = s0[1] + mt[1];
555                                 
556                                 /* draw this line twice (once for end of current segment, and once for start of next) */
557                                 glVertex2fv(t1);
558                                 glVertex2fv(t0);
559                                 glVertex2fv(t0);
560                                 glVertex2fv(t1);
561                         }
562                         
563                         /* if last segment, also draw end of segment (defined as segment's normal) */
564                         if (i == totpoints - 2) {
565                                 /* for once, we use second point's pressure (otherwise it won't be drawn) */
566                                 pthick = (pt2->pressure * thickness);
567                                 
568                                 /* calculate points for end of segment */
569                                 mt[0] = m2[0] * pthick;
570                                 mt[1] = m2[1] * pthick;
571                                 
572                                 t0[0] = s1[0] - mt[0];
573                                 t0[1] = s1[1] - mt[1];
574                                 t1[0] = s1[0] + mt[0];
575                                 t1[1] = s1[1] + mt[1];
576                                 
577                                 /* draw this line twice (once for end of stroke, and once for endcap)*/
578                                 glVertex2fv(t1);
579                                 glVertex2fv(t0);
580                                 glVertex2fv(t0);
581                                 glVertex2fv(t1);
582                                 
583                                 
584                                 /* draw end cap as last step 
585                                  *      - make points slightly closer to center (about halfway across) 
586                                  */
587                                 mt[0] = m2[0] * pthick * 0.5f;
588                                 mt[1] = m2[1] * pthick * 0.5f;
589                                 sc[0] = s1[0] + (m1[0] * pthick * 0.75f);
590                                 sc[1] = s1[1] + (m1[1] * pthick * 0.75f);
591                                 
592                                 t0[0] = sc[0] - mt[0];
593                                 t0[1] = sc[1] - mt[1];
594                                 t1[0] = sc[0] + mt[0];
595                                 t1[1] = sc[1] + mt[1];
596                                 
597                                 glVertex2fv(t1);
598                                 glVertex2fv(t0);
599                         }
600                         
601                         /* store stroke's 'natural' normal for next stroke to use */
602                         copy_v2_v2(pm, m2);
603                 }
604                 
605                 glEnd();
606         }
607         
608         /* draw debug points of curve on top? (original stroke points) */
609         if (debug) {
610                 bGPDspoint *pt;
611                 int i;
612                 
613                 glBegin(GL_POINTS);
614                 for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
615                         float co[2];
616                         
617                         gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co);
618                         glVertex2fv(co);
619                 }
620                 glEnd();
621         }
622 }
623
624 /* ----- Strokes Drawing ------ */
625
626 /* Helper for doing all the checks on whether a stroke can be drawn */
627 static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag)
628 {
629         /* skip stroke if it isn't in the right display space for this drawing context */
630         /* 1) 3D Strokes */
631         if ((dflag & GP_DRAWDATA_ONLY3D) && !(gps->flag & GP_STROKE_3DSPACE))
632                 return false;
633         if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE))
634                 return false;
635                 
636         /* 2) Screen Space 2D Strokes */
637         if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE))
638                 return false;
639         if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE))
640                 return false;
641                 
642         /* 3) Image Space (2D) */
643         if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE))
644                 return false;
645         if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE))
646                 return false;
647                 
648                 
649         /* skip stroke if it doesn't have any valid data */
650         if ((gps->points == NULL) || (gps->totpoints < 1))
651                 return false;
652                 
653         /* stroke can be drawn */
654         return true;
655 }
656
657 /* draw a set of strokes */
658 static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag,
659                             bool debug, short lthick, const float color[4], const float fill_color[4])
660 {
661         bGPDstroke *gps;
662         
663         for (gps = gpf->strokes.first; gps; gps = gps->next) {
664                 /* check if stroke can be drawn */
665                 if (gp_can_draw_stroke(gps, dflag) == false)
666                         continue;
667                 
668                 /* check which stroke-drawer to use */
669                 if (dflag & GP_DRAWDATA_ONLY3D) {
670                         const int no_xray = (dflag & GP_DRAWDATA_NO_XRAY);
671                         int mask_orig = 0;
672                         
673                         if (no_xray) {
674                                 glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
675                                 glDepthMask(0);
676                                 glEnable(GL_DEPTH_TEST);
677                                 
678                                 /* first arg is normally rv3d->dist, but this isn't
679                                  * available here and seems to work quite well without */
680                                 bglPolygonOffset(1.0f, 1.0f);
681 #if 0
682                                 glEnable(GL_POLYGON_OFFSET_LINE);
683                                 glPolygonOffset(-1.0f, -1.0f);
684 #endif
685                         }
686                         
687                         /* 3D Fill */
688                         if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
689                                 glColor4fv(fill_color);
690                                 gp_draw_stroke_fill(gps->points, gps->totpoints, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
691                         }
692                         
693                         /* 3D Stroke */
694                         glColor4fv(color);
695                         
696                         if (dflag & GP_DRAWDATA_VOLUMETRIC) {
697                                 /* volumetric stroke drawing */
698                                 gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, lthick, dflag, gps->flag);
699                         }
700                         else {
701                                 /* 3D Lines - OpenGL primitives-based */
702                                 if (gps->totpoints == 1) {
703                                         gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
704                                 }
705                                 else {
706                                         gp_draw_stroke_3d(gps->points, gps->totpoints, lthick, debug, gps->flag);
707                                 }
708                         }
709                         
710                         if (no_xray) {
711                                 glDepthMask(mask_orig);
712                                 glDisable(GL_DEPTH_TEST);
713                                 
714                                 bglPolygonOffset(0.0, 0.0);
715 #if 0
716                                 glDisable(GL_POLYGON_OFFSET_LINE);
717                                 glPolygonOffset(0, 0);
718 #endif
719                         }
720                 }
721                 else {
722                         /* 2D - Fill */
723                         if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
724                                 gp_draw_stroke_fill(gps->points, gps->totpoints, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
725                         }
726                         
727                         /* 2D Strokes... */
728                         glColor4fv(color);
729                         
730                         if (dflag & GP_DRAWDATA_VOLUMETRIC) {
731                                 /* blob/disk-based "volumetric" drawing */
732                                 gp_draw_stroke_volumetric_2d(gps->points, gps->totpoints, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
733                         }
734                         else {
735                                 /* normal 2D strokes */
736                                 if (gps->totpoints == 1) {
737                                         gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
738                                 }
739                                 else {
740                                         gp_draw_stroke_2d(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, offsx, offsy, winx, winy);
741                                 }
742                         }
743                 }
744         }
745 }
746
747 /* Draw selected verts for strokes being edited */
748 static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx, int winy, short dflag, const float tcolor[3])
749 {
750         bGPDstroke *gps;
751         
752         const int no_xray = (dflag & GP_DRAWDATA_NO_XRAY);
753         int mask_orig = 0;
754         
755         /* set up depth masks... */
756         if (dflag & GP_DRAWDATA_ONLY3D) {
757                 if (no_xray) {
758                         glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
759                         glDepthMask(0);
760                         glEnable(GL_DEPTH_TEST);
761                         
762                         /* first arg is normally rv3d->dist, but this isn't
763                          * available here and seems to work quite well without */
764                         bglPolygonOffset(1.0f, 1.0f);
765 #if 0
766                         glEnable(GL_POLYGON_OFFSET_LINE);
767                         glPolygonOffset(-1.0f, -1.0f);
768 #endif
769                 }
770         }
771         
772         
773         /* draw stroke verts */
774         for (gps = gpf->strokes.first; gps; gps = gps->next) {
775                 bGPDspoint *pt;
776                 float vsize, bsize;
777                 int i;
778                 
779                 /* check if stroke can be drawn */
780                 if (gp_can_draw_stroke(gps, dflag) == false)
781                         continue;
782                 
783                 /* Optimisation: only draw points for selected strokes
784                  * We assume that selected points can only occur in
785                  * strokes that are selected too.
786                  */
787                 if ((gps->flag & GP_STROKE_SELECT) == 0)
788                         continue;
789                         
790                 /* Get size of verts:
791                  * - The selected state needs to be larger than the unselected state so that
792                  *   they stand out more.
793                  * - We use the theme setting for size of the unselected verts
794                  */
795                 bsize = UI_GetThemeValuef(TH_VERTEX_SIZE);
796                 if ((int)bsize > 8) {
797                         vsize = 10.0f;
798                         bsize = 8.0f;
799                 }
800                 else {
801                         vsize = bsize + 2;
802                 }
803                 
804                 /* First Pass: Draw all the verts (i.e. these become the unselected state) */
805                 if (tcolor != NULL) {
806                         /* for now, we assume that the base color of the points is not too close to the real color */
807                         glColor3fv(tcolor);
808                 }
809                 else {
810                         /* this doesn't work well with the default theme and black strokes... */
811                         UI_ThemeColor(TH_VERTEX);
812                 }
813                 glPointSize(bsize);
814                 
815                 glBegin(GL_POINTS);
816                 for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
817                         if (gps->flag & GP_STROKE_3DSPACE) {
818                                 glVertex3fv(&pt->x);
819                         }
820                         else {
821                                 float co[2];
822                                 
823                                 gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
824                                 glVertex2fv(co);
825                         }
826                 }
827                 glEnd();
828                 
829                 
830                 /* Second Pass: Draw only verts which are selected */
831                 UI_ThemeColor(TH_VERTEX_SELECT);
832                 glPointSize(vsize);
833                 
834                 glBegin(GL_POINTS);
835                 for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
836                         if (pt->flag & GP_SPOINT_SELECT) {
837                                 if (gps->flag & GP_STROKE_3DSPACE) {
838                                         glVertex3fv(&pt->x);
839                                 }
840                                 else {
841                                         float co[2];
842                                         
843                                         gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
844                                         glVertex2fv(co);
845                                 }
846                         }
847                 }
848                 glEnd();
849         }
850         
851         
852         /* clear depth mask */
853         if (dflag & GP_DRAWDATA_ONLY3D) {
854                 if (no_xray) {
855                         glDepthMask(mask_orig);
856                         glDisable(GL_DEPTH_TEST);
857                         
858                         bglPolygonOffset(0.0, 0.0);
859 #if 0
860                         glDisable(GL_POLYGON_OFFSET_LINE);
861                         glPolygonOffset(0, 0);
862 #endif
863                 }
864         }
865 }
866
867 /* ----- General Drawing ------ */
868
869 /* draw onion-skinning for a layer */
870 static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int offsy, int winx, int winy, 
871                                int cfra, int dflag, short debug, short lthick)
872 {
873         const float alpha = gpl->color[3];
874         float color[4];
875         
876         /* 1) Draw Previous Frames First */
877         if (gpl->flag & GP_LAYER_GHOST_PREVCOL) {
878                 copy_v3_v3(color, gpl->gcolor_prev);
879         }
880         else {
881                 copy_v3_v3(color, gpl->color);
882         }
883         
884         if (gpl->gstep) {
885                 bGPDframe *gf;
886                 float fac;
887                 
888                 /* draw previous frames first */
889                 for (gf = gpf->prev; gf; gf = gf->prev) {
890                         /* check if frame is drawable */
891                         if ((gpf->framenum - gf->framenum) <= gpl->gstep) {
892                                 /* alpha decreases with distance from curframe index */
893                                 fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1));
894                                 color[3] = alpha * fac * 0.66f;
895                                 gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
896                         }
897                         else 
898                                 break;
899                 }
900         }
901         else {
902                 /* draw the strokes for the ghost frames (at half of the alpha set by user) */
903                 if (gpf->prev) {
904                         color[3] = (alpha / 7);
905                         gp_draw_strokes(gpf->prev, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
906                 }
907         }
908         
909         
910         /* 2) Now draw next frames */
911         if (gpl->flag & GP_LAYER_GHOST_NEXTCOL) {
912                 copy_v3_v3(color, gpl->gcolor_next);
913         }
914         else {
915                 copy_v3_v3(color, gpl->color);
916         }
917         
918         if (gpl->gstep_next) {
919                 bGPDframe *gf;
920                 float fac;
921                 
922                 /* now draw next frames */
923                 for (gf = gpf->next; gf; gf = gf->next) {
924                         /* check if frame is drawable */
925                         if ((gf->framenum - gpf->framenum) <= gpl->gstep_next) {
926                                 /* alpha decreases with distance from curframe index */
927                                 fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep_next + 1));
928                                 color[3] = alpha * fac * 0.66f;
929                                 gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
930                         }
931                         else 
932                                 break;
933                 }
934         }
935         else {
936                 /* draw the strokes for the ghost frames (at half of the alpha set by user) */
937                 if (gpf->next) {
938                         color[3] = (alpha / 4);
939                         gp_draw_strokes(gpf->next, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
940                 }
941         }
942         
943         /* 3) restore alpha */
944         glColor4fv(gpl->color);
945 }
946
947 /* draw grease-pencil datablock */
948 static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag)
949 {
950         bGPDlayer *gpl;
951         
952         /* reset line drawing style (in case previous user didn't reset) */
953         setlinestyle(0);
954         
955         /* turn on smooth lines (i.e. anti-aliasing) */
956         glEnable(GL_LINE_SMOOTH);
957         
958         /* turn on alpha-blending */
959         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
960         glEnable(GL_BLEND);
961                 
962         /* loop over layers, drawing them */
963         for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
964                 bGPDframe *gpf;
965                 
966                 bool debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? true : false;
967                 short lthick = gpl->thickness;
968                 
969                 /* don't draw layer if hidden */
970                 if (gpl->flag & GP_LAYER_HIDE) 
971                         continue;
972                 
973                 /* get frame to draw */
974                 gpf = gpencil_layer_getframe(gpl, cfra, 0);
975                 if (gpf == NULL) 
976                         continue;
977                 
978                 /* set color, stroke thickness, and point size */
979                 glLineWidth(lthick);
980                 glPointSize((float)(gpl->thickness + 2));
981                 
982                 /* Add layer drawing settings to the set of "draw flags" 
983                  * NOTE: If the setting doesn't apply, it *must* be cleared,
984                  *       as dflag's carry over from the previous layer
985                  */
986 #define GP_DRAWFLAG_APPLY(condition, draw_flag_value)     { \
987                         if (condition) dflag |= (draw_flag_value);      \
988                         else           dflag &= ~(draw_flag_value);     \
989                 } (void)0
990                 
991                 /* xray... */
992                 GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_NO_XRAY), GP_DRAWDATA_NO_XRAY);
993                 
994                 /* volumetric strokes... */
995                 GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_VOLUMETRIC), GP_DRAWDATA_VOLUMETRIC);
996                 
997                 /* fill strokes... */
998                 // XXX: this is not a very good limit
999                 GP_DRAWFLAG_APPLY((gpl->fill[3] > 0.001f), GP_DRAWDATA_FILL);
1000 #undef GP_DRAWFLAG_APPLY
1001                 
1002                 /* draw 'onionskins' (frame left + right) */
1003                 if ((gpl->flag & GP_LAYER_ONIONSKIN) && !(dflag & GP_DRAWDATA_NO_ONIONS)) {
1004                         /* Drawing method - only immediately surrounding (gstep = 0),
1005                          * or within a frame range on either side (gstep > 0)
1006                          */
1007                         gp_draw_onionskins(gpl, gpf, offsx, offsy, winx, winy, cfra, dflag, debug, lthick);
1008                 }
1009                 
1010                 /* draw the strokes already in active frame */
1011                 gp_draw_strokes(gpf, offsx, offsy, winx, winy, dflag, debug, lthick, gpl->color, gpl->fill);
1012                 
1013                 /* Draw verts of selected strokes 
1014                  *  - when doing OpenGL renders, we don't want to be showing these, as that ends up flickering
1015                  *      - locked layers can't be edited, so there's no point showing these verts
1016                  *    as they will have no bearings on what gets edited
1017                  *  - only show when in editmode, since operators shouldn't work otherwise
1018                  *    (NOTE: doing it this way means that the toggling editmode shows visible change immediately)
1019                  */
1020                 /* XXX: perhaps we don't want to show these when users are drawing... */
1021                 if ((G.f & G_RENDER_OGL) == 0 &&
1022                     (gpl->flag & GP_LAYER_LOCKED) == 0 && 
1023                     (gpd->flag & GP_DATA_STROKE_EDITMODE))
1024                 {
1025                         gp_draw_strokes_edit(gpf, offsx, offsy, winx, winy, dflag, 
1026                                              (gpl->color[3] < 0.95f) ? gpl->color : NULL);
1027                 }
1028                 
1029                 /* Check if may need to draw the active stroke cache, only if this layer is the active layer
1030                  * that is being edited. (Stroke buffer is currently stored in gp-data)
1031                  */
1032                 if (ED_gpencil_session_active() && (gpl->flag & GP_LAYER_ACTIVE) &&
1033                     (gpf->flag & GP_FRAME_PAINT))
1034                 {
1035                         /* Set color for drawing buffer stroke - since this may not be set yet */
1036                         glColor4fv(gpl->color);
1037                         
1038                         /* Buffer stroke needs to be drawn with a different linestyle
1039                          * to help differentiate them from normal strokes.
1040                          * 
1041                          * It should also be noted that sbuffer contains temporary point types
1042                          * i.e. tGPspoints NOT bGPDspoints
1043                          */
1044                         if (gpl->flag & GP_LAYER_VOLUMETRIC) {
1045                                 gp_draw_stroke_volumetric_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag);
1046                         }
1047                         else {
1048                                 gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag);
1049                         }
1050                 }
1051         }
1052         
1053         /* turn off alpha blending, then smooth lines */
1054         glDisable(GL_BLEND); // alpha blending
1055         glDisable(GL_LINE_SMOOTH); // smooth lines
1056                 
1057         /* restore initial gl conditions */
1058         glLineWidth(1.0);
1059         glPointSize(1.0);
1060         glColor4f(0, 0, 0, 1);
1061 }
1062
1063 /* ----- Grease Pencil Sketches Drawing API ------ */
1064
1065 /* ............................
1066  * XXX
1067  *      We need to review the calls below, since they may be/are not that suitable for
1068  *      the new ways that we intend to be drawing data...
1069  * ............................ */
1070
1071 /* draw grease-pencil sketches to specified 2d-view that uses ibuf corrections */
1072 void ED_gpencil_draw_2dimage(const bContext *C)
1073 {
1074         ScrArea *sa = CTX_wm_area(C);
1075         ARegion *ar = CTX_wm_region(C);
1076         Scene *scene = CTX_data_scene(C);
1077         bGPdata *gpd;
1078         int offsx, offsy, sizex, sizey;
1079         int dflag = GP_DRAWDATA_NOSTATUS;
1080         
1081         gpd = ED_gpencil_data_get_active(C); // XXX
1082         if (gpd == NULL) return;
1083         
1084         /* calculate rect */
1085         switch (sa->spacetype) {
1086                 case SPACE_IMAGE: /* image */
1087                 case SPACE_CLIP: /* clip */
1088                 {
1089                         
1090                         /* just draw using standard scaling (settings here are currently ignored anyways) */
1091                         /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */
1092                         offsx = 0;
1093                         offsy = 0;
1094                         sizex = ar->winx;
1095                         sizey = ar->winy;
1096                         
1097                         wmOrtho2(ar->v2d.cur.xmin, ar->v2d.cur.xmax, ar->v2d.cur.ymin, ar->v2d.cur.ymax);
1098                         
1099                         dflag |= GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_IEDITHACK;
1100                         break;
1101                 }
1102                 case SPACE_SEQ: /* sequence */
1103                 {
1104                         /* just draw using standard scaling (settings here are currently ignored anyways) */
1105                         offsx = 0;
1106                         offsy = 0;
1107                         sizex = ar->winx;
1108                         sizey = ar->winy;
1109                         
1110                         /* NOTE: I2D was used in 2.4x, but the old settings for that have been deprecated 
1111                          * and everything moved to standard View2d 
1112                          */
1113                         dflag |= GP_DRAWDATA_ONLYV2D;
1114                         break;
1115                 }
1116                 default: /* for spacetype not yet handled */
1117                         offsx = 0;
1118                         offsy = 0;
1119                         sizex = ar->winx;
1120                         sizey = ar->winy;
1121                         
1122                         dflag |= GP_DRAWDATA_ONLYI2D;
1123                         break;
1124         }
1125         
1126         
1127         /* draw it! */
1128         gp_draw_data(gpd, offsx, offsy, sizex, sizey, CFRA, dflag);
1129 }
1130
1131 /* draw grease-pencil sketches to specified 2d-view assuming that matrices are already set correctly 
1132  * Note: this gets called twice - first time with onlyv2d=1 to draw 'canvas' strokes,
1133  * second time with onlyv2d=0 for screen-aligned strokes */
1134 void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d)
1135 {
1136         ScrArea *sa = CTX_wm_area(C);
1137         ARegion *ar = CTX_wm_region(C);
1138         Scene *scene = CTX_data_scene(C);
1139         bGPdata *gpd;
1140         int dflag = 0;
1141         
1142         /* check that we have grease-pencil stuff to draw */
1143         if (sa == NULL) return;
1144         gpd = ED_gpencil_data_get_active(C); // XXX
1145         if (gpd == NULL) return;
1146         
1147         /* special hack for Image Editor */
1148         /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */
1149         if (ELEM(sa->spacetype, SPACE_IMAGE, SPACE_CLIP))
1150                 dflag |= GP_DRAWDATA_IEDITHACK;
1151         
1152         /* draw it! */
1153         if (onlyv2d) dflag |= (GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_NOSTATUS);
1154         gp_draw_data(gpd, 0, 0, ar->winx, ar->winy, CFRA, dflag);
1155 }
1156
1157 /* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly 
1158  * Note: this gets called twice - first time with only3d=1 to draw 3d-strokes,
1159  * second time with only3d=0 for screen-aligned strokes */
1160 void ED_gpencil_draw_view3d(Scene *scene, View3D *v3d, ARegion *ar, bool only3d)
1161 {
1162         bGPdata *gpd;
1163         int dflag = 0;
1164         RegionView3D *rv3d = ar->regiondata;
1165         int offsx,  offsy,  winx,  winy;
1166
1167         /* check that we have grease-pencil stuff to draw */
1168         gpd = ED_gpencil_data_get_active_v3d(scene, v3d);
1169         if (gpd == NULL) return;
1170
1171         /* when rendering to the offscreen buffer we don't want to
1172          * deal with the camera border, otherwise map the coords to the camera border. */
1173         if ((rv3d->persp == RV3D_CAMOB) && !(G.f & G_RENDER_OGL)) {
1174                 rctf rectf;
1175                 ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &rectf, true); /* no shift */
1176
1177                 offsx = iroundf(rectf.xmin);
1178                 offsy = iroundf(rectf.ymin);
1179                 winx  = iroundf(rectf.xmax - rectf.xmin);
1180                 winy  = iroundf(rectf.ymax - rectf.ymin);
1181         }
1182         else {
1183                 offsx = 0;
1184                 offsy = 0;
1185                 winx  = ar->winx;
1186                 winy  = ar->winy;
1187         }
1188         
1189         /* draw it! */
1190         if (only3d) dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS);
1191
1192         gp_draw_data(gpd, offsx, offsy, winx, winy, CFRA, dflag);
1193 }
1194
1195 void ED_gpencil_draw_ex(bGPdata *gpd, int winx, int winy, const int cfra)
1196 {
1197         int dflag = GP_DRAWDATA_NOSTATUS | GP_DRAWDATA_ONLYV2D;
1198
1199         gp_draw_data(gpd, 0, 0, winx, winy, cfra, dflag);
1200 }
1201
1202 /* ************************************************** */