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