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