Blender  V3.3
gpencil_utils.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2014 Blender Foundation. */
3 
8 #include <math.h>
9 #include <stddef.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 
14 #include "MEM_guardedalloc.h"
15 
16 #include "BLI_blenlib.h"
17 #include "BLI_ghash.h"
18 #include "BLI_hash.h"
19 #include "BLI_lasso_2d.h"
20 #include "BLI_math.h"
21 #include "BLI_rand.h"
22 #include "BLI_utildefines.h"
23 #include "BLT_translation.h"
24 
25 #include "PIL_time.h"
26 
27 #include "DNA_brush_types.h"
28 #include "DNA_collection_types.h"
29 #include "DNA_gpencil_types.h"
30 #include "DNA_material_types.h"
31 #include "DNA_meshdata_types.h"
32 #include "DNA_object_types.h"
33 #include "DNA_scene_types.h"
34 #include "DNA_screen_types.h"
35 #include "DNA_space_types.h"
36 #include "DNA_view3d_types.h"
37 
38 #include "BKE_action.h"
39 #include "BKE_brush.h"
40 #include "BKE_collection.h"
41 #include "BKE_colortools.h"
42 #include "BKE_context.h"
43 #include "BKE_deform.h"
44 #include "BKE_gpencil.h"
45 #include "BKE_gpencil_curve.h"
46 #include "BKE_gpencil_geom.h"
47 #include "BKE_main.h"
48 #include "BKE_material.h"
49 #include "BKE_object.h"
50 #include "BKE_paint.h"
51 #include "BKE_tracking.h"
52 
53 #include "WM_api.h"
54 #include "WM_toolsystem.h"
55 #include "WM_types.h"
56 
57 #include "RNA_access.h"
58 #include "RNA_define.h"
59 #include "RNA_enum_types.h"
60 #include "RNA_prototypes.h"
61 
62 #include "UI_resources.h"
63 #include "UI_view2d.h"
64 
65 #include "ED_clip.h"
66 #include "ED_gpencil.h"
67 #include "ED_object.h"
68 #include "ED_screen.h"
69 #include "ED_select_utils.h"
71 #include "ED_view3d.h"
72 
73 #include "GPU_immediate.h"
74 #include "GPU_immediate_util.h"
75 #include "GPU_state.h"
76 
77 #include "DEG_depsgraph.h"
78 #include "DEG_depsgraph_query.h"
79 
80 #include "gpencil_intern.h"
81 
82 /* ******************************************************** */
83 /* Context Wrangling... */
84 
86 {
87  /* if there's an active area, check if the particular editor may
88  * have defined any special Grease Pencil context for editing...
89  */
90  if (area) {
91  switch (area->spacetype) {
92  case SPACE_PROPERTIES: /* properties */
93  case SPACE_INFO: /* header info */
94  case SPACE_TOPBAR: /* Top-bar */
95  case SPACE_VIEW3D: /* 3D-View */
96  {
97  if (ob && (ob->type == OB_GPENCIL)) {
98  /* GP Object. */
99  if (r_ptr) {
100  RNA_id_pointer_create(&ob->id, r_ptr);
101  }
102  return (bGPdata **)&ob->data;
103  }
104  return NULL;
105  }
106  default: /* Unsupported space. */
107  return NULL;
108  }
109  }
110 
111  return NULL;
112 }
113 
115  ScrArea *area,
116  Scene *scene,
117  PointerRNA *r_ptr)
118 {
119  /* If there's an active area, check if the particular editor may
120  * have defined any special Grease Pencil context for editing. */
121  if (area) {
122  SpaceLink *sl = area->spacedata.first;
123 
124  switch (area->spacetype) {
125  case SPACE_PROPERTIES: /* properties */
126  case SPACE_INFO: /* header info */
127  {
128  return NULL;
129  }
130 
131  case SPACE_TOPBAR: /* Top-bar */
132  case SPACE_VIEW3D: /* 3D-View */
133  {
134  if (r_ptr) {
135  RNA_id_pointer_create(&scene->id, r_ptr);
136  }
137  return &scene->gpd;
138 
139  break;
140  }
141  case SPACE_NODE: /* Nodes Editor */
142  {
143  SpaceNode *snode = (SpaceNode *)sl;
144 
145  /* return the GP data for the active node block/node */
146  if (snode && snode->nodetree) {
147  /* for now, as long as there's an active node tree,
148  * default to using that in the Nodes Editor */
149  if (r_ptr) {
150  RNA_id_pointer_create(&snode->nodetree->id, r_ptr);
151  }
152  return &snode->nodetree->gpd;
153  }
154 
155  /* Even when there is no node-tree, don't allow this to flow to scene. */
156  return NULL;
157  }
158  case SPACE_SEQ: /* Sequencer */
159  {
160  SpaceSeq *sseq = (SpaceSeq *)sl;
161 
162  /* For now, Grease Pencil data is associated with the space
163  * (actually preview region only). */
164  if (r_ptr) {
165  RNA_pointer_create(screen_id, &RNA_SpaceSequenceEditor, sseq, r_ptr);
166  }
167  return &sseq->gpd;
168  }
169  case SPACE_IMAGE: /* Image/UV Editor */
170  {
171  SpaceImage *sima = (SpaceImage *)sl;
172 
173  /* For now, Grease Pencil data is associated with the space... */
174  if (r_ptr) {
175  RNA_pointer_create(screen_id, &RNA_SpaceImageEditor, sima, r_ptr);
176  }
177  return &sima->gpd;
178  }
179  case SPACE_CLIP: /* Nodes Editor */
180  {
181  SpaceClip *sc = (SpaceClip *)sl;
182  MovieClip *clip = ED_space_clip_get_clip(sc);
183 
184  if (clip) {
185  if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
187 
188  if (!track) {
189  return NULL;
190  }
191 
192  if (r_ptr) {
193  RNA_pointer_create(&clip->id, &RNA_MovieTrackingTrack, track, r_ptr);
194  }
195  return &track->gpd;
196  }
197  if (r_ptr) {
198  RNA_id_pointer_create(&clip->id, r_ptr);
199  }
200  return &clip->gpd;
201  }
202  break;
203  }
204  default: /* unsupported space */
205  return NULL;
206  }
207  }
208 
209  return NULL;
210 }
211 
213 {
216 
217  return ED_gpencil_data_get_pointers_direct(area, ob, r_ptr);
218 }
219 
221 {
222  ID *screen_id = (ID *)CTX_wm_screen(C);
225 
226  return ED_annotation_data_get_pointers_direct(screen_id, area, scene, r_ptr);
227 }
228 /* -------------------------------------------------------- */
229 
231 {
233  return (gpd_ptr) ? *(gpd_ptr) : NULL;
234 }
235 
237 {
239  return (gpd_ptr) ? *(gpd_ptr) : NULL;
240 }
241 
243 {
245  if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
246  return NULL;
247  }
248  return ob->data;
249 }
250 
252 {
254  return (gpd_ptr) ? *(gpd_ptr) : NULL;
255 }
256 
258 {
260 
263  Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
264 
265  return ED_gpencil_data_get_active_direct(area, ob_eval);
266 }
267 
268 /* -------------------------------------------------------- */
269 
271 {
272  /* Key Assumption: If the pointer is an object, we're dealing with a GP Object's data.
273  * Otherwise, the GP data-block is being used for annotations (i.e. everywhere else). */
274  return ((owner_ptr) && (owner_ptr->type != &RNA_Object));
275 }
276 
277 /* ******************************************************** */
278 /* Keyframe Indicator Checks */
279 
281 {
282  if (ob && ob->data && (ob->type == OB_GPENCIL)) {
284  if (gpl) {
285  if (gpl->actframe) {
286  /* XXX: assumes that frame has been fetched already */
287  return (gpl->actframe->framenum == cfra);
288  }
289  /* XXX: disabled as could be too much of a penalty */
290  // return BKE_gpencil_layer_frame_find(gpl, cfra);
291  }
292  }
293 
294  return false;
295 }
296 
297 /* ******************************************************** */
298 /* Poll Callbacks */
299 
301 {
303  if (ob == NULL) {
304  return false;
305  }
306  bGPdata *gpd = (bGPdata *)ob->data;
307 
308  return (gpd != NULL);
309 }
310 
312 {
314  if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
315  return false;
316  }
317  bGPdata *gpd = (bGPdata *)ob->data;
319 
320  return (gpl != NULL);
321 }
322 
324 {
326  Paint *paint = &ts->gp_paint->paint;
327  if (paint) {
328  return (paint->brush != NULL);
329  }
330  return false;
331 }
332 
333 /* ******************************************************** */
334 /* Dynamic Enums of GP Layers */
335 /* NOTE: These include an option to create a new layer and use that... */
336 
339  PropertyRNA *UNUSED(prop),
340  bool *r_free)
341 {
343  bGPDlayer *gpl;
344  EnumPropertyItem *item = NULL, item_tmp = {0};
345  int totitem = 0;
346  int i = 0;
347 
348  if (ELEM(NULL, C, gpd)) {
349  return DummyRNA_DEFAULT_items;
350  }
351 
352  /* Existing layers */
353  for (gpl = gpd->layers.first; gpl; gpl = gpl->next, i++) {
354  item_tmp.identifier = gpl->info;
355  item_tmp.name = gpl->info;
356  item_tmp.value = i;
357 
358  if (gpl->flag & GP_LAYER_ACTIVE) {
359  item_tmp.icon = ICON_GREASEPENCIL;
360  }
361  else {
362  item_tmp.icon = ICON_NONE;
363  }
364 
365  RNA_enum_item_add(&item, &totitem, &item_tmp);
366  }
367 
368  RNA_enum_item_end(&item, &totitem);
369  *r_free = true;
370 
371  return item;
372 }
373 
376  PropertyRNA *UNUSED(prop),
377  bool *r_free)
378 {
380  bGPDlayer *gpl;
381  EnumPropertyItem *item = NULL, item_tmp = {0};
382  int totitem = 0;
383  int i = 0;
384 
385  if (ELEM(NULL, C, gpd)) {
386  return DummyRNA_DEFAULT_items;
387  }
388 
389  /* Create new layer */
390  /* TODO: have some way of specifying that we don't want this? */
391  {
392  /* "New Layer" entry */
393  item_tmp.identifier = "__CREATE__";
394  item_tmp.name = "New Layer";
395  item_tmp.value = -1;
396  item_tmp.icon = ICON_ADD;
397  RNA_enum_item_add(&item, &totitem, &item_tmp);
398 
399  /* separator */
400  RNA_enum_item_add_separator(&item, &totitem);
401  }
402 
403  const int tot = BLI_listbase_count(&gpd->layers);
404  /* Existing layers */
405  for (gpl = gpd->layers.last, i = 0; gpl; gpl = gpl->prev, i++) {
406  item_tmp.identifier = gpl->info;
407  item_tmp.name = gpl->info;
408  item_tmp.value = tot - i - 1;
409 
410  if (gpl->flag & GP_LAYER_ACTIVE) {
411  item_tmp.icon = ICON_GREASEPENCIL;
412  }
413  else {
414  item_tmp.icon = ICON_NONE;
415  }
416 
417  RNA_enum_item_add(&item, &totitem, &item_tmp);
418  }
419 
420  RNA_enum_item_end(&item, &totitem);
421  *r_free = true;
422 
423  return item;
424 }
425 
428  PropertyRNA *UNUSED(prop),
429  bool *r_free)
430 {
432  EnumPropertyItem *item = NULL, item_tmp = {0};
433  int totitem = 0;
434  int i = 0;
435 
436  if (ELEM(NULL, C, ob)) {
437  return DummyRNA_DEFAULT_items;
438  }
439 
440  /* Existing materials */
441  for (i = 1; i <= ob->totcol; i++) {
442  Material *ma = BKE_object_material_get(ob, i);
443  if (ma) {
444  item_tmp.identifier = ma->id.name + 2;
445  item_tmp.name = ma->id.name + 2;
446  item_tmp.value = i;
447  item_tmp.icon = ma->preview ? ma->preview->icon_id : ICON_NONE;
448 
449  RNA_enum_item_add(&item, &totitem, &item_tmp);
450  }
451  }
452 
453  RNA_enum_item_end(&item, &totitem);
454  *r_free = true;
455 
456  return item;
457 }
458 
459 /* ******************************************************** */
460 /* Brush Tool Core */
461 
462 bool gpencil_stroke_inside_circle(const float mval[2], int rad, int x0, int y0, int x1, int y1)
463 {
464  /* simple within-radius check for now */
465  const float screen_co_a[2] = {x0, y0};
466  const float screen_co_b[2] = {x1, y1};
467 
468  if (edge_inside_circle(mval, rad, screen_co_a, screen_co_b)) {
469  return true;
470  }
471 
472  /* not inside */
473  return false;
474 }
475 
476 /* ******************************************************** */
477 /* Selection Validity Testing */
478 
480 {
481  LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
482  if (gps->flag & GP_STROKE_SELECT) {
483  return true;
484  }
485  }
486 
487  return false;
488 }
489 
490 bool ED_gpencil_layer_has_selected_stroke(const bGPDlayer *gpl, const bool is_multiedit)
491 {
492  bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
493  for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
494  if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
496  return true;
497  }
498  }
499  /* If not multi-edit, exit loop. */
500  if (!is_multiedit) {
501  break;
502  }
503  }
504 
505  return false;
506 }
507 
508 /* ******************************************************** */
509 /* Stroke Validity Testing */
510 
512 {
513  /* sanity check */
514  if (ELEM(NULL, area, gps)) {
515  return false;
516  }
517 
518  /* filter stroke types by flags + spacetype */
519  if (gps->flag & GP_STROKE_3DSPACE) {
520  /* 3D strokes - only in 3D view */
521  return (ELEM(area->spacetype, SPACE_VIEW3D, SPACE_PROPERTIES));
522  }
523  if (gps->flag & GP_STROKE_2DIMAGE) {
524  /* Special "image" strokes - only in Image Editor */
525  return (area->spacetype == SPACE_IMAGE);
526  }
527  if (gps->flag & GP_STROKE_2DSPACE) {
528  /* 2D strokes (data-space) - for any 2D view (i.e. everything other than 3D view). */
529  return (area->spacetype != SPACE_VIEW3D);
530  }
531  /* view aligned - anything goes */
532  return true;
533 }
534 
536 {
539 }
540 
542 {
543  /* check if the color is editable */
545 
546  if (gp_style != NULL) {
547  if (gp_style->flag & GP_MATERIAL_HIDE) {
548  return false;
549  }
550  if (((gpl->flag & GP_LAYER_UNLOCK_COLOR) == 0) && (gp_style->flag & GP_MATERIAL_LOCKED)) {
551  return false;
552  }
553  }
554 
555  return true;
556 }
557 
559 {
560  /* check if the color is editable */
562 
563  if (gp_style != NULL) {
564  if (gp_style->flag & GP_MATERIAL_HIDE) {
565  return false;
566  }
567  }
568 
569  return true;
570 }
571 
572 /* ******************************************************** */
573 /* Space Conversion */
574 
576 {
578  ARegion *region = CTX_wm_region(C);
579 
580  /* zero out the storage (just in case) */
581  memset(r_gsc, 0, sizeof(GP_SpaceConversion));
582  unit_m4(r_gsc->mat);
583 
584  /* store settings */
585  r_gsc->scene = CTX_data_scene(C);
586  r_gsc->ob = CTX_data_active_object(C);
587 
588  r_gsc->area = area;
589  r_gsc->region = region;
590  r_gsc->v2d = &region->v2d;
591 
592  /* init region-specific stuff */
593  if (area->spacetype == SPACE_VIEW3D) {
594  wmWindow *win = CTX_wm_window(C);
597  View3D *v3d = (View3D *)CTX_wm_space_data(C);
598  RegionView3D *rv3d = region->regiondata;
599 
600  /* init 3d depth buffers */
602 
605 
606  /* for camera view set the subrect */
607  if (rv3d->persp == RV3D_CAMOB) {
609  scene, depsgraph, region, v3d, rv3d, &r_gsc->subrect_data, true);
610  r_gsc->subrect = &r_gsc->subrect_data;
611  }
612  }
613 }
614 
616  const float diff_mat[4][4],
617  bGPDspoint *r_pt)
618 {
619  float fpt[3];
620 
621  mul_v3_m4v3(fpt, diff_mat, &pt->x);
622  copy_v3_v3(&r_pt->x, fpt);
623 }
624 
626 {
627  bGPDspoint *pt;
628  int i;
629 
630  /* undo matrix */
631  float diff_mat[4][4];
632  float inverse_diff_mat[4][4];
633  float fpt[3];
634 
635  BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
636  zero_axis_bias_m4(diff_mat);
637  invert_m4_m4(inverse_diff_mat, diff_mat);
638 
639  for (i = 0; i < gps->totpoints; i++) {
640  pt = &gps->points[i];
641  mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x);
642  copy_v3_v3(&pt->x, fpt);
643  }
644 }
645 
647  Object *obact,
648  bGPDlayer *gpl,
649  bGPDspoint *pt)
650 {
651  /* undo matrix */
652  float diff_mat[4][4];
653  float inverse_diff_mat[4][4];
654  float fpt[3];
655 
656  BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
657  zero_axis_bias_m4(diff_mat);
658  invert_m4_m4(inverse_diff_mat, diff_mat);
659 
660  mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x);
661 
662  copy_v3_v3(&pt->x, fpt);
663 }
664 
666  const GP_SpaceConversion *gsc, const bGPDstroke *gps, const bGPDspoint *pt, int *r_x, int *r_y)
667 {
668  const ARegion *region = gsc->region;
669  const View2D *v2d = gsc->v2d;
670  const rctf *subrect = gsc->subrect;
671  int xyval[2];
672 
673  /* sanity checks */
674  BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->area->spacetype == SPACE_VIEW3D));
675  BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->area->spacetype != SPACE_VIEW3D));
676 
677  if (gps->flag & GP_STROKE_3DSPACE) {
678  if (ED_view3d_project_int_global(region, &pt->x, xyval, V3D_PROJ_TEST_NOP) ==
679  V3D_PROJ_RET_OK) {
680  *r_x = xyval[0];
681  *r_y = xyval[1];
682  }
683  else {
684  *r_x = V2D_IS_CLIPPED;
685  *r_y = V2D_IS_CLIPPED;
686  }
687  }
688  else if (gps->flag & GP_STROKE_2DSPACE) {
689  float vec[3] = {pt->x, pt->y, 0.0f};
690  mul_m4_v3(gsc->mat, vec);
691  UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], r_x, r_y);
692  }
693  else {
694  if (subrect == NULL) {
695  /* normal 3D view (or view space) */
696  *r_x = (int)(pt->x / 100 * region->winx);
697  *r_y = (int)(pt->y / 100 * region->winy);
698  }
699  else {
700  /* camera view, use subrect */
701  *r_x = (int)((pt->x / 100) * BLI_rctf_size_x(subrect)) + subrect->xmin;
702  *r_y = (int)((pt->y / 100) * BLI_rctf_size_y(subrect)) + subrect->ymin;
703  }
704  }
705 }
706 
708  const bGPDstroke *gps,
709  const bGPDspoint *pt,
710  float *r_x,
711  float *r_y)
712 {
713  const ARegion *region = gsc->region;
714  const View2D *v2d = gsc->v2d;
715  const rctf *subrect = gsc->subrect;
716  float xyval[2];
717 
718  /* sanity checks */
719  BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->area->spacetype == SPACE_VIEW3D));
720  BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->area->spacetype != SPACE_VIEW3D));
721 
722  if (gps->flag & GP_STROKE_3DSPACE) {
723  if (ED_view3d_project_float_global(region, &pt->x, xyval, V3D_PROJ_TEST_NOP) ==
724  V3D_PROJ_RET_OK) {
725  *r_x = xyval[0];
726  *r_y = xyval[1];
727  }
728  else {
729  *r_x = 0.0f;
730  *r_y = 0.0f;
731  }
732  }
733  else if (gps->flag & GP_STROKE_2DSPACE) {
734  float vec[3] = {pt->x, pt->y, 0.0f};
735  int t_x, t_y;
736 
737  mul_m4_v3(gsc->mat, vec);
738  UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], &t_x, &t_y);
739 
740  if ((t_x == t_y) && (t_x == V2D_IS_CLIPPED)) {
741  /* XXX: Or should we just always use the values as-is? */
742  *r_x = 0.0f;
743  *r_y = 0.0f;
744  }
745  else {
746  *r_x = (float)t_x;
747  *r_y = (float)t_y;
748  }
749  }
750  else {
751  if (subrect == NULL) {
752  /* normal 3D view (or view space) */
753  *r_x = (pt->x / 100.0f * region->winx);
754  *r_y = (pt->y / 100.0f * region->winy);
755  }
756  else {
757  /* camera view, use subrect */
758  *r_x = ((pt->x / 100.0f) * BLI_rctf_size_x(subrect)) + subrect->xmin;
759  *r_y = ((pt->y / 100.0f) * BLI_rctf_size_y(subrect)) + subrect->ymin;
760  }
761  }
762 }
763 
765  const short flag,
766  const float pt[3],
767  float xy[2])
768 {
769  const ARegion *region = gsc->region;
770  const View2D *v2d = gsc->v2d;
771  const rctf *subrect = gsc->subrect;
772  float xyval[2];
773 
774  /* sanity checks */
776 
777  if (flag & GP_STROKE_3DSPACE) {
779  xy[0] = xyval[0];
780  xy[1] = xyval[1];
781  }
782  else {
783  xy[0] = 0.0f;
784  xy[1] = 0.0f;
785  }
786  }
787  else if (flag & GP_STROKE_2DSPACE) {
788  float vec[3] = {pt[0], pt[1], 0.0f};
789  int t_x, t_y;
790 
791  mul_m4_v3(gsc->mat, vec);
792  UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], &t_x, &t_y);
793 
794  if ((t_x == t_y) && (t_x == V2D_IS_CLIPPED)) {
795  /* XXX: Or should we just always use the values as-is? */
796  xy[0] = 0.0f;
797  xy[1] = 0.0f;
798  }
799  else {
800  xy[0] = (float)t_x;
801  xy[1] = (float)t_y;
802  }
803  }
804  else {
805  if (subrect == NULL) {
806  /* normal 3D view (or view space) */
807  xy[0] = (pt[0] / 100.0f * region->winx);
808  xy[1] = (pt[1] / 100.0f * region->winy);
809  }
810  else {
811  /* camera view, use subrect */
812  xy[0] = ((pt[0] / 100.0f) * BLI_rctf_size_x(subrect)) + subrect->xmin;
813  xy[1] = ((pt[1] / 100.0f) * BLI_rctf_size_y(subrect)) + subrect->ymin;
814  }
815  }
816 }
817 
819  Scene *scene,
820  const float screen_co[2],
821  float r_out[3])
822 {
823  const RegionView3D *rv3d = gsc->region->regiondata;
824  float rvec[3];
825 
827 
828  float zfac = ED_view3d_calc_zfac(rv3d, rvec);
829 
830  float mval_prj[2];
831 
832  if (ED_view3d_project_float_global(gsc->region, rvec, mval_prj, V3D_PROJ_TEST_NOP) ==
833  V3D_PROJ_RET_OK) {
834  float dvec[3];
835  float xy_delta[2];
836  sub_v2_v2v2(xy_delta, mval_prj, screen_co);
837  ED_view3d_win_to_delta(gsc->region, xy_delta, zfac, dvec);
838  sub_v3_v3v3(r_out, rvec, dvec);
839 
840  return true;
841  }
842  zero_v3(r_out);
843  return false;
844 }
845 
847  ARegion *region,
848  Object *ob,
849  const tGPspoint *point2D,
850  float *depth,
851  float r_out[3])
852 {
854 
855  if (depth && (*depth == DEPTH_INVALID)) {
856  depth = NULL;
857  }
858 
859  int mval_i[2];
860  round_v2i_v2fl(mval_i, point2D->m_xy);
861 
862  if ((depth != NULL) && (ED_view3d_autodist_simple(region, mval_i, r_out, 0, depth))) {
863  /* projecting onto 3D-Geometry
864  * - nothing more needs to be done here, since view_autodist_simple() has already done it
865  */
866  }
867  else {
868  float mval_prj[2];
869  float rvec[3];
870 
871  /* Current method just converts each point in screen-coordinates to
872  * 3D-coordinates using the 3D-cursor as reference.
873  */
875  const float zfac = ED_view3d_calc_zfac(region->regiondata, rvec);
876 
877  if (ED_view3d_project_float_global(region, rvec, mval_prj, V3D_PROJ_TEST_NOP) ==
878  V3D_PROJ_RET_OK) {
879  float dvec[3];
880  float xy_delta[2];
881  sub_v2_v2v2(xy_delta, mval_prj, point2D->m_xy);
882  ED_view3d_win_to_delta(region, xy_delta, zfac, dvec);
883  sub_v3_v3v3(r_out, rvec, dvec);
884  }
885  else {
886  zero_v3(r_out);
887  }
888  }
889 }
890 
892  const Object *ob,
893  char align_flag,
894  float r_vec[3])
895 {
896  const float *fp = scene->cursor.location;
897 
898  /* if using a gpencil object at cursor mode, can use the location of the object */
899  if (align_flag & GP_PROJECT_VIEWSPACE) {
900  if (ob && (ob->type == OB_GPENCIL)) {
901  /* fallback (no strokes) - use cursor or object location */
902  if (align_flag & GP_PROJECT_CURSOR) {
903  /* use 3D-cursor */
904  copy_v3_v3(r_vec, fp);
905  }
906  else {
907  /* use object location */
908  copy_v3_v3(r_vec, ob->obmat[3]);
909  /* Apply layer offset. */
910  bGPdata *gpd = ob->data;
912  if (gpl != NULL) {
913  add_v3_v3(r_vec, gpl->layer_mat[3]);
914  }
915  }
916  }
917  }
918  else {
919  /* use 3D-cursor */
920  copy_v3_v3(r_vec, fp);
921  }
922 }
923 
925 {
929  GP_SpaceConversion gsc = {NULL};
930 
931  bGPDspoint *pt;
932  int i;
933  float diff_mat[4][4];
934  float inverse_diff_mat[4][4];
935 
936  /* init space conversion stuff */
938 
940  zero_axis_bias_m4(diff_mat);
941  invert_m4_m4(inverse_diff_mat, diff_mat);
942 
943  /* Adjust each point */
944  for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
945  float xy[2];
946 
947  bGPDspoint pt2;
948  gpencil_point_to_parent_space(pt, diff_mat, &pt2);
949  gpencil_point_to_xy_fl(&gsc, gps, &pt2, &xy[0], &xy[1]);
950 
951  /* Planar - All on same plane parallel to the viewplane */
952  gpencil_point_xy_to_3d(&gsc, scene, xy, &pt->x);
953 
954  /* Unapply parent corrections */
955  mul_m4_v3(inverse_diff_mat, &pt->x);
956  }
957 }
958 
960  const Object *ob,
961  const RegionView3D *rv3d,
962  bGPDlayer *gpl,
963  bGPDstroke *gps,
964  const float origin[3],
965  const int axis)
966 {
967  const ToolSettings *ts = scene->toolsettings;
968  const View3DCursor *cursor = &scene->cursor;
969  float plane_normal[3];
970  float vn[3];
971 
972  float ray[3];
973  float rpoint[3];
974 
975  /* Recalculate layer transform matrix. */
976  loc_eul_size_to_mat4(gpl->layer_mat, gpl->location, gpl->rotation, gpl->scale);
977  invert_m4_m4(gpl->layer_invmat, gpl->layer_mat);
978 
979  /* normal vector for a plane locked to axis */
980  zero_v3(plane_normal);
981  if (axis < 0) {
982  /* if the axis is not locked, need a vector to the view direction
983  * in order to get the right size of the stroke.
984  */
985  ED_view3d_global_to_vector(rv3d, origin, plane_normal);
986  }
987  else if (axis < 3) {
988  plane_normal[axis] = 1.0f;
989  /* if object, apply object rotation */
990  if (ob && (ob->type == OB_GPENCIL)) {
991  float mat[4][4];
992  copy_m4_m4(mat, ob->obmat);
993 
994  /* move origin to cursor */
995  if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) {
996  if (gpl != NULL) {
997  add_v3_v3(mat[3], gpl->location);
998  }
999  }
1001  copy_v3_v3(mat[3], cursor->location);
1002  }
1003 
1004  mul_mat3_m4_v3(mat, plane_normal);
1005  }
1006 
1007  if ((gpl != NULL) && (ts->gp_sculpt.lock_axis != GP_LOCKAXIS_CURSOR)) {
1008  mul_mat3_m4_v3(gpl->layer_mat, plane_normal);
1009  }
1010  }
1011  else {
1012  const float scale[3] = {1.0f, 1.0f, 1.0f};
1013  plane_normal[2] = 1.0f;
1014  float mat[4][4];
1015  loc_eul_size_to_mat4(mat, cursor->location, cursor->rotation_euler, scale);
1016  mul_mat3_m4_v3(mat, plane_normal);
1017  }
1018 
1019  /* Reproject the points in the plane */
1020  for (int i = 0; i < gps->totpoints; i++) {
1021  bGPDspoint *pt = &gps->points[i];
1022 
1023  /* get a vector from the point with the current view direction of the viewport */
1024  ED_view3d_global_to_vector(rv3d, &pt->x, vn);
1025 
1026  /* calculate line extreme point to create a ray that cross the plane */
1027  mul_v3_fl(vn, -50.0f);
1028  add_v3_v3v3(ray, &pt->x, vn);
1029 
1030  /* if the line never intersect, the point is not changed */
1031  if (isect_line_plane_v3(rpoint, &pt->x, ray, origin, plane_normal)) {
1032  copy_v3_v3(&pt->x, rpoint);
1033  }
1034  }
1035 }
1036 
1038  const GP_SpaceConversion *gsc,
1039  SnapObjectContext *sctx,
1040  bGPDlayer *gpl,
1041  bGPDframe *gpf,
1042  bGPDstroke *gps,
1043  const eGP_ReprojectModes mode,
1044  const bool keep_original)
1045 {
1046  ToolSettings *ts = gsc->scene->toolsettings;
1047  ARegion *region = gsc->region;
1048  RegionView3D *rv3d = region->regiondata;
1049 
1050  /* Recalculate layer transform matrix. */
1051  loc_eul_size_to_mat4(gpl->layer_mat, gpl->location, gpl->rotation, gpl->scale);
1052  invert_m4_m4(gpl->layer_invmat, gpl->layer_mat);
1053 
1054  float diff_mat[4][4], inverse_diff_mat[4][4];
1055  BKE_gpencil_layer_transform_matrix_get(depsgraph, gsc->ob, gpl, diff_mat);
1056  zero_axis_bias_m4(diff_mat);
1057  invert_m4_m4(inverse_diff_mat, diff_mat);
1058 
1059  float origin[3];
1060  if (mode != GP_REPROJECT_CURSOR) {
1062  }
1063  else {
1064  copy_v3_v3(origin, gsc->scene->cursor.location);
1065  }
1066 
1067  bGPDspoint *pt;
1068  int i;
1069 
1070  /* If keep original, do a copy. */
1071  bGPDstroke *gps_active = gps;
1072  /* if duplicate, deselect all points. */
1073  if (keep_original) {
1074  gps_active = BKE_gpencil_stroke_duplicate(gps, true, true);
1075  gps_active->flag &= ~GP_STROKE_SELECT;
1077  for (i = 0, pt = gps_active->points; i < gps_active->totpoints; i++, pt++) {
1078  pt->flag &= ~GP_SPOINT_SELECT;
1079  }
1080  /* Add to frame. */
1081  BLI_addtail(&gpf->strokes, gps_active);
1082  }
1083 
1084  /* Adjust each point */
1085  for (i = 0, pt = gps_active->points; i < gps_active->totpoints; i++, pt++) {
1086  float xy[2];
1087 
1088  /* 3D to Screen-space */
1089  /* NOTE: We can't use gpencil_point_to_xy() here because that uses ints for the screen-space
1090  * coordinates, resulting in lost precision, which in turn causes stair-stepping
1091  * artifacts in the final points. */
1092 
1093  bGPDspoint pt2;
1094  gpencil_point_to_parent_space(pt, diff_mat, &pt2);
1095  gpencil_point_to_xy_fl(gsc, gps_active, &pt2, &xy[0], &xy[1]);
1096 
1097  /* Project stroke in one axis */
1099  int axis = 0;
1100  switch (mode) {
1101  case GP_REPROJECT_FRONT: {
1102  axis = 1;
1103  break;
1104  }
1105  case GP_REPROJECT_SIDE: {
1106  axis = 0;
1107  break;
1108  }
1109  case GP_REPROJECT_TOP: {
1110  axis = 2;
1111  break;
1112  }
1113  case GP_REPROJECT_CURSOR: {
1114  axis = 3;
1115  break;
1116  }
1117  default: {
1118  axis = 1;
1119  break;
1120  }
1121  }
1122 
1123  ED_gpencil_project_point_to_plane(gsc->scene, gsc->ob, gpl, rv3d, origin, axis, &pt2);
1124 
1125  copy_v3_v3(&pt->x, &pt2.x);
1126 
1127  /* apply parent again */
1128  gpencil_apply_parent_point(depsgraph, gsc->ob, gpl, pt);
1129  }
1130  /* Project screen-space back to 3D space (from current perspective)
1131  * so that all points have been treated the same way. */
1132  else if (mode == GP_REPROJECT_VIEW) {
1133  /* Planar - All on same plane parallel to the view-plane. */
1134  gpencil_point_xy_to_3d(gsc, gsc->scene, xy, &pt->x);
1135  }
1136  else {
1137  /* Geometry - Snap to surfaces of visible geometry */
1138  float ray_start[3];
1139  float ray_normal[3];
1140  /* magic value for initial depth copied from the default
1141  * value of Python's Scene.ray_cast function
1142  */
1143  float depth = 1.70141e+38f;
1144  float location[3] = {0.0f, 0.0f, 0.0f};
1145  float normal[3] = {0.0f, 0.0f, 0.0f};
1146 
1148  BLI_assert(gsc->area && gsc->area->spacetype == SPACE_VIEW3D);
1149  const View3D *v3d = gsc->area->spacedata.first;
1151  depsgraph, region, v3d, xy, &ray_start[0], &ray_normal[0], true);
1153  depsgraph,
1154  v3d,
1155  &(const struct SnapObjectParams){
1156  .snap_target_select = SCE_SNAP_TARGET_ALL,
1157  },
1158  &ray_start[0],
1159  &ray_normal[0],
1160  &depth,
1161  &location[0],
1162  &normal[0])) {
1163  copy_v3_v3(&pt->x, location);
1164  }
1165  else {
1166  /* Default to planar */
1167  gpencil_point_xy_to_3d(gsc, gsc->scene, xy, &pt->x);
1168  }
1169  }
1170 
1171  /* Unapply parent corrections */
1173  mul_m4_v3(inverse_diff_mat, &pt->x);
1174  }
1175  }
1176 }
1177 
1179  const Object *ob,
1180  bGPDlayer *gpl,
1181  const RegionView3D *rv3d,
1182  const float origin[3],
1183  const int axis,
1184  bGPDspoint *pt)
1185 {
1186  const ToolSettings *ts = scene->toolsettings;
1187  const View3DCursor *cursor = &scene->cursor;
1188  float plane_normal[3];
1189  float vn[3];
1190 
1191  float ray[3];
1192  float rpoint[3];
1193 
1194  /* normal vector for a plane locked to axis */
1195  zero_v3(plane_normal);
1196  if (axis < 0) {
1197  /* if the axis is not locked, need a vector to the view direction
1198  * in order to get the right size of the stroke.
1199  */
1200  ED_view3d_global_to_vector(rv3d, origin, plane_normal);
1201  }
1202  else if (axis < 3) {
1203  plane_normal[axis] = 1.0f;
1204  /* if object, apply object rotation */
1205  if (ob && (ob->type == OB_GPENCIL)) {
1206  float mat[4][4];
1207  copy_m4_m4(mat, ob->obmat);
1208  if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) {
1209  if (gpl != NULL) {
1210  add_v3_v3(mat[3], gpl->location);
1211  }
1212  }
1213 
1214  /* move origin to cursor */
1216  copy_v3_v3(mat[3], cursor->location);
1217  }
1218 
1219  mul_mat3_m4_v3(mat, plane_normal);
1220  /* Apply layer rotation (local transform). */
1221  if ((gpl != NULL) && (ts->gp_sculpt.lock_axis != GP_LOCKAXIS_CURSOR)) {
1222  mul_mat3_m4_v3(gpl->layer_mat, plane_normal);
1223  }
1224  }
1225  }
1226  else {
1227  const float scale[3] = {1.0f, 1.0f, 1.0f};
1228  plane_normal[2] = 1.0f;
1229  float mat[4][4];
1230  loc_eul_size_to_mat4(mat, cursor->location, cursor->rotation_euler, scale);
1231 
1232  /* move origin to object */
1233  if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) {
1234  copy_v3_v3(mat[3], ob->obmat[3]);
1235  }
1236 
1237  mul_mat3_m4_v3(mat, plane_normal);
1238  }
1239 
1240  /* Reproject the points in the plane */
1241  /* get a vector from the point with the current view direction of the viewport */
1242  ED_view3d_global_to_vector(rv3d, &pt->x, vn);
1243 
1244  /* calculate line extreme point to create a ray that cross the plane */
1245  mul_v3_fl(vn, -50.0f);
1246  add_v3_v3v3(ray, &pt->x, vn);
1247 
1248  /* if the line never intersect, the point is not changed */
1249  if (isect_line_plane_v3(rpoint, &pt->x, ray, origin, plane_normal)) {
1250  copy_v3_v3(&pt->x, rpoint);
1251  }
1252 }
1253 
1254 /* ******************************************************** */
1255 /* Stroke Operations */
1256 
1257 /* XXX: Check if these functions duplicate stuff in blenkernel,
1258  * and/or whether we should just deduplicate. */
1259 
1260 void gpencil_subdivide_stroke(bGPdata *gpd, bGPDstroke *gps, const int subdivide)
1261 {
1262  bGPDspoint *temp_points;
1263  int totnewpoints, oldtotpoints;
1264  int i2;
1265 
1266  /* loop as many times as levels */
1267  for (int s = 0; s < subdivide; s++) {
1268  totnewpoints = gps->totpoints - 1;
1269  /* duplicate points in a temp area */
1270  temp_points = MEM_dupallocN(gps->points);
1271  oldtotpoints = gps->totpoints;
1272 
1273  /* resize the points arrays */
1274  gps->totpoints += totnewpoints;
1275  gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
1276  if (gps->dvert != NULL) {
1277  gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
1278  }
1279 
1280  /* move points from last to first to new place */
1281  i2 = gps->totpoints - 1;
1282  for (int i = oldtotpoints - 1; i > 0; i--) {
1283  bGPDspoint *pt = &temp_points[i];
1284  bGPDspoint *pt_final = &gps->points[i2];
1285 
1286  copy_v3_v3(&pt_final->x, &pt->x);
1287  pt_final->pressure = pt->pressure;
1288  pt_final->strength = pt->strength;
1289  pt_final->time = pt->time;
1290  pt_final->flag = pt->flag;
1291  pt_final->uv_fac = pt->uv_fac;
1292  pt_final->uv_rot = pt->uv_rot;
1293  copy_v4_v4(pt_final->vert_color, pt->vert_color);
1294 
1295  if (gps->dvert != NULL) {
1296  MDeformVert *dvert = &gps->dvert[i];
1297  MDeformVert *dvert_final = &gps->dvert[i2];
1298 
1299  dvert_final->totweight = dvert->totweight;
1300  dvert_final->dw = dvert->dw;
1301  }
1302 
1303  i2 -= 2;
1304  }
1305  /* interpolate mid points */
1306  i2 = 1;
1307  for (int i = 0; i < oldtotpoints - 1; i++) {
1308  bGPDspoint *pt = &temp_points[i];
1309  bGPDspoint *next = &temp_points[i + 1];
1310  bGPDspoint *pt_final = &gps->points[i2];
1311 
1312  /* add a half way point */
1313  interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
1314  pt_final->pressure = interpf(pt->pressure, next->pressure, 0.5f);
1315  pt_final->strength = interpf(pt->strength, next->strength, 0.5f);
1316  CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f);
1317  pt_final->time = interpf(pt->time, next->time, 0.5f);
1318  pt_final->uv_fac = interpf(pt->uv_fac, next->uv_fac, 0.5f);
1319  pt_final->uv_rot = interpf(pt->uv_rot, next->uv_rot, 0.5f);
1320  interp_v4_v4v4(pt_final->vert_color, pt->vert_color, next->vert_color, 0.5f);
1321 
1322  if (gps->dvert != NULL) {
1323  MDeformVert *dvert_final = &gps->dvert[i2];
1324  dvert_final->totweight = 0;
1325  dvert_final->dw = NULL;
1326  }
1327 
1328  i2 += 2;
1329  }
1330 
1331  MEM_SAFE_FREE(temp_points);
1332 
1333  /* move points to smooth stroke */
1334  /* duplicate points in a temp area with the new subdivide data */
1335  temp_points = MEM_dupallocN(gps->points);
1336 
1337  /* extreme points are not changed */
1338  for (int i = 0; i < gps->totpoints - 2; i++) {
1339  bGPDspoint *pt = &temp_points[i];
1340  bGPDspoint *next = &temp_points[i + 1];
1341  bGPDspoint *pt_final = &gps->points[i + 1];
1342 
1343  /* move point */
1344  interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
1345  }
1346  /* free temp memory */
1347  MEM_SAFE_FREE(temp_points);
1348  }
1349  /* Calc geometry data. */
1351 }
1352 
1354 {
1355  bGPDspoint *pt;
1356  int i;
1357  float diff_mat[4][4];
1358  float cur_mat[4][4];
1359  float gpl_loc[3];
1360  zero_v3(gpl_loc);
1361 
1362  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
1363  if (gpl->parent != NULL) {
1364  /* calculate new matrix */
1365  if (ELEM(gpl->partype, PAROBJECT, PARSKEL)) {
1366  invert_m4_m4(cur_mat, gpl->parent->obmat);
1367  copy_v3_v3(gpl_loc, obact->obmat[3]);
1368  }
1369  else if (gpl->partype == PARBONE) {
1370  bPoseChannel *pchan = BKE_pose_channel_find_name(gpl->parent->pose, gpl->parsubstr);
1371  if (pchan) {
1372  float tmp_mat[4][4];
1373  mul_m4_m4m4(tmp_mat, gpl->parent->obmat, pchan->pose_mat);
1374  invert_m4_m4(cur_mat, tmp_mat);
1375  copy_v3_v3(gpl_loc, obact->obmat[3]);
1376  }
1377  }
1378 
1379  /* only redo if any change */
1380  if (!equals_m4m4(gpl->inverse, cur_mat)) {
1381  /* first apply current transformation to all strokes */
1382  BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
1383  /* undo local object */
1384  sub_v3_v3(diff_mat[3], gpl_loc);
1385 
1386  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
1387  LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
1388  for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
1389  mul_m4_v3(diff_mat, &pt->x);
1390  }
1391  }
1392  }
1393  /* set new parent matrix */
1394  copy_m4_m4(gpl->inverse, cur_mat);
1395  }
1396  }
1397  }
1398 }
1399 /* ******************************************************** */
1400 /* GP Object Stuff */
1401 
1402 Object *ED_gpencil_add_object(bContext *C, const float loc[3], ushort local_view_bits)
1403 {
1404  const float rot[3] = {0.0f};
1405 
1406  Object *ob = ED_object_add_type(C, OB_GPENCIL, NULL, loc, rot, false, local_view_bits);
1407 
1408  /* create default brushes and colors */
1410 
1411  return ob;
1412 }
1413 
1415 {
1416  Main *bmain = CTX_data_main(C);
1418 
1419  BKE_paint_ensure(ts, (Paint **)&ts->gp_paint);
1420  Paint *paint = &ts->gp_paint->paint;
1421  /* if not exist, create a new one */
1422  if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
1423  /* create new brushes */
1424  BKE_brush_gpencil_paint_presets(bmain, ts, true);
1425  }
1426 
1427  /* ensure a color exists and is assigned to object */
1429 
1430  /* Ensure multi-frame falloff curve. */
1431  if (ts->gp_sculpt.cur_falloff == NULL) {
1432  ts->gp_sculpt.cur_falloff = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
1433  CurveMapping *gp_falloff_curve = ts->gp_sculpt.cur_falloff;
1434  BKE_curvemapping_init(gp_falloff_curve);
1435  BKE_curvemap_reset(gp_falloff_curve->cm,
1436  &gp_falloff_curve->clipr,
1439  }
1440 }
1441 
1442 /* ******************************************************** */
1443 /* Vertex Groups */
1444 
1445 void ED_gpencil_vgroup_assign(bContext *C, Object *ob, float weight)
1446 {
1447  bGPdata *gpd = (bGPdata *)ob->data;
1448  const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
1449  const int def_nr = gpd->vertex_group_active_index - 1;
1450  if (!BLI_findlink(&gpd->vertex_group_names, def_nr)) {
1451  return;
1452  }
1453 
1454  CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
1455  bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
1456  bGPDstroke *gps = NULL;
1457 
1458  for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
1459  if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
1460  if (gpf == NULL) {
1461  continue;
1462  }
1463 
1464  for (gps = gpf->strokes.first; gps; gps = gps->next) {
1465 
1466  /* skip strokes that are invalid for current view */
1467  if (ED_gpencil_stroke_can_use(C, gps) == false) {
1468  continue;
1469  }
1470 
1471  if (gps->flag & GP_STROKE_SELECT) {
1472  /* verify the weight array is created */
1474 
1475  for (int i = 0; i < gps->totpoints; i++) {
1476  bGPDspoint *pt = &gps->points[i];
1477  MDeformVert *dvert = &gps->dvert[i];
1478  if (pt->flag & GP_SPOINT_SELECT) {
1479  MDeformWeight *dw = BKE_defvert_ensure_index(dvert, def_nr);
1480  if (dw) {
1481  dw->weight = weight;
1482  }
1483  }
1484  }
1485  }
1486  }
1487  }
1488 
1489  /* If not multi-edit, exit loop. */
1490  if (!is_multiedit) {
1491  break;
1492  }
1493  }
1494  }
1495  CTX_DATA_END;
1496 }
1497 
1499 {
1500  bGPdata *gpd = (bGPdata *)ob->data;
1501  const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
1502  const int def_nr = gpd->vertex_group_active_index - 1;
1503  if (!BLI_findlink(&gpd->vertex_group_names, def_nr)) {
1504  return;
1505  }
1506 
1507  CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
1508  bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
1509  bGPDstroke *gps = NULL;
1510 
1511  for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
1512  if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
1513  if (gpf == NULL) {
1514  continue;
1515  }
1516 
1517  for (gps = gpf->strokes.first; gps; gps = gps->next) {
1518 
1519  /* skip strokes that are invalid for current view */
1520  if (ED_gpencil_stroke_can_use(C, gps) == false) {
1521  continue;
1522  }
1523 
1524  for (int i = 0; i < gps->totpoints; i++) {
1525  bGPDspoint *pt = &gps->points[i];
1526  if (gps->dvert == NULL) {
1527  continue;
1528  }
1529  MDeformVert *dvert = &gps->dvert[i];
1530 
1531  if ((pt->flag & GP_SPOINT_SELECT) && (dvert->totweight > 0)) {
1532  MDeformWeight *dw = BKE_defvert_find_index(dvert, def_nr);
1533  if (dw != NULL) {
1534  BKE_defvert_remove_group(dvert, dw);
1535  }
1536  }
1537  }
1538  }
1539  }
1540 
1541  /* If not multi-edit, exit loop. */
1542  if (!is_multiedit) {
1543  break;
1544  }
1545  }
1546  }
1547  CTX_DATA_END;
1548 }
1549 
1551 {
1552  bGPdata *gpd = (bGPdata *)ob->data;
1553  const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
1554  const int def_nr = gpd->vertex_group_active_index - 1;
1555  if (!BLI_findlink(&gpd->vertex_group_names, def_nr)) {
1556  return;
1557  }
1558 
1559  CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
1560  bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
1561  bGPDstroke *gps = NULL;
1562 
1563  for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
1564  if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
1565  if (gpf == NULL) {
1566  continue;
1567  }
1568 
1569  for (gps = gpf->strokes.first; gps; gps = gps->next) {
1570 
1571  /* skip strokes that are invalid for current view */
1572  if (ED_gpencil_stroke_can_use(C, gps) == false) {
1573  continue;
1574  }
1575 
1576  for (int i = 0; i < gps->totpoints; i++) {
1577  bGPDspoint *pt = &gps->points[i];
1578  if (gps->dvert == NULL) {
1579  continue;
1580  }
1581  MDeformVert *dvert = &gps->dvert[i];
1582 
1583  if (BKE_defvert_find_index(dvert, def_nr) != NULL) {
1584  pt->flag |= GP_SPOINT_SELECT;
1585  gps->flag |= GP_STROKE_SELECT;
1586  }
1587  }
1588 
1589  if (gps->flag & GP_STROKE_SELECT) {
1591  }
1592  }
1593  }
1594 
1595  /* If not multi-edit, exit loop. */
1596  if (!is_multiedit) {
1597  break;
1598  }
1599  }
1600  }
1601  CTX_DATA_END;
1602 }
1603 
1605 {
1606  bGPdata *gpd = (bGPdata *)ob->data;
1607  const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
1608  const int def_nr = gpd->vertex_group_active_index - 1;
1609  if (!BLI_findlink(&gpd->vertex_group_names, def_nr)) {
1610  return;
1611  }
1612 
1613  CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
1614  bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
1615  bGPDstroke *gps = NULL;
1616 
1617  for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
1618  if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
1619  if (gpf == NULL) {
1620  continue;
1621  }
1622 
1623  for (gps = gpf->strokes.first; gps; gps = gps->next) {
1624 
1625  /* skip strokes that are invalid for current view */
1626  if (ED_gpencil_stroke_can_use(C, gps) == false) {
1627  continue;
1628  }
1629 
1630  for (int i = 0; i < gps->totpoints; i++) {
1631  bGPDspoint *pt = &gps->points[i];
1632  if (gps->dvert == NULL) {
1633  continue;
1634  }
1635  MDeformVert *dvert = &gps->dvert[i];
1636 
1637  if (BKE_defvert_find_index(dvert, def_nr) != NULL) {
1638  pt->flag &= ~GP_SPOINT_SELECT;
1639  }
1640  }
1641  }
1642  }
1643 
1644  /* If not multi-edit, exit loop. */
1645  if (!is_multiedit) {
1646  break;
1647  }
1648  }
1649  }
1650  CTX_DATA_END;
1651 }
1652 
1653 /* ******************************************************** */
1654 /* Cursor drawing */
1655 
1656 /* check if cursor is in drawing region */
1657 static bool gpencil_check_cursor_region(bContext *C, const int mval_i[2])
1658 {
1659  ARegion *region = CTX_wm_region(C);
1660  ScrArea *area = CTX_wm_area(C);
1662 
1663  if ((ob == NULL) || (!ELEM(ob->mode,
1668  return false;
1669  }
1670 
1671  /* TODO: add more spacetypes */
1672  if (!ELEM(area->spacetype, SPACE_VIEW3D)) {
1673  return false;
1674  }
1675  if ((region) && (region->regiontype != RGN_TYPE_WINDOW)) {
1676  return false;
1677  }
1678  if (region) {
1679  return BLI_rcti_isect_pt_v(&region->winrct, mval_i);
1680  }
1681  return false;
1682 }
1683 
1684 void ED_gpencil_brush_draw_eraser(Brush *brush, int x, int y)
1685 {
1686  short radius = (short)brush->size;
1687 
1689  const uint shdr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1691 
1692  GPU_line_smooth(true);
1694 
1695  immUniformColor4ub(255, 100, 100, 20);
1696  imm_draw_circle_fill_2d(shdr_pos, x, y, radius, 40);
1697 
1698  immUnbindProgram();
1699 
1701 
1702  float viewport_size[4];
1703  GPU_viewport_size_get_f(viewport_size);
1704  immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
1705 
1706  immUniformColor4f(1.0f, 0.39f, 0.39f, 0.78f);
1707  immUniform1i("colors_len", 0); /* "simple" mode */
1708  immUniform1f("dash_width", 12.0f);
1709  immUniform1f("dash_factor", 0.5f);
1710 
1711  imm_draw_circle_wire_2d(shdr_pos,
1712  x,
1713  y,
1714  radius,
1715  /* XXX Dashed shader gives bad results with sets of small segments
1716  * currently, temp hack around the issue. :( */
1717  max_ii(8, radius / 2)); /* was fixed 40 */
1718 
1719  immUnbindProgram();
1720 
1722  GPU_line_smooth(false);
1723 }
1724 
1726 {
1728  return true;
1729  }
1730  return false;
1731 }
1732 
1736 static void gpencil_brush_cursor_draw(bContext *C, int x, int y, void *customdata)
1737 {
1740  ARegion *region = CTX_wm_region(C);
1742 
1744  Brush *brush = NULL;
1745  Material *ma = NULL;
1746  MaterialGPencilStyle *gp_style = NULL;
1747  float *last_mouse_position = customdata;
1748 
1749  /* default radius and color */
1750  float color[3] = {1.0f, 1.0f, 1.0f};
1751  float darkcolor[3];
1752  float radius = 3.0f;
1753 
1754  const int mval_i[2] = {x, y};
1755  /* Check if cursor is in drawing region and has valid data-block. */
1756  if ((!gpencil_check_cursor_region(C, mval_i)) || (gpd == NULL)) {
1757  return;
1758  }
1759 
1760  /* for paint use paint brush size and color */
1761  if (gpd->flag & GP_DATA_STROKE_PAINTMODE) {
1762  brush = scene->toolsettings->gp_paint->paint.brush;
1763  if ((brush == NULL) || (brush->gpencil_settings == NULL)) {
1764  return;
1765  }
1766 
1767  /* while drawing hide */
1768  if ((gpd->runtime.sbuffer_used > 0) &&
1769  ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
1771  return;
1772  }
1773 
1774  if ((paint->flags & PAINT_SHOW_BRUSH) == 0) {
1775  return;
1776  }
1777 
1778  /* eraser has special shape and use a different shader program */
1779  if (brush->gpencil_tool == GPAINT_TOOL_ERASE) {
1780  ED_gpencil_brush_draw_eraser(brush, x, y);
1781  return;
1782  }
1783 
1784  /* get current drawing color */
1786 
1787  if (ma) {
1788  gp_style = ma->gp_style;
1789 
1790  /* after some testing, display the size of the brush is not practical because
1791  * is too disruptive and the size of cursor does not change with zoom factor.
1792  * The decision was to use a fix size, instead of brush->thickness value.
1793  */
1794  if ((gp_style) && (GPENCIL_PAINT_MODE(gpd)) &&
1795  ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
1797  (brush->gpencil_tool == GPAINT_TOOL_DRAW)) {
1798  radius = 2.0f;
1799  copy_v3_v3(color, gp_style->stroke_rgba);
1800  }
1801  else {
1802  /* Only Tint tool must show big cursor. */
1803  if (brush->gpencil_tool == GPAINT_TOOL_TINT) {
1804  radius = brush->size;
1805  copy_v3_v3(color, brush->rgb);
1806  }
1807  else {
1808  radius = 5.0f;
1809  copy_v3_v3(color, brush->add_col);
1810  }
1811  }
1812  }
1813  }
1814 
1815  /* Sculpt use sculpt brush size */
1816  if (GPENCIL_SCULPT_MODE(gpd)) {
1818  if ((brush == NULL) || (brush->gpencil_settings == NULL)) {
1819  return;
1820  }
1821  if ((paint->flags & PAINT_SHOW_BRUSH) == 0) {
1822  return;
1823  }
1824 
1825  radius = brush->size;
1826  if (brush->gpencil_settings->sculpt_flag &
1828  copy_v3_v3(color, brush->sub_col);
1829  }
1830  else {
1831  copy_v3_v3(color, brush->add_col);
1832  }
1833  }
1834 
1835  /* Weight Paint */
1836  if (GPENCIL_WEIGHT_MODE(gpd)) {
1838  if ((brush == NULL) || (brush->gpencil_settings == NULL)) {
1839  return;
1840  }
1841  if ((paint->flags & PAINT_SHOW_BRUSH) == 0) {
1842  return;
1843  }
1844 
1845  radius = brush->size;
1846  if (brush->gpencil_settings->sculpt_flag &
1848  copy_v3_v3(color, brush->sub_col);
1849  }
1850  else {
1851  copy_v3_v3(color, brush->add_col);
1852  }
1853  }
1854 
1855  /* For Vertex Paint use brush size. */
1856  if (GPENCIL_VERTEX_MODE(gpd)) {
1858  if ((brush == NULL) || (brush->gpencil_settings == NULL)) {
1859  return;
1860  }
1861  if ((paint->flags & PAINT_SHOW_BRUSH) == 0) {
1862  return;
1863  }
1864 
1865  radius = brush->size;
1866  copy_v3_v3(color, brush->rgb);
1867  }
1868 
1869  /* draw icon */
1873 
1874  GPU_line_smooth(true);
1876 
1877  /* Inner Ring: Color from UI panel */
1878  immUniformColor4f(color[0], color[1], color[2], 0.8f);
1879  if ((gp_style) && (GPENCIL_PAINT_MODE(gpd)) &&
1880  ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
1882  (brush->gpencil_tool == GPAINT_TOOL_DRAW)) {
1883  imm_draw_circle_fill_2d(pos, x, y, radius, 40);
1884  }
1885  else {
1886  imm_draw_circle_wire_2d(pos, x, y, radius, 40);
1887  }
1888 
1889  /* Outer Ring: Dark color for contrast on light backgrounds (e.g. gray on white) */
1890  mul_v3_v3fl(darkcolor, color, 0.40f);
1891  immUniformColor4f(darkcolor[0], darkcolor[1], darkcolor[2], 0.8f);
1892  imm_draw_circle_wire_2d(pos, x, y, radius + 1, 40);
1893 
1895  GPU_line_smooth(false);
1896 
1897  /* Draw line for lazy mouse */
1898  if ((last_mouse_position) && (brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP)) {
1899  GPU_line_smooth(true);
1901 
1902  copy_v3_v3(color, brush->add_col);
1903  immUniformColor4f(color[0], color[1], color[2], 0.8f);
1904 
1906  immVertex2f(pos, x, y);
1907  immVertex2f(pos,
1908  last_mouse_position[0] + region->winrct.xmin,
1909  last_mouse_position[1] + region->winrct.ymin);
1910  immEnd();
1911 
1913  GPU_line_smooth(false);
1914  }
1915 
1916  immUnbindProgram();
1917 }
1918 
1919 void ED_gpencil_toggle_brush_cursor(bContext *C, bool enable, void *customdata)
1920 {
1923  float *lastpost = customdata;
1924 
1925  if (gset->paintcursor && !enable) {
1926  /* clear cursor */
1928  gset->paintcursor = NULL;
1929  }
1930  else if (enable) {
1931  /* in some situations cursor could be duplicated, so it is better disable first if exist */
1932  if (gset->paintcursor) {
1933  /* clear cursor */
1935  gset->paintcursor = NULL;
1936  }
1937  /* enable cursor */
1939  RGN_TYPE_ANY,
1942  (lastpost) ? customdata : NULL);
1943  }
1944 }
1945 
1946 void ED_gpencil_setup_modes(bContext *C, bGPdata *gpd, int newmode)
1947 {
1948  if (!gpd) {
1949  return;
1950  }
1951 
1952  switch (newmode) {
1953  case OB_MODE_EDIT_GPENCIL:
1954  gpd->flag |= GP_DATA_STROKE_EDITMODE;
1955  gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
1960  break;
1961  case OB_MODE_PAINT_GPENCIL:
1962  gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
1968  break;
1970  gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
1971  gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
1976  break;
1978  gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
1979  gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
1984  break;
1986  gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
1987  gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
1992  break;
1993  default:
1994  gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
1995  gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
2000  break;
2001  }
2002 }
2003 
2008  const tGPspoint *point2D,
2009  const float origin[3],
2010  float out[3])
2011 {
2012  float mval_prj[2];
2013  float rvec[3];
2014 
2015  copy_v3_v3(rvec, origin);
2016 
2017  const float zfac = ED_view3d_calc_zfac(region->regiondata, rvec);
2018 
2019  if (ED_view3d_project_float_global(region, rvec, mval_prj, V3D_PROJ_TEST_NOP) ==
2020  V3D_PROJ_RET_OK) {
2021  float dvec[3];
2022  float xy_delta[2];
2023  sub_v2_v2v2(xy_delta, mval_prj, point2D->m_xy);
2024  ED_view3d_win_to_delta(region, xy_delta, zfac, dvec);
2025  sub_v3_v3v3(out, rvec, dvec);
2026  }
2027  else {
2028  zero_v3(out);
2029  }
2030 }
2031 
2033  float origin[3],
2034  const tGPspoint *tpt,
2035  bGPDspoint *pt)
2036 {
2037  float p3d[3];
2038  /* conversion to 3d format */
2039  gpencil_stroke_convertcoords(region, tpt, origin, p3d);
2040  copy_v3_v3(&pt->x, p3d);
2041  zero_v4(pt->vert_color);
2042 
2043  pt->pressure = tpt->pressure;
2044  pt->strength = tpt->strength;
2045  pt->uv_fac = tpt->uv_fac;
2046  pt->uv_rot = tpt->uv_rot;
2047 }
2048 
2050 {
2051  Material *gps_ma = NULL;
2052  /* Read all strokes. */
2053  for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
2054  if (ob->type == OB_GPENCIL) {
2055  bGPdata *gpd = ob->data;
2056  if (gpd == NULL) {
2057  continue;
2058  }
2059 
2060  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
2061  /* only editable and visible layers are considered */
2062  if (BKE_gpencil_layer_is_editable(gpl)) {
2063  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
2064  LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
2065  /* check if it is editable */
2066  if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
2067  continue;
2068  }
2069  gps_ma = BKE_gpencil_material(ob, gps->mat_nr + 1);
2070  /* update */
2071  if ((gps_ma) && (gps_ma == mat)) {
2073  }
2074  }
2075  }
2076  }
2077  }
2079  }
2080  }
2081 }
2082 
2084  bGPDstroke **gps_array,
2085  GHash *all_2d,
2086  int totstrokes,
2087  const float p2d_a1[2],
2088  const float p2d_a2[2],
2089  float r_hit[2])
2090 {
2091  bool hit = false;
2092  /* check segment with all segments of all strokes */
2093  for (int s = 0; s < totstrokes; s++) {
2094  bGPDstroke *gps_iter = gps_array[s];
2095  if (gps_iter->totpoints < 2) {
2096  continue;
2097  }
2098  /* get stroke 2d version */
2099  float(*points2d)[2] = BLI_ghash_lookup(all_2d, gps_iter);
2100 
2101  for (int i2 = 0; i2 < gps_iter->totpoints - 1; i2++) {
2102  float p2d_b1[2], p2d_b2[2];
2103  copy_v2_v2(p2d_b1, points2d[i2]);
2104  copy_v2_v2(p2d_b2, points2d[i2 + 1]);
2105 
2106  /* don't self check */
2107  if (gps == gps_iter) {
2108  if (equals_v2v2(p2d_a1, p2d_b1) || equals_v2v2(p2d_a1, p2d_b2)) {
2109  continue;
2110  }
2111  if (equals_v2v2(p2d_a2, p2d_b1) || equals_v2v2(p2d_a2, p2d_b2)) {
2112  continue;
2113  }
2114  }
2115  /* check collision */
2116  int check = isect_seg_seg_v2_point(p2d_a1, p2d_a2, p2d_b1, p2d_b2, r_hit);
2117  if (check > 0) {
2118  hit = true;
2119  break;
2120  }
2121  }
2122 
2123  if (hit) {
2124  break;
2125  }
2126  }
2127 
2128  if (!hit) {
2129  zero_v2(r_hit);
2130  }
2131 
2132  return hit;
2133 }
2134 
2136  bGPDstroke *gps, bGPDspoint *pt, bGPDspoint *pt_final, int i, int i2)
2137 {
2138  /* don't copy same point */
2139  if (i == i2) {
2140  return;
2141  }
2142 
2143  copy_v3_v3(&pt_final->x, &pt->x);
2144  pt_final->pressure = pt->pressure;
2145  pt_final->strength = pt->strength;
2146  pt_final->time = pt->time;
2147  pt_final->flag = pt->flag;
2148  pt_final->uv_fac = pt->uv_fac;
2149  pt_final->uv_rot = pt->uv_rot;
2150  copy_v4_v4(pt_final->vert_color, pt->vert_color);
2151 
2152  if (gps->dvert != NULL) {
2153  MDeformVert *dvert = &gps->dvert[i];
2154  MDeformVert *dvert_final = &gps->dvert[i2];
2155  MEM_SAFE_FREE(dvert_final->dw);
2156 
2157  dvert_final->totweight = dvert->totweight;
2158  if (dvert->dw == NULL) {
2159  dvert_final->dw = NULL;
2160  dvert_final->totweight = 0;
2161  }
2162  else {
2163  dvert_final->dw = MEM_dupallocN(dvert->dw);
2164  }
2165  }
2166 }
2167 
2169  bGPDstroke *gps,
2170  bGPDspoint *a_pt,
2171  bGPDspoint *b_pt,
2172  const float co_a[3],
2173  const float co_b[3])
2174 {
2175  bGPDspoint *temp_points;
2176  int totnewpoints, oldtotpoints;
2177 
2178  totnewpoints = gps->totpoints;
2179  if (a_pt) {
2180  totnewpoints++;
2181  }
2182  if (b_pt) {
2183  totnewpoints++;
2184  }
2185 
2186  /* duplicate points in a temp area */
2187  temp_points = MEM_dupallocN(gps->points);
2188  oldtotpoints = gps->totpoints;
2189 
2190  /* look index of base points because memory is changed when resize points array */
2191  int a_idx = -1;
2192  int b_idx = -1;
2193  for (int i = 0; i < oldtotpoints; i++) {
2194  bGPDspoint *pt = &gps->points[i];
2195  if (pt == a_pt) {
2196  a_idx = i;
2197  }
2198  if (pt == b_pt) {
2199  b_idx = i;
2200  }
2201  }
2202 
2203  /* resize the points arrays */
2204  gps->totpoints = totnewpoints;
2205  gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
2206  if (gps->dvert != NULL) {
2207  gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
2208  }
2209 
2210  /* copy all points */
2211  int i2 = 0;
2212  for (int i = 0; i < oldtotpoints; i++) {
2213  bGPDspoint *pt = &temp_points[i];
2214  bGPDspoint *pt_final = &gps->points[i2];
2215  gpencil_copy_points(gps, pt, pt_final, i, i2);
2216 
2217  /* create new point duplicating point and copy location */
2218  if (ELEM(i, a_idx, b_idx)) {
2219  i2++;
2220  pt_final = &gps->points[i2];
2221  gpencil_copy_points(gps, pt, pt_final, i, i2);
2222  copy_v3_v3(&pt_final->x, (i == a_idx) ? co_a : co_b);
2223 
2224  /* Un-select. */
2225  pt_final->flag &= ~GP_SPOINT_SELECT;
2226  /* tag to avoid more checking with this point */
2227  pt_final->flag |= GP_SPOINT_TAG;
2228  }
2229 
2230  i2++;
2231  }
2232  /* Calc geometry data. */
2234 
2235  MEM_SAFE_FREE(temp_points);
2236 }
2237 
2238 static float gpencil_calc_factor(const float p2d_a1[2],
2239  const float p2d_a2[2],
2240  const float r_hit2d[2])
2241 {
2242  float dist1 = len_squared_v2v2(p2d_a1, p2d_a2);
2243  float dist2 = len_squared_v2v2(p2d_a1, r_hit2d);
2244  float f = dist1 > 0.0f ? dist2 / dist1 : 0.0f;
2245 
2246  /* apply a correction factor */
2247  float v1[2];
2248  interp_v2_v2v2(v1, p2d_a1, p2d_a2, f);
2249  float dist3 = len_squared_v2v2(p2d_a1, v1);
2250  float f1 = dist1 > 0.0f ? dist3 / dist1 : 0.0f;
2251  f = f + (f - f1);
2252 
2253  return f;
2254 }
2255 
2257  bGPDlayer *gpl,
2258  bGPDstroke *gps,
2259  bGPDspoint *pt,
2260  bool select,
2261  bool insert,
2262  const float scale,
2263  float r_hita[3],
2264  float r_hitb[3])
2265 {
2266  if (gps->totpoints < 2) {
2267  return 0;
2268  }
2269  const float min_factor = 0.0015f;
2270  bGPDspoint *pta1 = NULL;
2271  bGPDspoint *pta2 = NULL;
2272  float f = 0.0f;
2273  int i2 = 0;
2274 
2275  bGPDlayer *gpl_orig = (gpl->runtime.gpl_orig) ? gpl->runtime.gpl_orig : gpl;
2276  bGPDframe *gpf = gpl_orig->actframe;
2277  if (gpf == NULL) {
2278  return 0;
2279  }
2280 
2281  int memsize = BLI_listbase_count(&gpf->strokes);
2282  bGPDstroke **gps_array = MEM_callocN(sizeof(bGPDstroke *) * memsize, __func__);
2283 
2284  /* save points */
2285  bGPDspoint *oldpoints = MEM_dupallocN(gps->points);
2286 
2287  /* Save list of strokes to check */
2288  int totstrokes = 0;
2289  LISTBASE_FOREACH (bGPDstroke *, gps_iter, &gpf->strokes) {
2290  if (gps_iter->totpoints < 2) {
2291  continue;
2292  }
2293  gps_array[totstrokes] = gps_iter;
2294  totstrokes++;
2295  }
2296 
2297  if (totstrokes == 0) {
2298  return 0;
2299  }
2300 
2301  /* look for index of the current point */
2302  int cur_idx = -1;
2303  for (int i = 0; i < gps->totpoints; i++) {
2304  pta1 = &gps->points[i];
2305  if (pta1 == pt) {
2306  cur_idx = i;
2307  break;
2308  }
2309  }
2310  if (cur_idx < 0) {
2311  return 0;
2312  }
2313 
2314  /* Convert all gps points to 2d and save in a hash to avoid recalculation. */
2315  int direction = 0;
2316  float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints,
2317  "GP Stroke temp 2d points");
2319  gps->points, gps->totpoints, gps->points, gps->totpoints, points2d, scale, &direction);
2320 
2321  GHash *all_2d = BLI_ghash_ptr_new(__func__);
2322 
2323  for (int s = 0; s < totstrokes; s++) {
2324  bGPDstroke *gps_iter = gps_array[s];
2325  float(*points2d_iter)[2] = MEM_mallocN(sizeof(*points2d_iter) * gps_iter->totpoints, __func__);
2326 
2327  /* the extremes of the stroke are scaled to improve collision detection
2328  * for near lines */
2330  gps->totpoints,
2331  gps_iter->points,
2332  gps_iter->totpoints,
2333  points2d_iter,
2334  scale,
2335  &direction);
2336  BLI_ghash_insert(all_2d, gps_iter, points2d_iter);
2337  }
2338 
2339  bool hit_a = false;
2340  bool hit_b = false;
2341  float p2d_a1[2] = {0.0f, 0.0f};
2342  float p2d_a2[2] = {0.0f, 0.0f};
2343  float r_hit2d[2];
2344  bGPDspoint *hit_pointa = NULL;
2345  bGPDspoint *hit_pointb = NULL;
2346 
2347  /* analyze points before current */
2348  if (cur_idx > 0) {
2349  for (int i = cur_idx; i >= 0; i--) {
2350  pta1 = &gps->points[i];
2351  copy_v2_v2(p2d_a1, points2d[i]);
2352 
2353  i2 = i - 1;
2354  CLAMP_MIN(i2, 0);
2355  pta2 = &gps->points[i2];
2356  copy_v2_v2(p2d_a2, points2d[i2]);
2357 
2358  hit_a = gpencil_check_collision(gps, gps_array, all_2d, totstrokes, p2d_a1, p2d_a2, r_hit2d);
2359 
2360  if (select) {
2361  pta1->flag |= GP_SPOINT_SELECT;
2362  }
2363  else {
2364  pta1->flag &= ~GP_SPOINT_SELECT;
2365  }
2366 
2367  if (hit_a) {
2368  f = gpencil_calc_factor(p2d_a1, p2d_a2, r_hit2d);
2369  interp_v3_v3v3(r_hita, &pta1->x, &pta2->x, f);
2370  if (f > min_factor) {
2371  hit_pointa = pta2; /* first point is second (inverted loop) */
2372  }
2373  else {
2374  pta1->flag &= ~GP_SPOINT_SELECT;
2375  }
2376  break;
2377  }
2378  }
2379  }
2380 
2381  /* analyze points after current */
2382  for (int i = cur_idx; i < gps->totpoints; i++) {
2383  pta1 = &gps->points[i];
2384  copy_v2_v2(p2d_a1, points2d[i]);
2385 
2386  i2 = i + 1;
2387  CLAMP_MAX(i2, gps->totpoints - 1);
2388  pta2 = &gps->points[i2];
2389  copy_v2_v2(p2d_a2, points2d[i2]);
2390 
2391  hit_b = gpencil_check_collision(gps, gps_array, all_2d, totstrokes, p2d_a1, p2d_a2, r_hit2d);
2392 
2393  if (select) {
2394  pta1->flag |= GP_SPOINT_SELECT;
2395  }
2396  else {
2397  pta1->flag &= ~GP_SPOINT_SELECT;
2398  }
2399 
2400  if (hit_b) {
2401  f = gpencil_calc_factor(p2d_a1, p2d_a2, r_hit2d);
2402  interp_v3_v3v3(r_hitb, &pta1->x, &pta2->x, f);
2403  if (f > min_factor) {
2404  hit_pointb = pta1;
2405  }
2406  else {
2407  pta1->flag &= ~GP_SPOINT_SELECT;
2408  }
2409  break;
2410  }
2411  }
2412 
2413  /* insert new point in the collision points */
2414  if (insert) {
2415  gpencil_insert_point(gpd, gps, hit_pointa, hit_pointb, r_hita, r_hitb);
2416  }
2417 
2418  /* free memory */
2419  if (all_2d) {
2420  GHashIterator gh_iter;
2421  GHASH_ITER (gh_iter, all_2d) {
2422  float(*p2d)[2] = BLI_ghashIterator_getValue(&gh_iter);
2423  MEM_SAFE_FREE(p2d);
2424  }
2425  BLI_ghash_free(all_2d, NULL, NULL);
2426  }
2427 
2428  /* if no hit, reset selection flag */
2429  if ((!hit_a) && (!hit_b)) {
2430  for (int i = 0; i < gps->totpoints; i++) {
2431  pta1 = &gps->points[i];
2432  pta2 = &oldpoints[i];
2433  pta1->flag = pta2->flag;
2434  }
2435  }
2436 
2437  MEM_SAFE_FREE(points2d);
2438  MEM_SAFE_FREE(gps_array);
2439  MEM_SAFE_FREE(oldpoints);
2440 
2441  /* return type of hit */
2442  if ((hit_a) && (hit_b)) {
2443  return 3;
2444  }
2445  if (hit_a) {
2446  return 1;
2447  }
2448  if (hit_b) {
2449  return 2;
2450  }
2451  return 0;
2452 }
2453 
2455 {
2457  bGPdata *gpd = ob->data;
2458 
2459  /* for "toggle", test for existing selected strokes */
2460  if (action == SEL_TOGGLE) {
2461  action = SEL_SELECT;
2462 
2463  CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
2464  if (gps->flag & GP_STROKE_SELECT) {
2465  action = SEL_DESELECT;
2466  break; /* XXX: this only gets out of the inner loop. */
2467  }
2468  }
2469  CTX_DATA_END;
2470  }
2471 
2472  /* if deselecting, we need to deselect strokes across all frames
2473  * - Currently, an exception is only given for deselection
2474  * Selecting and toggling should only affect what's visible,
2475  * while deselecting helps clean up unintended/forgotten
2476  * stuff on other frames
2477  */
2478  if (action == SEL_DESELECT) {
2479  /* deselect strokes across editable layers
2480  * NOTE: we limit ourselves to editable layers, since once a layer is "locked/hidden
2481  * nothing should be able to touch it
2482  */
2483  /* Set selection index to 0. */
2484  gpd->select_last_index = 0;
2485 
2486  CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
2487 
2488  /* deselect all strokes on all frames */
2489  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
2490  bGPDstroke *gps;
2491 
2492  for (gps = gpf->strokes.first; gps; gps = gps->next) {
2493  bGPDspoint *pt;
2494  int i;
2495 
2496  /* only edit strokes that are valid in this view... */
2497  if (ED_gpencil_stroke_can_use(C, gps)) {
2498  for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
2499  pt->flag &= ~GP_SPOINT_SELECT;
2500  }
2501 
2502  gps->flag &= ~GP_STROKE_SELECT;
2504  }
2505  }
2506  }
2507  }
2508  CTX_DATA_END;
2509  }
2510  else {
2511  /* select or deselect all strokes */
2512  CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
2513  bGPDspoint *pt;
2514  int i;
2515  bool selected = false;
2516 
2517  /* Change selection status of all points, then make the stroke match */
2518  for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
2519  switch (action) {
2520  case SEL_SELECT:
2521  pt->flag |= GP_SPOINT_SELECT;
2522  break;
2523 #if 0
2524  case SEL_DESELECT:
2525  pt->flag &= ~GP_SPOINT_SELECT;
2526  break;
2527 #endif
2528  case SEL_INVERT:
2529  pt->flag ^= GP_SPOINT_SELECT;
2530  break;
2531  }
2532 
2533  if (pt->flag & GP_SPOINT_SELECT) {
2534  selected = true;
2535  }
2536  }
2537 
2538  /* Change status of stroke */
2539  if (selected) {
2540  gps->flag |= GP_STROKE_SELECT;
2542  }
2543  else {
2544  gps->flag &= ~GP_STROKE_SELECT;
2546  }
2547  }
2548  CTX_DATA_END;
2549  }
2550 }
2551 
2553 {
2554  /* if toggle, check if we need to select or deselect */
2555  if (action == SEL_TOGGLE) {
2556  action = SEL_SELECT;
2557  GP_EDITABLE_CURVES_BEGIN(gps_iter, C, gpl, gps, gpc)
2558  {
2559  if (gpc->flag & GP_CURVE_SELECT) {
2560  action = SEL_DESELECT;
2561  }
2562  }
2563  GP_EDITABLE_CURVES_END(gps_iter);
2564  }
2565 
2566  if (action == SEL_DESELECT) {
2567  /* Set selection index to 0. */
2569  bGPdata *gpd = ob->data;
2570  gpd->select_last_index = 0;
2571 
2572  GP_EDITABLE_CURVES_BEGIN(gps_iter, C, gpl, gps, gpc)
2573  {
2574  for (int i = 0; i < gpc->tot_curve_points; i++) {
2575  bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
2576  BezTriple *bezt = &gpc_pt->bezt;
2577  gpc_pt->flag &= ~GP_CURVE_POINT_SELECT;
2578  BEZT_DESEL_ALL(bezt);
2579  }
2580  gpc->flag &= ~GP_CURVE_SELECT;
2581  gps->flag &= ~GP_STROKE_SELECT;
2583  }
2584  GP_EDITABLE_CURVES_END(gps_iter);
2585  }
2586  else {
2587  GP_EDITABLE_STROKES_BEGIN (gps_iter, C, gpl, gps) {
2589  bGPdata *gpd = ob->data;
2590  bool selected = false;
2591 
2592  /* Make sure stroke has an editcurve */
2593  if (gps->editcurve == NULL) {
2594  BKE_gpencil_stroke_editcurve_update(gpd, gpl, gps);
2595  gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
2597  }
2598 
2599  bGPDcurve *gpc = gps->editcurve;
2600  for (int i = 0; i < gpc->tot_curve_points; i++) {
2601  bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
2602  BezTriple *bezt = &gpc_pt->bezt;
2603  switch (action) {
2604  case SEL_SELECT:
2605  gpc_pt->flag |= GP_CURVE_POINT_SELECT;
2606  BEZT_SEL_ALL(bezt);
2607  break;
2608  case SEL_INVERT:
2609  gpc_pt->flag ^= GP_CURVE_POINT_SELECT;
2610  BEZT_SEL_INVERT(bezt);
2611  break;
2612  default:
2613  break;
2614  }
2615 
2616  if (gpc_pt->flag & GP_CURVE_POINT_SELECT) {
2617  selected = true;
2618  }
2619  }
2620 
2621  if (selected) {
2622  gpc->flag |= GP_CURVE_SELECT;
2623  gps->flag |= GP_STROKE_SELECT;
2625  }
2626  else {
2627  gpc->flag &= ~GP_CURVE_SELECT;
2628  gps->flag &= ~GP_STROKE_SELECT;
2630  }
2631  }
2632  GP_EDITABLE_STROKES_END(gps_iter);
2633  }
2634 }
2635 
2637  int *buffer_size,
2638  int *buffer_used,
2639  const bool clear)
2640 {
2641  tGPspoint *p = NULL;
2642 
2643  /* By default a buffer is created with one block with a predefined number of free points,
2644  * if the size is not enough, the cache is reallocated adding a new block of free points.
2645  * This is done in order to keep cache small and improve speed. */
2646  if (*buffer_used + 1 > *buffer_size) {
2647  if ((*buffer_size == 0) || (buffer_array == NULL)) {
2648  p = MEM_callocN(sizeof(struct tGPspoint) * GP_STROKE_BUFFER_CHUNK, "GPencil Sbuffer");
2649  *buffer_size = GP_STROKE_BUFFER_CHUNK;
2650  }
2651  else {
2652  *buffer_size += GP_STROKE_BUFFER_CHUNK;
2653  p = MEM_recallocN(buffer_array, sizeof(struct tGPspoint) * *buffer_size);
2654  }
2655 
2656  if (p == NULL) {
2657  *buffer_size = *buffer_used = 0;
2658  }
2659 
2660  buffer_array = p;
2661  }
2662 
2663  /* clear old data */
2664  if (clear) {
2665  *buffer_used = 0;
2666  if (buffer_array != NULL) {
2667  memset(buffer_array, 0, sizeof(tGPspoint) * *buffer_size);
2668  }
2669  }
2670 
2671  return buffer_array;
2672 }
2673 
2675 {
2676  bGPdata *gpd_eval = (bGPdata *)ob_eval->data;
2677 
2678  gpd_eval->runtime.sbuffer = gpd->runtime.sbuffer;
2679  gpd_eval->runtime.sbuffer_sflag = gpd->runtime.sbuffer_sflag;
2680  gpd_eval->runtime.sbuffer_used = gpd->runtime.sbuffer_used;
2681  gpd_eval->runtime.sbuffer_size = gpd->runtime.sbuffer_size;
2682  gpd_eval->runtime.tot_cp_points = gpd->runtime.tot_cp_points;
2683  gpd_eval->runtime.cp_points = gpd->runtime.cp_points;
2684 }
2685 
2687 {
2688  /* Mark all grease pencil data-blocks of the scene. */
2689  FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
2691  if (ob->type == OB_GPENCIL) {
2692  bGPdata *gpd = (bGPdata *)ob->data;
2693  gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
2695  }
2696  }
2698  }
2700 
2702 
2704 }
2705 
2707 {
2708  const bool is_vertex = (GPENCIL_USE_VERTEX_COLOR_FILL(ts, brush) &&
2710  (!GPENCIL_USE_VERTEX_COLOR_FILL(ts, brush) &&
2712  if (is_vertex) {
2713  copy_v3_v3(gps->vert_color_fill, brush->rgb);
2716  }
2717  else {
2718  zero_v4(gps->vert_color_fill);
2719  }
2720 }
2721 
2723  Brush *brush,
2724  bGPDspoint *pt,
2725  tGPspoint *tpt)
2726 {
2727  const bool is_vertex = (GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush) &&
2729  (!GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush) &&
2731 
2732  if (is_vertex) {
2733  if (tpt == NULL) {
2734  copy_v3_v3(pt->vert_color, brush->rgb);
2735  pt->vert_color[3] = brush->gpencil_settings->vertex_factor;
2737  }
2738  else {
2739  copy_v3_v3(pt->vert_color, tpt->vert_color);
2740  pt->vert_color[3] = brush->gpencil_settings->vertex_factor;
2741  }
2742  }
2743  else {
2744  zero_v4(pt->vert_color);
2745  }
2746 }
2747 
2749  const int mval[2],
2750  GpRandomSettings *random_settings)
2751 {
2752  int seed = ((uint)(ceil(PIL_check_seconds_timer())) + 1) % 128;
2753  /* Use mouse position to get randomness. */
2754  int ix = mval[0] * seed;
2755  int iy = mval[1] * seed;
2756  int iz = ix + iy * seed;
2757  zero_v3(random_settings->hsv);
2758 
2759  BrushGpencilSettings *brush_settings = brush->gpencil_settings;
2760  /* Random to Hue. */
2761  if (brush_settings->random_hue > 0.0f) {
2762  float rand = BLI_hash_int_01(BLI_hash_int_2d(ix, iy)) * 2.0f - 1.0f;
2763  random_settings->hsv[0] = rand * brush_settings->random_hue * 0.5f;
2764  }
2765  /* Random to Saturation. */
2766  if (brush_settings->random_saturation > 0.0f) {
2767  float rand = BLI_hash_int_01(BLI_hash_int_2d(iy, ix)) * 2.0f - 1.0f;
2768  random_settings->hsv[1] = rand * brush_settings->random_saturation;
2769  }
2770  /* Random to Value. */
2771  if (brush_settings->random_value > 0.0f) {
2772  float rand = BLI_hash_int_01(BLI_hash_int_2d(ix * iz, iy * iz)) * 2.0f - 1.0f;
2773  random_settings->hsv[2] = rand * brush_settings->random_value;
2774  }
2775 
2776  /* Random to pressure. */
2777  if (brush_settings->draw_random_press > 0.0f) {
2778  random_settings->pressure = BLI_hash_int_01(BLI_hash_int_2d(ix + iz, iy + iz)) * 2.0f - 1.0f;
2779  }
2780 
2781  /* Random to color strength. */
2782  if (brush_settings->draw_random_strength) {
2783  random_settings->strength = BLI_hash_int_01(BLI_hash_int_2d(ix + iy, iy + iz + ix)) * 2.0f -
2784  1.0f;
2785  }
2786 
2787  /* Random to uv texture rotation. */
2788  if (brush_settings->uv_random > 0.0f) {
2789  random_settings->uv = BLI_hash_int_01(BLI_hash_int_2d(iy + iz, ix * iz)) * 2.0f - 1.0f;
2790  }
2791 }
2792 
2794  bGPdata *gpd, Brush *brush, tGPspoint *tpt, const float random_color[3], float pen_pressure)
2795 {
2796  BrushGpencilSettings *brush_settings = brush->gpencil_settings;
2797  if (brush_settings->flag & GP_BRUSH_GROUP_RANDOM) {
2798  int seed = ((uint)(ceil(PIL_check_seconds_timer())) + 1) % 128;
2799 
2800  int ix = (int)(tpt->m_xy[0] * seed);
2801  int iy = (int)(tpt->m_xy[1] * seed);
2802  int iz = ix + iy * seed;
2803  float hsv[3];
2804  float factor_value[3];
2805  zero_v3(factor_value);
2806 
2807  /* Apply randomness to Hue. */
2808  if (brush_settings->random_hue > 0.0f) {
2809  if ((brush_settings->flag2 & GP_BRUSH_USE_HUE_AT_STROKE) == 0) {
2810 
2811  float rand = BLI_hash_int_01(BLI_hash_int_2d(ix, gpd->runtime.sbuffer_used)) * 2.0f - 1.0f;
2812  factor_value[0] = rand * brush_settings->random_hue * 0.5f;
2813  }
2814  else {
2815  factor_value[0] = random_color[0];
2816  }
2817 
2818  /* Apply random curve. */
2819  if (brush_settings->flag2 & GP_BRUSH_USE_HUE_RAND_PRESS) {
2820  factor_value[0] *= BKE_curvemapping_evaluateF(
2821  brush_settings->curve_rand_hue, 0, pen_pressure);
2822  }
2823  }
2824 
2825  /* Apply randomness to Saturation. */
2826  if (brush_settings->random_saturation > 0.0f) {
2827  if ((brush_settings->flag2 & GP_BRUSH_USE_SAT_AT_STROKE) == 0) {
2828  float rand = BLI_hash_int_01(BLI_hash_int_2d(iy, gpd->runtime.sbuffer_used)) * 2.0f - 1.0f;
2829  factor_value[1] = rand * brush_settings->random_saturation;
2830  }
2831  else {
2832  factor_value[1] = random_color[1];
2833  }
2834 
2835  /* Apply random curve. */
2836  if (brush_settings->flag2 & GP_BRUSH_USE_SAT_RAND_PRESS) {
2837  factor_value[1] *= BKE_curvemapping_evaluateF(
2838  brush_settings->curve_rand_saturation, 0, pen_pressure);
2839  }
2840  }
2841 
2842  /* Apply randomness to Value. */
2843  if (brush_settings->random_value > 0.0f) {
2844  if ((brush_settings->flag2 & GP_BRUSH_USE_VAL_AT_STROKE) == 0) {
2845  float rand = BLI_hash_int_01(BLI_hash_int_2d(iz, gpd->runtime.sbuffer_used)) * 2.0f - 1.0f;
2846  factor_value[2] = rand * brush_settings->random_value;
2847  }
2848  else {
2849  factor_value[2] = random_color[2];
2850  }
2851 
2852  /* Apply random curve. */
2853  if (brush_settings->flag2 & GP_BRUSH_USE_VAL_RAND_PRESS) {
2854  factor_value[2] *= BKE_curvemapping_evaluateF(
2855  brush_settings->curve_rand_value, 0, pen_pressure);
2856  }
2857  }
2858 
2859  rgb_to_hsv_v(tpt->vert_color, hsv);
2860  add_v3_v3(hsv, factor_value);
2861  /* For Hue need to cover all range, but for Saturation and Value
2862  * is not logic because the effect is too hard, so the value is just clamped. */
2863  if (hsv[0] < 0.0f) {
2864  hsv[0] += 1.0f;
2865  }
2866  else if (hsv[0] > 1.0f) {
2867  hsv[0] -= 1.0f;
2868  }
2869 
2870  CLAMP3(hsv, 0.0f, 1.0f);
2871  hsv_to_rgb_v(hsv, tpt->vert_color);
2872  }
2873 }
2874 
2876  Object *ob,
2877  ToolSettings *ts,
2878  Brush *brush,
2879  Material *material,
2880  float random_color[3],
2881  float pen_pressure)
2882 {
2883  bGPdata *gpd = (bGPdata *)ob->data;
2884  Object *ob_eval = (Object *)DEG_get_evaluated_id(depsgraph, &ob->id);
2885  bGPdata *gpd_eval = (bGPdata *)ob_eval->data;
2886  MaterialGPencilStyle *gp_style = material->gp_style;
2887 
2888  const bool is_vertex_fill =
2889  (GPENCIL_USE_VERTEX_COLOR_FILL(ts, brush) &&
2891  (!GPENCIL_USE_VERTEX_COLOR_FILL(ts, brush) &&
2893 
2894  const bool is_vertex_stroke =
2895  (GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush) &&
2897  (!GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush) &&
2899 
2900  int idx = gpd->runtime.sbuffer_used;
2901  tGPspoint *tpt = (tGPspoint *)gpd->runtime.sbuffer + idx;
2902 
2903  float vertex_color[4];
2904  copy_v3_v3(vertex_color, brush->rgb);
2905  vertex_color[3] = brush->gpencil_settings->vertex_factor;
2906  srgb_to_linearrgb_v4(vertex_color, vertex_color);
2907 
2908  /* Copy fill vertex color. */
2909  if (is_vertex_fill) {
2910  copy_v4_v4(gpd->runtime.vert_color_fill, vertex_color);
2911  }
2912  else {
2913  copy_v4_v4(gpd->runtime.vert_color_fill, gp_style->fill_rgba);
2914  }
2915  /* Copy stroke vertex color. */
2916  if (is_vertex_stroke) {
2917  copy_v4_v4(tpt->vert_color, vertex_color);
2918  }
2919  else {
2920  copy_v4_v4(tpt->vert_color, gp_style->stroke_rgba);
2921  }
2922 
2923  /* Random Color. */
2924  gpencil_sbuffer_vertex_color_random(gpd, brush, tpt, random_color, pen_pressure);
2925 
2926  /* Copy to evaluate data because paint operators don't tag refresh until end for speedup
2927  * painting. */
2928  if (gpd_eval != NULL) {
2930  gpd_eval->runtime.matid = gpd->runtime.matid;
2931  }
2932 }
2933 
2935  const bGPDstroke *gps,
2936  const float diff_mat[4][4],
2937  float r_min[2],
2938  float r_max[2])
2939 {
2940  float bounds[8][2];
2941  BoundBox bb;
2943 
2944  /* Project 8 vertices in 2D. */
2945  for (int i = 0; i < 8; i++) {
2946  bGPDspoint pt_dummy, pt_dummy_ps;
2947  copy_v3_v3(&pt_dummy.x, bb.vec[i]);
2948  gpencil_point_to_parent_space(&pt_dummy, diff_mat, &pt_dummy_ps);
2949  gpencil_point_to_xy_fl(gsc, gps, &pt_dummy_ps, &bounds[i][0], &bounds[i][1]);
2950  }
2951 
2952  /* Take extremes. */
2953  INIT_MINMAX2(r_min, r_max);
2954  for (int i = 0; i < 8; i++) {
2955  minmax_v2v2_v2(r_min, r_max, bounds[i]);
2956  }
2957 
2958  /* Ensure the bounding box is oriented to axis. */
2959  if (r_max[0] < r_min[0]) {
2960  SWAP(float, r_min[0], r_max[0]);
2961  }
2962  if (r_max[1] < r_min[1]) {
2963  SWAP(float, r_min[1], r_max[1]);
2964  }
2965 }
2966 
2968  bGPDstroke *gps,
2969  const float mval[2],
2970  const int radius,
2971  const float diff_mat[4][4])
2972 {
2973  const int offset = (int)ceil(sqrt((radius * radius) * 2));
2974  float boundbox_min[2];
2975  float boundbox_max[2];
2976 
2977  /* Check we have something to use (only for old files). */
2978  if (is_zero_v3(gps->boundbox_min)) {
2980  }
2981 
2982  ED_gpencil_projected_2d_bound_box(gsc, gps, diff_mat, boundbox_min, boundbox_max);
2983 
2984  rcti rect_stroke = {boundbox_min[0], boundbox_max[0], boundbox_min[1], boundbox_max[1]};
2985 
2986  /* For mouse, add a small offset to avoid false negative in corners. */
2987  rcti rect_mouse = {mval[0] - offset, mval[0] + offset, mval[1] - offset, mval[1] + offset};
2988 
2989  /* Check collision between both rectangles. */
2990  return BLI_rcti_isect(&rect_stroke, &rect_mouse, NULL);
2991 }
2992 
2994  const GP_SpaceConversion *gsc,
2995  const int mval[2],
2996  const float diff_mat[4][4])
2997 {
2998  bool hit = false;
2999  if (gps->totpoints == 0) {
3000  return hit;
3001  }
3002 
3003  int(*mcoords)[2] = NULL;
3004  int len = gps->totpoints;
3005  mcoords = MEM_mallocN(sizeof(int[2]) * len, __func__);
3006 
3007  /* Convert stroke to 2D array of points. */
3008  const bGPDspoint *pt;
3009  int i;
3010  for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
3011  bGPDspoint pt2;
3012  gpencil_point_to_parent_space(pt, diff_mat, &pt2);
3013  gpencil_point_to_xy(gsc, gps, &pt2, &mcoords[i][0], &mcoords[i][1]);
3014  }
3015 
3016  /* Compute bound-box of lasso (for faster testing later). */
3017  rcti rect;
3018  BLI_lasso_boundbox(&rect, mcoords, len);
3019 
3020  /* Test if point inside stroke. */
3021  hit = ((!ELEM(V2D_IS_CLIPPED, mval[0], mval[1])) && BLI_rcti_isect_pt(&rect, mval[0], mval[1]) &&
3022  BLI_lasso_is_point_inside(mcoords, len, mval[0], mval[1], INT_MAX));
3023 
3024  /* Free memory. */
3025  MEM_SAFE_FREE(mcoords);
3026 
3027  return hit;
3028 }
3029 
3031  const float diff_mat[4][4],
3032  bGPDstroke *gps,
3033  float r_ctrl1[2],
3034  float r_ctrl2[2])
3035 {
3036  bGPDspoint pt_dummy_ps;
3037 
3038  gpencil_point_to_parent_space(&gps->points[0], diff_mat, &pt_dummy_ps);
3039  gpencil_point_to_xy_fl(gsc, gps, &pt_dummy_ps, &r_ctrl1[0], &r_ctrl1[1]);
3040  gpencil_point_to_parent_space(&gps->points[gps->totpoints - 1], diff_mat, &pt_dummy_ps);
3041  gpencil_point_to_xy_fl(gsc, gps, &pt_dummy_ps, &r_ctrl2[0], &r_ctrl2[1]);
3042 }
3043 
3045  const GP_SpaceConversion *gsc,
3046  bGPDlayer *gpl,
3047  bGPDframe *gpf,
3048  bGPDstroke *gps,
3049  const float ctrl1[2],
3050  const float ctrl2[2],
3051  const float radius,
3052  int *r_index)
3053 {
3056  bGPDstroke *gps_rtn = NULL;
3057  const float radius_sqr = radius * radius;
3058 
3059  /* calculate difference matrix object */
3060  float diff_mat[4][4];
3062 
3063  /* Calculate the extremes of the stroke in 2D. */
3064  bGPDspoint pt_parent;
3065  float pt2d_start[2], pt2d_end[2];
3066 
3067  bGPDspoint *pt = &gps->points[0];
3068  gpencil_point_to_parent_space(pt, diff_mat, &pt_parent);
3069  gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d_start[0], &pt2d_start[1]);
3070 
3071  pt = &gps->points[gps->totpoints - 1];
3072  gpencil_point_to_parent_space(pt, diff_mat, &pt_parent);
3073  gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d_end[0], &pt2d_end[1]);
3074 
3075  /* Loop all strokes of the active frame. */
3076  float dist_min = FLT_MAX;
3077  LISTBASE_FOREACH (bGPDstroke *, gps_target, &gpf->strokes) {
3078  /* Check if the color is editable. */
3079  if ((gps_target == gps) || (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false)) {
3080  continue;
3081  }
3082 
3083  /* Check that stroke is not closed. Closed strokes must not be included in the merge. */
3084  if (gps_target->flag & GP_STROKE_CYCLIC) {
3085  continue;
3086  }
3087 
3088  /* Check if one of the ends is inside target stroke bounding box. */
3089  if ((!ED_gpencil_stroke_check_collision(gsc, gps_target, pt2d_start, radius, diff_mat)) &&
3090  (!ED_gpencil_stroke_check_collision(gsc, gps_target, pt2d_end, radius, diff_mat))) {
3091  continue;
3092  }
3093  /* Check the distance of the ends with the ends of target stroke to avoid middle contact.
3094  * All is done in 2D plane. */
3095  float pt2d_target_start[2], pt2d_target_end[2];
3096 
3097  pt = &gps_target->points[0];
3098  gpencil_point_to_parent_space(pt, diff_mat, &pt_parent);
3099  gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d_target_start[0], &pt2d_target_start[1]);
3100 
3101  pt = &gps_target->points[gps_target->totpoints - 1];
3102  gpencil_point_to_parent_space(pt, diff_mat, &pt_parent);
3103  gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d_target_end[0], &pt2d_target_end[1]);
3104 
3105  /* If the distance to the original stroke extremes is too big, the stroke must not be joined.
3106  */
3107  if ((len_squared_v2v2(ctrl1, pt2d_target_start) > radius_sqr) &&
3108  (len_squared_v2v2(ctrl1, pt2d_target_end) > radius_sqr) &&
3109  (len_squared_v2v2(ctrl2, pt2d_target_start) > radius_sqr) &&
3110  (len_squared_v2v2(ctrl2, pt2d_target_end) > radius_sqr)) {
3111  continue;
3112  }
3113 
3114  if ((len_squared_v2v2(pt2d_start, pt2d_target_start) > radius_sqr) &&
3115  (len_squared_v2v2(pt2d_start, pt2d_target_end) > radius_sqr) &&
3116  (len_squared_v2v2(pt2d_end, pt2d_target_start) > radius_sqr) &&
3117  (len_squared_v2v2(pt2d_end, pt2d_target_end) > radius_sqr)) {
3118  continue;
3119  }
3120 
3121  /* Loop all points and check what is the nearest point. */
3122  int i;
3123  for (i = 0, pt = gps_target->points; i < gps_target->totpoints; i++, pt++) {
3124  /* Convert point to 2D. */
3125  float pt2d[2];
3126  gpencil_point_to_parent_space(pt, diff_mat, &pt_parent);
3127  gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d[0], &pt2d[1]);
3128 
3129  /* Check with Start point. */
3130  float dist = len_squared_v2v2(pt2d, pt2d_start);
3131  if ((dist <= radius_sqr) && (dist < dist_min)) {
3132  *r_index = i;
3133  dist_min = dist;
3134  gps_rtn = gps_target;
3135  }
3136  /* Check with End point. */
3137  dist = len_squared_v2v2(pt2d, pt2d_end);
3138  if ((dist <= radius_sqr) && (dist < dist_min)) {
3139  *r_index = i;
3140  dist_min = dist;
3141  gps_rtn = gps_target;
3142  }
3143  }
3144  }
3145 
3146  return gps_rtn;
3147 }
3148 
3150  bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *gps_dst, const int pt_index)
3151 {
3152  if ((gps->totpoints < 1) || (gps_dst->totpoints < 1)) {
3153  return NULL;
3154  }
3155  BLI_assert(pt_index >= 0 && pt_index < gps_dst->totpoints);
3156 
3157  bGPDspoint *pt = NULL;
3158 
3159  /* Cannot be cyclic. */
3160  gps->flag &= ~GP_STROKE_CYCLIC;
3161  gps_dst->flag &= ~GP_STROKE_CYCLIC;
3162 
3163  /* Trim stroke. */
3164  bGPDstroke *gps_final = gps_dst;
3165  if ((pt_index > 0) && (pt_index < gps_dst->totpoints - 2)) {
3166  /* Untag any pending operation. */
3167  gps_dst->flag &= ~GP_STROKE_TAG;
3168  for (int i = 0; i < gps_dst->totpoints; i++) {
3169  gps_dst->points[i].flag &= ~GP_SPOINT_TAG;
3170  }
3171 
3172  /* Delete points of the shorter extreme */
3173  pt = &gps_dst->points[0];
3174  float dist_to_start = BKE_gpencil_stroke_segment_length(gps_dst, 0, pt_index, true);
3175  pt = &gps_dst->points[gps_dst->totpoints - 1];
3176  float dist_to_end = BKE_gpencil_stroke_segment_length(
3177  gps_dst, pt_index, gps_dst->totpoints - 1, true);
3178 
3179  if (dist_to_start < dist_to_end) {
3180  for (int i = 0; i < pt_index; i++) {
3181  gps_dst->points[i].flag |= GP_SPOINT_TAG;
3182  }
3183  }
3184  else {
3185  for (int i = pt_index + 1; i < gps_dst->totpoints; i++) {
3186  gps_dst->points[i].flag |= GP_SPOINT_TAG;
3187  }
3188  }
3189  /* Remove tagged points to trim stroke. */
3191  gpd, gpf, gps_dst, gps_dst->next, GP_SPOINT_TAG, false, false, 0);
3192  }
3193 
3194  /* Join both strokes. */
3195  int totpoint = gps_final->totpoints;
3196  BKE_gpencil_stroke_join(gps_final, gps, false, true, true);
3197 
3198  /* Select the join points and merge if the distance is very small. */
3199  pt = &gps_final->points[totpoint - 1];
3200  pt->flag |= GP_SPOINT_SELECT;
3201 
3202  pt = &gps_final->points[totpoint];
3203  pt->flag |= GP_SPOINT_SELECT;
3204  BKE_gpencil_stroke_merge_distance(gpd, gpf, gps_final, 0.01f, false);
3205 
3206  /* Unselect all points. */
3207  for (int i = 0; i < gps_final->totpoints; i++) {
3208  gps_final->points[i].flag &= ~GP_SPOINT_SELECT;
3209  }
3210 
3211  /* Delete old stroke. */
3212  BLI_remlink(&gpf->strokes, gps);
3214 
3215  return gps_final;
3216 }
3217 
3219 {
3220  if (gps == NULL) {
3221  return;
3222  }
3223  bGPDspoint *pt_start = &gps->points[0];
3224  bGPDspoint *pt_end = &gps->points[gps->totpoints - 1];
3225 
3226  const float threshold_sqr = threshold * threshold;
3227  float dist_to_close = len_squared_v3v3(&pt_start->x, &pt_end->x);
3228  if (dist_to_close < threshold_sqr) {
3229  gps->flag |= GP_STROKE_CYCLIC;
3231  }
3232 }
3233 
3235  bGPDlayer *gpl_src,
3236  bGPDlayer *gpl_dst,
3237  const bool reverse)
3238 {
3239  /* Collect frames of gpl_dst in hash table to avoid O(n^2) lookups. */
3240  GHash *gh_frames_dst = BLI_ghash_int_new_ex(__func__, 64);
3241  LISTBASE_FOREACH (bGPDframe *, gpf_dst, &gpl_dst->frames) {
3242  BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_dst->framenum), gpf_dst);
3243  }
3244 
3245  /* Read all frames from merge layer and add any missing in destination layer,
3246  * copying all previous strokes to keep the image equals.
3247  * Need to do it in a separated loop to avoid strokes accumulation. */
3248  LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) {
3249  /* Try to find frame in destination layer hash table. */
3250  bGPDframe *gpf_dst = BLI_ghash_lookup(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum));
3251  if (!gpf_dst) {
3252  gpf_dst = BKE_gpencil_layer_frame_get(gpl_dst, gpf_src->framenum, GP_GETFRAME_ADD_COPY);
3253  /* Use same frame type. */
3254  gpf_dst->key_type = gpf_src->key_type;
3255  BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum), gpf_dst);
3256  }
3257 
3258  /* Copy current source frame to further frames
3259  * that are keyframes in destination layer and not in source layer
3260  * to keep the image equals. */
3261  if (gpf_dst->next && (!gpf_src->next || (gpf_dst->next->framenum < gpf_src->next->framenum))) {
3262  gpf_dst = gpf_dst->next;
3264  }
3265  }
3266 
3267  /* Read all frames from merge layer and add strokes. */
3268  LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) {
3269  /* Try to find frame in destination layer hash table. */
3270  bGPDframe *gpf_dst = BLI_ghash_lookup(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum));
3271  /* Add to tail all strokes. */
3272  if (gpf_dst) {
3273  if (reverse) {
3274  BLI_movelisttolist_reverse(&gpf_dst->strokes, &gpf_src->strokes);
3275  }
3276  else {
3277  BLI_movelisttolist(&gpf_dst->strokes, &gpf_src->strokes);
3278  }
3279  }
3280  }
3281 
3282  /* Add Masks to destination layer. */
3284  /* Don't add merged layers or missing layer names. */
3285  if (!BKE_gpencil_layer_named_get(gpd, mask->name) || STREQ(mask->name, gpl_src->info) ||
3286  STREQ(mask->name, gpl_dst->info)) {
3287  continue;
3288  }
3289  if (!BKE_gpencil_layer_mask_named_get(gpl_dst, mask->name)) {
3290  bGPDlayer_Mask *mask_new = MEM_dupallocN(mask);
3291  BLI_addtail(&gpl_dst->mask_layers, mask_new);
3292  gpl_dst->act_mask++;
3293  }
3294  }
3295 
3296  /* Set destination layer as active. */
3297  BKE_gpencil_layer_active_set(gpd, gpl_dst);
3298 
3299  /* Now delete merged layer. */
3300  BKE_gpencil_layer_delete(gpd, gpl_src);
3301  BLI_ghash_free(gh_frames_dst, NULL, NULL);
3302 
3303  /* Reorder masking. */
3304  if (gpl_dst->mask_layers.first) {
3305  BKE_gpencil_layer_mask_sort(gpd, gpl_dst);
3306  }
3307 }
typedef float(TangentPoint)[2]
Blender kernel action and pose functionality.
struct bPoseChannel * BKE_pose_channel_find_name(const struct bPose *pose, const char *name)
void BKE_brush_gpencil_paint_presets(struct Main *bmain, struct ToolSettings *ts, bool reset)
Definition: brush.cc:1308
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_END
#define FOREACH_SCENE_COLLECTION_END
#define FOREACH_SCENE_COLLECTION_BEGIN(scene, _instance)
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(_collection, _object)
void BKE_curvemapping_init(struct CurveMapping *cumap)
Definition: colortools.c:1235
float BKE_curvemapping_evaluateF(const struct CurveMapping *cumap, int cur, float value)
void BKE_curvemap_reset(struct CurveMap *cuma, const struct rctf *clipr, int preset, int slope)
@ CURVEMAP_SLOPE_POSITIVE
struct CurveMapping * BKE_curvemapping_add(int tot, float minx, float miny, float maxx, float maxy)
Definition: colortools.c:72
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:738
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
#define CTX_DATA_BEGIN(C, Type, instance, member)
Definition: BKE_context.h:269
struct bGPdata * CTX_data_gpencil_data(const bContext *C)
Definition: context.c:1445
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1528
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1353
struct bScreen * CTX_wm_screen(const bContext *C)
Definition: context.c:733
struct SpaceLink * CTX_wm_space_data(const bContext *C)
Definition: context.c:743
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
struct ToolSettings * CTX_data_tool_settings(const bContext *C)
Definition: context.c:1282
#define CTX_DATA_END
Definition: BKE_context.h:278
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
support for deformation groups and hooks.
struct MDeformWeight * BKE_defvert_find_index(const struct MDeformVert *dv, int defgroup)
struct MDeformWeight * BKE_defvert_ensure_index(struct MDeformVert *dv, int defgroup)
Definition: deform.c:748
void BKE_defvert_remove_group(struct MDeformVert *dvert, struct MDeformWeight *dw)
Definition: deform.c:804
void BKE_gpencil_stroke_select_index_set(struct bGPdata *gpd, struct bGPDstroke *gps)
Definition: gpencil.c:1155
void BKE_gpencil_layer_active_set(struct bGPdata *gpd, struct bGPDlayer *active)
Definition: gpencil.c:1601
#define GPENCIL_USE_VERTEX_COLOR_STROKE(toolsettings, brush)
Definition: BKE_gpencil.h:58
struct bGPDlayer_Mask * BKE_gpencil_layer_mask_named_get(struct bGPDlayer *gpl, const char *name)
Definition: gpencil.c:1427
void BKE_gpencil_layer_mask_sort(struct bGPdata *gpd, struct bGPDlayer *gpl)
Definition: gpencil.c:1484
struct bGPDstroke * BKE_gpencil_stroke_duplicate(struct bGPDstroke *gps_src, bool dup_points, bool dup_curve)
Definition: gpencil.c:855
struct bGPDlayer * BKE_gpencil_layer_active_get(struct bGPdata *gpd)
Definition: gpencil.c:1558
void BKE_gpencil_stroke_select_index_reset(struct bGPDstroke *gps)
Definition: gpencil.c:1161
void BKE_gpencil_dvert_ensure(struct bGPDstroke *gps)
Definition: gpencil.c:1891
bool BKE_gpencil_layer_is_editable(const struct bGPDlayer *gpl)
struct bGPDlayer * BKE_gpencil_layer_named_get(struct bGPdata *gpd, const char *name)
Definition: gpencil.c:1419
void BKE_gpencil_free_stroke(struct bGPDstroke *gps)
Definition: gpencil.c:391
struct Material * BKE_gpencil_object_material_ensure_from_active_input_toolsettings(struct Main *bmain, struct Object *ob, struct ToolSettings *ts)
Definition: gpencil.c:1768
struct Material * BKE_gpencil_object_material_from_brush_get(struct Object *ob, struct Brush *brush)
Definition: gpencil.c:1748
struct bGPDframe * BKE_gpencil_layer_frame_get(struct bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew)
Definition: gpencil.c:1232
#define GPENCIL_STRENGTH_MIN
Definition: BKE_gpencil.h:324
void BKE_gpencil_layer_transform_matrix_get(const struct Depsgraph *depsgraph, struct Object *obact, struct bGPDlayer *gpl, float diff_mat[4][4])
void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl)
Definition: gpencil.c:1653
@ GP_GETFRAME_ADD_COPY
Definition: BKE_gpencil.h:343
#define GPENCIL_USE_VERTEX_COLOR_FILL(toolsettings, brush)
Definition: BKE_gpencil.h:62
void BKE_gpencil_stroke_editcurve_update(struct bGPdata *gpd, struct bGPDlayer *gpl, struct bGPDstroke *gps)
void BKE_gpencil_stroke_2d_flat_ref(const struct bGPDspoint *ref_points, int ref_totpoints, const struct bGPDspoint *points, int totpoints, float(*points2d)[2], float scale, int *r_direction)
void BKE_gpencil_stroke_join(struct bGPDstroke *gps_a, struct bGPDstroke *gps_b, bool leave_gaps, bool fit_thickness, bool smooth)
void BKE_gpencil_stroke_geometry_update(struct bGPdata *gpd, struct bGPDstroke *gps)
float BKE_gpencil_stroke_segment_length(const struct bGPDstroke *gps, int start_index, int end_index, bool use_3d)
void BKE_gpencil_stroke_uv_update(struct bGPDstroke *gps)
void BKE_gpencil_stroke_boundingbox_calc(struct bGPDstroke *gps)
struct bGPDstroke * BKE_gpencil_stroke_delete_tagged_points(struct bGPdata *gpd, struct bGPDframe *gpf, struct bGPDstroke *gps, struct bGPDstroke *next_stroke, int tag_flags, bool select, bool flat_cap, int limit)
void BKE_gpencil_stroke_merge_distance(struct bGPdata *gpd, struct bGPDframe *gpf, struct bGPDstroke *gps, float threshold, bool use_unselected)
bool BKE_gpencil_stroke_close(struct bGPDstroke *gps)
General operations, lookup, etc. for materials.
struct MaterialGPencilStyle * BKE_gpencil_material_settings(struct Object *ob, short act)
Definition: material.c:805
struct Material * BKE_object_material_get(struct Object *ob, short act)
Definition: material.c:687
struct Material * BKE_gpencil_material(struct Object *ob, short act)
Definition: material.c:795
General operations, lookup, etc. for blender objects.
void BKE_boundbox_init_from_minmax(struct BoundBox *bb, const float min[3], const float max[3])
Definition: object.cc:3645
bool BKE_paint_ensure(struct ToolSettings *ts, struct Paint **r_paint)
Definition: paint.c:1042
struct Paint * BKE_paint_get_active_from_context(const struct bContext *C)
struct MovieTrackingTrack * BKE_tracking_track_get_active(struct MovieTracking *tracking)
Definition: tracking.c:1089
#define BLI_assert(a)
Definition: BLI_assert.h:46
sqrt(x)+1/max(0
GHash * BLI_ghash_int_new_ex(const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.h:302
#define GHASH_ITER(gh_iter_, ghash_)
Definition: BLI_ghash.h:321
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:734
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:710
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:863
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
BLI_INLINE float BLI_hash_int_01(unsigned int k)
Definition: BLI_hash.h:94
BLI_INLINE unsigned int BLI_hash_int_2d(unsigned int kx, unsigned int ky)
Definition: BLI_hash.h:53
bool BLI_lasso_is_point_inside(const int mcoords[][2], unsigned int mcoords_len, int sx, int sy, int error_value)
Definition: lasso_2d.c:38
void BLI_lasso_boundbox(struct rcti *rect, const int mcoords[][2], unsigned int mcoords_len)
Definition: lasso_2d.c:15
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
void void void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:100
void void void void BLI_movelisttolist_reverse(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE int max_ii(int a, int b)
MINLINE float interpf(float a, float b, float t)
void hsv_to_rgb_v(const float hsv[3], float r_rgb[3])
Definition: math_color.c:49
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3])
Definition: math_color.c:232
MINLINE void srgb_to_linearrgb_v4(float linear[4], const float srgb[4])
int isect_seg_seg_v2_point(const float v0[2], const float v1[2], const float v2[2], const float v3[2], float vi[2])
Definition: math_geom.c:1296
bool isect_line_plane_v3(float r_isect_co[3], const float l1[3], const float l2[3], const float plane_co[3], const float plane_no[3]) ATTR_WARN_UNUSED_RESULT
Definition: math_geom.c:2078
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:259
void unit_m4(float m[4][4])
Definition: rct.c:1090
void mul_mat3_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:790
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1287
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:729
bool equals_m4m4(const float mat1[4][4], const float mat2[4][4])
Definition: math_matrix.c:2531
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:77
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:739
void zero_axis_bias_m4(float mat[4][4])
Definition: math_matrix.c:3125
void loc_eul_size_to_mat4(float R[4][4], const float loc[3], const float eul[3], const float size[3])
Definition: math_matrix.c:2547
MINLINE void round_v2i_v2fl(int r[2], const float a[2])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
void interp_v2_v2v2(float r[2], const float a[2], const float b[2], float t)
Definition: math_vector.c:14
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
void interp_v4_v4v4(float r[4], const float a[4], const float b[4], float t)
Definition: math_vector.c:38
MINLINE bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
void minmax_v2v2_v2(float min[2], float max[2], const float vec[2])
Definition: math_vector.c:890
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition: math_vector.c:29
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE bool equals_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v4(float r[4])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void zero_v2(float r[2])
MINLINE void zero_v3(float r[3])
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
Random number functions.
bool BLI_rcti_isect_pt_v(const struct rcti *rect, const int xy[2])
bool BLI_rcti_isect_pt(const struct rcti *rect, int x, int y)
bool BLI_rcti_isect(const struct rcti *src1, const struct rcti *src2, struct rcti *dest)
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition: BLI_rect.h:194
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition: BLI_rect.h:198
unsigned int uint
Definition: BLI_sys_types.h:67
unsigned short ushort
Definition: BLI_sys_types.h:68
#define INIT_MINMAX2(min, max)
#define CLAMP_MAX(a, c)
#define SWAP(type, a, b)
#define POINTER_FROM_INT(i)
#define UNUSED(x)
#define ELEM(...)
#define CLAMP3(vec, b, c)
#define STREQ(a, b)
#define CLAMP_MIN(a, b)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
void DEG_id_tag_update(struct ID *id, int flag)
struct ID * DEG_get_evaluated_id(const struct Depsgraph *depsgraph, struct ID *id)
struct Object * DEG_get_evaluated_object(const struct Depsgraph *depsgraph, struct Object *object)
@ ID_RECALC_TRANSFORM
Definition: DNA_ID.h:771
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:834
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
@ GPAINT_TOOL_ERASE
@ GPAINT_TOOL_DRAW
@ GPAINT_TOOL_TINT
@ GP_SCULPT_FLAG_TMP_INVERT
@ GP_SCULPT_FLAG_INVERT
@ GP_BRUSH_USE_SAT_RAND_PRESS
@ GP_BRUSH_USE_VAL_RAND_PRESS
@ GP_BRUSH_USE_HUE_RAND_PRESS
@ GP_BRUSH_USE_HUE_AT_STROKE
@ GP_BRUSH_USE_VAL_AT_STROKE
@ GP_BRUSH_USE_SAT_AT_STROKE
@ GP_BRUSH_MODE_VERTEXCOLOR
@ GP_BRUSH_MODE_MATERIAL
@ GP_BRUSH_STABILIZE_MOUSE
@ GP_BRUSH_STABILIZE_MOUSE_TEMP
@ GP_BRUSH_GROUP_RANDOM
Object groups, one object can be in many groups at once.
@ CURVE_PRESET_GAUSS
#define BEZT_SEL_INVERT(bezt)
#define BEZT_SEL_ALL(bezt)
#define BEZT_DESEL_ALL(bezt)
#define GPENCIL_VERTEX_MODE(gpd)
#define GPENCIL_WEIGHT_MODE(gpd)
@ GP_CURVE_SELECT
#define GPENCIL_SCULPT_MODE(gpd)
@ GP_STROKE_TAG
@ GP_STROKE_2DIMAGE
@ GP_STROKE_NEEDS_CURVE_UPDATE
@ GP_STROKE_SELECT
@ GP_STROKE_CYCLIC
@ GP_STROKE_2DSPACE
@ GP_STROKE_3DSPACE
#define GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)
#define GPENCIL_PAINT_MODE(gpd)
@ GP_LAYER_ACTIVE
@ GP_LAYER_UNLOCK_COLOR
@ GP_FRAME_SELECT
@ GP_DATA_STROKE_WEIGHTMODE
@ GP_DATA_STROKE_VERTEXMODE
@ GP_DATA_CACHE_IS_DIRTY
@ GP_DATA_STROKE_PAINTMODE
@ GP_DATA_STROKE_SCULPTMODE
@ GP_DATA_STROKE_EDITMODE
@ GP_CURVE_POINT_SELECT
@ GP_SPOINT_TAG
@ GP_SPOINT_SELECT
@ GP_MATERIAL_LOCKED
@ GP_MATERIAL_HIDE
@ OB_MODE_VERTEX_GPENCIL
@ OB_MODE_EDIT_GPENCIL
@ OB_MODE_WEIGHT_GPENCIL
@ OB_MODE_SCULPT_GPENCIL
@ OB_MODE_PAINT_GPENCIL
Object is a sort of wrapper for general info.
@ OB_GPENCIL
@ PARSKEL
@ PAROBJECT
@ PARBONE
@ SCE_SNAP_TARGET_ALL
@ GP_LOCKAXIS_CURSOR
@ PAINT_SHOW_BRUSH
@ GP_PROJECT_VIEWSPACE
@ GP_PROJECT_CURSOR
@ RGN_TYPE_WINDOW
#define RGN_TYPE_ANY
@ SPACE_CLIP
@ SPACE_TOPBAR
@ SPACE_NODE
@ SPACE_PROPERTIES
@ SPACE_SEQ
@ SPACE_IMAGE
@ SPACE_VIEW3D
@ SPACE_INFO
@ SC_GPENCIL_SRC_TRACK
#define SPACE_TYPE_ANY
#define RV3D_CAMOB
struct MovieClip * ED_space_clip_get_clip(struct SpaceClip *sc)
Definition: clip_editor.c:570
eGP_ReprojectModes
Definition: ED_gpencil.h:52
@ GP_REPROJECT_VIEW
Definition: ED_gpencil.h:58
@ GP_REPROJECT_CURSOR
Definition: ED_gpencil.h:62
@ GP_REPROJECT_SIDE
Definition: ED_gpencil.h:55
@ GP_REPROJECT_TOP
Definition: ED_gpencil.h:56
@ GP_REPROJECT_FRONT
Definition: ED_gpencil.h:54
struct Object * ED_object_add_type(struct bContext *C, int type, const char *name, const float loc[3], const float rot[3], bool enter_editmode, unsigned short local_view_bits) ATTR_NONNULL(1) ATTR_RETURNS_NONNULL
Definition: object_add.cc:668
@ SEL_SELECT
@ SEL_INVERT
@ SEL_DESELECT
@ SEL_TOGGLE
bool ED_transform_snap_object_project_ray(SnapObjectContext *sctx, struct Depsgraph *depsgraph, const View3D *v3d, const struct SnapObjectParams *params, const float ray_origin[3], const float ray_direction[3], float *ray_depth, float r_co[3], float r_no[3])
@ V3D_PROJ_TEST_NOP
Definition: ED_view3d.h:234
void ED_view3d_win_to_delta(const struct ARegion *region, const float xy_delta[2], float zfac, float r_out[3])
eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *region, const float co[3], float r_co[2], eV3DProjTest flag)
@ V3D_PROJ_RET_OK
Definition: ED_view3d.h:217
eV3DProjStatus ED_view3d_project_int_global(const struct ARegion *region, const float co[3], int r_co[2], eV3DProjTest flag)
bool ED_view3d_win_to_ray_clipped(struct Depsgraph *depsgraph, const struct ARegion *region, const struct View3D *v3d, const float mval[2], float r_ray_start[3], float r_ray_normal[3], bool do_clip_planes)
@ V3D_DEPTH_NO_GPENCIL
Definition: ED_view3d.h:182
void ED_view3d_global_to_vector(const struct RegionView3D *rv3d, const float coord[3], float vec[3])
float ED_view3d_calc_zfac(const struct RegionView3D *rv3d, const float co[3])
void view3d_region_operator_needs_opengl(struct wmWindow *win, struct ARegion *region)
bool ED_view3d_autodist_simple(struct ARegion *region, const int mval[2], float mouse_worldloc[3], int margin, const float *force_depth)
void view3d_operator_needs_opengl(const struct bContext *C)
bool edge_inside_circle(const float cent[2], float radius, const float screen_co_a[2], const float screen_co_b[2])
void ED_view3d_calc_camera_border(const struct Scene *scene, struct Depsgraph *depsgraph, const struct ARegion *region, const struct View3D *v3d, const struct RegionView3D *rv3d, struct rctf *r_viewborder, bool no_shift)
void ED_view3d_depth_override(struct Depsgraph *depsgraph, struct ARegion *region, struct View3D *v3d, struct Object *obact, eV3DDepthOverrideMode mode, struct ViewDepths **r_depths)
Definition: view3d_draw.c:2294
void immUniform2f(const char *name, float x, float y)
void immUniformColor4f(float r, float g, float b, float a)
void immUnbindProgram(void)
void immVertex2f(uint attr_id, float x, float y)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
void immUniform1i(const char *name, int x)
void immUniform1f(const char *name, float x)
void immUniformColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
GPUVertFormat * immVertexFormat(void)
void immBegin(GPUPrimType, uint vertex_len)
void immEnd(void)
void imm_draw_circle_fill_2d(uint shdr_pos, float x, float y, float radius, int nsegments)
void imm_draw_circle_wire_2d(uint shdr_pos, float x, float y, float radius, int nsegments)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble y1
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint vn
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
@ GPU_PRIM_LINES
Definition: GPU_primitive.h:20
@ GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR
Definition: GPU_shader.h:349
@ GPU_SHADER_2D_UNIFORM_COLOR
Definition: GPU_shader.h:201
@ GPU_BLEND_NONE
Definition: GPU_state.h:60
@ GPU_BLEND_ALPHA
Definition: GPU_state.h:62
void GPU_blend(eGPUBlend blend)
Definition: gpu_state.cc:39
void GPU_line_smooth(bool enable)
Definition: gpu_state.cc:75
void GPU_viewport_size_get_f(float coords[4])
Definition: gpu_state.cc:259
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
Read Guarded memory(de)allocation.
#define MEM_recallocN(vmemh, len)
#define MEM_SAFE_FREE(v)
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position CLAMP
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert a color
Platform independent time functions.
#define C
Definition: RandGen.cpp:25
bool UI_view2d_view_to_region_clip(const struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL()
#define V2D_IS_CLIPPED
Definition: UI_view2d.h:25
#define NA_EDITED
Definition: WM_types.h:523
#define NC_GPENCIL
Definition: WM_types.h:349
#define DEPTH_INVALID
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: avxb.h:154
return(oflags[bm->toolflag_index].f &oflag) !=0
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition: btDbvt.cpp:299
static unsigned long seed
Definition: btSoftBody.h:39
Scene scene
Material material
const Depsgraph * depsgraph
int len
Definition: draw_manager.c:108
#define rot(x, k)
#define GP_EDITABLE_CURVES_END(gpstroke_iter)
#define GP_EDITABLE_CURVES_BEGIN(gpstroke_iter, C, gpl, gps, gpc)
#define GP_EDITABLE_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
#define GP_STROKE_BUFFER_CHUNK
#define GP_EDITABLE_STROKES_END(gpstroke_iter)
void ED_gpencil_stroke_close_by_distance(bGPDstroke *gps, const float threshold)
void ED_gpencil_projected_2d_bound_box(const GP_SpaceConversion *gsc, const bGPDstroke *gps, const float diff_mat[4][4], float r_min[2], float r_max[2])
Object * ED_gpencil_add_object(bContext *C, const float loc[3], ushort local_view_bits)
void ED_gpencil_select_toggle_all(bContext *C, int action)
void ED_gpencil_vgroup_deselect(bContext *C, Object *ob)
void gpencil_apply_parent(Depsgraph *depsgraph, Object *obact, bGPDlayer *gpl, bGPDstroke *gps)
void gpencil_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
bool ED_gpencil_stroke_material_editable(Object *ob, const bGPDlayer *gpl, const bGPDstroke *gps)
void ED_gpencil_project_point_to_plane(const Scene *scene, const Object *ob, bGPDlayer *gpl, const RegionView3D *rv3d, const float origin[3], const int axis, bGPDspoint *pt)
void ED_gpencil_project_stroke_to_plane(const Scene *scene, const Object *ob, const RegionView3D *rv3d, bGPDlayer *gpl, bGPDstroke *gps, const float origin[3], const int axis)
bool gpencil_active_layer_poll(bContext *C)
void ED_gpencil_project_stroke_to_view(bContext *C, bGPDlayer *gpl, bGPDstroke *gps)
bGPDstroke * ED_gpencil_stroke_join_and_trim(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *gps_dst, const int pt_index)
static bool gpencil_check_collision(bGPDstroke *gps, bGPDstroke **gps_array, GHash *all_2d, int totstrokes, const float p2d_a1[2], const float p2d_a2[2], float r_hit[2])
static void gpencil_brush_cursor_draw(bContext *C, int x, int y, void *customdata)
bool ED_gpencil_stroke_can_use_direct(const ScrArea *area, const bGPDstroke *gps)
void ED_gpencil_update_color_uv(Main *bmain, Material *mat)
void ED_gpencil_fill_vertex_color_set(ToolSettings *ts, Brush *brush, bGPDstroke *gps)
bGPdata * ED_gpencil_data_get_active_direct(ScrArea *area, Object *ob)
void ED_gpencil_tag_scene_gpencil(Scene *scene)
void ED_gpencil_toggle_brush_cursor(bContext *C, bool enable, void *customdata)
void ED_gpencil_init_random_settings(Brush *brush, const int mval[2], GpRandomSettings *random_settings)
bool gpencil_point_xy_to_3d(const GP_SpaceConversion *gsc, Scene *scene, const float screen_co[2], float r_out[3])
bGPDstroke * ED_gpencil_stroke_nearest_to_ends(bContext *C, const GP_SpaceConversion *gsc, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps, const float ctrl1[2], const float ctrl2[2], const float radius, int *r_index)
void gpencil_subdivide_stroke(bGPdata *gpd, bGPDstroke *gps, const int subdivide)
void ED_gpencil_vgroup_select(bContext *C, Object *ob)
void ED_gpencil_brush_draw_eraser(Brush *brush, int x, int y)
bool ED_gpencil_stroke_check_collision(const GP_SpaceConversion *gsc, bGPDstroke *gps, const float mval[2], const int radius, const float diff_mat[4][4])
void gpencil_point_to_parent_space(const bGPDspoint *pt, const float diff_mat[4][4], bGPDspoint *r_pt)
const EnumPropertyItem * ED_gpencil_layers_with_new_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
bGPdata ** ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
static bool gpencil_brush_cursor_poll(bContext *C)
void ED_gpencil_sbuffer_update_eval(bGPdata *gpd, Object *ob_eval)
void ED_gpencil_vgroup_remove(bContext *C, Object *ob)
bGPdata ** ED_annotation_data_get_pointers_direct(ID *screen_id, ScrArea *area, Scene *scene, PointerRNA *r_ptr)
static void gpencil_copy_points(bGPDstroke *gps, bGPDspoint *pt, bGPDspoint *pt_final, int i, int i2)
static void gpencil_stroke_convertcoords(ARegion *region, const tGPspoint *point2D, const float origin[3], float out[3])
bool ED_gpencil_stroke_material_visible(Object *ob, const bGPDstroke *gps)
void ED_gpencil_select_curve_toggle_all(bContext *C, int action)
const EnumPropertyItem * ED_gpencil_material_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
void ED_gpencil_point_vertex_color_set(ToolSettings *ts, Brush *brush, bGPDspoint *pt, tGPspoint *tpt)
void ED_gpencil_stroke_extremes_to2d(const GP_SpaceConversion *gsc, const float diff_mat[4][4], bGPDstroke *gps, float r_ctrl1[2], float r_ctrl2[2])
void gpencil_point_3d_to_xy(const GP_SpaceConversion *gsc, const short flag, const float pt[3], float xy[2])
int ED_gpencil_select_stroke_segment(bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps, bGPDspoint *pt, bool select, bool insert, const float scale, float r_hita[3], float r_hitb[3])
void ED_gpencil_setup_modes(bContext *C, bGPdata *gpd, int newmode)
bool ED_gpencil_stroke_point_is_inside(const bGPDstroke *gps, const GP_SpaceConversion *gsc, const int mval[2], const float diff_mat[4][4])
void ED_gpencil_tpoint_to_point(ARegion *region, float origin[3], const tGPspoint *tpt, bGPDspoint *pt)
bool ED_gpencil_frame_has_selected_stroke(const bGPDframe *gpf)
static void gpencil_sbuffer_vertex_color_random(bGPdata *gpd, Brush *brush, tGPspoint *tpt, const float random_color[3], float pen_pressure)
bool gpencil_active_brush_poll(bContext *C)
void ED_gpencil_stroke_reproject(Depsgraph *depsgraph, const GP_SpaceConversion *gsc, SnapObjectContext *sctx, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps, const eGP_ReprojectModes mode, const bool keep_original)
bGPdata ** ED_gpencil_data_get_pointers_direct(ScrArea *area, Object *ob, PointerRNA *r_ptr)
Definition: gpencil_utils.c:85
bGPdata * ED_annotation_data_get_active(const bContext *C)
void gpencil_point_to_xy(const GP_SpaceConversion *gsc, const bGPDstroke *gps, const bGPDspoint *pt, int *r_x, int *r_y)
bool gpencil_add_poll(bContext *C)
void ED_gpencil_layer_merge(bGPdata *gpd, bGPDlayer *gpl_src, bGPDlayer *gpl_dst, const bool reverse)
bool ED_gpencil_stroke_can_use(const bContext *C, const bGPDstroke *gps)
void ED_gpencil_drawing_reference_get(const Scene *scene, const Object *ob, char align_flag, float r_vec[3])
bool ED_gpencil_data_owner_is_annotation(PointerRNA *owner_ptr)
void gpencil_point_to_xy_fl(const GP_SpaceConversion *gsc, const bGPDstroke *gps, const bGPDspoint *pt, float *r_x, float *r_y)
bGPdata * ED_gpencil_data_get_active_evaluated(const bContext *C)
void ED_gpencil_sbuffer_vertex_color_set(Depsgraph *depsgraph, Object *ob, ToolSettings *ts, Brush *brush, Material *material, float random_color[3], float pen_pressure)
bGPdata * ED_annotation_data_get_active_direct(ID *screen_id, ScrArea *area, Scene *scene)
void ED_gpencil_reset_layers_parent(Depsgraph *depsgraph, Object *obact, bGPdata *gpd)
bGPdata * ED_gpencil_data_get_active(const bContext *C)
tGPspoint * ED_gpencil_sbuffer_ensure(tGPspoint *buffer_array, int *buffer_size, int *buffer_used, const bool clear)
bool ED_gpencil_layer_has_selected_stroke(const bGPDlayer *gpl, const bool is_multiedit)
static void gpencil_insert_point(bGPdata *gpd, bGPDstroke *gps, bGPDspoint *a_pt, bGPDspoint *b_pt, const float co_a[3], const float co_b[3])
void gpencil_apply_parent_point(Depsgraph *depsgraph, Object *obact, bGPDlayer *gpl, bGPDspoint *pt)
static float gpencil_calc_factor(const float p2d_a1[2], const float p2d_a2[2], const float r_hit2d[2])
void ED_gpencil_add_defaults(bContext *C, Object *ob)
bool gpencil_stroke_inside_circle(const float mval[2], int rad, int x0, int y0, int x1, int y1)
const EnumPropertyItem * ED_gpencil_layers_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
bGPdata ** ED_annotation_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
static bool gpencil_check_cursor_region(bContext *C, const int mval_i[2])
bool ED_gpencil_has_keyframe_v3d(Scene *UNUSED(scene), Object *ob, int cfra)
void gpencil_stroke_convertcoords_tpoint(Scene *scene, ARegion *region, Object *ob, const tGPspoint *point2D, float *depth, float r_out[3])
void ED_gpencil_vgroup_assign(bContext *C, Object *ob, float weight)
uint pos
IconTextureDrawCall normal
ccl_gpu_kernel_postfix ccl_global float int int int int float threshold
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
format
Definition: logImageCore.h:38
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:28
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
ccl_device_inline float3 ceil(const float3 &a)
Definition: math_float3.h:363
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
static ulong * next
static void clear(Message *msg)
Definition: msgfmt.c:278
Insertion insert(const float3 &point_prev, const float3 &handle_prev, const float3 &handle_next, const float3 &point_next, float parameter)
Definition: curve_bezier.cc:61
static void area(int d1, int d2, int e1, int e2, float weights[2])
static const pxr::TfToken out("out", pxr::TfToken::Immortal)
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:136
void RNA_id_pointer_create(ID *id, PointerRNA *r_ptr)
Definition: rna_access.c:112
void RNA_enum_item_end(EnumPropertyItem **items, int *totitem)
Definition: rna_define.c:4487
void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
Definition: rna_define.c:4436
void RNA_enum_item_add_separator(EnumPropertyItem **items, int *totitem)
Definition: rna_define.c:4459
const EnumPropertyItem DummyRNA_DEFAULT_items[]
Definition: rna_rna.c:31
void * regiondata
short regiontype
float vec[8][3]
struct CurveMapping * curve_rand_saturation
struct CurveMapping * curve_rand_hue
struct CurveMapping * curve_rand_value
float add_col[4]
float rgb[3]
struct BrushGpencilSettings * gpencil_settings
float sub_col[4]
char gpencil_tool
CurveMap cm[4]
const char * identifier
Definition: RNA_types.h:461
struct CurveMapping * cur_falloff
struct ARegion * region
struct View2D * v2d
struct Object * ob
struct Scene * scene
struct ScrArea * area
Definition: DNA_ID.h:368
char name[66]
Definition: DNA_ID.h:378
void * last
Definition: DNA_listBase.h:31
void * first
Definition: DNA_listBase.h:31
struct MDeformWeight * dw
Definition: BKE_main.h:121
ListBase objects
Definition: BKE_main.h:170
struct PreviewImage * preview
struct MaterialGPencilStyle * gp_style
struct MovieTracking tracking
struct bGPdata * gpd
struct bGPdata * gpd
float obmat[4][4]
void * data
struct Brush * brush
struct StructRNA * type
Definition: RNA_types.h:37
int icon_id
Definition: DNA_ID.h:540
struct ToolSettings * toolsettings
struct bGPdata * gpd
View3DCursor cursor
ListBase spacedata
struct bGPdata * gpd
struct bNodeTree * nodetree
struct bGPdata * gpd
GpWeightPaint * gp_weightpaint
GpPaint * gp_paint
GpSculptPaint * gp_sculptpaint
struct GP_Sculpt_Settings gp_sculpt
GpVertexPaint * gp_vertexpaint
float rotation_euler[3]
bGPDcurve_point * curve_points
struct bGPDframe * next
ListBase strokes
struct bGPDlayer * gpl_orig
char info[128]
struct bGPDlayer * next
bGPDframe * actframe
float layer_mat[4][4]
bGPDlayer_Runtime runtime
float layer_invmat[4][4]
ListBase frames
ListBase mask_layers
float rotation[3]
float scale[3]
float location[3]
struct bGPDlayer * prev
float vert_color[4]
bGPDspoint * points
float vert_color_fill[4]
float boundbox_max[3]
float boundbox_min[3]
struct MDeformVert * dvert
struct bGPDstroke * next
bGPDcontrolpoint * cp_points
ListBase vertex_group_names
int select_last_index
ListBase layers
int vertex_group_active_index
bGPdata_Runtime runtime
struct bGPdata * gpd
float pose_mat[4][4]
float xmin
Definition: DNA_vec_types.h:69
float ymin
Definition: DNA_vec_types.h:70
int ymin
Definition: DNA_vec_types.h:64
int xmin
Definition: DNA_vec_types.h:63
float pressure
Definition: ED_gpencil.h:83
float m_xy[2]
Definition: ED_gpencil.h:81
float uv_rot
Definition: ED_gpencil.h:91
float strength
Definition: ED_gpencil.h:85
float vert_color[4]
Definition: ED_gpencil.h:97
float uv_fac
Definition: ED_gpencil.h:89
double PIL_check_seconds_timer(void)
Definition: time.c:64
int xy[2]
Definition: wm_draw.c:135
void WM_main_add_notifier(unsigned int type, void *reference)
PointerRNA * ptr
Definition: wm_files.c:3480
bool WM_paint_cursor_end(wmPaintCursor *handle)
wmPaintCursor * WM_paint_cursor_activate(short space_type, short region_type, bool(*poll)(bContext *C), wmPaintCursorDraw draw, void *customdata)
bool WM_toolsystem_active_tool_is_brush(const bContext *C)