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