Fix: "show_points" setting for Grease Pencil drawing didn't work
[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                 glPointSize((float)(thickness + 2));
447                 
448                 glBegin(GL_POINTS);
449                 for (i = 0, pt = points; i < totpoints && pt; i++, pt++)
450                         glVertex3fv(&pt->x);
451                 glEnd();
452         }
453 }
454
455 /* ----- Fancy 2D-Stroke Drawing ------ */
456
457 /* draw a given stroke in 2d */
458 static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag,
459                               bool debug, int offsx, int offsy, int winx, int winy)
460 {
461         /* otherwise thickness is twice that of the 3D view */
462         float thickness = (float)thickness_s * 0.5f;
463         
464         /* strokes in Image Editor need a scale factor, since units there are not pixels! */
465         float scalefac  = 1.0f;
466         if ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) {
467                 scalefac = 0.001f;
468         }
469         
470         /* tessellation code - draw stroke as series of connected quads with connection
471          * edges rotated to minimize shrinking artifacts, and rounded endcaps
472          */
473         {
474                 bGPDspoint *pt1, *pt2;
475                 float pm[2];
476                 int i;
477                 
478                 glShadeModel(GL_FLAT);
479                 glBegin(GL_QUADS);
480                 
481                 for (i = 0, pt1 = points, pt2 = points + 1; i < (totpoints - 1); i++, pt1++, pt2++) {
482                         float s0[2], s1[2];     /* segment 'center' points */
483                         float t0[2], t1[2];     /* tessellated coordinates */
484                         float m1[2], m2[2];     /* gradient and normal */
485                         float mt[2], sc[2];     /* gradient for thickness, point for end-cap */
486                         float pthick;           /* thickness at segment point */
487                         
488                         /* get x and y coordinates from points */
489                         gp_calc_2d_stroke_xy(pt1, sflag, offsx, offsy, winx, winy, s0);
490                         gp_calc_2d_stroke_xy(pt2, sflag, offsx, offsy, winx, winy, s1);
491                         
492                         /* calculate gradient and normal - 'angle'=(ny/nx) */
493                         m1[1] = s1[1] - s0[1];
494                         m1[0] = s1[0] - s0[0];
495                         normalize_v2(m1);
496                         m2[1] = -m1[0];
497                         m2[0] = m1[1];
498                         
499                         /* always use pressure from first point here */
500                         pthick = (pt1->pressure * thickness * scalefac);
501                         
502                         /* if the first segment, start of segment is segment's normal */
503                         if (i == 0) {
504                                 /* draw start cap first
505                                  *      - make points slightly closer to center (about halfway across)
506                                  */
507                                 mt[0] = m2[0] * pthick * 0.5f;
508                                 mt[1] = m2[1] * pthick * 0.5f;
509                                 sc[0] = s0[0] - (m1[0] * pthick * 0.75f);
510                                 sc[1] = s0[1] - (m1[1] * pthick * 0.75f);
511                                 
512                                 t0[0] = sc[0] - mt[0];
513                                 t0[1] = sc[1] - mt[1];
514                                 t1[0] = sc[0] + mt[0];
515                                 t1[1] = sc[1] + mt[1];
516                                 
517                                 glVertex2fv(t0);
518                                 glVertex2fv(t1);
519                                 
520                                 /* calculate points for start of segment */
521                                 mt[0] = m2[0] * pthick;
522                                 mt[1] = m2[1] * pthick;
523                                 
524                                 t0[0] = s0[0] - mt[0];
525                                 t0[1] = s0[1] - mt[1];
526                                 t1[0] = s0[0] + mt[0];
527                                 t1[1] = s0[1] + mt[1];
528                                 
529                                 /* draw this line twice (first to finish off start cap, then for stroke) */
530                                 glVertex2fv(t1);
531                                 glVertex2fv(t0);
532                                 glVertex2fv(t0);
533                                 glVertex2fv(t1);
534                         }
535                         /* if not the first segment, use bisector of angle between segments */
536                         else {
537                                 float mb[2];         /* bisector normal */
538                                 float athick, dfac;  /* actual thickness, difference between thicknesses */
539                                 
540                                 /* calculate gradient of bisector (as average of normals) */
541                                 mb[0] = (pm[0] + m2[0]) / 2;
542                                 mb[1] = (pm[1] + m2[1]) / 2;
543                                 normalize_v2(mb);
544                                 
545                                 /* calculate gradient to apply
546                                  *  - as basis, use just pthick * bisector gradient
547                                  *      - if cross-section not as thick as it should be, add extra padding to fix it
548                                  */
549                                 mt[0] = mb[0] * pthick;
550                                 mt[1] = mb[1] * pthick;
551                                 athick = len_v2(mt);
552                                 dfac = pthick - (athick * 2);
553                                 
554                                 if (((athick * 2.0f) < pthick) && (IS_EQF(athick, pthick) == 0)) {
555                                         mt[0] += (mb[0] * dfac);
556                                         mt[1] += (mb[1] * dfac);
557                                 }
558                                 
559                                 /* calculate points for start of segment */
560                                 t0[0] = s0[0] - mt[0];
561                                 t0[1] = s0[1] - mt[1];
562                                 t1[0] = s0[0] + mt[0];
563                                 t1[1] = s0[1] + mt[1];
564                                 
565                                 /* draw this line twice (once for end of current segment, and once for start of next) */
566                                 glVertex2fv(t1);
567                                 glVertex2fv(t0);
568                                 glVertex2fv(t0);
569                                 glVertex2fv(t1);
570                         }
571                         
572                         /* if last segment, also draw end of segment (defined as segment's normal) */
573                         if (i == totpoints - 2) {
574                                 /* for once, we use second point's pressure (otherwise it won't be drawn) */
575                                 pthick = (pt2->pressure * thickness * scalefac);
576                                 
577                                 /* calculate points for end of segment */
578                                 mt[0] = m2[0] * pthick;
579                                 mt[1] = m2[1] * pthick;
580                                 
581                                 t0[0] = s1[0] - mt[0];
582                                 t0[1] = s1[1] - mt[1];
583                                 t1[0] = s1[0] + mt[0];
584                                 t1[1] = s1[1] + mt[1];
585                                 
586                                 /* draw this line twice (once for end of stroke, and once for endcap)*/
587                                 glVertex2fv(t1);
588                                 glVertex2fv(t0);
589                                 glVertex2fv(t0);
590                                 glVertex2fv(t1);
591                                 
592                                 
593                                 /* draw end cap as last step
594                                  *      - make points slightly closer to center (about halfway across)
595                                  */
596                                 mt[0] = m2[0] * pthick * 0.5f;
597                                 mt[1] = m2[1] * pthick * 0.5f;
598                                 sc[0] = s1[0] + (m1[0] * pthick * 0.75f);
599                                 sc[1] = s1[1] + (m1[1] * pthick * 0.75f);
600                                 
601                                 t0[0] = sc[0] - mt[0];
602                                 t0[1] = sc[1] - mt[1];
603                                 t1[0] = sc[0] + mt[0];
604                                 t1[1] = sc[1] + mt[1];
605                                 
606                                 glVertex2fv(t1);
607                                 glVertex2fv(t0);
608                         }
609                         
610                         /* store stroke's 'natural' normal for next stroke to use */
611                         copy_v2_v2(pm, m2);
612                 }
613                 
614                 glEnd();
615         }
616         
617         /* draw debug points of curve on top? (original stroke points) */
618         if (debug) {
619                 bGPDspoint *pt;
620                 int i;
621                 
622                 glPointSize((float)(thickness_s + 2));
623                 
624                 glBegin(GL_POINTS);
625                 for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
626                         float co[2];
627                         
628                         gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co);
629                         glVertex2fv(co);
630                 }
631                 glEnd();
632         }
633 }
634
635 /* ----- Strokes Drawing ------ */
636
637 /* Helper for doing all the checks on whether a stroke can be drawn */
638 static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag)
639 {
640         /* skip stroke if it isn't in the right display space for this drawing context */
641         /* 1) 3D Strokes */
642         if ((dflag & GP_DRAWDATA_ONLY3D) && !(gps->flag & GP_STROKE_3DSPACE))
643                 return false;
644         if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE))
645                 return false;
646         
647         /* 2) Screen Space 2D Strokes */
648         if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE))
649                 return false;
650         if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE))
651                 return false;
652         
653         /* 3) Image Space (2D) */
654         if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE))
655                 return false;
656         if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE))
657                 return false;
658         
659         
660         /* skip stroke if it doesn't have any valid data */
661         if ((gps->points == NULL) || (gps->totpoints < 1))
662                 return false;
663         
664         /* stroke can be drawn */
665         return true;
666 }
667
668 /* draw a set of strokes */
669 static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag,
670                             bool debug, short lthick, const float color[4], const float fill_color[4])
671 {
672         bGPDstroke *gps;
673         
674         for (gps = gpf->strokes.first; gps; gps = gps->next) {
675                 /* check if stroke can be drawn */
676                 if (gp_can_draw_stroke(gps, dflag) == false)
677                         continue;
678                 
679                 /* check which stroke-drawer to use */
680                 if (dflag & GP_DRAWDATA_ONLY3D) {
681                         const int no_xray = (dflag & GP_DRAWDATA_NO_XRAY);
682                         int mask_orig = 0;
683                         
684                         if (no_xray) {
685                                 glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
686                                 glDepthMask(0);
687                                 glEnable(GL_DEPTH_TEST);
688                                 
689                                 /* first arg is normally rv3d->dist, but this isn't
690                                  * available here and seems to work quite well without */
691                                 bglPolygonOffset(1.0f, 1.0f);
692 #if 0
693                                 glEnable(GL_POLYGON_OFFSET_LINE);
694                                 glPolygonOffset(-1.0f, -1.0f);
695 #endif
696                         }
697                         
698                         /* 3D Fill */
699                         if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
700                                 glColor4fv(fill_color);
701                                 gp_draw_stroke_fill(gps->points, gps->totpoints, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
702                         }
703                         
704                         /* 3D Stroke */
705                         glColor4fv(color);
706                         
707                         if (dflag & GP_DRAWDATA_VOLUMETRIC) {
708                                 /* volumetric stroke drawing */
709                                 gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, lthick, dflag, gps->flag);
710                         }
711                         else {
712                                 /* 3D Lines - OpenGL primitives-based */
713                                 if (gps->totpoints == 1) {
714                                         gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
715                                 }
716                                 else {
717                                         gp_draw_stroke_3d(gps->points, gps->totpoints, lthick, debug, gps->flag);
718                                 }
719                         }
720                         
721                         if (no_xray) {
722                                 glDepthMask(mask_orig);
723                                 glDisable(GL_DEPTH_TEST);
724                                 
725                                 bglPolygonOffset(0.0, 0.0);
726 #if 0
727                                 glDisable(GL_POLYGON_OFFSET_LINE);
728                                 glPolygonOffset(0, 0);
729 #endif
730                         }
731                 }
732                 else {
733                         /* 2D - Fill */
734                         if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
735                                 glColor4fv(fill_color);
736                                 gp_draw_stroke_fill(gps->points, gps->totpoints, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
737                         }
738                         
739                         /* 2D Strokes... */
740                         glColor4fv(color);
741                         
742                         if (dflag & GP_DRAWDATA_VOLUMETRIC) {
743                                 /* blob/disk-based "volumetric" drawing */
744                                 gp_draw_stroke_volumetric_2d(gps->points, gps->totpoints, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
745                         }
746                         else {
747                                 /* normal 2D strokes */
748                                 if (gps->totpoints == 1) {
749                                         gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
750                                 }
751                                 else {
752                                         gp_draw_stroke_2d(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, offsx, offsy, winx, winy);
753                                 }
754                         }
755                 }
756         }
757 }
758
759 /* Draw selected verts for strokes being edited */
760 static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx, int winy, short dflag, const float tcolor[3])
761 {
762         bGPDstroke *gps;
763         
764         const int no_xray = (dflag & GP_DRAWDATA_NO_XRAY);
765         int mask_orig = 0;
766         
767         /* set up depth masks... */
768         if (dflag & GP_DRAWDATA_ONLY3D) {
769                 if (no_xray) {
770                         glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
771                         glDepthMask(0);
772                         glEnable(GL_DEPTH_TEST);
773                         
774                         /* first arg is normally rv3d->dist, but this isn't
775                          * available here and seems to work quite well without */
776                         bglPolygonOffset(1.0f, 1.0f);
777 #if 0
778                         glEnable(GL_POLYGON_OFFSET_LINE);
779                         glPolygonOffset(-1.0f, -1.0f);
780 #endif
781                 }
782         }
783         
784         
785         /* draw stroke verts */
786         for (gps = gpf->strokes.first; gps; gps = gps->next) {
787                 bGPDspoint *pt;
788                 float vsize, bsize;
789                 int i;
790                 
791                 /* check if stroke can be drawn */
792                 if (gp_can_draw_stroke(gps, dflag) == false)
793                         continue;
794                 
795                 /* Optimisation: only draw points for selected strokes
796                  * We assume that selected points can only occur in
797                  * strokes that are selected too.
798                  */
799                 if ((gps->flag & GP_STROKE_SELECT) == 0)
800                         continue;
801                 
802                 /* Get size of verts:
803                  * - The selected state needs to be larger than the unselected state so that
804                  *   they stand out more.
805                  * - We use the theme setting for size of the unselected verts
806                  */
807                 bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE);
808                 if ((int)bsize > 8) {
809                         vsize = 10.0f;
810                         bsize = 8.0f;
811                 }
812                 else {
813                         vsize = bsize + 2;
814                 }
815                 
816                 /* First Pass: Draw all the verts (i.e. these become the unselected state) */
817                 if (tcolor != NULL) {
818                         /* for now, we assume that the base color of the points is not too close to the real color */
819                         glColor3fv(tcolor);
820                 }
821                 else {
822                         /* this doesn't work well with the default theme and black strokes... */
823                         UI_ThemeColor(TH_GP_VERTEX);
824                 }
825                 glPointSize(bsize);
826                 
827                 glBegin(GL_POINTS);
828                 for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
829                         if (gps->flag & GP_STROKE_3DSPACE) {
830                                 glVertex3fv(&pt->x);
831                         }
832                         else {
833                                 float co[2];
834                                 
835                                 gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
836                                 glVertex2fv(co);
837                         }
838                 }
839                 glEnd();
840                 
841                 
842                 /* Second Pass: Draw only verts which are selected */
843                 UI_ThemeColor(TH_GP_VERTEX_SELECT);
844                 glPointSize(vsize);
845                 
846                 glBegin(GL_POINTS);
847                 for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
848                         if (pt->flag & GP_SPOINT_SELECT) {
849                                 if (gps->flag & GP_STROKE_3DSPACE) {
850                                         glVertex3fv(&pt->x);
851                                 }
852                                 else {
853                                         float co[2];
854                                         
855                                         gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
856                                         glVertex2fv(co);
857                                 }
858                         }
859                 }
860                 glEnd();
861         }
862         
863         
864         /* clear depth mask */
865         if (dflag & GP_DRAWDATA_ONLY3D) {
866                 if (no_xray) {
867                         glDepthMask(mask_orig);
868                         glDisable(GL_DEPTH_TEST);
869                         
870                         bglPolygonOffset(0.0, 0.0);
871 #if 0
872                         glDisable(GL_POLYGON_OFFSET_LINE);
873                         glPolygonOffset(0, 0);
874 #endif
875                 }
876         }
877 }
878
879 /* ----- General Drawing ------ */
880
881 /* draw onion-skinning for a layer */
882 static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int offsy, int winx, int winy,
883                                int UNUSED(cfra), int dflag, bool debug, short lthick)
884 {
885         const float alpha = gpl->color[3];
886         float color[4];
887         
888         /* 1) Draw Previous Frames First */
889         if (gpl->flag & GP_LAYER_GHOST_PREVCOL) {
890                 copy_v3_v3(color, gpl->gcolor_prev);
891         }
892         else {
893                 copy_v3_v3(color, gpl->color);
894         }
895         
896         if (gpl->gstep) {
897                 bGPDframe *gf;
898                 float fac;
899                 
900                 /* draw previous frames first */
901                 for (gf = gpf->prev; gf; gf = gf->prev) {
902                         /* check if frame is drawable */
903                         if ((gpf->framenum - gf->framenum) <= gpl->gstep) {
904                                 /* alpha decreases with distance from curframe index */
905                                 fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1));
906                                 color[3] = alpha * fac * 0.66f;
907                                 gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
908                         }
909                         else
910                                 break;
911                 }
912         }
913         else {
914                 /* draw the strokes for the ghost frames (at half of the alpha set by user) */
915                 if (gpf->prev) {
916                         color[3] = (alpha / 7);
917                         gp_draw_strokes(gpf->prev, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
918                 }
919         }
920         
921         
922         /* 2) Now draw next frames */
923         if (gpl->flag & GP_LAYER_GHOST_NEXTCOL) {
924                 copy_v3_v3(color, gpl->gcolor_next);
925         }
926         else {
927                 copy_v3_v3(color, gpl->color);
928         }
929         
930         if (gpl->gstep_next) {
931                 bGPDframe *gf;
932                 float fac;
933                 
934                 /* now draw next frames */
935                 for (gf = gpf->next; gf; gf = gf->next) {
936                         /* check if frame is drawable */
937                         if ((gf->framenum - gpf->framenum) <= gpl->gstep_next) {
938                                 /* alpha decreases with distance from curframe index */
939                                 fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep_next + 1));
940                                 color[3] = alpha * fac * 0.66f;
941                                 gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
942                         }
943                         else
944                                 break;
945                 }
946         }
947         else {
948                 /* draw the strokes for the ghost frames (at half of the alpha set by user) */
949                 if (gpf->next) {
950                         color[3] = (alpha / 4);
951                         gp_draw_strokes(gpf->next, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
952                 }
953         }
954         
955         /* 3) restore alpha */
956         glColor4fv(gpl->color);
957 }
958
959 /* loop over gpencil data layers, drawing them */
960 static void gp_draw_data_layers(bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag)
961 {
962         bGPDlayer *gpl;
963         
964         for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
965                 bGPDframe *gpf;
966                 
967                 bool debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? true : false;
968                 short lthick = gpl->thickness;
969                 
970                 /* don't draw layer if hidden */
971                 if (gpl->flag & GP_LAYER_HIDE)
972                         continue;
973                 
974                 /* get frame to draw */
975                 gpf = gpencil_layer_getframe(gpl, cfra, 0);
976                 if (gpf == NULL)
977                         continue;
978                 
979                 /* set basic stroke thickness */
980                 glLineWidth(lthick);
981                 
982                 /* Add layer drawing settings to the set of "draw flags"
983                  * NOTE: If the setting doesn't apply, it *must* be cleared,
984                  *       as dflag's carry over from the previous layer
985                  */
986 #define GP_DRAWFLAG_APPLY(condition, draw_flag_value)     { \
987                         if (condition) dflag |= (draw_flag_value);      \
988                         else           dflag &= ~(draw_flag_value);     \
989                 } (void)0
990                 
991                 /* xray... */
992                 GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_NO_XRAY), GP_DRAWDATA_NO_XRAY);
993                 
994                 /* volumetric strokes... */
995                 GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_VOLUMETRIC), GP_DRAWDATA_VOLUMETRIC);
996                 
997                 /* fill strokes... */
998                 // XXX: this is not a very good limit
999                 GP_DRAWFLAG_APPLY((gpl->fill[3] > 0.001f), GP_DRAWDATA_FILL);
1000 #undef GP_DRAWFLAG_APPLY
1001                 
1002                 /* draw 'onionskins' (frame left + right) */
1003                 if ((gpl->flag & GP_LAYER_ONIONSKIN) && !(dflag & GP_DRAWDATA_NO_ONIONS)) {
1004                         /* Drawing method - only immediately surrounding (gstep = 0),
1005                          * or within a frame range on either side (gstep > 0)
1006                          */
1007                         gp_draw_onionskins(gpl, gpf, offsx, offsy, winx, winy, cfra, dflag, debug, lthick);
1008                 }
1009                 
1010                 /* draw the strokes already in active frame */
1011                 gp_draw_strokes(gpf, offsx, offsy, winx, winy, dflag, debug, lthick, gpl->color, gpl->fill);
1012                 
1013                 /* Draw verts of selected strokes
1014                  *  - when doing OpenGL renders, we don't want to be showing these, as that ends up flickering
1015                  *      - locked layers can't be edited, so there's no point showing these verts
1016                  *    as they will have no bearings on what gets edited
1017                  *  - only show when in editmode, since operators shouldn't work otherwise
1018                  *    (NOTE: doing it this way means that the toggling editmode shows visible change immediately)
1019                  */
1020                 /* XXX: perhaps we don't want to show these when users are drawing... */
1021                 if ((G.f & G_RENDER_OGL) == 0 &&
1022                     (gpl->flag & GP_LAYER_LOCKED) == 0 &&
1023                     (gpd->flag & GP_DATA_STROKE_EDITMODE))
1024                 {
1025                         gp_draw_strokes_edit(gpf, offsx, offsy, winx, winy, dflag,
1026                                              (gpl->color[3] < 0.95f) ? gpl->color : NULL);
1027                 }
1028                 
1029                 /* Check if may need to draw the active stroke cache, only if this layer is the active layer
1030                  * that is being edited. (Stroke buffer is currently stored in gp-data)
1031                  */
1032                 if (ED_gpencil_session_active() && (gpl->flag & GP_LAYER_ACTIVE) &&
1033                     (gpf->flag & GP_FRAME_PAINT))
1034                 {
1035                         /* Set color for drawing buffer stroke - since this may not be set yet */
1036                         glColor4fv(gpl->color);
1037                         
1038                         /* Buffer stroke needs to be drawn with a different linestyle
1039                          * to help differentiate them from normal strokes.
1040                          * 
1041                          * It should also be noted that sbuffer contains temporary point types
1042                          * i.e. tGPspoints NOT bGPDspoints
1043                          */
1044                         if (gpl->flag & GP_LAYER_VOLUMETRIC) {
1045                                 gp_draw_stroke_volumetric_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag);
1046                         }
1047                         else {
1048                                 gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag);
1049                         }
1050                 }
1051         }
1052 }
1053
1054 /* draw a short status message in the top-right corner */
1055 static void gp_draw_status_text(bGPdata *gpd, ARegion *ar)
1056 {
1057         rcti rect;
1058         
1059         /* Cannot draw any status text when drawing OpenGL Renders */
1060         if (G.f & G_RENDER_OGL)
1061                 return;
1062         
1063         /* Get bounds of region - Necessary to avoid problems with region overlap */
1064         ED_region_visible_rect(ar, &rect);
1065         
1066         /* for now, this should only be used to indicate when we are in stroke editmode */
1067         if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
1068                 const char *printable = IFACE_("GPencil Stroke Editing");
1069                 float       printable_size[2];
1070                 int xco, yco;
1071                 
1072                 BLF_width_and_height_default(printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
1073                 
1074                 xco = (rect.xmax - U.widget_unit) - (int)printable_size[0];
1075                 yco = (rect.ymax - U.widget_unit);
1076                 
1077                 /* text label */
1078                 UI_ThemeColor(TH_TEXT_HI);
1079 #ifdef WITH_INTERNATIONAL
1080                 BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
1081 #else
1082                 BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
1083 #endif
1084                 
1085                 /* grease pencil icon... */
1086                 // XXX: is this too intrusive?
1087                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1088                 glEnable(GL_BLEND);
1089                 
1090                 xco -= U.widget_unit;
1091                 yco -= (int)printable_size[1] / 2;
1092
1093                 UI_icon_draw(xco, yco, ICON_GREASEPENCIL);
1094                 
1095                 glDisable(GL_BLEND);
1096         }
1097 }
1098
1099 /* draw grease-pencil datablock */
1100 static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag)
1101 {
1102         /* reset line drawing style (in case previous user didn't reset) */
1103         setlinestyle(0);
1104         
1105         /* turn on smooth lines (i.e. anti-aliasing) */
1106         glEnable(GL_LINE_SMOOTH);
1107         
1108         /* XXX: turn on some way of ensuring that the polygon edges get smoothed 
1109          *      GL_POLYGON_SMOOTH is nasty and shouldn't be used, as it ends up
1110          *      creating internal white rays due to the ways it accumulates stuff
1111          */
1112         
1113         /* turn on alpha-blending */
1114         glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1115         glEnable(GL_BLEND);
1116         
1117         /* draw! */
1118         gp_draw_data_layers(gpd, offsx, offsy, winx, winy, cfra, dflag);
1119         
1120         /* turn off alpha blending, then smooth lines */
1121         glDisable(GL_BLEND); // alpha blending
1122         glDisable(GL_LINE_SMOOTH); // smooth lines
1123         
1124         /* restore initial gl conditions */
1125         glLineWidth(1.0);
1126         glPointSize(1.0);
1127         glColor4f(0, 0, 0, 1);
1128 }
1129
1130 /* if we have strokes for scenes (3d view)/clips (movie clip editor)
1131  * and objects/tracks, multiple data blocks have to be drawn */
1132 static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, int winx, int winy,
1133                              int cfra, int dflag, const char spacetype)
1134 {
1135         bGPdata *gpd_source = NULL;
1136         
1137         if (scene) {
1138                 if (spacetype == SPACE_VIEW3D) {
1139                         gpd_source = (scene->gpd ? scene->gpd : NULL);
1140                 }
1141                 else if (spacetype == SPACE_CLIP && scene->clip) {
1142                         /* currently drawing only gpencil data from either clip or track, but not both - XXX fix logic behind */
1143                         gpd_source = (scene->clip->gpd ? scene->clip->gpd : NULL);
1144                 }
1145                 
1146                 if (gpd_source) {
1147                         gp_draw_data(gpd_source, offsx, offsy, winx, winy, cfra, dflag);
1148                 }
1149         }
1150         
1151         /* scene/clip data has already been drawn, only object/track data is drawn here
1152          * if gpd_source == gpd, we don't have any object/track data and we can skip */
1153         if (gpd_source == NULL || (gpd_source && gpd_source != gpd)) {
1154                 gp_draw_data(gpd, offsx, offsy, winx, winy, cfra, dflag);
1155         }
1156 }
1157
1158 /* ----- Grease Pencil Sketches Drawing API ------ */
1159
1160 /* ............................
1161  * XXX
1162  *      We need to review the calls below, since they may be/are not that suitable for
1163  *      the new ways that we intend to be drawing data...
1164  * ............................ */
1165
1166 /* draw grease-pencil sketches to specified 2d-view that uses ibuf corrections */
1167 void ED_gpencil_draw_2dimage(const bContext *C)
1168 {
1169         ScrArea *sa = CTX_wm_area(C);
1170         ARegion *ar = CTX_wm_region(C);
1171         Scene *scene = CTX_data_scene(C);
1172         bGPdata *gpd;
1173         int offsx, offsy, sizex, sizey;
1174         int dflag = GP_DRAWDATA_NOSTATUS;
1175         
1176         gpd = ED_gpencil_data_get_active(C); // XXX
1177         if (gpd == NULL) return;
1178         
1179         /* calculate rect */
1180         switch (sa->spacetype) {
1181                 case SPACE_IMAGE: /* image */
1182                 case SPACE_CLIP: /* clip */
1183                 {
1184                 
1185                         /* just draw using standard scaling (settings here are currently ignored anyways) */
1186                         /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */
1187                         offsx = 0;
1188                         offsy = 0;
1189                         sizex = ar->winx;
1190                         sizey = ar->winy;
1191                         
1192                         wmOrtho2(ar->v2d.cur.xmin, ar->v2d.cur.xmax, ar->v2d.cur.ymin, ar->v2d.cur.ymax);
1193                         
1194                         dflag |= GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_IEDITHACK;
1195                         break;
1196                 }
1197                 case SPACE_SEQ: /* sequence */
1198                 {
1199                         /* just draw using standard scaling (settings here are currently ignored anyways) */
1200                         offsx = 0;
1201                         offsy = 0;
1202                         sizex = ar->winx;
1203                         sizey = ar->winy;
1204                         
1205                         /* NOTE: I2D was used in 2.4x, but the old settings for that have been deprecated
1206                          * and everything moved to standard View2d
1207                          */
1208                         dflag |= GP_DRAWDATA_ONLYV2D;
1209                         break;
1210                 }
1211                 default: /* for spacetype not yet handled */
1212                         offsx = 0;
1213                         offsy = 0;
1214                         sizex = ar->winx;
1215                         sizey = ar->winy;
1216                         
1217                         dflag |= GP_DRAWDATA_ONLYI2D;
1218                         break;
1219         }
1220         
1221         
1222         /* draw it! */
1223         gp_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, sa->spacetype);
1224 }
1225
1226 /* draw grease-pencil sketches to specified 2d-view assuming that matrices are already set correctly
1227  * Note: this gets called twice - first time with onlyv2d=1 to draw 'canvas' strokes,
1228  * second time with onlyv2d=0 for screen-aligned strokes */
1229 void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d)
1230 {
1231         ScrArea *sa = CTX_wm_area(C);
1232         ARegion *ar = CTX_wm_region(C);
1233         Scene *scene = CTX_data_scene(C);
1234         bGPdata *gpd;
1235         int dflag = 0;
1236         
1237         /* check that we have grease-pencil stuff to draw */
1238         if (sa == NULL) return;
1239         gpd = ED_gpencil_data_get_active(C); // XXX
1240         if (gpd == NULL) return;
1241         
1242         /* special hack for Image Editor */
1243         /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */
1244         if (ELEM(sa->spacetype, SPACE_IMAGE, SPACE_CLIP))
1245                 dflag |= GP_DRAWDATA_IEDITHACK;
1246         
1247         /* draw it! */
1248         if (onlyv2d) dflag |= (GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_NOSTATUS);
1249         gp_draw_data_all(scene, gpd, 0, 0, ar->winx, ar->winy, CFRA, dflag, sa->spacetype);
1250         
1251         /* draw status text (if in screen/pixel-space) */
1252         if (onlyv2d == false) {
1253                 gp_draw_status_text(gpd, ar);
1254         }
1255 }
1256
1257 /* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly
1258  * Note: this gets called twice - first time with only3d=1 to draw 3d-strokes,
1259  * second time with only3d=0 for screen-aligned strokes */
1260 void ED_gpencil_draw_view3d(Scene *scene, View3D *v3d, ARegion *ar, bool only3d)
1261 {
1262         bGPdata *gpd;
1263         int dflag = 0;
1264         RegionView3D *rv3d = ar->regiondata;
1265         int offsx,  offsy,  winx,  winy;
1266         
1267         /* check that we have grease-pencil stuff to draw */
1268         gpd = ED_gpencil_data_get_active_v3d(scene, v3d);
1269         if (gpd == NULL) return;
1270         
1271         /* when rendering to the offscreen buffer we don't want to
1272          * deal with the camera border, otherwise map the coords to the camera border. */
1273         if ((rv3d->persp == RV3D_CAMOB) && !(G.f & G_RENDER_OGL)) {
1274                 rctf rectf;
1275                 ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &rectf, true); /* no shift */
1276                 
1277                 offsx = iroundf(rectf.xmin);
1278                 offsy = iroundf(rectf.ymin);
1279                 winx  = iroundf(rectf.xmax - rectf.xmin);
1280                 winy  = iroundf(rectf.ymax - rectf.ymin);
1281         }
1282         else {
1283                 offsx = 0;
1284                 offsy = 0;
1285                 winx  = ar->winx;
1286                 winy  = ar->winy;
1287         }
1288         
1289         /* set flags */
1290         if (only3d) {
1291                 /* 3D strokes/3D space:
1292                  * - only 3D space points
1293                  * - don't status text either (as it's the wrong space)
1294                  */
1295                 dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS);
1296         }
1297         
1298         if (v3d->flag2 & V3D_RENDER_OVERRIDE) {
1299                 /* don't draw status text when "only render" flag is set */
1300                 dflag |= GP_DRAWDATA_NOSTATUS;
1301         }
1302         
1303         /* draw it! */
1304         gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype);
1305         
1306         /* draw status text (if in screen/pixel-space) */
1307         if (only3d == false) {
1308                 gp_draw_status_text(gpd, ar);
1309         }
1310 }
1311
1312 void ED_gpencil_draw_ex(Scene *scene, bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype)
1313 {
1314         int dflag = GP_DRAWDATA_NOSTATUS | GP_DRAWDATA_ONLYV2D;
1315         
1316         gp_draw_data_all(scene, gpd, 0, 0, winx, winy, cfra, dflag, spacetype);
1317 }
1318
1319 /* ************************************************** */