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