84bfd709b10665c0a1f8dc1f1b48b410eadf9752
[blender.git] / source / blender / editors / gpencil / gpencil_utils.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2014, Blender Foundation
17  */
18
19 /** \file
20  * \ingroup edgpencil
21  */
22
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <stddef.h>
27 #include <math.h>
28
29 #include "MEM_guardedalloc.h"
30
31 #include "BLI_math.h"
32 #include "BLI_blenlib.h"
33 #include "BLI_ghash.h"
34 #include "BLI_utildefines.h"
35 #include "BLT_translation.h"
36 #include "BLI_rand.h"
37
38 #include "DNA_meshdata_types.h"
39 #include "DNA_gpencil_types.h"
40 #include "DNA_brush_types.h"
41 #include "DNA_object_types.h"
42 #include "DNA_scene_types.h"
43 #include "DNA_screen_types.h"
44 #include "DNA_space_types.h"
45 #include "DNA_view3d_types.h"
46
47 #include "BKE_action.h"
48 #include "BKE_colortools.h"
49 #include "BKE_deform.h"
50 #include "BKE_main.h"
51 #include "BKE_brush.h"
52 #include "BKE_context.h"
53 #include "BKE_gpencil.h"
54 #include "BKE_object.h"
55 #include "BKE_paint.h"
56 #include "BKE_material.h"
57 #include "BKE_tracking.h"
58
59 #include "WM_api.h"
60 #include "WM_toolsystem.h"
61
62 #include "RNA_access.h"
63 #include "RNA_define.h"
64 #include "RNA_enum_types.h"
65
66 #include "UI_resources.h"
67 #include "UI_view2d.h"
68
69 #include "ED_gpencil.h"
70 #include "ED_clip.h"
71 #include "ED_view3d.h"
72 #include "ED_object.h"
73 #include "ED_screen.h"
74 #include "ED_select_utils.h"
75
76 #include "GPU_immediate.h"
77 #include "GPU_immediate_util.h"
78
79 #include "DEG_depsgraph.h"
80 #include "DEG_depsgraph_query.h"
81
82 #include "gpencil_intern.h"
83
84 /* ******************************************************** */
85 /* Context Wrangling... */
86
87 /* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it,
88  * when context info is not available.
89  */
90 bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, ScrArea *sa, Scene *scene, Object *ob, PointerRNA *r_ptr)
91 {
92         /* if there's an active area, check if the particular editor may
93          * have defined any special Grease Pencil context for editing...
94          */
95         if (sa) {
96                 SpaceLink *sl = sa->spacedata.first;
97
98                 switch (sa->spacetype) {
99                         /* XXX: Should we reduce reliance on context.gpencil_data for these cases? */
100                         case SPACE_PROPERTIES: /* properties */
101                         case SPACE_INFO: /* header info (needed after workspaces merge) */
102                         {
103                                 if (ob && (ob->type == OB_GPENCIL)) {
104                                         /* GP Object */
105                                         if (r_ptr) RNA_id_pointer_create(&ob->id, r_ptr);
106                                         return (bGPdata **)&ob->data;
107                                 }
108                                 else {
109                                         return NULL;
110                                 }
111
112                                 break;
113                         }
114
115                         case SPACE_TOPBAR: /* Topbar (needed after topbar merge) */
116                         case SPACE_VIEW3D: /* 3D-View */
117                         {
118                                 if (ob && (ob->type == OB_GPENCIL)) {
119                                         /* GP Object */
120                                         if (r_ptr) RNA_id_pointer_create(&ob->id, r_ptr);
121                                         return (bGPdata **)&ob->data;
122                                 }
123                                 else {
124                                         /* Annotations */
125                                         /* XXX: */
126                                         if (r_ptr) RNA_id_pointer_create(&scene->id, r_ptr);
127                                         return &scene->gpd;
128                                 }
129
130                                 break;
131                         }
132                         case SPACE_NODE: /* Nodes Editor */
133                         {
134                                 SpaceNode *snode = (SpaceNode *)sl;
135
136                                 /* return the GP data for the active node block/node */
137                                 if (snode && snode->nodetree) {
138                                         /* for now, as long as there's an active node tree,
139                                          * default to using that in the Nodes Editor */
140                                         if (r_ptr) RNA_id_pointer_create(&snode->nodetree->id, r_ptr);
141                                         return &snode->nodetree->gpd;
142                                 }
143
144                                 /* even when there is no node-tree, don't allow this to flow to scene */
145                                 return NULL;
146                         }
147                         case SPACE_SEQ: /* Sequencer */
148                         {
149                                 SpaceSeq *sseq = (SpaceSeq *)sl;
150
151                                 /* for now, Grease Pencil data is associated with the space (actually preview region only) */
152                                 /* XXX our convention for everything else is to link to data though... */
153                                 if (r_ptr) RNA_pointer_create(screen_id, &RNA_SpaceSequenceEditor, sseq, r_ptr);
154                                 return &sseq->gpd;
155                         }
156                         case SPACE_IMAGE: /* Image/UV Editor */
157                         {
158                                 SpaceImage *sima = (SpaceImage *)sl;
159
160                                 /* for now, Grease Pencil data is associated with the space... */
161                                 /* XXX our convention for everything else is to link to data though... */
162                                 if (r_ptr) RNA_pointer_create(screen_id, &RNA_SpaceImageEditor, sima, r_ptr);
163                                 return &sima->gpd;
164                         }
165                         case SPACE_CLIP: /* Nodes Editor */
166                         {
167                                 SpaceClip *sc = (SpaceClip *)sl;
168                                 MovieClip *clip = ED_space_clip_get_clip(sc);
169
170                                 if (clip) {
171                                         if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
172                                                 MovieTrackingTrack *track = BKE_tracking_track_get_active(&clip->tracking);
173
174                                                 if (!track)
175                                                         return NULL;
176
177                                                 if (r_ptr) RNA_pointer_create(&clip->id, &RNA_MovieTrackingTrack, track, r_ptr);
178                                                 return &track->gpd;
179                                         }
180                                         else {
181                                                 if (r_ptr) RNA_id_pointer_create(&clip->id, r_ptr);
182                                                 return &clip->gpd;
183                                         }
184                                 }
185                                 break;
186                         }
187                         default: /* unsupported space */
188                                 return NULL;
189                 }
190         }
191
192         return NULL;
193 }
194
195 /* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it */
196 bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
197 {
198         ID *screen_id = (ID *)CTX_wm_screen(C);
199         Scene *scene = CTX_data_scene(C);
200         ScrArea *sa = CTX_wm_area(C);
201         Object *ob = CTX_data_active_object(C);
202
203         return ED_gpencil_data_get_pointers_direct(screen_id, sa, scene, ob, r_ptr);
204 }
205
206 /* -------------------------------------------------------- */
207
208 /* Get the active Grease Pencil datablock, when context is not available */
209 bGPdata *ED_gpencil_data_get_active_direct(ID *screen_id, ScrArea *sa, Scene *scene, Object *ob)
210 {
211         bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(screen_id, sa, scene, ob, NULL);
212         return (gpd_ptr) ? *(gpd_ptr) : NULL;
213 }
214
215 /**
216  * Get the active Grease Pencil datablock
217  * \note This is the original (bmain) copy of the datablock, stored in files.
218  *       Do not use for reading evaluated copies of GP Objects data
219  */
220 bGPdata *ED_gpencil_data_get_active(const bContext *C)
221 {
222         bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
223         return (gpd_ptr) ? *(gpd_ptr) : NULL;
224 }
225
226 /**
227  * Get the evaluated copy of the active Grease Pencil datablock (where applicable)
228  * - For the 3D View (i.e. "GP Objects"), this gives the evaluated copy of the GP datablock
229  *   (i.e. a copy of the active GP datablock for the active object, where modifiers have been
230  *   applied). This is needed to correctly work with "Copy-on-Write"
231  * - For all other editors (i.e. "GP Annotations"), this just gives the active datablock
232  *   like for ED_gpencil_data_get_active()
233  */
234 bGPdata *ED_gpencil_data_get_active_evaluated(const bContext *C)
235 {
236         ID *screen_id = (ID *)CTX_wm_screen(C);
237         ScrArea *sa = CTX_wm_area(C);
238
239         const Depsgraph *depsgraph = CTX_data_depsgraph(C);
240         Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
241         Object *ob = CTX_data_active_object(C);
242         Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
243
244         /* if (ob && ob->type == OB_GPENCIL) BLI_assert(ob_eval->data == DEG_get_evaluated_id(ob->data)); */
245         return ED_gpencil_data_get_active_direct(screen_id, sa, scene_eval, ob_eval);
246 }
247
248 /* -------------------------------------------------------- */
249
250 /**
251  * Utility to check whether the r_ptr output of ED_gpencil_data_get_pointers()
252  * is for annotation usage.
253  */
254 bool ED_gpencil_data_owner_is_annotation(PointerRNA *owner_ptr)
255 {
256         /* Key Assumption: If the pointer is an object, we're dealing with a GP Object's data.
257          * Otherwise, the GP datablock is being used for annotations (i.e. everywhere else)
258          */
259         return ((owner_ptr) && (owner_ptr->type != &RNA_Object));
260 }
261
262 /* -------------------------------------------------------- */
263
264 // XXX: this should be removed... We really shouldn't duplicate logic like this!
265 bGPdata *ED_gpencil_data_get_active_v3d(ViewLayer *view_layer, View3D *v3d)
266 {
267         Base *base = view_layer->basact;
268         bGPdata *gpd = NULL;
269
270         /* We have to make sure active object is actually visible and selected, else we must use default scene gpd,
271          * to be consistent with ED_gpencil_data_get_active's behavior.
272          */
273         if (base && BASE_SELECTED(v3d, base)) {
274                 if (base->object->type == OB_GPENCIL)
275                         gpd = base->object->data;
276         }
277         return gpd ? gpd : NULL;
278 }
279
280 /* ******************************************************** */
281 /* Keyframe Indicator Checks */
282
283 /* Check whether there's an active GP keyframe on the current frame */
284 bool ED_gpencil_has_keyframe_v3d(Scene *UNUSED(scene), Object *ob, int cfra)
285 {
286         if (ob && ob->data && (ob->type == OB_GPENCIL)) {
287                 bGPDlayer *gpl = BKE_gpencil_layer_getactive(ob->data);
288                 if (gpl) {
289                         if (gpl->actframe) {
290                                 // XXX: assumes that frame has been fetched already
291                                 return (gpl->actframe->framenum == cfra);
292                         }
293                         else {
294                                 /* XXX: disabled as could be too much of a penalty */
295                                 /* return BKE_gpencil_layer_find_frame(gpl, cfra); */
296                         }
297                 }
298         }
299
300         return false;
301 }
302
303 /* ******************************************************** */
304 /* Poll Callbacks */
305
306 /* poll callback for adding data/layers - special */
307 bool gp_add_poll(bContext *C)
308 {
309         /* the base line we have is that we have somewhere to add Grease Pencil data */
310         return ED_gpencil_data_get_pointers(C, NULL) != NULL;
311 }
312
313 /* poll callback for checking if there is an active layer */
314 bool gp_active_layer_poll(bContext *C)
315 {
316         bGPdata *gpd = ED_gpencil_data_get_active(C);
317         bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
318
319         return (gpl != NULL);
320 }
321
322 /* poll callback for checking if there is an active brush */
323 bool gp_active_brush_poll(bContext *C)
324 {
325         ToolSettings *ts = CTX_data_tool_settings(C);
326         Paint *paint = &ts->gp_paint->paint;
327         if (paint) {
328                 return (paint->brush != NULL);
329         }
330         else {
331                 return false;
332         }
333 }
334
335 /* ******************************************************** */
336 /* Dynamic Enums of GP Layers */
337 /* NOTE: These include an option to create a new layer and use that... */
338
339 /* Just existing layers */
340 const EnumPropertyItem *ED_gpencil_layers_enum_itemf(
341         bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
342 {
343         bGPdata *gpd = CTX_data_gpencil_data(C);
344         bGPDlayer *gpl;
345         EnumPropertyItem *item = NULL, item_tmp = {0};
346         int totitem = 0;
347         int i = 0;
348
349         if (ELEM(NULL, C, gpd)) {
350                 return DummyRNA_DEFAULT_items;
351         }
352
353         /* Existing layers */
354         for (gpl = gpd->layers.first; gpl; gpl = gpl->next, i++) {
355                 item_tmp.identifier = gpl->info;
356                 item_tmp.name = gpl->info;
357                 item_tmp.value = i;
358
359                 if (gpl->flag & GP_LAYER_ACTIVE)
360                         item_tmp.icon = ICON_GREASEPENCIL;
361                 else
362                         item_tmp.icon = ICON_NONE;
363
364                 RNA_enum_item_add(&item, &totitem, &item_tmp);
365         }
366
367         RNA_enum_item_end(&item, &totitem);
368         *r_free = true;
369
370         return item;
371 }
372
373 /* Existing + Option to add/use new layer */
374 const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(
375         bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
376 {
377         bGPdata *gpd = CTX_data_gpencil_data(C);
378         bGPDlayer *gpl;
379         EnumPropertyItem *item = NULL, item_tmp = {0};
380         int totitem = 0;
381         int i = 0;
382
383         if (ELEM(NULL, C, gpd)) {
384                 return DummyRNA_DEFAULT_items;
385         }
386
387         /* Create new layer */
388         /* TODO: have some way of specifying that we don't want this? */
389         {
390                 /* "New Layer" entry */
391                 item_tmp.identifier = "__CREATE__";
392                 item_tmp.name = "New Layer";
393                 item_tmp.value = -1;
394                 item_tmp.icon = ICON_ADD;
395                 RNA_enum_item_add(&item, &totitem, &item_tmp);
396
397                 /* separator */
398                 RNA_enum_item_add_separator(&item, &totitem);
399         }
400         const int tot = BLI_listbase_count(&gpd->layers);
401         /* Existing layers */
402         for (gpl = gpd->layers.last, i = 0; gpl; gpl = gpl->prev, i++) {
403                 item_tmp.identifier = gpl->info;
404                 item_tmp.name = gpl->info;
405                 item_tmp.value = tot - i - 1;
406
407                 if (gpl->flag & GP_LAYER_ACTIVE)
408                         item_tmp.icon = ICON_GREASEPENCIL;
409                 else
410                         item_tmp.icon = ICON_NONE;
411
412                 RNA_enum_item_add(&item, &totitem, &item_tmp);
413         }
414
415         RNA_enum_item_end(&item, &totitem);
416         *r_free = true;
417
418         return item;
419 }
420
421
422 /* ******************************************************** */
423 /* Brush Tool Core */
424
425 /**
426  * Check whether a given stroke segment is inside a circular brush
427  *
428  * \param mval: The current screen-space coordinates (midpoint) of the brush
429  * \param mvalo: The previous screen-space coordinates (midpoint) of the brush (NOT CURRENTLY USED)
430  * \param rad: The radius of the brush
431  *
432  * \param x0, y0: The screen-space x and y coordinates of the start of the stroke segment
433  * \param x1, y1: The screen-space x and y coordinates of the end of the stroke segment
434  */
435 bool gp_stroke_inside_circle(
436         const float mval[2], const float UNUSED(mvalo[2]),
437         int rad, int x0, int y0, int x1, int y1)
438 {
439         /* simple within-radius check for now */
440         const float screen_co_a[2] = {x0, y0};
441         const float screen_co_b[2] = {x1, y1};
442
443         if (edge_inside_circle(mval, rad, screen_co_a, screen_co_b)) {
444                 return true;
445         }
446
447         /* not inside */
448         return false;
449 }
450
451 /* ******************************************************** */
452 /* Stroke Validity Testing */
453
454 /* Check whether given stroke can be edited given the supplied context */
455 /* TODO: do we need additional flags for screenspace vs dataspace? */
456 bool ED_gpencil_stroke_can_use_direct(const ScrArea *sa, const bGPDstroke *gps)
457 {
458         /* sanity check */
459         if (ELEM(NULL, sa, gps))
460                 return false;
461
462         /* filter stroke types by flags + spacetype */
463         if (gps->flag & GP_STROKE_3DSPACE) {
464                 /* 3D strokes - only in 3D view */
465                 return ((sa->spacetype == SPACE_VIEW3D) || (sa->spacetype == SPACE_PROPERTIES));
466         }
467         else if (gps->flag & GP_STROKE_2DIMAGE) {
468                 /* Special "image" strokes - only in Image Editor */
469                 return (sa->spacetype == SPACE_IMAGE);
470         }
471         else if (gps->flag & GP_STROKE_2DSPACE) {
472                 /* 2D strokes (dataspace) - for any 2D view (i.e. everything other than 3D view) */
473                 return (sa->spacetype != SPACE_VIEW3D);
474         }
475         else {
476                 /* view aligned - anything goes */
477                 return true;
478         }
479 }
480
481 /* Check whether given stroke can be edited in the current context */
482 bool ED_gpencil_stroke_can_use(const bContext *C, const bGPDstroke *gps)
483 {
484         ScrArea *sa = CTX_wm_area(C);
485         return ED_gpencil_stroke_can_use_direct(sa, gps);
486 }
487
488 /* Check whether given stroke can be edited for the current color */
489 bool ED_gpencil_stroke_color_use(Object *ob, const bGPDlayer *gpl, const bGPDstroke *gps)
490 {
491         /* check if the color is editable */
492         MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
493
494         if (gp_style != NULL) {
495                 if (gp_style->flag & GP_STYLE_COLOR_HIDE)
496                         return false;
497                 if (((gpl->flag & GP_LAYER_UNLOCK_COLOR) == 0) && (gp_style->flag & GP_STYLE_COLOR_LOCKED))
498                         return false;
499         }
500
501         return true;
502 }
503
504 /* ******************************************************** */
505 /* Space Conversion */
506
507 /**
508  * Init settings for stroke point space conversions
509  *
510  * \param r_gsc: [out] The space conversion settings struct, populated with necessary params
511  */
512 void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
513 {
514         ScrArea *sa = CTX_wm_area(C);
515         ARegion *ar = CTX_wm_region(C);
516
517         /* zero out the storage (just in case) */
518         memset(r_gsc, 0, sizeof(GP_SpaceConversion));
519         unit_m4(r_gsc->mat);
520
521         /* store settings */
522         r_gsc->scene = CTX_data_scene(C);
523         r_gsc->ob = CTX_data_active_object(C);
524
525         r_gsc->sa = sa;
526         r_gsc->ar = ar;
527         r_gsc->v2d = &ar->v2d;
528
529         /* init region-specific stuff */
530         if (sa->spacetype == SPACE_VIEW3D) {
531                 wmWindow *win = CTX_wm_window(C);
532                 Scene *scene = CTX_data_scene(C);
533                 struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
534                 View3D *v3d = (View3D *)CTX_wm_space_data(C);
535                 RegionView3D *rv3d = ar->regiondata;
536
537                 /* init 3d depth buffers */
538                 view3d_operator_needs_opengl(C);
539
540                 view3d_region_operator_needs_opengl(win, ar);
541                 ED_view3d_autodist_init(depsgraph, ar, v3d, 0);
542
543                 /* for camera view set the subrect */
544                 if (rv3d->persp == RV3D_CAMOB) {
545                         ED_view3d_calc_camera_border(scene, CTX_data_depsgraph(C), ar, v3d, rv3d, &r_gsc->subrect_data, true);
546                         r_gsc->subrect = &r_gsc->subrect_data;
547                 }
548         }
549 }
550
551 /**
552  * Convert point to parent space
553  *
554  * \param pt: Original point
555  * \param diff_mat: Matrix with the difference between original parent matrix
556  * \param[out] r_pt: Pointer to new point after apply matrix
557  */
558 void gp_point_to_parent_space(const bGPDspoint *pt, const float diff_mat[4][4], bGPDspoint *r_pt)
559 {
560         float fpt[3];
561
562         mul_v3_m4v3(fpt, diff_mat, &pt->x);
563         copy_v3_v3(&r_pt->x, fpt);
564 }
565
566 /**
567  * Change position relative to parent object
568  */
569 void gp_apply_parent(Depsgraph *depsgraph, Object *obact, bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps)
570 {
571         bGPDspoint *pt;
572         int i;
573
574         /* undo matrix */
575         float diff_mat[4][4];
576         float inverse_diff_mat[4][4];
577         float fpt[3];
578
579         ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
580         invert_m4_m4(inverse_diff_mat, diff_mat);
581
582         for (i = 0; i < gps->totpoints; i++) {
583                 pt = &gps->points[i];
584                 mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x);
585                 copy_v3_v3(&pt->x, fpt);
586         }
587 }
588
589 /**
590  * Change point position relative to parent object
591  */
592 void gp_apply_parent_point(Depsgraph *depsgraph, Object *obact, bGPdata *gpd, bGPDlayer *gpl, bGPDspoint *pt)
593 {
594         /* undo matrix */
595         float diff_mat[4][4];
596         float inverse_diff_mat[4][4];
597         float fpt[3];
598
599         ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
600         invert_m4_m4(inverse_diff_mat, diff_mat);
601
602         mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x);
603         copy_v3_v3(&pt->x, fpt);
604 }
605
606 /**
607  * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D)
608  *
609  * \param[out] r_x  The screen-space x-coordinate of the point
610  * \param[out] r_y  The screen-space y-coordinate of the point
611  *
612  * \warning This assumes that the caller has already checked whether the stroke in question can be drawn.
613  */
614 void gp_point_to_xy(
615         const GP_SpaceConversion *gsc, const bGPDstroke *gps, const bGPDspoint *pt,
616         int *r_x, int *r_y)
617 {
618         const ARegion *ar = gsc->ar;
619         const View2D *v2d = gsc->v2d;
620         const rctf *subrect = gsc->subrect;
621         int xyval[2];
622
623         /* sanity checks */
624         BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->sa->spacetype == SPACE_VIEW3D));
625         BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->sa->spacetype != SPACE_VIEW3D));
626
627
628         if (gps->flag & GP_STROKE_3DSPACE) {
629                 if (ED_view3d_project_int_global(ar, &pt->x, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
630                         *r_x = xyval[0];
631                         *r_y = xyval[1];
632                 }
633                 else {
634                         *r_x = V2D_IS_CLIPPED;
635                         *r_y = V2D_IS_CLIPPED;
636                 }
637         }
638         else if (gps->flag & GP_STROKE_2DSPACE) {
639                 float vec[3] = {pt->x, pt->y, 0.0f};
640                 mul_m4_v3(gsc->mat, vec);
641                 UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], r_x, r_y);
642         }
643         else {
644                 if (subrect == NULL) {
645                         /* normal 3D view (or view space) */
646                         *r_x = (int)(pt->x / 100 * ar->winx);
647                         *r_y = (int)(pt->y / 100 * ar->winy);
648                 }
649                 else {
650                         /* camera view, use subrect */
651                         *r_x = (int)((pt->x / 100) * BLI_rctf_size_x(subrect)) + subrect->xmin;
652                         *r_y = (int)((pt->y / 100) * BLI_rctf_size_y(subrect)) + subrect->ymin;
653                 }
654         }
655 }
656
657 /**
658  * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D)
659  *
660  * Just like gp_point_to_xy(), except the resulting coordinates are floats not ints.
661  * Use this version to solve "stair-step" artifacts which may arise when roundtripping the calculations.
662  *
663  * \param r_x: [out] The screen-space x-coordinate of the point
664  * \param r_y: [out] The screen-space y-coordinate of the point
665  *
666  * \warning This assumes that the caller has already checked whether the stroke in question can be drawn
667  */
668 void gp_point_to_xy_fl(
669         const GP_SpaceConversion *gsc, const bGPDstroke *gps, const bGPDspoint *pt,
670         float *r_x, float *r_y)
671 {
672         const ARegion *ar = gsc->ar;
673         const View2D *v2d = gsc->v2d;
674         const rctf *subrect = gsc->subrect;
675         float xyval[2];
676
677         /* sanity checks */
678         BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->sa->spacetype == SPACE_VIEW3D));
679         BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->sa->spacetype != SPACE_VIEW3D));
680
681
682         if (gps->flag & GP_STROKE_3DSPACE) {
683                 if (ED_view3d_project_float_global(ar, &pt->x, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
684                         *r_x = xyval[0];
685                         *r_y = xyval[1];
686                 }
687                 else {
688                         *r_x = 0.0f;
689                         *r_y = 0.0f;
690                 }
691         }
692         else if (gps->flag & GP_STROKE_2DSPACE) {
693                 float vec[3] = {pt->x, pt->y, 0.0f};
694                 int t_x, t_y;
695
696                 mul_m4_v3(gsc->mat, vec);
697                 UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], &t_x, &t_y);
698
699                 if ((t_x == t_y) && (t_x == V2D_IS_CLIPPED)) {
700                         /* XXX: Or should we just always use the values as-is? */
701                         *r_x = 0.0f;
702                         *r_y = 0.0f;
703                 }
704                 else {
705                         *r_x = (float)t_x;
706                         *r_y = (float)t_y;
707                 }
708         }
709         else {
710                 if (subrect == NULL) {
711                         /* normal 3D view (or view space) */
712                         *r_x = (pt->x / 100.0f * ar->winx);
713                         *r_y = (pt->y / 100.0f * ar->winy);
714                 }
715                 else {
716                         /* camera view, use subrect */
717                         *r_x = ((pt->x / 100.0f) * BLI_rctf_size_x(subrect)) + subrect->xmin;
718                         *r_y = ((pt->y / 100.0f) * BLI_rctf_size_y(subrect)) + subrect->ymin;
719                 }
720         }
721 }
722
723
724 /**
725  * generic based on gp_point_to_xy_fl
726  */
727 void gp_point_3d_to_xy(const GP_SpaceConversion *gsc, const short flag, const float pt[3], float xy[2])
728 {
729         const ARegion *ar = gsc->ar;
730         const View2D *v2d = gsc->v2d;
731         const rctf *subrect = gsc->subrect;
732         float xyval[2];
733
734         /* sanity checks */
735         BLI_assert((gsc->sa->spacetype == SPACE_VIEW3D));
736
737         if (flag & GP_STROKE_3DSPACE) {
738                 if (ED_view3d_project_float_global(ar, pt, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
739                         xy[0] = xyval[0];
740                         xy[1] = xyval[1];
741                 }
742                 else {
743                         xy[0] = 0.0f;
744                         xy[1] = 0.0f;
745                 }
746         }
747         else if (flag & GP_STROKE_2DSPACE) {
748                 float vec[3] = { pt[0], pt[1], 0.0f };
749                 int t_x, t_y;
750
751                 mul_m4_v3(gsc->mat, vec);
752                 UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], &t_x, &t_y);
753
754                 if ((t_x == t_y) && (t_x == V2D_IS_CLIPPED)) {
755                         /* XXX: Or should we just always use the values as-is? */
756                         xy[0] = 0.0f;
757                         xy[1] = 0.0f;
758                 }
759                 else {
760                         xy[0] = (float)t_x;
761                         xy[1] = (float)t_y;
762                 }
763         }
764         else {
765                 if (subrect == NULL) {
766                         /* normal 3D view (or view space) */
767                         xy[0] = (pt[0] / 100.0f * ar->winx);
768                         xy[1] = (pt[1] / 100.0f * ar->winy);
769                 }
770                 else {
771                         /* camera view, use subrect */
772                         xy[0] = ((pt[0] / 100.0f) * BLI_rctf_size_x(subrect)) + subrect->xmin;
773                         xy[1] = ((pt[1] / 100.0f) * BLI_rctf_size_y(subrect)) + subrect->ymin;
774                 }
775         }
776 }
777
778
779 /**
780  * Project screenspace coordinates to 3D-space
781  *
782  * For use with editing tools where it is easier to perform the operations in 2D,
783  * and then later convert the transformed points back to 3D.
784  *
785  * \param screen_co: The screenspace 2D coordinates to convert to
786  * \param r_out: The resulting 3D coordinates of the input point
787  *
788  * \note We include this as a utility function, since the standard method
789  * involves quite a few steps, which are invariably always the same
790  * for all GPencil operations. So, it's nicer to just centralize these.
791  *
792  * \warning Assumes that it is getting called in a 3D view only.
793  */
794 bool gp_point_xy_to_3d(const GP_SpaceConversion *gsc, Scene *scene, const float screen_co[2], float r_out[3])
795 {
796         const RegionView3D *rv3d = gsc->ar->regiondata;
797         float rvec[3];
798
799         ED_gp_get_drawing_reference(
800                 scene, gsc->ob, gsc->gpl,
801                 scene->toolsettings->gpencil_v3d_align, rvec);
802
803         float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
804
805         float mval_f[2], mval_prj[2];
806         float dvec[3];
807
808         copy_v2_v2(mval_f, screen_co);
809
810         if (ED_view3d_project_float_global(gsc->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
811                 sub_v2_v2v2(mval_f, mval_prj, mval_f);
812                 ED_view3d_win_to_delta(gsc->ar, mval_f, dvec, zfac);
813                 sub_v3_v3v3(r_out, rvec, dvec);
814
815                 return true;
816         }
817         else {
818                 zero_v3(r_out);
819
820                 return false;
821         }
822 }
823
824 /**
825  * Convert tGPspoint (temporary 2D/screenspace point data used by GP modal operators)
826  * to 3D coordinates.
827  *
828  * \param point2D: The screenspace 2D point data to convert
829  * \param depth: Depth array (via ED_view3d_autodist_depth())
830  * \param[out] r_out: The resulting 2D point data
831  */
832 void gp_stroke_convertcoords_tpoint(
833         Scene *scene, ARegion *ar,
834         Object *ob, bGPDlayer *gpl,
835         const tGPspoint *point2D, float *depth,
836         float r_out[3])
837 {
838         ToolSettings *ts = scene->toolsettings;
839
840         int mval_i[2];
841         round_v2i_v2fl(mval_i, &point2D->x);
842
843         if ((depth != NULL) && (ED_view3d_autodist_simple(ar, mval_i, r_out, 0, depth))) {
844                 /* projecting onto 3D-Geometry
845                  * - nothing more needs to be done here, since view_autodist_simple() has already done it
846                  */
847         }
848         else {
849                 float mval_f[2] = {point2D->x, point2D->y};
850                 float mval_prj[2];
851                 float rvec[3], dvec[3];
852                 float zfac;
853
854                 /* Current method just converts each point in screen-coordinates to
855                  * 3D-coordinates using the 3D-cursor as reference.
856                  */
857                 ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, rvec);
858                 zfac = ED_view3d_calc_zfac(ar->regiondata, rvec, NULL);
859
860                 if (ED_view3d_project_float_global(ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
861                         sub_v2_v2v2(mval_f, mval_prj, mval_f);
862                         ED_view3d_win_to_delta(ar, mval_f, dvec, zfac);
863                         sub_v3_v3v3(r_out, rvec, dvec);
864                 }
865                 else {
866                         zero_v3(r_out);
867                 }
868         }
869 }
870
871 /**
872  * Get drawing reference point for conversion or projection of the stroke
873  * \param[out] r_vec : Reference point found
874  */
875 void ED_gp_get_drawing_reference(
876         const Scene *scene, const Object *ob, bGPDlayer *UNUSED(gpl),
877         char align_flag, float r_vec[3])
878 {
879         const float *fp = scene->cursor.location;
880
881         /* if using a gpencil object at cursor mode, can use the location of the object */
882         if (align_flag & GP_PROJECT_VIEWSPACE) {
883                 if (ob && (ob->type == OB_GPENCIL)) {
884                         /* fallback (no strokes) - use cursor or object location */
885                         if (align_flag & GP_PROJECT_CURSOR) {
886                                 /* use 3D-cursor */
887                                 copy_v3_v3(r_vec, fp);
888                         }
889                         else {
890                                 /* use object location */
891                                 copy_v3_v3(r_vec, ob->obmat[3]);
892                         }
893                 }
894         }
895         else {
896                 /* use 3D-cursor */
897                 copy_v3_v3(r_vec, fp);
898         }
899 }
900
901 void ED_gpencil_project_stroke_to_view(bContext *C, bGPDlayer *gpl, bGPDstroke *gps)
902 {
903         Scene *scene = CTX_data_scene(C);
904         Depsgraph *depsgraph = CTX_data_depsgraph(C);
905         Object *ob = CTX_data_active_object(C);
906         bGPdata *gpd = (bGPdata *)ob->data;
907         GP_SpaceConversion gsc = { NULL };
908
909         bGPDspoint *pt;
910         int i;
911         float diff_mat[4][4];
912         float inverse_diff_mat[4][4];
913
914         /* init space conversion stuff */
915         gp_point_conversion_init(C, &gsc);
916
917         ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, diff_mat);
918         invert_m4_m4(inverse_diff_mat, diff_mat);
919
920         /* Adjust each point */
921         for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
922                 float xy[2];
923
924                 bGPDspoint pt2;
925                 gp_point_to_parent_space(pt, diff_mat, &pt2);
926                 gp_point_to_xy_fl(&gsc, gps, &pt2, &xy[0], &xy[1]);
927
928                 /* Planar - All on same plane parallel to the viewplane */
929                 gp_point_xy_to_3d(&gsc, scene, xy, &pt->x);
930
931                 /* Unapply parent corrections */
932                 mul_m4_v3(inverse_diff_mat, &pt->x);
933         }
934 }
935
936 /**
937  * Reproject all points of the stroke to a plane locked to axis to avoid stroke offset
938  */
939 void ED_gp_project_stroke_to_plane(
940         const Object *ob, const RegionView3D *rv3d, bGPDstroke *gps, const float origin[3], const int axis)
941 {
942         float plane_normal[3];
943         float vn[3];
944
945         float ray[3];
946         float rpoint[3];
947
948         /* normal vector for a plane locked to axis */
949         zero_v3(plane_normal);
950         if (axis < 0) {
951                 /* if the axis is not locked, need a vector to the view direction
952                  * in order to get the right size of the stroke.
953                  */
954                 ED_view3d_global_to_vector(rv3d, origin, plane_normal);
955         }
956         else {
957                 plane_normal[axis] = 1.0f;
958                 /* if object, apply object rotation */
959                 if (ob && (ob->type == OB_GPENCIL)) {
960                         mul_mat3_m4_v3(ob->obmat, plane_normal);
961                 }
962         }
963
964         /* Reproject the points in the plane */
965         for (int i = 0; i < gps->totpoints; i++) {
966                 bGPDspoint *pt = &gps->points[i];
967
968                 /* get a vector from the point with the current view direction of the viewport */
969                 ED_view3d_global_to_vector(rv3d, &pt->x, vn);
970
971                 /* calculate line extreme point to create a ray that cross the plane */
972                 mul_v3_fl(vn, -50.0f);
973                 add_v3_v3v3(ray, &pt->x, vn);
974
975                 /* if the line never intersect, the point is not changed */
976                 if (isect_line_plane_v3(rpoint, &pt->x, ray, origin, plane_normal)) {
977                         copy_v3_v3(&pt->x, rpoint);
978                 }
979         }
980 }
981
982 /**
983  * Reproject given point to a plane locked to axis to avoid stroke offset
984  * \param[in, out] pt : Point to affect
985  */
986 void ED_gp_project_point_to_plane(
987         const Object *ob, const RegionView3D *rv3d, const float origin[3], const int axis, bGPDspoint *pt)
988 {
989         float plane_normal[3];
990         float vn[3];
991
992         float ray[3];
993         float rpoint[3];
994
995         /* normal vector for a plane locked to axis */
996         zero_v3(plane_normal);
997         if (axis < 0) {
998                 /* if the axis is not locked, need a vector to the view direction
999                  * in order to get the right size of the stroke.
1000                  */
1001                 ED_view3d_global_to_vector(rv3d, origin, plane_normal);
1002         }
1003         else {
1004                 plane_normal[axis] = 1.0f;
1005                 /* if object, apply object rotation */
1006                 if (ob && (ob->type == OB_GPENCIL)) {
1007                         mul_mat3_m4_v3(ob->obmat, plane_normal);
1008                 }
1009         }
1010
1011
1012         /* Reproject the points in the plane */
1013         /* get a vector from the point with the current view direction of the viewport */
1014         ED_view3d_global_to_vector(rv3d, &pt->x, vn);
1015
1016         /* calculate line extrem point to create a ray that cross the plane */
1017         mul_v3_fl(vn, -50.0f);
1018         add_v3_v3v3(ray, &pt->x, vn);
1019
1020         /* if the line never intersect, the point is not changed */
1021         if (isect_line_plane_v3(rpoint, &pt->x, ray, origin, plane_normal)) {
1022                 copy_v3_v3(&pt->x, rpoint);
1023         }
1024 }
1025
1026 /* ******************************************************** */
1027 /* Stroke Operations */
1028 // XXX: Check if these functions duplicate stuff in blenkernel, and/or whether we should just deduplicate
1029
1030 /**
1031  * Subdivide a stroke once, by adding a point half way between each pair of existing points
1032  * \param gps: Stroke data
1033  * \param subdivide: Number of times to subdivide
1034  */
1035 void gp_subdivide_stroke(bGPDstroke *gps, const int subdivide)
1036 {
1037         bGPDspoint *temp_points;
1038         int totnewpoints, oldtotpoints;
1039         int i2;
1040
1041         /* loop as many times as levels */
1042         for (int s = 0; s < subdivide; s++) {
1043                 totnewpoints = gps->totpoints - 1;
1044                 /* duplicate points in a temp area */
1045                 temp_points = MEM_dupallocN(gps->points);
1046                 oldtotpoints = gps->totpoints;
1047
1048                 /* resize the points arrays */
1049                 gps->totpoints += totnewpoints;
1050                 gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
1051                 if (gps->dvert != NULL) {
1052                         gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
1053                 }
1054                 gps->flag |= GP_STROKE_RECALC_GEOMETRY;
1055
1056                 /* move points from last to first to new place */
1057                 i2 = gps->totpoints - 1;
1058                 for (int i = oldtotpoints - 1; i > 0; i--) {
1059                         bGPDspoint *pt = &temp_points[i];
1060                         bGPDspoint *pt_final = &gps->points[i2];
1061
1062                         copy_v3_v3(&pt_final->x, &pt->x);
1063                         pt_final->pressure = pt->pressure;
1064                         pt_final->strength = pt->strength;
1065                         pt_final->time = pt->time;
1066                         pt_final->flag = pt->flag;
1067                         pt_final->uv_fac = pt->uv_fac;
1068                         pt_final->uv_rot = pt->uv_rot;
1069
1070                         if (gps->dvert != NULL) {
1071                                 MDeformVert *dvert = &gps->dvert[i];
1072                                 MDeformVert *dvert_final = &gps->dvert[i2];
1073
1074                                 dvert_final->totweight = dvert->totweight;
1075                                 dvert_final->dw = dvert->dw;
1076                         }
1077
1078                         i2 -= 2;
1079                 }
1080                 /* interpolate mid points */
1081                 i2 = 1;
1082                 for (int i = 0; i < oldtotpoints - 1; i++) {
1083                         bGPDspoint *pt = &temp_points[i];
1084                         bGPDspoint *next = &temp_points[i + 1];
1085                         bGPDspoint *pt_final = &gps->points[i2];
1086
1087                         /* add a half way point */
1088                         interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
1089                         pt_final->pressure = interpf(pt->pressure, next->pressure, 0.5f);
1090                         pt_final->strength = interpf(pt->strength, next->strength, 0.5f);
1091                         CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f);
1092                         pt_final->time = interpf(pt->time, next->time, 0.5f);
1093                         pt_final->uv_fac = interpf(pt->uv_fac, next->uv_fac, 0.5f);
1094                         pt_final->uv_rot = interpf(pt->uv_rot, next->uv_rot, 0.5f);
1095
1096                         if (gps->dvert != NULL) {
1097                                 MDeformVert *dvert_final = &gps->dvert[i2];
1098                                 dvert_final->totweight = 0;
1099                                 dvert_final->dw = NULL;
1100                         }
1101
1102                         i2 += 2;
1103                 }
1104
1105                 MEM_SAFE_FREE(temp_points);
1106
1107                 /* move points to smooth stroke */
1108                 /* duplicate points in a temp area with the new subdivide data */
1109                 temp_points = MEM_dupallocN(gps->points);
1110
1111                 /* extreme points are not changed */
1112                 for (int i = 0; i < gps->totpoints - 2; i++) {
1113                         bGPDspoint *pt = &temp_points[i];
1114                         bGPDspoint *next = &temp_points[i + 1];
1115                         bGPDspoint *pt_final = &gps->points[i + 1];
1116
1117                         /* move point */
1118                         interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
1119                 }
1120                 /* free temp memory */
1121                 MEM_SAFE_FREE(temp_points);
1122         }
1123 }
1124
1125 /**
1126  * Add randomness to stroke
1127  * \param gps: Stroke data
1128  * \param brush: Brush data
1129  */
1130 void gp_randomize_stroke(bGPDstroke *gps, Brush *brush, RNG *rng)
1131 {
1132         bGPDspoint *pt1, *pt2, *pt3;
1133         float v1[3];
1134         float v2[3];
1135         if (gps->totpoints < 3) {
1136                 return;
1137         }
1138
1139         /* get two vectors using 3 points */
1140         pt1 = &gps->points[0];
1141         pt2 = &gps->points[1];
1142         pt3 = &gps->points[(int)(gps->totpoints * 0.75)];
1143
1144         sub_v3_v3v3(v1, &pt2->x, &pt1->x);
1145         sub_v3_v3v3(v2, &pt3->x, &pt2->x);
1146         normalize_v3(v1);
1147         normalize_v3(v2);
1148
1149         /* get normal vector to plane created by two vectors */
1150         float normal[3];
1151         cross_v3_v3v3(normal, v1, v2);
1152         normalize_v3(normal);
1153
1154         /* get orthogonal vector to plane to rotate random effect */
1155         float ortho[3];
1156         cross_v3_v3v3(ortho, v1, normal);
1157         normalize_v3(ortho);
1158
1159         /* Read all points and apply shift vector (first and last point not modified) */
1160         for (int i = 1; i < gps->totpoints - 1; i++) {
1161                 bGPDspoint *pt = &gps->points[i];
1162                 /* get vector with shift (apply a division because random is too sensitive */
1163                 const float fac = BLI_rng_get_float(rng) * (brush->gpencil_settings->draw_random_sub / 10.0f);
1164                 float svec[3];
1165                 copy_v3_v3(svec, ortho);
1166                 if (BLI_rng_get_float(rng) > 0.5f) {
1167                         mul_v3_fl(svec, -fac);
1168                 }
1169                 else {
1170                         mul_v3_fl(svec, fac);
1171                 }
1172
1173                 /* apply shift */
1174                 add_v3_v3(&pt->x, svec);
1175         }
1176 }
1177
1178 /* ******************************************************** */
1179 /* Layer Parenting  - Compute Parent Transforms */
1180
1181 /* calculate difference matrix */
1182 void ED_gpencil_parent_location(
1183         const Depsgraph *depsgraph, Object *obact, bGPdata *UNUSED(gpd),
1184         bGPDlayer *gpl, float diff_mat[4][4])
1185 {
1186         Object *ob_eval = depsgraph != NULL ? DEG_get_evaluated_object(depsgraph, obact) : obact;
1187         Object *obparent = gpl->parent;
1188         Object *obparent_eval = depsgraph != NULL ? DEG_get_evaluated_object(depsgraph, obparent) : obparent;
1189
1190         /* if not layer parented, try with object parented */
1191         if (obparent_eval == NULL) {
1192                 if (ob_eval != NULL) {
1193                         if (ob_eval->type == OB_GPENCIL) {
1194                                 copy_m4_m4(diff_mat, ob_eval->obmat);
1195                                 return;
1196                         }
1197                 }
1198                 /* not gpencil object */
1199                 unit_m4(diff_mat);
1200                 return;
1201         }
1202         else {
1203                 if ((gpl->partype == PAROBJECT) || (gpl->partype == PARSKEL)) {
1204                         mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse);
1205                         return;
1206                 }
1207                 else if (gpl->partype == PARBONE) {
1208                         bPoseChannel *pchan = BKE_pose_channel_find_name(obparent_eval->pose, gpl->parsubstr);
1209                         if (pchan) {
1210                                 float tmp_mat[4][4];
1211                                 mul_m4_m4m4(tmp_mat, obparent_eval->obmat, pchan->pose_mat);
1212                                 mul_m4_m4m4(diff_mat, tmp_mat, gpl->inverse);
1213                         }
1214                         else {
1215                                 /* if bone not found use object (armature) */
1216                                 mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse);
1217                         }
1218                         return;
1219                 }
1220                 else {
1221                         unit_m4(diff_mat); /* not defined type */
1222                 }
1223         }
1224 }
1225
1226 /* reset parent matrix for all layers */
1227 void ED_gpencil_reset_layers_parent(Depsgraph *depsgraph, Object *obact, bGPdata *gpd)
1228 {
1229         bGPDspoint *pt;
1230         int i;
1231         float diff_mat[4][4];
1232         float cur_mat[4][4];
1233
1234         for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
1235                 if (gpl->parent != NULL) {
1236                         /* calculate new matrix */
1237                         if ((gpl->partype == PAROBJECT) || (gpl->partype == PARSKEL)) {
1238                                 invert_m4_m4(cur_mat, gpl->parent->obmat);
1239                         }
1240                         else if (gpl->partype == PARBONE) {
1241                                 bPoseChannel *pchan = BKE_pose_channel_find_name(gpl->parent->pose, gpl->parsubstr);
1242                                 if (pchan) {
1243                                         float tmp_mat[4][4];
1244                                         mul_m4_m4m4(tmp_mat, gpl->parent->obmat, pchan->pose_mat);
1245                                         invert_m4_m4(cur_mat, tmp_mat);
1246                                 }
1247                         }
1248
1249                         /* only redo if any change */
1250                         if (!equals_m4m4(gpl->inverse, cur_mat)) {
1251                                 /* first apply current transformation to all strokes */
1252                                 ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
1253                                 for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
1254                                         for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
1255                                                 for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
1256                                                         mul_m4_v3(diff_mat, &pt->x);
1257                                                 }
1258                                         }
1259                                 }
1260                                 /* set new parent matrix */
1261                                 copy_m4_m4(gpl->inverse, cur_mat);
1262                         }
1263                 }
1264         }
1265 }
1266 /* ******************************************************** */
1267 /* GP Object Stuff */
1268
1269 /* Helper function to create new OB_GPENCIL Object */
1270 Object *ED_gpencil_add_object(bContext *C, Scene *UNUSED(scene), const float loc[3], ushort local_view_bits)
1271 {
1272         float rot[3] = {0.0f};
1273
1274         Object *ob = ED_object_add_type(C, OB_GPENCIL, NULL, loc, rot, false, local_view_bits);
1275
1276         /* create default brushes and colors */
1277         ED_gpencil_add_defaults(C, ob);
1278
1279         return ob;
1280 }
1281
1282 /* Helper function to create default colors and drawing brushes */
1283 void ED_gpencil_add_defaults(bContext *C, Object *ob)
1284 {
1285         Main *bmain = CTX_data_main(C);
1286         ToolSettings *ts = CTX_data_tool_settings(C);
1287
1288         /* first try to reuse default material */
1289         if (ob->actcol > 0) {
1290                 Material *ma = give_current_material(ob, ob->actcol);
1291                 if ((ma) && (ma->gp_style == NULL)) {
1292                         BKE_material_init_gpencil_settings(ma);
1293                 }
1294         }
1295
1296         /* ensure color exist */
1297         BKE_gpencil_material_ensure(bmain, ob);
1298
1299         BKE_paint_ensure(ts, (Paint **)&ts->gp_paint);
1300         Paint *paint = &ts->gp_paint->paint;
1301         /* if not exist, create a new one */
1302         if (paint->brush == NULL) {
1303                 /* create new brushes */
1304                 BKE_brush_gpencil_presets(C);
1305         }
1306
1307         /* ensure multiframe falloff curve */
1308         if (ts->gp_sculpt.cur_falloff == NULL) {
1309                 ts->gp_sculpt.cur_falloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
1310                 CurveMapping *gp_falloff_curve = ts->gp_sculpt.cur_falloff;
1311                 curvemapping_initialize(gp_falloff_curve);
1312                 curvemap_reset(
1313                         gp_falloff_curve->cm,
1314                         &gp_falloff_curve->clipr,
1315                         CURVE_PRESET_GAUSS,
1316                         CURVEMAP_SLOPE_POSITIVE);
1317         }
1318 }
1319
1320 /* ******************************************************** */
1321 /* Vertex Groups */
1322
1323 /* assign points to vertex group */
1324 void ED_gpencil_vgroup_assign(bContext *C, Object *ob, float weight)
1325 {
1326         bGPdata *gpd = (bGPdata *)ob->data;
1327         const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
1328         const int def_nr = ob->actdef - 1;
1329         if (!BLI_findlink(&ob->defbase, def_nr))
1330                 return;
1331
1332         CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
1333         {
1334                 bGPDframe *init_gpf = gpl->actframe;
1335                 bGPDstroke *gps = NULL;
1336                 if (is_multiedit) {
1337                         init_gpf = gpl->frames.first;
1338                 }
1339
1340                 for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
1341                         if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
1342                                 if (gpf == NULL)
1343                                         continue;
1344
1345                                 for (gps = gpf->strokes.first; gps; gps = gps->next) {
1346
1347                                         /* skip strokes that are invalid for current view */
1348                                         if (ED_gpencil_stroke_can_use(C, gps) == false)
1349                                                 continue;
1350
1351                                         if (gps->flag & GP_STROKE_SELECT) {
1352                                                 /* verify the weight array is created */
1353                                                 BKE_gpencil_dvert_ensure(gps);
1354
1355                                                 for (int i = 0; i < gps->totpoints; i++) {
1356                                                         bGPDspoint *pt = &gps->points[i];
1357                                                         MDeformVert *dvert = &gps->dvert[i];
1358                                                         if (pt->flag & GP_SPOINT_SELECT) {
1359                                                                 MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
1360                                                                 if (dw) {
1361                                                                         dw->weight = weight;
1362                                                                 }
1363                                                         }
1364                                                 }
1365                                         }
1366                                 }
1367                         }
1368
1369                         /* if not multiedit, exit loop*/
1370                         if (!is_multiedit) {
1371                                 break;
1372                         }
1373                 }
1374         }
1375         CTX_DATA_END;
1376 }
1377
1378 /* remove points from vertex group */
1379 void ED_gpencil_vgroup_remove(bContext *C, Object *ob)
1380 {
1381         bGPdata *gpd = (bGPdata *)ob->data;
1382         const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
1383         const int def_nr = ob->actdef - 1;
1384         if (!BLI_findlink(&ob->defbase, def_nr))
1385                 return;
1386
1387         CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
1388         {
1389                 bGPDframe *init_gpf = gpl->actframe;
1390                 bGPDstroke *gps = NULL;
1391                 if (is_multiedit) {
1392                         init_gpf = gpl->frames.first;
1393                 }
1394
1395                 for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
1396                         if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
1397                                 if (gpf == NULL)
1398                                         continue;
1399
1400                                 for (gps = gpf->strokes.first; gps; gps = gps->next) {
1401
1402                                         /* skip strokes that are invalid for current view */
1403                                         if (ED_gpencil_stroke_can_use(C, gps) == false)
1404                                                 continue;
1405
1406                                         for (int i = 0; i < gps->totpoints; i++) {
1407                                                 bGPDspoint *pt = &gps->points[i];
1408                                                 if (gps->dvert == NULL) {
1409                                                         continue;
1410                                                 }
1411                                                 MDeformVert *dvert = &gps->dvert[i];
1412
1413                                                 if ((pt->flag & GP_SPOINT_SELECT) && (dvert->totweight > 0)) {
1414                                                         MDeformWeight *dw = defvert_find_index(dvert, def_nr);
1415                                                         if (dw != NULL) {
1416                                                                 defvert_remove_group(dvert, dw);
1417                                                         }
1418                                                 }
1419                                         }
1420                                 }
1421                         }
1422
1423                         /* if not multiedit, exit loop*/
1424                         if (!is_multiedit) {
1425                                 break;
1426                         }
1427                 }
1428         }
1429         CTX_DATA_END;
1430 }
1431
1432 /* select points of vertex group */
1433 void ED_gpencil_vgroup_select(bContext *C, Object *ob)
1434 {
1435         bGPdata *gpd = (bGPdata *)ob->data;
1436         const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
1437         const int def_nr = ob->actdef - 1;
1438         if (!BLI_findlink(&ob->defbase, def_nr))
1439                 return;
1440
1441         CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
1442         {
1443                 bGPDframe *init_gpf = gpl->actframe;
1444                 bGPDstroke *gps = NULL;
1445                 if (is_multiedit) {
1446                         init_gpf = gpl->frames.first;
1447                 }
1448
1449                 for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
1450                         if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
1451                                 if (gpf == NULL)
1452                                         continue;
1453
1454                                 for (gps = gpf->strokes.first; gps; gps = gps->next) {
1455
1456                                         /* skip strokes that are invalid for current view */
1457                                         if (ED_gpencil_stroke_can_use(C, gps) == false)
1458                                                 continue;
1459
1460                                         for (int i = 0; i < gps->totpoints; i++) {
1461                                                 bGPDspoint *pt = &gps->points[i];
1462                                                 if (gps->dvert == NULL) {
1463                                                         continue;
1464                                                 }
1465                                                 MDeformVert *dvert = &gps->dvert[i];
1466
1467                                                 if (defvert_find_index(dvert, def_nr) != NULL) {
1468                                                         pt->flag |= GP_SPOINT_SELECT;
1469                                                         gps->flag |= GP_STROKE_SELECT;
1470                                                 }
1471                                         }
1472                                 }
1473                         }
1474
1475                         /* if not multiedit, exit loop*/
1476                         if (!is_multiedit) {
1477                                 break;
1478                         }
1479                 }
1480         }
1481         CTX_DATA_END;
1482 }
1483
1484 /* unselect points of vertex group */
1485 void ED_gpencil_vgroup_deselect(bContext *C, Object *ob)
1486 {
1487         bGPdata *gpd = (bGPdata *)ob->data;
1488         const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
1489         const int def_nr = ob->actdef - 1;
1490         if (!BLI_findlink(&ob->defbase, def_nr))
1491                 return;
1492
1493         CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
1494         {
1495                 bGPDframe *init_gpf = gpl->actframe;
1496                 bGPDstroke *gps = NULL;
1497                 if (is_multiedit) {
1498                         init_gpf = gpl->frames.first;
1499                 }
1500
1501                 for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
1502                         if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
1503                                 if (gpf == NULL)
1504                                         continue;
1505
1506                                 for (gps = gpf->strokes.first; gps; gps = gps->next) {
1507
1508                                         /* skip strokes that are invalid for current view */
1509                                         if (ED_gpencil_stroke_can_use(C, gps) == false)
1510                                                 continue;
1511
1512                                         for (int i = 0; i < gps->totpoints; i++) {
1513                                                 bGPDspoint *pt = &gps->points[i];
1514                                                 if (gps->dvert == NULL) {
1515                                                         continue;
1516                                                 }
1517                                                 MDeformVert *dvert = &gps->dvert[i];
1518
1519                                                 if (defvert_find_index(dvert, def_nr) != NULL) {
1520                                                         pt->flag &= ~GP_SPOINT_SELECT;
1521                                                 }
1522                                         }
1523                                 }
1524                         }
1525
1526                         /* if not multiedit, exit loop*/
1527                         if (!is_multiedit) {
1528                                 break;
1529                         }
1530                 }
1531         }
1532         CTX_DATA_END;
1533 }
1534
1535 /* ******************************************************** */
1536 /* Cursor drawing */
1537
1538 /* check if cursor is in drawing region */
1539 static bool gp_check_cursor_region(bContext *C, int mval_i[2])
1540 {
1541         ARegion *ar = CTX_wm_region(C);
1542         ScrArea *sa = CTX_wm_area(C);
1543         Object *ob = CTX_data_active_object(C);
1544
1545         if ((ob == NULL) ||
1546             (!ELEM(ob->mode, OB_MODE_PAINT_GPENCIL, OB_MODE_SCULPT_GPENCIL, OB_MODE_WEIGHT_GPENCIL)))
1547         {
1548                 return false;
1549         }
1550
1551         /* TODO: add more spacetypes */
1552         if (!ELEM(sa->spacetype, SPACE_VIEW3D)) {
1553                 return false;
1554         }
1555         if ((ar) && (ar->regiontype != RGN_TYPE_WINDOW)) {
1556                 return false;
1557         }
1558         else if (ar) {
1559                 return BLI_rcti_isect_pt_v(&ar->winrct, mval_i);
1560         }
1561         else {
1562                 return false;
1563         }
1564 }
1565
1566 /* draw eraser cursor */
1567 void ED_gpencil_brush_draw_eraser(Brush *brush, int x, int y)
1568 {
1569         short radius = (short)brush->size;
1570
1571         GPUVertFormat *format = immVertexFormat();
1572         const uint shdr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1573         immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
1574
1575         glEnable(GL_LINE_SMOOTH);
1576         glEnable(GL_BLEND);
1577         glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1578
1579         immUniformColor4ub(255, 100, 100, 20);
1580         imm_draw_circle_fill_2d(shdr_pos, x, y, radius, 40);
1581
1582         immUnbindProgram();
1583
1584         immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
1585
1586         float viewport_size[4];
1587         glGetFloatv(GL_VIEWPORT, viewport_size);
1588         immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
1589
1590         immUniformColor4f(1.0f, 0.39f, 0.39f, 0.78f);
1591         immUniform1i("colors_len", 0);  /* "simple" mode */
1592         immUniform1f("dash_width", 12.0f);
1593         immUniform1f("dash_factor", 0.5f);
1594
1595         imm_draw_circle_wire_2d(
1596                 shdr_pos, x, y, radius,
1597                 /* XXX Dashed shader gives bad results with sets of small segments currently,
1598                  *     temp hack around the issue. :( */
1599                 max_ii(8, radius / 2));  /* was fixed 40 */
1600
1601         immUnbindProgram();
1602
1603         glDisable(GL_BLEND);
1604         glDisable(GL_LINE_SMOOTH);
1605 }
1606
1607 static bool gp_brush_cursor_poll(bContext *C)
1608 {
1609    if (WM_toolsystem_active_tool_is_brush(C)) {
1610        return true;
1611    }
1612    return false;
1613 }
1614
1615 /* Helper callback for drawing the cursor itself */
1616 static void gp_brush_cursor_draw(bContext *C, int x, int y, void *customdata)
1617 {
1618         Main *bmain = CTX_data_main(C);
1619         Scene *scene = CTX_data_scene(C);
1620         Object *ob = CTX_data_active_object(C);
1621         ARegion *ar = CTX_wm_region(C);
1622
1623         GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
1624         bGPdata *gpd = ED_gpencil_data_get_active(C);
1625         GP_Sculpt_Data *gp_brush = NULL;
1626         Brush *brush = NULL;
1627         Material *ma = NULL;
1628         MaterialGPencilStyle *gp_style = NULL;
1629         float *last_mouse_position = customdata;
1630
1631         if ((gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE)) {
1632                 gp_brush = &gset->brush[gset->weighttype];
1633         }
1634         else {
1635                 gp_brush = &gset->brush[gset->brushtype];
1636         }
1637
1638         /* default radius and color */
1639         float color[3] = {1.0f, 1.0f, 1.0f};
1640         float darkcolor[3];
1641         float radius = 3.0f;
1642
1643         int mval_i[2] = {x, y};
1644         /* check if cursor is in drawing region and has valid datablock */
1645         if ((!gp_check_cursor_region(C, mval_i)) || (gpd == NULL)) {
1646                 return;
1647         }
1648
1649         /* for paint use paint brush size and color */
1650         if (gpd->flag & GP_DATA_STROKE_PAINTMODE) {
1651                 brush = scene->toolsettings->gp_paint->paint.brush;
1652                 if ((brush == NULL) || (brush->gpencil_settings == NULL)) {
1653                         return;
1654                 }
1655
1656                 /* while drawing hide */
1657                 if ((gpd->runtime.sbuffer_size > 0) &&
1658                     ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
1659                     ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0))
1660                 {
1661                         return;
1662                 }
1663
1664                 if ((brush->gpencil_settings->flag & GP_BRUSH_ENABLE_CURSOR) == 0) {
1665                         return;
1666                 }
1667
1668                 /* eraser has special shape and use a different shader program */
1669                 if (brush->gpencil_tool == GPAINT_TOOL_ERASE) {
1670                         ED_gpencil_brush_draw_eraser(brush, x, y);
1671                         return;
1672                 }
1673
1674                 /* get current drawing color */
1675                 ma = BKE_gpencil_get_material_from_brush(brush);
1676                 if (ma == NULL) {
1677                         BKE_gpencil_material_ensure(bmain, ob);
1678                         /* assign the first material to the brush */
1679                         ma = give_current_material(ob, 1);
1680                         brush->gpencil_settings->material = ma;
1681                 }
1682                 gp_style = ma->gp_style;
1683
1684                 /* after some testing, display the size of the brush is not practical because
1685                  * is too disruptive and the size of cursor does not change with zoom factor.
1686                  * The decision was to use a fix size, instead of brush->thickness value.
1687                  */
1688                 if ((gp_style) && (GPENCIL_PAINT_MODE(gpd)) &&
1689                     ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
1690                     ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0) &&
1691                     (brush->gpencil_tool == GPAINT_TOOL_DRAW))
1692                 {
1693                         radius = 2.0f;
1694                         copy_v3_v3(color, gp_style->stroke_rgba);
1695                 }
1696                 else {
1697                         radius = 5.0f;
1698                         copy_v3_v3(color, brush->add_col);
1699                 }
1700         }
1701
1702         /* for sculpt use sculpt brush size */
1703         if (GPENCIL_SCULPT_OR_WEIGHT_MODE(gpd)) {
1704                 if (gp_brush) {
1705                         if ((gp_brush->flag & GP_SCULPT_FLAG_ENABLE_CURSOR) == 0) {
1706                                 return;
1707                         }
1708
1709                         radius = gp_brush->size;
1710                         if (gp_brush->flag & (GP_SCULPT_FLAG_INVERT | GP_SCULPT_FLAG_TMP_INVERT)) {
1711                                 copy_v3_v3(color, gp_brush->curcolor_sub);
1712                         }
1713                         else {
1714                                 copy_v3_v3(color, gp_brush->curcolor_add);
1715                         }
1716                 }
1717         }
1718
1719         /* draw icon */
1720         GPUVertFormat *format = immVertexFormat();
1721         uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1722         immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
1723
1724         glEnable(GL_LINE_SMOOTH);
1725         glEnable(GL_BLEND);
1726
1727         /* Inner Ring: Color from UI panel */
1728         immUniformColor4f(color[0], color[1], color[2], 0.8f);
1729         if ((gp_style) && (GPENCIL_PAINT_MODE(gpd)) &&
1730             ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
1731             ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0) &&
1732             (brush->gpencil_tool == GPAINT_TOOL_DRAW))
1733         {
1734                 imm_draw_circle_fill_2d(pos, x, y, radius, 40);
1735         }
1736         else {
1737                 imm_draw_circle_wire_2d(pos, x, y, radius, 40);
1738         }
1739
1740         /* Outer Ring: Dark color for contrast on light backgrounds (e.g. gray on white) */
1741         mul_v3_v3fl(darkcolor, color, 0.40f);
1742         immUniformColor4f(darkcolor[0], darkcolor[1], darkcolor[2], 0.8f);
1743         imm_draw_circle_wire_2d(pos, x, y, radius + 1, 40);
1744
1745         glDisable(GL_BLEND);
1746         glDisable(GL_LINE_SMOOTH);
1747
1748         /* Draw line for lazy mouse */
1749         if ((last_mouse_position) &&
1750             (brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP))
1751         {
1752                 glEnable(GL_LINE_SMOOTH);
1753                 glEnable(GL_BLEND);
1754
1755                 copy_v3_v3(color, brush->add_col);
1756                 immUniformColor4f(color[0], color[1], color[2], 0.8f);
1757
1758                 immBegin(GPU_PRIM_LINES, 2);
1759                 immVertex2f(pos, x, y);
1760                 immVertex2f(
1761                         pos,
1762                         last_mouse_position[0] + ar->winrct.xmin,
1763                         last_mouse_position[1] + ar->winrct.ymin);
1764                 immEnd();
1765
1766                 glDisable(GL_BLEND);
1767                 glDisable(GL_LINE_SMOOTH);
1768         }
1769
1770         immUnbindProgram();
1771 }
1772
1773 /* Turn brush cursor in on/off */
1774 void ED_gpencil_toggle_brush_cursor(bContext *C, bool enable, void *customdata)
1775 {
1776         Scene *scene = CTX_data_scene(C);
1777         GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
1778         float *lastpost = customdata;
1779
1780         if (gset->paintcursor && !enable) {
1781                 /* clear cursor */
1782                 WM_paint_cursor_end(CTX_wm_manager(C), gset->paintcursor);
1783                 gset->paintcursor = NULL;
1784         }
1785         else if (enable) {
1786                 /* in some situations cursor could be duplicated, so it is better disable first if exist */
1787                 if (gset->paintcursor) {
1788                         /* clear cursor */
1789                         WM_paint_cursor_end(CTX_wm_manager(C), gset->paintcursor);
1790                         gset->paintcursor = NULL;
1791                 }
1792                 /* enable cursor */
1793                 gset->paintcursor = WM_paint_cursor_activate(
1794                         CTX_wm_manager(C),
1795                         SPACE_TYPE_ANY, RGN_TYPE_ANY,
1796                         gp_brush_cursor_poll,
1797                         gp_brush_cursor_draw,
1798                         (lastpost) ? customdata : NULL);
1799         }
1800 }
1801
1802 /* verify if is using the right brush */
1803 static void gpencil_verify_brush_type(bContext *C, int newmode)
1804 {
1805         ToolSettings *ts = CTX_data_tool_settings(C);
1806         GP_Sculpt_Settings *gset = &ts->gp_sculpt;
1807
1808         switch (newmode) {
1809                 case OB_MODE_SCULPT_GPENCIL:
1810                         gset->flag &= ~GP_SCULPT_SETT_FLAG_WEIGHT_MODE;
1811                         if ((gset->brushtype < 0) || (gset->brushtype >= GP_SCULPT_TYPE_WEIGHT)) {
1812                                 gset->brushtype = GP_SCULPT_TYPE_PUSH;
1813                         }
1814                         break;
1815                 case OB_MODE_WEIGHT_GPENCIL:
1816                         gset->flag |= GP_SCULPT_SETT_FLAG_WEIGHT_MODE;
1817                         if ((gset->weighttype < GP_SCULPT_TYPE_WEIGHT) || (gset->weighttype >= GP_SCULPT_TYPE_MAX)) {
1818                                 gset->weighttype = GP_SCULPT_TYPE_WEIGHT;
1819                         }
1820                         break;
1821                 default:
1822                         break;
1823         }
1824 }
1825
1826 /* set object modes */
1827 void ED_gpencil_setup_modes(bContext *C, bGPdata *gpd, int newmode)
1828 {
1829         if (!gpd) {
1830                 return;
1831         }
1832
1833         switch (newmode) {
1834                 case OB_MODE_EDIT_GPENCIL:
1835                         gpd->flag |= GP_DATA_STROKE_EDITMODE;
1836                         gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
1837                         gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
1838                         gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
1839                         ED_gpencil_toggle_brush_cursor(C, false, NULL);
1840                         break;
1841                 case OB_MODE_PAINT_GPENCIL:
1842                         gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
1843                         gpd->flag |= GP_DATA_STROKE_PAINTMODE;
1844                         gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
1845                         gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
1846                         ED_gpencil_toggle_brush_cursor(C, true, NULL);
1847                         break;
1848                 case OB_MODE_SCULPT_GPENCIL:
1849                         gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
1850                         gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
1851                         gpd->flag |= GP_DATA_STROKE_SCULPTMODE;
1852                         gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
1853                         gpencil_verify_brush_type(C, OB_MODE_SCULPT_GPENCIL);
1854                         ED_gpencil_toggle_brush_cursor(C, true, NULL);
1855                         break;
1856                 case OB_MODE_WEIGHT_GPENCIL:
1857                         gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
1858                         gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
1859                         gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
1860                         gpd->flag |= GP_DATA_STROKE_WEIGHTMODE;
1861                         gpencil_verify_brush_type(C, OB_MODE_WEIGHT_GPENCIL);
1862                         ED_gpencil_toggle_brush_cursor(C, true, NULL);
1863                         break;
1864                 default:
1865                         gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
1866                         gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
1867                         gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
1868                         gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
1869                         ED_gpencil_toggle_brush_cursor(C, false, NULL);
1870                         break;
1871         }
1872 }
1873
1874 /* helper to convert 2d to 3d for simple drawing buffer */
1875 static void gpencil_stroke_convertcoords(ARegion *ar, const tGPspoint *point2D, float origin[3], float out[3])
1876 {
1877         float mval_f[2] = { (float)point2D->x, (float)point2D->y };
1878         float mval_prj[2];
1879         float rvec[3], dvec[3];
1880         float zfac;
1881
1882         copy_v3_v3(rvec, origin);
1883
1884         zfac = ED_view3d_calc_zfac(ar->regiondata, rvec, NULL);
1885
1886         if (ED_view3d_project_float_global(ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
1887                 sub_v2_v2v2(mval_f, mval_prj, mval_f);
1888                 ED_view3d_win_to_delta(ar, mval_f, dvec, zfac);
1889                 sub_v3_v3v3(out, rvec, dvec);
1890         }
1891         else {
1892                 zero_v3(out);
1893         }
1894 }
1895
1896 /* convert 2d tGPspoint to 3d bGPDspoint */
1897 void ED_gpencil_tpoint_to_point(ARegion *ar, float origin[3], const tGPspoint *tpt, bGPDspoint *pt)
1898 {
1899         float p3d[3];
1900         /* conversion to 3d format */
1901         gpencil_stroke_convertcoords(ar, tpt, origin, p3d);
1902         copy_v3_v3(&pt->x, p3d);
1903
1904         pt->pressure = tpt->pressure;
1905         pt->strength = tpt->strength;
1906         pt->uv_fac = tpt->uv_fac;
1907         pt->uv_rot = tpt->uv_rot;
1908 }
1909
1910 /* texture coordinate utilities */
1911 void ED_gpencil_calc_stroke_uv(Object *ob, bGPDstroke *gps)
1912 {
1913         if (gps == NULL) {
1914                 return;
1915         }
1916         MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
1917         float pixsize;
1918         if (gp_style) {
1919                 pixsize = gp_style->texture_pixsize / 1000000.0f;
1920         }
1921         else {
1922                 /* use this value by default */
1923                 pixsize = 0.0001f;
1924         }
1925         pixsize = MAX2(pixsize, 0.0000001f);
1926
1927         bGPDspoint *pt = NULL;
1928         bGPDspoint *ptb = NULL;
1929         int i;
1930         float totlen = 0.0f;
1931
1932         /* first read all points and calc distance */
1933         for (i = 0; i < gps->totpoints; i++) {
1934                 pt = &gps->points[i];
1935                 /* first point */
1936                 if (i == 0) {
1937                         pt->uv_fac = 0.0f;
1938                         continue;
1939                 }
1940
1941                 ptb = &gps->points[i - 1];
1942                 totlen += len_v3v3(&pt->x, &ptb->x) / pixsize;
1943                 pt->uv_fac = totlen;
1944         }
1945
1946         /* normalize the distance using a factor */
1947         float factor;
1948
1949         /* if image, use texture width */
1950         if ((gp_style) && (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) &&
1951             (gp_style->sima))
1952         {
1953                 factor = gp_style->sima->gen_x;
1954         }
1955         else if (totlen == 0) {
1956                 return;
1957         }
1958         else {
1959                 factor = totlen;
1960         }
1961
1962         for (i = 0; i < gps->totpoints; i++) {
1963                 pt = &gps->points[i];
1964                 pt->uv_fac /= factor;
1965         }
1966 }
1967
1968 /* recalc uv for any stroke using the material */
1969 void ED_gpencil_update_color_uv(Main *bmain, Material *mat)
1970 {
1971         Material *gps_ma = NULL;
1972         /* read all strokes  */
1973         for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
1974                 if (ob->type == OB_GPENCIL) {
1975                         bGPdata *gpd = ob->data;
1976                         if (gpd == NULL) {
1977                                 continue;
1978                         }
1979
1980                         for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
1981                                 /* only editable and visible layers are considered */
1982                                 if (gpencil_layer_is_editable(gpl)) {
1983                                         for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
1984                                                 for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
1985                                                         /* check if it is editable */
1986                                                         if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
1987                                                                 continue;
1988                                                         }
1989                                                         gps_ma = give_current_material(ob, gps->mat_nr + 1);
1990                                                         /* update */
1991                                                         if ((gps_ma) && (gps_ma == mat)) {
1992                                                                 ED_gpencil_calc_stroke_uv(ob, gps);
1993                                                         }
1994                                                 }
1995                                         }
1996                                 }
1997                         }
1998                         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
1999                 }
2000         }
2001 }
2002
2003 static bool gpencil_check_collision(
2004         bGPDstroke *gps, bGPDstroke **gps_array, GHash *all_2d,
2005         int totstrokes, float p2d_a1[2], float p2d_a2[2], float r_hit[2])
2006 {
2007         bool hit = false;
2008         /* check segment with all segments of all strokes */
2009         for (int s = 0; s < totstrokes; s++) {
2010                 bGPDstroke *gps_iter = gps_array[s];
2011                 if (gps_iter->totpoints < 2) {
2012                         continue;
2013                 }
2014                 /* get stroke 2d version */
2015                 float(*points2d)[2] = BLI_ghash_lookup(all_2d, gps_iter);
2016
2017                 for (int i2 = 0; i2 < gps_iter->totpoints - 1; i2++) {
2018                         float p2d_b1[2], p2d_b2[2];
2019                         copy_v2_v2(p2d_b1, points2d[i2]);
2020                         copy_v2_v2(p2d_b2, points2d[i2 + 1]);
2021
2022                         /* don't self check */
2023                         if (gps == gps_iter) {
2024                                 if (equals_v2v2(p2d_a1, p2d_b1) || equals_v2v2(p2d_a1, p2d_b2)) {
2025                                         continue;
2026                                 }
2027                                 if (equals_v2v2(p2d_a2, p2d_b1) || equals_v2v2(p2d_a2, p2d_b2)) {
2028                                         continue;
2029                                 }
2030                         }
2031                         /* check collision */
2032                         int check = isect_seg_seg_v2_point(p2d_a1, p2d_a2, p2d_b1, p2d_b2, r_hit);
2033                         if (check > 0) {
2034                                 hit = true;
2035                                 break;
2036                         }
2037                 }
2038
2039                 if (hit) {
2040                         break;
2041                 }
2042         }
2043
2044         if (!hit) {
2045                 zero_v2(r_hit);
2046         }
2047
2048         return hit;
2049 }
2050
2051 static void gp_copy_points(
2052         bGPDstroke *gps, bGPDspoint *pt, bGPDspoint *pt_final, int i, int i2)
2053 {
2054         /* don't copy same point */
2055         if (i == i2) {
2056                 return;
2057         }
2058
2059         copy_v3_v3(&pt_final->x, &pt->x);
2060         pt_final->pressure = pt->pressure;
2061         pt_final->strength = pt->strength;
2062         pt_final->time = pt->time;
2063         pt_final->flag = pt->flag;
2064         pt_final->uv_fac = pt->uv_fac;
2065         pt_final->uv_rot = pt->uv_rot;
2066
2067         if (gps->dvert != NULL) {
2068                 MDeformVert *dvert = &gps->dvert[i];
2069                 MDeformVert *dvert_final = &gps->dvert[i2];
2070                 MEM_SAFE_FREE(dvert_final->dw);
2071
2072                 dvert_final->totweight = dvert->totweight;
2073                 if (dvert->dw == NULL) {
2074                         dvert_final->dw = NULL;
2075                         dvert_final->totweight = 0;
2076                 }
2077                 else {
2078                         dvert_final->dw = MEM_dupallocN(dvert->dw);
2079                 }
2080         }
2081
2082 }
2083
2084 static void gp_insert_point(
2085         bGPDstroke *gps,
2086         bGPDspoint *a_pt, bGPDspoint *b_pt,
2087         float co_a[3], float co_b[3])
2088 {
2089         bGPDspoint *temp_points;
2090         int totnewpoints, oldtotpoints;
2091
2092         totnewpoints = gps->totpoints;
2093         if (a_pt) {
2094                 totnewpoints++;
2095         }
2096         if (b_pt) {
2097                 totnewpoints++;
2098         }
2099
2100         /* duplicate points in a temp area */
2101         temp_points = MEM_dupallocN(gps->points);
2102         oldtotpoints = gps->totpoints;
2103
2104         /* look index of base points because memory is changed when resize points array */
2105         int a_idx = -1;
2106         int b_idx = -1;
2107         for (int i = 0; i < oldtotpoints; i++) {
2108                 bGPDspoint *pt = &gps->points[i];
2109                 if (pt == a_pt) {
2110                         a_idx = i;
2111                 }
2112                 if (pt == b_pt) {
2113                         b_idx = i;
2114                 }
2115         }
2116
2117         /* resize the points arrays */
2118         gps->totpoints = totnewpoints;
2119         gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
2120         if (gps->dvert != NULL) {
2121                 gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
2122         }
2123         gps->flag |= GP_STROKE_RECALC_GEOMETRY;
2124
2125         /* copy all points */
2126         int i2 = 0;
2127         for (int i = 0; i < oldtotpoints; i++) {
2128                 bGPDspoint *pt = &temp_points[i];
2129                 bGPDspoint *pt_final = &gps->points[i2];
2130                 gp_copy_points(gps, pt, pt_final, i, i2);
2131
2132                 /* create new point duplicating point and copy location */
2133                 if ((i == a_idx) || (i == b_idx)) {
2134                         i2++;
2135                         pt_final = &gps->points[i2];
2136                         gp_copy_points(gps, pt, pt_final, i, i2);
2137                         copy_v3_v3(&pt_final->x, (i == a_idx) ? co_a : co_b);
2138
2139                         /* unselect */
2140                         pt_final->flag &= ~GP_SPOINT_SELECT;
2141                         /* tag to avoid more checking with this point */
2142                         pt_final->flag |= GP_SPOINT_TAG;
2143                 }
2144
2145                 i2++;
2146         }
2147
2148         MEM_SAFE_FREE(temp_points);
2149 }
2150
2151 static float gp_calc_factor(float p2d_a1[2], float p2d_a2[2], float r_hit2d[2])
2152 {
2153         float dist1 = len_squared_v2v2(p2d_a1, p2d_a2);
2154         float dist2 = len_squared_v2v2(p2d_a1, r_hit2d);
2155         float f = dist1 > 0.0f ? dist2 / dist1 : 0.0f;
2156
2157         /* apply a correction factor */
2158         float v1[2];
2159         interp_v2_v2v2(v1, p2d_a1, p2d_a2, f);
2160         float dist3 = len_squared_v2v2(p2d_a1, v1);
2161         float f1 = dist1 > 0.0f ? dist3 / dist1 : 0.0f;
2162         f = f + (f - f1);
2163
2164         return f;
2165 }
2166
2167 /* extend selection to stroke intersections */
2168 int ED_gpencil_select_stroke_segment(
2169         bGPDlayer *gpl, bGPDstroke *gps, bGPDspoint *pt,
2170         bool select, bool insert, const float scale,
2171         float r_hita[3], float r_hitb[3])
2172 {
2173         const float min_factor = 0.0015f;
2174         bGPDspoint *pta1 = NULL;
2175         bGPDspoint *pta2 = NULL;
2176         float f = 0.0f;
2177         int i2 = 0;
2178
2179         bGPDframe *gpf = gpl->actframe;
2180         if (gpf == NULL) {
2181                 return 0;
2182         }
2183
2184         int memsize = BLI_listbase_count(&gpf->strokes);
2185         bGPDstroke **gps_array = MEM_callocN(sizeof(bGPDstroke *) * memsize, __func__);
2186
2187         /* save points */
2188         bGPDspoint *oldpoints = MEM_dupallocN(gps->points);
2189
2190         /* Save list of strokes to check */
2191         int totstrokes = 0;
2192         for (bGPDstroke *gps_iter = gpf->strokes.first; gps_iter; gps_iter = gps_iter->next) {
2193                 if (gps_iter->totpoints < 2) {
2194                         continue;
2195                 }
2196                 gps_array[totstrokes] = gps_iter;
2197                 totstrokes++;
2198         }
2199
2200         if (totstrokes == 0) {
2201                 return 0;
2202         }
2203
2204         /* look for index of the current point */
2205         int cur_idx = -1;
2206         for (int i = 0; i < gps->totpoints; i++) {
2207                 pta1 = &gps->points[i];
2208                 if (pta1 == pt) {
2209                         cur_idx = i;
2210                         break;
2211                 }
2212         }
2213         if (cur_idx < 0) {
2214                 return 0;
2215         }
2216
2217         /* convert all gps points to 2d and save in a hash to avoid recalculation  */
2218         int direction = 0;
2219         float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints, "GP Stroke temp 2d points");
2220         BKE_gpencil_stroke_2d_flat_ref(
2221                 gps->points, gps->totpoints,
2222                 gps->points, gps->totpoints, points2d, scale, &direction);
2223
2224         GHash *all_2d = BLI_ghash_ptr_new(__func__);
2225
2226         for (int s = 0; s < totstrokes; s++) {
2227                 bGPDstroke *gps_iter = gps_array[s];
2228                 float(*points2d_iter)[2] = MEM_mallocN(sizeof(*points2d_iter) * gps_iter->totpoints, __func__);
2229
2230                 /* the extremes of the stroke are scaled to improve collision detection
2231                  * for near lines */
2232                 BKE_gpencil_stroke_2d_flat_ref(
2233                         gps->points, gps->totpoints,
2234                         gps_iter->points, gps_iter->totpoints, points2d_iter,
2235                         scale, &direction);
2236                 BLI_ghash_insert(all_2d, gps_iter, points2d_iter);
2237         }
2238
2239         bool hit_a = false;
2240         bool hit_b = false;
2241         float p2d_a1[2] = {0.0f, 0.0f};
2242         float p2d_a2[2] = {0.0f, 0.0f};
2243         float r_hit2d[2];
2244         bGPDspoint *hit_pointa = NULL;
2245         bGPDspoint *hit_pointb = NULL;
2246
2247         /* analyze points before current */
2248         if (cur_idx > 0) {
2249                 for (int i = cur_idx; i >= 0; i--) {
2250                         pta1 = &gps->points[i];
2251                         copy_v2_v2(p2d_a1, points2d[i]);
2252
2253                         i2 = i - 1;
2254                         CLAMP_MIN(i2, 0);
2255                         pta2 = &gps->points[i2];
2256                         copy_v2_v2(p2d_a2, points2d[i2]);
2257
2258                         hit_a = gpencil_check_collision(
2259                                 gps, gps_array, all_2d, totstrokes, p2d_a1, p2d_a2, r_hit2d);
2260
2261                         if (select) {
2262                                 pta1->flag |= GP_SPOINT_SELECT;
2263                         }
2264                         else {
2265                                 pta1->flag &= ~GP_SPOINT_SELECT;
2266                         }
2267
2268                         if (hit_a) {
2269                                 f = gp_calc_factor(p2d_a1, p2d_a2, r_hit2d);
2270                                 interp_v3_v3v3(r_hita, &pta1->x, &pta2->x, f);
2271                                 if (f > min_factor) {
2272                                         hit_pointa = pta2; /* first point is second (inverted loop) */
2273                                 }
2274                                 else {
2275                                         pta1->flag &= ~GP_SPOINT_SELECT;
2276                                 }
2277                                 break;
2278                         }
2279                 }
2280         }
2281
2282         /* analyze points after current */
2283         for (int i = cur_idx; i < gps->totpoints; i++) {
2284                 pta1 = &gps->points[i];
2285                 copy_v2_v2(p2d_a1, points2d[i]);
2286
2287                 i2 = i + 1;
2288                 CLAMP_MAX(i2, gps->totpoints - 1);
2289                 pta2 = &gps->points[i2];
2290                 copy_v2_v2(p2d_a2, points2d[i2]);
2291
2292                 hit_b = gpencil_check_collision(
2293                         gps, gps_array, all_2d, totstrokes, p2d_a1, p2d_a2, r_hit2d);
2294
2295                 if (select) {
2296                         pta1->flag |= GP_SPOINT_SELECT;
2297                 }
2298                 else {
2299                         pta1->flag &= ~GP_SPOINT_SELECT;
2300                 }
2301
2302                 if (hit_b) {
2303                         f = gp_calc_factor(p2d_a1, p2d_a2, r_hit2d);
2304                         interp_v3_v3v3(r_hitb, &pta1->x, &pta2->x, f);
2305                         if (f > min_factor) {
2306                                 hit_pointb = pta1;
2307                         }
2308                         else {
2309                                 pta1->flag &= ~GP_SPOINT_SELECT;
2310                         }
2311                         break;
2312                 }
2313         }
2314
2315         /* insert new point in the collision points */
2316         if (insert) {
2317                 gp_insert_point(gps, hit_pointa, hit_pointb, r_hita, r_hitb);
2318         }
2319
2320         /* free memory */
2321         if (all_2d) {
2322                 GHashIterator gh_iter;
2323                 GHASH_ITER(gh_iter, all_2d) {
2324                         float(*p2d)[2] = BLI_ghashIterator_getValue(&gh_iter);
2325                         MEM_SAFE_FREE(p2d);
2326                 }
2327                 BLI_ghash_free(all_2d, NULL, NULL);
2328         }
2329
2330         /* if no hit, reset selection flag */
2331         if ((!hit_a) && (!hit_b)) {
2332                 for (int i = 0; i < gps->totpoints; i++) {
2333                         pta1 = &gps->points[i];
2334                         pta2 = &oldpoints[i];
2335                         pta1->flag = pta2->flag;
2336                 }
2337         }
2338
2339         MEM_SAFE_FREE(points2d);
2340         MEM_SAFE_FREE(gps_array);
2341         MEM_SAFE_FREE(oldpoints);
2342
2343         /* return type of hit */
2344         if ((hit_a) && (hit_b)) {
2345                 return 3;
2346         }
2347         else if (hit_a) {
2348                 return 1;
2349         }
2350         else if (hit_b) {
2351                 return 2;
2352         }
2353         else {
2354                 return 0;
2355         }
2356 }
2357
2358 void ED_gpencil_select_toggle_all(bContext *C, int action)
2359 {
2360         /* for "toggle", test for existing selected strokes */
2361         if (action == SEL_TOGGLE) {
2362                 action = SEL_SELECT;
2363
2364                 CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
2365                 {
2366                         if (gps->flag & GP_STROKE_SELECT) {
2367                                 action = SEL_DESELECT;
2368                                 break; // XXX: this only gets out of the inner loop...
2369                         }
2370                 }
2371                 CTX_DATA_END;
2372         }
2373
2374         /* if deselecting, we need to deselect strokes across all frames
2375          * - Currently, an exception is only given for deselection
2376          *   Selecting and toggling should only affect what's visible,
2377          *   while deselecting helps clean up unintended/forgotten
2378          *   stuff on other frames
2379          */
2380         if (action == SEL_DESELECT) {
2381                 /* deselect strokes across editable layers
2382                  * NOTE: we limit ourselves to editable layers, since once a layer is "locked/hidden
2383                  *       nothing should be able to touch it
2384                  */
2385                 CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
2386                 {
2387                         bGPDframe *gpf;
2388
2389                         /* deselect all strokes on all frames */
2390                         for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
2391                                 bGPDstroke *gps;
2392
2393                                 for (gps = gpf->strokes.first; gps; gps = gps->next) {
2394                                         bGPDspoint *pt;
2395                                         int i;
2396
2397                                         /* only edit strokes that are valid in this view... */
2398                                         if (ED_gpencil_stroke_can_use(C, gps)) {
2399                                                 for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
2400                                                         pt->flag &= ~GP_SPOINT_SELECT;
2401                                                 }
2402
2403                                                 gps->flag &= ~GP_STROKE_SELECT;
2404                                         }
2405                                 }
2406                         }
2407                 }
2408                 CTX_DATA_END;
2409         }
2410         else {
2411                 /* select or deselect all strokes */
2412                 CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
2413                 {
2414                         bGPDspoint *pt;
2415                         int i;
2416                         bool selected = false;
2417
2418                         /* Change selection status of all points, then make the stroke match */
2419                         for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
2420                                 switch (action) {
2421                                         case SEL_SELECT:
2422                                                 pt->flag |= GP_SPOINT_SELECT;
2423                                                 break;
2424                                         //case SEL_DESELECT:
2425                                         //      pt->flag &= ~GP_SPOINT_SELECT;
2426                                         //      break;
2427                                         case SEL_INVERT:
2428                                                 pt->flag ^= GP_SPOINT_SELECT;
2429                                                 break;
2430                                 }
2431
2432                                 if (pt->flag & GP_SPOINT_SELECT)
2433                                         selected = true;
2434                         }
2435
2436                         /* Change status of stroke */
2437                         if (selected)
2438                                 gps->flag |= GP_STROKE_SELECT;
2439                         else
2440                                 gps->flag &= ~GP_STROKE_SELECT;
2441                 }
2442                 CTX_DATA_END;
2443         }
2444 }