73230e5fb0eee67cf2b1c69c5f88264f59fa52e5
[blender.git] / source / blender / editors / gpencil / annotate_paint.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2008/2018, Blender Foundation
17  * This is a new part of Blender
18  */
19
20 /** \file
21  * \ingroup edgpencil
22  */
23
24 #include <stdio.h>
25 #include <stddef.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <math.h>
29
30 #include "MEM_guardedalloc.h"
31
32 #include "BLI_blenlib.h"
33 #include "BLI_math.h"
34 #include "BLI_utildefines.h"
35 #include "BLI_math_geom.h"
36
37 #include "BLT_translation.h"
38
39 #include "PIL_time.h"
40
41 #include "BKE_colortools.h"
42 #include "BKE_context.h"
43 #include "BKE_global.h"
44 #include "BKE_gpencil.h"
45 #include "BKE_layer.h"
46 #include "BKE_main.h"
47 #include "BKE_report.h"
48 #include "BKE_screen.h"
49 #include "BKE_tracking.h"
50
51 #include "DNA_object_types.h"
52 #include "DNA_scene_types.h"
53 #include "DNA_gpencil_types.h"
54 #include "DNA_windowmanager_types.h"
55
56 #include "UI_view2d.h"
57
58 #include "ED_gpencil.h"
59 #include "ED_screen.h"
60 #include "ED_view3d.h"
61 #include "ED_clip.h"
62
63 #include "GPU_immediate.h"
64 #include "GPU_immediate_util.h"
65 #include "GPU_state.h"
66
67 #include "RNA_access.h"
68 #include "RNA_define.h"
69
70 #include "WM_api.h"
71 #include "WM_types.h"
72
73 #include "DEG_depsgraph.h"
74
75 #include "gpencil_intern.h"
76
77 /* ******************************************* */
78 /* 'Globals' and Defines */
79
80 /* values for tGPsdata->status */
81 typedef enum eGPencil_PaintStatus {
82   GP_STATUS_IDLING = 0, /* stroke isn't in progress yet */
83   GP_STATUS_PAINTING,   /* a stroke is in progress */
84   GP_STATUS_ERROR,      /* something wasn't correctly set up */
85   GP_STATUS_DONE,       /* painting done */
86   GP_STATUS_CAPTURE     /* capture event, but cancel */
87 } eGPencil_PaintStatus;
88
89 /* Return flags for adding points to stroke buffer */
90 typedef enum eGP_StrokeAdd_Result {
91   GP_STROKEADD_INVALID = -2,  /* error occurred - insufficient info to do so */
92   GP_STROKEADD_OVERFLOW = -1, /* error occurred - cannot fit any more points */
93   GP_STROKEADD_NORMAL,        /* point was successfully added */
94   GP_STROKEADD_FULL,          /* cannot add any more points to buffer */
95 } eGP_StrokeAdd_Result;
96
97 /* Runtime flags */
98 typedef enum eGPencil_PaintFlags {
99   GP_PAINTFLAG_FIRSTRUN = (1 << 0), /* operator just started */
100   GP_PAINTFLAG_STROKEADDED = (1 << 1),
101   GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2),
102   GP_PAINTFLAG_SELECTMASK = (1 << 3),
103 } eGPencil_PaintFlags;
104
105 /* Temporary 'Stroke' Operation data
106  *   "p" = op->customdata
107  */
108 typedef struct tGPsdata {
109   Main *bmain;
110   /** current scene from context. */
111   Scene *scene;
112   struct Depsgraph *depsgraph;
113
114   /** window where painting originated. */
115   wmWindow *win;
116   /** area where painting originated. */
117   ScrArea *sa;
118   /** region where painting originated. */
119   ARegion *ar;
120   /** needed for GP_STROKE_2DSPACE. */
121   View2D *v2d;
122   /** for using the camera rect within the 3d view. */
123   rctf *subrect;
124   rctf subrect_data;
125
126   /** settings to pass to gp_points_to_xy(). */
127   GP_SpaceConversion gsc;
128
129   /** pointer to owner of gp-datablock. */
130   PointerRNA ownerPtr;
131   /** gp-datablock layer comes from. */
132   bGPdata *gpd;
133   /** layer we're working on. */
134   bGPDlayer *gpl;
135   /** frame we're working on. */
136   bGPDframe *gpf;
137
138   /** projection-mode flags (toolsettings - eGPencil_Placement_Flags) */
139   char *align_flag;
140
141   /** current status of painting. */
142   eGPencil_PaintStatus status;
143   /** mode for painting. */
144   eGPencil_PaintModes paintmode;
145   /** flags that can get set during runtime (eGPencil_PaintFlags) */
146   eGPencil_PaintFlags flags;
147
148   /** radius of influence for eraser. */
149   short radius;
150
151   /** current mouse-position. */
152   float mval[2];
153   /** previous recorded mouse-position. */
154   float mvalo[2];
155
156   /** current stylus pressure. */
157   float pressure;
158   /** previous stylus pressure. */
159   float opressure;
160
161   /* These need to be doubles, as (at least under unix) they are in seconds since epoch,
162    * float (and its 7 digits precision) is definitively not enough here!
163    * double, with its 15 digits precision,
164    * ensures us millisecond precision for a few centuries at least.
165    */
166   /** Used when converting to path. */
167   double inittime;
168   /** Used when converting to path. */
169   double curtime;
170   /** Used when converting to path. */
171   double ocurtime;
172
173   /** Inverted transformation matrix applying when converting coords from screen-space
174    * to region space. */
175   float imat[4][4];
176   float mat[4][4];
177
178   /** custom color - hack for enforcing a particular color for track/mask editing. */
179   float custom_color[4];
180
181   /** radial cursor data for drawing eraser. */
182   void *erasercursor;
183
184   /** 1: line horizontal, 2: line vertical, other: not defined, second element position. */
185   short straight[2];
186
187   /** key used for invoking the operator. */
188   short keymodifier;
189 } tGPsdata;
190
191 /* ------ */
192
193 /* Macros for accessing sensitivity thresholds... */
194 /* minimum number of pixels mouse should move before new point created */
195 #define MIN_MANHATTEN_PX (U.gp_manhattendist)
196 /* minimum length of new segment before new point can be added */
197 #define MIN_EUCLIDEAN_PX (U.gp_euclideandist)
198
199 static bool gp_stroke_added_check(tGPsdata *p)
200 {
201   return (p->gpf && p->gpf->strokes.last && p->flags & GP_PAINTFLAG_STROKEADDED);
202 }
203
204 static void gp_stroke_added_enable(tGPsdata *p)
205 {
206   BLI_assert(p->gpf->strokes.last != NULL);
207   p->flags |= GP_PAINTFLAG_STROKEADDED;
208 }
209
210 /* ------ */
211 /* Forward defines for some functions... */
212
213 static void gp_session_validatebuffer(tGPsdata *p);
214
215 /* ******************************************* */
216 /* Context Wrangling... */
217
218 /* check if context is suitable for drawing */
219 static bool gpencil_draw_poll(bContext *C)
220 {
221   /* if is inside grease pencil draw mode cannot use annotations */
222   Object *obact = CTX_data_active_object(C);
223   ScrArea *sa = CTX_wm_area(C);
224   if ((sa) && (sa->spacetype == SPACE_VIEW3D)) {
225     if ((obact) && (obact->type == OB_GPENCIL) && (obact->mode == OB_MODE_PAINT_GPENCIL)) {
226       CTX_wm_operator_poll_msg_set(C, "Annotation cannot be used in grease pencil draw mode");
227       return false;
228     }
229   }
230
231   if (ED_operator_regionactive(C)) {
232     /* check if current context can support GPencil data */
233     if (ED_gpencil_data_get_pointers(C, NULL) != NULL) {
234       /* check if Grease Pencil isn't already running */
235       if (ED_gpencil_session_active() == 0) {
236         return true;
237       }
238       else {
239         CTX_wm_operator_poll_msg_set(C, "Annotation operator is already active");
240       }
241     }
242     else {
243       CTX_wm_operator_poll_msg_set(C, "Failed to find Grease Pencil data to draw into");
244     }
245   }
246   else {
247     CTX_wm_operator_poll_msg_set(C, "Active region not set");
248   }
249
250   return false;
251 }
252
253 /* check if projecting strokes into 3d-geometry in the 3D-View */
254 static bool gpencil_project_check(tGPsdata *p)
255 {
256   bGPdata *gpd = p->gpd;
257   return ((gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) &&
258           (*p->align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)));
259 }
260
261 /* ******************************************* */
262 /* Calculations/Conversions */
263
264 /* Utilities --------------------------------- */
265
266 /* get the reference point for stroke-point conversions */
267 static void gp_get_3d_reference(tGPsdata *p, float vec[3])
268 {
269   const float *fp = p->scene->cursor.location;
270
271   /* use 3D-cursor */
272   copy_v3_v3(vec, fp);
273 }
274
275 /* Stroke Editing ---------------------------- */
276
277 /* check if the current mouse position is suitable for adding a new point */
278 static bool gp_stroke_filtermval(tGPsdata *p, const float mval[2], float pmval[2])
279 {
280   int dx = (int)fabsf(mval[0] - pmval[0]);
281   int dy = (int)fabsf(mval[1] - pmval[1]);
282
283   /* if buffer is empty, just let this go through (i.e. so that dots will work) */
284   if (p->gpd->runtime.sbuffer_size == 0) {
285     return true;
286
287     /* check if mouse moved at least certain distance on both axes (best case)
288      * - aims to eliminate some jitter-noise from input when trying to draw straight lines freehand
289      */
290   }
291   else if ((dx > MIN_MANHATTEN_PX) && (dy > MIN_MANHATTEN_PX)) {
292     return true;
293
294     /* Check if the distance since the last point is significant enough:
295      * - Prevents points being added too densely
296      * - Distance here doesn't use sqrt to prevent slowness.
297      *   We should still be safe from overflows though.
298      */
299   }
300   else if ((dx * dx + dy * dy) > MIN_EUCLIDEAN_PX * MIN_EUCLIDEAN_PX) {
301     return true;
302
303     /* mouse 'didn't move' */
304   }
305   else {
306     return false;
307   }
308 }
309
310 /* convert screen-coordinates to buffer-coordinates */
311 static void gp_stroke_convertcoords(tGPsdata *p, const float mval[2], float out[3], float *depth)
312 {
313   bGPdata *gpd = p->gpd;
314
315   /* in 3d-space - pt->x/y/z are 3 side-by-side floats */
316   if (gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) {
317     int mval_i[2];
318     round_v2i_v2fl(mval_i, mval);
319     if (gpencil_project_check(p) && (ED_view3d_autodist_simple(p->ar, mval_i, out, 0, depth))) {
320       /* projecting onto 3D-Geometry
321        * - nothing more needs to be done here, since view_autodist_simple() has already done it
322        */
323     }
324     else {
325       float mval_prj[2];
326       float rvec[3], dvec[3];
327       float zfac;
328
329       /* Current method just converts each point in screen-coordinates to
330        * 3D-coordinates using the 3D-cursor as reference. In general, this
331        * works OK, but it could of course be improved.
332        *
333        * TODO:
334        * - investigate using nearest point(s) on a previous stroke as
335        *   reference point instead or as offset, for easier stroke matching
336        */
337
338       gp_get_3d_reference(p, rvec);
339       zfac = ED_view3d_calc_zfac(p->ar->regiondata, rvec, NULL);
340
341       if (ED_view3d_project_float_global(p->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) ==
342           V3D_PROJ_RET_OK) {
343         float mval_f[2];
344         sub_v2_v2v2(mval_f, mval_prj, mval);
345         ED_view3d_win_to_delta(p->ar, mval_f, dvec, zfac);
346         sub_v3_v3v3(out, rvec, dvec);
347       }
348       else {
349         zero_v3(out);
350       }
351     }
352   }
353
354   /* 2d - on 'canvas' (assume that p->v2d is set) */
355   else if ((gpd->runtime.sbuffer_sflag & GP_STROKE_2DSPACE) && (p->v2d)) {
356     UI_view2d_region_to_view(p->v2d, mval[0], mval[1], &out[0], &out[1]);
357     mul_v3_m4v3(out, p->imat, out);
358   }
359
360   /* 2d - relative to screen (viewport area) */
361   else {
362     if (p->subrect == NULL) { /* normal 3D view */
363       out[0] = (float)(mval[0]) / (float)(p->ar->winx) * 100;
364       out[1] = (float)(mval[1]) / (float)(p->ar->winy) * 100;
365     }
366     else { /* camera view, use subrect */
367       out[0] = ((mval[0] - p->subrect->xmin) / BLI_rctf_size_x(p->subrect)) * 100;
368       out[1] = ((mval[1] - p->subrect->ymin) / BLI_rctf_size_y(p->subrect)) * 100;
369     }
370   }
371 }
372
373 /* Apply smooth to buffer while drawing
374  * to smooth point C, use 2 before (A, B) and current point (D):
375  *
376  *   A----B-----C------D
377  *
378  * \param p: Temp data
379  * \param inf: Influence factor
380  * \param idx: Index of the last point (need minimum 3 points in the array)
381  */
382 static void gp_smooth_buffer(tGPsdata *p, float inf, int idx)
383 {
384   bGPdata *gpd = p->gpd;
385   short num_points = gpd->runtime.sbuffer_size;
386
387   /* Do nothing if not enough points to smooth out */
388   if ((num_points < 3) || (idx < 3) || (inf == 0.0f)) {
389     return;
390   }
391
392   tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
393   float steps = 4.0f;
394   if (idx < 4) {
395     steps--;
396   }
397
398   tGPspoint *pta = idx >= 4 ? &points[idx - 4] : NULL;
399   tGPspoint *ptb = idx >= 3 ? &points[idx - 3] : NULL;
400   tGPspoint *ptc = idx >= 2 ? &points[idx - 2] : NULL;
401   tGPspoint *ptd = &points[idx - 1];
402
403   float sco[2] = {0.0f};
404   float a[2], b[2], c[2], d[2];
405   const float average_fac = 1.0f / steps;
406
407   /* Compute smoothed coordinate by taking the ones nearby */
408   if (pta) {
409     copy_v2_v2(a, &pta->x);
410     madd_v2_v2fl(sco, a, average_fac);
411   }
412   if (ptb) {
413     copy_v2_v2(b, &ptb->x);
414     madd_v2_v2fl(sco, b, average_fac);
415   }
416   if (ptc) {
417     copy_v2_v2(c, &ptc->x);
418     madd_v2_v2fl(sco, c, average_fac);
419   }
420   if (ptd) {
421     copy_v2_v2(d, &ptd->x);
422     madd_v2_v2fl(sco, d, average_fac);
423   }
424
425   /* Based on influence factor, blend between original and optimal smoothed coordinate */
426   interp_v2_v2v2(c, c, sco, inf);
427   copy_v2_v2(&ptc->x, c);
428 }
429
430 /* add current stroke-point to buffer (returns whether point was successfully added) */
431 static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure, double curtime)
432 {
433   bGPdata *gpd = p->gpd;
434   tGPspoint *pt;
435   ToolSettings *ts = p->scene->toolsettings;
436
437   /* check painting mode */
438   if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
439     /* straight lines only - i.e. only store start and end point in buffer */
440     if (gpd->runtime.sbuffer_size == 0) {
441       /* first point in buffer (start point) */
442       pt = (tGPspoint *)(gpd->runtime.sbuffer);
443
444       /* store settings */
445       copy_v2_v2(&pt->x, mval);
446       /* T44932 - Pressure vals are unreliable, so ignore for now */
447       pt->pressure = 1.0f;
448       pt->strength = 1.0f;
449       pt->time = (float)(curtime - p->inittime);
450
451       /* increment buffer size */
452       gpd->runtime.sbuffer_size++;
453     }
454     else {
455       /* just reset the endpoint to the latest value
456        * - assume that pointers for this are always valid...
457        */
458       pt = ((tGPspoint *)(gpd->runtime.sbuffer) + 1);
459
460       /* store settings */
461       copy_v2_v2(&pt->x, mval);
462       /* T44932 - Pressure vals are unreliable, so ignore for now */
463       pt->pressure = 1.0f;
464       pt->strength = 1.0f;
465       pt->time = (float)(curtime - p->inittime);
466
467       /* now the buffer has 2 points (and shouldn't be allowed to get any larger) */
468       gpd->runtime.sbuffer_size = 2;
469     }
470
471     /* can keep carrying on this way :) */
472     return GP_STROKEADD_NORMAL;
473   }
474   else if (p->paintmode == GP_PAINTMODE_DRAW) { /* normal drawing */
475     /* check if still room in buffer */
476     if (gpd->runtime.sbuffer_size >= GP_STROKE_BUFFER_MAX) {
477       return GP_STROKEADD_OVERFLOW;
478     }
479
480     /* get pointer to destination point */
481     pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_size);
482
483     /* store settings */
484     copy_v2_v2(&pt->x, mval);
485     pt->pressure = pressure;
486     /* unused for annotations, but initialise for easier conversions to GP Object */
487     pt->strength = 1.0f;
488
489     /* point time */
490     pt->time = (float)(curtime - p->inittime);
491
492     /* increment counters */
493     gpd->runtime.sbuffer_size++;
494     /* smooth while drawing previous points with a reduction factor for previous */
495     for (int s = 0; s < 3; s++) {
496       gp_smooth_buffer(p, 0.5f * ((3.0f - s) / 3.0f), gpd->runtime.sbuffer_size - s);
497     }
498
499     /* check if another operation can still occur */
500     if (gpd->runtime.sbuffer_size == GP_STROKE_BUFFER_MAX) {
501       return GP_STROKEADD_FULL;
502     }
503     else {
504       return GP_STROKEADD_NORMAL;
505     }
506   }
507   else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
508     /* get pointer to destination point */
509     pt = (tGPspoint *)(gpd->runtime.sbuffer);
510
511     /* store settings */
512     copy_v2_v2(&pt->x, mval);
513     /* T44932 - Pressure vals are unreliable, so ignore for now */
514     pt->pressure = 1.0f;
515     pt->strength = 1.0f;
516     pt->time = (float)(curtime - p->inittime);
517
518     /* if there's stroke for this poly line session add (or replace last) point
519      * to stroke. This allows to draw lines more interactively (see new segment
520      * during mouse slide, e.g.)
521      */
522     if (gp_stroke_added_check(p)) {
523       bGPDstroke *gps = p->gpf->strokes.last;
524       bGPDspoint *pts;
525
526       /* first time point is adding to temporary buffer -- need to allocate new point in stroke */
527       if (gpd->runtime.sbuffer_size == 0) {
528         gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
529         gps->totpoints++;
530       }
531
532       pts = &gps->points[gps->totpoints - 1];
533
534       /* special case for poly lines: normally,
535        * depth is needed only when creating new stroke from buffer,
536        * but poly lines are converting to stroke instantly,
537        * so initialize depth buffer before converting coordinates
538        */
539       if (gpencil_project_check(p)) {
540         View3D *v3d = p->sa->spacedata.first;
541
542         view3d_region_operator_needs_opengl(p->win, p->ar);
543         ED_view3d_autodist_init(
544             p->depsgraph, p->ar, v3d, (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
545       }
546
547       /* convert screen-coordinates to appropriate coordinates (and store them) */
548       gp_stroke_convertcoords(p, &pt->x, &pts->x, NULL);
549
550       /* copy pressure and time */
551       pts->pressure = pt->pressure;
552       pts->strength = pt->strength;
553       pts->time = pt->time;
554
555       /* force fill recalc */
556       gps->flag |= GP_STROKE_RECALC_GEOMETRY;
557     }
558
559     /* increment counters */
560     if (gpd->runtime.sbuffer_size == 0) {
561       gpd->runtime.sbuffer_size++;
562     }
563
564     return GP_STROKEADD_NORMAL;
565   }
566
567   /* return invalid state for now... */
568   return GP_STROKEADD_INVALID;
569 }
570
571 /* simplify a stroke (in buffer) before storing it
572  * - applies a reverse Chaikin filter
573  * - code adapted from etch-a-ton branch
574  */
575 static void gp_stroke_simplify(tGPsdata *p)
576 {
577   bGPdata *gpd = p->gpd;
578   tGPspoint *old_points = (tGPspoint *)gpd->runtime.sbuffer;
579   short num_points = gpd->runtime.sbuffer_size;
580   short flag = gpd->runtime.sbuffer_sflag;
581   short i, j;
582
583   /* only simplify if simplification is enabled, and we're not doing a straight line */
584   if (!(U.gp_settings & GP_PAINT_DOSIMPLIFY) || (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT)) {
585     return;
586   }
587
588   /* don't simplify if less than 4 points in buffer */
589   if ((num_points <= 4) || (old_points == NULL)) {
590     return;
591   }
592
593   /* clear buffer (but don't free mem yet) so that we can write to it
594    * - firstly set sbuffer to NULL, so a new one is allocated
595    * - secondly, reset flag after, as it gets cleared auto
596    */
597   gpd->runtime.sbuffer = NULL;
598   gp_session_validatebuffer(p);
599   gpd->runtime.sbuffer_sflag = flag;
600
601 /* macro used in loop to get position of new point
602  * - used due to the mixture of datatypes in use here
603  */
604 #define GP_SIMPLIFY_AVPOINT(offs, sfac) \
605   { \
606     co[0] += (float)(old_points[offs].x * sfac); \
607     co[1] += (float)(old_points[offs].y * sfac); \
608     pressure += old_points[offs].pressure * sfac; \
609     time += old_points[offs].time * sfac; \
610   } \
611   (void)0
612
613   /* XXX Here too, do not lose start and end points! */
614   gp_stroke_addpoint(
615       p, &old_points->x, old_points->pressure, p->inittime + (double)old_points->time);
616   for (i = 0, j = 0; i < num_points; i++) {
617     if (i - j == 3) {
618       float co[2], pressure, time;
619       float mco[2];
620
621       /* initialize values */
622       co[0] = 0.0f;
623       co[1] = 0.0f;
624       pressure = 0.0f;
625       time = 0.0f;
626
627       /* using macro, calculate new point */
628       GP_SIMPLIFY_AVPOINT(j, -0.25f);
629       GP_SIMPLIFY_AVPOINT(j + 1, 0.75f);
630       GP_SIMPLIFY_AVPOINT(j + 2, 0.75f);
631       GP_SIMPLIFY_AVPOINT(j + 3, -0.25f);
632
633       /* set values for adding */
634       mco[0] = co[0];
635       mco[1] = co[1];
636
637       /* ignore return values on this... assume to be ok for now */
638       gp_stroke_addpoint(p, mco, pressure, p->inittime + (double)time);
639
640       j += 2;
641     }
642   }
643   gp_stroke_addpoint(p,
644                      &old_points[num_points - 1].x,
645                      old_points[num_points - 1].pressure,
646                      p->inittime + (double)old_points[num_points - 1].time);
647
648   /* free old buffer */
649   MEM_freeN(old_points);
650 }
651
652 /* make a new stroke from the buffer data */
653 static void gp_stroke_newfrombuffer(tGPsdata *p)
654 {
655   bGPdata *gpd = p->gpd;
656   bGPDlayer *gpl = p->gpl;
657   bGPDstroke *gps;
658   bGPDspoint *pt;
659   tGPspoint *ptc;
660   ToolSettings *ts = p->scene->toolsettings;
661
662   int i, totelem;
663   /* Since strokes are so fine, when using their depth we need a margin
664    * otherwise they might get missed. */
665   int depth_margin = (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0;
666
667   /* get total number of points to allocate space for
668    * - drawing straight-lines only requires the endpoints
669    */
670   if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
671     totelem = (gpd->runtime.sbuffer_size >= 2) ? 2 : gpd->runtime.sbuffer_size;
672   }
673   else {
674     totelem = gpd->runtime.sbuffer_size;
675   }
676
677   /* exit with error if no valid points from this stroke */
678   if (totelem == 0) {
679     if (G.debug & G_DEBUG) {
680       printf("Error: No valid points in stroke buffer to convert (tot=%d)\n",
681              gpd->runtime.sbuffer_size);
682     }
683     return;
684   }
685
686   /* special case for poly line -- for already added stroke during session
687    * coordinates are getting added to stroke immediately to allow more
688    * interactive behavior
689    */
690   if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
691     if (gp_stroke_added_check(p)) {
692       return;
693     }
694   }
695
696   /* allocate memory for a new stroke */
697   gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
698
699   /* copy appropriate settings for stroke */
700   gps->totpoints = totelem;
701   gps->thickness = gpl->thickness;
702   gps->gradient_f = 1.0f;
703   gps->gradient_s[0] = 1.0f;
704   gps->gradient_s[1] = 1.0f;
705   gps->flag = gpd->runtime.sbuffer_sflag;
706   gps->inittime = p->inittime;
707
708   /* enable recalculation flag by default (only used if hq fill) */
709   gps->flag |= GP_STROKE_RECALC_GEOMETRY;
710
711   /* allocate enough memory for a continuous array for storage points */
712   gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
713   gps->tot_triangles = 0;
714
715   /* set pointer to first non-initialized point */
716   pt = gps->points + (gps->totpoints - totelem);
717
718   /* copy points from the buffer to the stroke */
719   if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
720     /* straight lines only -> only endpoints */
721     {
722       /* first point */
723       ptc = gpd->runtime.sbuffer;
724
725       /* convert screen-coordinates to appropriate coordinates (and store them) */
726       gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
727
728       /* copy pressure and time */
729       pt->pressure = ptc->pressure;
730       pt->strength = ptc->strength;
731       CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
732       pt->time = ptc->time;
733
734       pt++;
735     }
736
737     if (totelem == 2) {
738       /* last point if applicable */
739       ptc = ((tGPspoint *)gpd->runtime.sbuffer) + (gpd->runtime.sbuffer_size - 1);
740
741       /* convert screen-coordinates to appropriate coordinates (and store them) */
742       gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
743
744       /* copy pressure and time */
745       pt->pressure = ptc->pressure;
746       pt->strength = ptc->strength;
747       CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
748       pt->time = ptc->time;
749     }
750   }
751   else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
752     /* first point */
753     ptc = gpd->runtime.sbuffer;
754
755     /* convert screen-coordinates to appropriate coordinates (and store them) */
756     gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
757
758     /* copy pressure and time */
759     pt->pressure = ptc->pressure;
760     pt->strength = ptc->strength;
761     pt->time = ptc->time;
762   }
763   else {
764     float *depth_arr = NULL;
765
766     /* get an array of depths, far depths are blended */
767     if (gpencil_project_check(p)) {
768       int mval_i[2], mval_prev[2] = {0};
769       int interp_depth = 0;
770       int found_depth = 0;
771
772       depth_arr = MEM_mallocN(sizeof(float) * gpd->runtime.sbuffer_size, "depth_points");
773
774       for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_size; i++, ptc++, pt++) {
775         round_v2i_v2fl(mval_i, &ptc->x);
776
777         if ((ED_view3d_autodist_depth(p->ar, mval_i, depth_margin, depth_arr + i) == 0) &&
778             (i && (ED_view3d_autodist_depth_seg(
779                        p->ar, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) {
780           interp_depth = true;
781         }
782         else {
783           found_depth = true;
784         }
785
786         copy_v2_v2_int(mval_prev, mval_i);
787       }
788
789       if (found_depth == false) {
790         /* eeh... not much we can do.. :/, ignore depth in this case, use the 3D cursor */
791         for (i = gpd->runtime.sbuffer_size - 1; i >= 0; i--) {
792           depth_arr[i] = 0.9999f;
793         }
794       }
795       else {
796         if (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE_ENDPOINTS) {
797           /* remove all info between the valid endpoints */
798           int first_valid = 0;
799           int last_valid = 0;
800
801           for (i = 0; i < gpd->runtime.sbuffer_size; i++) {
802             if (depth_arr[i] != FLT_MAX) {
803               break;
804             }
805           }
806           first_valid = i;
807
808           for (i = gpd->runtime.sbuffer_size - 1; i >= 0; i--) {
809             if (depth_arr[i] != FLT_MAX) {
810               break;
811             }
812           }
813           last_valid = i;
814
815           /* invalidate non-endpoints, so only blend between first and last */
816           for (i = first_valid + 1; i < last_valid; i++) {
817             depth_arr[i] = FLT_MAX;
818           }
819
820           interp_depth = true;
821         }
822
823         if (interp_depth) {
824           interp_sparse_array(depth_arr, gpd->runtime.sbuffer_size, FLT_MAX);
825         }
826       }
827     }
828
829     pt = gps->points;
830
831     /* convert all points (normal behavior) */
832     for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_size && ptc;
833          i++, ptc++, pt++) {
834       /* convert screen-coordinates to appropriate coordinates (and store them) */
835       gp_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL);
836
837       /* copy pressure and time */
838       pt->pressure = ptc->pressure;
839       pt->strength = ptc->strength;
840       CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
841       pt->time = ptc->time;
842     }
843
844     if (depth_arr) {
845       MEM_freeN(depth_arr);
846     }
847   }
848
849   /* add stroke to frame */
850   BLI_addtail(&p->gpf->strokes, gps);
851   gp_stroke_added_enable(p);
852 }
853
854 /* --- 'Eraser' for 'Paint' Tool ------ */
855
856 /* helper to free a stroke
857  * NOTE: gps->dvert and gps->triangles should be NULL, but check anyway for good measure
858  */
859 static void gp_free_stroke(bGPDframe *gpf, bGPDstroke *gps)
860 {
861   if (gps->points) {
862     MEM_freeN(gps->points);
863   }
864
865   if (gps->dvert) {
866     BKE_gpencil_free_stroke_weights(gps);
867     MEM_freeN(gps->dvert);
868   }
869
870   if (gps->triangles) {
871     MEM_freeN(gps->triangles);
872   }
873
874   BLI_freelinkN(&gpf->strokes, gps);
875 }
876
877 /* which which point is infront (result should only be used for comparison) */
878 static float view3d_point_depth(const RegionView3D *rv3d, const float co[3])
879 {
880   if (rv3d->is_persp) {
881     return ED_view3d_calc_zfac(rv3d, co, NULL);
882   }
883   else {
884     return -dot_v3v3(rv3d->viewinv[2], co);
885   }
886 }
887
888 /* only erase stroke points that are visible (3d view) */
889 static bool gp_stroke_eraser_is_occluded(tGPsdata *p,
890                                          const bGPDspoint *pt,
891                                          const int x,
892                                          const int y)
893 {
894   if ((p->sa->spacetype == SPACE_VIEW3D) && (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH)) {
895     RegionView3D *rv3d = p->ar->regiondata;
896     const int mval_i[2] = {x, y};
897     float mval_3d[3];
898
899     if (ED_view3d_autodist_simple(p->ar, mval_i, mval_3d, 0, NULL)) {
900       const float depth_mval = view3d_point_depth(rv3d, mval_3d);
901       const float depth_pt = view3d_point_depth(rv3d, &pt->x);
902
903       if (depth_pt > depth_mval) {
904         return true;
905       }
906     }
907   }
908   return false;
909 }
910
911 /* eraser tool - evaluation per stroke */
912 /* TODO: this could really do with some optimization (KD-Tree/BVH?) */
913 static void gp_stroke_eraser_dostroke(tGPsdata *p,
914                                       bGPDframe *gpf,
915                                       bGPDstroke *gps,
916                                       const float mval[2],
917                                       const float mvalo[2],
918                                       const int radius,
919                                       const rcti *rect)
920 {
921   bGPDspoint *pt1, *pt2;
922   int pc1[2] = {0};
923   int pc2[2] = {0};
924   int i;
925   int mval_i[2];
926   round_v2i_v2fl(mval_i, mval);
927
928   if (gps->totpoints == 0) {
929     /* just free stroke */
930     gp_free_stroke(gpf, gps);
931   }
932   else if (gps->totpoints == 1) {
933     /* only process if it hasn't been masked out... */
934     if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) {
935       gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]);
936
937       /* do boundbox check first */
938       if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
939         /* only check if point is inside */
940         if (len_v2v2_int(mval_i, pc1) <= radius) {
941           /* free stroke */
942           gp_free_stroke(gpf, gps);
943         }
944       }
945     }
946   }
947   else {
948     /* Perform culling? */
949     bool do_cull = false;
950
951     /* Clear Tags
952      *
953      * Note: It's better this way, as we are sure that
954      * we don't miss anything, though things will be
955      * slightly slower as a result
956      */
957     for (i = 0; i < gps->totpoints; i++) {
958       bGPDspoint *pt = &gps->points[i];
959       pt->flag &= ~GP_SPOINT_TAG;
960     }
961
962     /* First Pass: Loop over the points in the stroke
963      *   1) Thin out parts of the stroke under the brush
964      *   2) Tag "too thin" parts for removal (in second pass)
965      */
966     for (i = 0; (i + 1) < gps->totpoints; i++) {
967       /* get points to work with */
968       pt1 = gps->points + i;
969       pt2 = gps->points + i + 1;
970
971       /* only process if it hasn't been masked out... */
972       if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT)) {
973         continue;
974       }
975
976       gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]);
977       gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]);
978
979       /* Check that point segment of the boundbox of the eraser stroke */
980       if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
981           ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
982         /* Check if point segment of stroke had anything to do with
983          * eraser region  (either within stroke painted, or on its lines)
984          *  - this assumes that linewidth is irrelevant
985          */
986         if (gp_stroke_inside_circle(mval, mvalo, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
987           if ((gp_stroke_eraser_is_occluded(p, pt1, pc1[0], pc1[1]) == false) ||
988               (gp_stroke_eraser_is_occluded(p, pt2, pc2[0], pc2[1]) == false)) {
989             /* Edge is affected - Check individual points now */
990             if (len_v2v2_int(mval_i, pc1) <= radius) {
991               pt1->flag |= GP_SPOINT_TAG;
992             }
993             if (len_v2v2_int(mval_i, pc2) <= radius) {
994               pt2->flag |= GP_SPOINT_TAG;
995             }
996             do_cull = true;
997           }
998         }
999       }
1000     }
1001
1002     /* Second Pass: Remove any points that are tagged */
1003     if (do_cull) {
1004       gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG, false, 0);
1005     }
1006   }
1007 }
1008
1009 /* erase strokes which fall under the eraser strokes */
1010 static void gp_stroke_doeraser(tGPsdata *p)
1011 {
1012   bGPDframe *gpf = p->gpf;
1013   bGPDstroke *gps, *gpn;
1014   rcti rect;
1015
1016   /* rect is rectangle of eraser */
1017   rect.xmin = p->mval[0] - p->radius;
1018   rect.ymin = p->mval[1] - p->radius;
1019   rect.xmax = p->mval[0] + p->radius;
1020   rect.ymax = p->mval[1] + p->radius;
1021
1022   if (p->sa->spacetype == SPACE_VIEW3D) {
1023     if (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH) {
1024       View3D *v3d = p->sa->spacedata.first;
1025       view3d_region_operator_needs_opengl(p->win, p->ar);
1026       ED_view3d_autodist_init(p->depsgraph, p->ar, v3d, 0);
1027     }
1028   }
1029
1030   /* loop over strokes of active layer only (session init already took care of ensuring validity),
1031    * checking segments for intersections to remove
1032    */
1033   for (gps = gpf->strokes.first; gps; gps = gpn) {
1034     gpn = gps->next;
1035     /* Not all strokes in the datablock may be valid in the current editor/context
1036      * (e.g. 2D space strokes in the 3D view, if the same datablock is shared)
1037      */
1038     if (ED_gpencil_stroke_can_use_direct(p->sa, gps)) {
1039       gp_stroke_eraser_dostroke(p, gpf, gps, p->mval, p->mvalo, p->radius, &rect);
1040     }
1041   }
1042 }
1043
1044 /* ******************************************* */
1045 /* Sketching Operator */
1046
1047 /* clear the session buffers (call this before AND after a paint operation) */
1048 static void gp_session_validatebuffer(tGPsdata *p)
1049 {
1050   bGPdata *gpd = p->gpd;
1051
1052   /* clear memory of buffer (or allocate it if starting a new session) */
1053   if (gpd->runtime.sbuffer) {
1054     /* printf("\t\tGP - reset sbuffer\n"); */
1055     memset(gpd->runtime.sbuffer, 0, sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX);
1056   }
1057   else {
1058     /* printf("\t\tGP - allocate sbuffer\n"); */
1059     gpd->runtime.sbuffer = MEM_callocN(sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX,
1060                                        "gp_session_strokebuffer");
1061   }
1062
1063   /* reset indices */
1064   gpd->runtime.sbuffer_size = 0;
1065
1066   /* reset flags */
1067   gpd->runtime.sbuffer_sflag = 0;
1068
1069   /* reset inittime */
1070   p->inittime = 0.0;
1071 }
1072
1073 /* (re)init new painting data */
1074 static bool gp_session_initdata(bContext *C, tGPsdata *p)
1075 {
1076   Main *bmain = CTX_data_main(C);
1077   bGPdata **gpd_ptr = NULL;
1078   ScrArea *curarea = CTX_wm_area(C);
1079   ARegion *ar = CTX_wm_region(C);
1080   ToolSettings *ts = CTX_data_tool_settings(C);
1081
1082   /* make sure the active view (at the starting time) is a 3d-view */
1083   if (curarea == NULL) {
1084     p->status = GP_STATUS_ERROR;
1085     if (G.debug & G_DEBUG) {
1086       printf("Error: No active view for painting\n");
1087     }
1088     return 0;
1089   }
1090
1091   /* pass on current scene and window */
1092   p->bmain = CTX_data_main(C);
1093   p->scene = CTX_data_scene(C);
1094   p->depsgraph = CTX_data_depsgraph(C);
1095   p->win = CTX_wm_window(C);
1096
1097   unit_m4(p->imat);
1098   unit_m4(p->mat);
1099
1100   switch (curarea->spacetype) {
1101     /* supported views first */
1102     case SPACE_VIEW3D: {
1103       /* View3D *v3d = curarea->spacedata.first; */
1104       /* RegionView3D *rv3d = ar->regiondata; */
1105
1106       /* set current area
1107        * - must verify that region data is 3D-view (and not something else)
1108        */
1109       /* CAUTION: If this is the "toolbar", then this will change on the first stroke */
1110       p->sa = curarea;
1111       p->ar = ar;
1112       p->align_flag = &ts->annotate_v3d_align;
1113
1114       if (ar->regiondata == NULL) {
1115         p->status = GP_STATUS_ERROR;
1116         if (G.debug & G_DEBUG) {
1117           printf(
1118               "Error: 3D-View active region doesn't have any region data, so cannot be "
1119               "drawable\n");
1120         }
1121         return 0;
1122       }
1123       break;
1124     }
1125     case SPACE_NODE: {
1126       /* SpaceNode *snode = curarea->spacedata.first; */
1127
1128       /* set current area */
1129       p->sa = curarea;
1130       p->ar = ar;
1131       p->v2d = &ar->v2d;
1132       p->align_flag = &ts->gpencil_v2d_align;
1133       break;
1134     }
1135     case SPACE_SEQ: {
1136       SpaceSeq *sseq = curarea->spacedata.first;
1137
1138       /* set current area */
1139       p->sa = curarea;
1140       p->ar = ar;
1141       p->v2d = &ar->v2d;
1142       p->align_flag = &ts->gpencil_seq_align;
1143
1144       /* check that gpencil data is allowed to be drawn */
1145       if (sseq->mainb == SEQ_DRAW_SEQUENCE) {
1146         p->status = GP_STATUS_ERROR;
1147         if (G.debug & G_DEBUG) {
1148           printf("Error: In active view (sequencer), active mode doesn't support Grease Pencil\n");
1149         }
1150         return 0;
1151       }
1152       break;
1153     }
1154     case SPACE_IMAGE: {
1155       /* SpaceImage *sima = curarea->spacedata.first; */
1156
1157       /* set the current area */
1158       p->sa = curarea;
1159       p->ar = ar;
1160       p->v2d = &ar->v2d;
1161       p->align_flag = &ts->gpencil_ima_align;
1162       break;
1163     }
1164     case SPACE_CLIP: {
1165       SpaceClip *sc = curarea->spacedata.first;
1166       MovieClip *clip = ED_space_clip_get_clip(sc);
1167
1168       if (clip == NULL) {
1169         p->status = GP_STATUS_ERROR;
1170         return false;
1171       }
1172
1173       /* set the current area */
1174       p->sa = curarea;
1175       p->ar = ar;
1176       p->v2d = &ar->v2d;
1177       p->align_flag = &ts->gpencil_v2d_align;
1178
1179       invert_m4_m4(p->imat, sc->unistabmat);
1180
1181       /* custom color for new layer */
1182       p->custom_color[0] = 1.0f;
1183       p->custom_color[1] = 0.0f;
1184       p->custom_color[2] = 0.5f;
1185       p->custom_color[3] = 0.9f;
1186
1187       if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
1188         int framenr = ED_space_clip_get_clip_frame_number(sc);
1189         MovieTrackingTrack *track = BKE_tracking_track_get_active(&clip->tracking);
1190         MovieTrackingMarker *marker = track ? BKE_tracking_marker_get(track, framenr) : NULL;
1191
1192         if (marker) {
1193           p->imat[3][0] -= marker->pos[0];
1194           p->imat[3][1] -= marker->pos[1];
1195         }
1196         else {
1197           p->status = GP_STATUS_ERROR;
1198           return false;
1199         }
1200       }
1201
1202       invert_m4_m4(p->mat, p->imat);
1203       copy_m4_m4(p->gsc.mat, p->mat);
1204       break;
1205     }
1206     /* unsupported views */
1207     default: {
1208       p->status = GP_STATUS_ERROR;
1209       if (G.debug & G_DEBUG) {
1210         printf("Error: Annotations are not supported in this editor\n");
1211       }
1212       return 0;
1213     }
1214   }
1215
1216   /* get gp-data */
1217   gpd_ptr = ED_gpencil_data_get_pointers(C, &p->ownerPtr);
1218   if ((gpd_ptr == NULL) || !ED_gpencil_data_owner_is_annotation(&p->ownerPtr)) {
1219     p->status = GP_STATUS_ERROR;
1220     if (G.debug & G_DEBUG) {
1221       printf("Error: Current context doesn't allow for any Annotation data\n");
1222     }
1223     return 0;
1224   }
1225   else {
1226     /* if no existing GPencil block exists, add one */
1227     if (*gpd_ptr == NULL) {
1228       bGPdata *gpd = BKE_gpencil_data_addnew(bmain, "Annotations");
1229       *gpd_ptr = gpd;
1230
1231       /* mark datablock as being used for annotations */
1232       gpd->flag |= GP_DATA_ANNOTATIONS;
1233     }
1234     p->gpd = *gpd_ptr;
1235   }
1236
1237   if (ED_gpencil_session_active() == 0) {
1238     /* initialize undo stack,
1239      * also, existing undo stack would make buffer drawn
1240      */
1241     gpencil_undo_init(p->gpd);
1242   }
1243
1244   /* clear out buffer (stored in gp-data), in case something contaminated it */
1245   gp_session_validatebuffer(p);
1246
1247   return 1;
1248 }
1249
1250 /* init new painting session */
1251 static tGPsdata *gp_session_initpaint(bContext *C)
1252 {
1253   tGPsdata *p = NULL;
1254
1255   /* create new context data */
1256   p = MEM_callocN(sizeof(tGPsdata), "Annotation Drawing Data");
1257
1258   /* Try to initialise context data
1259    * WARNING: This may not always succeed (e.g. using GP in an annotation-only context)
1260    */
1261   if (gp_session_initdata(C, p) == 0) {
1262     /* Invalid state - Exit
1263      * NOTE: It should be safe to just free the data, since failing context checks should
1264      * only happen when no data has been allocated.
1265      */
1266     MEM_freeN(p);
1267     return NULL;
1268   }
1269
1270   /* Radius for eraser circle is defined in userprefs */
1271   /* NOTE: we do this here, so that if we exit immediately,
1272    *       erase size won't get lost
1273    */
1274   p->radius = U.gp_eraser;
1275
1276   /* return context data for running paint operator */
1277   return p;
1278 }
1279
1280 /* cleanup after a painting session */
1281 static void gp_session_cleanup(tGPsdata *p)
1282 {
1283   bGPdata *gpd = (p) ? p->gpd : NULL;
1284
1285   /* error checking */
1286   if (gpd == NULL) {
1287     return;
1288   }
1289
1290   /* free stroke buffer */
1291   if (gpd->runtime.sbuffer) {
1292     /* printf("\t\tGP - free sbuffer\n"); */
1293     MEM_freeN(gpd->runtime.sbuffer);
1294     gpd->runtime.sbuffer = NULL;
1295   }
1296
1297   /* clear flags */
1298   gpd->runtime.sbuffer_size = 0;
1299   gpd->runtime.sbuffer_sflag = 0;
1300   p->inittime = 0.0;
1301 }
1302
1303 static void gp_session_free(tGPsdata *p)
1304 {
1305   MEM_freeN(p);
1306 }
1307
1308 /* init new stroke */
1309 static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Depsgraph *depsgraph)
1310 {
1311   Scene *scene = p->scene;
1312   ToolSettings *ts = scene->toolsettings;
1313
1314   /* get active layer (or add a new one if non-existent) */
1315   p->gpl = BKE_gpencil_layer_getactive(p->gpd);
1316   if (p->gpl == NULL) {
1317     /* tag for annotations */
1318     p->gpd->flag |= GP_DATA_ANNOTATIONS;
1319     p->gpl = BKE_gpencil_layer_addnew(p->gpd, DATA_("Note"), true);
1320
1321     if (p->custom_color[3]) {
1322       copy_v3_v3(p->gpl->color, p->custom_color);
1323     }
1324   }
1325   if (p->gpl->flag & GP_LAYER_LOCKED) {
1326     p->status = GP_STATUS_ERROR;
1327     if (G.debug & G_DEBUG) {
1328       printf("Error: Cannot paint on locked layer\n");
1329     }
1330     return;
1331   }
1332
1333   /* get active frame (add a new one if not matching frame) */
1334   if (paintmode == GP_PAINTMODE_ERASER) {
1335     /* Eraser mode:
1336      * 1) Only allow erasing on the active layer (unlike for 3d-art Grease Pencil),
1337      *    since we won't be exposing layer locking in the UI
1338      * 2) Ensure that p->gpf refers to the frame used for the active layer
1339      *    (to avoid problems with other tools which expect it to exist)
1340      */
1341     bool has_layer_to_erase = false;
1342
1343     if (gpencil_layer_is_editable(p->gpl)) {
1344       /* Ensure that there's stuff to erase here (not including selection mask below)... */
1345       if (p->gpl->actframe && p->gpl->actframe->strokes.first) {
1346         has_layer_to_erase = true;
1347       }
1348     }
1349
1350     /* Ensure active frame is set correctly... */
1351     p->gpf = p->gpl->actframe;
1352
1353     /* Restrict eraser to only affecting selected strokes, if the "selection mask" is on
1354      * (though this is only available in editmode)
1355      */
1356     if (p->gpd->flag & GP_DATA_STROKE_EDITMODE) {
1357       if (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_SELECT_MASK) {
1358         p->flags |= GP_PAINTFLAG_SELECTMASK;
1359       }
1360     }
1361
1362     if (has_layer_to_erase == false) {
1363       p->status = GP_STATUS_CAPTURE;
1364       // if (G.debug & G_DEBUG)
1365       printf("Error: Eraser will not be affecting anything (gpencil_paint_init)\n");
1366       return;
1367     }
1368   }
1369   else {
1370     /* Drawing Modes - Add a new frame if needed on the active layer */
1371     short add_frame_mode = GP_GETFRAME_ADD_NEW;
1372
1373     if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) {
1374       add_frame_mode = GP_GETFRAME_ADD_COPY;
1375     }
1376     else {
1377       add_frame_mode = GP_GETFRAME_ADD_NEW;
1378     }
1379
1380     p->gpf = BKE_gpencil_layer_getframe(p->gpl, CFRA, add_frame_mode);
1381
1382     if (p->gpf == NULL) {
1383       p->status = GP_STATUS_ERROR;
1384       if (G.debug & G_DEBUG) {
1385         printf("Error: No frame created (gpencil_paint_init)\n");
1386       }
1387       return;
1388     }
1389     else {
1390       p->gpf->flag |= GP_FRAME_PAINT;
1391     }
1392   }
1393
1394   /* set 'eraser' for this stroke if using eraser */
1395   p->paintmode = paintmode;
1396   if (p->paintmode == GP_PAINTMODE_ERASER) {
1397     p->gpd->runtime.sbuffer_sflag |= GP_STROKE_ERASER;
1398
1399     /* check if we should respect depth while erasing */
1400     if (p->sa->spacetype == SPACE_VIEW3D) {
1401       if (p->gpl->flag & GP_LAYER_NO_XRAY) {
1402         p->flags |= GP_PAINTFLAG_V3D_ERASER_DEPTH;
1403       }
1404     }
1405   }
1406   else {
1407     /* disable eraser flags - so that we can switch modes during a session */
1408     p->gpd->runtime.sbuffer_sflag &= ~GP_STROKE_ERASER;
1409
1410     if (p->sa->spacetype == SPACE_VIEW3D) {
1411       if (p->gpl->flag & GP_LAYER_NO_XRAY) {
1412         p->flags &= ~GP_PAINTFLAG_V3D_ERASER_DEPTH;
1413       }
1414     }
1415   }
1416
1417   /* set 'initial run' flag, which is only used to denote when a new stroke is starting */
1418   p->flags |= GP_PAINTFLAG_FIRSTRUN;
1419
1420   /* when drawing in the camera view, in 2D space, set the subrect */
1421   p->subrect = NULL;
1422   if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) {
1423     if (p->sa->spacetype == SPACE_VIEW3D) {
1424       View3D *v3d = p->sa->spacedata.first;
1425       RegionView3D *rv3d = p->ar->regiondata;
1426
1427       /* for camera view set the subrect */
1428       if (rv3d->persp == RV3D_CAMOB) {
1429         /* no shift */
1430         ED_view3d_calc_camera_border(
1431             p->scene, depsgraph, p->ar, v3d, rv3d, &p->subrect_data, true);
1432         p->subrect = &p->subrect_data;
1433       }
1434     }
1435   }
1436
1437   /* init stroke point space-conversion settings... */
1438   p->gsc.gpd = p->gpd;
1439   p->gsc.gpl = p->gpl;
1440
1441   p->gsc.sa = p->sa;
1442   p->gsc.ar = p->ar;
1443   p->gsc.v2d = p->v2d;
1444
1445   p->gsc.subrect_data = p->subrect_data;
1446   p->gsc.subrect = p->subrect;
1447
1448   copy_m4_m4(p->gsc.mat, p->mat);
1449
1450   /* check if points will need to be made in view-aligned space */
1451   if (*p->align_flag & GP_PROJECT_VIEWSPACE) {
1452     switch (p->sa->spacetype) {
1453       case SPACE_VIEW3D: {
1454         p->gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE;
1455         break;
1456       }
1457       case SPACE_NODE:
1458       case SPACE_SEQ:
1459       case SPACE_IMAGE:
1460       case SPACE_CLIP: {
1461         p->gpd->runtime.sbuffer_sflag |= GP_STROKE_2DSPACE;
1462         break;
1463       }
1464     }
1465   }
1466 }
1467
1468 /* finish off a stroke (clears buffer, but doesn't finish the paint operation) */
1469 static void gp_paint_strokeend(tGPsdata *p)
1470 {
1471   ToolSettings *ts = p->scene->toolsettings;
1472   /* for surface sketching, need to set the right OpenGL context stuff so that
1473    * the conversions will project the values correctly...
1474    */
1475   if (gpencil_project_check(p)) {
1476     View3D *v3d = p->sa->spacedata.first;
1477
1478     /* need to restore the original projection settings before packing up */
1479     view3d_region_operator_needs_opengl(p->win, p->ar);
1480     ED_view3d_autodist_init(
1481         p->depsgraph, p->ar, v3d, (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
1482   }
1483
1484   /* check if doing eraser or not */
1485   if ((p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) {
1486     /* simplify stroke before transferring? */
1487     gp_stroke_simplify(p);
1488
1489     /* transfer stroke to frame */
1490     gp_stroke_newfrombuffer(p);
1491   }
1492
1493   /* clean up buffer now */
1494   gp_session_validatebuffer(p);
1495 }
1496
1497 /* finish off stroke painting operation */
1498 static void gp_paint_cleanup(tGPsdata *p)
1499 {
1500   /* p->gpd==NULL happens when stroke failed to initialize,
1501    * for example when GP is hidden in current space (sergey)
1502    */
1503   if (p->gpd) {
1504     /* finish off a stroke */
1505     gp_paint_strokeend(p);
1506   }
1507
1508   /* "unlock" frame */
1509   if (p->gpf) {
1510     p->gpf->flag &= ~GP_FRAME_PAINT;
1511   }
1512 }
1513
1514 /* ------------------------------- */
1515
1516 /* Helper callback for drawing the cursor itself */
1517 static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr)
1518 {
1519   tGPsdata *p = (tGPsdata *)p_ptr;
1520
1521   if (p->paintmode == GP_PAINTMODE_ERASER) {
1522     GPUVertFormat *format = immVertexFormat();
1523     const uint shdr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1524     immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
1525
1526     GPU_line_smooth(true);
1527     GPU_blend(true);
1528     GPU_blend_set_func_separate(
1529         GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
1530
1531     immUniformColor4ub(255, 100, 100, 20);
1532     imm_draw_circle_fill_2d(shdr_pos, x, y, p->radius, 40);
1533
1534     immUnbindProgram();
1535
1536     immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
1537
1538     float viewport_size[4];
1539     GPU_viewport_size_get_f(viewport_size);
1540     immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
1541
1542     immUniformColor4f(1.0f, 0.39f, 0.39f, 0.78f);
1543     immUniform1i("colors_len", 0); /* "simple" mode */
1544     immUniform1f("dash_width", 12.0f);
1545     immUniform1f("dash_factor", 0.5f);
1546
1547     imm_draw_circle_wire_2d(shdr_pos,
1548                             x,
1549                             y,
1550                             p->radius,
1551                             /* XXX Dashed shader gives bad results with sets of small segments
1552                              * currently, temp hack around the issue. :( */
1553                             max_ii(8, p->radius / 2)); /* was fixed 40 */
1554
1555     immUnbindProgram();
1556
1557     GPU_blend(false);
1558     GPU_line_smooth(false);
1559   }
1560 }
1561
1562 /* Turn brush cursor in 3D view on/off */
1563 static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short enable)
1564 {
1565   if (p->erasercursor && !enable) {
1566     /* clear cursor */
1567     WM_paint_cursor_end(CTX_wm_manager(C), p->erasercursor);
1568     p->erasercursor = NULL;
1569   }
1570   else if (enable && !p->erasercursor) {
1571     /* enable cursor */
1572     p->erasercursor = WM_paint_cursor_activate(CTX_wm_manager(C),
1573                                                SPACE_TYPE_ANY,
1574                                                RGN_TYPE_ANY,
1575                                                NULL, /* XXX */
1576                                                gpencil_draw_eraser,
1577                                                p);
1578   }
1579 }
1580
1581 /* Check if tablet eraser is being used (when processing events) */
1582 static bool gpencil_is_tablet_eraser_active(const wmEvent *event)
1583 {
1584   if (event->tablet_data) {
1585     const wmTabletData *wmtab = event->tablet_data;
1586     return (wmtab->Active == EVT_TABLET_ERASER);
1587   }
1588
1589   return false;
1590 }
1591
1592 /* ------------------------------- */
1593
1594 static void gpencil_draw_exit(bContext *C, wmOperator *op)
1595 {
1596   tGPsdata *p = op->customdata;
1597
1598   /* restore cursor to indicate end of drawing */
1599   WM_cursor_modal_restore(CTX_wm_window(C));
1600
1601   /* don't assume that operator data exists at all */
1602   if (p) {
1603     /* check size of buffer before cleanup, to determine if anything happened here */
1604     if (p->paintmode == GP_PAINTMODE_ERASER) {
1605       /* turn off radial brush cursor */
1606       gpencil_draw_toggle_eraser_cursor(C, p, false);
1607     }
1608
1609     /* always store the new eraser size to be used again next time
1610      * NOTE: Do this even when not in eraser mode, as eraser may
1611      *       have been toggled at some point.
1612      */
1613     U.gp_eraser = p->radius;
1614
1615     /* clear undo stack */
1616     gpencil_undo_finish();
1617
1618     /* cleanup */
1619     gp_paint_cleanup(p);
1620     gp_session_cleanup(p);
1621     gp_session_free(p);
1622     p = NULL;
1623   }
1624
1625   op->customdata = NULL;
1626 }
1627
1628 static void gpencil_draw_cancel(bContext *C, wmOperator *op)
1629 {
1630   /* this is just a wrapper around exit() */
1631   gpencil_draw_exit(C, op);
1632 }
1633
1634 /* ------------------------------- */
1635
1636 static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event)
1637 {
1638   tGPsdata *p;
1639   eGPencil_PaintModes paintmode = RNA_enum_get(op->ptr, "mode");
1640
1641   /* check context */
1642   p = op->customdata = gp_session_initpaint(C);
1643   if ((p == NULL) || (p->status == GP_STATUS_ERROR)) {
1644     /* something wasn't set correctly in context */
1645     gpencil_draw_exit(C, op);
1646     return 0;
1647   }
1648
1649   /* init painting data */
1650   gp_paint_initstroke(p, paintmode, CTX_data_depsgraph(C));
1651   if (p->status == GP_STATUS_ERROR) {
1652     gpencil_draw_exit(C, op);
1653     return 0;
1654   }
1655
1656   if (event != NULL) {
1657     p->keymodifier = event->keymodifier;
1658   }
1659   else {
1660     p->keymodifier = -1;
1661   }
1662
1663   /* everything is now setup ok */
1664   return 1;
1665 }
1666
1667 /* ------------------------------- */
1668
1669 /* ensure that the correct cursor icon is set */
1670 static void gpencil_draw_cursor_set(tGPsdata *p)
1671 {
1672   if (p->paintmode == GP_PAINTMODE_ERASER) {
1673     WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */
1674   }
1675   else {
1676     WM_cursor_modal_set(p->win, BC_PAINTBRUSHCURSOR);
1677   }
1678 }
1679
1680 /* update UI indicators of status, including cursor and header prints */
1681 static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p)
1682 {
1683   /* header prints */
1684   switch (p->status) {
1685     case GP_STATUS_PAINTING:
1686       switch (p->paintmode) {
1687         case GP_PAINTMODE_DRAW_POLY:
1688           /* Provide usage tips, since this is modal, and unintuitive without hints */
1689           ED_workspace_status_text(
1690               C,
1691               IFACE_("Annotation Create Poly: LMB click to place next stroke vertex | "
1692                      "ESC/Enter to end  (or click outside this area)"));
1693           break;
1694         default:
1695           /* Do nothing - the others are self explanatory, exit quickly once the mouse is released
1696            * Showing any text would just be annoying as it would flicker.
1697            */
1698           break;
1699       }
1700       break;
1701
1702     case GP_STATUS_IDLING:
1703       /* print status info */
1704       switch (p->paintmode) {
1705         case GP_PAINTMODE_ERASER:
1706           ED_workspace_status_text(C,
1707                                    IFACE_("Annotation Eraser: Hold and drag LMB or RMB to erase | "
1708                                           "ESC/Enter to end  (or click outside this area)"));
1709           break;
1710         case GP_PAINTMODE_DRAW_STRAIGHT:
1711           ED_workspace_status_text(C,
1712                                    IFACE_("Annotation Line Draw: Hold and drag LMB to draw | "
1713                                           "ESC/Enter to end  (or click outside this area)"));
1714           break;
1715         case GP_PAINTMODE_DRAW:
1716           ED_workspace_status_text(C,
1717                                    IFACE_("Annotation Freehand Draw: Hold and drag LMB to draw | "
1718                                           "E/ESC/Enter to end  (or click outside this area)"));
1719           break;
1720         case GP_PAINTMODE_DRAW_POLY:
1721           ED_workspace_status_text(
1722               C,
1723               IFACE_("Annotation Create Poly: LMB click to place next stroke vertex | "
1724                      "ESC/Enter to end  (or click outside this area)"));
1725           break;
1726
1727         default: /* unhandled future cases */
1728           ED_workspace_status_text(
1729               C, IFACE_("Annotation Session: ESC/Enter to end   (or click outside this area)"));
1730           break;
1731       }
1732       break;
1733
1734     case GP_STATUS_ERROR:
1735     case GP_STATUS_DONE:
1736     case GP_STATUS_CAPTURE:
1737       /* clear status string */
1738       ED_workspace_status_text(C, NULL);
1739       break;
1740   }
1741 }
1742
1743 /* ------------------------------- */
1744
1745 /* create a new stroke point at the point indicated by the painting context */
1746 static void gpencil_draw_apply(wmOperator *op, tGPsdata *p, Depsgraph *depsgraph)
1747 {
1748   /* handle drawing/erasing -> test for erasing first */
1749   if (p->paintmode == GP_PAINTMODE_ERASER) {
1750     /* do 'live' erasing now */
1751     gp_stroke_doeraser(p);
1752
1753     /* store used values */
1754     p->mvalo[0] = p->mval[0];
1755     p->mvalo[1] = p->mval[1];
1756     p->opressure = p->pressure;
1757   }
1758   /* Only add current point to buffer if mouse moved
1759    * (even though we got an event, it might be just noise). */
1760   else if (gp_stroke_filtermval(p, p->mval, p->mvalo)) {
1761     /* try to add point */
1762     short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
1763
1764     /* handle errors while adding point */
1765     if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) {
1766       /* finish off old stroke */
1767       gp_paint_strokeend(p);
1768       /* And start a new one!!! Else, projection errors! */
1769       gp_paint_initstroke(p, p->paintmode, depsgraph);
1770
1771       /* start a new stroke, starting from previous point */
1772       /* XXX Must manually reset inittime... */
1773       /* XXX We only need to reuse previous point if overflow! */
1774       if (ok == GP_STROKEADD_OVERFLOW) {
1775         p->inittime = p->ocurtime;
1776         gp_stroke_addpoint(p, p->mvalo, p->opressure, p->ocurtime);
1777       }
1778       else {
1779         p->inittime = p->curtime;
1780       }
1781       gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
1782     }
1783     else if (ok == GP_STROKEADD_INVALID) {
1784       /* the painting operation cannot continue... */
1785       BKE_report(op->reports, RPT_ERROR, "Cannot paint stroke");
1786       p->status = GP_STATUS_ERROR;
1787
1788       if (G.debug & G_DEBUG) {
1789         printf("Error: Grease-Pencil Paint - Add Point Invalid\n");
1790       }
1791       return;
1792     }
1793
1794     /* store used values */
1795     p->mvalo[0] = p->mval[0];
1796     p->mvalo[1] = p->mval[1];
1797     p->opressure = p->pressure;
1798     p->ocurtime = p->curtime;
1799   }
1800 }
1801
1802 /* handle draw event */
1803 static void annotation_draw_apply_event(
1804     wmOperator *op, const wmEvent *event, Depsgraph *depsgraph, float x, float y)
1805 {
1806   tGPsdata *p = op->customdata;
1807   PointerRNA itemptr;
1808   float mousef[2];
1809   int tablet = 0;
1810
1811   /* convert from window-space to area-space mouse coordinates
1812    * add any x,y override position for fake events
1813    */
1814   p->mval[0] = (float)event->mval[0] - x;
1815   p->mval[1] = (float)event->mval[1] - y;
1816
1817   /* verify key status for straight lines */
1818   if ((event->ctrl > 0) || (event->alt > 0)) {
1819     if (p->straight[0] == 0) {
1820       int dx = abs((int)(p->mval[0] - p->mvalo[0]));
1821       int dy = abs((int)(p->mval[1] - p->mvalo[1]));
1822       if ((dx > 0) || (dy > 0)) {
1823         /* check mouse direction to replace the other coordinate with previous values */
1824         if (dx >= dy) {
1825           /* horizontal */
1826           p->straight[0] = 1;
1827           p->straight[1] = p->mval[1]; /* save y */
1828         }
1829         else {
1830           /* vertical */
1831           p->straight[0] = 2;
1832           p->straight[1] = p->mval[0]; /* save x */
1833         }
1834       }
1835     }
1836   }
1837   else {
1838     p->straight[0] = 0;
1839   }
1840
1841   p->curtime = PIL_check_seconds_timer();
1842
1843   /* handle pressure sensitivity (which is supplied by tablets) */
1844   if (event->tablet_data) {
1845     const wmTabletData *wmtab = event->tablet_data;
1846
1847     tablet = (wmtab->Active != EVT_TABLET_NONE);
1848     p->pressure = wmtab->Pressure;
1849
1850     /* Hack for pressure sensitive eraser on D+RMB when using a tablet:
1851      * The pen has to float over the tablet surface, resulting in
1852      * zero pressure (T47101). Ignore pressure values if floating
1853      * (i.e. "effectively zero" pressure), and only when the "active"
1854      * end is the stylus (i.e. the default when not eraser)
1855      */
1856     if (p->paintmode == GP_PAINTMODE_ERASER) {
1857       if ((wmtab->Active != EVT_TABLET_ERASER) && (p->pressure < 0.001f)) {
1858         p->pressure = 1.0f;
1859       }
1860     }
1861   }
1862   else {
1863     /* No tablet data -> No pressure info is available */
1864     p->pressure = 1.0f;
1865   }
1866
1867   /* special exception for start of strokes (i.e. maybe for just a dot) */
1868   if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
1869     p->flags &= ~GP_PAINTFLAG_FIRSTRUN;
1870
1871     p->mvalo[0] = p->mval[0];
1872     p->mvalo[1] = p->mval[1];
1873     p->opressure = p->pressure;
1874     p->inittime = p->ocurtime = p->curtime;
1875     p->straight[0] = 0;
1876     p->straight[1] = 0;
1877
1878     /* special exception here for too high pressure values on first touch in
1879      * windows for some tablets, then we just skip first touch...
1880      */
1881     if (tablet && (p->pressure >= 0.99f)) {
1882       return;
1883     }
1884   }
1885
1886   /* check if alt key is pressed and limit to straight lines */
1887   if ((p->paintmode != GP_PAINTMODE_ERASER) && (p->straight[0] != 0)) {
1888     if (p->straight[0] == 1) {
1889       /* horizontal */
1890       p->mval[1] = p->straight[1]; /* replace y */
1891     }
1892     else {
1893       /* vertical */
1894       p->mval[0] = p->straight[1]; /* replace x */
1895     }
1896   }
1897
1898   /* fill in stroke data (not actually used directly by gpencil_draw_apply) */
1899   RNA_collection_add(op->ptr, "stroke", &itemptr);
1900
1901   mousef[0] = p->mval[0];
1902   mousef[1] = p->mval[1];
1903   RNA_float_set_array(&itemptr, "mouse", mousef);
1904   RNA_float_set(&itemptr, "pressure", p->pressure);
1905   RNA_boolean_set(&itemptr, "is_start", (p->flags & GP_PAINTFLAG_FIRSTRUN) != 0);
1906
1907   RNA_float_set(&itemptr, "time", p->curtime - p->inittime);
1908
1909   /* apply the current latest drawing point */
1910   gpencil_draw_apply(op, p, depsgraph);
1911
1912   /* force refresh */
1913   /* just active area for now, since doing whole screen is too slow */
1914   ED_region_tag_redraw(p->ar);
1915 }
1916
1917 /* ------------------------------- */
1918
1919 /* operator 'redo' (i.e. after changing some properties, but also for repeat last) */
1920 static int gpencil_draw_exec(bContext *C, wmOperator *op)
1921 {
1922   tGPsdata *p = NULL;
1923   Depsgraph *depsgraph = CTX_data_depsgraph(C);
1924
1925   /* printf("GPencil - Starting Re-Drawing\n"); */
1926
1927   /* try to initialize context data needed while drawing */
1928   if (!gpencil_draw_init(C, op, NULL)) {
1929     if (op->customdata) {
1930       MEM_freeN(op->customdata);
1931     }
1932     /* printf("\tGP - no valid data\n"); */
1933     return OPERATOR_CANCELLED;
1934   }
1935   else {
1936     p = op->customdata;
1937   }
1938
1939   /* printf("\tGP - Start redrawing stroke\n"); */
1940
1941   /* loop over the stroke RNA elements recorded (i.e. progress of mouse movement),
1942    * setting the relevant values in context at each step, then applying
1943    */
1944   RNA_BEGIN (op->ptr, itemptr, "stroke") {
1945     float mousef[2];
1946
1947     /* printf("\t\tGP - stroke elem\n"); */
1948
1949     /* get relevant data for this point from stroke */
1950     RNA_float_get_array(&itemptr, "mouse", mousef);
1951     p->mval[0] = (int)mousef[0];
1952     p->mval[1] = (int)mousef[1];
1953     p->pressure = RNA_float_get(&itemptr, "pressure");
1954     p->curtime = (double)RNA_float_get(&itemptr, "time") + p->inittime;
1955
1956     if (RNA_boolean_get(&itemptr, "is_start")) {
1957       /* if first-run flag isn't set already (i.e. not true first stroke),
1958        * then we must terminate the previous one first before continuing
1959        */
1960       if ((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) {
1961         /* TODO: both of these ops can set error-status, but we probably don't need to worry */
1962         gp_paint_strokeend(p);
1963         gp_paint_initstroke(p, p->paintmode, depsgraph);
1964       }
1965     }
1966
1967     /* if first run, set previous data too */
1968     if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
1969       p->flags &= ~GP_PAINTFLAG_FIRSTRUN;
1970
1971       p->mvalo[0] = p->mval[0];
1972       p->mvalo[1] = p->mval[1];
1973       p->opressure = p->pressure;
1974       p->ocurtime = p->curtime;
1975     }
1976
1977     /* apply this data as necessary now (as per usual) */
1978     gpencil_draw_apply(op, p, depsgraph);
1979   }
1980   RNA_END;
1981
1982   /* printf("\tGP - done\n"); */
1983
1984   /* cleanup */
1985   gpencil_draw_exit(C, op);
1986
1987   /* refreshes */
1988   WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
1989
1990   /* done */
1991   return OPERATOR_FINISHED;
1992 }
1993
1994 /* ------------------------------- */
1995
1996 /* start of interactive drawing part of operator */
1997 static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1998 {
1999   Object *ob = CTX_data_active_object(C);
2000   ScrArea *sa = CTX_wm_area(C);
2001   Scene *scene = CTX_data_scene(C);
2002   tGPsdata *p = NULL;
2003
2004   /* support for tablets eraser pen */
2005   if (gpencil_is_tablet_eraser_active(event)) {
2006     RNA_enum_set(op->ptr, "mode", GP_PAINTMODE_ERASER);
2007   }
2008
2009   /* if try to do annotations with a gp object selected, first
2010    * unselect the object to avoid conflicts.
2011    * The solution is not perfect but we can keep running the annotations while
2012    * found a better solution.
2013    */
2014   if (sa && sa->spacetype == SPACE_VIEW3D) {
2015     if ((ob != NULL) && (ob->type == OB_GPENCIL)) {
2016       ob->mode = OB_MODE_OBJECT;
2017       bGPdata *gpd = (bGPdata *)ob->data;
2018       ED_gpencil_setup_modes(C, gpd, 0);
2019       DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
2020
2021       ViewLayer *view_layer = CTX_data_view_layer(C);
2022       BKE_view_layer_base_deselect_all(view_layer);
2023       view_layer->basact = NULL;
2024       DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
2025       WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
2026     }
2027   }
2028
2029   if (G.debug & G_DEBUG) {
2030     printf("GPencil - Starting Drawing\n");
2031   }
2032
2033   /* try to initialize context data needed while drawing */
2034   if (!gpencil_draw_init(C, op, event)) {
2035     if (op->customdata) {
2036       MEM_freeN(op->customdata);
2037     }
2038     if (G.debug & G_DEBUG) {
2039       printf("\tGP - no valid data\n");
2040     }
2041     return OPERATOR_CANCELLED;
2042   }
2043   else {
2044     p = op->customdata;
2045   }
2046
2047   /* if empty erase capture and finish */
2048   if (p->status == GP_STATUS_CAPTURE) {
2049     gpencil_draw_exit(C, op);
2050
2051     BKE_report(op->reports, RPT_ERROR, "Nothing to erase");
2052     return OPERATOR_FINISHED;
2053   }
2054
2055   /* TODO: set any additional settings that we can take from the events?
2056    * TODO? if tablet is erasing, force eraser to be on? */
2057
2058   /* TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway... */
2059
2060   /* if eraser is on, draw radial aid */
2061   if (p->paintmode == GP_PAINTMODE_ERASER) {
2062     gpencil_draw_toggle_eraser_cursor(C, p, true);
2063   }
2064   /* set cursor
2065    * NOTE: This may change later (i.e. intentionally via brush toggle,
2066    *       or unintentionally if the user scrolls outside the area)...
2067    */
2068   gpencil_draw_cursor_set(p);
2069
2070   /* only start drawing immediately if we're allowed to do so... */
2071   if (RNA_boolean_get(op->ptr, "wait_for_input") == false) {
2072     /* hotkey invoked - start drawing */
2073     /* printf("\tGP - set first spot\n"); */
2074     p->status = GP_STATUS_PAINTING;
2075
2076     /* handle the initial drawing - i.e. for just doing a simple dot */
2077     annotation_draw_apply_event(op, event, CTX_data_depsgraph(C), 0.0f, 0.0f);
2078     op->flag |= OP_IS_MODAL_CURSOR_REGION;
2079   }
2080   else {
2081     /* toolbar invoked - don't start drawing yet... */
2082     /* printf("\tGP - hotkey invoked... waiting for click-drag\n"); */
2083     op->flag |= OP_IS_MODAL_CURSOR_REGION;
2084   }
2085
2086   WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
2087   /* add a modal handler for this operator, so that we can then draw continuous strokes */
2088   WM_event_add_modal_handler(C, op);
2089   return OPERATOR_RUNNING_MODAL;
2090 }
2091
2092 /* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
2093 static bool gpencil_area_exists(bContext *C, ScrArea *sa_test)
2094 {
2095   bScreen *sc = CTX_wm_screen(C);
2096   return (BLI_findindex(&sc->areabase, sa_test) != -1);
2097 }
2098
2099 static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
2100 {
2101   tGPsdata *p = op->customdata;
2102
2103   /* we must check that we're still within the area that we're set up to work from
2104    * otherwise we could crash (see bug #20586)
2105    */
2106   if (CTX_wm_area(C) != p->sa) {
2107     printf("\t\t\tGP - wrong area execution abort!\n");
2108     p->status = GP_STATUS_ERROR;
2109   }
2110
2111   /* printf("\t\tGP - start stroke\n"); */
2112
2113   /* we may need to set up paint env again if we're resuming */
2114   /* XXX: watch it with the paintmode! in future,
2115    *      it'd be nice to allow changing paint-mode when in sketching-sessions */
2116
2117   if (gp_session_initdata(C, p)) {
2118     gp_paint_initstroke(p, p->paintmode, CTX_data_depsgraph(C));
2119   }
2120
2121   if (p->status != GP_STATUS_ERROR) {
2122     p->status = GP_STATUS_PAINTING;
2123     op->flag &= ~OP_IS_MODAL_CURSOR_REGION;
2124   }
2125
2126   return op->customdata;
2127 }
2128
2129 static void gpencil_stroke_end(wmOperator *op)
2130 {
2131   tGPsdata *p = op->customdata;
2132
2133   gp_paint_cleanup(p);
2134
2135   gpencil_undo_push(p->gpd);
2136
2137   gp_session_cleanup(p);
2138
2139   p->status = GP_STATUS_IDLING;
2140   op->flag |= OP_IS_MODAL_CURSOR_REGION;
2141
2142   p->gpd = NULL;
2143   p->gpl = NULL;
2144   p->gpf = NULL;
2145 }
2146
2147 /* add events for missing mouse movements when the artist draw very fast */
2148 static void annotation_add_missing_events(bContext *C,
2149                                           wmOperator *op,
2150                                           const wmEvent *event,
2151                                           tGPsdata *p)
2152 {
2153   float pt[2], a[2], b[2];
2154   float factor = 10.0f;
2155
2156   copy_v2_v2(a, p->mvalo);
2157   b[0] = (float)event->mval[0] + 1.0f;
2158   b[1] = (float)event->mval[1] + 1.0f;
2159
2160   /* get distance in pixels */
2161   float dist = len_v2v2(a, b);
2162
2163   /* for very small distances, add a half way point */
2164   if (dist <= 2.0f) {
2165     interp_v2_v2v2(pt, a, b, 0.5f);
2166     sub_v2_v2v2(pt, b, pt);
2167     /* create fake event */
2168     annotation_draw_apply_event(op, event, CTX_data_depsgraph(C), pt[0], pt[1]);
2169   }
2170   else if (dist >= factor) {
2171     int slices = 2 + (int)((dist - 1.0) / factor);
2172     float n = 1.0f / slices;
2173     for (int i = 1; i < slices; i++) {
2174       interp_v2_v2v2(pt, a, b, n * i);
2175       sub_v2_v2v2(pt, b, pt);
2176       /* create fake event */
2177       annotation_draw_apply_event(op, event, CTX_data_depsgraph(C), pt[0], pt[1]);
2178     }
2179   }
2180 }
2181
2182 /* events handling during interactive drawing part of operator */
2183 static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
2184 {
2185   tGPsdata *p = op->customdata;
2186   /* default exit state - pass through to support MMB view nav, etc. */
2187   int estate = OPERATOR_PASS_THROUGH;
2188
2189   /* if (event->type == NDOF_MOTION)
2190    *    return OPERATOR_PASS_THROUGH;
2191    * -------------------------------
2192    * [mce] Not quite what I was looking
2193    * for, but a good start! GP continues to
2194    * draw on the screen while the 3D mouse
2195    * moves the viewpoint. Problem is that
2196    * the stroke is converted to 3D only after
2197    * it is finished. This approach should work
2198    * better in tools that immediately apply
2199    * in 3D space.
2200    */
2201
2202   if (p->status == GP_STATUS_IDLING) {
2203     ARegion *ar = CTX_wm_region(C);
2204     p->ar = ar;
2205   }
2206
2207   /* We don't pass on key events, GP is used with key-modifiers -
2208    * prevents Dkey to insert drivers. */
2209   if (ISKEYBOARD(event->type)) {
2210     if (ELEM(event->type, LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY, ZKEY)) {
2211       /* allow some keys:
2212        *   - for frame changing [#33412]
2213        *   - for undo (during sketching sessions)
2214        */
2215     }
2216     else if (ELEM(event->type, PAD0, PAD1, PAD2, PAD3, PAD4, PAD5, PAD6, PAD7, PAD8, PAD9)) {
2217       /* allow numpad keys so that camera/view manipulations can still take place
2218        * - PAD0 in particular is really important for Grease Pencil drawing,
2219        *   as animators may be working "to camera", so having this working
2220        *   is essential for ensuring that they can quickly return to that view
2221        */
2222     }
2223     else if ((event->type == BKEY) && (event->val == KM_RELEASE)) {
2224       /* Add Blank Frame
2225        * - Since this operator is non-modal, we can just call it here, and keep going...
2226        * - This operator is especially useful when animating
2227        */
2228       WM_operator_name_call(C, "GPENCIL_OT_blank_frame_add", WM_OP_EXEC_DEFAULT, NULL);
2229       estate = OPERATOR_RUNNING_MODAL;
2230     }
2231     else {
2232       estate = OPERATOR_RUNNING_MODAL;
2233     }
2234   }
2235
2236   // printf("\tGP - handle modal event...\n");
2237
2238   /* Exit painting mode (and/or end current stroke)
2239    *
2240    * NOTE: cannot do RIGHTMOUSE (as is standard for canceling)
2241    * as that would break polyline T32647.
2242    */
2243   if (ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY, EKEY)) {
2244     /* exit() ends the current stroke before cleaning up */
2245     /* printf("\t\tGP - end of paint op + end of stroke\n"); */
2246     p->status = GP_STATUS_DONE;
2247     estate = OPERATOR_FINISHED;
2248   }
2249
2250   /* toggle painting mode upon mouse-button movement
2251    *  - LEFTMOUSE  = standard drawing (all) / straight line drawing (all) / polyline (toolbox only)
2252    *  - RIGHTMOUSE = polyline (hotkey) / eraser (all)
2253    *    (Disabling RIGHTMOUSE case here results in bugs like [#32647])
2254    * also making sure we have a valid event value, to not exit too early
2255    */
2256   if (ELEM(event->type, LEFTMOUSE, RIGHTMOUSE) && (ELEM(event->val, KM_PRESS, KM_RELEASE))) {
2257     /* if painting, end stroke */
2258     if (p->status == GP_STATUS_PAINTING) {
2259       int sketch = 0;
2260
2261       /* basically, this should be mouse-button up = end stroke
2262        * BUT, polyline drawing is an exception -- all knots should be added during one session
2263        */
2264       sketch |= (p->paintmode == GP_PAINTMODE_DRAW_POLY);
2265
2266       if (sketch) {
2267         /* end stroke only, and then wait to resume painting soon */
2268         /* printf("\t\tGP - end stroke only\n"); */
2269         gpencil_stroke_end(op);
2270
2271         /* If eraser mode is on, turn it off after the stroke finishes
2272          * NOTE: This just makes it nicer to work with drawing sessions
2273          */
2274         if (p->paintmode == GP_PAINTMODE_ERASER) {
2275           p->paintmode = RNA_enum_get(op->ptr, "mode");
2276
2277           /* if the original mode was *still* eraser,
2278            * we'll let it say for now, since this gives
2279            * users an opportunity to have visual feedback
2280            * when adjusting eraser size
2281            */
2282           if (p->paintmode != GP_PAINTMODE_ERASER) {
2283             /* turn off cursor...
2284              * NOTE: this should be enough for now
2285              *       Just hiding this makes it seem like
2286              *       you can paint again...
2287              */
2288             gpencil_draw_toggle_eraser_cursor(C, p, false);
2289           }
2290         }
2291
2292         /* we've just entered idling state, so this event was processed (but no others yet) */
2293         estate = OPERATOR_RUNNING_MODAL;
2294
2295         /* stroke could be smoothed, send notifier to refresh screen */
2296         WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
2297       }
2298       else {
2299         /* printf("\t\tGP - end of stroke + op\n"); */
2300         p->status = GP_STATUS_DONE;
2301         estate = OPERATOR_FINISHED;
2302       }
2303     }
2304     else if (event->val == KM_PRESS) {
2305       bool in_bounds = false;
2306
2307       /* Check if we're outside the bounds of the active region
2308        * NOTE: An exception here is that if launched from the toolbar,
2309        *       whatever region we're now in should become the new region
2310        */
2311       if ((p->ar) && (p->ar->regiontype == RGN_TYPE_TOOLS)) {
2312         /* Change to whatever region is now under the mouse */
2313         ARegion *current_region = BKE_area_find_region_xy(p->sa, RGN_TYPE_ANY, event->x, event->y);
2314
2315         if (G.debug & G_DEBUG) {
2316           printf("found alternative region %p (old was %p) - at %d %d (sa: %d %d -> %d %d)\n",
2317                  current_region,
2318                  p->ar,
2319                  event->x,
2320                  event->y,
2321                  p->sa->totrct.xmin,
2322                  p->sa->totrct.ymin,
2323                  p->sa->totrct.xmax,
2324                  p->sa->totrct.ymax);
2325         }
2326
2327         if (current_region) {
2328           /* Assume that since we found the cursor in here, it is in bounds
2329            * and that this should be the region that we begin drawing in
2330            */
2331           p->ar = current_region;
2332           in_bounds = true;
2333         }
2334         else {
2335           /* Out of bounds, or invalid in some other way */
2336           p->status = GP_STATUS_ERROR;
2337           estate = OPERATOR_CANCELLED;
2338
2339           if (G.debug & G_DEBUG) {
2340             printf("%s: Region under cursor is out of bounds, so cannot be drawn on\n", __func__);
2341           }
2342         }
2343       }
2344       else if (p->ar) {
2345         rcti region_rect;
2346
2347         /* Perform bounds check using  */
2348         ED_region_visible_rect(p->ar, &region_rect);
2349         in_bounds = BLI_rcti_isect_pt_v(&region_rect, event->mval);
2350       }
2351       else {
2352         /* No region */
2353         p->status = GP_STATUS_ERROR;
2354         estate = OPERATOR_CANCELLED;
2355
2356         if (G.debug & G_DEBUG) {
2357           printf("%s: No active region found in GP Paint session data\n", __func__);
2358         }
2359       }
2360
2361       if (in_bounds) {
2362         /* Switch paintmode (temporarily if need be) based on which button was used
2363          * NOTE: This is to make it more convenient to erase strokes when using drawing sessions
2364          */
2365         if ((event->type == RIGHTMOUSE) || gpencil_is_tablet_eraser_active(event)) {
2366           /* turn on eraser */
2367           p->paintmode = GP_PAINTMODE_ERASER;
2368         }
2369         else if (event->type == LEFTMOUSE) {
2370           /* restore drawmode to default */
2371           p->paintmode = RNA_enum_get(op->ptr, "mode");
2372         }
2373
2374         gpencil_draw_toggle_eraser_cursor(C, p, p->paintmode == GP_PAINTMODE_ERASER);
2375
2376         /* not painting, so start stroke (this should be mouse-button down) */
2377         p = gpencil_stroke_begin(C, op);
2378
2379         if (p->status == GP_STATUS_ERROR) {
2380           estate = OPERATOR_CANCELLED;
2381         }
2382       }
2383       else if (p->status != GP_STATUS_ERROR) {
2384         /* User clicked outside bounds of window while idling, so exit paintmode
2385          * NOTE: Don't enter this case if an error occurred while finding the
2386          *       region (as above)
2387          */
2388         p->status = GP_STATUS_DONE;
2389         estate = OPERATOR_FINISHED;
2390       }
2391     }
2392     else if (event->val == KM_RELEASE) {
2393       p->status = GP_STATUS_IDLING;
2394       op->flag |= OP_IS_MODAL_CURSOR_REGION;
2395     }
2396   }
2397
2398   /* handle mode-specific events */
2399   if (p->status == GP_STATUS_PAINTING) {
2400     /* handle painting mouse-movements? */
2401     if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) {
2402       /* handle drawing event */
2403       if ((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) {
2404         annotation_add_missing_events(C, op, event, p);
2405       }
2406
2407       annotation_draw_apply_event(op, event, CTX_data_depsgraph(C), 0.0f, 0.0f);
2408
2409       /* finish painting operation if anything went wrong just now */
2410       if (p->status == GP_STATUS_ERROR) {
2411         printf("\t\t\t\tGP - add error done!\n");
2412         estate = OPERATOR_CANCELLED;
2413       }
2414       else {
2415         /* event handled, so just tag as running modal */
2416         /* printf("\t\t\t\tGP - add point handled!\n"); */
2417         estate = OPERATOR_RUNNING_MODAL;
2418       }
2419     }
2420     /* eraser size */
2421     else if ((p->paintmode == GP_PAINTMODE_ERASER) &&
2422              ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, PADPLUSKEY, PADMINUS)) {
2423       /* just resize the brush (local version)
2424        * TODO: fix the hardcoded size jumps (set to make a visible difference) and hardcoded keys
2425        */
2426       /* printf("\t\tGP - resize eraser\n"); */
2427       switch (event->type) {
2428         case WHEELDOWNMOUSE: /* larger */
2429         case PADPLUSKEY:
2430           p->radius += 5;
2431           break;
2432
2433         case WHEELUPMOUSE: /* smaller */
2434         case PADMINUS:
2435           p->radius -= 5;
2436
2437           if (p->radius <= 0) {
2438             p->radius = 1;
2439           }
2440           break;
2441       }
2442
2443       /* force refresh */
2444       /* just active area for now, since doing whole screen is too slow */
2445       ED_region_tag_redraw(p->ar);
2446
2447       /* event handled, so just tag as running modal */
2448       estate = OPERATOR_RUNNING_MODAL;
2449     }
2450     /* there shouldn't be any other events, but just in case there are, let's swallow them
2451      * (i.e. to prevent problems with undo)
2452      */
2453     else {
2454       /* swallow event to save ourselves trouble */
2455       estate = OPERATOR_RUNNING_MODAL;
2456     }
2457   }
2458
2459   /* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
2460   if (0 == gpencil_area_exists(C, p->sa)) {
2461     estate = OPERATOR_CANCELLED;
2462   }
2463   else {
2464     /* update status indicators - cursor, header, etc. */
2465     gpencil_draw_status_indicators(C, p);
2466     /* cursor may have changed outside our control - T44084 */
2467     gpencil_draw_cursor_set(p);
2468   }
2469
2470   /* process last operations before exiting */
2471   switch (estate) {
2472     case OPERATOR_FINISHED:
2473       /* one last flush before we're done */
2474       gpencil_draw_exit(C, op);
2475       WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
2476       break;
2477
2478     case OPERATOR_CANCELLED:
2479       gpencil_draw_exit(C, op);
2480       break;
2481
2482     case OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH:
2483       /* event doesn't need to be handled */
2484 #if 0
2485       printf("unhandled event -> %d (mmb? = %d | mmv? = %d)\n",
2486              event->type,
2487              event->type == MIDDLEMOUSE,
2488              event->type == MOUSEMOVE);
2489 #endif
2490       break;
2491   }
2492
2493   /* return status code */
2494   return estate;
2495 }
2496
2497 /* ------------------------------- */
2498
2499 static const EnumPropertyItem prop_gpencil_drawmodes[] = {
2500     {GP_PAINTMODE_DRAW, "DRAW", 0, "Draw Freehand", "Draw freehand stroke(s)"},
2501     {GP_PAINTMODE_DRAW_STRAIGHT,
2502      "DRAW_STRAIGHT",
2503      0,
2504      "Draw Straight Lines",
2505      "Draw straight line segment(s)"},
2506     {GP_PAINTMODE_DRAW_POLY,
2507      "DRAW_POLY",
2508      0,
2509      "Draw Poly Line",
2510      "Click to place endpoints of straight line segments (connected)"},
2511     {GP_PAINTMODE_ERASER, "ERASER", 0, "Eraser", "Erase Annotation strokes"},
2512     {0, NULL, 0, NULL, NULL},
2513 };
2514
2515 void GPENCIL_OT_annotate(wmOperatorType *ot)
2516 {
2517   PropertyRNA *prop;
2518
2519   /* identifiers */
2520   ot->name = "Annotation Draw";
2521   ot->idname = "GPENCIL_OT_annotate";
2522   ot->description = "Make annotations on the active data";
2523
2524   /* api callbacks */
2525   ot->exec = gpencil_draw_exec;
2526   ot->invoke = gpencil_draw_invoke;
2527   ot->modal = gpencil_draw_modal;
2528   ot->cancel = gpencil_draw_cancel;
2529   ot->poll = gpencil_draw_poll;
2530
2531   /* flags */
2532   ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
2533
2534   /* settings for drawing */
2535   ot->prop = RNA_def_enum(
2536       ot->srna, "mode", prop_gpencil_drawmodes, 0, "Mode", "Way to interpret mouse movements");
2537
2538   prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
2539   RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
2540
2541   /* NOTE: wait for input is enabled by default,
2542    * so that all UI code can work properly without needing users to know about this */
2543   prop = RNA_def_boolean(ot->srna,
2544                          "wait_for_input",
2545                          true,
2546                          "Wait for Input",
2547                          "Wait for first click instead of painting immediately");
2548   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2549 }