Cleanup: replace gpencil tri vars w/ array
[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, Antonio Vazquez
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/gpencil/drawgpencil.c
27  *  \ingroup edgpencil
28  */
29
30
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <stddef.h>
35 #include <math.h>
36 #include <float.h>
37
38 #include "MEM_guardedalloc.h"
39
40 #include "BLI_sys_types.h"
41
42 #include "BLI_math.h"
43 #include "BLI_utildefines.h"
44 #include "BLI_polyfill2d.h"
45
46 #include "BLF_api.h"
47 #include "BLT_translation.h"
48
49 #include "DNA_gpencil_types.h"
50 #include "DNA_scene_types.h"
51 #include "DNA_screen_types.h"
52 #include "DNA_space_types.h"
53 #include "DNA_view3d_types.h"
54 #include "DNA_userdef_types.h"
55 #include "DNA_object_types.h"
56
57 #include "BKE_context.h"
58 #include "BKE_global.h"
59 #include "BKE_gpencil.h"
60
61 #include "WM_api.h"
62
63 #include "BIF_gl.h"
64 #include "BIF_glutil.h"
65
66 #include "ED_gpencil.h"
67 #include "ED_screen.h"
68 #include "ED_view3d.h"
69 #include "ED_space_api.h"
70
71 #include "UI_interface_icons.h"
72 #include "UI_resources.h"
73
74 /* ************************************************** */
75 /* GREASE PENCIL DRAWING */
76
77 /* ----- General Defines ------ */
78 /* flags for sflag */
79 typedef enum eDrawStrokeFlags {
80         GP_DRAWDATA_NOSTATUS    = (1 << 0),   /* don't draw status info */
81         GP_DRAWDATA_ONLY3D      = (1 << 1),   /* only draw 3d-strokes */
82         GP_DRAWDATA_ONLYV2D     = (1 << 2),   /* only draw 'canvas' strokes */
83         GP_DRAWDATA_ONLYI2D     = (1 << 3),   /* only draw 'image' strokes */
84         GP_DRAWDATA_IEDITHACK   = (1 << 4),   /* special hack for drawing strokes in Image Editor (weird coordinates) */
85         GP_DRAWDATA_NO_XRAY     = (1 << 5),   /* don't draw xray in 3D view (which is default) */
86         GP_DRAWDATA_NO_ONIONS   = (1 << 6),       /* no onionskins should be drawn (for animation playback) */
87         GP_DRAWDATA_VOLUMETRIC  = (1 << 7),   /* draw strokes as "volumetric" circular billboards */
88         GP_DRAWDATA_FILL        = (1 << 8),   /* fill insides/bounded-regions of strokes */
89         GP_DRAWDATA_HQ_FILL     = (1 << 9)    /* Use high quality fill */
90 } eDrawStrokeFlags;
91
92
93
94 /* thickness above which we should use special drawing */
95 #define GP_DRAWTHICKNESS_SPECIAL    3
96
97 /* ----- Tool Buffer Drawing ------ */
98 /* helper function to set color of buffer point */
99 static void gp_set_tpoint_color(tGPspoint *pt, float ink[4])
100 {
101         float alpha = ink[3] * pt->strength;
102         CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
103         glColor4f(ink[0], ink[1], ink[2], alpha);
104 }
105
106 /* helper function to set color of point */
107 static void gp_set_point_color(bGPDspoint *pt, float ink[4])
108 {
109         float alpha = ink[3] * pt->strength;
110         CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
111         glColor4f(ink[0], ink[1], ink[2], alpha);
112 }
113
114 /* helper function to set color and point */
115 static void gp_set_color_and_tpoint(tGPspoint *pt, float ink[4])
116 {
117         gp_set_tpoint_color(pt, ink);
118         glVertex2iv(&pt->x);
119 }
120
121 /* draw stroke defined in buffer (simple ogl lines/points for now, as dotted lines) */
122 static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickness,
123                                   short dflag, short sflag, float ink[4])
124 {
125         tGPspoint *pt;
126         int i;
127         
128         /* error checking */
129         if ((points == NULL) || (totpoints <= 0))
130                 return;
131         
132         /* check if buffer can be drawn */
133         if (dflag & (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_ONLYV2D))
134                 return;
135         
136         if (totpoints == 1) {
137                 /* if drawing a single point, draw it larger */
138                 glPointSize((float)(thickness + 2) * points->pressure);
139                 glBegin(GL_POINTS);
140
141                 gp_set_color_and_tpoint(points, ink);
142                 glEnd();
143         }
144         else if (sflag & GP_STROKE_ERASER) {
145                 /* don't draw stroke at all! */
146         }
147         else {
148                 float oldpressure = points[0].pressure;
149                 
150                 /* draw stroke curve */
151                 if (G.debug & G_DEBUG) setlinestyle(2);
152                 
153                 glLineWidth(max_ff(oldpressure * thickness, 1.0));
154                 glBegin(GL_LINE_STRIP);
155                 
156                 for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
157                         /* if there was a significant pressure change, stop the curve, change the thickness of the stroke,
158                          * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP)
159                          */
160                         if (fabsf(pt->pressure - oldpressure) > 0.2f) {
161                                 glEnd();
162                                 glLineWidth(max_ff(pt->pressure * thickness, 1.0f));
163                                 glBegin(GL_LINE_STRIP);
164                                 
165                                 /* need to roll-back one point to ensure that there are no gaps in the stroke */
166                                 if (i != 0) { 
167                                         gp_set_color_and_tpoint((pt - 1), ink);
168                                 }
169                                 
170                                 /* now the point we want... */
171                                 gp_set_color_and_tpoint(pt, ink);
172                                 
173                                 oldpressure = pt->pressure;
174                         }
175                         else {
176                                 gp_set_color_and_tpoint(pt, ink);
177                         }
178                 }
179                 glEnd();
180
181                 if (G.debug & G_DEBUG) setlinestyle(0);
182         }
183 }
184
185 /* --------- 2D Stroke Drawing Helpers --------- */
186 /* change in parameter list */
187 static void gp_calc_2d_stroke_fxy(float pt[3], short sflag, int offsx, int offsy, int winx, int winy, float r_co[2])
188 {
189         if (sflag & GP_STROKE_2DSPACE) {
190                 r_co[0] = pt[0];
191                 r_co[1] = pt[1];
192         }
193         else if (sflag & GP_STROKE_2DIMAGE) {
194                 const float x = (float)((pt[0] * winx) + offsx);
195                 const float y = (float)((pt[1] * winy) + offsy);
196
197                 r_co[0] = x;
198                 r_co[1] = y;
199         }
200         else {
201                 const float x = (float)(pt[0] / 100 * winx) + offsx;
202                 const float y = (float)(pt[1] / 100 * winy) + offsy;
203
204                 r_co[0] = x;
205                 r_co[1] = y;
206         }
207 }
208 /* ----------- Volumetric Strokes --------------- */
209
210 /* draw a 2D buffer stroke in "volumetric" style
211  * NOTE: the stroke buffer doesn't have any coordinate offsets/transforms
212  */
213 static void gp_draw_stroke_volumetric_buffer(tGPspoint *points, int totpoints, short thickness,
214                                              short dflag, short UNUSED(sflag), float ink[4])
215 {
216         GLUquadricObj *qobj = gluNewQuadric();
217         float modelview[4][4];
218         
219         tGPspoint *pt;
220         int i;
221         
222         /* error checking */
223         if ((points == NULL) || (totpoints <= 0))
224                 return;
225         
226         /* check if buffer can be drawn */
227         if (dflag & (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_ONLYV2D))
228                 return;
229         
230         /* get basic matrix - should be camera space (i.e "identity") */
231         glGetFloatv(GL_MODELVIEW_MATRIX, (float *)modelview);
232         
233         /* draw points */
234         glPushMatrix();
235         
236         for (i = 0, pt = points; i < totpoints; i++, pt++) {
237                 /* set the transformed position */
238                 // TODO: scale should change based on zoom level, which requires proper translation mult too!
239                 modelview[3][0] = pt->x;
240                 modelview[3][1] = pt->y;
241                 
242                 glLoadMatrixf((float *)modelview);
243                 
244                 /* draw the disk using the current state... */
245                 gp_set_tpoint_color(pt, ink);
246                 gluDisk(qobj, 0.0,  pt->pressure * thickness, 32, 1);
247                 
248                 
249                 modelview[3][0] = modelview[3][1] = 0.0f;
250         }
251
252         glPopMatrix();
253         gluDeleteQuadric(qobj);
254 }
255
256 /* draw a 2D strokes in "volumetric" style */
257 static void gp_draw_stroke_volumetric_2d(bGPDspoint *points, int totpoints, short thickness,
258                                          short dflag, short sflag,
259                                          int offsx, int offsy, int winx, int winy,
260                                          float diff_mat[4][4], float ink[4])
261 {
262         GLUquadricObj *qobj = gluNewQuadric();
263         float modelview[4][4];
264         float baseloc[3];
265         float scalefac = 1.0f;
266         
267         bGPDspoint *pt;
268         int i;
269         float fpt[3];
270         
271         /* HACK: We need a scale factor for the drawing in the image editor,
272          * which seems to use 1 unit as it's maximum size, whereas everything
273          * else assumes 1 unit = 1 pixel. Otherwise, we only get a massive blob.
274          */
275         if ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) {
276                 scalefac = 0.001f;
277         }
278         
279         /* get basic matrix */
280         glGetFloatv(GL_MODELVIEW_MATRIX, (float *)modelview);
281         copy_v3_v3(baseloc, modelview[3]);
282         
283         /* draw points */
284         glPushMatrix();
285         
286         for (i = 0, pt = points; i < totpoints; i++, pt++) {
287                 /* color of point */
288                 gp_set_point_color(pt, ink);
289
290                 /* set the transformed position */
291                 float co[2];
292                 
293                 mul_v3_m4v3(fpt, diff_mat, &pt->x);
294                 gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
295                 translate_m4(modelview, co[0], co[1], 0.0f);
296                 
297                 glLoadMatrixf((float *)modelview);
298                 
299                 /* draw the disk using the current state... */
300                 gluDisk(qobj, 0.0,  pt->pressure * thickness * scalefac, 32, 1);
301                 
302                 /* restore matrix */
303                 copy_v3_v3(modelview[3], baseloc);
304         }
305         
306         glPopMatrix();
307         gluDeleteQuadric(qobj);
308 }
309
310 /* draw a 3D stroke in "volumetric" style */
311 static void gp_draw_stroke_volumetric_3d(
312         bGPDspoint *points, int totpoints, short thickness,
313         short UNUSED(dflag), short UNUSED(sflag), float diff_mat[4][4], float ink[4])
314 {
315         GLUquadricObj *qobj = gluNewQuadric();
316         
317         float base_modelview[4][4], modelview[4][4];
318         float base_loc[3];
319         
320         bGPDspoint *pt;
321         int i;
322         float fpt[3];
323         
324         /* Get the basic modelview matrix we use for performing calculations */
325         glGetFloatv(GL_MODELVIEW_MATRIX, (float *)base_modelview);
326         copy_v3_v3(base_loc, base_modelview[3]);
327         
328         /* Create the basic view-aligned billboard matrix we're going to actually draw qobj with:
329          * - We need to knock out the rotation so that we are
330          *   simply left with a camera-facing billboard
331          * - The scale factors here are chosen so that the thickness
332          *   is relatively reasonable. Otherwise, it gets far too
333          *   large!
334          */
335         scale_m4_fl(modelview, 0.1f);
336         
337         /* draw each point as a disk... */
338         glPushMatrix();
339         
340         for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
341                 /* color of point */
342                 gp_set_point_color(pt, ink);
343
344                 mul_v3_m4v3(fpt, diff_mat, &pt->x);
345
346                 /* apply translation to base_modelview, so that the translated point is put in the right place */
347                 translate_m4(base_modelview, fpt[0], fpt[1], fpt[2]);
348                 
349                 /* copy the translation component to the billboard matrix we're going to use,
350                  * then reset the base matrix to the original values so that we can do the same
351                  * for the next point without accumulation/pollution effects
352                  */
353                 copy_v3_v3(modelview[3], base_modelview[3]); /* copy offset value */
354                 copy_v3_v3(base_modelview[3], base_loc);     /* restore */
355                 
356                 /* apply our billboard matrix for drawing... */
357                 glLoadMatrixf((float *)modelview);
358                 
359                 /* draw the disk using the current state... */
360                 gluDisk(qobj, 0.0,  pt->pressure * thickness, 32, 1);
361         }
362         
363         glPopMatrix();
364         gluDeleteQuadric(qobj);
365 }
366
367
368 /* --------------- Stroke Fills ----------------- */
369
370 /* Get points of stroke always flat to view not affected by camera view or view position */
371 static void gp_stroke_2d_flat(bGPDspoint *points, int totpoints, float(*points2d)[2], int *r_direction)
372 {
373         bGPDspoint *pt0 = &points[0];
374         bGPDspoint *pt1 = &points[1];
375         bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
376         
377         float locx[3];
378         float locy[3];
379         float loc3[3];
380         float normal[3];
381         
382         /* local X axis (p0 -> p1) */
383         sub_v3_v3v3(locx, &pt1->x, &pt0->x);
384         
385         /* point vector at 3/4 */
386         sub_v3_v3v3(loc3, &pt3->x, &pt0->x);
387         
388         /* vector orthogonal to polygon plane */
389         cross_v3_v3v3(normal, locx, loc3);
390         
391         /* local Y axis (cross to normal/x axis) */
392         cross_v3_v3v3(locy, normal, locx);
393         
394         /* Normalize vectors */
395         normalize_v3(locx);
396         normalize_v3(locy);
397         
398         /* Get all points in local space */
399         for (int i = 0; i < totpoints; i++) {
400                 bGPDspoint *pt = &points[i];
401                 float loc[3];
402                 
403                 /* Get local space using first point as origin */
404                 sub_v3_v3v3(loc, &pt->x, &pt0->x);
405                 
406                 points2d[i][0] = dot_v3v3(loc, locx);
407                 points2d[i][1] = dot_v3v3(loc, locy);
408         }
409         
410         /* Concave (-1), Convex (1), or Autodetect (0)? */
411         *r_direction = (int)locy[2];
412 }
413
414
415 /* Triangulate stroke for high quality fill (this is done only if cache is null or stroke was modified) */
416 static void gp_triangulate_stroke_fill(bGPDstroke *gps)
417 {
418         BLI_assert(gps->totpoints >= 3);
419         
420         /* allocate memory for temporary areas */
421         gps->tot_triangles = gps->totpoints - 2;
422         unsigned int (*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles, "GP Stroke temp triangulation");
423         float (*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints, "GP Stroke temp 2d points");
424         
425         int direction = 0;
426         
427         /* convert to 2d and triangulate */
428         gp_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction);
429         BLI_polyfill_calc((const float(*)[2])points2d, (unsigned int)gps->totpoints, direction, (unsigned int(*)[3])tmp_triangles);
430
431         /* Number of triangles */
432         gps->tot_triangles = gps->totpoints - 2;
433         /* save triangulation data in stroke cache */
434         if (gps->tot_triangles > 0) {
435                 if (gps->triangles == NULL) {
436                         gps->triangles = MEM_callocN(sizeof(*gps->triangles) * gps->tot_triangles, "GP Stroke triangulation");
437                 }
438                 else {
439                         gps->triangles = MEM_recallocN(gps->triangles, sizeof(*gps->triangles) * gps->tot_triangles);
440                 }
441                 
442                 for (int i = 0; i < gps->tot_triangles; i++) {
443                         bGPDtriangle *stroke_triangle = &gps->triangles[i];
444                         memcpy(stroke_triangle->verts, tmp_triangles[i], sizeof(uint[3]));
445                 }
446         }
447         else {
448                 /* No triangles needed - Free anything allocated previously */
449                 if (gps->triangles)
450                         MEM_freeN(gps->triangles);
451                         
452                 gps->triangles = NULL;
453         }
454         
455         /* disable recalculation flag */
456         if (gps->flag & GP_STROKE_RECALC_CACHES) {
457                 gps->flag &= ~GP_STROKE_RECALC_CACHES;
458         }
459         
460         /* clear memory */
461         if (tmp_triangles) MEM_freeN(tmp_triangles);
462         if (points2d) MEM_freeN(points2d);
463 }
464
465
466 /* draw fills for shapes */
467 static void gp_draw_stroke_fill(
468         bGPdata *gpd, bGPDstroke *gps,
469         int offsx, int offsy, int winx, int winy, float diff_mat[4][4])
470 {
471         bGPDpalettecolor *palcolor;
472         int i;
473         float fpt[3];
474
475         BLI_assert(gps->totpoints >= 3);
476
477         palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
478
479         /* Triangulation fill if high quality flag is enabled */
480         if (palcolor->flag & PC_COLOR_HQ_FILL) {
481                 bGPDtriangle *stroke_triangle;
482                 bGPDspoint *pt;
483
484                 /* Calculate triangles cache for filling area (must be done only after changes) */
485                 if ((gps->flag & GP_STROKE_RECALC_CACHES) || (gps->tot_triangles == 0) || (gps->triangles == NULL)) {
486                         gp_triangulate_stroke_fill(gps);
487                 }
488                 /* Draw all triangles for filling the polygon (cache must be calculated before) */
489                 BLI_assert(gps->tot_triangles >= 1);
490                 glBegin(GL_TRIANGLES);
491                 if (gps->flag & GP_STROKE_3DSPACE) {
492                         for (i = 0, stroke_triangle = gps->triangles; i < gps->tot_triangles; i++, stroke_triangle++) {
493                                 for (int j = 0; j < 3; j++) {
494                                         pt = &gps->points[stroke_triangle->verts[j]];
495                                         mul_v3_m4v3(fpt, diff_mat, &pt->x);
496                                         glVertex3fv(fpt);
497                                 }
498                         }
499                 }
500                 else {
501                         for (i = 0, stroke_triangle = gps->triangles; i < gps->tot_triangles; i++, stroke_triangle++) {
502                                 for (int j = 0; j < 3; j++) {
503                                         float co[2];
504                                         pt = &gps->points[stroke_triangle->verts[j]];
505                                         mul_v3_m4v3(fpt, diff_mat, &pt->x);
506                                         gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
507                                         glVertex2fv(co);
508                                 }
509                         }
510                 }
511                 glEnd();
512         }
513         else {
514                 /* As an initial implementation, we use the OpenGL filled polygon drawing
515                  * here since it's the easiest option to implement for this case. It does
516                  * come with limitations (notably for concave shapes), though it shouldn't
517                  * be much of an issue in most cases.
518                  *
519                  * We keep this legacy implementation around despite now having the high quality
520                  * fills, as this is necessary for keeping everything working nicely for files
521                  * created using old versions of Blender which may have depended on the artifacts
522                  * the old fills created.
523                  */
524                 bGPDspoint *pt;
525
526                 glBegin(GL_POLYGON);
527                 for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
528                         if (gps->flag & GP_STROKE_3DSPACE) {
529                                 mul_v3_m4v3(fpt, diff_mat, &pt->x);
530                                 glVertex3fv(fpt);
531                         }
532                         else {
533                                 float co[2];
534                                 mul_v3_m4v3(fpt, diff_mat, &pt->x);
535                                 gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
536                                 glVertex2fv(co);
537                         }
538                 }
539
540                 glEnd();
541         }
542 }
543
544 /* ----- Existing Strokes Drawing (3D and Point) ------ */
545
546 /* draw a given stroke - just a single dot (only one point) */
547 static void gp_draw_stroke_point(
548         bGPDspoint *points, short thickness, short dflag, short sflag,
549         int offsx, int offsy, int winx, int winy, float diff_mat[4][4], float ink[4])
550 {
551         float fpt[3];
552         bGPDspoint *pt = &points[0];
553
554         /* color of point */
555         gp_set_point_color(pt, ink);
556
557         /* set point thickness (since there's only one of these) */
558         glPointSize((float)(thickness + 2) * points->pressure);
559         
560         /* get final position using parent matrix */
561         mul_v3_m4v3(fpt, diff_mat, &pt->x);
562
563         /* draw point */
564         if (sflag & GP_STROKE_3DSPACE) {
565                 glBegin(GL_POINTS);
566                 glVertex3fv(fpt);
567                 glEnd();
568         }
569         else {
570                 float co[2];
571                 
572                 /* get coordinates of point */
573                 gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
574                 
575                 /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, simple dot looks ok
576                  *  - also mandatory in if Image Editor 'image-based' dot
577                  */
578                 if ((thickness < GP_DRAWTHICKNESS_SPECIAL) ||
579                     ((dflag & GP_DRAWDATA_IEDITHACK) && (sflag & GP_STROKE_2DSPACE)))
580                 {
581                         glBegin(GL_POINTS);
582                         glVertex2fv(co);
583                         glEnd();
584                 }
585                 else {
586                         /* draw filled circle as is done in circf (but without the matrix push/pops which screwed things up) */
587                         GLUquadricObj *qobj = gluNewQuadric();
588                         
589                         gluQuadricDrawStyle(qobj, GLU_FILL);
590                         
591                         /* need to translate drawing position, but must reset after too! */
592                         glTranslate2fv(co);
593                         gluDisk(qobj, 0.0,  thickness, 32, 1);
594                         glTranslatef(-co[0], -co[1], 0.0);
595                         
596                         gluDeleteQuadric(qobj);
597                 }
598         }
599 }
600
601 /* draw a given stroke in 3d (i.e. in 3d-space), using simple ogl lines */
602 static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness, bool debug,
603                               short UNUSED(sflag), float diff_mat[4][4], float ink[4], bool cyclic)
604 {
605         bGPDspoint *pt, *pt2;
606         float curpressure = points[0].pressure;
607         int i;
608         float fpt[3];
609         float cyclic_fpt[3];
610
611         /* draw stroke curve */
612         glLineWidth(max_ff(curpressure * thickness, 1.0f));
613         glBegin(GL_LINE_STRIP);
614         for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
615                 gp_set_point_color(pt, ink);
616
617                 /* if there was a significant pressure change, stop the curve, change the thickness of the stroke,
618                  * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP)
619                  * Note: we want more visible levels of pressures when thickness is bigger.
620                  */
621                 if (fabsf(pt->pressure - curpressure) > 0.2f / (float)thickness) {
622                         glEnd();
623                         curpressure = pt->pressure;
624                         glLineWidth(max_ff(curpressure * thickness, 1.0f));
625                         glBegin(GL_LINE_STRIP);
626                         
627                         /* need to roll-back one point to ensure that there are no gaps in the stroke */
628                         if (i != 0) { 
629                                 pt2 = pt - 1;
630                                 mul_v3_m4v3(fpt, diff_mat, &pt2->x);
631                                 glVertex3fv(fpt);
632                         }
633                         
634                         /* now the point we want... */
635                         mul_v3_m4v3(fpt, diff_mat, &pt->x);
636                         glVertex3fv(fpt);
637                 }
638                 else {
639                         mul_v3_m4v3(fpt, diff_mat, &pt->x);
640                         glVertex3fv(fpt);
641                 }
642                 /* saves first point to use in cyclic */
643                 if (i == 0) {
644                         copy_v3_v3(cyclic_fpt, fpt);
645                 }
646         }
647         /* if cyclic draw line to first point */
648         if (cyclic) {
649                 glVertex3fv(cyclic_fpt);
650         }
651         glEnd();
652
653         /* draw debug points of curve on top? */
654         /* XXX: for now, we represent "selected" strokes in the same way as debug, which isn't used anymore */
655         if (debug) {
656                 glPointSize((float)(thickness + 2));
657                 
658                 glBegin(GL_POINTS);
659                 for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
660                         mul_v3_m4v3(fpt, diff_mat, &pt->x);
661                         glVertex3fv(fpt);
662                 }
663                 glEnd();
664
665         }
666 }
667
668 /* ----- Fancy 2D-Stroke Drawing ------ */
669
670 /* draw a given stroke in 2d */
671 static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag,
672                               bool debug, int offsx, int offsy, int winx, int winy, float diff_mat[4][4], float ink[4])
673 {
674         /* otherwise thickness is twice that of the 3D view */
675         float thickness = (float)thickness_s * 0.5f;
676         
677         /* strokes in Image Editor need a scale factor, since units there are not pixels! */
678         float scalefac  = 1.0f;
679         if ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) {
680                 scalefac = 0.001f;
681         }
682         
683         /* tessellation code - draw stroke as series of connected quads with connection
684          * edges rotated to minimize shrinking artifacts, and rounded endcaps
685          */
686         {
687                 bGPDspoint *pt1, *pt2;
688                 float s0[2], s1[2];     /* segment 'center' points */
689                 float pm[2];  /* normal from previous segment. */
690                 int i;
691                 float fpt[3];
692                 
693                 glShadeModel(GL_FLAT);
694                 glBegin(GL_QUADS);
695
696                 /* get x and y coordinates from first point */
697                 mul_v3_m4v3(fpt, diff_mat, &points->x);
698                 gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s0);
699
700                 for (i = 0, pt1 = points, pt2 = points + 1; i < (totpoints - 1); i++, pt1++, pt2++) {
701                         float t0[2], t1[2];     /* tessellated coordinates */
702                         float m1[2], m2[2];     /* gradient and normal */
703                         float mt[2], sc[2];     /* gradient for thickness, point for end-cap */
704                         float pthick;           /* thickness at segment point */
705
706                         /* get x and y coordinates from point2 (point1 has already been computed in previous iteration). */
707                         mul_v3_m4v3(fpt, diff_mat, &pt2->x);
708                         gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s1);
709                         
710                         /* calculate gradient and normal - 'angle'=(ny/nx) */
711                         m1[1] = s1[1] - s0[1];
712                         m1[0] = s1[0] - s0[0];
713                         normalize_v2(m1);
714                         m2[1] = -m1[0];
715                         m2[0] = m1[1];
716                         
717                         /* always use pressure from first point here */
718                         pthick = (pt1->pressure * thickness * scalefac);
719                         
720                         /* color of point */
721                         gp_set_point_color(pt1, ink);
722
723                         /* if the first segment, start of segment is segment's normal */
724                         if (i == 0) {
725                                 /* draw start cap first
726                                  *      - make points slightly closer to center (about halfway across)
727                                  */
728                                 mt[0] = m2[0] * pthick * 0.5f;
729                                 mt[1] = m2[1] * pthick * 0.5f;
730                                 sc[0] = s0[0] - (m1[0] * pthick * 0.75f);
731                                 sc[1] = s0[1] - (m1[1] * pthick * 0.75f);
732                                 
733                                 t0[0] = sc[0] - mt[0];
734                                 t0[1] = sc[1] - mt[1];
735                                 t1[0] = sc[0] + mt[0];
736                                 t1[1] = sc[1] + mt[1];
737                                 
738                                 glVertex2fv(t0);
739                                 glVertex2fv(t1);
740                                 
741                                 /* calculate points for start of segment */
742                                 mt[0] = m2[0] * pthick;
743                                 mt[1] = m2[1] * pthick;
744                                 
745                                 t0[0] = s0[0] - mt[0];
746                                 t0[1] = s0[1] - mt[1];
747                                 t1[0] = s0[0] + mt[0];
748                                 t1[1] = s0[1] + mt[1];
749                                 
750                                 /* draw this line twice (first to finish off start cap, then for stroke) */
751                                 glVertex2fv(t1);
752                                 glVertex2fv(t0);
753                                 glVertex2fv(t0);
754                                 glVertex2fv(t1);
755                         }
756                         /* if not the first segment, use bisector of angle between segments */
757                         else {
758                                 float mb[2];         /* bisector normal */
759                                 float athick, dfac;  /* actual thickness, difference between thicknesses */
760                                 
761                                 /* calculate gradient of bisector (as average of normals) */
762                                 mb[0] = (pm[0] + m2[0]) / 2;
763                                 mb[1] = (pm[1] + m2[1]) / 2;
764                                 normalize_v2(mb);
765                                 
766                                 /* calculate gradient to apply
767                                  *  - as basis, use just pthick * bisector gradient
768                                  *      - if cross-section not as thick as it should be, add extra padding to fix it
769                                  */
770                                 mt[0] = mb[0] * pthick;
771                                 mt[1] = mb[1] * pthick;
772                                 athick = len_v2(mt);
773                                 dfac = pthick - (athick * 2);
774                                 
775                                 if (((athick * 2.0f) < pthick) && (IS_EQF(athick, pthick) == 0)) {
776                                         mt[0] += (mb[0] * dfac);
777                                         mt[1] += (mb[1] * dfac);
778                                 }
779                                 
780                                 /* calculate points for start of segment */
781                                 t0[0] = s0[0] - mt[0];
782                                 t0[1] = s0[1] - mt[1];
783                                 t1[0] = s0[0] + mt[0];
784                                 t1[1] = s0[1] + mt[1];
785                                 
786                                 /* draw this line twice (once for end of current segment, and once for start of next) */
787                                 glVertex2fv(t1);
788                                 glVertex2fv(t0);
789                                 glVertex2fv(t0);
790                                 glVertex2fv(t1);
791                         }
792                         
793                         /* if last segment, also draw end of segment (defined as segment's normal) */
794                         if (i == totpoints - 2) {
795                                 /* for once, we use second point's pressure (otherwise it won't be drawn) */
796                                 pthick = (pt2->pressure * thickness * scalefac);
797                                 
798                                 /* color of point */
799                                 gp_set_point_color(pt2, ink);
800
801                                 /* calculate points for end of segment */
802                                 mt[0] = m2[0] * pthick;
803                                 mt[1] = m2[1] * pthick;
804                                 
805                                 t0[0] = s1[0] - mt[0];
806                                 t0[1] = s1[1] - mt[1];
807                                 t1[0] = s1[0] + mt[0];
808                                 t1[1] = s1[1] + mt[1];
809                                 
810                                 /* draw this line twice (once for end of stroke, and once for endcap)*/
811                                 glVertex2fv(t1);
812                                 glVertex2fv(t0);
813                                 glVertex2fv(t0);
814                                 glVertex2fv(t1);
815                                 
816                                 
817                                 /* draw end cap as last step
818                                  *      - make points slightly closer to center (about halfway across)
819                                  */
820                                 mt[0] = m2[0] * pthick * 0.5f;
821                                 mt[1] = m2[1] * pthick * 0.5f;
822                                 sc[0] = s1[0] + (m1[0] * pthick * 0.75f);
823                                 sc[1] = s1[1] + (m1[1] * pthick * 0.75f);
824                                 
825                                 t0[0] = sc[0] - mt[0];
826                                 t0[1] = sc[1] - mt[1];
827                                 t1[0] = sc[0] + mt[0];
828                                 t1[1] = sc[1] + mt[1];
829                                 
830                                 glVertex2fv(t1);
831                                 glVertex2fv(t0);
832                         }
833                         
834                         /* store computed point2 coordinates as point1 ones of next segment. */
835                         copy_v2_v2(s0, s1);
836                         /* store stroke's 'natural' normal for next stroke to use */
837                         copy_v2_v2(pm, m2);
838                 }
839                 
840                 glEnd();
841                 glShadeModel(GL_SMOOTH);
842         }
843         
844         /* draw debug points of curve on top? (original stroke points) */
845         if (debug) {
846                 bGPDspoint *pt;
847                 int i;
848                 float fpt[3];
849
850                 glPointSize((float)(thickness_s + 2));
851                 
852                 glBegin(GL_POINTS);
853                 for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
854                         float co[2];
855                         mul_v3_m4v3(fpt, diff_mat, &pt->x);
856                         gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
857                         glVertex2fv(co);
858                 }
859                 glEnd();
860         }
861 }
862
863 /* ----- Strokes Drawing ------ */
864
865 /* Helper for doing all the checks on whether a stroke can be drawn */
866 static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag)
867 {
868         /* skip stroke if it isn't in the right display space for this drawing context */
869         /* 1) 3D Strokes */
870         if ((dflag & GP_DRAWDATA_ONLY3D) && !(gps->flag & GP_STROKE_3DSPACE))
871                 return false;
872         if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE))
873                 return false;
874         
875         /* 2) Screen Space 2D Strokes */
876         if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE))
877                 return false;
878         if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE))
879                 return false;
880         
881         /* 3) Image Space (2D) */
882         if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE))
883                 return false;
884         if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE))
885                 return false;
886         
887         
888         /* skip stroke if it doesn't have any valid data */
889         if ((gps->points == NULL) || (gps->totpoints < 1))
890                 return false;
891         
892         /* stroke can be drawn */
893         return true;
894 }
895
896 /* draw a set of strokes */
897 static void gp_draw_strokes(
898         bGPdata *gpd, bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag,
899         bool debug, short lthick, const float opacity, const float tintcolor[4],
900         const bool onion, const bool custonion, float diff_mat[4][4])
901 {
902         bGPDstroke *gps;
903         float tcolor[4];
904         float tfill[4];
905         short sthickness;
906         float ink[4];
907
908         for (gps = gpf->strokes.first; gps; gps = gps->next) {
909                 /* check if stroke can be drawn */
910                 if (gp_can_draw_stroke(gps, dflag) == false) {
911                         continue;
912                 }
913                 /* check if the color is visible */
914                 bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
915                 if ((palcolor == NULL) ||
916                     (palcolor->flag & PC_COLOR_HIDE) ||
917                     /* if onion and ghost flag do not draw*/
918                     (onion && (palcolor->flag & PC_COLOR_ONIONSKIN)))
919                 {
920                         continue;
921                 }
922
923                 /* calculate thickness */
924                 sthickness = gps->thickness + lthick;
925
926                 /* check which stroke-drawer to use */
927                 if (dflag & GP_DRAWDATA_ONLY3D) {
928                         const int no_xray = (dflag & GP_DRAWDATA_NO_XRAY);
929                         int mask_orig = 0;
930
931                         if (no_xray) {
932                                 glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
933                                 glDepthMask(0);
934                                 glEnable(GL_DEPTH_TEST);
935
936                                 /* first arg is normally rv3d->dist, but this isn't
937                                  * available here and seems to work quite well without */
938                                 bglPolygonOffset(1.0f, 1.0f);
939 #if 0
940                                 glEnable(GL_POLYGON_OFFSET_LINE);
941                                 glPolygonOffset(-1.0f, -1.0f);
942 #endif
943                         }
944
945                         /* 3D Fill */
946                         //if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
947                         if (gps->totpoints >= 3) {
948                                 /* set color using palette, tint color and opacity */
949                                 interp_v3_v3v3(tfill, palcolor->fill, tintcolor, tintcolor[3]);
950                                 tfill[3] = palcolor->fill[3] * opacity;
951                                 if (tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) {
952                                         if (!onion) {
953                                                 glColor4fv(tfill);
954                                         }
955                                         else {
956                                                 if (custonion) {
957                                                         glColor4fv(tintcolor);
958                                                 }
959                                                 else {
960                                                         ARRAY_SET_ITEMS(tfill, UNPACK3(palcolor->fill), tintcolor[3]);
961                                                         glColor4fv(tfill);
962                                                 }
963                                         }
964                                         gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat);
965                                 }
966                         }
967
968                         /* 3D Stroke */
969                         /* set color using palette, tint color and opacity */
970                         if (!onion) {
971                                 interp_v3_v3v3(tcolor, palcolor->color, tintcolor, tintcolor[3]);
972                                 tcolor[3] = palcolor->color[3] * opacity;
973                                 copy_v4_v4(ink, tcolor);
974                         }
975                         else {
976                                 if (custonion) {
977                                         copy_v4_v4(ink, tintcolor);
978                                 }
979                                 else {
980                                         ARRAY_SET_ITEMS(tcolor, palcolor->color[0], palcolor->color[1], palcolor->color[2], opacity);
981                                         copy_v4_v4(ink, tcolor);
982                                 }
983                         }
984                         if (palcolor->flag & PC_COLOR_VOLUMETRIC) {
985                                 /* volumetric stroke drawing */
986                                 gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, sthickness, dflag, gps->flag, diff_mat, ink);
987                         }
988                         else {
989                                 /* 3D Lines - OpenGL primitives-based */
990                                 if (gps->totpoints == 1) {
991                                         gp_draw_stroke_point(gps->points, sthickness, dflag, gps->flag, offsx, offsy, winx, winy,
992                                                              diff_mat, ink);
993                                 }
994                                 else {
995                                         gp_draw_stroke_3d(gps->points, gps->totpoints, sthickness, debug, gps->flag,
996                                                           diff_mat, ink, gps->flag & GP_STROKE_CYCLIC);
997                                 }
998                         }
999                         if (no_xray) {
1000                                 glDepthMask(mask_orig);
1001                                 glDisable(GL_DEPTH_TEST);
1002
1003                                 bglPolygonOffset(0.0, 0.0);
1004 #if 0
1005                                 glDisable(GL_POLYGON_OFFSET_LINE);
1006                                 glPolygonOffset(0, 0);
1007 #endif
1008                         }
1009                 }
1010                 else {
1011                         /* 2D - Fill */
1012                         if (gps->totpoints >= 3) {
1013                                 /* set color using palette, tint color and opacity */
1014                                 interp_v3_v3v3(tfill, palcolor->fill, tintcolor, tintcolor[3]);
1015                                 tfill[3] = palcolor->fill[3] * opacity;
1016                                 if (tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) {
1017                                         if (!onion) {
1018                                                 glColor4fv(tfill);
1019                                         }
1020                                         else {
1021                                                 if (custonion) {
1022                                                         glColor4fv(tintcolor);
1023                                                 }
1024                                                 else {
1025                                                         ARRAY_SET_ITEMS(tfill, palcolor->fill[0], palcolor->fill[1], palcolor->fill[2],
1026                                                                         tintcolor[3]);
1027                                                         glColor4fv(tfill);
1028                                                 }
1029                                         }
1030                                         gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat);
1031                                 }
1032                         }
1033
1034                         /* 2D Strokes... */
1035                         /* set color using palette, tint color and opacity */
1036                         if (!onion) {
1037                                 interp_v3_v3v3(tcolor, palcolor->color, tintcolor, tintcolor[3]);
1038                                 tcolor[3] = palcolor->color[3] * opacity;
1039                                 copy_v4_v4(ink, tcolor);
1040                         }
1041                         else {
1042                                 if (custonion) {
1043                                         copy_v4_v4(ink, tintcolor);
1044                                 }
1045                                 else {
1046                                         ARRAY_SET_ITEMS(tcolor, palcolor->color[0], palcolor->color[1], palcolor->color[2], opacity);
1047                                         copy_v4_v4(ink, tcolor);
1048                                 }
1049                         }
1050                         if (palcolor->flag & PC_COLOR_VOLUMETRIC) {
1051                                 /* blob/disk-based "volumetric" drawing */
1052                                 gp_draw_stroke_volumetric_2d(gps->points, gps->totpoints, sthickness, dflag, gps->flag,
1053                                                              offsx, offsy, winx, winy, diff_mat, ink);
1054                         }
1055                         else {
1056                                 /* normal 2D strokes */
1057                                 if (gps->totpoints == 1) {
1058                                         gp_draw_stroke_point(gps->points, sthickness, dflag, gps->flag, offsx, offsy, winx, winy,
1059                                                              diff_mat, ink);
1060                                 }
1061                                 else {
1062                                         gp_draw_stroke_2d(gps->points, gps->totpoints, sthickness, dflag, gps->flag, debug,
1063                                                           offsx, offsy, winx, winy, diff_mat, ink);
1064                                 }
1065                         }
1066                 }
1067         }
1068 }
1069
1070 /* Draw selected verts for strokes being edited */
1071 static void gp_draw_strokes_edit(
1072         bGPdata *gpd, bGPDframe *gpf, int offsx, int offsy, int winx, int winy, short dflag,
1073         short lflag, float diff_mat[4][4], float alpha)
1074 {
1075         bGPDstroke *gps;
1076         
1077         /* if alpha 0 do not draw */
1078         if (alpha == 0.0f)
1079                 return;
1080
1081         const bool no_xray = (dflag & GP_DRAWDATA_NO_XRAY) != 0;
1082         int mask_orig = 0;
1083
1084         /* set up depth masks... */
1085         if (dflag & GP_DRAWDATA_ONLY3D) {
1086                 if (no_xray) {
1087                         glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
1088                         glDepthMask(0);
1089                         glEnable(GL_DEPTH_TEST);
1090                         
1091                         /* first arg is normally rv3d->dist, but this isn't
1092                          * available here and seems to work quite well without */
1093                         bglPolygonOffset(1.0f, 1.0f);
1094 #if 0
1095                         glEnable(GL_POLYGON_OFFSET_LINE);
1096                         glPolygonOffset(-1.0f, -1.0f);
1097 #endif
1098                 }
1099         }
1100         
1101         
1102         /* draw stroke verts */
1103         for (gps = gpf->strokes.first; gps; gps = gps->next) {
1104                 bGPDspoint *pt;
1105                 float vsize, bsize;
1106                 int i;
1107                 float fpt[3];
1108
1109                 /* check if stroke can be drawn */
1110                 if (gp_can_draw_stroke(gps, dflag) == false)
1111                         continue;
1112                 
1113                 /* Optimisation: only draw points for selected strokes
1114                  * We assume that selected points can only occur in
1115                  * strokes that are selected too.
1116                  */
1117                 if ((gps->flag & GP_STROKE_SELECT) == 0)
1118                         continue;
1119                 
1120                 /* verify palette color lock */
1121                 {
1122                         bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
1123                         if (palcolor != NULL) {
1124                                 if (palcolor->flag & PC_COLOR_HIDE) {
1125                                         continue;
1126                                 }
1127                                 if (((lflag & GP_LAYER_UNLOCK_COLOR) == 0) && (palcolor->flag & PC_COLOR_LOCKED)) {
1128                                         continue;
1129                                 }
1130                         }
1131                 }
1132
1133                 /* Get size of verts:
1134                  * - The selected state needs to be larger than the unselected state so that
1135                  *   they stand out more.
1136                  * - We use the theme setting for size of the unselected verts
1137                  */
1138                 bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE);
1139                 if ((int)bsize > 8) {
1140                         vsize = 10.0f;
1141                         bsize = 8.0f;
1142                 }
1143                 else {
1144                         vsize = bsize + 2;
1145                 }
1146                 
1147                 /* First Pass: Draw all the verts (i.e. these become the unselected state) */
1148                 /* for now, we assume that the base color of the points is not too close to the real color */
1149                 /* set color using palette */
1150                 bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
1151                 glColor3fv(palcolor->color);
1152
1153                 glPointSize(bsize);
1154                 
1155                 glBegin(GL_POINTS);
1156                 for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
1157                         if (gps->flag & GP_STROKE_3DSPACE) {
1158                                 mul_v3_m4v3(fpt, diff_mat, &pt->x);
1159                                 glVertex3fv(fpt);
1160                         }
1161                         else {
1162                                 float co[2];
1163                                 mul_v3_m4v3(fpt, diff_mat, &pt->x);
1164                                 gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
1165                                 glVertex2fv(co);
1166                         }
1167                 }
1168                 glEnd();
1169                 
1170                 
1171                 /* Second Pass: Draw only verts which are selected */
1172                 float curColor[4];
1173                 UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, curColor);
1174                 glColor4f(curColor[0], curColor[1], curColor[2], alpha);
1175
1176                 glPointSize(vsize);
1177                 
1178                 glBegin(GL_POINTS);
1179                 for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
1180                         if (pt->flag & GP_SPOINT_SELECT) {
1181                                 if (gps->flag & GP_STROKE_3DSPACE) {
1182                                         mul_v3_m4v3(fpt, diff_mat, &pt->x);
1183                                         glVertex3fv(fpt);
1184                                 }
1185                                 else {
1186                                         float co[2];
1187                                         
1188                                         mul_v3_m4v3(fpt, diff_mat, &pt->x);
1189                                         gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
1190                                         glVertex2fv(co);
1191                                 }
1192                         }
1193                 }
1194                 glEnd();
1195
1196                 /* Draw start and end point if enabled stroke direction hint */
1197                 if ((gpd->flag & GP_DATA_SHOW_DIRECTION) && (gps->totpoints > 1)) {
1198                         bGPDspoint *p;
1199                         
1200                         glPointSize(vsize + 4);
1201                         glBegin(GL_POINTS);
1202
1203                         /* start point in green bigger */
1204                         glColor3f(0.0f, 1.0f, 0.0f);
1205                         p = &gps->points[0];
1206                         mul_v3_m4v3(fpt, diff_mat, &p->x);
1207                         glVertex3fv(fpt);
1208                         glEnd();
1209
1210                         /* end point in red smaller */
1211                         glPointSize(vsize + 1);
1212                         glBegin(GL_POINTS);
1213
1214                         glColor3f(1.0f, 0.0f, 0.0f);
1215                         p = &gps->points[gps->totpoints - 1];
1216                         mul_v3_m4v3(fpt, diff_mat, &p->x);
1217                         glVertex3fv(fpt);
1218                         glEnd();
1219                 }
1220         }
1221         
1222         
1223         /* clear depth mask */
1224         if (dflag & GP_DRAWDATA_ONLY3D) {
1225                 if (no_xray) {
1226                         glDepthMask(mask_orig);
1227                         glDisable(GL_DEPTH_TEST);
1228                         
1229                         bglPolygonOffset(0.0, 0.0);
1230 #if 0
1231                         glDisable(GL_POLYGON_OFFSET_LINE);
1232                         glPolygonOffset(0, 0);
1233 #endif
1234                 }
1235         }
1236 }
1237
1238 /* ----- General Drawing ------ */
1239
1240 /* draw onion-skinning for a layer */
1241 static void gp_draw_onionskins(
1242         bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, int offsx, int offsy, int winx, int winy,
1243         int UNUSED(cfra), int dflag, bool debug, float diff_mat[4][4])
1244 {
1245         const float default_color[3] = {UNPACK3(U.gpencil_new_layer_col)};
1246         const float alpha = 1.0f;
1247         float color[4];
1248
1249         /* 1) Draw Previous Frames First */
1250         if (gpl->flag & GP_LAYER_GHOST_PREVCOL) {
1251                 copy_v3_v3(color, gpl->gcolor_prev);
1252         }
1253         else {
1254                 copy_v3_v3(color, default_color);
1255         }
1256         
1257         if (gpl->gstep > 0) {
1258                 bGPDframe *gf;
1259                 float fac;
1260                 
1261                 /* draw previous frames first */
1262                 for (gf = gpf->prev; gf; gf = gf->prev) {
1263                         /* check if frame is drawable */
1264                         if ((gpf->framenum - gf->framenum) <= gpl->gstep) {
1265                                 /* alpha decreases with distance from curframe index */
1266                                 fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1));
1267                                 color[3] = alpha * fac * 0.66f;
1268                                 gp_draw_strokes(gpd, gf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
1269                                                 true, gpl->flag & GP_LAYER_GHOST_PREVCOL, diff_mat);
1270                         }
1271                         else
1272                                 break;
1273                 }
1274         }
1275         else if (gpl->gstep == 0) {
1276                 /* draw the strokes for the ghost frames (at half of the alpha set by user) */
1277                 if (gpf->prev) {
1278                         color[3] = (alpha / 7);
1279                         gp_draw_strokes(gpd, gpf->prev, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
1280                                         true, gpl->flag & GP_LAYER_GHOST_PREVCOL, diff_mat);
1281                 }
1282         }
1283         else {
1284                 /* don't draw - disabled */
1285         }
1286         
1287         
1288         /* 2) Now draw next frames */
1289         if (gpl->flag & GP_LAYER_GHOST_NEXTCOL) {
1290                 copy_v3_v3(color, gpl->gcolor_next);
1291         }
1292         else {
1293                 copy_v3_v3(color, default_color);
1294         }
1295         
1296         if (gpl->gstep_next > 0) {
1297                 bGPDframe *gf;
1298                 float fac;
1299                 
1300                 /* now draw next frames */
1301                 for (gf = gpf->next; gf; gf = gf->next) {
1302                         /* check if frame is drawable */
1303                         if ((gf->framenum - gpf->framenum) <= gpl->gstep_next) {
1304                                 /* alpha decreases with distance from curframe index */
1305                                 fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep_next + 1));
1306                                 color[3] = alpha * fac * 0.66f;
1307                                 gp_draw_strokes(gpd, gf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
1308                                                 true, gpl->flag & GP_LAYER_GHOST_NEXTCOL, diff_mat);
1309                         }
1310                         else
1311                                 break;
1312                 }
1313         }
1314         else if (gpl->gstep_next == 0) {
1315                 /* draw the strokes for the ghost frames (at half of the alpha set by user) */
1316                 if (gpf->next) {
1317                         color[3] = (alpha / 4);
1318                         gp_draw_strokes(gpd, gpf->next, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
1319                                         true, gpl->flag & GP_LAYER_GHOST_NEXTCOL, diff_mat);
1320                 }
1321         }
1322         else {
1323                 /* don't draw - disabled */
1324         }
1325         
1326 }
1327
1328 /* draw interpolate strokes (used only while operator is running) */
1329 void ED_gp_draw_interpolation(tGPDinterpolate *tgpi, const int type)
1330 {
1331         tGPDinterpolate_layer *tgpil;
1332         float diff_mat[4][4];
1333         float color[4];
1334
1335         int offsx = 0;
1336         int offsy = 0;
1337         int winx = tgpi->ar->winx;
1338         int winy = tgpi->ar->winy;
1339
1340         UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, color);
1341         color[3] = 0.6f;
1342         int dflag = 0; 
1343         /* if 3d stuff, enable flags */
1344         if (type == REGION_DRAW_POST_VIEW) {
1345                 dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS);
1346         }
1347
1348         /* turn on alpha-blending */
1349         glEnable(GL_BLEND);
1350         for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
1351                 /* calculate parent position */
1352                 ED_gpencil_parent_location(tgpil->gpl, diff_mat);
1353                 if (tgpil->interFrame) {
1354                         gp_draw_strokes(tgpi->gpd, tgpil->interFrame, offsx, offsy, winx, winy, dflag, false,
1355                                 tgpil->gpl->thickness, 1.0f, color, true, true, diff_mat);
1356                 }
1357         }
1358         glDisable(GL_BLEND);
1359 }
1360
1361 /* loop over gpencil data layers, drawing them */
1362 static void gp_draw_data_layers(
1363         bGPDbrush *brush, float alpha, bGPdata *gpd,
1364         int offsx, int offsy, int winx, int winy, int cfra, int dflag)
1365 {
1366         bGPDlayer *gpl;
1367         float diff_mat[4][4];
1368
1369         for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
1370                 bGPDframe *gpf;
1371                 /* calculate parent position */
1372                 ED_gpencil_parent_location(gpl, diff_mat);
1373
1374                 bool debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? true : false;
1375                 short lthick = brush->thickness + gpl->thickness;
1376                 
1377                 /* don't draw layer if hidden */
1378                 if (gpl->flag & GP_LAYER_HIDE)
1379                         continue;
1380                 
1381                 /* get frame to draw */
1382                 gpf = BKE_gpencil_layer_getframe(gpl, cfra, 0);
1383                 if (gpf == NULL)
1384                         continue;
1385                 
1386                 /* set basic stroke thickness */
1387                 glLineWidth(lthick);
1388                 
1389                 /* Add layer drawing settings to the set of "draw flags"
1390                  * NOTE: If the setting doesn't apply, it *must* be cleared,
1391                  *       as dflag's carry over from the previous layer
1392                  */
1393 #define GP_DRAWFLAG_APPLY(condition, draw_flag_value)     { \
1394                         if (condition) dflag |= (draw_flag_value);      \
1395                         else           dflag &= ~(draw_flag_value);     \
1396                 } (void)0
1397                 
1398                 /* xray... */
1399                 GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_NO_XRAY), GP_DRAWDATA_NO_XRAY);
1400                 
1401                 /* volumetric strokes... */
1402                 GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_VOLUMETRIC), GP_DRAWDATA_VOLUMETRIC);
1403
1404                 /* HQ fills... */
1405                 GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_HQ_FILL), GP_DRAWDATA_HQ_FILL);
1406
1407 #undef GP_DRAWFLAG_APPLY
1408                 
1409                 /* Draw 'onionskins' (frame left + right)
1410                  *   - It is only possible to show these if the option is enabled
1411                  *   - The "no onions" flag prevents ghosts from appearing during animation playback/scrubbing
1412                  *     and in renders
1413                  *   - The per-layer "always show" flag however overrides the playback/render restriction,
1414                  *     allowing artists to selectively turn onionskins on/off during playback
1415                  */
1416                 if ((gpl->flag & GP_LAYER_ONIONSKIN) && 
1417                     ((dflag & GP_DRAWDATA_NO_ONIONS) == 0 || (gpl->flag & GP_LAYER_GHOST_ALWAYS))) 
1418                 {
1419                         /* Drawing method - only immediately surrounding (gstep = 0),
1420                          * or within a frame range on either side (gstep > 0)
1421                          */
1422                         gp_draw_onionskins(gpd, gpl, gpf, offsx, offsy, winx, winy, cfra, dflag, debug, diff_mat);
1423                 }
1424                 
1425                 /* draw the strokes already in active frame */
1426                 gp_draw_strokes(gpd, gpf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness,
1427                                 gpl->opacity, gpl->tintcolor, false, false, diff_mat);
1428                 
1429                 /* Draw verts of selected strokes
1430                  *  - when doing OpenGL renders, we don't want to be showing these, as that ends up flickering
1431                  *      - locked layers can't be edited, so there's no point showing these verts
1432                  *    as they will have no bearings on what gets edited
1433                  *  - only show when in editmode, since operators shouldn't work otherwise
1434                  *    (NOTE: doing it this way means that the toggling editmode shows visible change immediately)
1435                  */
1436                 /* XXX: perhaps we don't want to show these when users are drawing... */
1437                 if ((G.f & G_RENDER_OGL) == 0 &&
1438                     (gpl->flag & GP_LAYER_LOCKED) == 0 &&
1439                     (gpd->flag & GP_DATA_STROKE_EDITMODE))
1440                 {
1441                         gp_draw_strokes_edit(gpd, gpf, offsx, offsy, winx, winy, dflag, gpl->flag, diff_mat, alpha);
1442                 }
1443                 
1444                 /* Check if may need to draw the active stroke cache, only if this layer is the active layer
1445                  * that is being edited. (Stroke buffer is currently stored in gp-data)
1446                  */
1447                 if (ED_gpencil_session_active() && (gpl->flag & GP_LAYER_ACTIVE) &&
1448                     (gpf->flag & GP_FRAME_PAINT))
1449                 {
1450                         /* Set color for drawing buffer stroke - since this may not be set yet */
1451                         // glColor4fv(gpl->color);
1452                         
1453                         /* Buffer stroke needs to be drawn with a different linestyle
1454                          * to help differentiate them from normal strokes.
1455                          * 
1456                          * It should also be noted that sbuffer contains temporary point types
1457                          * i.e. tGPspoints NOT bGPDspoints
1458                          */
1459                         if (gpd->sflag & PC_COLOR_VOLUMETRIC) {
1460                                 gp_draw_stroke_volumetric_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick,
1461                                                                  dflag, gpd->sbuffer_sflag, gpd->scolor);
1462                         }
1463                         else {
1464                                 gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag, gpd->scolor);
1465                         }
1466                 }
1467         }
1468 }
1469
1470 /* draw a short status message in the top-right corner */
1471 static void gp_draw_status_text(bGPdata *gpd, ARegion *ar)
1472 {
1473         rcti rect;
1474         
1475         /* Cannot draw any status text when drawing OpenGL Renders */
1476         if (G.f & G_RENDER_OGL)
1477                 return;
1478         
1479         /* Get bounds of region - Necessary to avoid problems with region overlap */
1480         ED_region_visible_rect(ar, &rect);
1481         
1482         /* for now, this should only be used to indicate when we are in stroke editmode */
1483         if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
1484                 const char *printable = IFACE_("GPencil Stroke Editing");
1485                 float       printable_size[2];
1486                 int xco, yco;
1487                 
1488                 BLF_width_and_height_default(printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
1489                 
1490                 xco = (rect.xmax - U.widget_unit) - (int)printable_size[0];
1491                 yco = (rect.ymax - U.widget_unit);
1492                 
1493                 /* text label */
1494                 UI_ThemeColor(TH_TEXT_HI);
1495 #ifdef WITH_INTERNATIONAL
1496                 BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
1497 #else
1498                 BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
1499 #endif
1500                 
1501                 /* grease pencil icon... */
1502                 // XXX: is this too intrusive?
1503                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1504                 glEnable(GL_BLEND);
1505                 
1506                 xco -= U.widget_unit;
1507                 yco -= (int)printable_size[1] / 2;
1508
1509                 UI_icon_draw(xco, yco, ICON_GREASEPENCIL);
1510                 
1511                 glDisable(GL_BLEND);
1512         }
1513 }
1514
1515 /* draw grease-pencil datablock */
1516 static void gp_draw_data(
1517         bGPDbrush *brush, float alpha, bGPdata *gpd,
1518         int offsx, int offsy, int winx, int winy, int cfra, int dflag)
1519 {
1520         /* reset line drawing style (in case previous user didn't reset) */
1521         setlinestyle(0);
1522         
1523         /* turn on smooth lines (i.e. anti-aliasing) */
1524         glEnable(GL_LINE_SMOOTH);
1525         
1526         /* XXX: turn on some way of ensuring that the polygon edges get smoothed 
1527          *      GL_POLYGON_SMOOTH is nasty and shouldn't be used, as it ends up
1528          *      creating internal white rays due to the ways it accumulates stuff
1529          */
1530         
1531         /* turn on alpha-blending */
1532         glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1533         glEnable(GL_BLEND);
1534         
1535         /* draw! */
1536         gp_draw_data_layers(brush, alpha, gpd, offsx, offsy, winx, winy, cfra, dflag);
1537         
1538         /* turn off alpha blending, then smooth lines */
1539         glDisable(GL_BLEND); // alpha blending
1540         glDisable(GL_LINE_SMOOTH); // smooth lines
1541         
1542         /* restore initial gl conditions */
1543         glColor4f(0, 0, 0, 1);
1544 }
1545
1546 /* if we have strokes for scenes (3d view)/clips (movie clip editor)
1547  * and objects/tracks, multiple data blocks have to be drawn */
1548 static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, int winx, int winy,
1549                              int cfra, int dflag, const char spacetype)
1550 {
1551         bGPdata *gpd_source = NULL;
1552         ToolSettings *ts;
1553         bGPDbrush *brush = NULL;
1554         if (scene) {
1555                 ts = scene->toolsettings;
1556                 brush = BKE_gpencil_brush_getactive(ts);
1557                 /* if no brushes, create default set */
1558                 if (brush == NULL) {
1559                         BKE_gpencil_brush_init_presets(ts);
1560                         brush = BKE_gpencil_brush_getactive(ts);
1561                 }
1562
1563                 if (spacetype == SPACE_VIEW3D) {
1564                         gpd_source = (scene->gpd ? scene->gpd : NULL);
1565                 }
1566                 else if (spacetype == SPACE_CLIP && scene->clip) {
1567                         /* currently drawing only gpencil data from either clip or track, but not both - XXX fix logic behind */
1568                         gpd_source = (scene->clip->gpd ? scene->clip->gpd : NULL);
1569                 }
1570
1571                 if (gpd_source) {
1572                         if (brush != NULL) {
1573                                 gp_draw_data(brush, ts->gp_sculpt.alpha, gpd_source,
1574                                              offsx, offsy, winx, winy, cfra, dflag);
1575                         }
1576                 }
1577         }
1578         
1579         /* scene/clip data has already been drawn, only object/track data is drawn here
1580          * if gpd_source == gpd, we don't have any object/track data and we can skip */
1581         if (gpd_source == NULL || (gpd_source && gpd_source != gpd)) {
1582                 if (brush != NULL) {
1583                         gp_draw_data(brush, ts->gp_sculpt.alpha, gpd,
1584                                      offsx, offsy, winx, winy, cfra, dflag);
1585                 }
1586         }
1587 }
1588
1589 /* ----- Grease Pencil Sketches Drawing API ------ */
1590
1591 /* ............................
1592  * XXX
1593  *      We need to review the calls below, since they may be/are not that suitable for
1594  *      the new ways that we intend to be drawing data...
1595  * ............................ */
1596
1597 /* draw grease-pencil sketches to specified 2d-view that uses ibuf corrections */
1598 void ED_gpencil_draw_2dimage(const bContext *C)
1599 {
1600         wmWindowManager *wm = CTX_wm_manager(C);
1601         ScrArea *sa = CTX_wm_area(C);
1602         ARegion *ar = CTX_wm_region(C);
1603         Scene *scene = CTX_data_scene(C);
1604         bGPdata *gpd;
1605         int offsx, offsy, sizex, sizey;
1606         int dflag = GP_DRAWDATA_NOSTATUS;
1607         
1608         gpd = ED_gpencil_data_get_active(C); // XXX
1609         if (gpd == NULL) return;
1610         
1611         /* calculate rect */
1612         switch (sa->spacetype) {
1613                 case SPACE_IMAGE: /* image */
1614                 case SPACE_CLIP: /* clip */
1615                 {
1616                 
1617                         /* just draw using standard scaling (settings here are currently ignored anyways) */
1618                         /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */
1619                         offsx = 0;
1620                         offsy = 0;
1621                         sizex = ar->winx;
1622                         sizey = ar->winy;
1623                         
1624                         wmOrtho2(ar->v2d.cur.xmin, ar->v2d.cur.xmax, ar->v2d.cur.ymin, ar->v2d.cur.ymax);
1625                         
1626                         dflag |= GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_IEDITHACK;
1627                         break;
1628                 }
1629                 case SPACE_SEQ: /* sequence */
1630                 {
1631                         /* just draw using standard scaling (settings here are currently ignored anyways) */
1632                         offsx = 0;
1633                         offsy = 0;
1634                         sizex = ar->winx;
1635                         sizey = ar->winy;
1636                         
1637                         /* NOTE: I2D was used in 2.4x, but the old settings for that have been deprecated
1638                          * and everything moved to standard View2d
1639                          */
1640                         dflag |= GP_DRAWDATA_ONLYV2D;
1641                         break;
1642                 }
1643                 default: /* for spacetype not yet handled */
1644                         offsx = 0;
1645                         offsy = 0;
1646                         sizex = ar->winx;
1647                         sizey = ar->winy;
1648                         
1649                         dflag |= GP_DRAWDATA_ONLYI2D;
1650                         break;
1651         }
1652         
1653         if (ED_screen_animation_playing(wm)) {
1654                 /* don't show onionskins during animation playback/scrub (i.e. it obscures the poses)
1655                  * OpenGL Renders (i.e. final output), or depth buffer (i.e. not real strokes)
1656                  */
1657                 dflag |= GP_DRAWDATA_NO_ONIONS;
1658         }
1659         
1660         
1661         /* draw it! */
1662         gp_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, sa->spacetype);
1663 }
1664
1665 /* draw grease-pencil sketches to specified 2d-view assuming that matrices are already set correctly
1666  * Note: this gets called twice - first time with onlyv2d=1 to draw 'canvas' strokes,
1667  * second time with onlyv2d=0 for screen-aligned strokes */
1668 void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d)
1669 {
1670         wmWindowManager *wm = CTX_wm_manager(C);
1671         ScrArea *sa = CTX_wm_area(C);
1672         ARegion *ar = CTX_wm_region(C);
1673         Scene *scene = CTX_data_scene(C);
1674         bGPdata *gpd;
1675         int dflag = 0;
1676         
1677         /* check that we have grease-pencil stuff to draw */
1678         if (sa == NULL) return;
1679         gpd = ED_gpencil_data_get_active(C); // XXX
1680         if (gpd == NULL) return;
1681         
1682         /* special hack for Image Editor */
1683         /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */
1684         if (ELEM(sa->spacetype, SPACE_IMAGE, SPACE_CLIP))
1685                 dflag |= GP_DRAWDATA_IEDITHACK;
1686         
1687         /* draw it! */
1688         if (onlyv2d) dflag |= (GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_NOSTATUS);
1689         if (ED_screen_animation_playing(wm)) dflag |= GP_DRAWDATA_NO_ONIONS;
1690         
1691         gp_draw_data_all(scene, gpd, 0, 0, ar->winx, ar->winy, CFRA, dflag, sa->spacetype);
1692         
1693         /* draw status text (if in screen/pixel-space) */
1694         if (onlyv2d == false) {
1695                 gp_draw_status_text(gpd, ar);
1696         }
1697 }
1698
1699 /* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly
1700  * Note: this gets called twice - first time with only3d=1 to draw 3d-strokes,
1701  * second time with only3d=0 for screen-aligned strokes */
1702 void ED_gpencil_draw_view3d(wmWindowManager *wm, Scene *scene, View3D *v3d, ARegion *ar, bool only3d)
1703 {
1704         bGPdata *gpd;
1705         int dflag = 0;
1706         RegionView3D *rv3d = ar->regiondata;
1707         int offsx,  offsy,  winx,  winy;
1708         
1709         /* check that we have grease-pencil stuff to draw */
1710         gpd = ED_gpencil_data_get_active_v3d(scene, v3d);
1711         if (gpd == NULL) return;
1712         
1713         /* when rendering to the offscreen buffer we don't want to
1714          * deal with the camera border, otherwise map the coords to the camera border. */
1715         if ((rv3d->persp == RV3D_CAMOB) && !(G.f & G_RENDER_OGL)) {
1716                 rctf rectf;
1717                 ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &rectf, true); /* no shift */
1718                 
1719                 offsx = round_fl_to_int(rectf.xmin);
1720                 offsy = round_fl_to_int(rectf.ymin);
1721                 winx  = round_fl_to_int(rectf.xmax - rectf.xmin);
1722                 winy  = round_fl_to_int(rectf.ymax - rectf.ymin);
1723         }
1724         else {
1725                 offsx = 0;
1726                 offsy = 0;
1727                 winx  = ar->winx;
1728                 winy  = ar->winy;
1729         }
1730         
1731         /* set flags */
1732         if (only3d) {
1733                 /* 3D strokes/3D space:
1734                  * - only 3D space points
1735                  * - don't status text either (as it's the wrong space)
1736                  */
1737                 dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS);
1738         }
1739         
1740         if (v3d->flag2 & V3D_RENDER_OVERRIDE) {
1741                 /* don't draw status text when "only render" flag is set */
1742                 dflag |= GP_DRAWDATA_NOSTATUS;
1743         }
1744         
1745         if ((wm == NULL) || ED_screen_animation_playing(wm)) {
1746                 /* don't show onionskins during animation playback/scrub (i.e. it obscures the poses)
1747                  * OpenGL Renders (i.e. final output), or depth buffer (i.e. not real strokes)
1748                  */
1749                 dflag |= GP_DRAWDATA_NO_ONIONS;
1750         }
1751         
1752         /* draw it! */
1753         gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype);
1754         
1755 }
1756
1757 void ED_gpencil_draw_ex(Scene *scene, bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype)
1758 {
1759         int dflag = GP_DRAWDATA_NOSTATUS | GP_DRAWDATA_ONLYV2D;
1760         
1761         gp_draw_data_all(scene, gpd, 0, 0, winx, winy, cfra, dflag, spacetype);
1762 }
1763
1764 /* ************************************************** */