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