48d6cab7b2ae640d93ec8ad8ae67aba6300e2ad5
[blender.git] / source / blender / editors / gpencil / gpencil_brush.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) 2015, Blender Foundation
17  * This is a new part of Blender
18  * Brush based operators for editing Grease Pencil strokes
19  */
20
21 /** \file
22  * \ingroup edgpencil
23  */
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <stddef.h>
29 #include <math.h>
30
31 #include "MEM_guardedalloc.h"
32
33 #include "BLI_blenlib.h"
34 #include "BLI_ghash.h"
35 #include "BLI_math.h"
36 #include "BLI_rand.h"
37 #include "BLI_utildefines.h"
38
39 #include "PIL_time.h"
40
41 #include "BLT_translation.h"
42
43 #include "DNA_meshdata_types.h"
44 #include "DNA_scene_types.h"
45 #include "DNA_screen_types.h"
46 #include "DNA_space_types.h"
47 #include "DNA_view3d_types.h"
48 #include "DNA_gpencil_types.h"
49 #include "DNA_object_types.h"
50
51 #include "BKE_colortools.h"
52 #include "BKE_context.h"
53 #include "BKE_deform.h"
54 #include "BKE_gpencil.h"
55 #include "BKE_material.h"
56 #include "BKE_object_deform.h"
57 #include "BKE_report.h"
58
59 #include "UI_interface.h"
60
61 #include "WM_api.h"
62 #include "WM_types.h"
63
64 #include "RNA_access.h"
65 #include "RNA_define.h"
66 #include "RNA_enum_types.h"
67
68 #include "UI_view2d.h"
69
70 #include "ED_gpencil.h"
71 #include "ED_screen.h"
72 #include "ED_view3d.h"
73
74 #include "GPU_immediate.h"
75 #include "GPU_immediate_util.h"
76 #include "GPU_state.h"
77
78 #include "DEG_depsgraph.h"
79 #include "DEG_depsgraph_query.h"
80
81 #include "gpencil_intern.h"
82
83 /* ************************************************ */
84 /* General Brush Editing Context */
85
86 /* Context for brush operators */
87 typedef struct tGP_BrushEditData {
88   /* Current editor/region/etc. */
89   /* NOTE: This stuff is mainly needed to handle 3D view projection stuff... */
90   Depsgraph *depsgraph;
91   struct Main *bmain;
92   Scene *scene;
93   Object *object;
94
95   ScrArea *sa;
96   ARegion *ar;
97
98   /* Current GPencil datablock */
99   bGPdata *gpd;
100
101   /* Brush Settings */
102   GP_Sculpt_Settings *settings;
103   GP_Sculpt_Data *gp_brush;
104   GP_Sculpt_Data *gp_brush_old;
105
106   eGP_Sculpt_Types brush_type;
107   eGP_Sculpt_Types brush_type_old;
108   eGP_Sculpt_Flag flag;
109
110   /* Space Conversion Data */
111   GP_SpaceConversion gsc;
112
113   /* Is the brush currently painting? */
114   bool is_painting;
115   bool is_weight_mode;
116
117   /* Start of new sculpt stroke */
118   bool first;
119
120   /* Is multiframe editing enabled, and are we using falloff for that? */
121   bool is_multiframe;
122   bool use_multiframe_falloff;
123
124   /* Current frame */
125   int cfra;
126
127   /* Brush Runtime Data: */
128   /* - position and pressure
129    * - the *_prev variants are the previous values
130    */
131   float mval[2], mval_prev[2];
132   float pressure, pressure_prev;
133
134   /* - effect vector (e.g. 2D/3D translation for grab brush) */
135   float dvec[3];
136
137   /* - multiframe falloff factor */
138   float mf_falloff;
139
140   /* active vertex group */
141   int vrgroup;
142
143   /* brush geometry (bounding box) */
144   rcti brush_rect;
145
146   /* Custom data for certain brushes */
147   /* - map from bGPDstroke's to structs containing custom data about those strokes */
148   GHash *stroke_customdata;
149   /* - general customdata */
150   void *customdata;
151
152   /* Timer for in-place accumulation of brush effect */
153   wmTimer *timer;
154   bool timerTick; /* is this event from a timer */
155
156   RNG *rng;
157 } tGP_BrushEditData;
158
159 /* Callback for performing some brush operation on a single point */
160 typedef bool (*GP_BrushApplyCb)(
161     tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2]);
162
163 /* ************************************************ */
164 /* Utility Functions */
165
166 /* apply lock axis reset */
167 static void gpsculpt_compute_lock_axis(tGP_BrushEditData *gso,
168                                        bGPDspoint *pt,
169                                        const float save_pt[3])
170 {
171   if (gso->sa->spacetype != SPACE_VIEW3D) {
172     return;
173   }
174
175   const ToolSettings *ts = gso->scene->toolsettings;
176   const View3DCursor *cursor = &gso->scene->cursor;
177   const int axis = ts->gp_sculpt.lock_axis;
178
179   /* lock axis control */
180   switch (axis) {
181     case GP_LOCKAXIS_X: {
182       pt->x = save_pt[0];
183       break;
184     }
185     case GP_LOCKAXIS_Y: {
186       pt->y = save_pt[1];
187       break;
188     }
189     case GP_LOCKAXIS_Z: {
190       pt->z = save_pt[2];
191       break;
192     }
193     case GP_LOCKAXIS_CURSOR: {
194       /* Compute a plane with cursor normal and position of the point before do the sculpt. */
195       const float scale[3] = {1.0f, 1.0f, 1.0f};
196       float plane_normal[3] = {0.0f, 0.0f, 1.0f};
197       float plane[4];
198       float mat[4][4];
199       float r_close[3];
200
201       loc_eul_size_to_mat4(mat, cursor->location, cursor->rotation_euler, scale);
202
203       mul_mat3_m4_v3(mat, plane_normal);
204       plane_from_point_normal_v3(plane, save_pt, plane_normal);
205
206       /* find closest point to the plane with the new position */
207       closest_to_plane_v3(r_close, plane, &pt->x);
208       copy_v3_v3(&pt->x, r_close);
209       break;
210     }
211     default: {
212       break;
213     }
214   }
215 }
216
217 /* Context ---------------------------------------- */
218
219 /* Get the sculpting settings */
220 static GP_Sculpt_Settings *gpsculpt_get_settings(Scene *scene)
221 {
222   return &scene->toolsettings->gp_sculpt;
223 }
224
225 /* Get the active brush */
226 static GP_Sculpt_Data *gpsculpt_get_brush(Scene *scene, bool is_weight_mode)
227 {
228   GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
229   GP_Sculpt_Data *gp_brush = NULL;
230   if (is_weight_mode) {
231     gp_brush = &gset->brush[gset->weighttype];
232   }
233   else {
234     gp_brush = &gset->brush[gset->brushtype];
235   }
236
237   return gp_brush;
238 }
239
240 /* Brush Operations ------------------------------- */
241
242 /* Invert behavior of brush? */
243 static bool gp_brush_invert_check(tGP_BrushEditData *gso)
244 {
245   /* The basic setting is the brush's setting (from the panel) */
246   bool invert = ((gso->gp_brush->flag & GP_SCULPT_FLAG_INVERT) != 0);
247
248   /* During runtime, the user can hold down the Ctrl key to invert the basic behavior */
249   if (gso->flag & GP_SCULPT_FLAG_INVERT) {
250     invert ^= true;
251   }
252
253   /* set temporary status */
254   if (invert) {
255     gso->gp_brush->flag |= GP_SCULPT_FLAG_TMP_INVERT;
256   }
257   else {
258     gso->gp_brush->flag &= ~GP_SCULPT_FLAG_TMP_INVERT;
259   }
260
261   return invert;
262 }
263
264 /* Compute strength of effect */
265 static float gp_brush_influence_calc(tGP_BrushEditData *gso, const int radius, const int co[2])
266 {
267   GP_Sculpt_Data *gp_brush = gso->gp_brush;
268
269   /* basic strength factor from brush settings */
270   float influence = gp_brush->strength;
271
272   /* use pressure? */
273   if (gp_brush->flag & GP_SCULPT_FLAG_USE_PRESSURE) {
274     influence *= gso->pressure;
275   }
276
277   /* distance fading */
278   if (gp_brush->flag & GP_SCULPT_FLAG_USE_FALLOFF) {
279     int mval_i[2];
280     round_v2i_v2fl(mval_i, gso->mval);
281     float distance = (float)len_v2v2_int(mval_i, co);
282     float fac;
283
284     CLAMP(distance, 0.0f, (float)radius);
285     fac = 1.0f - (distance / (float)radius);
286
287     influence *= fac;
288   }
289
290   /* apply multiframe falloff */
291   influence *= gso->mf_falloff;
292
293   /* return influence */
294   return influence;
295 }
296
297 /* ************************************************ */
298 /* Brush Callbacks */
299 /* This section defines the callbacks used by each brush to perform their magic.
300  * These are called on each point within the brush's radius.
301  */
302
303 /* ----------------------------------------------- */
304 /* Smooth Brush */
305
306 /* A simple (but slower + inaccurate)
307  * smooth-brush implementation to test the algorithm for stroke smoothing. */
308 static bool gp_brush_smooth_apply(
309     tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
310 {
311   // GP_Sculpt_Data *gp_brush = gso->brush;
312   float inf = gp_brush_influence_calc(gso, radius, co);
313   /* need one flag enabled by default */
314   if ((gso->settings->flag &
315        (GP_SCULPT_SETT_FLAG_APPLY_POSITION | GP_SCULPT_SETT_FLAG_APPLY_STRENGTH |
316         GP_SCULPT_SETT_FLAG_APPLY_THICKNESS | GP_SCULPT_SETT_FLAG_APPLY_UV)) == 0) {
317     gso->settings->flag |= GP_SCULPT_SETT_FLAG_APPLY_POSITION;
318   }
319
320   /* perform smoothing */
321   if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_POSITION) {
322     BKE_gpencil_smooth_stroke(gps, pt_index, inf);
323   }
324   if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_STRENGTH) {
325     BKE_gpencil_smooth_stroke_strength(gps, pt_index, inf);
326   }
327   if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_THICKNESS) {
328     BKE_gpencil_smooth_stroke_thickness(gps, pt_index, inf);
329   }
330   if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_UV) {
331     BKE_gpencil_smooth_stroke_uv(gps, pt_index, inf);
332   }
333
334   gps->flag |= GP_STROKE_RECALC_GEOMETRY;
335
336   return true;
337 }
338
339 /* ----------------------------------------------- */
340 /* Line Thickness Brush */
341
342 /* Make lines thicker or thinner by the specified amounts */
343 static bool gp_brush_thickness_apply(
344     tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
345 {
346   bGPDspoint *pt = gps->points + pt_index;
347   float inf;
348
349   /* Compute strength of effect
350    * - We divide the strength by 10, so that users can set "sane" values.
351    *   Otherwise, good default values are in the range of 0.093
352    */
353   inf = gp_brush_influence_calc(gso, radius, co) / 10.0f;
354
355   /* apply */
356   /* XXX: this is much too strong,
357    * and it should probably do some smoothing with the surrounding stuff. */
358   if (gp_brush_invert_check(gso)) {
359     /* make line thinner - reduce stroke pressure */
360     pt->pressure -= inf;
361   }
362   else {
363     /* make line thicker - increase stroke pressure */
364     pt->pressure += inf;
365   }
366
367   /* Pressure should stay within [0.0, 1.0]
368    * However, it is nice for volumetric strokes to be able to exceed
369    * the upper end of this range. Therefore, we don't actually clamp
370    * down on the upper end.
371    */
372   if (pt->pressure < 0.0f) {
373     pt->pressure = 0.0f;
374   }
375
376   return true;
377 }
378
379 /* ----------------------------------------------- */
380 /* Color Strength Brush */
381
382 /* Make color more or less transparent by the specified amounts */
383 static bool gp_brush_strength_apply(
384     tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
385 {
386   bGPDspoint *pt = gps->points + pt_index;
387   float inf;
388
389   /* Compute strength of effect
390    * - We divide the strength, so that users can set "sane" values.
391    *   Otherwise, good default values are in the range of 0.093
392    */
393   inf = gp_brush_influence_calc(gso, radius, co) / 20.0f;
394
395   /* apply */
396   if (gp_brush_invert_check(gso)) {
397     /* make line more transparent - reduce alpha factor */
398     pt->strength -= inf;
399   }
400   else {
401     /* make line more opaque - increase stroke strength */
402     pt->strength += inf;
403   }
404   /* smooth the strength */
405   BKE_gpencil_smooth_stroke_strength(gps, pt_index, inf);
406
407   /* Strength should stay within [0.0, 1.0] */
408   CLAMP(pt->strength, 0.0f, 1.0f);
409
410   return true;
411 }
412
413 /* ----------------------------------------------- */
414 /* Grab Brush */
415
416 /* Custom data per stroke for the Grab Brush
417  *
418  * This basically defines the strength of the effect for each
419  * affected stroke point that was within the initial range of
420  * the brush region.
421  */
422 typedef struct tGPSB_Grab_StrokeData {
423   /* array of indices to corresponding points in the stroke */
424   int *points;
425   /* array of influence weights for each of the included points */
426   float *weights;
427
428   /* capacity of the arrays */
429   int capacity;
430   /* actual number of items currently stored */
431   int size;
432 } tGPSB_Grab_StrokeData;
433
434 /* initialise custom data for handling this stroke */
435 static void gp_brush_grab_stroke_init(tGP_BrushEditData *gso, bGPDstroke *gps)
436 {
437   tGPSB_Grab_StrokeData *data = NULL;
438
439   BLI_assert(gps->totpoints > 0);
440
441   /* Check if there are buffers already (from a prior run) */
442   if (BLI_ghash_haskey(gso->stroke_customdata, gps)) {
443     /* Ensure that the caches are empty
444      * - Since we reuse these between different strokes, we don't
445      *   want the previous invocation's data polluting the arrays
446      */
447     data = BLI_ghash_lookup(gso->stroke_customdata, gps);
448     BLI_assert(data != NULL);
449
450     data->size = 0; /* minimum requirement - so that we can repopulate again */
451
452     memset(data->points, 0, sizeof(int) * data->capacity);
453     memset(data->weights, 0, sizeof(float) * data->capacity);
454   }
455   else {
456     /* Create new instance */
457     data = MEM_callocN(sizeof(tGPSB_Grab_StrokeData), "GP Stroke Grab Data");
458
459     data->capacity = gps->totpoints;
460     data->size = 0;
461
462     data->points = MEM_callocN(sizeof(int) * data->capacity, "GP Stroke Grab Indices");
463     data->weights = MEM_callocN(sizeof(float) * data->capacity, "GP Stroke Grab Weights");
464
465     /* hook up to the cache */
466     BLI_ghash_insert(gso->stroke_customdata, gps, data);
467   }
468 }
469
470 /* store references to stroke points in the initial stage */
471 static bool gp_brush_grab_store_points(
472     tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
473 {
474   tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps);
475   float inf = gp_brush_influence_calc(gso, radius, co);
476
477   BLI_assert(data != NULL);
478   BLI_assert(data->size < data->capacity);
479
480   /* insert this point into the set of affected points */
481   data->points[data->size] = pt_index;
482   data->weights[data->size] = inf;
483   data->size++;
484
485   /* done */
486   return true;
487 }
488
489 /* Compute effect vector for grab brush */
490 static void gp_brush_grab_calc_dvec(tGP_BrushEditData *gso)
491 {
492   /* Convert mouse-movements to movement vector */
493   // TODO: incorporate pressure into this?
494   // XXX: screen-space strokes in 3D space will suffer!
495   if (gso->sa->spacetype == SPACE_VIEW3D) {
496     RegionView3D *rv3d = gso->ar->regiondata;
497     float *rvec = gso->scene->cursor.location;
498     float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
499
500     float mval_f[2];
501
502     /* convert from 2D screenspace to 3D... */
503     mval_f[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
504     mval_f[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
505
506     ED_view3d_win_to_delta(gso->ar, mval_f, gso->dvec, zfac);
507   }
508   else {
509     /* 2D - just copy */
510     // XXX: view2d?
511     gso->dvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
512     gso->dvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
513     gso->dvec[2] = 0.0f; /* unused */
514   }
515 }
516
517 /* Apply grab transform to all relevant points of the affected strokes */
518 static void gp_brush_grab_apply_cached(tGP_BrushEditData *gso,
519                                        bGPDstroke *gps,
520                                        float diff_mat[4][4])
521 {
522   tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps);
523   int i;
524
525   /* Apply dvec to all of the stored points */
526   for (i = 0; i < data->size; i++) {
527     bGPDspoint *pt = &gps->points[data->points[i]];
528     float delta[3] = {0.0f};
529
530     /* adjust the amount of displacement to apply */
531     mul_v3_v3fl(delta, gso->dvec, data->weights[i]);
532
533     float fpt[3];
534     float save_pt[3];
535     copy_v3_v3(save_pt, &pt->x);
536     /* apply transformation */
537     mul_v3_m4v3(fpt, diff_mat, &pt->x);
538     /* apply */
539     add_v3_v3v3(&pt->x, fpt, delta);
540     /* undo transformation to the init parent position */
541     float inverse_diff_mat[4][4];
542     invert_m4_m4(inverse_diff_mat, diff_mat);
543     mul_m4_v3(inverse_diff_mat, &pt->x);
544
545     /* compute lock axis */
546     gpsculpt_compute_lock_axis(gso, pt, save_pt);
547   }
548   gps->flag |= GP_STROKE_RECALC_GEOMETRY;
549 }
550
551 /* free customdata used for handling this stroke */
552 static void gp_brush_grab_stroke_free(void *ptr)
553 {
554   tGPSB_Grab_StrokeData *data = (tGPSB_Grab_StrokeData *)ptr;
555
556   /* free arrays */
557   MEM_freeN(data->points);
558   MEM_freeN(data->weights);
559
560   /* ... and this item itself, since it was also allocated */
561   MEM_freeN(data);
562 }
563
564 /* ----------------------------------------------- */
565 /* Push Brush */
566 /* NOTE: Depends on gp_brush_grab_calc_dvec() */
567
568 static bool gp_brush_push_apply(
569     tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
570 {
571   bGPDspoint *pt = gps->points + pt_index;
572   float save_pt[3];
573   copy_v3_v3(save_pt, &pt->x);
574
575   float inf = gp_brush_influence_calc(gso, radius, co);
576   float delta[3] = {0.0f};
577
578   /* adjust the amount of displacement to apply */
579   mul_v3_v3fl(delta, gso->dvec, inf);
580
581   /* apply */
582   add_v3_v3(&pt->x, delta);
583
584   /* compute lock axis */
585   gpsculpt_compute_lock_axis(gso, pt, save_pt);
586
587   gps->flag |= GP_STROKE_RECALC_GEOMETRY;
588
589   /* done */
590   return true;
591 }
592
593 /* ----------------------------------------------- */
594 /* Pinch Brush */
595
596 /* Compute reference midpoint for the brush - this is what we'll be moving towards */
597 static void gp_brush_calc_midpoint(tGP_BrushEditData *gso)
598 {
599   if (gso->sa->spacetype == SPACE_VIEW3D) {
600     /* Convert mouse position to 3D space
601      * See: gpencil_paint.c :: gp_stroke_convertcoords()
602      */
603     RegionView3D *rv3d = gso->ar->regiondata;
604     const float *rvec = gso->scene->cursor.location;
605     float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
606
607     float mval_f[2];
608     copy_v2_v2(mval_f, gso->mval);
609     float mval_prj[2];
610     float dvec[3];
611
612     if (ED_view3d_project_float_global(gso->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) ==
613         V3D_PROJ_RET_OK) {
614       sub_v2_v2v2(mval_f, mval_prj, mval_f);
615       ED_view3d_win_to_delta(gso->ar, mval_f, dvec, zfac);
616       sub_v3_v3v3(gso->dvec, rvec, dvec);
617     }
618     else {
619       zero_v3(gso->dvec);
620     }
621   }
622   else {
623     /* Just 2D coordinates */
624     // XXX: fix View2D offsets later
625     gso->dvec[0] = (float)gso->mval[0];
626     gso->dvec[1] = (float)gso->mval[1];
627     gso->dvec[2] = 0.0f;
628   }
629 }
630
631 /* Shrink distance between midpoint and this point... */
632 static bool gp_brush_pinch_apply(
633     tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
634 {
635   bGPDspoint *pt = gps->points + pt_index;
636   float fac, inf;
637   float vec[3];
638   float save_pt[3];
639   copy_v3_v3(save_pt, &pt->x);
640
641   /* Scale down standard influence value to get it more manageable...
642    * - No damping = Unmanageable at > 0.5 strength
643    * - Div 10     = Not enough effect
644    * - Div 5      = Happy medium... (by trial and error)
645    */
646   inf = gp_brush_influence_calc(gso, radius, co) / 5.0f;
647
648   /* 1) Make this point relative to the cursor/midpoint (dvec) */
649   sub_v3_v3v3(vec, &pt->x, gso->dvec);
650
651   /* 2) Shrink the distance by pulling the point towards the midpoint
652    *    (0.0 = at midpoint, 1 = at edge of brush region)
653    *                         OR
654    *    Increase the distance (if inverting the brush action!)
655    */
656   if (gp_brush_invert_check(gso)) {
657     /* Inflate (inverse) */
658     fac = 1.0f + (inf * inf); /* squared to temper the effect... */
659   }
660   else {
661     /* Shrink (default) */
662     fac = 1.0f - (inf * inf); /* squared to temper the effect... */
663   }
664   mul_v3_fl(vec, fac);
665
666   /* 3) Translate back to original space, with the shrinkage applied */
667   add_v3_v3v3(&pt->x, gso->dvec, vec);
668
669   /* compute lock axis */
670   gpsculpt_compute_lock_axis(gso, pt, save_pt);
671
672   gps->flag |= GP_STROKE_RECALC_GEOMETRY;
673
674   /* done */
675   return true;
676 }
677
678 /* ----------------------------------------------- */
679 /* Twist Brush - Rotate Around midpoint */
680
681 /* Take the screenspace coordinates of the point, rotate this around the brush midpoint,
682  * convert the rotated point and convert it into "data" space
683  */
684
685 static bool gp_brush_twist_apply(
686     tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
687 {
688   bGPDspoint *pt = gps->points + pt_index;
689   float angle, inf;
690   float save_pt[3];
691   copy_v3_v3(save_pt, &pt->x);
692
693   /* Angle to rotate by */
694   inf = gp_brush_influence_calc(gso, radius, co);
695   angle = DEG2RADF(1.0f) * inf;
696
697   if (gp_brush_invert_check(gso)) {
698     /* invert angle that we rotate by */
699     angle *= -1;
700   }
701
702   /* Rotate in 2D or 3D space? */
703   if (gps->flag & GP_STROKE_3DSPACE) {
704     /* Perform rotation in 3D space... */
705     RegionView3D *rv3d = gso->ar->regiondata;
706     float rmat[3][3];
707     float axis[3];
708     float vec[3];
709
710     /* Compute rotation matrix - rotate around view vector by angle */
711     negate_v3_v3(axis, rv3d->persinv[2]);
712     normalize_v3(axis);
713
714     axis_angle_normalized_to_mat3(rmat, axis, angle);
715
716     /* Rotate point (no matrix-space transforms needed, as GP points are in world space) */
717     sub_v3_v3v3(vec, &pt->x, gso->dvec); /* make relative to center
718                                           * (center is stored in dvec) */
719     mul_m3_v3(rmat, vec);
720     add_v3_v3v3(&pt->x, vec, gso->dvec); /* restore */
721
722     /* compute lock axis */
723     gpsculpt_compute_lock_axis(gso, pt, save_pt);
724   }
725   else {
726     const float axis[3] = {0.0f, 0.0f, 1.0f};
727     float vec[3] = {0.0f};
728     float rmat[3][3];
729
730     /* Express position of point relative to cursor, ready to rotate */
731     // XXX: There is still some offset here, but it's close to working as expected...
732     vec[0] = (float)(co[0] - gso->mval[0]);
733     vec[1] = (float)(co[1] - gso->mval[1]);
734
735     /* rotate point */
736     axis_angle_normalized_to_mat3(rmat, axis, angle);
737     mul_m3_v3(rmat, vec);
738
739     /* Convert back to screen-coordinates */
740     vec[0] += (float)gso->mval[0];
741     vec[1] += (float)gso->mval[1];
742
743     /* Map from screen-coordinates to final coordinate space */
744     if (gps->flag & GP_STROKE_2DSPACE) {
745       View2D *v2d = gso->gsc.v2d;
746       UI_view2d_region_to_view(v2d, vec[0], vec[1], &pt->x, &pt->y);
747     }
748     else {
749       // XXX
750       copy_v2_v2(&pt->x, vec);
751     }
752   }
753
754   gps->flag |= GP_STROKE_RECALC_GEOMETRY;
755
756   /* done */
757   return true;
758 }
759
760 /* ----------------------------------------------- */
761 /* Randomize Brush */
762
763 /* Apply some random jitter to the point */
764 static bool gp_brush_randomize_apply(
765     tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
766 {
767   bGPDspoint *pt = gps->points + pt_index;
768   float save_pt[3];
769   copy_v3_v3(save_pt, &pt->x);
770
771   /* Amount of jitter to apply depends on the distance of the point to the cursor,
772    * as well as the strength of the brush
773    */
774   const float inf = gp_brush_influence_calc(gso, radius, co) / 2.0f;
775   const float fac = BLI_rng_get_float(gso->rng) * inf;
776   /* need one flag enabled by default */
777   if ((gso->settings->flag &
778        (GP_SCULPT_SETT_FLAG_APPLY_POSITION | GP_SCULPT_SETT_FLAG_APPLY_STRENGTH |
779         GP_SCULPT_SETT_FLAG_APPLY_THICKNESS | GP_SCULPT_SETT_FLAG_APPLY_UV)) == 0) {
780     gso->settings->flag |= GP_SCULPT_SETT_FLAG_APPLY_POSITION;
781   }
782
783   /* apply random to position */
784   if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_POSITION) {
785     /* Jitter is applied perpendicular to the mouse movement vector
786      * - We compute all effects in screenspace (since it's easier)
787      *   and then project these to get the points/distances in
788      *   view-space as needed.
789      */
790     float mvec[2], svec[2];
791
792     /* mouse movement in ints -> floats */
793     mvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
794     mvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
795
796     /* rotate mvec by 90 degrees... */
797     svec[0] = -mvec[1];
798     svec[1] = mvec[0];
799
800     /* scale the displacement by the random displacement, and apply */
801     if (BLI_rng_get_float(gso->rng) > 0.5f) {
802       mul_v2_fl(svec, -fac);
803     }
804     else {
805       mul_v2_fl(svec, fac);
806     }
807
808 #if 0
809     printf("%f %f (%f), nco = {%f %f}, co = %d %d\n",
810            svec[0],
811            svec[1],
812            fac,
813            nco[0],
814            nco[1],
815            co[0],
816            co[1]);
817 #endif
818
819     /* convert to dataspace */
820     if (gps->flag & GP_STROKE_3DSPACE) {
821       /* 3D: Project to 3D space */
822       if (gso->sa->spacetype == SPACE_VIEW3D) {
823         bool flip;
824         RegionView3D *rv3d = gso->ar->regiondata;
825         float zfac = ED_view3d_calc_zfac(rv3d, &pt->x, &flip);
826         if (flip == false) {
827           float dvec[3];
828           ED_view3d_win_to_delta(gso->gsc.ar, svec, dvec, zfac);
829           add_v3_v3(&pt->x, dvec);
830           /* compute lock axis */
831           gpsculpt_compute_lock_axis(gso, pt, save_pt);
832         }
833       }
834       else {
835         /* ERROR */
836         BLI_assert(!"3D stroke being sculpted in non-3D view");
837       }
838     }
839     else {
840       /* 2D: As-is */
841       // XXX: v2d scaling/offset?
842       float nco[2];
843       nco[0] = (float)co[0] + svec[0];
844       nco[1] = (float)co[1] + svec[1];
845
846       copy_v2_v2(&pt->x, nco);
847     }
848   }
849   /* apply random to strength */
850   if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_STRENGTH) {
851     if (BLI_rng_get_float(gso->rng) > 0.5f) {
852       pt->strength += fac;
853     }
854     else {
855       pt->strength -= fac;
856     }
857     CLAMP_MIN(pt->strength, 0.0f);
858     CLAMP_MAX(pt->strength, 1.0f);
859   }
860   /* apply random to thickness (use pressure) */
861   if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_THICKNESS) {
862     if (BLI_rng_get_float(gso->rng) > 0.5f) {
863       pt->pressure += fac;
864     }
865     else {
866       pt->pressure -= fac;
867     }
868     /* only limit lower value */
869     CLAMP_MIN(pt->pressure, 0.0f);
870   }
871   /* apply random to UV (use pressure) */
872   if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_UV) {
873     if (BLI_rng_get_float(gso->rng) > 0.5f) {
874       pt->uv_rot += fac;
875     }
876     else {
877       pt->uv_rot -= fac;
878     }
879     CLAMP(pt->uv_rot, -M_PI_2, M_PI_2);
880   }
881
882   gps->flag |= GP_STROKE_RECALC_GEOMETRY;
883
884   /* done */
885   return true;
886 }
887
888 /* Weight Paint Brush */
889
890 /* Change weight paint for vertex groups */
891 static bool gp_brush_weight_apply(
892     tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
893 {
894   /* create dvert */
895   BKE_gpencil_dvert_ensure(gps);
896
897   MDeformVert *dvert = gps->dvert + pt_index;
898   float inf;
899
900   /* Compute strength of effect
901    * - We divide the strength by 10, so that users can set "sane" values.
902    *   Otherwise, good default values are in the range of 0.093
903    */
904   inf = gp_brush_influence_calc(gso, radius, co) / 10.0f;
905
906   /* need a vertex group */
907   if (gso->vrgroup == -1) {
908     if (gso->object) {
909       BKE_object_defgroup_add(gso->object);
910       DEG_relations_tag_update(gso->bmain);
911       gso->vrgroup = 0;
912     }
913   }
914   else {
915     bDeformGroup *defgroup = BLI_findlink(&gso->object->defbase, gso->vrgroup);
916     if (defgroup->flag & DG_LOCK_WEIGHT) {
917       return false;
918     }
919   }
920   /* get current weight */
921   MDeformWeight *dw = defvert_verify_index(dvert, gso->vrgroup);
922   float curweight = dw ? dw->weight : 0.0f;
923
924   if (gp_brush_invert_check(gso)) {
925     curweight -= inf;
926   }
927   else {
928     /* increase weight */
929     curweight += inf;
930     /* verify maximum target weight */
931     CLAMP_MAX(curweight, gso->gp_brush->weight);
932   }
933
934   CLAMP(curweight, 0.0f, 1.0f);
935   if (dw) {
936     dw->weight = curweight;
937   }
938
939   return true;
940 }
941
942 /* ************************************************ */
943 /* Non Callback-Based Brushes */
944
945 /* Clone Brush ------------------------------------- */
946 /* How this brush currently works:
947  * - If this is start of the brush stroke, paste immediately under the cursor
948  *   by placing the midpoint of the buffer strokes under the cursor now
949  *
950  * - Otherwise, in:
951  *   "Stamp Mode" - Move the newly pasted strokes so that their center follows the cursor
952  *   "Continuous" - Repeatedly just paste new copies for where the brush is now
953  */
954
955 /* Custom state data for clone brush */
956 typedef struct tGPSB_CloneBrushData {
957   /* midpoint of the strokes on the clipboard */
958   float buffer_midpoint[3];
959
960   /* number of strokes in the paste buffer (and/or to be created each time) */
961   size_t totitems;
962
963   /* for "stamp" mode, the currently pasted brushes */
964   bGPDstroke **new_strokes;
965
966   /** Mapping from colors referenced per stroke, to the new colors in the "pasted" strokes. */
967   GHash *new_colors;
968 } tGPSB_CloneBrushData;
969
970 /* Initialise "clone" brush data */
971 static void gp_brush_clone_init(bContext *C, tGP_BrushEditData *gso)
972 {
973   tGPSB_CloneBrushData *data;
974   bGPDstroke *gps;
975
976   /* init custom data */
977   gso->customdata = data = MEM_callocN(sizeof(tGPSB_CloneBrushData), "CloneBrushData");
978
979   /* compute midpoint of strokes on clipboard */
980   for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
981     if (ED_gpencil_stroke_can_use(C, gps)) {
982       const float dfac = 1.0f / ((float)gps->totpoints);
983       float mid[3] = {0.0f};
984
985       bGPDspoint *pt;
986       int i;
987
988       /* compute midpoint of this stroke */
989       for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
990         float co[3];
991
992         mul_v3_v3fl(co, &pt->x, dfac);
993         add_v3_v3(mid, co);
994       }
995
996       /* combine this stroke's data with the main data */
997       add_v3_v3(data->buffer_midpoint, mid);
998       data->totitems++;
999     }
1000   }
1001
1002   /* Divide the midpoint by the number of strokes, to finish averaging it */
1003   if (data->totitems > 1) {
1004     mul_v3_fl(data->buffer_midpoint, 1.0f / (float)data->totitems);
1005   }
1006
1007   /* Create a buffer for storing the current strokes */
1008   if (1 /*gso->brush->mode == GP_EDITBRUSH_CLONE_MODE_STAMP*/) {
1009     data->new_strokes = MEM_callocN(sizeof(bGPDstroke *) * data->totitems,
1010                                     "cloned strokes ptr array");
1011   }
1012
1013   /* Init colormap for mapping between the pasted stroke's source color (names)
1014    * and the final colors that will be used here instead.
1015    */
1016   data->new_colors = gp_copybuf_validate_colormap(C);
1017 }
1018
1019 /* Free custom data used for "clone" brush */
1020 static void gp_brush_clone_free(tGP_BrushEditData *gso)
1021 {
1022   tGPSB_CloneBrushData *data = gso->customdata;
1023
1024   /* free strokes array */
1025   if (data->new_strokes) {
1026     MEM_freeN(data->new_strokes);
1027     data->new_strokes = NULL;
1028   }
1029
1030   /* free copybuf colormap */
1031   if (data->new_colors) {
1032     BLI_ghash_free(data->new_colors, NULL, NULL);
1033     data->new_colors = NULL;
1034   }
1035
1036   /* free the customdata itself */
1037   MEM_freeN(data);
1038   gso->customdata = NULL;
1039 }
1040
1041 /* Create new copies of the strokes on the clipboard */
1042 static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso)
1043 {
1044   tGPSB_CloneBrushData *data = gso->customdata;
1045
1046   Object *ob = CTX_data_active_object(C);
1047   bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
1048   Depsgraph *depsgraph = CTX_data_depsgraph(C);
1049   int cfra_eval = (int)DEG_get_ctime(depsgraph);
1050
1051   bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
1052   bGPDstroke *gps;
1053
1054   float delta[3];
1055   size_t strokes_added = 0;
1056
1057   /* Compute amount to offset the points by */
1058   /* NOTE: This assumes that screenspace strokes are NOT used in the 3D view... */
1059
1060   gp_brush_calc_midpoint(gso); /* this puts the cursor location into gso->dvec */
1061   sub_v3_v3v3(delta, gso->dvec, data->buffer_midpoint);
1062
1063   /* Copy each stroke into the layer */
1064   for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
1065     if (ED_gpencil_stroke_can_use(C, gps)) {
1066       bGPDstroke *new_stroke;
1067       bGPDspoint *pt;
1068       int i;
1069
1070       /* Make a new stroke */
1071       new_stroke = MEM_dupallocN(gps);
1072
1073       new_stroke->points = MEM_dupallocN(gps->points);
1074       if (gps->dvert != NULL) {
1075         new_stroke->dvert = MEM_dupallocN(gps->dvert);
1076         BKE_gpencil_stroke_weights_duplicate(gps, new_stroke);
1077       }
1078       new_stroke->triangles = MEM_dupallocN(gps->triangles);
1079
1080       new_stroke->next = new_stroke->prev = NULL;
1081       BLI_addtail(&gpf->strokes, new_stroke);
1082
1083       /* Fix color references */
1084       Material *ma = BLI_ghash_lookup(data->new_colors, &new_stroke->mat_nr);
1085       gps->mat_nr = BKE_gpencil_object_material_get_index(ob, ma);
1086       if (!ma || gps->mat_nr) {
1087         gps->mat_nr = 0;
1088       }
1089       /* Adjust all the stroke's points, so that the strokes
1090        * get pasted relative to where the cursor is now
1091        */
1092       for (i = 0, pt = new_stroke->points; i < new_stroke->totpoints; i++, pt++) {
1093         /* assume that the delta can just be applied, and then everything works */
1094         add_v3_v3(&pt->x, delta);
1095       }
1096
1097       /* Store ref for later */
1098       if ((data->new_strokes) && (strokes_added < data->totitems)) {
1099         data->new_strokes[strokes_added] = new_stroke;
1100         strokes_added++;
1101       }
1102     }
1103   }
1104 }
1105
1106 /* Move newly-added strokes around - "Stamp" mode of the Clone brush */
1107 static void gp_brush_clone_adjust(tGP_BrushEditData *gso)
1108 {
1109   tGPSB_CloneBrushData *data = gso->customdata;
1110   size_t snum;
1111
1112   /* Compute the amount of movement to apply (overwrites dvec) */
1113   gp_brush_grab_calc_dvec(gso);
1114
1115   /* For each of the stored strokes, apply the offset to each point */
1116   /* NOTE: Again this assumes that in the 3D view,
1117    * we only have 3d space and not screenspace strokes... */
1118   for (snum = 0; snum < data->totitems; snum++) {
1119     bGPDstroke *gps = data->new_strokes[snum];
1120     bGPDspoint *pt;
1121     int i;
1122
1123     for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
1124       if (gso->gp_brush->flag & GP_SCULPT_FLAG_USE_FALLOFF) {
1125         /* "Smudge" Effect when falloff is enabled */
1126         float delta[3] = {0.0f};
1127         int sco[2] = {0};
1128         float influence;
1129
1130         /* compute influence on point */
1131         gp_point_to_xy(&gso->gsc, gps, pt, &sco[0], &sco[1]);
1132         influence = gp_brush_influence_calc(gso, gso->gp_brush->size, sco);
1133
1134         /* adjust the amount of displacement to apply */
1135         mul_v3_v3fl(delta, gso->dvec, influence);
1136
1137         /* apply */
1138         add_v3_v3(&pt->x, delta);
1139       }
1140       else {
1141         /* Just apply the offset - All points move perfectly in sync with the cursor */
1142         add_v3_v3(&pt->x, gso->dvec);
1143       }
1144     }
1145   }
1146 }
1147
1148 /* Entrypoint for applying "clone" brush */
1149 static bool gpsculpt_brush_apply_clone(bContext *C, tGP_BrushEditData *gso)
1150 {
1151   /* Which "mode" are we operating in? */
1152   if (gso->first) {
1153     /* Create initial clones */
1154     gp_brush_clone_add(C, gso);
1155   }
1156   else {
1157     /* Stamp or Continuous Mode */
1158     if (1 /*gso->brush->mode == GP_EDITBRUSH_CLONE_MODE_STAMP*/) {
1159       /* Stamp - Proceed to translate the newly added strokes */
1160       gp_brush_clone_adjust(gso);
1161     }
1162     else {
1163       /* Continuous - Just keep pasting everytime we move */
1164       /* TODO: The spacing of repeat should be controlled using a
1165        * "stepsize" or similar property? */
1166       gp_brush_clone_add(C, gso);
1167     }
1168   }
1169
1170   return true;
1171 }
1172
1173 /* ************************************************ */
1174 /* Header Info for GPencil Sculpt */
1175
1176 static void gpsculpt_brush_header_set(bContext *C, tGP_BrushEditData *gso)
1177 {
1178   const char *brush_name = NULL;
1179   char str[UI_MAX_DRAW_STR] = "";
1180
1181   RNA_enum_name(rna_enum_gpencil_sculpt_brush_items, gso->brush_type, &brush_name);
1182
1183   BLI_snprintf(str,
1184                sizeof(str),
1185                IFACE_("GPencil Sculpt: %s Stroke  | LMB to paint | RMB/Escape to Exit"
1186                       " | Ctrl to Invert Action | Wheel Up/Down for Size "
1187                       " | Shift-Wheel Up/Down for Strength"),
1188                (brush_name) ? brush_name : "<?>");
1189
1190   ED_workspace_status_text(C, str);
1191 }
1192
1193 /* ************************************************ */
1194 /* Grease Pencil Sculpting Operator */
1195
1196 /* Init/Exit ----------------------------------------------- */
1197
1198 static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
1199 {
1200   Scene *scene = CTX_data_scene(C);
1201   ToolSettings *ts = CTX_data_tool_settings(C);
1202   Object *ob = CTX_data_active_object(C);
1203
1204   const bool is_weight_mode = ob->mode == OB_MODE_WEIGHT_GPENCIL;
1205   /* set the brush using the tool */
1206 #if 0
1207   GP_Sculpt_Settings *gset = &ts->gp_sculpt;
1208   eGP_Sculpt_Types mode = is_weight_mode ? gset->weighttype : gset->brushtype;
1209 #endif
1210   tGP_BrushEditData *gso;
1211
1212   /* setup operator data */
1213   gso = MEM_callocN(sizeof(tGP_BrushEditData), "tGP_BrushEditData");
1214   op->customdata = gso;
1215
1216   gso->depsgraph = CTX_data_depsgraph(C);
1217   gso->bmain = CTX_data_main(C);
1218   /* store state */
1219   gso->settings = gpsculpt_get_settings(scene);
1220   gso->gp_brush = gpsculpt_get_brush(scene, is_weight_mode);
1221   gso->is_weight_mode = is_weight_mode;
1222
1223   if (is_weight_mode) {
1224     gso->brush_type = gso->settings->weighttype;
1225   }
1226   else {
1227     gso->brush_type = gso->settings->brushtype;
1228   }
1229
1230   /* Random generator, only init once. */
1231   uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
1232   rng_seed ^= POINTER_AS_UINT(gso);
1233   gso->rng = BLI_rng_new(rng_seed);
1234
1235   gso->is_painting = false;
1236   gso->first = true;
1237
1238   gso->gpd = ED_gpencil_data_get_active(C);
1239   gso->cfra = INT_MAX; /* NOTE: So that first stroke will get handled in init_stroke() */
1240
1241   /* some brushes cannot use pressure for radius */
1242   if (ELEM(gso->brush_type, GP_SCULPT_TYPE_GRAB, GP_SCULPT_TYPE_CLONE)) {
1243     gso->gp_brush->flag &= ~GP_SCULPT_FLAG_PRESSURE_RADIUS;
1244   }
1245
1246   gso->scene = scene;
1247   gso->object = ob;
1248   if (ob) {
1249     gso->vrgroup = ob->actdef - 1;
1250     if (!BLI_findlink(&ob->defbase, gso->vrgroup)) {
1251       gso->vrgroup = -1;
1252     }
1253   }
1254   else {
1255     gso->vrgroup = -1;
1256   }
1257
1258   gso->sa = CTX_wm_area(C);
1259   gso->ar = CTX_wm_region(C);
1260
1261   /* multiframe settings */
1262   gso->is_multiframe = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd);
1263   gso->use_multiframe_falloff = (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_FRAME_FALLOFF) != 0;
1264
1265   /* Init multi-edit falloff curve data before doing anything,
1266    * so we won't have to do it again later. */
1267   if (gso->is_multiframe) {
1268     curvemapping_initialize(ts->gp_sculpt.cur_falloff);
1269   }
1270
1271   /* initialise custom data for brushes */
1272   switch (gso->brush_type) {
1273     case GP_SCULPT_TYPE_CLONE: {
1274       bGPDstroke *gps;
1275       bool found = false;
1276
1277       /* check that there are some usable strokes in the buffer */
1278       for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
1279         if (ED_gpencil_stroke_can_use(C, gps)) {
1280           found = true;
1281           break;
1282         }
1283       }
1284
1285       if (found == false) {
1286         /* STOP HERE! Nothing to paste! */
1287         BKE_report(op->reports,
1288                    RPT_ERROR,
1289                    "Copy some strokes to the clipboard before using the Clone brush to paste "
1290                    "copies of them");
1291
1292         MEM_freeN(gso);
1293         op->customdata = NULL;
1294         return false;
1295       }
1296       else {
1297         /* initialise customdata */
1298         gp_brush_clone_init(C, gso);
1299       }
1300       break;
1301     }
1302
1303     case GP_SCULPT_TYPE_GRAB: {
1304       /* initialise the cache needed for this brush */
1305       gso->stroke_customdata = BLI_ghash_ptr_new("GP Grab Brush - Strokes Hash");
1306       break;
1307     }
1308
1309     /* Others - No customdata needed */
1310     default:
1311       break;
1312   }
1313
1314   /* setup space conversions */
1315   gp_point_conversion_init(C, &gso->gsc);
1316
1317   /* update header */
1318   gpsculpt_brush_header_set(C, gso);
1319
1320   /* setup cursor drawing */
1321   // WM_cursor_modal_set(CTX_wm_window(C), BC_CROSSCURSOR);
1322   if (gso->sa->spacetype != SPACE_VIEW3D) {
1323     ED_gpencil_toggle_brush_cursor(C, true, NULL);
1324   }
1325   return true;
1326 }
1327
1328 static void gpsculpt_brush_exit(bContext *C, wmOperator *op)
1329 {
1330   tGP_BrushEditData *gso = op->customdata;
1331   wmWindow *win = CTX_wm_window(C);
1332
1333   /* free brush-specific data */
1334   switch (gso->brush_type) {
1335     case GP_SCULPT_TYPE_GRAB: {
1336       /* Free per-stroke customdata
1337        * - Keys don't need to be freed, as those are the strokes
1338        * - Values assigned to those keys do, as they are custom structs
1339        */
1340       BLI_ghash_free(gso->stroke_customdata, NULL, gp_brush_grab_stroke_free);
1341       break;
1342     }
1343
1344     case GP_SCULPT_TYPE_CLONE: {
1345       /* Free customdata */
1346       gp_brush_clone_free(gso);
1347       break;
1348     }
1349
1350     default:
1351       break;
1352   }
1353
1354   /* unregister timer (only used for realtime) */
1355   if (gso->timer) {
1356     WM_event_remove_timer(CTX_wm_manager(C), win, gso->timer);
1357   }
1358
1359   if (gso->rng != NULL) {
1360     BLI_rng_free(gso->rng);
1361   }
1362
1363   /* disable cursor and headerprints */
1364   ED_workspace_status_text(C, NULL);
1365   WM_cursor_modal_restore(win);
1366   if (gso->sa->spacetype != SPACE_VIEW3D) {
1367     ED_gpencil_toggle_brush_cursor(C, false, NULL);
1368   }
1369
1370   /* disable temp invert flag */
1371   gso->gp_brush->flag &= ~GP_SCULPT_FLAG_TMP_INVERT;
1372
1373   /* free operator data */
1374   MEM_freeN(gso);
1375   op->customdata = NULL;
1376 }
1377
1378 /* poll callback for stroke sculpting operator(s) */
1379 static bool gpsculpt_brush_poll(bContext *C)
1380 {
1381   /* NOTE: this is a bit slower, but is the most accurate... */
1382   return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0;
1383 }
1384
1385 /* Init Sculpt Stroke ---------------------------------- */
1386
1387 static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso)
1388 {
1389   bGPdata *gpd = gso->gpd;
1390
1391   bGPDlayer *gpl;
1392   int cfra_eval = (int)DEG_get_ctime(gso->depsgraph);
1393
1394   /* only try to add a new frame if this is the first stroke, or the frame has changed */
1395   if ((gpd == NULL) || (cfra_eval == gso->cfra)) {
1396     return;
1397   }
1398
1399   /* go through each layer, and ensure that we've got a valid frame to use */
1400   for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
1401     /* only editable and visible layers are considered */
1402     if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
1403       bGPDframe *gpf = gpl->actframe;
1404
1405       /* Make a new frame to work on if the layer's frame
1406        * and the current scene frame don't match up:
1407        * - This is useful when animating as it saves that "uh-oh" moment when you realize you've
1408        *   spent too much time editing the wrong frame.
1409        */
1410       // XXX: should this be allowed when framelock is enabled?
1411       if (gpf->framenum != cfra_eval) {
1412         BKE_gpencil_frame_addcopy(gpl, cfra_eval);
1413       }
1414     }
1415   }
1416
1417   /* save off new current frame, so that next update works fine */
1418   gso->cfra = cfra_eval;
1419 }
1420
1421 /* Apply ----------------------------------------------- */
1422
1423 /* Apply brush operation to points in this stroke */
1424 static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
1425                                      bGPDstroke *gps,
1426                                      float diff_mat[4][4],
1427                                      GP_BrushApplyCb apply)
1428 {
1429   GP_SpaceConversion *gsc = &gso->gsc;
1430   rcti *rect = &gso->brush_rect;
1431   GP_Sculpt_Data *gp_brush = gso->gp_brush;
1432   const int radius = (gp_brush->flag & GP_SCULPT_FLAG_PRESSURE_RADIUS) ?
1433                          gso->gp_brush->size * gso->pressure :
1434                          gso->gp_brush->size;
1435
1436   bGPDspoint *pt1, *pt2;
1437   int pc1[2] = {0};
1438   int pc2[2] = {0};
1439   int i;
1440   bool include_last = false;
1441   bool changed = false;
1442
1443   if (gps->totpoints == 1) {
1444     bGPDspoint pt_temp;
1445     gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
1446     gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
1447
1448     /* do boundbox check first */
1449     if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
1450       /* only check if point is inside */
1451       int mval_i[2];
1452       round_v2i_v2fl(mval_i, gso->mval);
1453       if (len_v2v2_int(mval_i, pc1) <= radius) {
1454         /* apply operation to this point */
1455         changed = apply(gso, gps, 0, radius, pc1);
1456       }
1457     }
1458   }
1459   else {
1460     /* Loop over the points in the stroke, checking for intersections
1461      * - an intersection means that we touched the stroke
1462      */
1463     for (i = 0; (i + 1) < gps->totpoints; i++) {
1464       /* Get points to work with */
1465       pt1 = gps->points + i;
1466       pt2 = gps->points + i + 1;
1467
1468       /* Skip if neither one is selected
1469        * (and we are only allowed to edit/consider selected points) */
1470       if (gso->settings->flag & GP_SCULPT_SETT_FLAG_SELECT_MASK) {
1471         if (!(pt1->flag & GP_SPOINT_SELECT) && !(pt2->flag & GP_SPOINT_SELECT)) {
1472           include_last = false;
1473           continue;
1474         }
1475       }
1476       bGPDspoint npt;
1477       gp_point_to_parent_space(pt1, diff_mat, &npt);
1478       gp_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]);
1479
1480       gp_point_to_parent_space(pt2, diff_mat, &npt);
1481       gp_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
1482
1483       /* Check that point segment of the boundbox of the selection stroke */
1484       if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
1485           ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
1486         /* Check if point segment of stroke had anything to do with
1487          * brush region  (either within stroke painted, or on its lines)
1488          * - this assumes that linewidth is irrelevant
1489          */
1490         if (gp_stroke_inside_circle(
1491                 gso->mval, gso->mval_prev, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
1492           /* Apply operation to these points */
1493           bool ok = false;
1494
1495           /* To each point individually... */
1496           ok = apply(gso, gps, i, radius, pc1);
1497
1498           /* Only do the second point if this is the last segment,
1499            * and it is unlikely that the point will get handled
1500            * otherwise.
1501            *
1502            * NOTE: There is a small risk here that the second point wasn't really
1503            *       actually in-range. In that case, it only got in because
1504            *       the line linking the points was!
1505            */
1506           if (i + 1 == gps->totpoints - 1) {
1507             ok |= apply(gso, gps, i + 1, radius, pc2);
1508             include_last = false;
1509           }
1510           else {
1511             include_last = true;
1512           }
1513
1514           changed |= ok;
1515         }
1516         else if (include_last) {
1517           /* This case is for cases where for whatever reason the second vert (1st here)
1518            * doesn't get included because the whole edge isn't in bounds,
1519            * but it would've qualified since it did with the previous step
1520            * (but wasn't added then, to avoid double-ups).
1521            */
1522           changed |= apply(gso, gps, i, radius, pc1);
1523           include_last = false;
1524         }
1525       }
1526     }
1527   }
1528
1529   return changed;
1530 }
1531
1532 /* Apply sculpt brushes to strokes in the given frame */
1533 static bool gpsculpt_brush_do_frame(
1534     bContext *C, tGP_BrushEditData *gso, bGPDlayer *gpl, bGPDframe *gpf, float diff_mat[4][4])
1535 {
1536   bool changed = false;
1537   Object *ob = CTX_data_active_object(C);
1538
1539   for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
1540     /* skip strokes that are invalid for current view */
1541     if (ED_gpencil_stroke_can_use(C, gps) == false) {
1542       continue;
1543     }
1544     /* check if the color is editable */
1545     if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
1546       continue;
1547     }
1548
1549     switch (gso->brush_type) {
1550       case GP_SCULPT_TYPE_SMOOTH: /* Smooth strokes */
1551       {
1552         changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_smooth_apply);
1553         break;
1554       }
1555
1556       case GP_SCULPT_TYPE_THICKNESS: /* Adjust stroke thickness */
1557       {
1558         changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_thickness_apply);
1559         break;
1560       }
1561
1562       case GP_SCULPT_TYPE_STRENGTH: /* Adjust stroke color strength */
1563       {
1564         changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_strength_apply);
1565         break;
1566       }
1567
1568       case GP_SCULPT_TYPE_GRAB: /* Grab points */
1569       {
1570         if (gso->first) {
1571           /* First time this brush stroke is being applied:
1572            * 1) Prepare data buffers (init/clear) for this stroke
1573            * 2) Use the points now under the cursor
1574            */
1575           gp_brush_grab_stroke_init(gso, gps);
1576           changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_grab_store_points);
1577         }
1578         else {
1579           /* Apply effect to the stored points */
1580           gp_brush_grab_apply_cached(gso, gps, diff_mat);
1581           changed |= true;
1582         }
1583         break;
1584       }
1585
1586       case GP_SCULPT_TYPE_PUSH: /* Push points */
1587       {
1588         changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_push_apply);
1589         break;
1590       }
1591
1592       case GP_SCULPT_TYPE_PINCH: /* Pinch points */
1593       {
1594         changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_pinch_apply);
1595         break;
1596       }
1597
1598       case GP_SCULPT_TYPE_TWIST: /* Twist points around midpoint */
1599       {
1600         changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_twist_apply);
1601         break;
1602       }
1603
1604       case GP_SCULPT_TYPE_RANDOMIZE: /* Apply jitter */
1605       {
1606         changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_randomize_apply);
1607         break;
1608       }
1609
1610       case GP_SCULPT_TYPE_WEIGHT: /* Adjust vertex group weight */
1611       {
1612         changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_weight_apply);
1613         break;
1614       }
1615
1616       default:
1617         printf("ERROR: Unknown type of GPencil Sculpt brush - %u\n", gso->brush_type);
1618         break;
1619     }
1620     /* Triangulation must be calculated if changed */
1621     if (changed) {
1622       gps->flag |= GP_STROKE_RECALC_GEOMETRY;
1623       gps->tot_triangles = 0;
1624     }
1625   }
1626
1627   return changed;
1628 }
1629
1630 /* Perform two-pass brushes which modify the existing strokes */
1631 static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
1632 {
1633   ToolSettings *ts = CTX_data_tool_settings(C);
1634   Depsgraph *depsgraph = CTX_data_depsgraph(C);
1635   Object *obact = gso->object;
1636   bGPdata *gpd = gso->gpd;
1637   bool changed = false;
1638
1639   /* Calculate brush-specific data which applies equally to all points */
1640   switch (gso->brush_type) {
1641     case GP_SCULPT_TYPE_GRAB: /* Grab points */
1642     case GP_SCULPT_TYPE_PUSH: /* Push points */
1643     {
1644       /* calculate amount of displacement to apply */
1645       gp_brush_grab_calc_dvec(gso);
1646       break;
1647     }
1648
1649     case GP_SCULPT_TYPE_PINCH: /* Pinch points */
1650     case GP_SCULPT_TYPE_TWIST: /* Twist points around midpoint */
1651     {
1652       /* calculate midpoint of the brush (in data space) */
1653       gp_brush_calc_midpoint(gso);
1654       break;
1655     }
1656
1657     case GP_SCULPT_TYPE_RANDOMIZE: /* Random jitter */
1658     {
1659       /* compute the displacement vector for the cursor (in data space) */
1660       gp_brush_grab_calc_dvec(gso);
1661       break;
1662     }
1663
1664     default:
1665       break;
1666   }
1667
1668   /* Find visible strokes, and perform operations on those if hit */
1669   CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
1670     /* If no active frame, don't do anything... */
1671     if (gpl->actframe == NULL) {
1672       continue;
1673     }
1674
1675     /* calculate difference matrix */
1676     float diff_mat[4][4];
1677     ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
1678
1679     /* Active Frame or MultiFrame? */
1680     if (gso->is_multiframe) {
1681       /* init multiframe falloff options */
1682       int f_init = 0;
1683       int f_end = 0;
1684
1685       if (gso->use_multiframe_falloff) {
1686         BKE_gpencil_get_range_selected(gpl, &f_init, &f_end);
1687       }
1688
1689       for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
1690         /* Always do active frame; Otherwise, only include selected frames */
1691         if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) {
1692           /* compute multiframe falloff factor */
1693           if (gso->use_multiframe_falloff) {
1694             /* Faloff depends on distance to active frame (relative to the overall frame range) */
1695             gso->mf_falloff = BKE_gpencil_multiframe_falloff_calc(
1696                 gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff);
1697           }
1698           else {
1699             /* No falloff */
1700             gso->mf_falloff = 1.0f;
1701           }
1702
1703           /* affect strokes in this frame */
1704           changed |= gpsculpt_brush_do_frame(C, gso, gpl, gpf, diff_mat);
1705         }
1706       }
1707     }
1708     else {
1709       /* Apply to active frame's strokes */
1710       gso->mf_falloff = 1.0f;
1711       changed |= gpsculpt_brush_do_frame(C, gso, gpl, gpl->actframe, diff_mat);
1712     }
1713   }
1714   CTX_DATA_END;
1715
1716   return changed;
1717 }
1718
1719 /* Calculate settings for applying brush */
1720 static void gpsculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
1721 {
1722   tGP_BrushEditData *gso = op->customdata;
1723   GP_Sculpt_Data *gp_brush = gso->gp_brush;
1724   const int radius = ((gp_brush->flag & GP_SCULPT_FLAG_PRESSURE_RADIUS) ?
1725                           gso->gp_brush->size * gso->pressure :
1726                           gso->gp_brush->size);
1727   float mousef[2];
1728   int mouse[2];
1729   bool changed = false;
1730
1731   /* Get latest mouse coordinates */
1732   RNA_float_get_array(itemptr, "mouse", mousef);
1733   gso->mval[0] = mouse[0] = (int)(mousef[0]);
1734   gso->mval[1] = mouse[1] = (int)(mousef[1]);
1735
1736   gso->pressure = RNA_float_get(itemptr, "pressure");
1737
1738   if (RNA_boolean_get(itemptr, "pen_flip")) {
1739     gso->flag |= GP_SCULPT_FLAG_INVERT;
1740   }
1741   else {
1742     gso->flag &= ~GP_SCULPT_FLAG_INVERT;
1743   }
1744
1745   /* Store coordinates as reference, if operator just started running */
1746   if (gso->first) {
1747     gso->mval_prev[0] = gso->mval[0];
1748     gso->mval_prev[1] = gso->mval[1];
1749     gso->pressure_prev = gso->pressure;
1750   }
1751
1752   /* Update brush_rect, so that it represents the bounding rectangle of brush */
1753   gso->brush_rect.xmin = mouse[0] - radius;
1754   gso->brush_rect.ymin = mouse[1] - radius;
1755   gso->brush_rect.xmax = mouse[0] + radius;
1756   gso->brush_rect.ymax = mouse[1] + radius;
1757
1758   /* Apply brush */
1759   if (gso->brush_type == GP_SCULPT_TYPE_CLONE) {
1760     changed = gpsculpt_brush_apply_clone(C, gso);
1761   }
1762   else {
1763     changed = gpsculpt_brush_apply_standard(C, gso);
1764   }
1765
1766   /* Updates */
1767   if (changed) {
1768     DEG_id_tag_update(&gso->gpd->id, ID_RECALC_GEOMETRY);
1769     WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1770   }
1771
1772   /* Store values for next step */
1773   gso->mval_prev[0] = gso->mval[0];
1774   gso->mval_prev[1] = gso->mval[1];
1775   gso->pressure_prev = gso->pressure;
1776   gso->first = false;
1777 }
1778
1779 /* Running --------------------------------------------- */
1780
1781 /* helper - a record stroke, and apply paint event */
1782 static void gpsculpt_brush_apply_event(bContext *C, wmOperator *op, const wmEvent *event)
1783 {
1784   tGP_BrushEditData *gso = op->customdata;
1785   ToolSettings *ts = CTX_data_tool_settings(C);
1786   GP_Sculpt_Settings *gset = &ts->gp_sculpt;
1787   PointerRNA itemptr;
1788   float mouse[2];
1789   int tablet = 0;
1790
1791   mouse[0] = event->mval[0] + 1;
1792   mouse[1] = event->mval[1] + 1;
1793
1794   /* fill in stroke */
1795   RNA_collection_add(op->ptr, "stroke", &itemptr);
1796
1797   RNA_float_set_array(&itemptr, "mouse", mouse);
1798   RNA_boolean_set(&itemptr, "pen_flip", event->ctrl != false);
1799   RNA_boolean_set(&itemptr, "is_start", gso->first);
1800
1801   /* handle pressure sensitivity (which is supplied by tablets) */
1802   if (event->tablet_data) {
1803     const wmTabletData *wmtab = event->tablet_data;
1804     float pressure = wmtab->Pressure;
1805
1806     tablet = (wmtab->Active != EVT_TABLET_NONE);
1807
1808     /* special exception here for too high pressure values on first touch in
1809      * windows for some tablets: clamp the values to be sane
1810      */
1811     if (tablet && (pressure >= 0.99f)) {
1812       pressure = 1.0f;
1813     }
1814     RNA_float_set(&itemptr, "pressure", pressure);
1815   }
1816   else {
1817     RNA_float_set(&itemptr, "pressure", 1.0f);
1818   }
1819
1820   if (!gso->is_weight_mode) {
1821     if (event->shift) {
1822       gso->gp_brush_old = gso->gp_brush;
1823       gso->brush_type_old = gso->brush_type;
1824
1825       gso->gp_brush = &gset->brush[GP_SCULPT_TYPE_SMOOTH];
1826       gso->brush_type = GP_SCULPT_TYPE_SMOOTH;
1827     }
1828     else {
1829       if (gso->gp_brush_old != NULL) {
1830         gso->gp_brush = gso->gp_brush_old;
1831         gso->brush_type = gso->brush_type_old;
1832       }
1833     }
1834   }
1835
1836   /* apply */
1837   gpsculpt_brush_apply(C, op, &itemptr);
1838 }
1839
1840 /* reapply */
1841 static int gpsculpt_brush_exec(bContext *C, wmOperator *op)
1842 {
1843   if (!gpsculpt_brush_init(C, op)) {
1844     return OPERATOR_CANCELLED;
1845   }
1846
1847   RNA_BEGIN (op->ptr, itemptr, "stroke") {
1848     gpsculpt_brush_apply(C, op, &itemptr);
1849   }
1850   RNA_END;
1851
1852   gpsculpt_brush_exit(C, op);
1853
1854   return OPERATOR_FINISHED;
1855 }
1856
1857 /* start modal painting */
1858 static int gpsculpt_brush_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1859 {
1860   tGP_BrushEditData *gso = NULL;
1861   const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
1862   const bool is_playing = ED_screen_animation_playing(CTX_wm_manager(C)) != NULL;
1863   bool needs_timer = false;
1864   float brush_rate = 0.0f;
1865
1866   /* the operator cannot work while play animation */
1867   if (is_playing) {
1868     BKE_report(op->reports, RPT_ERROR, "Cannot sculpt while play animation");
1869
1870     return OPERATOR_CANCELLED;
1871   }
1872
1873   /* init painting data */
1874   if (!gpsculpt_brush_init(C, op)) {
1875     return OPERATOR_CANCELLED;
1876   }
1877
1878   gso = op->customdata;
1879
1880   /* initialise type-specific data (used for the entire session) */
1881   switch (gso->brush_type) {
1882     /* Brushes requiring timer... */
1883     case GP_SCULPT_TYPE_THICKNESS:
1884       brush_rate = 0.01f;  // XXX: hardcoded
1885       needs_timer = true;
1886       break;
1887
1888     case GP_SCULPT_TYPE_STRENGTH:
1889       brush_rate = 0.01f;  // XXX: hardcoded
1890       needs_timer = true;
1891       break;
1892
1893     case GP_SCULPT_TYPE_PINCH:
1894       brush_rate = 0.001f;  // XXX: hardcoded
1895       needs_timer = true;
1896       break;
1897
1898     case GP_SCULPT_TYPE_TWIST:
1899       brush_rate = 0.01f;  // XXX: hardcoded
1900       needs_timer = true;
1901       break;
1902
1903     default:
1904       break;
1905   }
1906
1907   /* register timer for increasing influence by hovering over an area */
1908   if (needs_timer) {
1909     gso->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, brush_rate);
1910   }
1911
1912   /* register modal handler */
1913   WM_event_add_modal_handler(C, op);
1914
1915   /* start drawing immediately? */
1916   if (is_modal == false) {
1917     ARegion *ar = CTX_wm_region(C);
1918
1919     /* ensure that we'll have a new frame to draw on */
1920     gpsculpt_brush_init_stroke(gso);
1921
1922     /* apply first dab... */
1923     gso->is_painting = true;
1924     gpsculpt_brush_apply_event(C, op, event);
1925
1926     /* redraw view with feedback */
1927     ED_region_tag_redraw(ar);
1928   }
1929
1930   return OPERATOR_RUNNING_MODAL;
1931 }
1932
1933 /* painting - handle events */
1934 static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *event)
1935 {
1936   tGP_BrushEditData *gso = op->customdata;
1937   const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
1938   bool redraw_region = false;
1939   bool redraw_toolsettings = false;
1940
1941   /* The operator can be in 2 states: Painting and Idling */
1942   if (gso->is_painting) {
1943     /* Painting  */
1944     switch (event->type) {
1945       /* Mouse Move = Apply somewhere else */
1946       case MOUSEMOVE:
1947       case INBETWEEN_MOUSEMOVE:
1948         /* apply brush effect at new position */
1949         gpsculpt_brush_apply_event(C, op, event);
1950
1951         /* force redraw, so that the cursor will at least be valid */
1952         redraw_region = true;
1953         break;
1954
1955       /* Timer Tick - Only if this was our own timer */
1956       case TIMER:
1957         if (event->customdata == gso->timer) {
1958           gso->timerTick = true;
1959           gpsculpt_brush_apply_event(C, op, event);
1960           gso->timerTick = false;
1961         }
1962         break;
1963
1964       /* Adjust brush settings */
1965       /* FIXME: Step increments and modifier keys are hardcoded here! */
1966       case WHEELUPMOUSE:
1967       case PADPLUSKEY:
1968         if (event->shift) {
1969           /* increase strength */
1970           gso->gp_brush->strength += 0.05f;
1971           CLAMP_MAX(gso->gp_brush->strength, 1.0f);
1972         }
1973         else {
1974           /* increase brush size */
1975           gso->gp_brush->size += 3;
1976           CLAMP_MAX(gso->gp_brush->size, 300);
1977         }
1978
1979         redraw_region = true;
1980         redraw_toolsettings = true;
1981         break;
1982
1983       case WHEELDOWNMOUSE:
1984       case PADMINUS:
1985         if (event->shift) {
1986           /* decrease strength */
1987           gso->gp_brush->strength -= 0.05f;
1988           CLAMP_MIN(gso->gp_brush->strength, 0.0f);
1989         }
1990         else {
1991           /* decrease brush size */
1992           gso->gp_brush->size -= 3;
1993           CLAMP_MIN(gso->gp_brush->size, 1);
1994         }
1995
1996         redraw_region = true;
1997         redraw_toolsettings = true;
1998         break;
1999
2000       /* Painting mbut release = Stop painting (back to idle) */
2001       case LEFTMOUSE:
2002         // BLI_assert(event->val == KM_RELEASE);
2003         if (is_modal) {
2004           /* go back to idling... */
2005           gso->is_painting = false;
2006         }
2007         else {
2008           /* end sculpt session, since we're not modal */
2009           gso->is_painting = false;
2010
2011           gpsculpt_brush_exit(C, op);
2012           return OPERATOR_FINISHED;
2013         }
2014         break;
2015
2016       /* Abort painting if any of the usual things are tried */
2017       case MIDDLEMOUSE:
2018       case RIGHTMOUSE:
2019       case ESCKEY:
2020         gpsculpt_brush_exit(C, op);
2021         return OPERATOR_FINISHED;
2022     }
2023   }
2024   else {
2025     /* Idling */
2026     BLI_assert(is_modal == true);
2027
2028     switch (event->type) {
2029       /* Painting mbut press = Start painting (switch to painting state) */
2030       case LEFTMOUSE:
2031         /* do initial "click" apply */
2032         gso->is_painting = true;
2033         gso->first = true;
2034
2035         gpsculpt_brush_init_stroke(gso);
2036         gpsculpt_brush_apply_event(C, op, event);
2037         break;
2038
2039       /* Exit modal operator, based on the "standard" ops */
2040       case RIGHTMOUSE:
2041       case ESCKEY:
2042         gpsculpt_brush_exit(C, op);
2043         return OPERATOR_FINISHED;
2044
2045       /* MMB is often used for view manipulations */
2046       case MIDDLEMOUSE:
2047         return OPERATOR_PASS_THROUGH;
2048
2049       /* Mouse movements should update the brush cursor - Just redraw the active region */
2050       case MOUSEMOVE:
2051       case INBETWEEN_MOUSEMOVE:
2052         redraw_region = true;
2053         break;
2054
2055       /* Adjust brush settings */
2056       /* FIXME: Step increments and modifier keys are hardcoded here! */
2057       case WHEELUPMOUSE:
2058       case PADPLUSKEY:
2059         if (event->shift) {
2060           /* increase strength */
2061           gso->gp_brush->strength += 0.05f;
2062           CLAMP_MAX(gso->gp_brush->strength, 1.0f);
2063         }
2064         else {
2065           /* increase brush size */
2066           gso->gp_brush->size += 3;
2067           CLAMP_MAX(gso->gp_brush->size, 300);
2068         }
2069
2070         redraw_region = true;
2071         redraw_toolsettings = true;
2072         break;
2073
2074       case WHEELDOWNMOUSE:
2075       case PADMINUS:
2076         if (event->shift) {
2077           /* decrease strength */
2078           gso->gp_brush->strength -= 0.05f;
2079           CLAMP_MIN(gso->gp_brush->strength, 0.0f);
2080         }
2081         else {
2082           /* decrease brush size */
2083           gso->gp_brush->size -= 3;
2084           CLAMP_MIN(gso->gp_brush->size, 1);
2085         }
2086
2087         redraw_region = true;
2088         redraw_toolsettings = true;
2089         break;
2090
2091       /* Change Frame - Allowed */
2092       case LEFTARROWKEY:
2093       case RIGHTARROWKEY:
2094       case UPARROWKEY:
2095       case DOWNARROWKEY:
2096         return OPERATOR_PASS_THROUGH;
2097
2098       /* Camera/View Gizmo's - Allowed */
2099       /* (See rationale in gpencil_paint.c -> gpencil_draw_modal()) */
2100       case PAD0:
2101       case PAD1:
2102       case PAD2:
2103       case PAD3:
2104       case PAD4:
2105       case PAD5:
2106       case PAD6:
2107       case PAD7:
2108       case PAD8:
2109       case PAD9:
2110         return OPERATOR_PASS_THROUGH;
2111
2112       /* Unhandled event */
2113       default:
2114         break;
2115     }
2116   }
2117
2118   /* Redraw region? */
2119   if (redraw_region) {
2120     ARegion *ar = CTX_wm_region(C);
2121     ED_region_tag_redraw(ar);
2122   }
2123
2124   /* Redraw toolsettings (brush settings)? */
2125   if (redraw_toolsettings) {
2126     DEG_id_tag_update(&gso->gpd->id, ID_RECALC_GEOMETRY);
2127     WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
2128   }
2129
2130   return OPERATOR_RUNNING_MODAL;
2131 }
2132
2133 /* Also used for weight paint. */
2134 void GPENCIL_OT_sculpt_paint(wmOperatorType *ot)
2135 {
2136   /* identifiers */
2137   ot->name = "Stroke Sculpt";
2138   ot->idname = "GPENCIL_OT_sculpt_paint";
2139   ot->description = "Apply tweaks to strokes by painting over the strokes";  // XXX
2140
2141   /* api callbacks */
2142   ot->exec = gpsculpt_brush_exec;
2143   ot->invoke = gpsculpt_brush_invoke;
2144   ot->modal = gpsculpt_brush_modal;
2145   ot->cancel = gpsculpt_brush_exit;
2146   ot->poll = gpsculpt_brush_poll;
2147
2148   /* flags */
2149   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
2150
2151   /* properties */
2152   PropertyRNA *prop;
2153   prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
2154   RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
2155
2156   prop = RNA_def_boolean(
2157       ot->srna,
2158       "wait_for_input",
2159       true,
2160       "Wait for Input",
2161       "Enter a mini 'sculpt-mode' if enabled, otherwise, exit after drawing a single stroke");
2162   RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
2163 }