Cleanup: unused args
[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
45 #include "BLT_translation.h"
46
47 #include "DNA_brush_types.h"
48 #include "DNA_gpencil_types.h"
49 #include "DNA_meshdata_types.h"
50 #include "DNA_object_types.h"
51 #include "DNA_scene_types.h"
52 #include "DNA_screen_types.h"
53 #include "DNA_space_types.h"
54 #include "DNA_view3d_types.h"
55
56 #include "BKE_brush.h"
57 #include "BKE_context.h"
58 #include "BKE_deform.h"
59 #include "BKE_global.h"
60 #include "BKE_gpencil.h"
61 #include "BKE_main.h"
62 #include "BKE_material.h"
63 #include "BKE_paint.h"
64 #include "BKE_report.h"
65
66 #include "UI_interface.h"
67
68 #include "WM_api.h"
69 #include "WM_types.h"
70
71 #include "RNA_access.h"
72 #include "RNA_define.h"
73 #include "RNA_enum_types.h"
74
75 #include "ED_gpencil.h"
76 #include "ED_object.h"
77 #include "ED_screen.h"
78 #include "ED_view3d.h"
79 #include "ED_space_api.h"
80
81 #include "DEG_depsgraph.h"
82 #include "DEG_depsgraph_query.h"
83
84 #include "gpencil_intern.h"
85
86 #define MIN_EDGES 2
87 #define MAX_EDGES 128
88
89 #define IDLE 0
90 #define IN_PROGRESS 1
91
92   /* ************************************************ */
93   /* Core/Shared Utilities */
94
95   /* Poll callback for primitive operators */
96 static bool gpencil_primitive_add_poll(bContext *C)
97 {
98         /* only 3D view */
99         ScrArea *sa = CTX_wm_area(C);
100         if (sa && sa->spacetype != SPACE_VIEW3D) {
101                 return 0;
102         }
103
104         /* need data to create primitive */
105         bGPdata *gpd = CTX_data_gpencil_data(C);
106         if (gpd == NULL) {
107                 return 0;
108         }
109
110         /* only in edit and paint modes
111          * - paint as it's the "drawing/creation mode"
112          * - edit as this is more of an atomic editing operation
113          *   (similar to copy/paste), and also for consistency
114          */
115         if ((gpd->flag & (GP_DATA_STROKE_PAINTMODE | GP_DATA_STROKE_EDITMODE)) == 0) {
116                 CTX_wm_operator_poll_msg_set(C, "Primitives can only be added in Draw or Edit modes");
117                 return 0;
118         }
119
120         /* don't allow operator to function if the active layer is locked/hidden
121          * (BUT, if there isn't an active layer, we are free to add new layer when the time comes)
122          */
123         bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
124         if ((gpl) && (gpl->flag & (GP_LAYER_LOCKED | GP_LAYER_HIDE))) {
125                 CTX_wm_operator_poll_msg_set(C, "Primitives cannot be added as active layer is locked or hidden");
126                 return 0;
127         }
128
129         return 1;
130 }
131
132
133 /* ****************** Primitive Interactive *********************** */
134
135 /* Helper: Create internal strokes primitives data */
136 static void gp_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi)
137 {
138         ToolSettings *ts = CTX_data_tool_settings(C);
139         Depsgraph *depsgraph = CTX_data_depsgraph(C);
140         int cfra_eval = (int)DEG_get_ctime(depsgraph);
141
142         bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
143
144         /* if brush doesn't exist, create a new one */
145         Paint *paint = &ts->gp_paint->paint;
146         /* if not exist, create a new one */
147         if (paint->brush == NULL) {
148                 /* create new brushes */
149                 BKE_brush_gpencil_presets(C);
150         }
151         tgpi->brush = paint->brush;
152
153         /* if layer doesn't exist, create a new one */
154         if (gpl == NULL) {
155                 gpl = BKE_gpencil_layer_addnew(tgpi->gpd, DATA_("Primitives"), true);
156         }
157         tgpi->gpl = gpl;
158
159         /* create a new temporary frame */
160         tgpi->gpf = MEM_callocN(sizeof(bGPDframe), "Temp bGPDframe");
161         tgpi->gpf->framenum = tgpi->cframe = cfra_eval;
162
163         /* create new temp stroke */
164         bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "Temp bGPDstroke");
165         gps->thickness = 2.0f;
166         gps->inittime = 0.0f;
167
168         /* enable recalculation flag by default */
169         gps->flag |= GP_STROKE_RECALC_CACHES;
170         /* the polygon must be closed, so enabled cyclic */
171         if (tgpi->type != GP_STROKE_LINE && tgpi->type != GP_STROKE_ARC) {
172                 gps->flag |= GP_STROKE_CYCLIC;
173         }
174         else {
175                 gps->flag &= ~GP_STROKE_CYCLIC;
176         }
177         gps->flag |= GP_STROKE_3DSPACE;
178
179         gps->mat_nr = BKE_gpencil_get_material_index(tgpi->ob, tgpi->mat) - 1;
180
181         /* allocate memory for storage points, but keep empty */
182         gps->totpoints = 0;
183         gps->points = MEM_callocN(sizeof(bGPDspoint), "gp_stroke_points");
184         /* initialize triangle memory to dummy data */
185         gps->tot_triangles = 0;
186         gps->triangles = NULL;
187         gps->flag |= GP_STROKE_RECALC_CACHES;
188
189         /* add to strokes */
190         BLI_addtail(&tgpi->gpf->strokes, gps);
191 }
192
193 /* ----------------------- */
194 /* Drawing Callbacks */
195
196 /* Drawing callback for modal operator in 3d mode */
197 static void gpencil_primitive_draw_3d(const bContext *C, ARegion *UNUSED(ar), void *arg)
198 {
199         tGPDprimitive *tgpi = (tGPDprimitive *)arg;
200         ED_gp_draw_primitives(C, tgpi, REGION_DRAW_POST_VIEW);
201 }
202
203 /* ----------------------- */
204
205 /* Helper: Draw status message while the user is running the operator */
206 static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi)
207 {
208         Scene *scene = tgpi->scene;
209         char status_str[UI_MAX_DRAW_STR];
210         char msg_str[UI_MAX_DRAW_STR];
211
212         if (tgpi->type == GP_STROKE_BOX) {
213                 BLI_strncpy(msg_str, IFACE_("Rectangle: ESC/RMB to cancel, LMB set origin, Enter/LMB to confirm, Shift to square, Alt to center"), UI_MAX_DRAW_STR);
214         }
215         else if (tgpi->type == GP_STROKE_LINE) {
216                 BLI_strncpy(msg_str, IFACE_("Line: ESC/RMB to cancel, LMB set origin, Enter/LMB to confirm, Alt to center"), UI_MAX_DRAW_STR);
217         }
218         else if (tgpi->type == GP_STROKE_ARC) {
219                 BLI_strncpy(msg_str, IFACE_("Arc: ESC/RMB to cancel, Enter/LMB to confirm, WHEEL/+- to adjust edge number, Shift to square, Alt to center, F to flip, C to Close"), UI_MAX_DRAW_STR);
220         }
221         else {
222                 BLI_strncpy(msg_str, IFACE_("Circle: ESC/RMB to cancel, Enter/LMB to confirm, WHEEL/+- to adjust edge number, Shift to square, Alt to center"), UI_MAX_DRAW_STR);
223         }
224
225         if (tgpi->type == GP_STROKE_CIRCLE || tgpi->type == GP_STROKE_ARC) {
226                 if (hasNumInput(&tgpi->num)) {
227                         char str_offs[NUM_STR_REP_LEN];
228
229                         outputNumInput(&tgpi->num, str_offs, &scene->unit);
230                         BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_offs);
231                 }
232                 else {
233                         if (tgpi->flag == IN_PROGRESS) {
234                                 BLI_snprintf(
235                                         status_str, sizeof(status_str), "%s: %d (%d, %d) (%d, %d)", msg_str, (int)tgpi->tot_edges,
236                                         tgpi->top[0], tgpi->top[1], tgpi->bottom[0], tgpi->bottom[1]);
237                         }
238                         else {
239                                 BLI_snprintf(
240                                         status_str, sizeof(status_str), "%s: %d (%d, %d)", msg_str, (int)tgpi->tot_edges,
241                                         tgpi->bottom[0], tgpi->bottom[1]);
242                         }
243                 }
244         }
245         else {
246                 if (tgpi->flag == IN_PROGRESS) {
247                         BLI_snprintf(
248                                 status_str, sizeof(status_str), "%s: (%d, %d) (%d, %d)", msg_str,
249                                 tgpi->top[0], tgpi->top[1], tgpi->bottom[0], tgpi->bottom[1]);
250                 }
251                 else {
252                         BLI_snprintf(
253                                 status_str, sizeof(status_str), "%s: (%d, %d)", msg_str,
254                                 tgpi->bottom[0], tgpi->bottom[1]);
255                 }
256         }
257         ED_workspace_status_text(C, status_str);
258 }
259
260 /* ----------------------- */
261
262 /* create a rectangle */
263 static void gp_primitive_rectangle(tGPDprimitive *tgpi, tGPspoint *points2D)
264 {
265         BLI_assert(tgpi->tot_edges == 4);
266
267         points2D[0].x = tgpi->top[0];
268         points2D[0].y = tgpi->top[1];
269
270         points2D[1].x = tgpi->bottom[0];
271         points2D[1].y = tgpi->top[1];
272
273         points2D[2].x = tgpi->bottom[0];
274         points2D[2].y = tgpi->bottom[1];
275
276         points2D[3].x = tgpi->top[0];
277         points2D[3].y = tgpi->bottom[1];
278 }
279
280 /* create a line */
281 static void gp_primitive_line(tGPDprimitive *tgpi, tGPspoint *points2D)
282 {
283         BLI_assert(tgpi->tot_edges == 2);
284
285         points2D[0].x = tgpi->top[0];
286         points2D[0].y = tgpi->top[1];
287
288         points2D[1].x = tgpi->bottom[0];
289         points2D[1].y = tgpi->bottom[1];
290 }
291
292 /* create an arc */
293 static void gp_primitive_arc(tGPDprimitive *tgpi, tGPspoint *points2D)
294 {
295         const int totpoints = tgpi->tot_edges;
296         const float step = M_PI_2 / (float)(totpoints - 1);
297         float length[2];
298         int start[2];
299         int end[2];
300         float a = 0.0f;
301
302         start[0] = tgpi->top[0];
303         start[1] = tgpi->top[1];
304         end[0] = tgpi->bottom[0];
305         end[1] = tgpi->bottom[1];
306
307         if (tgpi->flip) {
308                 SWAP(int, end[0], start[0]);
309                 SWAP(int, end[1], start[1]);
310         }
311
312         length[0] = end[0] - start[0];
313         length[1] = end[1] - start[1];
314
315         for (int i = 0; i < totpoints; i++) {
316                 tGPspoint *p2d = &points2D[i];
317                 p2d->x = (int)(start[0] + sinf(a) * length[0]);
318                 p2d->y = (int)(end[1] - cosf(a) * length[1]);
319                 a += step;
320         }
321 }
322
323 /* create a circle */
324 static void gp_primitive_circle(tGPDprimitive *tgpi, tGPspoint *points2D)
325 {
326         const int totpoints = tgpi->tot_edges;
327         const float step = (2.0f * M_PI) / (float)(totpoints);
328         float center[2];
329         float radius[2];
330         float a = 0.0f;
331
332         /* TODO: Use math-lib functions for these? */
333         center[0] = tgpi->top[0] + ((tgpi->bottom[0] - tgpi->top[0]) / 2.0f);
334         center[1] = tgpi->top[1] + ((tgpi->bottom[1] - tgpi->top[1]) / 2.0f);
335         radius[0] = fabsf(((tgpi->bottom[0] - tgpi->top[0]) / 2.0f));
336         radius[1] = fabsf(((tgpi->bottom[1] - tgpi->top[1]) / 2.0f));
337
338         for (int i = 0; i < totpoints; i++) {
339                 tGPspoint *p2d = &points2D[i];
340
341                 p2d->x = (int)(center[0] + cosf(a) * radius[0]);
342                 p2d->y = (int)(center[1] + sinf(a) * radius[1]);
343                 a += step;
344         }
345 }
346
347 /* Helper: Update shape of the stroke */
348 static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
349 {
350         ToolSettings *ts = tgpi->scene->toolsettings;
351         bGPdata *gpd = tgpi->gpd;
352         bGPDstroke *gps = tgpi->gpf->strokes.first;
353
354         /* realloc points to new size */
355         /* TODO: only do this if the size has changed? */
356         gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * tgpi->tot_edges);
357         if (gps->dvert != NULL) {
358                 gps->dvert = MEM_reallocN(gps->dvert, sizeof(MDeformVert) * tgpi->tot_edges);
359         }
360         gps->totpoints = tgpi->tot_edges;
361
362         /* compute screen-space coordinates for points */
363         tGPspoint *points2D = MEM_callocN(sizeof(tGPspoint) * tgpi->tot_edges, "gp primitive points2D");
364         switch (tgpi->type) {
365                 case GP_STROKE_BOX:
366                         gp_primitive_rectangle(tgpi, points2D);
367                         break;
368                 case GP_STROKE_LINE:
369                         gp_primitive_line(tgpi, points2D);
370                         break;
371                 case GP_STROKE_CIRCLE:
372                         gp_primitive_circle(tgpi, points2D);
373                         break;
374                 case GP_STROKE_ARC:
375                         gp_primitive_arc(tgpi, points2D);
376                         if (tgpi->cyclic)
377                                 gps->flag |= GP_STROKE_CYCLIC;
378                         else
379                                 gps->flag &= ~GP_STROKE_CYCLIC;
380                         break;
381                 default:
382                         break;
383         }
384
385         /* convert screen-coordinates to 3D coordinates */
386         for (int i = 0; i < gps->totpoints; i++) {
387                 bGPDspoint *pt = &gps->points[i];
388                 tGPspoint *p2d = &points2D[i];
389
390                 /* convert screen-coordinates to 3D coordinates */
391                 gp_stroke_convertcoords_tpoint(tgpi->scene, tgpi->ar, tgpi->ob, tgpi->gpl, p2d, NULL, &pt->x);
392
393                 pt->pressure = 1.0f;
394                 pt->strength = tgpi->brush->gpencil_settings->draw_strength;
395                 pt->time = 0.0f;
396
397                 if (gps->dvert != NULL) {
398                         MDeformVert *dvert = &gps->dvert[i];
399                         dvert->totweight = 0;
400                         dvert->dw = NULL;
401                 }
402         }
403
404         /* if axis locked, reproject to plane locked */
405         if (tgpi->lock_axis > GP_LOCKAXIS_VIEW) {
406                 bGPDspoint *tpt = gps->points;
407                 float origin[3];
408                 ED_gp_get_drawing_reference(tgpi->scene, tgpi->ob, tgpi->gpl,
409                         ts->gpencil_v3d_align, origin);
410
411                 for (int i = 0; i < gps->totpoints; i++, tpt++) {
412                         ED_gp_project_point_to_plane(tgpi->ob, tgpi->rv3d, origin,
413                                 ts->gp_sculpt.lock_axis - 1,
414                                 tpt);
415                 }
416         }
417
418         /* if parented change position relative to parent object */
419         for (int i = 0; i < gps->totpoints; i++) {
420                 bGPDspoint *pt = &gps->points[i];
421                 gp_apply_parent_point(tgpi->depsgraph, tgpi->ob, tgpi->gpd, tgpi->gpl, pt);
422         }
423
424         /* force fill recalc */
425         gps->flag |= GP_STROKE_RECALC_CACHES;
426
427         /* free temp data */
428         MEM_SAFE_FREE(points2D);
429
430         DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
431         DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
432         WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
433 }
434
435 /* Update screen and stroke */
436 static void gpencil_primitive_update(bContext *C, wmOperator *op, tGPDprimitive *tgpi)
437 {
438         /* update indicator in header */
439         gpencil_primitive_status_indicators(C, tgpi);
440         /* apply... */
441         tgpi->type = RNA_enum_get(op->ptr, "type");
442         tgpi->tot_edges = RNA_int_get(op->ptr, "edges");
443         /* update points position */
444         gp_primitive_update_strokes(C, tgpi);
445 }
446
447 /* ----------------------- */
448
449 static void gpencil_primitive_interaction_begin(tGPDprimitive *tgpi, const wmEvent *event)
450 {
451         tgpi->origin[0] = event->mval[0];
452         tgpi->origin[1] = event->mval[1];
453
454         tgpi->top[0] = event->mval[0];
455         tgpi->top[1] = event->mval[1];
456
457         tgpi->bottom[0] = event->mval[0];
458         tgpi->bottom[1] = event->mval[1];
459 }
460
461 /* Exit and free memory */
462 static void gpencil_primitive_exit(bContext *C, wmOperator *op)
463 {
464         tGPDprimitive *tgpi = op->customdata;
465         bGPdata *gpd = tgpi->gpd;
466
467         /* don't assume that operator data exists at all */
468         if (tgpi) {
469                 /* remove drawing handler */
470                 if (tgpi->draw_handle_3d) {
471                         ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_3d);
472                 }
473
474                 /* clear status message area */
475                 ED_workspace_status_text(C, NULL);
476
477                 /* finally, free memory used by temp data */
478                 BKE_gpencil_free_strokes(tgpi->gpf);
479                 MEM_freeN(tgpi->gpf);
480                 MEM_freeN(tgpi);
481         }
482         DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
483         WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
484
485         /* clear pointer */
486         op->customdata = NULL;
487 }
488
489 /* Init new temporary primitive data */
490 static void gpencil_primitive_init(bContext *C, wmOperator *op)
491 {
492         ToolSettings *ts = CTX_data_tool_settings(C);
493         bGPdata *gpd = CTX_data_gpencil_data(C);
494         Main *bmain = CTX_data_main(C);
495         Scene *scene = CTX_data_scene(C);
496         Depsgraph *depsgraph = CTX_data_depsgraph(C);
497         int cfra_eval = (int)DEG_get_ctime(depsgraph);
498
499         /* create temporary operator data */
500         tGPDprimitive *tgpi = MEM_callocN(sizeof(tGPDprimitive), "GPencil Primitive Data");
501         op->customdata = tgpi;
502
503         /* set current scene and window info */
504         tgpi->scene = scene;
505         tgpi->ob = CTX_data_active_object(C);
506         tgpi->sa = CTX_wm_area(C);
507         tgpi->ar = CTX_wm_region(C);
508         tgpi->rv3d = tgpi->ar->regiondata;
509         tgpi->v3d = tgpi->sa->spacedata.first;
510         tgpi->depsgraph = CTX_data_depsgraph(C);
511         tgpi->win = CTX_wm_window(C);
512
513         /* set current frame number */
514         tgpi->cframe = cfra_eval;
515
516         /* set GP datablock */
517         tgpi->gpd = gpd;
518
519         /* getcolor info */
520         tgpi->mat = BKE_gpencil_material_ensure(bmain, tgpi->ob);
521
522         /* set parameters */
523         tgpi->type = RNA_enum_get(op->ptr, "type");
524
525         /* set default edge count */
526         if (tgpi->type == GP_STROKE_CIRCLE) {
527                 RNA_int_set(op->ptr, "edges", 64);
528         }
529         else if (tgpi->type == GP_STROKE_ARC) {
530                 RNA_int_set(op->ptr, "edges", 32);
531         }
532         else if (tgpi->type == GP_STROKE_BOX) {
533                 RNA_int_set(op->ptr, "edges", 4);
534         }
535         else { /* LINE */
536                 RNA_int_set(op->ptr, "edges", 2);
537         }
538
539         tgpi->tot_edges = RNA_int_get(op->ptr, "edges");
540         tgpi->flag = IDLE;
541
542         tgpi->lock_axis = ts->gp_sculpt.lock_axis;
543
544         /* set temp layer, frame and stroke */
545         gp_primitive_set_initdata(C, tgpi);
546 }
547
548 /* ----------------------- */
549
550 /* Invoke handler: Initialize the operator */
551 static int gpencil_primitive_invoke(bContext *C, wmOperator *op, const wmEvent *event)
552 {
553         wmWindow *win = CTX_wm_window(C);
554         bGPdata *gpd = CTX_data_gpencil_data(C);
555         tGPDprimitive *tgpi = NULL;
556
557         /* initialize operator runtime data */
558         gpencil_primitive_init(C, op);
559         tgpi = op->customdata;
560
561         const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
562         if (!is_modal) {
563                 tgpi->flag = IN_PROGRESS;
564                 gpencil_primitive_interaction_begin(tgpi, event);
565         }
566
567         /* if in tools region, wait till we get to the main (3d-space)
568          * region before allowing drawing to take place.
569          */
570         op->flag |= OP_IS_MODAL_CURSOR_REGION;
571
572         /* Enable custom drawing handlers */
573         tgpi->draw_handle_3d = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_primitive_draw_3d, tgpi, REGION_DRAW_POST_VIEW);
574
575         /* set cursor to indicate modal */
576         WM_cursor_modal_set(win, BC_CROSSCURSOR);
577
578         /* update sindicator in header */
579         gpencil_primitive_status_indicators(C, tgpi);
580         DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
581         WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
582
583         /* add a modal handler for this operator */
584         WM_event_add_modal_handler(C, op);
585
586         return OPERATOR_RUNNING_MODAL;
587 }
588
589 /* Helper to complete a primitive */
590 static void gpencil_primitive_interaction_end(bContext *C, wmOperator *op, wmWindow *win, tGPDprimitive *tgpi)
591 {
592         bGPDframe *gpf;
593         bGPDstroke *gps;
594
595         ToolSettings *ts = tgpi->scene->toolsettings;
596
597         const int def_nr = tgpi->ob->actdef - 1;
598         const bool have_weight = (bool)BLI_findlink(&tgpi->ob->defbase, def_nr);
599
600         /* return to normal cursor and header status */
601         ED_workspace_status_text(C, NULL);
602         WM_cursor_modal_restore(win);
603
604         /* insert keyframes as required... */
605         gpf = BKE_gpencil_layer_getframe(tgpi->gpl, tgpi->cframe, GP_GETFRAME_ADD_NEW);
606
607         /* prepare stroke to get transferred */
608         gps = tgpi->gpf->strokes.first;
609         if (gps) {
610                 gps->thickness = tgpi->brush->size;
611                 gps->flag |= GP_STROKE_RECALC_CACHES;
612                 gps->tot_triangles = 0;
613         }
614
615         /* transfer stroke from temporary buffer to the actual frame */
616         BLI_movelisttolist(&gpf->strokes, &tgpi->gpf->strokes);
617         BLI_assert(BLI_listbase_is_empty(&tgpi->gpf->strokes));
618
619         /* add weights if required */
620         if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
621                 BKE_gpencil_dvert_ensure(gps);
622                 for (int i = 0; i < gps->totpoints; i++) {
623                         MDeformVert *ve = &gps->dvert[i];
624                         MDeformWeight *dw = defvert_verify_index(ve, def_nr);
625                         if (dw) {
626                                 dw->weight = ts->vgroup_weight;
627                         }
628
629                 }
630         }
631
632         DEG_id_tag_update(&tgpi->gpd->id, DEG_TAG_COPY_ON_WRITE);
633         DEG_id_tag_update(&tgpi->gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
634
635         /* clean up temp data */
636         gpencil_primitive_exit(C, op);
637 }
638
639 /* Helper to square a primitive */
640 static void gpencil_primitive_to_square(tGPDprimitive *tgpi, const int x, const int y)
641 {
642         int w = abs(x);
643         int h = abs(y);
644         if ((x > 0 && y > 0) || (x < 0 && y < 0)) {
645                 if (w > h)
646                         tgpi->bottom[1] = tgpi->origin[1] + x;
647                 else
648                         tgpi->bottom[0] = tgpi->origin[0] + y;
649         }
650         else {
651                 if (w > h)
652                         tgpi->bottom[1] = tgpi->origin[1] - x;
653                 else
654                         tgpi->bottom[0] = tgpi->origin[0] - y;
655         }
656 }
657
658 /* Modal handler: Events handling during interactive part */
659 static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *event)
660 {
661         tGPDprimitive *tgpi = op->customdata;
662         wmWindow *win = CTX_wm_window(C);
663         const bool has_numinput = hasNumInput(&tgpi->num);
664
665         switch (event->type) {
666                 case LEFTMOUSE:
667                         if ((event->val == KM_PRESS) && (tgpi->flag == IDLE)) {
668                                 /* start drawing primitive */
669                                 /* TODO: Ignore if not in main region yet */
670                                 tgpi->flag = IN_PROGRESS;
671                                 gpencil_primitive_interaction_begin(tgpi, event);
672                         }
673                         else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS)) {
674                                 /* stop drawing primitive */
675                                 tgpi->flag = IDLE;
676                                 gpencil_primitive_interaction_end(C, op, win, tgpi);
677                                 /* done! */
678                                 return OPERATOR_FINISHED;
679                         }
680                         else {
681                                 if (G.debug & G_DEBUG) {
682                                         printf("GP Add Primitive Modal: LEFTMOUSE %d, Status = %d\n", event->val, tgpi->flag);
683                                 }
684                         }
685                         break;
686                 case RETKEY:  /* confirm */
687                 {
688                         tgpi->flag = IDLE;
689                         gpencil_primitive_interaction_end(C, op, win, tgpi);
690                         /* done! */
691                         return OPERATOR_FINISHED;
692                 }
693                 case ESCKEY:    /* cancel */
694                 case RIGHTMOUSE:
695                 {
696                         /* return to normal cursor and header status */
697                         ED_workspace_status_text(C, NULL);
698                         WM_cursor_modal_restore(win);
699
700                         /* clean up temp data */
701                         gpencil_primitive_exit(C, op);
702
703                         /* canceled! */
704                         return OPERATOR_CANCELLED;
705                 }
706                 case CKEY:
707                 {
708                         if ((event->val == KM_RELEASE) && tgpi->type == GP_STROKE_ARC) {
709                                 tgpi->cyclic ^= 1;
710
711                                 /* update screen */
712                                 gpencil_primitive_update(C, op, tgpi);
713                         }
714                         break;
715                 }
716                 case FKEY:
717                 {
718                         if ((event->val == KM_RELEASE) && tgpi->type == GP_STROKE_ARC) {
719                                 tgpi->flip ^= 1;
720
721                                 /* update screen */
722                                 gpencil_primitive_update(C, op, tgpi);
723                         }
724                         break;
725                 }
726                 case PADPLUSKEY:
727                 case WHEELUPMOUSE:
728                 {
729                         if ((event->val != KM_RELEASE) && (tgpi->type == GP_STROKE_CIRCLE || tgpi->type == GP_STROKE_ARC)) {
730                                 tgpi->tot_edges = tgpi->tot_edges + 1;
731                                 CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
732                                 RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
733
734                                 /* update screen */
735                                 gpencil_primitive_update(C, op, tgpi);
736                         }
737                         break;
738                 }
739                 case PADMINUS:
740                 case WHEELDOWNMOUSE:
741                 {
742                         if ((event->val != KM_RELEASE) && (tgpi->type == GP_STROKE_CIRCLE || tgpi->type == GP_STROKE_ARC)) {
743                                 tgpi->tot_edges = tgpi->tot_edges - 1;
744                                 CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
745                                 RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
746
747                                 /* update screen */
748                                 gpencil_primitive_update(C, op, tgpi);
749                         }
750                         break;
751                 }
752                 case MOUSEMOVE: /* calculate new position */
753                 {
754                         /* only handle mousemove if not doing numinput */
755                         if (has_numinput == false) {
756                                 /* update position of mouse */
757                                 tgpi->bottom[0] = event->mval[0];
758                                 tgpi->bottom[1] = event->mval[1];
759                                 tgpi->top[0] = tgpi->origin[0];
760                                 tgpi->top[1] = tgpi->origin[1];
761                                 if (tgpi->flag == IDLE) {
762                                         tgpi->origin[0] = event->mval[0];
763                                         tgpi->origin[1] = event->mval[1];
764                                 }
765                                 /* Keep square if shift key */
766                                 if (event->shift) {
767                                         int x = tgpi->bottom[0] - tgpi->origin[0];
768                                         int y = tgpi->bottom[1] - tgpi->origin[1];
769                                         if (tgpi->type == GP_STROKE_LINE) {
770                                                 float angle = fabsf(atan2f((float)y, (float)x));
771                                                 if (angle < 0.4f || angle > (M_PI - 0.4f)) {
772                                                         tgpi->bottom[1] = tgpi->origin[1];
773                                                 }
774                                                 else if (angle > (M_PI_2 - 0.4f) && angle < (M_PI_2 + 0.4f)) {
775                                                         tgpi->bottom[0] = tgpi->origin[0];
776                                                 }
777                                                 else {
778                                                         gpencil_primitive_to_square(tgpi, x, y);
779                                                 }
780                                         }
781                                         else {
782                                                 gpencil_primitive_to_square(tgpi, x, y);
783                                         }
784                                 }
785                                 /* Center primitive if alt key */
786                                 if (event->alt) {
787                                         tgpi->top[0] = tgpi->origin[0] - (tgpi->bottom[0] - tgpi->origin[0]);
788                                         tgpi->top[1] = tgpi->origin[1] - (tgpi->bottom[1] - tgpi->origin[1]);
789                                 }
790                                 /* update screen */
791                                 gpencil_primitive_update(C, op, tgpi);
792                         }
793                         break;
794                 }
795                 default:
796                 {
797                         if ((event->val == KM_PRESS) && handleNumInput(C, &tgpi->num, event)) {
798                                 float value;
799
800                                 /* Grab data from numeric input, and store this new value (the user see an int) */
801                                 value = tgpi->tot_edges;
802                                 applyNumInput(&tgpi->num, &value);
803                                 tgpi->tot_edges = value;
804
805                                 CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
806                                 RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
807
808                                 /* update screen */
809                                 gpencil_primitive_update(C, op, tgpi);
810
811                                 break;
812                         }
813                         else {
814                                 /* unhandled event - allow to pass through */
815                                 return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
816                         }
817                 }
818         }
819
820         /* still running... */
821         return OPERATOR_RUNNING_MODAL;
822 }
823
824 /* Cancel handler */
825 static void gpencil_primitive_cancel(bContext *C, wmOperator *op)
826 {
827         /* this is just a wrapper around exit() */
828         gpencil_primitive_exit(C, op);
829 }
830
831 void GPENCIL_OT_primitive(wmOperatorType *ot)
832 {
833         static EnumPropertyItem primitive_type[] = {
834                 {GP_STROKE_BOX, "BOX", 0, "Box", ""},
835                 {GP_STROKE_LINE, "LINE", 0, "Line", ""},
836                 {GP_STROKE_CIRCLE, "CIRCLE", 0, "Circle", ""},
837                 {GP_STROKE_ARC, "ARC", 0, "Arc", ""},
838                 {0, NULL, 0, NULL, NULL}
839         };
840
841         /* identifiers */
842         ot->name = "Grease Pencil Shapes";
843         ot->idname = "GPENCIL_OT_primitive";
844         ot->description = "Create predefined grease pencil stroke shapes";
845
846         /* callbacks */
847         ot->invoke = gpencil_primitive_invoke;
848         ot->modal = gpencil_primitive_modal;
849         ot->cancel = gpencil_primitive_cancel;
850         ot->poll = gpencil_primitive_add_poll;
851
852         /* flags */
853         ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
854
855         /* properties */
856         PropertyRNA *prop;
857
858         RNA_def_int(ot->srna, "edges", 4, MIN_EDGES, MAX_EDGES, "Edges", "Number of polygon edges", MIN_EDGES, MAX_EDGES);
859         RNA_def_enum(ot->srna, "type", primitive_type, GP_STROKE_BOX, "Type", "Type of shape");
860
861         prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
862         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
863 }
864
865 /* *************************************************************** */