Merge branch 'blender2.7'
[blender.git] / source / blender / editors / gpencil / gpencil_primitive.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2017, Blender Foundation
17  * This is a new part of Blender
18  * Operators for creating new Grease Pencil primitives (boxes, circles, ...)
19  */
20
21 /** \file
22  * \ingroup edgpencil
23  */
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <stddef.h>
29 #include <math.h>
30
31 #include "MEM_guardedalloc.h"
32
33 #include "BLI_blenlib.h"
34 #include "BLI_utildefines.h"
35 #include "BLI_math.h"
36 #include "BLI_rand.h"
37
38 #include "BLT_translation.h"
39
40 #include "PIL_time.h"
41
42 #include "DNA_brush_types.h"
43 #include "DNA_gpencil_types.h"
44 #include "DNA_meshdata_types.h"
45 #include "DNA_object_types.h"
46 #include "DNA_scene_types.h"
47 #include "DNA_screen_types.h"
48 #include "DNA_space_types.h"
49 #include "DNA_view3d_types.h"
50
51 #include "BKE_brush.h"
52 #include "BKE_colortools.h"
53 #include "BKE_context.h"
54 #include "BKE_deform.h"
55 #include "BKE_global.h"
56 #include "BKE_gpencil.h"
57 #include "BKE_main.h"
58 #include "BKE_material.h"
59 #include "BKE_paint.h"
60 #include "BKE_report.h"
61
62 #include "UI_interface.h"
63 #include "UI_resources.h"
64
65 #include "WM_api.h"
66 #include "WM_types.h"
67
68 #include "RNA_access.h"
69 #include "RNA_define.h"
70 #include "RNA_enum_types.h"
71
72 #include "ED_gpencil.h"
73 #include "ED_object.h"
74 #include "ED_screen.h"
75 #include "ED_view3d.h"
76 #include "ED_space_api.h"
77
78 #include "DEG_depsgraph.h"
79 #include "DEG_depsgraph_query.h"
80
81 #include "gpencil_intern.h"
82
83 #define MIN_EDGES 2
84 #define MAX_EDGES 128
85 #define MAX_CP 128
86
87 #define IDLE 0
88 #define IN_PROGRESS 1
89 #define IN_CURVE_EDIT 2
90 #define IN_MOVE 3
91 #define IN_BRUSH_SIZE 4
92 #define IN_BRUSH_STRENGTH 5
93
94 #define SELECT_NONE 0
95 #define SELECT_START 1
96 #define SELECT_CP1 2
97 #define SELECT_CP2 3
98 #define SELECT_END 4
99
100 #define BIG_SIZE_CTL    15
101 #define MID_SIZE_CTL    10
102 #define SMALL_SIZE_CTL   8
103
104 #define MOVE_NONE 0
105 #define MOVE_ENDS 1
106 #define MOVE_CP 2
107
108   /* ************************************************ */
109   /* Core/Shared Utilities */
110
111 /* clear the session buffers (call this before AND after a paint operation) */
112 static void gp_session_validatebuffer(tGPDprimitive *p)
113 {
114         bGPdata *gpd = p->gpd;
115
116         /* clear memory of buffer (or allocate it if starting a new session) */
117         if (gpd->runtime.sbuffer) {
118                 memset(gpd->runtime.sbuffer, 0, sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX);
119         }
120         else {
121                 gpd->runtime.sbuffer = MEM_callocN(sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer");
122         }
123
124         /* reset indices */
125         gpd->runtime.sbuffer_size = 0;
126
127         /* reset flags */
128         gpd->runtime.sbuffer_sflag = 0;
129         gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE;
130
131         if (ELEM(p->type, GP_STROKE_BOX, GP_STROKE_CIRCLE))
132                 gpd->runtime.sbuffer_sflag |= GP_STROKE_CYCLIC;
133 }
134
135 static void gp_init_colors(tGPDprimitive *p)
136 {
137         bGPdata *gpd = p->gpd;
138         Brush *brush = p->brush;
139
140         MaterialGPencilStyle *gp_style = NULL;
141
142         /* use brush material */
143         p->mat = BKE_gpencil_current_input_brush_material(p->bmain, p->ob, brush);
144
145         /* assign color information to temp data */
146         gp_style = p->mat->gp_style;
147         if (gp_style) {
148
149                 /* set colors */
150                 if (gp_style->flag & GP_STYLE_STROKE_SHOW) {
151                         copy_v4_v4(gpd->runtime.scolor, gp_style->stroke_rgba);
152                 }
153                 else {
154                         /* if no stroke, use fill */
155                         copy_v4_v4(gpd->runtime.scolor, gp_style->fill_rgba);
156                 }
157
158                 copy_v4_v4(gpd->runtime.sfill, gp_style->fill_rgba);
159                 /* add some alpha to make easy the filling without hide strokes */
160                 if (gpd->runtime.sfill[3] > 0.8f) {
161                         gpd->runtime.sfill[3] = 0.8f;
162                 }
163
164                 gpd->runtime.mode = (short)gp_style->mode;
165                 gpd->runtime.bstroke_style = gp_style->stroke_style;
166                 gpd->runtime.bfill_style = gp_style->fill_style;
167         }
168 }
169
170 /* Helper to square a primitive */
171 static void gpencil_primitive_to_square(tGPDprimitive *tgpi, const float x, const float y)
172 {
173         float w = fabsf(x);
174         float h = fabsf(y);
175         if ((x > 0 && y > 0) || (x < 0 && y < 0)) {
176                 if (w > h)
177                         tgpi->end[1] = tgpi->origin[1] + x;
178                 else
179                         tgpi->end[0] = tgpi->origin[0] + y;
180         }
181         else {
182                 if (w > h)
183                         tgpi->end[1] = tgpi->origin[1] - x;
184                 else
185                         tgpi->end[0] = tgpi->origin[0] - y;
186         }
187 }
188
189 /* Helper to rotate point around origin */
190 static void gp_rotate_v2_v2v2fl(float v[2], const float p[2], const float origin[2], const float angle)
191 {
192         float pt[2];
193         float r[2];
194         sub_v2_v2v2(pt, p, origin);
195         rotate_v2_v2fl(r, pt, angle);
196         add_v2_v2v2(v, r, origin);
197 }
198
199 /* Helper to rotate line around line centre */
200 static void gp_primitive_rotate_line(float va[2], float vb[2], const float a[2], const float b[2], const float angle)
201 {
202         float midpoint[2];
203         mid_v2_v2v2(midpoint, a, b);
204         gp_rotate_v2_v2v2fl(va, a, midpoint, angle);
205         gp_rotate_v2_v2v2fl(vb, b, midpoint, angle);
206 }
207
208 /* Helper to update cps */
209 static void gp_primitive_update_cps(tGPDprimitive *tgpi)
210 {
211         if (!tgpi->curve) {
212                 mid_v2_v2v2(tgpi->midpoint, tgpi->start, tgpi->end);
213                 copy_v2_v2(tgpi->cp1, tgpi->midpoint);
214                 copy_v2_v2(tgpi->cp2, tgpi->cp1);
215         }
216         else if (tgpi->type == GP_STROKE_CURVE) {
217                 mid_v2_v2v2(tgpi->midpoint, tgpi->start, tgpi->end);
218                 copy_v2_v2(tgpi->cp1, tgpi->midpoint);
219                 copy_v2_v2(tgpi->cp2, tgpi->cp1);
220         }
221         else if (tgpi->type == GP_STROKE_ARC) {
222                 if (tgpi->flip) {
223                         gp_primitive_rotate_line(tgpi->cp1, tgpi->cp2, tgpi->start, tgpi->end, M_PI_2);
224                 }
225                 else {
226                         gp_primitive_rotate_line(tgpi->cp1, tgpi->cp2, tgpi->end, tgpi->start, M_PI_2);
227                 }
228         }
229 }
230
231 /* Helper to reflect point */
232 static void UNUSED_FUNCTION(gp_reflect_point_v2_v2v2v2)(
233         float va[2], const float p[2], const float a[2], const float b[2])
234 {
235         float point[2];
236         closest_to_line_v2(point, p, a, b);
237         va[0] = point[0] - (p[0] - point[0]);
238         va[1] = point[1] - (p[1] - point[1]);
239 }
240
241   /* Poll callback for primitive operators */
242 static bool gpencil_primitive_add_poll(bContext *C)
243 {
244         /* only 3D view */
245         ScrArea *sa = CTX_wm_area(C);
246         if (sa && sa->spacetype != SPACE_VIEW3D) {
247                 return 0;
248         }
249
250         /* need data to create primitive */
251         bGPdata *gpd = CTX_data_gpencil_data(C);
252         if (gpd == NULL) {
253                 return 0;
254         }
255
256         /* only in edit and paint modes
257          * - paint as it's the "drawing/creation mode"
258          * - edit as this is more of an atomic editing operation
259          *   (similar to copy/paste), and also for consistency
260          */
261         if ((gpd->flag & (GP_DATA_STROKE_PAINTMODE | GP_DATA_STROKE_EDITMODE)) == 0) {
262                 CTX_wm_operator_poll_msg_set(C, "Primitives can only be added in Draw or Edit modes");
263                 return 0;
264         }
265
266         /* don't allow operator to function if the active layer is locked/hidden
267          * (BUT, if there isn't an active layer, we are free to add new layer when the time comes)
268          */
269         bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
270         if ((gpl) && (gpl->flag & (GP_LAYER_LOCKED | GP_LAYER_HIDE))) {
271                 CTX_wm_operator_poll_msg_set(C, "Primitives cannot be added as active layer is locked or hidden");
272                 return 0;
273         }
274
275         return 1;
276 }
277
278 /* Allocate memory to stroke, adds MAX_EDGES on every call */
279 static void gpencil_primitive_allocate_memory(tGPDprimitive *tgpi)
280 {
281         tgpi->point_count += (tgpi->type == GP_STROKE_BOX) ? (MAX_EDGES * 4 + 1) : (MAX_EDGES + 1);
282         bGPDstroke *gpsf = tgpi->gpf->strokes.first;
283         gpsf->points = MEM_reallocN(gpsf->points, sizeof(bGPDspoint) * tgpi->point_count);
284         if (gpsf->dvert != NULL)
285                 gpsf->dvert = MEM_reallocN(gpsf->dvert, sizeof(MDeformVert) * tgpi->point_count);
286         tgpi->points = MEM_reallocN(tgpi->points, sizeof(tGPspoint) * tgpi->point_count);
287 }
288
289 /* ****************** Primitive Interactive *********************** */
290
291 /* Helper: Create internal strokes primitives data */
292 static void gp_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi)
293 {
294         ToolSettings *ts = CTX_data_tool_settings(C);
295         Depsgraph *depsgraph = CTX_data_depsgraph(C);
296         int cfra_eval = (int)DEG_get_ctime(depsgraph);
297
298         bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
299
300         /* if brush doesn't exist, create a new one */
301         Paint *paint = &ts->gp_paint->paint;
302         /* if not exist, create a new one */
303         if (paint->brush == NULL) {
304                 /* create new brushes */
305                 BKE_brush_gpencil_presets(C);
306         }
307         tgpi->brush = paint->brush;
308
309         /* if layer doesn't exist, create a new one */
310         if (gpl == NULL) {
311                 gpl = BKE_gpencil_layer_addnew(tgpi->gpd, DATA_("Primitives"), true);
312         }
313         tgpi->gpl = gpl;
314
315         /* create a new temporary frame */
316         tgpi->gpf = MEM_callocN(sizeof(bGPDframe), "Temp bGPDframe");
317         tgpi->gpf->framenum = tgpi->cframe = cfra_eval;
318
319         /* create new temp stroke */
320         bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "Temp bGPDstroke");
321         gps->thickness = 2.0f;
322         gps->inittime = 0.0f;
323
324         /* enable recalculation flag by default */
325         gps->flag |= GP_STROKE_RECALC_GEOMETRY;
326         gps->flag &= ~GP_STROKE_SELECT;
327         /* the polygon must be closed, so enabled cyclic */
328         if (ELEM(tgpi->type, GP_STROKE_BOX, GP_STROKE_CIRCLE)) {
329                 gps->flag |= GP_STROKE_CYCLIC;
330         }
331
332         gps->flag |= GP_STROKE_3DSPACE;
333
334         gps->mat_nr = BKE_gpencil_get_material_index(tgpi->ob, tgpi->mat);
335
336         /* allocate memory for storage points, but keep empty */
337         gps->totpoints = 0;
338         gps->points = MEM_callocN(sizeof(bGPDspoint), "gp_stroke_points");
339         /* initialize triangle memory to dummy data */
340         gps->tot_triangles = 0;
341         gps->triangles = NULL;
342         gps->flag |= GP_STROKE_RECALC_GEOMETRY;
343
344         /* add to strokes */
345         BLI_addtail(&tgpi->gpf->strokes, gps);
346
347         /* allocate memory for storage points */
348         gpencil_primitive_allocate_memory(tgpi);
349
350         /* Random generator, only init once. */
351         uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
352         tgpi->rng = BLI_rng_new(rng_seed);
353 }
354
355 /* add new segment to curve */
356 static void gpencil_primitive_add_segment(tGPDprimitive *tgpi)
357 {
358         if (tgpi->tot_stored_edges > 0) {
359                 tgpi->tot_stored_edges += (tgpi->tot_edges - 1);
360         }
361         else {
362                 tgpi->tot_stored_edges += tgpi->tot_edges;
363         }
364         gpencil_primitive_allocate_memory(tgpi);
365 }
366
367 /* Helper: set control point */
368 static void gp_primitive_set_cp(tGPDprimitive *tgpi, float p[2], float color[4], int size)
369 {
370         if (tgpi->flag == IN_PROGRESS) {
371                 return;
372         }
373
374         bGPDcontrolpoint *cp_points = tgpi->gpd->runtime.cp_points;
375
376         if (tgpi->gpd->runtime.tot_cp_points < MAX_CP) {
377                 CLAMP(size, 5, 20);
378                 bGPDcontrolpoint *cp = &cp_points[tgpi->gpd->runtime.tot_cp_points];
379                 copy_v2_v2(&cp->x, p);
380                 copy_v4_v4(cp->color, color);
381                 color[3] = 0.8f;
382                 cp->size = size;
383                 tgpi->gpd->runtime.tot_cp_points += 1;
384         }
385 }
386
387 /* Helper: Draw status message while the user is running the operator */
388 static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi)
389 {
390         Scene *scene = tgpi->scene;
391         char status_str[UI_MAX_DRAW_STR];
392         char msg_str[UI_MAX_DRAW_STR];
393
394         if (tgpi->type == GP_STROKE_LINE) {
395                 BLI_strncpy(
396                         msg_str,
397                         IFACE_("Line: ESC to cancel, LMB set origin, Enter/MMB to confirm, WHEEL/+- to adjust subdivision number, Shift to align, Alt to center, E: extrude"),
398                         UI_MAX_DRAW_STR);
399         }
400         else if (tgpi->type == GP_STROKE_BOX) {
401                 BLI_strncpy(
402                         msg_str,
403                         IFACE_("Rectangle: ESC to cancel, LMB set origin, Enter/MMB to confirm, WHEEL/+- to adjust subdivision number, Shift to square, Alt to center"),
404                         UI_MAX_DRAW_STR);
405         }
406         else if (tgpi->type == GP_STROKE_CIRCLE) {
407                 BLI_strncpy(
408                         msg_str,
409                         IFACE_("Circle: ESC to cancel, Enter/MMB to confirm, WHEEL/+- to adjust edge number, Shift to square, Alt to center"),
410                         UI_MAX_DRAW_STR);
411         }
412         else if (tgpi->type == GP_STROKE_ARC) {
413                 BLI_strncpy(
414                         msg_str,
415                         IFACE_("Arc: ESC to cancel, Enter/MMB to confirm, WHEEL/+- to adjust edge number, Shift to square, Alt to center, M: Flip, E: extrude"),
416                         UI_MAX_DRAW_STR);
417         }
418         else if (tgpi->type == GP_STROKE_CURVE) {
419                 BLI_strncpy(
420                         msg_str,
421                         IFACE_("Curve: ESC to cancel, Enter/MMB to confirm, WHEEL/+- to adjust edge number, Shift to square, Alt to center, E: extrude"),
422                         UI_MAX_DRAW_STR);
423         }
424
425         if (ELEM(tgpi->type, GP_STROKE_CIRCLE, GP_STROKE_ARC, GP_STROKE_LINE, GP_STROKE_BOX)) {
426                 if (hasNumInput(&tgpi->num)) {
427                         char str_offs[NUM_STR_REP_LEN];
428
429                         outputNumInput(&tgpi->num, str_offs, &scene->unit);
430                         BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_offs);
431                 }
432                 else {
433                         if (tgpi->flag == IN_PROGRESS) {
434                                 BLI_snprintf(
435                                         status_str, sizeof(status_str), "%s: %d (%d, %d) (%d, %d)", msg_str, tgpi->tot_edges,
436                                         (int)tgpi->start[0], (int)tgpi->start[1], (int)tgpi->end[0], (int)tgpi->end[1]);
437                         }
438                         else {
439                                 BLI_snprintf(
440                                         status_str, sizeof(status_str), "%s: %d (%d, %d)", msg_str, tgpi->tot_edges,
441                                         (int)tgpi->end[0], (int)tgpi->end[1]);
442                         }
443                 }
444         }
445         else {
446                 if (tgpi->flag == IN_PROGRESS) {
447                         BLI_snprintf(
448                                 status_str, sizeof(status_str), "%s: %d (%d, %d) (%d, %d)", msg_str, tgpi->tot_edges,
449                                 (int)tgpi->start[0], (int)tgpi->start[1], (int)tgpi->end[0], (int)tgpi->end[1]);
450                 }
451                 else {
452                         BLI_snprintf(
453                                 status_str, sizeof(status_str), "%s: (%d, %d)", msg_str,
454                                 (int)tgpi->end[0], (int)tgpi->end[1]);
455                 }
456         }
457         ED_workspace_status_text(C, status_str);
458 }
459
460 /* create a rectangle */
461 static void gp_primitive_rectangle(tGPDprimitive *tgpi, tGPspoint *points2D)
462 {
463         float coords[5][2];
464
465         coords[0][0] = tgpi->start[0];
466         coords[0][1] = tgpi->start[1];
467         coords[1][0] = tgpi->end[0];
468         coords[1][1] = tgpi->start[1];
469         coords[2][0] = tgpi->end[0];
470         coords[2][1] = tgpi->end[1];
471         coords[3][0] = tgpi->start[0];
472         coords[3][1] = tgpi->end[1];
473         coords[4][0] = tgpi->start[0];
474         coords[4][1] = tgpi->start[1];
475
476         const float step = 1.0f / (float)(tgpi->tot_edges);
477         int i = tgpi->tot_stored_edges;
478
479         for (int j = 0; j < 4; j++) {
480                 float a = 0.0f;
481                 for (int k = 0; k < tgpi->tot_edges; k++) {
482                         tGPspoint *p2d = &points2D[i];
483                         interp_v2_v2v2(&p2d->x, coords[j], coords[j + 1], a);
484                         a += step;
485                         i++;
486                 }
487         }
488
489         mid_v2_v2v2(tgpi->midpoint, tgpi->start, tgpi->end);
490         float color[4];
491         UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
492         gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL);
493         if (tgpi->tot_stored_edges) {
494                 UI_GetThemeColor4fv(TH_REDALERT, color);
495                 gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL);
496         }
497         else {
498                 gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL);
499         }
500         UI_GetThemeColor4fv(TH_REDALERT, color);
501         gp_primitive_set_cp(tgpi, tgpi->midpoint, color, SMALL_SIZE_CTL);
502 }
503
504 /* create a line */
505 static void gp_primitive_line(tGPDprimitive *tgpi, tGPspoint *points2D)
506 {
507         const int totpoints = (tgpi->tot_edges + tgpi->tot_stored_edges);
508         const float step = 1.0f / (float)(tgpi->tot_edges - 1);
509         float a = tgpi->tot_stored_edges ? step : 0.0f;
510
511         for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
512                 tGPspoint *p2d = &points2D[i];
513                 interp_v2_v2v2(&p2d->x, tgpi->start, tgpi->end, a);
514                 a += step;
515         }
516
517         float color[4];
518         UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
519         gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL);
520         if (tgpi->tot_stored_edges) {
521                 UI_GetThemeColor4fv(TH_REDALERT, color);
522                 gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL);
523         }
524         else {
525                 gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL);
526         }
527 }
528
529 /* create an arc */
530 static void gp_primitive_arc(tGPDprimitive *tgpi, tGPspoint *points2D)
531 {
532         const int totpoints = (tgpi->tot_edges + tgpi->tot_stored_edges);
533         const float step = M_PI_2 / (float)(tgpi->tot_edges - 1);
534         float start[2];
535         float end[2];
536         float cp1[2];
537         float corner[2];
538         float midpoint[2];
539         float a = tgpi->tot_stored_edges ? step : 0.0f;
540
541         mid_v2_v2v2(tgpi->midpoint, tgpi->start, tgpi->end);
542         copy_v2_v2(start, tgpi->start);
543         copy_v2_v2(end, tgpi->end);
544         copy_v2_v2(cp1, tgpi->cp1);
545         copy_v2_v2(midpoint, tgpi->midpoint);
546
547         corner[0] = midpoint[0] - (cp1[0] - midpoint[0]);
548         corner[1] = midpoint[1] - (cp1[1] - midpoint[1]);
549
550         for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
551                 tGPspoint *p2d = &points2D[i];
552                 p2d->x = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a);
553                 p2d->y = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a);
554                 a += step;
555         }
556         float color[4];
557         UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
558         gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL);
559         if (tgpi->tot_stored_edges) {
560                 UI_GetThemeColor4fv(TH_REDALERT, color);
561                 gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL);
562         }
563         else {
564                 gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL);
565         }
566         UI_GetThemeColor4fv(TH_GIZMO_SECONDARY, color);
567         gp_primitive_set_cp(tgpi, tgpi->cp1, color, BIG_SIZE_CTL * 0.9f);
568 }
569
570 /* create a bezier */
571 static void gp_primitive_bezier(tGPDprimitive *tgpi, tGPspoint *points2D)
572 {
573         const int totpoints = (tgpi->tot_edges + tgpi->tot_stored_edges);
574         const float step = 1.0f / (float)(tgpi->tot_edges - 1);
575         float bcp1[2];
576         float bcp2[2];
577         float bcp3[2];
578         float bcp4[2];
579         float a = tgpi->tot_stored_edges ? step : 0.0f;
580
581         copy_v2_v2(bcp1, tgpi->start);
582         copy_v2_v2(bcp2, tgpi->cp1);
583         copy_v2_v2(bcp3, tgpi->cp2);
584         copy_v2_v2(bcp4, tgpi->end);
585
586         for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
587                 tGPspoint *p2d = &points2D[i];
588                 interp_v2_v2v2v2v2_cubic(&p2d->x, bcp1, bcp2, bcp3, bcp4, a);
589                 a += step;
590         }
591         float color[4];
592         UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
593         gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL);
594         if (tgpi->tot_stored_edges) {
595                 UI_GetThemeColor4fv(TH_REDALERT, color);
596                 gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL);
597         }
598         else {
599                 gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL);
600         }
601         UI_GetThemeColor4fv(TH_GIZMO_SECONDARY, color);
602         gp_primitive_set_cp(tgpi, tgpi->cp1, color, BIG_SIZE_CTL * 0.9f);
603         gp_primitive_set_cp(tgpi, tgpi->cp2, color, BIG_SIZE_CTL * 0.9f);
604 }
605
606 /* create a circle */
607 static void gp_primitive_circle(tGPDprimitive *tgpi, tGPspoint *points2D)
608 {
609         const int totpoints = (tgpi->tot_edges + tgpi->tot_stored_edges);
610         const float step = (2.0f * M_PI) / (float)(tgpi->tot_edges);
611         float center[2];
612         float radius[2];
613         float a = 0.0f;
614
615         center[0] = tgpi->start[0] + ((tgpi->end[0] - tgpi->start[0]) / 2.0f);
616         center[1] = tgpi->start[1] + ((tgpi->end[1] - tgpi->start[1]) / 2.0f);
617         radius[0] = fabsf(((tgpi->end[0] - tgpi->start[0]) / 2.0f));
618         radius[1] = fabsf(((tgpi->end[1] - tgpi->start[1]) / 2.0f));
619
620         for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
621                 tGPspoint *p2d = &points2D[i];
622                 p2d->x = (center[0] + cosf(a) * radius[0]);
623                 p2d->y = (center[1] + sinf(a) * radius[1]);
624                 a += step;
625         }
626         float color[4];
627         UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
628         gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL);
629         gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL);
630         UI_GetThemeColor4fv(TH_REDALERT, color);
631         gp_primitive_set_cp(tgpi, center, color, SMALL_SIZE_CTL);
632 }
633
634 /* Helper: Update shape of the stroke */
635 static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
636 {
637         ToolSettings *ts = tgpi->scene->toolsettings;
638         bGPdata *gpd = tgpi->gpd;
639         Brush *brush = tgpi->brush;
640         bGPDstroke *gps = tgpi->gpf->strokes.first;
641         GP_Sculpt_Settings *gset = &ts->gp_sculpt;
642         int depth_margin = (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0;
643         const char *align_flag = &ts->gpencil_v3d_align;
644         bool is_depth = (bool)(*align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE));
645         const bool is_camera = (bool)(ts->gp_sculpt.lock_axis == 0) &&
646                 (tgpi->rv3d->persp == RV3D_CAMOB) && (!is_depth);
647
648         if (tgpi->type == GP_STROKE_BOX)
649                 gps->totpoints = (tgpi->tot_edges * 4 + tgpi->tot_stored_edges);
650         else
651                 gps->totpoints = (tgpi->tot_edges + tgpi->tot_stored_edges);
652
653         if (tgpi->tot_stored_edges)
654                 gps->totpoints--;
655
656         tgpi->gpd->runtime.tot_cp_points = 0;
657
658         /* compute screen-space coordinates for points */
659         tGPspoint *points2D = tgpi->points;
660
661         if (tgpi->tot_edges > 1) {
662                 switch (tgpi->type) {
663                         case GP_STROKE_BOX:
664                                 gp_primitive_rectangle(tgpi, points2D);
665                                 break;
666                         case GP_STROKE_LINE:
667                                 gp_primitive_line(tgpi, points2D);
668                                 break;
669                         case GP_STROKE_CIRCLE:
670                                 gp_primitive_circle(tgpi, points2D);
671                                 break;
672                         case GP_STROKE_ARC:
673                                 gp_primitive_arc(tgpi, points2D);
674                                 break;
675                         case GP_STROKE_CURVE:
676                                 gp_primitive_bezier(tgpi, points2D);
677                         default:
678                                 break;
679                 }
680         }
681
682         /* convert screen-coordinates to 3D coordinates */
683         gp_session_validatebuffer(tgpi);
684         gp_init_colors(tgpi);
685         if (gset->flag & GP_SCULPT_SETT_FLAG_PRIMITIVE_CURVE) {
686                 curvemapping_initialize(ts->gp_sculpt.cur_primitive);
687         }
688         if (tgpi->brush->gpencil_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) {
689                 curvemapping_initialize(tgpi->brush->gpencil_settings->curve_jitter);
690         }
691         if (tgpi->brush->gpencil_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) {
692                 curvemapping_initialize(tgpi->brush->gpencil_settings->curve_strength);
693         }
694
695         /* get an array of depths, far depths are blended */
696         float *depth_arr = NULL;
697         if (is_depth) {
698                 int i;
699                 int mval_i[2], mval_prev[2] = { 0 };
700                 bool interp_depth = false;
701                 bool found_depth = false;
702
703                 /* need to restore the original projection settings before packing up */
704                 view3d_region_operator_needs_opengl(tgpi->win, tgpi->ar);
705                 ED_view3d_autodist_init(
706                         tgpi->depsgraph, tgpi->ar, tgpi->v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
707
708                 depth_arr = MEM_mallocN(sizeof(float) * gps->totpoints, "depth_points");
709                 tGPspoint *ptc = &points2D[0];
710                 for (i = 0; i < gps->totpoints; i++, ptc++) {
711                         round_v2i_v2fl(mval_i, &ptc->x);
712                         if ((ED_view3d_autodist_depth(
713                                      tgpi->ar, mval_i, depth_margin, depth_arr + i) == 0) &&
714                             (i && (ED_view3d_autodist_depth_seg(
715                                            tgpi->ar, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0)))
716                         {
717                                 interp_depth = true;
718                         }
719                         else {
720                                 found_depth = true;
721                         }
722                         copy_v2_v2_int(mval_prev, mval_i);
723                 }
724
725                 if (!found_depth) {
726                         for (i = 0; i < gps->totpoints; i++) {
727                                 depth_arr[i] = 0.9999f;
728                         }
729                 }
730                 else {
731                         /* if all depth are too high disable */
732                         bool valid_depth = false;
733                         for (i = 0; i < gps->totpoints; i++) {
734                                 if (depth_arr[i] < 0.9999f) {
735                                         valid_depth = true;
736                                         break;
737                                 }
738                         }
739                         if (!valid_depth) {
740                                 MEM_SAFE_FREE(depth_arr);
741                                 is_depth = false;
742                         }
743                         else {
744                                 if ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE_ENDPOINTS) ||
745                                     (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE_FIRST))
746                                 {
747                                         int first_valid = 0;
748                                         int last_valid = 0;
749
750                                         /* find first valid contact point */
751                                         for (i = 0; i < gps->totpoints; i++) {
752                                                 if (depth_arr[i] != FLT_MAX)
753                                                         break;
754                                         }
755                                         first_valid = i;
756
757                                         /* find last valid contact point */
758                                         if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE_FIRST) {
759                                                 last_valid = first_valid;
760                                         }
761                                         else {
762                                                 for (i = gps->totpoints - 1; i >= 0; i--) {
763                                                         if (depth_arr[i] != FLT_MAX)
764                                                                 break;
765                                                 }
766                                                 last_valid = i;
767                                         }
768
769                                         /* invalidate any other point, to interpolate between
770                                          * first and last contact in an imaginary line between them */
771                                         for (i = 0; i < gps->totpoints; i++) {
772                                                 if ((i != first_valid) && (i != last_valid)) {
773                                                         depth_arr[i] = FLT_MAX;
774                                                 }
775                                         }
776                                         interp_depth = true;
777                                 }
778
779                                 if (interp_depth) {
780                                         interp_sparse_array(depth_arr, gps->totpoints, FLT_MAX);
781                                 }
782                         }
783                 }
784         }
785
786         /* load stroke points and sbuffer */
787         for (int i = 0; i < gps->totpoints; i++) {
788                 bGPDspoint *pt = &gps->points[i];
789                 tGPspoint *p2d = &points2D[i];
790
791                 /* set rnd value for reuse */
792                 if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) && (p2d->rnd_dirty != true)) {
793                         p2d->rnd[0] = BLI_rng_get_float(tgpi->rng);
794                         p2d->rnd[1] = BLI_rng_get_float(tgpi->rng);
795                         p2d->rnd[2] = BLI_rng_get_float(tgpi->rng);
796                         p2d->rnd_dirty = true;
797                 }
798
799                 /* Copy points to buffer */
800                 tGPspoint *tpt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_size);
801
802                 /* Store original points */
803                 float tmp_xyp[2];
804                 copy_v2_v2(tmp_xyp, &p2d->x);
805
806                 /* calc pressure */
807                 float curve_pressure = 1.0;
808                 float pressure = 1.0;
809                 float strength = brush->gpencil_settings->draw_strength;
810
811                 /* normalize value to evaluate curve */
812                 if (gset->flag & GP_SCULPT_SETT_FLAG_PRIMITIVE_CURVE) {
813                         float value = (float)i / (gps->totpoints - 1);
814                         curve_pressure = curvemapping_evaluateF(gset->cur_primitive, 0, value);
815                         pressure = curve_pressure;
816                 }
817
818                 /* apply jitter to position */
819                 if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
820                     (brush->gpencil_settings->draw_jitter > 0.0f))
821                 {
822                         float jitter;
823
824                         if (brush->gpencil_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) {
825                                 jitter = curvemapping_evaluateF(brush->gpencil_settings->curve_jitter, 0, curve_pressure);
826                                 jitter *= brush->gpencil_settings->draw_sensitivity;
827                         }
828                         else {
829                                 jitter = brush->gpencil_settings->draw_jitter;
830                         }
831
832                         /* exponential value */
833                         const float exfactor = SQUARE(brush->gpencil_settings->draw_jitter + 2.0f);
834                         const float fac = p2d->rnd[0] * exfactor * jitter;
835
836                         /* vector */
837                         float mvec[2], svec[2];;
838                         if (i > 0) {
839                                 mvec[0] = (p2d->x - (p2d - 1)->x);
840                                 mvec[1] = (p2d->y - (p2d - 1)->y);
841                                 normalize_v2(mvec);
842                         }
843                         else {
844                                 zero_v2(mvec);
845                         }
846                         svec[0] = -mvec[1];
847                         svec[1] = mvec[0];
848
849                         if (p2d->rnd[1] > 0.5f) {
850                                 mul_v2_fl(svec, -fac);
851                         }
852                         else {
853                                 mul_v2_fl(svec, fac);
854                         }
855                         add_v2_v2(&p2d->x, svec);
856                 }
857
858                 /* apply randomness to pressure */
859                 if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
860                     (brush->gpencil_settings->draw_random_press > 0.0f))
861                 {
862                         if (p2d->rnd[0] > 0.5f) {
863                                 pressure -= brush->gpencil_settings->draw_random_press * p2d->rnd[1];
864                         }
865                         else {
866                                 pressure += brush->gpencil_settings->draw_random_press * p2d->rnd[2];
867                         }
868                 }
869
870                 /* color strength */
871                 if (brush->gpencil_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) {
872                         float curvef = curvemapping_evaluateF(brush->gpencil_settings->curve_strength, 0, curve_pressure);
873                         strength *= curvef * brush->gpencil_settings->draw_sensitivity;
874                         strength *= brush->gpencil_settings->draw_strength;
875                 }
876
877                 CLAMP(strength, GPENCIL_STRENGTH_MIN, 1.0f);
878
879                 /* apply randomness to color strength */
880                 if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
881                     (brush->gpencil_settings->draw_random_strength > 0.0f))
882                 {
883                         if (p2d->rnd[2] > 0.5f) {
884                                 strength -= strength * brush->gpencil_settings->draw_random_strength * p2d->rnd[0];
885                         }
886                         else {
887                                 strength += strength * brush->gpencil_settings->draw_random_strength * p2d->rnd[1];
888                         }
889                         CLAMP(strength, GPENCIL_STRENGTH_MIN, 1.0f);
890                 }
891
892                 copy_v2_v2(&tpt->x, &p2d->x);
893
894                 CLAMP_MIN(pressure, 0.1f);
895
896                 tpt->pressure = pressure;
897                 tpt->strength = strength;
898                 tpt->time = p2d->time;
899
900                 /* point uv */
901                 if (gpd->runtime.sbuffer_size > 0) {
902                         MaterialGPencilStyle *gp_style = tgpi->mat->gp_style;
903                         const float pixsize = gp_style->texture_pixsize / 1000000.0f;
904                         tGPspoint *tptb = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_size - 1;
905                         bGPDspoint spt, spt2;
906
907                         /* get origin to reproject point */
908                         float origin[3];
909                         ED_gp_get_drawing_reference(
910                                 tgpi->scene, tgpi->ob, tgpi->gpl,
911                                 ts->gpencil_v3d_align, origin);
912                         /* reproject current */
913                         ED_gpencil_tpoint_to_point(tgpi->ar, origin, tpt, &spt);
914                         ED_gp_project_point_to_plane(
915                                 tgpi->scene, tgpi->ob, tgpi->rv3d,
916                                 origin, tgpi->lock_axis - 1, &spt);
917
918                         /* reproject previous */
919                         ED_gpencil_tpoint_to_point(tgpi->ar, origin, tptb, &spt2);
920                         ED_gp_project_point_to_plane(
921                                 tgpi->scene, tgpi->ob, tgpi->rv3d,
922                                 origin, tgpi->lock_axis - 1, &spt2);
923                         tgpi->totpixlen += len_v3v3(&spt.x, &spt2.x) / pixsize;
924                         tpt->uv_fac = tgpi->totpixlen;
925                         if ((gp_style) && (gp_style->sima)) {
926                                 tpt->uv_fac /= gp_style->sima->gen_x;
927                         }
928                 }
929                 else {
930                         tgpi->totpixlen = 0.0f;
931                         tpt->uv_fac = 0.0f;
932                 }
933
934                 tpt->uv_rot = p2d->uv_rot;
935
936                 gpd->runtime.sbuffer_size++;
937
938                 /* add small offset to keep stroke over the surface */
939                 if ((depth_arr) && (gpd->zdepth_offset > 0.0f)) {
940                         depth_arr[i] *= (1.0f - gpd->zdepth_offset);
941                 }
942
943                 /* convert screen-coordinates to 3D coordinates */
944                 gp_stroke_convertcoords_tpoint(
945                         tgpi->scene, tgpi->ar, tgpi->ob, tgpi->gpl,
946                         p2d, depth_arr ? depth_arr + i : NULL,
947                         &pt->x);
948
949                 pt->pressure = pressure;
950                 pt->strength = strength;
951                 pt->time = 0.0f;
952                 pt->flag = 0;
953                 pt->uv_fac = tpt->uv_fac;
954
955                 if (gps->dvert != NULL) {
956                         MDeformVert *dvert = &gps->dvert[i];
957                         dvert->totweight = 0;
958                         dvert->dw = NULL;
959                 }
960
961                 /* Restore original points */
962                 copy_v2_v2(&p2d->x, tmp_xyp);
963         }
964
965         /* store cps and convert coords */
966         if (tgpi->gpd->runtime.tot_cp_points > 0) {
967                 bGPDcontrolpoint *cps = tgpi->gpd->runtime.cp_points;
968                 for (int i = 0; i < tgpi->gpd->runtime.tot_cp_points; i++) {
969                         bGPDcontrolpoint *cp = &cps[i];
970                         gp_stroke_convertcoords_tpoint(tgpi->scene, tgpi->ar, tgpi->ob, tgpi->gpl, (tGPspoint *)cp, NULL, &cp->x);
971                 }
972         }
973
974         /* reproject to plane */
975         if (!is_depth) {
976                 float origin[3];
977                 ED_gp_get_drawing_reference(
978                         tgpi->scene, tgpi->ob, tgpi->gpl,
979                         ts->gpencil_v3d_align, origin);
980                 ED_gp_project_stroke_to_plane(
981                         tgpi->scene, tgpi->ob, tgpi->rv3d, gps,
982                         origin, ts->gp_sculpt.lock_axis - 1);
983         }
984
985         /* if parented change position relative to parent object */
986         for (int i = 0; i < gps->totpoints; i++) {
987                 bGPDspoint *pt = &gps->points[i];
988                 gp_apply_parent_point(tgpi->depsgraph, tgpi->ob, tgpi->gpd, tgpi->gpl, pt);
989         }
990
991         /* if camera view, reproject flat to view to avoid perspective effect */
992         if (is_camera) {
993                 ED_gpencil_project_stroke_to_view(C, tgpi->gpl, gps);
994         }
995
996         /* force fill recalc */
997         gps->flag |= GP_STROKE_RECALC_GEOMETRY;
998
999         MEM_SAFE_FREE(depth_arr);
1000
1001         DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
1002         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
1003         WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
1004 }
1005
1006 /* Update screen and stroke */
1007 static void gpencil_primitive_update(bContext *C, wmOperator *op, tGPDprimitive *tgpi)
1008 {
1009         /* update indicator in header */
1010         gpencil_primitive_status_indicators(C, tgpi);
1011         /* apply... */
1012         tgpi->type = RNA_enum_get(op->ptr, "type");
1013         tgpi->tot_edges = RNA_int_get(op->ptr, "edges");
1014         /* update points position */
1015         gp_primitive_update_strokes(C, tgpi);
1016 }
1017
1018 static void gpencil_primitive_interaction_begin(tGPDprimitive *tgpi, const wmEvent *event)
1019 {
1020         copy_v2fl_v2i(tgpi->mval, event->mval);
1021         copy_v2_v2(tgpi->origin, tgpi->mval);
1022         copy_v2_v2(tgpi->start, tgpi->mval);
1023         copy_v2_v2(tgpi->end, tgpi->mval);
1024         copy_v2_v2(tgpi->cp1, tgpi->mval);
1025         copy_v2_v2(tgpi->cp2, tgpi->mval);
1026 }
1027
1028 /* Exit and free memory */
1029 static void gpencil_primitive_exit(bContext *C, wmOperator *op)
1030 {
1031         tGPDprimitive *tgpi = op->customdata;
1032         bGPdata *gpd = tgpi->gpd;
1033
1034         /* don't assume that operator data exists at all */
1035         if (tgpi) {
1036                 /* clear status message area */
1037                 ED_workspace_status_text(C, NULL);
1038
1039                 MEM_SAFE_FREE(tgpi->points);
1040                 tgpi->gpd->runtime.tot_cp_points = 0;
1041                 MEM_SAFE_FREE(tgpi->gpd->runtime.cp_points);
1042                 /* finally, free memory used by temp data */
1043                 BKE_gpencil_free_strokes(tgpi->gpf);
1044                 MEM_SAFE_FREE(tgpi->gpf);
1045
1046                 /* free random seed */
1047                 if (tgpi->rng != NULL) {
1048                         BLI_rng_free(tgpi->rng);
1049                 }
1050
1051                 MEM_freeN(tgpi);
1052         }
1053
1054         /* free stroke buffer */
1055         if ((gpd != NULL) && (gpd->runtime.sbuffer)) {
1056                 MEM_SAFE_FREE(gpd->runtime.sbuffer);
1057                 gpd->runtime.sbuffer = NULL;
1058
1059                 /* clear flags */
1060                 gpd->runtime.sbuffer_size = 0;
1061                 gpd->runtime.sbuffer_sflag = 0;
1062         }
1063
1064         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
1065         WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
1066
1067         /* clear pointer */
1068         op->customdata = NULL;
1069 }
1070
1071 /* Init new temporary primitive data */
1072 static void gpencil_primitive_init(bContext *C, wmOperator *op)
1073 {
1074         ToolSettings *ts = CTX_data_tool_settings(C);
1075         bGPdata *gpd = CTX_data_gpencil_data(C);
1076         Main *bmain = CTX_data_main(C);
1077         Scene *scene = CTX_data_scene(C);
1078         Depsgraph *depsgraph = CTX_data_depsgraph(C);
1079         int cfra_eval = (int)DEG_get_ctime(depsgraph);
1080
1081         /* create temporary operator data */
1082         tGPDprimitive *tgpi = MEM_callocN(sizeof(tGPDprimitive), "GPencil Primitive Data");
1083         op->customdata = tgpi;
1084
1085         tgpi->points = MEM_callocN(sizeof(tGPspoint), "gp primitive points2D");
1086
1087         /* set current scene and window info */
1088         tgpi->bmain = CTX_data_main(C);
1089         tgpi->scene = scene;
1090         tgpi->ob = CTX_data_active_object(C);
1091         tgpi->sa = CTX_wm_area(C);
1092         tgpi->ar = CTX_wm_region(C);
1093         tgpi->rv3d = tgpi->ar->regiondata;
1094         tgpi->v3d = tgpi->sa->spacedata.first;
1095         tgpi->depsgraph = CTX_data_depsgraph(C);
1096         tgpi->win = CTX_wm_window(C);
1097
1098         /* save original type */
1099         tgpi->orign_type = RNA_enum_get(op->ptr, "type");
1100
1101         /* set current frame number */
1102         tgpi->cframe = cfra_eval;
1103
1104         /* set GP datablock */
1105         tgpi->gpd = gpd;
1106         /* region where paint was originated */
1107         tgpi->gpd->runtime.ar = tgpi->ar;
1108
1109         /* control points */
1110         tgpi->gpd->runtime.cp_points = MEM_callocN(sizeof(bGPDcontrolpoint) * MAX_CP, "gp primitive cpoint");
1111         tgpi->gpd->runtime.tot_cp_points = 0;
1112
1113         /* getcolor info */
1114         tgpi->mat = BKE_gpencil_current_input_toolsettings_material(bmain, tgpi->ob, ts);
1115
1116         /* set parameters */
1117         tgpi->type = RNA_enum_get(op->ptr, "type");
1118
1119         if (ELEM(tgpi->type, GP_STROKE_ARC, GP_STROKE_CURVE)) {
1120                 tgpi->curve = true;
1121         }
1122         else {
1123                 tgpi->curve = false;
1124         }
1125
1126         /* set default edge count */
1127         switch (tgpi->type) {
1128                 case GP_STROKE_LINE:
1129                 {
1130                         RNA_int_set(op->ptr, "edges", 8);
1131                         break;
1132                 }
1133                 case GP_STROKE_BOX:
1134                 {
1135                         RNA_int_set(op->ptr, "edges", 8);
1136                         break;
1137                 }
1138                 case GP_STROKE_CIRCLE:
1139                 {
1140                         RNA_int_set(op->ptr, "edges", 96);
1141                         break;
1142                 }
1143                 default:
1144                 {
1145                         RNA_int_set(op->ptr, "edges", 64);
1146                         break;
1147                 }
1148         }
1149
1150         tgpi->tot_stored_edges = 0;
1151         tgpi->tot_edges = RNA_int_get(op->ptr, "edges");
1152         tgpi->flag = IDLE;
1153         tgpi->lock_axis = ts->gp_sculpt.lock_axis;
1154
1155         /* set temp layer, frame and stroke */
1156         gp_primitive_set_initdata(C, tgpi);
1157 }
1158
1159 /* Invoke handler: Initialize the operator */
1160 static int gpencil_primitive_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1161 {
1162         wmWindow *win = CTX_wm_window(C);
1163         bGPdata *gpd = CTX_data_gpencil_data(C);
1164         tGPDprimitive *tgpi = NULL;
1165
1166         /* initialize operator runtime data */
1167         gpencil_primitive_init(C, op);
1168         tgpi = op->customdata;
1169
1170         const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
1171         if (!is_modal) {
1172                 tgpi->flag = IN_PROGRESS;
1173                 gpencil_primitive_interaction_begin(tgpi, event);
1174         }
1175
1176         /* if in tools region, wait till we get to the main (3d-space)
1177          * region before allowing drawing to take place.
1178          */
1179         op->flag |= OP_IS_MODAL_CURSOR_REGION;
1180
1181         /* set cursor to indicate modal */
1182         WM_cursor_modal_set(win, BC_CROSSCURSOR);
1183
1184         /* update sindicator in header */
1185         gpencil_primitive_status_indicators(C, tgpi);
1186         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
1187         WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
1188
1189         /* add a modal handler for this operator */
1190         WM_event_add_modal_handler(C, op);
1191
1192         return OPERATOR_RUNNING_MODAL;
1193 }
1194
1195 /* Helper to complete a primitive */
1196 static void gpencil_primitive_interaction_end(bContext *C, wmOperator *op, wmWindow *win, tGPDprimitive *tgpi)
1197 {
1198         bGPDframe *gpf;
1199         bGPDstroke *gps;
1200
1201         ToolSettings *ts = tgpi->scene->toolsettings;
1202
1203         const int def_nr = tgpi->ob->actdef - 1;
1204         const bool have_weight = (bool)BLI_findlink(&tgpi->ob->defbase, def_nr);
1205
1206         /* return to normal cursor and header status */
1207         ED_workspace_status_text(C, NULL);
1208         WM_cursor_modal_restore(win);
1209
1210         /* insert keyframes as required... */
1211         short add_frame_mode;
1212         if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) {
1213                 add_frame_mode = GP_GETFRAME_ADD_COPY;
1214         }
1215         else {
1216                 add_frame_mode = GP_GETFRAME_ADD_NEW;
1217         }
1218
1219         gpf = BKE_gpencil_layer_getframe(tgpi->gpl, tgpi->cframe, add_frame_mode);
1220
1221         /* prepare stroke to get transferred */
1222         gps = tgpi->gpf->strokes.first;
1223         if (gps) {
1224                 gps->thickness = tgpi->brush->size;
1225                 gps->flag |= GP_STROKE_RECALC_GEOMETRY;
1226                 gps->tot_triangles = 0;
1227
1228                 /* calculate UVs along the stroke */
1229                 ED_gpencil_calc_stroke_uv(tgpi->ob, gps);
1230         }
1231
1232         /* transfer stroke from temporary buffer to the actual frame */
1233         if (ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) {
1234                 BLI_movelisttolist_reverse(&gpf->strokes, &tgpi->gpf->strokes);
1235         }
1236         else {
1237                 BLI_movelisttolist(&gpf->strokes, &tgpi->gpf->strokes);
1238         }
1239         BLI_assert(BLI_listbase_is_empty(&tgpi->gpf->strokes));
1240
1241         /* add weights if required */
1242         if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
1243                 BKE_gpencil_dvert_ensure(gps);
1244                 for (int i = 0; i < gps->totpoints; i++) {
1245                         MDeformVert *ve = &gps->dvert[i];
1246                         MDeformWeight *dw = defvert_verify_index(ve, def_nr);
1247                         if (dw) {
1248                                 dw->weight = ts->vgroup_weight;
1249                         }
1250                 }
1251         }
1252
1253         DEG_id_tag_update(&tgpi->gpd->id, ID_RECALC_COPY_ON_WRITE);
1254         DEG_id_tag_update(&tgpi->gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
1255
1256         /* clean up temp data */
1257         gpencil_primitive_exit(C, op);
1258 }
1259
1260 /* edit event handling */
1261 static void gpencil_primitive_edit_event_handling(bContext *C, wmOperator *op, wmWindow *win, const wmEvent *event, tGPDprimitive *tgpi)
1262 {
1263         /* calculate nearest point then set cursor */
1264         int move = MOVE_NONE;
1265         float a = len_v2v2(tgpi->mval, tgpi->start);
1266         float b = len_v2v2(tgpi->mval, tgpi->end);
1267
1268         float c = len_v2v2(tgpi->mval, tgpi->cp1);
1269         float d = len_v2v2(tgpi->mval, tgpi->cp2);
1270
1271         if (tgpi->flag == IN_CURVE_EDIT) {
1272                 if ((a < BIG_SIZE_CTL && tgpi->tot_stored_edges == 0) || b < BIG_SIZE_CTL) {
1273                         move = MOVE_ENDS;
1274                         WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
1275                 }
1276                 else if (tgpi->curve) {
1277                         move = MOVE_CP;
1278                         WM_cursor_modal_set(win, BC_HANDCURSOR);
1279                 }
1280                 else {
1281                         WM_cursor_modal_set(win, BC_CROSSCURSOR);
1282                 }
1283         }
1284         else if (tgpi->flag == IN_PROGRESS) {
1285                 WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
1286         }
1287
1288         switch (event->type) {
1289                 case MOUSEMOVE:
1290                 {
1291                         if ((event->val == KM_PRESS) && tgpi->sel_cp != SELECT_NONE) {
1292                                 if (tgpi->sel_cp == SELECT_START && tgpi->tot_stored_edges == 0) {
1293                                         copy_v2_v2(tgpi->start, tgpi->mval);
1294                                 }
1295                                 else if (tgpi->sel_cp == SELECT_END) {
1296                                         copy_v2_v2(tgpi->end, tgpi->mval);
1297                                 }
1298                                 else if (tgpi->sel_cp == SELECT_CP1 || (tgpi->sel_cp == SELECT_CP2 && tgpi->type != GP_STROKE_CURVE)) {
1299                                         float dx = (tgpi->mval[0] - tgpi->mvalo[0]);
1300                                         float dy = (tgpi->mval[1] - tgpi->mvalo[1]);
1301                                         tgpi->cp1[0] += dx;
1302                                         tgpi->cp1[1] += dy;
1303                                         if (event->shift)
1304                                                 copy_v2_v2(tgpi->cp2, tgpi->cp1);
1305                                 }
1306                                 else if (tgpi->sel_cp == SELECT_CP2) {
1307                                         float dx = (tgpi->mval[0] - tgpi->mvalo[0]);
1308                                         float dy = (tgpi->mval[1] - tgpi->mvalo[1]);
1309                                         tgpi->cp2[0] += dx;
1310                                         tgpi->cp2[1] += dy;
1311                                         if (event->shift)
1312                                                 copy_v2_v2(tgpi->cp1, tgpi->cp2);
1313                                 }
1314                                 /* update screen */
1315                                 gpencil_primitive_update(C, op, tgpi);
1316                         }
1317                         break;
1318                 }
1319                 case LEFTMOUSE:
1320                 {
1321                         if ((event->val == KM_PRESS)) {
1322                                 /* find nearest cp based on stroke end points */
1323                                 if (move == MOVE_ENDS)
1324                                         tgpi->sel_cp = (a < b) ? SELECT_START : SELECT_END;
1325                                 else if (move == MOVE_CP)
1326                                         tgpi->sel_cp = (c < d) ? SELECT_CP1 : SELECT_CP2;
1327                                 else
1328                                         tgpi->sel_cp = SELECT_NONE;
1329                                 break;
1330                         }
1331                         else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS)) {
1332                                 /* set control points and enter edit mode */
1333                                 tgpi->flag = IN_CURVE_EDIT;
1334                                 gp_primitive_update_cps(tgpi);
1335                                 gpencil_primitive_update(C, op, tgpi);
1336                         }
1337                         else {
1338                                 tgpi->sel_cp = SELECT_NONE;
1339                         }
1340                         break;
1341                 }
1342                 case MKEY:
1343                 {
1344                         if ((event->val == KM_PRESS) &&
1345                             (tgpi->curve) &&
1346                             (ELEM(tgpi->orign_type, GP_STROKE_ARC) ))
1347                         {
1348                                 tgpi->flip ^= 1;
1349                                 gp_primitive_update_cps(tgpi);
1350                                 gpencil_primitive_update(C, op, tgpi);
1351                         }
1352                         break;
1353                 }
1354                 case EKEY:
1355                 {
1356                         if (tgpi->flag == IN_CURVE_EDIT && !ELEM(tgpi->type, GP_STROKE_BOX, GP_STROKE_CIRCLE)) {
1357                                 tgpi->flag = IN_PROGRESS;
1358                                 WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
1359                                 gpencil_primitive_add_segment(tgpi);
1360                                 copy_v2_v2(tgpi->start, tgpi->end);
1361                                 copy_v2_v2(tgpi->origin, tgpi->start);
1362                                 gp_primitive_update_cps(tgpi);
1363                         }
1364                         break;
1365                 }
1366         }
1367 }
1368
1369 /* brush strength */
1370 static void gpencil_primitive_strength(tGPDprimitive *tgpi, bool reset)
1371 {
1372         Brush *brush = tgpi->brush;
1373         if (brush) {
1374                 if (reset) {
1375                         brush->gpencil_settings->draw_strength = tgpi->brush_strength;
1376                         tgpi->brush_strength = 0.0f;
1377                 }
1378                 else {
1379                         if (tgpi->brush_strength == 0.0f) {
1380                                 tgpi->brush_strength = brush->gpencil_settings->draw_strength;
1381                         }
1382                         float move[2];
1383                         sub_v2_v2v2(move, tgpi->mval, tgpi->mvalo);
1384                         float adjust = (move[1] > 0.0f) ? 0.01f : -0.01f;
1385                         brush->gpencil_settings->draw_strength += adjust * fabsf(len_manhattan_v2(move));
1386                 }
1387
1388                 /* limit low limit because below 0.2f the stroke is invisible */
1389                 CLAMP(brush->gpencil_settings->draw_strength, 0.2f, 1.0f);
1390         }
1391 }
1392
1393 /* brush size */
1394 static void gpencil_primitive_size(tGPDprimitive *tgpi, bool reset)
1395 {
1396         Brush *brush = tgpi->brush;
1397         if (brush) {
1398                 if (reset) {
1399                         brush->size = tgpi->brush_size;
1400                         tgpi->brush_size = 0;
1401                 }
1402                 else {
1403                         if (tgpi->brush_size == 0) {
1404                                 tgpi->brush_size = brush->size;
1405                         }
1406                         float move[2];
1407                         sub_v2_v2v2(move, tgpi->mval, tgpi->mvalo);
1408                         int adjust = (move[1] > 0.0f) ? 1 : -1;
1409                         brush->size += adjust * (int)fabsf(len_manhattan_v2(move));
1410                 }
1411                 CLAMP_MIN(brush->size, 1);
1412         }
1413 }
1414
1415 /* move */
1416 static void gpencil_primitive_move(tGPDprimitive *tgpi, bool reset)
1417 {
1418         float move[2];
1419         zero_v2(move);
1420
1421         if (reset) {
1422                 sub_v2_v2(move, tgpi->move);
1423                 zero_v2(tgpi->move);
1424         }
1425         else {
1426                 sub_v2_v2v2(move, tgpi->mval, tgpi->mvalo);
1427                 add_v2_v2(tgpi->move, move);
1428         }
1429
1430         bGPDstroke *gps = tgpi->gpf->strokes.first;
1431         tGPspoint *points2D = tgpi->points;
1432
1433         for (int i = 0; i < gps->totpoints; i++) {
1434                 tGPspoint *p2d = &points2D[i];
1435                 add_v2_v2(&p2d->x, move);
1436         }
1437
1438         add_v2_v2(tgpi->start, move);
1439         add_v2_v2(tgpi->end, move);
1440         add_v2_v2(tgpi->cp1, move);
1441         add_v2_v2(tgpi->cp2, move);
1442         add_v2_v2(tgpi->origin, move);
1443 }
1444
1445 /* Modal handler: Events handling during interactive part */
1446 static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *event)
1447 {
1448         tGPDprimitive *tgpi = op->customdata;
1449         wmWindow *win = CTX_wm_window(C);
1450         const bool has_numinput = hasNumInput(&tgpi->num);
1451
1452         copy_v2fl_v2i(tgpi->mval, event->mval);
1453
1454         if (tgpi->flag == IN_MOVE) {
1455
1456                 switch (event->type) {
1457                         case MOUSEMOVE:
1458                         {
1459                                 gpencil_primitive_move(tgpi, false);
1460                                 gpencil_primitive_update(C, op, tgpi);
1461                                 break;
1462                         }
1463                         case ESCKEY:
1464                         case LEFTMOUSE:
1465                         {
1466                                 zero_v2(tgpi->move);
1467                                 tgpi->flag = IN_CURVE_EDIT;
1468                                 break;
1469                         }
1470                         case RIGHTMOUSE:
1471                         {
1472                                 if (event->val == KM_RELEASE) {
1473                                         tgpi->flag = IN_CURVE_EDIT;
1474                                         gpencil_primitive_move(tgpi, true);
1475                                         gpencil_primitive_update(C, op, tgpi);
1476                                 }
1477                                 break;
1478                         }
1479                 }
1480                 copy_v2_v2(tgpi->mvalo, tgpi->mval);
1481                 return OPERATOR_RUNNING_MODAL;
1482         }
1483         else if (tgpi->flag == IN_BRUSH_SIZE) {
1484                 switch (event->type) {
1485                         case MOUSEMOVE:
1486                                 gpencil_primitive_size(tgpi, false);
1487                                 gpencil_primitive_update(C, op, tgpi);
1488                                 break;
1489                         case ESCKEY:
1490                         case MIDDLEMOUSE:
1491                         case LEFTMOUSE:
1492                                 tgpi->brush_size = 0;
1493                                 tgpi->flag = IN_CURVE_EDIT;
1494                                 break;
1495                         case RIGHTMOUSE:
1496                                 if (event->val == KM_RELEASE) {
1497                                         tgpi->flag = IN_CURVE_EDIT;
1498                                         gpencil_primitive_size(tgpi, true);
1499                                         gpencil_primitive_update(C, op, tgpi);
1500                                 }
1501                                 break;
1502                 }
1503                 copy_v2_v2(tgpi->mvalo, tgpi->mval);
1504                 return OPERATOR_RUNNING_MODAL;
1505         }
1506         else if (tgpi->flag == IN_BRUSH_STRENGTH) {
1507                 switch (event->type) {
1508                         case MOUSEMOVE:
1509                                 gpencil_primitive_strength(tgpi, false);
1510                                 gpencil_primitive_update(C, op, tgpi);
1511                                 break;
1512                         case ESCKEY:
1513                         case MIDDLEMOUSE:
1514                         case LEFTMOUSE:
1515                                 tgpi->brush_strength = 0.0f;
1516                                 tgpi->flag = IN_CURVE_EDIT;
1517                                 break;
1518                         case RIGHTMOUSE:
1519                                 if (event->val == KM_RELEASE) {
1520                                         tgpi->flag = IN_CURVE_EDIT;
1521                                         gpencil_primitive_strength(tgpi, true);
1522                                         gpencil_primitive_update(C, op, tgpi);
1523                                 }
1524                                 break;
1525                 }
1526                 copy_v2_v2(tgpi->mvalo, tgpi->mval);
1527                 return OPERATOR_RUNNING_MODAL;
1528         }
1529         else if (tgpi->flag != IDLE) {
1530                 gpencil_primitive_edit_event_handling(C, op, win, event, tgpi);
1531         }
1532
1533         switch (event->type) {
1534                 case LEFTMOUSE:
1535                 {
1536                         if ((event->val == KM_PRESS) && (tgpi->flag == IDLE)) {
1537                                 /* start drawing primitive */
1538                                 /* TODO: Ignore if not in main region yet */
1539                                 tgpi->flag = IN_PROGRESS;
1540                                 gpencil_primitive_interaction_begin(tgpi, event);
1541                         }
1542                         else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_MOVE)) {
1543                                 tgpi->flag = IN_CURVE_EDIT;
1544                         }
1545                         else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS)) {
1546                                 /* set control points and enter edit mode */
1547                                 tgpi->flag = IN_CURVE_EDIT;
1548                                 gp_primitive_update_cps(tgpi);
1549                                 gpencil_primitive_update(C, op, tgpi);
1550                         }
1551                         else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS) && (tgpi->type != GP_STROKE_CURVE)) {
1552                                 /* stop drawing primitive */
1553                                 tgpi->flag = IDLE;
1554                                 gpencil_primitive_interaction_end(C, op, win, tgpi);
1555                                 /* done! */
1556                                 return OPERATOR_FINISHED;
1557                         }
1558                         else {
1559                                 if (G.debug & G_DEBUG) {
1560                                         printf("GP Add Primitive Modal: LEFTMOUSE %d, Status = %d\n", event->val, tgpi->flag);
1561                                 }
1562                         }
1563                         break;
1564                 }
1565                 case SPACEKEY:  /* confirm */
1566                 case MIDDLEMOUSE:
1567                 case RETKEY:
1568                 {
1569                         tgpi->flag = IDLE;
1570                         gpencil_primitive_interaction_end(C, op, win, tgpi);
1571                         /* done! */
1572                         return OPERATOR_FINISHED;
1573                 }
1574                 case RIGHTMOUSE:
1575                 {
1576                         /* exception to cancel current stroke when we have previous strokes in buffer */
1577                         if (tgpi->tot_stored_edges > 0) {
1578                                 tgpi->flag = IDLE;
1579                                 tgpi->tot_edges = 0;
1580                                 gp_primitive_update_strokes(C, tgpi);
1581                                 gpencil_primitive_interaction_end(C, op, win, tgpi);
1582                                 /* done! */
1583                                 return OPERATOR_FINISHED;
1584                         }
1585                         ATTR_FALLTHROUGH;
1586                 }
1587                 case ESCKEY:
1588                 {
1589                         /* return to normal cursor and header status */
1590                         ED_workspace_status_text(C, NULL);
1591                         WM_cursor_modal_restore(win);
1592
1593                         /* clean up temp data */
1594                         gpencil_primitive_exit(C, op);
1595
1596                         /* canceled! */
1597                         return OPERATOR_CANCELLED;
1598                 }
1599                 case PADPLUSKEY:
1600                 case WHEELUPMOUSE:
1601                 {
1602                         if ((event->val != KM_RELEASE)) {
1603                                 tgpi->tot_edges = tgpi->tot_edges + 1;
1604                                 CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
1605                                 RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
1606
1607                                 /* update screen */
1608                                 gpencil_primitive_update(C, op, tgpi);
1609                         }
1610                         break;
1611                 }
1612                 case PADMINUS:
1613                 case WHEELDOWNMOUSE:
1614                 {
1615                         if ((event->val != KM_RELEASE)) {
1616                                 tgpi->tot_edges = tgpi->tot_edges - 1;
1617                                 CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
1618                                 RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
1619
1620                                 /* update screen */
1621                                 gpencil_primitive_update(C, op, tgpi);
1622                         }
1623                         break;
1624                 }
1625                 case GKEY: /* grab mode */
1626                 {
1627                         if ((event->val == KM_PRESS)) {
1628                                 tgpi->flag = IN_MOVE;
1629                                 WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
1630                         }
1631                         break;
1632                 }
1633                 case FKEY: /* brush thickness/ brush strength */
1634                 {
1635                         if ((event->val == KM_PRESS)) {
1636                                 if (event->shift) {
1637                                         tgpi->flag = IN_BRUSH_STRENGTH;
1638                                 }
1639                                 else {
1640                                         tgpi->flag = IN_BRUSH_SIZE;
1641                                 }
1642                                 WM_cursor_modal_set(win, BC_NS_SCROLLCURSOR);
1643                         }
1644                         break;
1645                 }
1646                 case CKEY: /* curve mode */
1647                 {
1648                         if ((event->val == KM_PRESS) &&
1649                             (tgpi->orign_type == GP_STROKE_CURVE))
1650                         {
1651                                 switch (tgpi->type) {
1652                                         case GP_STROKE_CURVE:
1653                                                 tgpi->type = GP_STROKE_ARC;
1654                                                 break;
1655                                         default:
1656                                         case GP_STROKE_ARC:
1657                                                 tgpi->type = GP_STROKE_CURVE;
1658                                                 break;
1659                                 }
1660
1661                                 RNA_enum_set(op->ptr, "type", tgpi->type);
1662                                 gp_primitive_update_cps(tgpi);
1663                                 gpencil_primitive_update(C, op, tgpi);
1664                         }
1665                         break;
1666                 }
1667                 case TABKEY:
1668                 {
1669                         if (tgpi->flag == IN_CURVE_EDIT) {
1670                                 tgpi->flag = IN_PROGRESS;
1671                                 WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
1672                                 gp_primitive_update_cps(tgpi);
1673                                 gpencil_primitive_update(C, op, tgpi);
1674                         }
1675                         break;
1676                 }
1677                 case MOUSEMOVE: /* calculate new position */
1678                 {
1679                         if (tgpi->flag == IN_CURVE_EDIT) {
1680                                 break;
1681                         }
1682                         /* only handle mousemove if not doing numinput */
1683                         if (has_numinput == false) {
1684                                 /* update position of mouse */
1685                                 copy_v2_v2(tgpi->end, tgpi->mval);
1686                                 copy_v2_v2(tgpi->start, tgpi->origin);
1687                                 if (tgpi->flag == IDLE) {
1688                                         copy_v2_v2(tgpi->origin, tgpi->mval);
1689                                 }
1690                                 /* Keep square if shift key */
1691                                 if (event->shift) {
1692                                         float x = tgpi->end[0] - tgpi->origin[0];
1693                                         float y = tgpi->end[1] - tgpi->origin[1];
1694                                         if (tgpi->type == GP_STROKE_LINE || tgpi->curve) {
1695                                                 float angle = fabsf(atan2f(y, x));
1696                                                 if (angle < 0.4f || angle > (M_PI - 0.4f)) {
1697                                                         tgpi->end[1] = tgpi->origin[1];
1698                                                 }
1699                                                 else if (angle > (M_PI_2 - 0.4f) && angle < (M_PI_2 + 0.4f)) {
1700                                                         tgpi->end[0] = tgpi->origin[0];
1701                                                 }
1702                                                 else {
1703                                                         gpencil_primitive_to_square(tgpi, x, y);
1704                                                 }
1705                                         }
1706                                         else {
1707                                                 gpencil_primitive_to_square(tgpi, x, y);
1708                                         }
1709                                 }
1710                                 /* Center primitive if alt key */
1711                                 if (event->alt) {
1712                                         tgpi->start[0] = tgpi->origin[0] - (tgpi->end[0] - tgpi->origin[0]);
1713                                         tgpi->start[1] = tgpi->origin[1] - (tgpi->end[1] - tgpi->origin[1]);
1714                                 }
1715                                 gp_primitive_update_cps(tgpi);
1716                                 /* update screen */
1717                                 gpencil_primitive_update(C, op, tgpi);
1718                         }
1719                         break;
1720                 }
1721                 default:
1722                 {
1723                         if (tgpi->flag != IN_CURVE_EDIT && (event->val == KM_PRESS) && handleNumInput(C, &tgpi->num, event)) {
1724                                 float value;
1725
1726                                 /* Grab data from numeric input, and store this new value (the user see an int) */
1727                                 value = tgpi->tot_edges;
1728                                 applyNumInput(&tgpi->num, &value);
1729                                 tgpi->tot_edges = value;
1730
1731                                 CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
1732                                 RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
1733
1734                                 /* update screen */
1735                                 gpencil_primitive_update(C, op, tgpi);
1736
1737                                 break;
1738                         }
1739                         else {
1740                                 /* unhandled event - allow to pass through */
1741                                 return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
1742                         }
1743                 }
1744         }
1745
1746         copy_v2_v2(tgpi->mvalo, tgpi->mval);
1747         /* still running... */
1748         return OPERATOR_RUNNING_MODAL;
1749 }
1750
1751 /* Cancel handler */
1752 static void gpencil_primitive_cancel(bContext *C, wmOperator *op)
1753 {
1754         /* this is just a wrapper around exit() */
1755         gpencil_primitive_exit(C, op);
1756 }
1757
1758 void GPENCIL_OT_primitive(wmOperatorType *ot)
1759 {
1760         static EnumPropertyItem primitive_type[] = {
1761                 {GP_STROKE_BOX, "BOX", 0, "Box", ""},
1762                 {GP_STROKE_LINE, "LINE", 0, "Line", ""},
1763                 {GP_STROKE_CIRCLE, "CIRCLE", 0, "Circle", ""},
1764                 {GP_STROKE_ARC, "ARC", 0, "Arc", ""},
1765                 {GP_STROKE_CURVE, "CURVE", 0, "Curve", ""},
1766                 {0, NULL, 0, NULL, NULL},
1767         };
1768
1769         /* identifiers */
1770         ot->name = "Grease Pencil Shapes";
1771         ot->idname = "GPENCIL_OT_primitive";
1772         ot->description = "Create predefined grease pencil stroke shapes";
1773
1774         /* callbacks */
1775         ot->invoke = gpencil_primitive_invoke;
1776         ot->modal = gpencil_primitive_modal;
1777         ot->cancel = gpencil_primitive_cancel;
1778         ot->poll = gpencil_primitive_add_poll;
1779
1780         /* flags */
1781         ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
1782
1783         /* properties */
1784         PropertyRNA *prop;
1785
1786         prop = RNA_def_int(ot->srna, "edges", 4, MIN_EDGES, MAX_EDGES, "Edges", "Number of polygon edges", MIN_EDGES, MAX_EDGES);
1787         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1788
1789         RNA_def_enum(ot->srna, "type", primitive_type, GP_STROKE_BOX, "Type", "Type of shape");
1790
1791         prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
1792         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1793 }