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