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