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