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