Grease Pencil v2 Branch
[blender-staging.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
70 #include "UI_interface_icons.h"
71 #include "UI_resources.h"
72
73 /* ************************************************** */
74 /* GREASE PENCIL DRAWING */
75
76 /* ----- General Defines ------ */
77
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                         stroke_triangle->v1 = tmp_triangles[i][0];
445                         stroke_triangle->v2 = tmp_triangles[i][1];
446                         stroke_triangle->v3 = tmp_triangles[i][2];
447                 }
448         }
449         else {
450                 /* No triangles needed - Free anything allocated previously */
451                 if (gps->triangles)
452                         MEM_freeN(gps->triangles);
453                         
454                 gps->triangles = NULL;
455         }
456         
457         /* disable recalculation flag */
458         if (gps->flag & GP_STROKE_RECALC_CACHES) {
459                 gps->flag &= ~GP_STROKE_RECALC_CACHES;
460         }
461         
462         /* clear memory */
463         if (tmp_triangles) MEM_freeN(tmp_triangles);
464         if (points2d) MEM_freeN(points2d);
465 }
466
467
468 /* draw fills for shapes */
469 static void gp_draw_stroke_fill(
470         bGPdata *gpd, bGPDstroke *gps,
471         int offsx, int offsy, int winx, int winy, float diff_mat[4][4])
472 {
473         bGPDpalettecolor *palcolor;
474         int i;
475         float fpt[3];
476
477         BLI_assert(gps->totpoints >= 3);
478
479         palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
480
481         /* Triangulation fill if high quality flag is enabled */
482         if (palcolor->flag & PC_COLOR_HQ_FILL) {
483                 bGPDtriangle *stroke_triangle;
484                 bGPDspoint *pt;
485
486                 /* Calculate triangles cache for filling area (must be done only after changes) */
487                 if ((gps->flag & GP_STROKE_RECALC_CACHES) || (gps->tot_triangles == 0) || (gps->triangles == NULL)) {
488                         gp_triangulate_stroke_fill(gps);
489                 }
490                 /* Draw all triangles for filling the polygon (cache must be calculated before) */
491                 BLI_assert(gps->tot_triangles >= 1);
492                 glBegin(GL_TRIANGLES);
493                 for (i = 0, stroke_triangle = gps->triangles; i < gps->tot_triangles; i++, stroke_triangle++) {
494                         if (gps->flag & GP_STROKE_3DSPACE) {
495                                 /* vertex 1 */
496                                 pt = &gps->points[stroke_triangle->v1];
497                                 mul_v3_m4v3(fpt, diff_mat, &pt->x);
498                                 glVertex3fv(fpt);
499                                 /* vertex 2 */
500                                 pt = &gps->points[stroke_triangle->v2];
501                                 mul_v3_m4v3(fpt, diff_mat, &pt->x);
502                                 glVertex3fv(fpt);
503                                 /* vertex 3 */
504                                 pt = &gps->points[stroke_triangle->v3];
505                                 mul_v3_m4v3(fpt, diff_mat, &pt->x);
506                                 glVertex3fv(fpt);
507                         }
508                         else {
509                                 float co[2];
510                                 /* vertex 1 */
511                                 pt = &gps->points[stroke_triangle->v1];
512                                 mul_v3_m4v3(fpt, diff_mat, &pt->x);
513                                 gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
514                                 glVertex2fv(co);
515                                 /* vertex 2 */
516                                 pt = &gps->points[stroke_triangle->v2];
517                                 mul_v3_m4v3(fpt, diff_mat, &pt->x);
518                                 gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
519                                 glVertex2fv(co);
520                                 /* vertex 3 */
521                                 pt = &gps->points[stroke_triangle->v3];
522                                 mul_v3_m4v3(fpt, diff_mat, &pt->x);
523                                 gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
524                                 glVertex2fv(co);
525                         }
526                 }
527                 glEnd();
528         }
529         else {
530                 /* As an initial implementation, we use the OpenGL filled polygon drawing
531                 * here since it's the easiest option to implement for this case. It does
532                 * come with limitations (notably for concave shapes), though it shouldn't
533                 * be much of an issue in most cases.
534                 *
535                 * We keep this legacy implementation around despite now having the high quality
536                 * fills, as this is necessary for keeping everything working nicely for files
537                 * created using old versions of Blender which may have depended on the artifacts
538                 * the old fills created.
539                 */
540                 bGPDspoint *pt;
541
542                 glBegin(GL_POLYGON);
543                 for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
544                         if (gps->flag & GP_STROKE_3DSPACE) {
545                                 mul_v3_m4v3(fpt, diff_mat, &pt->x);
546                                 glVertex3fv(fpt);
547                         }
548                         else {
549                                 float co[2];
550                                 mul_v3_m4v3(fpt, diff_mat, &pt->x);
551                                 gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
552                                 glVertex2fv(co);
553                         }
554                 }
555
556                 glEnd();
557         }
558 }
559
560 /* ----- Existing Strokes Drawing (3D and Point) ------ */
561
562 /* draw a given stroke - just a single dot (only one point) */
563 static void gp_draw_stroke_point(
564         bGPDspoint *points, short thickness, short dflag, short sflag,
565         int offsx, int offsy, int winx, int winy, float diff_mat[4][4], float ink[4])
566 {
567         float fpt[3];
568         bGPDspoint *pt = &points[0];
569
570         /* color of point */
571         gp_set_point_color(pt, ink);
572
573         /* set point thickness (since there's only one of these) */
574         glPointSize((float)(thickness + 2) * points->pressure);
575         
576         /* get final position using parent matrix */
577         mul_v3_m4v3(fpt, diff_mat, &pt->x);
578
579         /* draw point */
580         if (sflag & GP_STROKE_3DSPACE) {
581                 glBegin(GL_POINTS);
582                 glVertex3fv(fpt);
583                 glEnd();
584         }
585         else {
586                 float co[2];
587                 
588                 /* get coordinates of point */
589                 gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
590                 
591                 /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, simple dot looks ok
592                  *  - also mandatory in if Image Editor 'image-based' dot
593                  */
594                 if ((thickness < GP_DRAWTHICKNESS_SPECIAL) ||
595                     ((dflag & GP_DRAWDATA_IEDITHACK) && (sflag & GP_STROKE_2DSPACE)))
596                 {
597                         glBegin(GL_POINTS);
598                         glVertex2fv(co);
599                         glEnd();
600                 }
601                 else {
602                         /* draw filled circle as is done in circf (but without the matrix push/pops which screwed things up) */
603                         GLUquadricObj *qobj = gluNewQuadric();
604                         
605                         gluQuadricDrawStyle(qobj, GLU_FILL);
606                         
607                         /* need to translate drawing position, but must reset after too! */
608                         glTranslate2fv(co);
609                         gluDisk(qobj, 0.0,  thickness, 32, 1);
610                         glTranslatef(-co[0], -co[1], 0.0);
611                         
612                         gluDeleteQuadric(qobj);
613                 }
614         }
615 }
616
617 /* draw a given stroke in 3d (i.e. in 3d-space), using simple ogl lines */
618 static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness, bool debug,
619                               short UNUSED(sflag), float diff_mat[4][4], float ink[4], bool cyclic)
620 {
621         bGPDspoint *pt, *pt2;
622         float curpressure = points[0].pressure;
623         int i;
624         float fpt[3];
625         float cyclic_fpt[3];
626
627         /* draw stroke curve */
628         glLineWidth(max_ff(curpressure * thickness, 1.0f));
629         glBegin(GL_LINE_STRIP);
630         for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
631                 gp_set_point_color(pt, ink);
632
633                 /* if there was a significant pressure change, stop the curve, change the thickness of the stroke,
634                  * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP)
635                  * Note: we want more visible levels of pressures when thickness is bigger.
636                  */
637                 if (fabsf(pt->pressure - curpressure) > 0.2f / (float)thickness) {
638                         glEnd();
639                         curpressure = pt->pressure;
640                         glLineWidth(max_ff(curpressure * thickness, 1.0f));
641                         glBegin(GL_LINE_STRIP);
642                         
643                         /* need to roll-back one point to ensure that there are no gaps in the stroke */
644                         if (i != 0) { 
645                                 pt2 = pt - 1;
646                                 mul_v3_m4v3(fpt, diff_mat, &pt2->x);
647                                 glVertex3fv(fpt);
648                         }
649                         
650                         /* now the point we want... */
651                         mul_v3_m4v3(fpt, diff_mat, &pt->x);
652                         glVertex3fv(fpt);
653                 }
654                 else {
655                         mul_v3_m4v3(fpt, diff_mat, &pt->x);
656                         glVertex3fv(fpt);
657                 }
658                 /* saves first point to use in cyclic */
659                 if (i == 0) {
660                         copy_v3_v3(cyclic_fpt, fpt);
661                 }
662         }
663         /* if cyclic draw line to first point */
664         if (cyclic) {
665                 glVertex3fv(cyclic_fpt);
666         }
667         glEnd();
668
669         /* draw debug points of curve on top? */
670         /* XXX: for now, we represent "selected" strokes in the same way as debug, which isn't used anymore */
671         if (debug) {
672                 glPointSize((float)(thickness + 2));
673                 
674                 glBegin(GL_POINTS);
675                 for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
676                         mul_v3_m4v3(fpt, diff_mat, &pt->x);
677                         glVertex3fv(fpt);
678                 }
679                 glEnd();
680
681         }
682 }
683
684 /* ----- Fancy 2D-Stroke Drawing ------ */
685
686 /* draw a given stroke in 2d */
687 static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag,
688                               bool debug, int offsx, int offsy, int winx, int winy, float diff_mat[4][4], float ink[4])
689 {
690         /* otherwise thickness is twice that of the 3D view */
691         float thickness = (float)thickness_s * 0.5f;
692         
693         /* strokes in Image Editor need a scale factor, since units there are not pixels! */
694         float scalefac  = 1.0f;
695         if ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) {
696                 scalefac = 0.001f;
697         }
698         
699         /* tessellation code - draw stroke as series of connected quads with connection
700          * edges rotated to minimize shrinking artifacts, and rounded endcaps
701          */
702         {
703                 bGPDspoint *pt1, *pt2;
704                 float pm[2];
705                 int i;
706                 float fpt[3];
707                 
708                 glShadeModel(GL_FLAT);
709                 glBegin(GL_QUADS);
710                 
711                 for (i = 0, pt1 = points, pt2 = points + 1; i < (totpoints - 1); i++, pt1++, pt2++) {
712                         float s0[2], s1[2];     /* segment 'center' points */
713                         float t0[2], t1[2];     /* tessellated coordinates */
714                         float m1[2], m2[2];     /* gradient and normal */
715                         float mt[2], sc[2];     /* gradient for thickness, point for end-cap */
716                         float pthick;           /* thickness at segment point */
717
718                         /* get x and y coordinates from points */
719                         mul_v3_m4v3(fpt, diff_mat, &pt1->x);
720                         gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s0);
721
722                         mul_v3_m4v3(fpt, diff_mat, &pt2->x);
723                         gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s1);
724                         
725                         /* calculate gradient and normal - 'angle'=(ny/nx) */
726                         m1[1] = s1[1] - s0[1];
727                         m1[0] = s1[0] - s0[0];
728                         normalize_v2(m1);
729                         m2[1] = -m1[0];
730                         m2[0] = m1[1];
731                         
732                         /* always use pressure from first point here */
733                         pthick = (pt1->pressure * thickness * scalefac);
734                         
735                         /* color of point */
736                         gp_set_point_color(pt1, ink);
737
738                         /* if the first segment, start of segment is segment's normal */
739                         if (i == 0) {
740                                 /* draw start cap first
741                                  *      - make points slightly closer to center (about halfway across)
742                                  */
743                                 mt[0] = m2[0] * pthick * 0.5f;
744                                 mt[1] = m2[1] * pthick * 0.5f;
745                                 sc[0] = s0[0] - (m1[0] * pthick * 0.75f);
746                                 sc[1] = s0[1] - (m1[1] * pthick * 0.75f);
747                                 
748                                 t0[0] = sc[0] - mt[0];
749                                 t0[1] = sc[1] - mt[1];
750                                 t1[0] = sc[0] + mt[0];
751                                 t1[1] = sc[1] + mt[1];
752                                 
753                                 glVertex2fv(t0);
754                                 glVertex2fv(t1);
755                                 
756                                 /* calculate points for start of segment */
757                                 mt[0] = m2[0] * pthick;
758                                 mt[1] = m2[1] * pthick;
759                                 
760                                 t0[0] = s0[0] - mt[0];
761                                 t0[1] = s0[1] - mt[1];
762                                 t1[0] = s0[0] + mt[0];
763                                 t1[1] = s0[1] + mt[1];
764                                 
765                                 /* draw this line twice (first to finish off start cap, then for stroke) */
766                                 glVertex2fv(t1);
767                                 glVertex2fv(t0);
768                                 glVertex2fv(t0);
769                                 glVertex2fv(t1);
770                         }
771                         /* if not the first segment, use bisector of angle between segments */
772                         else {
773                                 float mb[2];         /* bisector normal */
774                                 float athick, dfac;  /* actual thickness, difference between thicknesses */
775                                 
776                                 /* calculate gradient of bisector (as average of normals) */
777                                 mb[0] = (pm[0] + m2[0]) / 2;
778                                 mb[1] = (pm[1] + m2[1]) / 2;
779                                 normalize_v2(mb);
780                                 
781                                 /* calculate gradient to apply
782                                  *  - as basis, use just pthick * bisector gradient
783                                  *      - if cross-section not as thick as it should be, add extra padding to fix it
784                                  */
785                                 mt[0] = mb[0] * pthick;
786                                 mt[1] = mb[1] * pthick;
787                                 athick = len_v2(mt);
788                                 dfac = pthick - (athick * 2);
789                                 
790                                 if (((athick * 2.0f) < pthick) && (IS_EQF(athick, pthick) == 0)) {
791                                         mt[0] += (mb[0] * dfac);
792                                         mt[1] += (mb[1] * dfac);
793                                 }
794                                 
795                                 /* calculate points for start of segment */
796                                 t0[0] = s0[0] - mt[0];
797                                 t0[1] = s0[1] - mt[1];
798                                 t1[0] = s0[0] + mt[0];
799                                 t1[1] = s0[1] + mt[1];
800                                 
801                                 /* draw this line twice (once for end of current segment, and once for start of next) */
802                                 glVertex2fv(t1);
803                                 glVertex2fv(t0);
804                                 glVertex2fv(t0);
805                                 glVertex2fv(t1);
806                         }
807                         
808                         /* if last segment, also draw end of segment (defined as segment's normal) */
809                         if (i == totpoints - 2) {
810                                 /* for once, we use second point's pressure (otherwise it won't be drawn) */
811                                 pthick = (pt2->pressure * thickness * scalefac);
812                                 
813                                 /* color of point */
814                                 gp_set_point_color(pt2, ink);
815
816                                 /* calculate points for end of segment */
817                                 mt[0] = m2[0] * pthick;
818                                 mt[1] = m2[1] * pthick;
819                                 
820                                 t0[0] = s1[0] - mt[0];
821                                 t0[1] = s1[1] - mt[1];
822                                 t1[0] = s1[0] + mt[0];
823                                 t1[1] = s1[1] + mt[1];
824                                 
825                                 /* draw this line twice (once for end of stroke, and once for endcap)*/
826                                 glVertex2fv(t1);
827                                 glVertex2fv(t0);
828                                 glVertex2fv(t0);
829                                 glVertex2fv(t1);
830                                 
831                                 
832                                 /* draw end cap as last step
833                                  *      - make points slightly closer to center (about halfway across)
834                                  */
835                                 mt[0] = m2[0] * pthick * 0.5f;
836                                 mt[1] = m2[1] * pthick * 0.5f;
837                                 sc[0] = s1[0] + (m1[0] * pthick * 0.75f);
838                                 sc[1] = s1[1] + (m1[1] * pthick * 0.75f);
839                                 
840                                 t0[0] = sc[0] - mt[0];
841                                 t0[1] = sc[1] - mt[1];
842                                 t1[0] = sc[0] + mt[0];
843                                 t1[1] = sc[1] + mt[1];
844                                 
845                                 glVertex2fv(t1);
846                                 glVertex2fv(t0);
847                         }
848                         
849                         /* store stroke's 'natural' normal for next stroke to use */
850                         copy_v2_v2(pm, m2);
851                 }
852                 
853                 glEnd();
854                 glShadeModel(GL_SMOOTH);
855         }
856         
857         /* draw debug points of curve on top? (original stroke points) */
858         if (debug) {
859                 bGPDspoint *pt;
860                 int i;
861                 float fpt[3];
862
863                 glPointSize((float)(thickness_s + 2));
864                 
865                 glBegin(GL_POINTS);
866                 for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
867                         float co[2];
868                         mul_v3_m4v3(fpt, diff_mat, &pt->x);
869                         gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
870                         glVertex2fv(co);
871                 }
872                 glEnd();
873         }
874 }
875
876 /* ----- Strokes Drawing ------ */
877
878 /* Helper for doing all the checks on whether a stroke can be drawn */
879 static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag)
880 {
881         /* skip stroke if it isn't in the right display space for this drawing context */
882         /* 1) 3D Strokes */
883         if ((dflag & GP_DRAWDATA_ONLY3D) && !(gps->flag & GP_STROKE_3DSPACE))
884                 return false;
885         if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE))
886                 return false;
887         
888         /* 2) Screen Space 2D Strokes */
889         if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE))
890                 return false;
891         if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE))
892                 return false;
893         
894         /* 3) Image Space (2D) */
895         if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE))
896                 return false;
897         if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE))
898                 return false;
899         
900         
901         /* skip stroke if it doesn't have any valid data */
902         if ((gps->points == NULL) || (gps->totpoints < 1))
903                 return false;
904         
905         /* stroke can be drawn */
906         return true;
907 }
908
909 /* draw a set of strokes */
910 static void gp_draw_strokes(
911         bGPdata *gpd, bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag,
912         bool debug, short lthick, const float opacity, const float tintcolor[4],
913         const bool onion, const bool custonion, float diff_mat[4][4])
914 {
915         bGPDstroke *gps;
916         float tcolor[4];
917         float tfill[4];
918         short sthickness;
919         float ink[4];
920
921         for (gps = gpf->strokes.first; gps; gps = gps->next) {
922                 /* check if stroke can be drawn */
923                 if (gp_can_draw_stroke(gps, dflag) == false) {
924                         continue;
925                 }
926                 /* check if the color is visible */
927                 bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
928                 if ((palcolor == NULL) ||
929                     (palcolor->flag & PC_COLOR_HIDE) ||
930                     /* if onion and ghost flag do not draw*/
931                     (onion && (palcolor->flag & PC_COLOR_ONIONSKIN)))
932                 {
933                         continue;
934                 }
935
936                 /* calculate thickness */
937                 sthickness = gps->thickness + lthick;
938
939                 /* check which stroke-drawer to use */
940                 if (dflag & GP_DRAWDATA_ONLY3D) {
941                         const int no_xray = (dflag & GP_DRAWDATA_NO_XRAY);
942                         int mask_orig = 0;
943
944                         if (no_xray) {
945                                 glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
946                                 glDepthMask(0);
947                                 glEnable(GL_DEPTH_TEST);
948
949                                 /* first arg is normally rv3d->dist, but this isn't
950                                  * available here and seems to work quite well without */
951                                 bglPolygonOffset(1.0f, 1.0f);
952 #if 0
953                                 glEnable(GL_POLYGON_OFFSET_LINE);
954                                 glPolygonOffset(-1.0f, -1.0f);
955 #endif
956                         }
957
958                         /* 3D Fill */
959                         //if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
960                         if (gps->totpoints >= 3) {
961                                 /* set color using palette, tint color and opacity */
962                                 interp_v3_v3v3(tfill, palcolor->fill, tintcolor, tintcolor[3]);
963                                 tfill[3] = palcolor->fill[3] * opacity;
964                                 if (tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) {
965                                         if (!onion) {
966                                                 glColor4fv(tfill);
967                                         }
968                                         else {
969                                                 if (custonion) {
970                                                         glColor4fv(tintcolor);
971                                                 }
972                                                 else {
973                                                         ARRAY_SET_ITEMS(tfill, UNPACK3(palcolor->fill), tintcolor[3]);
974                                                         glColor4fv(tfill);
975                                                 }
976                                         }
977                                         gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat);
978                                 }
979                         }
980
981                         /* 3D Stroke */
982                         /* set color using palette, tint color and opacity */
983                         if (!onion) {
984                                 interp_v3_v3v3(tcolor, palcolor->color, tintcolor, tintcolor[3]);
985                                 tcolor[3] = palcolor->color[3] * opacity;
986                                 copy_v4_v4(ink, tcolor);
987                         }
988                         else {
989                                 if (custonion) {
990                                         copy_v4_v4(ink, tintcolor);
991                                 }
992                                 else {
993                                         ARRAY_SET_ITEMS(tcolor, palcolor->color[0], palcolor->color[1], palcolor->color[2], opacity);
994                                         copy_v4_v4(ink, tcolor);
995                                 }
996                         }
997                         if (palcolor->flag & PC_COLOR_VOLUMETRIC) {
998                                 /* volumetric stroke drawing */
999                                 gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, sthickness, dflag, gps->flag, diff_mat, ink);
1000                         }
1001                         else {
1002                                 /* 3D Lines - OpenGL primitives-based */
1003                                 if (gps->totpoints == 1) {
1004                                         gp_draw_stroke_point(gps->points, sthickness, dflag, gps->flag, offsx, offsy, winx, winy,
1005                                                              diff_mat, ink);
1006                                 }
1007                                 else {
1008                                         gp_draw_stroke_3d(gps->points, gps->totpoints, sthickness, debug, gps->flag,
1009                                                           diff_mat, ink, gps->flag & GP_STROKE_CYCLIC);
1010                                 }
1011                         }
1012                         if (no_xray) {
1013                                 glDepthMask(mask_orig);
1014                                 glDisable(GL_DEPTH_TEST);
1015
1016                                 bglPolygonOffset(0.0, 0.0);
1017 #if 0
1018                                 glDisable(GL_POLYGON_OFFSET_LINE);
1019                                 glPolygonOffset(0, 0);
1020 #endif
1021                         }
1022                 }
1023                 else {
1024                         /* 2D - Fill */
1025                         if (gps->totpoints >= 3) {
1026                                 /* set color using palette, tint color and opacity */
1027                                 interp_v3_v3v3(tfill, palcolor->fill, tintcolor, tintcolor[3]);
1028                                 tfill[3] = palcolor->fill[3] * opacity;
1029                                 if (tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) {
1030                                         if (!onion) {
1031                                                 glColor4fv(tfill);
1032                                         }
1033                                         else {
1034                                                 if (custonion) {
1035                                                         glColor4fv(tintcolor);
1036                                                 }
1037                                                 else {
1038                                                         ARRAY_SET_ITEMS(tfill, palcolor->fill[0], palcolor->fill[1], palcolor->fill[2],
1039                                                                         tintcolor[3]);
1040                                                         glColor4fv(tfill);
1041                                                 }
1042                                         }
1043                                         gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat);
1044                                 }
1045                         }
1046
1047                         /* 2D Strokes... */
1048                         /* set color using palette, tint color and opacity */
1049                         if (!onion) {
1050                                 interp_v3_v3v3(tcolor, palcolor->color, tintcolor, tintcolor[3]);
1051                                 tcolor[3] = palcolor->color[3] * opacity;
1052                                 copy_v4_v4(ink, tcolor);
1053                         }
1054                         else {
1055                                 if (custonion) {
1056                                         copy_v4_v4(ink, tintcolor);
1057                                 }
1058                                 else {
1059                                         ARRAY_SET_ITEMS(tcolor, palcolor->color[0], palcolor->color[1], palcolor->color[2], opacity);
1060                                         copy_v4_v4(ink, tcolor);
1061                                 }
1062                         }
1063                         if (palcolor->flag & PC_COLOR_VOLUMETRIC) {
1064                                 /* blob/disk-based "volumetric" drawing */
1065                                 gp_draw_stroke_volumetric_2d(gps->points, gps->totpoints, sthickness, dflag, gps->flag,
1066                                                              offsx, offsy, winx, winy, diff_mat, ink);
1067                         }
1068                         else {
1069                                 /* normal 2D strokes */
1070                                 if (gps->totpoints == 1) {
1071                                         gp_draw_stroke_point(gps->points, sthickness, dflag, gps->flag, offsx, offsy, winx, winy,
1072                                                              diff_mat, ink);
1073                                 }
1074                                 else {
1075                                         gp_draw_stroke_2d(gps->points, gps->totpoints, sthickness, dflag, gps->flag, debug,
1076                                                           offsx, offsy, winx, winy, diff_mat, ink);
1077                                 }
1078                         }
1079                 }
1080         }
1081 }
1082
1083 /* Draw selected verts for strokes being edited */
1084 static void gp_draw_strokes_edit(
1085         bGPdata *gpd, bGPDframe *gpf, int offsx, int offsy, int winx, int winy, short dflag,
1086         short lflag, float diff_mat[4][4], float alpha)
1087 {
1088         bGPDstroke *gps;
1089         
1090         /* if alpha 0 do not draw */
1091         if (alpha == 0.0f)
1092                 return;
1093
1094         const bool no_xray = (dflag & GP_DRAWDATA_NO_XRAY) != 0;
1095         int mask_orig = 0;
1096
1097         /* set up depth masks... */
1098         if (dflag & GP_DRAWDATA_ONLY3D) {
1099                 if (no_xray) {
1100                         glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
1101                         glDepthMask(0);
1102                         glEnable(GL_DEPTH_TEST);
1103                         
1104                         /* first arg is normally rv3d->dist, but this isn't
1105                          * available here and seems to work quite well without */
1106                         bglPolygonOffset(1.0f, 1.0f);
1107 #if 0
1108                         glEnable(GL_POLYGON_OFFSET_LINE);
1109                         glPolygonOffset(-1.0f, -1.0f);
1110 #endif
1111                 }
1112         }
1113         
1114         
1115         /* draw stroke verts */
1116         for (gps = gpf->strokes.first; gps; gps = gps->next) {
1117                 bGPDspoint *pt;
1118                 float vsize, bsize;
1119                 int i;
1120                 float fpt[3];
1121
1122                 /* check if stroke can be drawn */
1123                 if (gp_can_draw_stroke(gps, dflag) == false)
1124                         continue;
1125                 
1126                 /* Optimisation: only draw points for selected strokes
1127                  * We assume that selected points can only occur in
1128                  * strokes that are selected too.
1129                  */
1130                 if ((gps->flag & GP_STROKE_SELECT) == 0)
1131                         continue;
1132                 
1133                 /* verify palette color lock */
1134                 {
1135                         bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
1136                         if (palcolor != NULL) {
1137                                 if (palcolor->flag & PC_COLOR_HIDE) {
1138                                         continue;
1139                                 }
1140                                 if (((lflag & GP_LAYER_UNLOCK_COLOR) == 0) && (palcolor->flag & PC_COLOR_LOCKED)) {
1141                                         continue;
1142                                 }
1143                         }
1144                 }
1145
1146                 /* Get size of verts:
1147                  * - The selected state needs to be larger than the unselected state so that
1148                  *   they stand out more.
1149                  * - We use the theme setting for size of the unselected verts
1150                  */
1151                 bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE);
1152                 if ((int)bsize > 8) {
1153                         vsize = 10.0f;
1154                         bsize = 8.0f;
1155                 }
1156                 else {
1157                         vsize = bsize + 2;
1158                 }
1159                 
1160                 /* First Pass: Draw all the verts (i.e. these become the unselected state) */
1161                 /* for now, we assume that the base color of the points is not too close to the real color */
1162                 /* set color using palette */
1163                 bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
1164                 glColor3fv(palcolor->color);
1165
1166                 glPointSize(bsize);
1167                 
1168                 glBegin(GL_POINTS);
1169                 for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
1170                         if (gps->flag & GP_STROKE_3DSPACE) {
1171                                 mul_v3_m4v3(fpt, diff_mat, &pt->x);
1172                                 glVertex3fv(fpt);
1173                         }
1174                         else {
1175                                 float co[2];
1176                                 mul_v3_m4v3(fpt, diff_mat, &pt->x);
1177                                 gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
1178                                 glVertex2fv(co);
1179                         }
1180                 }
1181                 glEnd();
1182                 
1183                 
1184                 /* Second Pass: Draw only verts which are selected */
1185                 float curColor[4];
1186                 UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, curColor);
1187                 glColor4f(curColor[0], curColor[1], curColor[2], alpha);
1188
1189                 glPointSize(vsize);
1190                 
1191                 glBegin(GL_POINTS);
1192                 for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
1193                         if (pt->flag & GP_SPOINT_SELECT) {
1194                                 if (gps->flag & GP_STROKE_3DSPACE) {
1195                                         mul_v3_m4v3(fpt, diff_mat, &pt->x);
1196                                         glVertex3fv(fpt);
1197                                 }
1198                                 else {
1199                                         float co[2];
1200                                         
1201                                         mul_v3_m4v3(fpt, diff_mat, &pt->x);
1202                                         gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
1203                                         glVertex2fv(co);
1204                                 }
1205                         }
1206                 }
1207                 glEnd();
1208
1209                 /* Draw start and end point if enabled stroke direction hint */
1210                 if ((gpd->flag & GP_DATA_SHOW_DIRECTION) && (gps->totpoints > 1)) {
1211                         bGPDspoint *p;
1212                         
1213                         glPointSize(vsize + 4);
1214                         glBegin(GL_POINTS);
1215
1216                         /* start point in green bigger */
1217                         glColor3f(0.0f, 1.0f, 0.0f);
1218                         p = &gps->points[0];
1219                         mul_v3_m4v3(fpt, diff_mat, &p->x);
1220                         glVertex3fv(fpt);
1221                         glEnd();
1222
1223                         /* end point in red smaller */
1224                         glPointSize(vsize + 1);
1225                         glBegin(GL_POINTS);
1226
1227                         glColor3f(1.0f, 0.0f, 0.0f);
1228                         p = &gps->points[gps->totpoints - 1];
1229                         mul_v3_m4v3(fpt, diff_mat, &p->x);
1230                         glVertex3fv(fpt);
1231                         glEnd();
1232                 }
1233         }
1234         
1235         
1236         /* clear depth mask */
1237         if (dflag & GP_DRAWDATA_ONLY3D) {
1238                 if (no_xray) {
1239                         glDepthMask(mask_orig);
1240                         glDisable(GL_DEPTH_TEST);
1241                         
1242                         bglPolygonOffset(0.0, 0.0);
1243 #if 0
1244                         glDisable(GL_POLYGON_OFFSET_LINE);
1245                         glPolygonOffset(0, 0);
1246 #endif
1247                 }
1248         }
1249 }
1250
1251 /* ----- General Drawing ------ */
1252
1253 /* draw onion-skinning for a layer */
1254 static void gp_draw_onionskins(
1255         bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, int offsx, int offsy, int winx, int winy,
1256         int UNUSED(cfra), int dflag, bool debug, float diff_mat[4][4])
1257 {
1258         const float default_color[3] = {UNPACK3(U.gpencil_new_layer_col)};
1259         const float alpha = 1.0f;
1260         float color[4];
1261
1262         /* 1) Draw Previous Frames First */
1263         if (gpl->flag & GP_LAYER_GHOST_PREVCOL) {
1264                 copy_v3_v3(color, gpl->gcolor_prev);
1265         }
1266         else {
1267                 copy_v3_v3(color, default_color);
1268         }
1269         
1270         if (gpl->gstep > 0) {
1271                 bGPDframe *gf;
1272                 float fac;
1273                 
1274                 /* draw previous frames first */
1275                 for (gf = gpf->prev; gf; gf = gf->prev) {
1276                         /* check if frame is drawable */
1277                         if ((gpf->framenum - gf->framenum) <= gpl->gstep) {
1278                                 /* alpha decreases with distance from curframe index */
1279                                 fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1));
1280                                 color[3] = alpha * fac * 0.66f;
1281                                 gp_draw_strokes(gpd, gf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
1282                                                 true, gpl->flag & GP_LAYER_GHOST_PREVCOL, diff_mat);
1283                         }
1284                         else
1285                                 break;
1286                 }
1287         }
1288         else if (gpl->gstep == 0) {
1289                 /* draw the strokes for the ghost frames (at half of the alpha set by user) */
1290                 if (gpf->prev) {
1291                         color[3] = (alpha / 7);
1292                         gp_draw_strokes(gpd, gpf->prev, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
1293                                         true, gpl->flag & GP_LAYER_GHOST_PREVCOL, diff_mat);
1294                 }
1295         }
1296         else {
1297                 /* don't draw - disabled */
1298         }
1299         
1300         
1301         /* 2) Now draw next frames */
1302         if (gpl->flag & GP_LAYER_GHOST_NEXTCOL) {
1303                 copy_v3_v3(color, gpl->gcolor_next);
1304         }
1305         else {
1306                 copy_v3_v3(color, default_color);
1307         }
1308         
1309         if (gpl->gstep_next > 0) {
1310                 bGPDframe *gf;
1311                 float fac;
1312                 
1313                 /* now draw next frames */
1314                 for (gf = gpf->next; gf; gf = gf->next) {
1315                         /* check if frame is drawable */
1316                         if ((gf->framenum - gpf->framenum) <= gpl->gstep_next) {
1317                                 /* alpha decreases with distance from curframe index */
1318                                 fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep_next + 1));
1319                                 color[3] = alpha * fac * 0.66f;
1320                                 gp_draw_strokes(gpd, gf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
1321                                                 true, gpl->flag & GP_LAYER_GHOST_NEXTCOL, diff_mat);
1322                         }
1323                         else
1324                                 break;
1325                 }
1326         }
1327         else if (gpl->gstep_next == 0) {
1328                 /* draw the strokes for the ghost frames (at half of the alpha set by user) */
1329                 if (gpf->next) {
1330                         color[3] = (alpha / 4);
1331                         gp_draw_strokes(gpd, gpf->next, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
1332                                         true, gpl->flag & GP_LAYER_GHOST_NEXTCOL, diff_mat);
1333                 }
1334         }
1335         else {
1336                 /* don't draw - disabled */
1337         }
1338         
1339 }
1340
1341 /* loop over gpencil data layers, drawing them */
1342 static void gp_draw_data_layers(
1343         bGPDbrush *brush, float alpha, bGPdata *gpd,
1344         int offsx, int offsy, int winx, int winy, int cfra, int dflag)
1345 {
1346         bGPDlayer *gpl;
1347         float diff_mat[4][4];
1348
1349         for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
1350                 bGPDframe *gpf;
1351                 /* calculate parent position */
1352                 ED_gpencil_parent_location(gpl, diff_mat);
1353
1354                 bool debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? true : false;
1355                 short lthick = brush->thickness + gpl->thickness;
1356                 
1357                 /* don't draw layer if hidden */
1358                 if (gpl->flag & GP_LAYER_HIDE)
1359                         continue;
1360                 
1361                 /* get frame to draw */
1362                 gpf = gpencil_layer_getframe(gpl, cfra, 0);
1363                 if (gpf == NULL)
1364                         continue;
1365                 
1366                 /* set basic stroke thickness */
1367                 glLineWidth(lthick);
1368                 
1369                 /* Add layer drawing settings to the set of "draw flags"
1370                  * NOTE: If the setting doesn't apply, it *must* be cleared,
1371                  *       as dflag's carry over from the previous layer
1372                  */
1373 #define GP_DRAWFLAG_APPLY(condition, draw_flag_value)     { \
1374                         if (condition) dflag |= (draw_flag_value);      \
1375                         else           dflag &= ~(draw_flag_value);     \
1376                 } (void)0
1377                 
1378                 /* xray... */
1379                 GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_NO_XRAY), GP_DRAWDATA_NO_XRAY);
1380                 
1381                 /* volumetric strokes... */
1382                 GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_VOLUMETRIC), GP_DRAWDATA_VOLUMETRIC);
1383
1384                 /* HQ fills... */
1385                 GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_HQ_FILL), GP_DRAWDATA_HQ_FILL);
1386
1387 #undef GP_DRAWFLAG_APPLY
1388                 
1389                 /* draw 'onionskins' (frame left + right) */
1390                 if ((gpl->flag & GP_LAYER_ONIONSKIN) && !(dflag & GP_DRAWDATA_NO_ONIONS)) {
1391                         /* Drawing method - only immediately surrounding (gstep = 0),
1392                          * or within a frame range on either side (gstep > 0)
1393                          */
1394                         gp_draw_onionskins(gpd, gpl, gpf, offsx, offsy, winx, winy, cfra, dflag, debug, diff_mat);
1395                 }
1396                 
1397                 /* draw the strokes already in active frame */
1398                 gp_draw_strokes(gpd, gpf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness,
1399                                 gpl->opacity, gpl->tintcolor, false, false, diff_mat);
1400                 
1401                 /* Draw verts of selected strokes
1402                  *  - when doing OpenGL renders, we don't want to be showing these, as that ends up flickering
1403                  *      - locked layers can't be edited, so there's no point showing these verts
1404                  *    as they will have no bearings on what gets edited
1405                  *  - only show when in editmode, since operators shouldn't work otherwise
1406                  *    (NOTE: doing it this way means that the toggling editmode shows visible change immediately)
1407                  */
1408                 /* XXX: perhaps we don't want to show these when users are drawing... */
1409                 if ((G.f & G_RENDER_OGL) == 0 &&
1410                     (gpl->flag & GP_LAYER_LOCKED) == 0 &&
1411                     (gpd->flag & GP_DATA_STROKE_EDITMODE))
1412                 {
1413                         gp_draw_strokes_edit(gpd, gpf, offsx, offsy, winx, winy, dflag, gpl->flag, diff_mat, alpha);
1414                 }
1415                 
1416                 /* Check if may need to draw the active stroke cache, only if this layer is the active layer
1417                  * that is being edited. (Stroke buffer is currently stored in gp-data)
1418                  */
1419                 if (ED_gpencil_session_active() && (gpl->flag & GP_LAYER_ACTIVE) &&
1420                     (gpf->flag & GP_FRAME_PAINT))
1421                 {
1422                         /* Set color for drawing buffer stroke - since this may not be set yet */
1423                         // glColor4fv(gpl->color);
1424                         
1425                         /* Buffer stroke needs to be drawn with a different linestyle
1426                          * to help differentiate them from normal strokes.
1427                          * 
1428                          * It should also be noted that sbuffer contains temporary point types
1429                          * i.e. tGPspoints NOT bGPDspoints
1430                          */
1431                         if (gpd->sflag & PC_COLOR_VOLUMETRIC) {
1432                                 gp_draw_stroke_volumetric_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick,
1433                                                                  dflag, gpd->sbuffer_sflag, gpd->scolor);
1434                         }
1435                         else {
1436                                 gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag, gpd->scolor);
1437                         }
1438                 }
1439         }
1440 }
1441
1442 /* draw a short status message in the top-right corner */
1443 static void gp_draw_status_text(bGPdata *gpd, ARegion *ar)
1444 {
1445         rcti rect;
1446         
1447         /* Cannot draw any status text when drawing OpenGL Renders */
1448         if (G.f & G_RENDER_OGL)
1449                 return;
1450         
1451         /* Get bounds of region - Necessary to avoid problems with region overlap */
1452         ED_region_visible_rect(ar, &rect);
1453         
1454         /* for now, this should only be used to indicate when we are in stroke editmode */
1455         if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
1456                 const char *printable = IFACE_("GPencil Stroke Editing");
1457                 float       printable_size[2];
1458                 int xco, yco;
1459                 
1460                 BLF_width_and_height_default(printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
1461                 
1462                 xco = (rect.xmax - U.widget_unit) - (int)printable_size[0];
1463                 yco = (rect.ymax - U.widget_unit);
1464                 
1465                 /* text label */
1466                 UI_ThemeColor(TH_TEXT_HI);
1467 #ifdef WITH_INTERNATIONAL
1468                 BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
1469 #else
1470                 BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
1471 #endif
1472                 
1473                 /* grease pencil icon... */
1474                 // XXX: is this too intrusive?
1475                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1476                 glEnable(GL_BLEND);
1477                 
1478                 xco -= U.widget_unit;
1479                 yco -= (int)printable_size[1] / 2;
1480
1481                 UI_icon_draw(xco, yco, ICON_GREASEPENCIL);
1482                 
1483                 glDisable(GL_BLEND);
1484         }
1485 }
1486
1487 /* draw grease-pencil datablock */
1488 static void gp_draw_data(
1489         bGPDbrush *brush, float alpha, bGPdata *gpd,
1490         int offsx, int offsy, int winx, int winy, int cfra, int dflag)
1491 {
1492         /* reset line drawing style (in case previous user didn't reset) */
1493         setlinestyle(0);
1494         
1495         /* turn on smooth lines (i.e. anti-aliasing) */
1496         glEnable(GL_LINE_SMOOTH);
1497         
1498         /* XXX: turn on some way of ensuring that the polygon edges get smoothed 
1499          *      GL_POLYGON_SMOOTH is nasty and shouldn't be used, as it ends up
1500          *      creating internal white rays due to the ways it accumulates stuff
1501          */
1502         
1503         /* turn on alpha-blending */
1504         glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1505         glEnable(GL_BLEND);
1506         
1507         /* draw! */
1508         gp_draw_data_layers(brush, alpha, gpd, offsx, offsy, winx, winy, cfra, dflag);
1509         
1510         /* turn off alpha blending, then smooth lines */
1511         glDisable(GL_BLEND); // alpha blending
1512         glDisable(GL_LINE_SMOOTH); // smooth lines
1513         
1514         /* restore initial gl conditions */
1515         glColor4f(0, 0, 0, 1);
1516 }
1517
1518 /* if we have strokes for scenes (3d view)/clips (movie clip editor)
1519  * and objects/tracks, multiple data blocks have to be drawn */
1520 static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, int winx, int winy,
1521                              int cfra, int dflag, const char spacetype)
1522 {
1523         bGPdata *gpd_source = NULL;
1524         
1525         if (scene) {
1526                 if (spacetype == SPACE_VIEW3D) {
1527                         gpd_source = (scene->gpd ? scene->gpd : NULL);
1528                 }
1529                 else if (spacetype == SPACE_CLIP && scene->clip) {
1530                         /* currently drawing only gpencil data from either clip or track, but not both - XXX fix logic behind */
1531                         gpd_source = (scene->clip->gpd ? scene->clip->gpd : NULL);
1532                 }
1533                 
1534                 if (gpd_source) {
1535                         ToolSettings *ts = scene->toolsettings;
1536                         bGPDbrush *brush = gpencil_brush_getactive(ts);
1537                         if (brush != NULL) {
1538                                 gp_draw_data(brush, ts->gp_sculpt.alpha, gpd_source,
1539                                              offsx, offsy, winx, winy, cfra, dflag);
1540                         }
1541                         
1542                 }
1543         }
1544         
1545         /* scene/clip data has already been drawn, only object/track data is drawn here
1546          * if gpd_source == gpd, we don't have any object/track data and we can skip */
1547         if (gpd_source == NULL || (gpd_source && gpd_source != gpd)) {
1548                 ToolSettings *ts = scene->toolsettings;
1549                 bGPDbrush *brush = gpencil_brush_getactive(ts);
1550                 if (brush != NULL) {
1551                         gp_draw_data(brush, ts->gp_sculpt.alpha, gpd,
1552                                      offsx, offsy, winx, winy, cfra, dflag);
1553                 }
1554         }
1555 }
1556
1557 /* ----- Grease Pencil Sketches Drawing API ------ */
1558
1559 /* ............................
1560  * XXX
1561  *      We need to review the calls below, since they may be/are not that suitable for
1562  *      the new ways that we intend to be drawing data...
1563  * ............................ */
1564
1565 /* draw grease-pencil sketches to specified 2d-view that uses ibuf corrections */
1566 void ED_gpencil_draw_2dimage(const bContext *C)
1567 {
1568         wmWindowManager *wm = CTX_wm_manager(C);
1569         ScrArea *sa = CTX_wm_area(C);
1570         ARegion *ar = CTX_wm_region(C);
1571         Scene *scene = CTX_data_scene(C);
1572         bGPdata *gpd;
1573         int offsx, offsy, sizex, sizey;
1574         int dflag = GP_DRAWDATA_NOSTATUS;
1575         
1576         gpd = ED_gpencil_data_get_active(C); // XXX
1577         if (gpd == NULL) return;
1578         
1579         /* calculate rect */
1580         switch (sa->spacetype) {
1581                 case SPACE_IMAGE: /* image */
1582                 case SPACE_CLIP: /* clip */
1583                 {
1584                 
1585                         /* just draw using standard scaling (settings here are currently ignored anyways) */
1586                         /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */
1587                         offsx = 0;
1588                         offsy = 0;
1589                         sizex = ar->winx;
1590                         sizey = ar->winy;
1591                         
1592                         wmOrtho2(ar->v2d.cur.xmin, ar->v2d.cur.xmax, ar->v2d.cur.ymin, ar->v2d.cur.ymax);
1593                         
1594                         dflag |= GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_IEDITHACK;
1595                         break;
1596                 }
1597                 case SPACE_SEQ: /* sequence */
1598                 {
1599                         /* just draw using standard scaling (settings here are currently ignored anyways) */
1600                         offsx = 0;
1601                         offsy = 0;
1602                         sizex = ar->winx;
1603                         sizey = ar->winy;
1604                         
1605                         /* NOTE: I2D was used in 2.4x, but the old settings for that have been deprecated
1606                          * and everything moved to standard View2d
1607                          */
1608                         dflag |= GP_DRAWDATA_ONLYV2D;
1609                         break;
1610                 }
1611                 default: /* for spacetype not yet handled */
1612                         offsx = 0;
1613                         offsy = 0;
1614                         sizex = ar->winx;
1615                         sizey = ar->winy;
1616                         
1617                         dflag |= GP_DRAWDATA_ONLYI2D;
1618                         break;
1619         }
1620         
1621         if (ED_screen_animation_playing(wm)) {
1622                 /* don't show onionskins during animation playback/scrub (i.e. it obscures the poses)
1623                  * OpenGL Renders (i.e. final output), or depth buffer (i.e. not real strokes)
1624                  */
1625                 dflag |= GP_DRAWDATA_NO_ONIONS;
1626         }
1627         
1628         
1629         /* draw it! */
1630         gp_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, sa->spacetype);
1631 }
1632
1633 /* draw grease-pencil sketches to specified 2d-view assuming that matrices are already set correctly
1634  * Note: this gets called twice - first time with onlyv2d=1 to draw 'canvas' strokes,
1635  * second time with onlyv2d=0 for screen-aligned strokes */
1636 void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d)
1637 {
1638         wmWindowManager *wm = CTX_wm_manager(C);
1639         ScrArea *sa = CTX_wm_area(C);
1640         ARegion *ar = CTX_wm_region(C);
1641         Scene *scene = CTX_data_scene(C);
1642         bGPdata *gpd;
1643         int dflag = 0;
1644         
1645         /* check that we have grease-pencil stuff to draw */
1646         if (sa == NULL) return;
1647         gpd = ED_gpencil_data_get_active(C); // XXX
1648         if (gpd == NULL) return;
1649         
1650         /* special hack for Image Editor */
1651         /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */
1652         if (ELEM(sa->spacetype, SPACE_IMAGE, SPACE_CLIP))
1653                 dflag |= GP_DRAWDATA_IEDITHACK;
1654         
1655         /* draw it! */
1656         if (onlyv2d) dflag |= (GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_NOSTATUS);
1657         if (ED_screen_animation_playing(wm)) dflag |= GP_DRAWDATA_NO_ONIONS;
1658         
1659         gp_draw_data_all(scene, gpd, 0, 0, ar->winx, ar->winy, CFRA, dflag, sa->spacetype);
1660         
1661         /* draw status text (if in screen/pixel-space) */
1662         if (onlyv2d == false) {
1663                 gp_draw_status_text(gpd, ar);
1664         }
1665 }
1666
1667 /* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly
1668  * Note: this gets called twice - first time with only3d=1 to draw 3d-strokes,
1669  * second time with only3d=0 for screen-aligned strokes */
1670 void ED_gpencil_draw_view3d(wmWindowManager *wm, Scene *scene, View3D *v3d, ARegion *ar, bool only3d)
1671 {
1672         bGPdata *gpd;
1673         int dflag = 0;
1674         RegionView3D *rv3d = ar->regiondata;
1675         int offsx,  offsy,  winx,  winy;
1676         
1677         /* check that we have grease-pencil stuff to draw */
1678         gpd = ED_gpencil_data_get_active_v3d(scene, v3d);
1679         if (gpd == NULL) return;
1680         
1681         /* when rendering to the offscreen buffer we don't want to
1682          * deal with the camera border, otherwise map the coords to the camera border. */
1683         if ((rv3d->persp == RV3D_CAMOB) && !(G.f & G_RENDER_OGL)) {
1684                 rctf rectf;
1685                 ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &rectf, true); /* no shift */
1686                 
1687                 offsx = iroundf(rectf.xmin);
1688                 offsy = iroundf(rectf.ymin);
1689                 winx  = iroundf(rectf.xmax - rectf.xmin);
1690                 winy  = iroundf(rectf.ymax - rectf.ymin);
1691         }
1692         else {
1693                 offsx = 0;
1694                 offsy = 0;
1695                 winx  = ar->winx;
1696                 winy  = ar->winy;
1697         }
1698         
1699         /* set flags */
1700         if (only3d) {
1701                 /* 3D strokes/3D space:
1702                  * - only 3D space points
1703                  * - don't status text either (as it's the wrong space)
1704                  */
1705                 dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS);
1706         }
1707         
1708         if (v3d->flag2 & V3D_RENDER_OVERRIDE) {
1709                 /* don't draw status text when "only render" flag is set */
1710                 dflag |= GP_DRAWDATA_NOSTATUS;
1711         }
1712         
1713         if ((wm == NULL) || ED_screen_animation_playing(wm)) {
1714                 /* don't show onionskins during animation playback/scrub (i.e. it obscures the poses)
1715                  * OpenGL Renders (i.e. final output), or depth buffer (i.e. not real strokes)
1716                  */
1717                 dflag |= GP_DRAWDATA_NO_ONIONS;
1718         }
1719         
1720         /* draw it! */
1721         gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype);
1722         
1723 }
1724
1725 void ED_gpencil_draw_ex(Scene *scene, bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype)
1726 {
1727         int dflag = GP_DRAWDATA_NOSTATUS | GP_DRAWDATA_ONLYV2D;
1728         
1729         gp_draw_data_all(scene, gpd, 0, 0, winx, winy, cfra, dflag, spacetype);
1730 }
1731
1732 /* ************************************************** */