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