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