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