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