Blender  V2.93
gpencil_utils.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2014, Blender Foundation
17  */
18 
23 #include <math.h>
24 #include <stddef.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "MEM_guardedalloc.h"
30 
31 #include "BLI_blenlib.h"
32 #include "BLI_ghash.h"
33 #include "BLI_hash.h"
34 #include "BLI_lasso_2d.h"
35 #include "BLI_math.h"
36 #include "BLI_rand.h"
37 #include "BLI_utildefines.h"
38 #include "BLT_translation.h"
39 
40 #include "PIL_time.h"
41 
42 #include "DNA_brush_types.h"
43 #include "DNA_collection_types.h"
44 #include "DNA_gpencil_types.h"
45 #include "DNA_material_types.h"
46 #include "DNA_meshdata_types.h"
47 #include "DNA_object_types.h"
48 #include "DNA_scene_types.h"
49 #include "DNA_screen_types.h"
50 #include "DNA_space_types.h"
51 #include "DNA_view3d_types.h"
52 
53 #include "BKE_action.h"
54 #include "BKE_brush.h"
55 #include "BKE_collection.h"
56 #include "BKE_colortools.h"
57 #include "BKE_context.h"
58 #include "BKE_deform.h"
59 #include "BKE_gpencil.h"
60 #include "BKE_gpencil_curve.h"
61 #include "BKE_gpencil_geom.h"
62 #include "BKE_main.h"
63 #include "BKE_material.h"
64 #include "BKE_object.h"
65 #include "BKE_paint.h"
66 #include "BKE_tracking.h"
67 
68 #include "WM_api.h"
69 #include "WM_toolsystem.h"
70 #include "WM_types.h"
71 
72 #include "RNA_access.h"
73 #include "RNA_define.h"
74 #include "RNA_enum_types.h"
75 
76 #include "UI_resources.h"
77 #include "UI_view2d.h"
78 
79 #include "ED_clip.h"
80 #include "ED_gpencil.h"
81 #include "ED_object.h"
82 #include "ED_screen.h"
83 #include "ED_select_utils.h"
85 #include "ED_view3d.h"
86 
87 #include "GPU_immediate.h"
88 #include "GPU_immediate_util.h"
89 #include "GPU_state.h"
90 
91 #include "DEG_depsgraph.h"
92 #include "DEG_depsgraph_query.h"
93 
94 #include "gpencil_intern.h"
95 
96 /* ******************************************************** */
97 /* Context Wrangling... */
98 
105 {
106  /* if there's an active area, check if the particular editor may
107  * have defined any special Grease Pencil context for editing...
108  */
109  if (area) {
110  switch (area->spacetype) {
111  case SPACE_PROPERTIES: /* properties */
112  case SPACE_INFO: /* header info */
113  case SPACE_TOPBAR: /* Top-bar */
114  case SPACE_VIEW3D: /* 3D-View */
115  {
116  if (ob && (ob->type == OB_GPENCIL)) {
117  /* GP Object. */
118  if (r_ptr) {
119  RNA_id_pointer_create(&ob->id, r_ptr);
120  }
121  return (bGPdata **)&ob->data;
122  }
123  return NULL;
124  }
125  default: /* Unsupported space. */
126  return NULL;
127  }
128  }
129 
130  return NULL;
131 }
132 
139  ScrArea *area,
140  Scene *scene,
141  PointerRNA *r_ptr)
142 {
143  /* If there's an active area, check if the particular editor may
144  * have defined any special Grease Pencil context for editing. */
145  if (area) {
146  SpaceLink *sl = area->spacedata.first;
147 
148  switch (area->spacetype) {
149  case SPACE_PROPERTIES: /* properties */
150  case SPACE_INFO: /* header info */
151  {
152  return NULL;
153  }
154 
155  case SPACE_TOPBAR: /* Top-bar */
156  case SPACE_VIEW3D: /* 3D-View */
157  {
158  if (r_ptr) {
159  RNA_id_pointer_create(&scene->id, r_ptr);
160  }
161  return &scene->gpd;
162 
163  break;
164  }
165  case SPACE_NODE: /* Nodes Editor */
166  {
167  SpaceNode *snode = (SpaceNode *)sl;
168 
169  /* return the GP data for the active node block/node */
170  if (snode && snode->nodetree) {
171  /* for now, as long as there's an active node tree,
172  * default to using that in the Nodes Editor */
173  if (r_ptr) {
174  RNA_id_pointer_create(&snode->nodetree->id, r_ptr);
175  }
176  return &snode->nodetree->gpd;
177  }
178 
179  /* Even when there is no node-tree, don't allow this to flow to scene. */
180  return NULL;
181  }
182  case SPACE_SEQ: /* Sequencer */
183  {
184  SpaceSeq *sseq = (SpaceSeq *)sl;
185 
186  /* For now, Grease Pencil data is associated with the space
187  * (actually preview region only). */
188  if (r_ptr) {
189  RNA_pointer_create(screen_id, &RNA_SpaceSequenceEditor, sseq, r_ptr);
190  }
191  return &sseq->gpd;
192  }
193  case SPACE_IMAGE: /* Image/UV Editor */
194  {
195  SpaceImage *sima = (SpaceImage *)sl;
196 
197  /* For now, Grease Pencil data is associated with the space... */
198  if (r_ptr) {
199  RNA_pointer_create(screen_id, &RNA_SpaceImageEditor, sima, r_ptr);
200  }
201  return &sima->gpd;
202  }
203  case SPACE_CLIP: /* Nodes Editor */
204  {
205  SpaceClip *sc = (SpaceClip *)sl;
206  MovieClip *clip = ED_space_clip_get_clip(sc);
207 
208  if (clip) {
209  if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
211 
212  if (!track) {
213  return NULL;
214  }
215 
216  if (r_ptr) {
217  RNA_pointer_create(&clip->id, &RNA_MovieTrackingTrack, track, r_ptr);
218  }
219  return &track->gpd;
220  }
221  if (r_ptr) {
222  RNA_id_pointer_create(&clip->id, r_ptr);
223  }
224  return &clip->gpd;
225  }
226  break;
227  }
228  default: /* unsupported space */
229  return NULL;
230  }
231  }
232 
233  return NULL;
234 }
235 
241 {
244 
245  return ED_gpencil_data_get_pointers_direct(area, ob, r_ptr);
246 }
247 
253 {
254  ID *screen_id = (ID *)CTX_wm_screen(C);
257 
258  return ED_annotation_data_get_pointers_direct(screen_id, area, scene, r_ptr);
259 }
260 /* -------------------------------------------------------- */
261 
262 /* Get the active Grease Pencil data-block, when context is not available */
264 {
266  return (gpd_ptr) ? *(gpd_ptr) : NULL;
267 }
268 
269 /* Get the active Grease Pencil data-block, when context is not available */
271 {
273  return (gpd_ptr) ? *(gpd_ptr) : NULL;
274 }
275 
280 {
282  if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
283  return NULL;
284  }
285  return ob->data;
286 }
287 
294 {
296  return (gpd_ptr) ? *(gpd_ptr) : NULL;
297 }
307 {
309 
312  Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
313 
314  return ED_gpencil_data_get_active_direct(area, ob_eval);
315 }
316 
317 /* -------------------------------------------------------- */
318 
324 {
325  /* Key Assumption: If the pointer is an object, we're dealing with a GP Object's data.
326  * Otherwise, the GP data-block is being used for annotations (i.e. everywhere else). */
327  return ((owner_ptr) && (owner_ptr->type != &RNA_Object));
328 }
329 
330 /* ******************************************************** */
331 /* Keyframe Indicator Checks */
332 
333 /* Check whether there's an active GP keyframe on the current frame */
335 {
336  if (ob && ob->data && (ob->type == OB_GPENCIL)) {
338  if (gpl) {
339  if (gpl->actframe) {
340  /* XXX: assumes that frame has been fetched already */
341  return (gpl->actframe->framenum == cfra);
342  }
343  /* XXX: disabled as could be too much of a penalty */
344  /* return BKE_gpencil_layer_frame_find(gpl, cfra); */
345  }
346  }
347 
348  return false;
349 }
350 
351 /* ******************************************************** */
352 /* Poll Callbacks */
353 
354 /* poll callback for adding data/layers - special */
356 {
358  if (ob == NULL) {
359  return false;
360  }
361  bGPdata *gpd = (bGPdata *)ob->data;
362 
363  return (gpd != NULL);
364 }
365 
366 /* poll callback for checking if there is an active layer */
368 {
370  if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
371  return false;
372  }
373  bGPdata *gpd = (bGPdata *)ob->data;
375 
376  return (gpl != NULL);
377 }
378 
379 /* poll callback for checking if there is an active brush */
381 {
383  Paint *paint = &ts->gp_paint->paint;
384  if (paint) {
385  return (paint->brush != NULL);
386  }
387  return false;
388 }
389 
390 /* ******************************************************** */
391 /* Dynamic Enums of GP Layers */
392 /* NOTE: These include an option to create a new layer and use that... */
393 
394 /* Just existing layers */
397  PropertyRNA *UNUSED(prop),
398  bool *r_free)
399 {
401  bGPDlayer *gpl;
402  EnumPropertyItem *item = NULL, item_tmp = {0};
403  int totitem = 0;
404  int i = 0;
405 
406  if (ELEM(NULL, C, gpd)) {
407  return DummyRNA_DEFAULT_items;
408  }
409 
410  /* Existing layers */
411  for (gpl = gpd->layers.first; gpl; gpl = gpl->next, i++) {
412  item_tmp.identifier = gpl->info;
413  item_tmp.name = gpl->info;
414  item_tmp.value = i;
415 
416  if (gpl->flag & GP_LAYER_ACTIVE) {
417  item_tmp.icon = ICON_GREASEPENCIL;
418  }
419  else {
420  item_tmp.icon = ICON_NONE;
421  }
422 
423  RNA_enum_item_add(&item, &totitem, &item_tmp);
424  }
425 
426  RNA_enum_item_end(&item, &totitem);
427  *r_free = true;
428 
429  return item;
430 }
431 
432 /* Existing + Option to add/use new layer */
435  PropertyRNA *UNUSED(prop),
436  bool *r_free)
437 {
439  bGPDlayer *gpl;
440  EnumPropertyItem *item = NULL, item_tmp = {0};
441  int totitem = 0;
442  int i = 0;
443 
444  if (ELEM(NULL, C, gpd)) {
445  return DummyRNA_DEFAULT_items;
446  }
447 
448  /* Create new layer */
449  /* TODO: have some way of specifying that we don't want this? */
450 
451  const int tot = BLI_listbase_count(&gpd->layers);
452  /* Existing layers */
453  for (gpl = gpd->layers.last, i = 0; gpl; gpl = gpl->prev, i++) {
454  item_tmp.identifier = gpl->info;
455  item_tmp.name = gpl->info;
456  item_tmp.value = tot - i - 1;
457 
458  if (gpl->flag & GP_LAYER_ACTIVE) {
459  item_tmp.icon = ICON_GREASEPENCIL;
460  }
461  else {
462  item_tmp.icon = ICON_NONE;
463  }
464 
465  RNA_enum_item_add(&item, &totitem, &item_tmp);
466  }
467  {
468  /* separator */
469  RNA_enum_item_add_separator(&item, &totitem);
470 
471  /* "New Layer" entry */
472  item_tmp.identifier = "__CREATE__";
473  item_tmp.name = "New Layer";
474  item_tmp.value = -1;
475  item_tmp.icon = ICON_ADD;
476  RNA_enum_item_add(&item, &totitem, &item_tmp);
477  }
478 
479  RNA_enum_item_end(&item, &totitem);
480  *r_free = true;
481 
482  return item;
483 }
484 
485 /* Just existing Materials */
488  PropertyRNA *UNUSED(prop),
489  bool *r_free)
490 {
492  EnumPropertyItem *item = NULL, item_tmp = {0};
493  int totitem = 0;
494  int i = 0;
495 
496  if (ELEM(NULL, C, ob)) {
497  return DummyRNA_DEFAULT_items;
498  }
499 
500  /* Existing materials */
501  for (i = 1; i <= ob->totcol; i++) {
502  Material *ma = BKE_object_material_get(ob, i);
503  if (ma) {
504  item_tmp.identifier = ma->id.name + 2;
505  item_tmp.name = ma->id.name + 2;
506  item_tmp.value = i;
507  item_tmp.icon = ma->preview ? ma->preview->icon_id : ICON_NONE;
508 
509  RNA_enum_item_add(&item, &totitem, &item_tmp);
510  }
511  }
512 
513  RNA_enum_item_end(&item, &totitem);
514  *r_free = true;
515 
516  return item;
517 }
518 
519 /* ******************************************************** */
520 /* Brush Tool Core */
521 
531 bool gpencil_stroke_inside_circle(const float mval[2], int rad, int x0, int y0, int x1, int y1)
532 {
533  /* simple within-radius check for now */
534  const float screen_co_a[2] = {x0, y0};
535  const float screen_co_b[2] = {x1, y1};
536 
537  if (edge_inside_circle(mval, rad, screen_co_a, screen_co_b)) {
538  return true;
539  }
540 
541  /* not inside */
542  return false;
543 }
544 
545 /* ******************************************************** */
546 /* Selection Validity Testing */
547 
549 {
550  LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
551  if (gps->flag & GP_STROKE_SELECT) {
552  return true;
553  }
554  }
555 
556  return false;
557 }
558 
559 bool ED_gpencil_layer_has_selected_stroke(const bGPDlayer *gpl, const bool is_multiedit)
560 {
561  bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
562  for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
563  if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
565  return true;
566  }
567  }
568  /* If not multiedit, exit loop. */
569  if (!is_multiedit) {
570  break;
571  }
572  }
573 
574  return false;
575 }
576 
577 /* ******************************************************** */
578 /* Stroke Validity Testing */
579 
580 /* Check whether given stroke can be edited given the supplied context */
581 /* TODO: do we need additional flags for screenspace vs dataspace? */
583 {
584  /* sanity check */
585  if (ELEM(NULL, area, gps)) {
586  return false;
587  }
588 
589  /* filter stroke types by flags + spacetype */
590  if (gps->flag & GP_STROKE_3DSPACE) {
591  /* 3D strokes - only in 3D view */
592  return (ELEM(area->spacetype, SPACE_VIEW3D, SPACE_PROPERTIES));
593  }
594  if (gps->flag & GP_STROKE_2DIMAGE) {
595  /* Special "image" strokes - only in Image Editor */
596  return (area->spacetype == SPACE_IMAGE);
597  }
598  if (gps->flag & GP_STROKE_2DSPACE) {
599  /* 2D strokes (dataspace) - for any 2D view (i.e. everything other than 3D view) */
600  return (area->spacetype != SPACE_VIEW3D);
601  }
602  /* view aligned - anything goes */
603  return true;
604 }
605 
606 /* Check whether given stroke can be edited in the current context */
608 {
611 }
612 
613 /* Check whether given stroke can be edited for the current color */
615 {
616  /* check if the color is editable */
618 
619  if (gp_style != NULL) {
620  if (gp_style->flag & GP_MATERIAL_HIDE) {
621  return false;
622  }
623  if (((gpl->flag & GP_LAYER_UNLOCK_COLOR) == 0) && (gp_style->flag & GP_MATERIAL_LOCKED)) {
624  return false;
625  }
626  }
627 
628  return true;
629 }
630 
631 /* Check whether given stroke is visible for the current material. */
633 {
634  /* check if the color is editable */
636 
637  if (gp_style != NULL) {
638  if (gp_style->flag & GP_MATERIAL_HIDE) {
639  return false;
640  }
641  }
642 
643  return true;
644 }
645 
646 /* ******************************************************** */
647 /* Space Conversion */
648 
655 {
657  ARegion *region = CTX_wm_region(C);
658 
659  /* zero out the storage (just in case) */
660  memset(r_gsc, 0, sizeof(GP_SpaceConversion));
661  unit_m4(r_gsc->mat);
662 
663  /* store settings */
664  r_gsc->scene = CTX_data_scene(C);
665  r_gsc->ob = CTX_data_active_object(C);
666 
667  r_gsc->area = area;
668  r_gsc->region = region;
669  r_gsc->v2d = &region->v2d;
670 
671  /* init region-specific stuff */
672  if (area->spacetype == SPACE_VIEW3D) {
673  wmWindow *win = CTX_wm_window(C);
676  View3D *v3d = (View3D *)CTX_wm_space_data(C);
677  RegionView3D *rv3d = region->regiondata;
678 
679  /* init 3d depth buffers */
681 
684 
685  /* for camera view set the subrect */
686  if (rv3d->persp == RV3D_CAMOB) {
688  scene, depsgraph, region, v3d, rv3d, &r_gsc->subrect_data, true);
689  r_gsc->subrect = &r_gsc->subrect_data;
690  }
691  }
692 }
693 
702  const float diff_mat[4][4],
703  bGPDspoint *r_pt)
704 {
705  float fpt[3];
706 
707  mul_v3_m4v3(fpt, diff_mat, &pt->x);
708  copy_v3_v3(&r_pt->x, fpt);
709 }
710 
715 {
716  bGPDspoint *pt;
717  int i;
718 
719  /* undo matrix */
720  float diff_mat[4][4];
721  float inverse_diff_mat[4][4];
722  float fpt[3];
723 
724  BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
725  invert_m4_m4(inverse_diff_mat, diff_mat);
726 
727  for (i = 0; i < gps->totpoints; i++) {
728  pt = &gps->points[i];
729  mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x);
730  copy_v3_v3(&pt->x, fpt);
731  }
732 }
733 
738  Object *obact,
739  bGPDlayer *gpl,
740  bGPDspoint *pt)
741 {
742  /* undo matrix */
743  float diff_mat[4][4];
744  float inverse_diff_mat[4][4];
745  float fpt[3];
746 
747  BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
748  invert_m4_m4(inverse_diff_mat, diff_mat);
749 
750  mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x);
751 
752  copy_v3_v3(&pt->x, fpt);
753 }
754 
765  const GP_SpaceConversion *gsc, const bGPDstroke *gps, const bGPDspoint *pt, int *r_x, int *r_y)
766 {
767  const ARegion *region = gsc->region;
768  const View2D *v2d = gsc->v2d;
769  const rctf *subrect = gsc->subrect;
770  int xyval[2];
771 
772  /* sanity checks */
773  BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->area->spacetype == SPACE_VIEW3D));
774  BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->area->spacetype != SPACE_VIEW3D));
775 
776  if (gps->flag & GP_STROKE_3DSPACE) {
777  if (ED_view3d_project_int_global(region, &pt->x, xyval, V3D_PROJ_TEST_NOP) ==
778  V3D_PROJ_RET_OK) {
779  *r_x = xyval[0];
780  *r_y = xyval[1];
781  }
782  else {
783  *r_x = V2D_IS_CLIPPED;
784  *r_y = V2D_IS_CLIPPED;
785  }
786  }
787  else if (gps->flag & GP_STROKE_2DSPACE) {
788  float vec[3] = {pt->x, pt->y, 0.0f};
789  mul_m4_v3(gsc->mat, vec);
790  UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], r_x, r_y);
791  }
792  else {
793  if (subrect == NULL) {
794  /* normal 3D view (or view space) */
795  *r_x = (int)(pt->x / 100 * region->winx);
796  *r_y = (int)(pt->y / 100 * region->winy);
797  }
798  else {
799  /* camera view, use subrect */
800  *r_x = (int)((pt->x / 100) * BLI_rctf_size_x(subrect)) + subrect->xmin;
801  *r_y = (int)((pt->y / 100) * BLI_rctf_size_y(subrect)) + subrect->ymin;
802  }
803  }
804 }
805 
820  const bGPDstroke *gps,
821  const bGPDspoint *pt,
822  float *r_x,
823  float *r_y)
824 {
825  const ARegion *region = gsc->region;
826  const View2D *v2d = gsc->v2d;
827  const rctf *subrect = gsc->subrect;
828  float xyval[2];
829 
830  /* sanity checks */
831  BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->area->spacetype == SPACE_VIEW3D));
832  BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->area->spacetype != SPACE_VIEW3D));
833 
834  if (gps->flag & GP_STROKE_3DSPACE) {
835  if (ED_view3d_project_float_global(region, &pt->x, xyval, V3D_PROJ_TEST_NOP) ==
836  V3D_PROJ_RET_OK) {
837  *r_x = xyval[0];
838  *r_y = xyval[1];
839  }
840  else {
841  *r_x = 0.0f;
842  *r_y = 0.0f;
843  }
844  }
845  else if (gps->flag & GP_STROKE_2DSPACE) {
846  float vec[3] = {pt->x, pt->y, 0.0f};
847  int t_x, t_y;
848 
849  mul_m4_v3(gsc->mat, vec);
850  UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], &t_x, &t_y);
851 
852  if ((t_x == t_y) && (t_x == V2D_IS_CLIPPED)) {
853  /* XXX: Or should we just always use the values as-is? */
854  *r_x = 0.0f;
855  *r_y = 0.0f;
856  }
857  else {
858  *r_x = (float)t_x;
859  *r_y = (float)t_y;
860  }
861  }
862  else {
863  if (subrect == NULL) {
864  /* normal 3D view (or view space) */
865  *r_x = (pt->x / 100.0f * region->winx);
866  *r_y = (pt->y / 100.0f * region->winy);
867  }
868  else {
869  /* camera view, use subrect */
870  *r_x = ((pt->x / 100.0f) * BLI_rctf_size_x(subrect)) + subrect->xmin;
871  *r_y = ((pt->y / 100.0f) * BLI_rctf_size_y(subrect)) + subrect->ymin;
872  }
873  }
874 }
875 
880  const short flag,
881  const float pt[3],
882  float xy[2])
883 {
884  const ARegion *region = gsc->region;
885  const View2D *v2d = gsc->v2d;
886  const rctf *subrect = gsc->subrect;
887  float xyval[2];
888 
889  /* sanity checks */
891 
892  if (flag & GP_STROKE_3DSPACE) {
894  xy[0] = xyval[0];
895  xy[1] = xyval[1];
896  }
897  else {
898  xy[0] = 0.0f;
899  xy[1] = 0.0f;
900  }
901  }
902  else if (flag & GP_STROKE_2DSPACE) {
903  float vec[3] = {pt[0], pt[1], 0.0f};
904  int t_x, t_y;
905 
906  mul_m4_v3(gsc->mat, vec);
907  UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], &t_x, &t_y);
908 
909  if ((t_x == t_y) && (t_x == V2D_IS_CLIPPED)) {
910  /* XXX: Or should we just always use the values as-is? */
911  xy[0] = 0.0f;
912  xy[1] = 0.0f;
913  }
914  else {
915  xy[0] = (float)t_x;
916  xy[1] = (float)t_y;
917  }
918  }
919  else {
920  if (subrect == NULL) {
921  /* normal 3D view (or view space) */
922  xy[0] = (pt[0] / 100.0f * region->winx);
923  xy[1] = (pt[1] / 100.0f * region->winy);
924  }
925  else {
926  /* camera view, use subrect */
927  xy[0] = ((pt[0] / 100.0f) * BLI_rctf_size_x(subrect)) + subrect->xmin;
928  xy[1] = ((pt[1] / 100.0f) * BLI_rctf_size_y(subrect)) + subrect->ymin;
929  }
930  }
931 }
932 
949  Scene *scene,
950  const float screen_co[2],
951  float r_out[3])
952 {
953  const RegionView3D *rv3d = gsc->region->regiondata;
954  float rvec[3];
955 
957 
958  float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
959 
960  float mval_f[2], mval_prj[2];
961  float dvec[3];
962 
963  copy_v2_v2(mval_f, screen_co);
964 
965  if (ED_view3d_project_float_global(gsc->region, rvec, mval_prj, V3D_PROJ_TEST_NOP) ==
966  V3D_PROJ_RET_OK) {
967  sub_v2_v2v2(mval_f, mval_prj, mval_f);
968  ED_view3d_win_to_delta(gsc->region, mval_f, dvec, zfac);
969  sub_v3_v3v3(r_out, rvec, dvec);
970 
971  return true;
972  }
973  zero_v3(r_out);
974  return false;
975 }
976 
986  ARegion *region,
987  Object *ob,
988  const tGPspoint *point2D,
989  float *depth,
990  float r_out[3])
991 {
993 
994  int mval_i[2];
995  round_v2i_v2fl(mval_i, &point2D->x);
996 
997  if ((depth != NULL) && (ED_view3d_autodist_simple(region, mval_i, r_out, 0, depth))) {
998  /* projecting onto 3D-Geometry
999  * - nothing more needs to be done here, since view_autodist_simple() has already done it
1000  */
1001  }
1002  else {
1003  float mval_f[2] = {point2D->x, point2D->y};
1004  float mval_prj[2];
1005  float rvec[3], dvec[3];
1006  float zfac;
1007 
1008  /* Current method just converts each point in screen-coordinates to
1009  * 3D-coordinates using the 3D-cursor as reference.
1010  */
1012  zfac = ED_view3d_calc_zfac(region->regiondata, rvec, NULL);
1013 
1014  if (ED_view3d_project_float_global(region, rvec, mval_prj, V3D_PROJ_TEST_NOP) ==
1015  V3D_PROJ_RET_OK) {
1016  sub_v2_v2v2(mval_f, mval_prj, mval_f);
1017  ED_view3d_win_to_delta(region, mval_f, dvec, zfac);
1018  sub_v3_v3v3(r_out, rvec, dvec);
1019  }
1020  else {
1021  zero_v3(r_out);
1022  }
1023  }
1024 }
1025 
1031  const Object *ob,
1032  char align_flag,
1033  float r_vec[3])
1034 {
1035  const float *fp = scene->cursor.location;
1036 
1037  /* if using a gpencil object at cursor mode, can use the location of the object */
1038  if (align_flag & GP_PROJECT_VIEWSPACE) {
1039  if (ob && (ob->type == OB_GPENCIL)) {
1040  /* fallback (no strokes) - use cursor or object location */
1041  if (align_flag & GP_PROJECT_CURSOR) {
1042  /* use 3D-cursor */
1043  copy_v3_v3(r_vec, fp);
1044  }
1045  else {
1046  /* use object location */
1047  copy_v3_v3(r_vec, ob->obmat[3]);
1048  /* Apply layer offset. */
1049  bGPdata *gpd = ob->data;
1051  if (gpl != NULL) {
1052  add_v3_v3(r_vec, gpl->layer_mat[3]);
1053  }
1054  }
1055  }
1056  }
1057  else {
1058  /* use 3D-cursor */
1059  copy_v3_v3(r_vec, fp);
1060  }
1061 }
1062 
1064 {
1068  GP_SpaceConversion gsc = {NULL};
1069 
1070  bGPDspoint *pt;
1071  int i;
1072  float diff_mat[4][4];
1073  float inverse_diff_mat[4][4];
1074 
1075  /* init space conversion stuff */
1077 
1079  invert_m4_m4(inverse_diff_mat, diff_mat);
1080 
1081  /* Adjust each point */
1082  for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
1083  float xy[2];
1084 
1085  bGPDspoint pt2;
1086  gpencil_point_to_parent_space(pt, diff_mat, &pt2);
1087  gpencil_point_to_xy_fl(&gsc, gps, &pt2, &xy[0], &xy[1]);
1088 
1089  /* Planar - All on same plane parallel to the viewplane */
1090  gpencil_point_xy_to_3d(&gsc, scene, xy, &pt->x);
1091 
1092  /* Unapply parent corrections */
1093  mul_m4_v3(inverse_diff_mat, &pt->x);
1094  }
1095 }
1096 
1101  const Object *ob,
1102  const RegionView3D *rv3d,
1103  bGPDlayer *gpl,
1104  bGPDstroke *gps,
1105  const float origin[3],
1106  const int axis)
1107 {
1108  const ToolSettings *ts = scene->toolsettings;
1109  const View3DCursor *cursor = &scene->cursor;
1110  float plane_normal[3];
1111  float vn[3];
1112 
1113  float ray[3];
1114  float rpoint[3];
1115 
1116  /* Recalculate layer transform matrix. */
1117  loc_eul_size_to_mat4(gpl->layer_mat, gpl->location, gpl->rotation, gpl->scale);
1118  invert_m4_m4(gpl->layer_invmat, gpl->layer_mat);
1119 
1120  /* normal vector for a plane locked to axis */
1121  zero_v3(plane_normal);
1122  if (axis < 0) {
1123  /* if the axis is not locked, need a vector to the view direction
1124  * in order to get the right size of the stroke.
1125  */
1126  ED_view3d_global_to_vector(rv3d, origin, plane_normal);
1127  }
1128  else if (axis < 3) {
1129  plane_normal[axis] = 1.0f;
1130  /* if object, apply object rotation */
1131  if (ob && (ob->type == OB_GPENCIL)) {
1132  float mat[4][4];
1133  copy_m4_m4(mat, ob->obmat);
1134 
1135  /* move origin to cursor */
1136  if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) {
1137  if (gpl != NULL) {
1138  add_v3_v3(mat[3], gpl->location);
1139  }
1140  }
1142  copy_v3_v3(mat[3], cursor->location);
1143  }
1144 
1145  mul_mat3_m4_v3(mat, plane_normal);
1146  }
1147 
1148  if ((gpl != NULL) && (ts->gp_sculpt.lock_axis != GP_LOCKAXIS_CURSOR)) {
1149  mul_mat3_m4_v3(gpl->layer_mat, plane_normal);
1150  }
1151  }
1152  else {
1153  const float scale[3] = {1.0f, 1.0f, 1.0f};
1154  plane_normal[2] = 1.0f;
1155  float mat[4][4];
1156  loc_eul_size_to_mat4(mat, cursor->location, cursor->rotation_euler, scale);
1157  mul_mat3_m4_v3(mat, plane_normal);
1158  }
1159 
1160  /* Reproject the points in the plane */
1161  for (int i = 0; i < gps->totpoints; i++) {
1162  bGPDspoint *pt = &gps->points[i];
1163 
1164  /* get a vector from the point with the current view direction of the viewport */
1165  ED_view3d_global_to_vector(rv3d, &pt->x, vn);
1166 
1167  /* calculate line extreme point to create a ray that cross the plane */
1168  mul_v3_fl(vn, -50.0f);
1169  add_v3_v3v3(ray, &pt->x, vn);
1170 
1171  /* if the line never intersect, the point is not changed */
1172  if (isect_line_plane_v3(rpoint, &pt->x, ray, origin, plane_normal)) {
1173  copy_v3_v3(&pt->x, rpoint);
1174  }
1175  }
1176 }
1177 
1178 /* Reproject selected strokes */
1180  const GP_SpaceConversion *gsc,
1181  SnapObjectContext *sctx,
1182  bGPDlayer *gpl,
1183  bGPDframe *gpf,
1184  bGPDstroke *gps,
1185  const eGP_ReprojectModes mode,
1186  const bool keep_original)
1187 {
1188  ToolSettings *ts = gsc->scene->toolsettings;
1189  ARegion *region = gsc->region;
1190  RegionView3D *rv3d = region->regiondata;
1191 
1192  /* Recalculate layer transform matrix. */
1193  loc_eul_size_to_mat4(gpl->layer_mat, gpl->location, gpl->rotation, gpl->scale);
1194  invert_m4_m4(gpl->layer_invmat, gpl->layer_mat);
1195 
1196  float diff_mat[4][4], inverse_diff_mat[4][4];
1197  BKE_gpencil_layer_transform_matrix_get(depsgraph, gsc->ob, gpl, diff_mat);
1198  invert_m4_m4(inverse_diff_mat, diff_mat);
1199 
1200  float origin[3];
1201  if (mode != GP_REPROJECT_CURSOR) {
1203  }
1204  else {
1205  copy_v3_v3(origin, gsc->scene->cursor.location);
1206  }
1207 
1208  bGPDspoint *pt;
1209  int i;
1210 
1211  /* If keep original, do a copy. */
1212  bGPDstroke *gps_active = gps;
1213  /* if duplicate, deselect all points. */
1214  if (keep_original) {
1215  gps_active = BKE_gpencil_stroke_duplicate(gps, true, true);
1216  gps_active->flag &= ~GP_STROKE_SELECT;
1218  for (i = 0, pt = gps_active->points; i < gps_active->totpoints; i++, pt++) {
1219  pt->flag &= ~GP_SPOINT_SELECT;
1220  }
1221  /* Add to frame. */
1222  BLI_addtail(&gpf->strokes, gps_active);
1223  }
1224 
1225  /* Adjust each point */
1226  for (i = 0, pt = gps_active->points; i < gps_active->totpoints; i++, pt++) {
1227  float xy[2];
1228 
1229  /* 3D to Screen-space */
1230  /* Note: We can't use gpencil_point_to_xy() here because that uses ints for the screen-space
1231  * coordinates, resulting in lost precision, which in turn causes stair-stepping
1232  * artifacts in the final points. */
1233 
1234  bGPDspoint pt2;
1235  gpencil_point_to_parent_space(pt, diff_mat, &pt2);
1236  gpencil_point_to_xy_fl(gsc, gps_active, &pt2, &xy[0], &xy[1]);
1237 
1238  /* Project stroke in one axis */
1240  int axis = 0;
1241  switch (mode) {
1242  case GP_REPROJECT_FRONT: {
1243  axis = 1;
1244  break;
1245  }
1246  case GP_REPROJECT_SIDE: {
1247  axis = 0;
1248  break;
1249  }
1250  case GP_REPROJECT_TOP: {
1251  axis = 2;
1252  break;
1253  }
1254  case GP_REPROJECT_CURSOR: {
1255  axis = 3;
1256  break;
1257  }
1258  default: {
1259  axis = 1;
1260  break;
1261  }
1262  }
1263 
1264  ED_gpencil_project_point_to_plane(gsc->scene, gsc->ob, gpl, rv3d, origin, axis, &pt2);
1265 
1266  copy_v3_v3(&pt->x, &pt2.x);
1267 
1268  /* apply parent again */
1269  gpencil_apply_parent_point(depsgraph, gsc->ob, gpl, pt);
1270  }
1271  /* Project screen-space back to 3D space (from current perspective)
1272  * so that all points have been treated the same way. */
1273  else if (mode == GP_REPROJECT_VIEW) {
1274  /* Planar - All on same plane parallel to the view-plane. */
1275  gpencil_point_xy_to_3d(gsc, gsc->scene, xy, &pt->x);
1276  }
1277  else {
1278  /* Geometry - Snap to surfaces of visible geometry */
1279  float ray_start[3];
1280  float ray_normal[3];
1281  /* magic value for initial depth copied from the default
1282  * value of Python's Scene.ray_cast function
1283  */
1284  float depth = 1.70141e+38f;
1285  float location[3] = {0.0f, 0.0f, 0.0f};
1286  float normal[3] = {0.0f, 0.0f, 0.0f};
1287 
1289  BLI_assert(gsc->area && gsc->area->spacetype == SPACE_VIEW3D);
1290  const View3D *v3d = gsc->area->spacedata.first;
1292  depsgraph, region, v3d, xy, &ray_start[0], &ray_normal[0], true);
1294  depsgraph,
1295  &(const struct SnapObjectParams){
1296  .snap_select = SNAP_ALL,
1297  },
1298  &ray_start[0],
1299  &ray_normal[0],
1300  &depth,
1301  &location[0],
1302  &normal[0])) {
1303  copy_v3_v3(&pt->x, location);
1304  }
1305  else {
1306  /* Default to planar */
1307  gpencil_point_xy_to_3d(gsc, gsc->scene, xy, &pt->x);
1308  }
1309  }
1310 
1311  /* Unapply parent corrections */
1313  mul_m4_v3(inverse_diff_mat, &pt->x);
1314  }
1315  }
1316 }
1317 
1323  const Object *ob,
1324  bGPDlayer *gpl,
1325  const RegionView3D *rv3d,
1326  const float origin[3],
1327  const int axis,
1328  bGPDspoint *pt)
1329 {
1330  const ToolSettings *ts = scene->toolsettings;
1331  const View3DCursor *cursor = &scene->cursor;
1332  float plane_normal[3];
1333  float vn[3];
1334 
1335  float ray[3];
1336  float rpoint[3];
1337 
1338  /* normal vector for a plane locked to axis */
1339  zero_v3(plane_normal);
1340  if (axis < 0) {
1341  /* if the axis is not locked, need a vector to the view direction
1342  * in order to get the right size of the stroke.
1343  */
1344  ED_view3d_global_to_vector(rv3d, origin, plane_normal);
1345  }
1346  else if (axis < 3) {
1347  plane_normal[axis] = 1.0f;
1348  /* if object, apply object rotation */
1349  if (ob && (ob->type == OB_GPENCIL)) {
1350  float mat[4][4];
1351  copy_m4_m4(mat, ob->obmat);
1352  if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) {
1353  if (gpl != NULL) {
1354  add_v3_v3(mat[3], gpl->location);
1355  }
1356  }
1357 
1358  /* move origin to cursor */
1360  copy_v3_v3(mat[3], cursor->location);
1361  }
1362 
1363  mul_mat3_m4_v3(mat, plane_normal);
1364  /* Apply layer rotation (local transform). */
1365  if ((gpl != NULL) && (ts->gp_sculpt.lock_axis != GP_LOCKAXIS_CURSOR)) {
1366  mul_mat3_m4_v3(gpl->layer_mat, plane_normal);
1367  }
1368  }
1369  }
1370  else {
1371  const float scale[3] = {1.0f, 1.0f, 1.0f};
1372  plane_normal[2] = 1.0f;
1373  float mat[4][4];
1374  loc_eul_size_to_mat4(mat, cursor->location, cursor->rotation_euler, scale);
1375 
1376  /* move origin to object */
1377  if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) {
1378  copy_v3_v3(mat[3], ob->obmat[3]);
1379  }
1380 
1381  mul_mat3_m4_v3(mat, plane_normal);
1382  }
1383 
1384  /* Reproject the points in the plane */
1385  /* get a vector from the point with the current view direction of the viewport */
1386  ED_view3d_global_to_vector(rv3d, &pt->x, vn);
1387 
1388  /* calculate line extreme point to create a ray that cross the plane */
1389  mul_v3_fl(vn, -50.0f);
1390  add_v3_v3v3(ray, &pt->x, vn);
1391 
1392  /* if the line never intersect, the point is not changed */
1393  if (isect_line_plane_v3(rpoint, &pt->x, ray, origin, plane_normal)) {
1394  copy_v3_v3(&pt->x, rpoint);
1395  }
1396 }
1397 
1398 /* ******************************************************** */
1399 /* Stroke Operations */
1400 
1401 /* XXX: Check if these functions duplicate stuff in blenkernel,
1402  * and/or whether we should just deduplicate. */
1403 
1410 void gpencil_subdivide_stroke(bGPdata *gpd, bGPDstroke *gps, const int subdivide)
1411 {
1412  bGPDspoint *temp_points;
1413  int totnewpoints, oldtotpoints;
1414  int i2;
1415 
1416  /* loop as many times as levels */
1417  for (int s = 0; s < subdivide; s++) {
1418  totnewpoints = gps->totpoints - 1;
1419  /* duplicate points in a temp area */
1420  temp_points = MEM_dupallocN(gps->points);
1421  oldtotpoints = gps->totpoints;
1422 
1423  /* resize the points arrays */
1424  gps->totpoints += totnewpoints;
1425  gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
1426  if (gps->dvert != NULL) {
1427  gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
1428  }
1429 
1430  /* move points from last to first to new place */
1431  i2 = gps->totpoints - 1;
1432  for (int i = oldtotpoints - 1; i > 0; i--) {
1433  bGPDspoint *pt = &temp_points[i];
1434  bGPDspoint *pt_final = &gps->points[i2];
1435 
1436  copy_v3_v3(&pt_final->x, &pt->x);
1437  pt_final->pressure = pt->pressure;
1438  pt_final->strength = pt->strength;
1439  pt_final->time = pt->time;
1440  pt_final->flag = pt->flag;
1441  pt_final->uv_fac = pt->uv_fac;
1442  pt_final->uv_rot = pt->uv_rot;
1443  copy_v4_v4(pt_final->vert_color, pt->vert_color);
1444 
1445  if (gps->dvert != NULL) {
1446  MDeformVert *dvert = &gps->dvert[i];
1447  MDeformVert *dvert_final = &gps->dvert[i2];
1448 
1449  dvert_final->totweight = dvert->totweight;
1450  dvert_final->dw = dvert->dw;
1451  }
1452 
1453  i2 -= 2;
1454  }
1455  /* interpolate mid points */
1456  i2 = 1;
1457  for (int i = 0; i < oldtotpoints - 1; i++) {
1458  bGPDspoint *pt = &temp_points[i];
1459  bGPDspoint *next = &temp_points[i + 1];
1460  bGPDspoint *pt_final = &gps->points[i2];
1461 
1462  /* add a half way point */
1463  interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
1464  pt_final->pressure = interpf(pt->pressure, next->pressure, 0.5f);
1465  pt_final->strength = interpf(pt->strength, next->strength, 0.5f);
1466  CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f);
1467  pt_final->time = interpf(pt->time, next->time, 0.5f);
1468  pt_final->uv_fac = interpf(pt->uv_fac, next->uv_fac, 0.5f);
1469  pt_final->uv_rot = interpf(pt->uv_rot, next->uv_rot, 0.5f);
1470  interp_v4_v4v4(pt_final->vert_color, pt->vert_color, next->vert_color, 0.5f);
1471 
1472  if (gps->dvert != NULL) {
1473  MDeformVert *dvert_final = &gps->dvert[i2];
1474  dvert_final->totweight = 0;
1475  dvert_final->dw = NULL;
1476  }
1477 
1478  i2 += 2;
1479  }
1480 
1481  MEM_SAFE_FREE(temp_points);
1482 
1483  /* move points to smooth stroke */
1484  /* duplicate points in a temp area with the new subdivide data */
1485  temp_points = MEM_dupallocN(gps->points);
1486 
1487  /* extreme points are not changed */
1488  for (int i = 0; i < gps->totpoints - 2; i++) {
1489  bGPDspoint *pt = &temp_points[i];
1490  bGPDspoint *next = &temp_points[i + 1];
1491  bGPDspoint *pt_final = &gps->points[i + 1];
1492 
1493  /* move point */
1494  interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
1495  }
1496  /* free temp memory */
1497  MEM_SAFE_FREE(temp_points);
1498  }
1499  /* Calc geometry data. */
1501 }
1502 
1503 /* Reset parent matrix for all layers. */
1505 {
1506  bGPDspoint *pt;
1507  int i;
1508  float diff_mat[4][4];
1509  float cur_mat[4][4];
1510  float gpl_loc[3];
1511  zero_v3(gpl_loc);
1512 
1513  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
1514  if (gpl->parent != NULL) {
1515  /* calculate new matrix */
1516  if (ELEM(gpl->partype, PAROBJECT, PARSKEL)) {
1517  invert_m4_m4(cur_mat, gpl->parent->obmat);
1518  copy_v3_v3(gpl_loc, obact->obmat[3]);
1519  }
1520  else if (gpl->partype == PARBONE) {
1521  bPoseChannel *pchan = BKE_pose_channel_find_name(gpl->parent->pose, gpl->parsubstr);
1522  if (pchan) {
1523  float tmp_mat[4][4];
1524  mul_m4_m4m4(tmp_mat, gpl->parent->obmat, pchan->pose_mat);
1525  invert_m4_m4(cur_mat, tmp_mat);
1526  copy_v3_v3(gpl_loc, obact->obmat[3]);
1527  }
1528  }
1529 
1530  /* only redo if any change */
1531  if (!equals_m4m4(gpl->inverse, cur_mat)) {
1532  /* first apply current transformation to all strokes */
1533  BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
1534  /* undo local object */
1535  sub_v3_v3(diff_mat[3], gpl_loc);
1536 
1537  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
1538  LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
1539  for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
1540  mul_m4_v3(diff_mat, &pt->x);
1541  }
1542  }
1543  }
1544  /* set new parent matrix */
1545  copy_m4_m4(gpl->inverse, cur_mat);
1546  }
1547  }
1548  }
1549 }
1550 /* ******************************************************** */
1551 /* GP Object Stuff */
1552 
1553 /* Helper function to create new OB_GPENCIL Object */
1554 Object *ED_gpencil_add_object(bContext *C, const float loc[3], ushort local_view_bits)
1555 {
1556  const float rot[3] = {0.0f};
1557 
1558  Object *ob = ED_object_add_type(C, OB_GPENCIL, NULL, loc, rot, false, local_view_bits);
1559 
1560  /* create default brushes and colors */
1562 
1563  return ob;
1564 }
1565 
1566 /* Helper function to create default colors and drawing brushes */
1568 {
1569  Main *bmain = CTX_data_main(C);
1571 
1572  BKE_paint_ensure(ts, (Paint **)&ts->gp_paint);
1573  Paint *paint = &ts->gp_paint->paint;
1574  /* if not exist, create a new one */
1575  if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
1576  /* create new brushes */
1577  BKE_brush_gpencil_paint_presets(bmain, ts, true);
1578  }
1579 
1580  /* ensure a color exists and is assigned to object */
1582 
1583  /* ensure multiframe falloff curve */
1584  if (ts->gp_sculpt.cur_falloff == NULL) {
1585  ts->gp_sculpt.cur_falloff = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
1586  CurveMapping *gp_falloff_curve = ts->gp_sculpt.cur_falloff;
1587  BKE_curvemapping_init(gp_falloff_curve);
1588  BKE_curvemap_reset(gp_falloff_curve->cm,
1589  &gp_falloff_curve->clipr,
1592  }
1593 }
1594 
1595 /* ******************************************************** */
1596 /* Vertex Groups */
1597 
1598 /* assign points to vertex group */
1599 void ED_gpencil_vgroup_assign(bContext *C, Object *ob, float weight)
1600 {
1601  bGPdata *gpd = (bGPdata *)ob->data;
1602  const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
1603  const int def_nr = ob->actdef - 1;
1604  if (!BLI_findlink(&ob->defbase, def_nr)) {
1605  return;
1606  }
1607 
1608  CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
1609  bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
1610  bGPDstroke *gps = NULL;
1611 
1612  for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
1613  if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
1614  if (gpf == NULL) {
1615  continue;
1616  }
1617 
1618  for (gps = gpf->strokes.first; gps; gps = gps->next) {
1619 
1620  /* skip strokes that are invalid for current view */
1621  if (ED_gpencil_stroke_can_use(C, gps) == false) {
1622  continue;
1623  }
1624 
1625  if (gps->flag & GP_STROKE_SELECT) {
1626  /* verify the weight array is created */
1628 
1629  for (int i = 0; i < gps->totpoints; i++) {
1630  bGPDspoint *pt = &gps->points[i];
1631  MDeformVert *dvert = &gps->dvert[i];
1632  if (pt->flag & GP_SPOINT_SELECT) {
1633  MDeformWeight *dw = BKE_defvert_ensure_index(dvert, def_nr);
1634  if (dw) {
1635  dw->weight = weight;
1636  }
1637  }
1638  }
1639  }
1640  }
1641  }
1642 
1643  /* if not multiedit, exit loop*/
1644  if (!is_multiedit) {
1645  break;
1646  }
1647  }
1648  }
1649  CTX_DATA_END;
1650 }
1651 
1652 /* remove points from vertex group */
1654 {
1655  bGPdata *gpd = (bGPdata *)ob->data;
1656  const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
1657  const int def_nr = ob->actdef - 1;
1658  if (!BLI_findlink(&ob->defbase, def_nr)) {
1659  return;
1660  }
1661 
1662  CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
1663  bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
1664  bGPDstroke *gps = NULL;
1665 
1666  for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
1667  if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
1668  if (gpf == NULL) {
1669  continue;
1670  }
1671 
1672  for (gps = gpf->strokes.first; gps; gps = gps->next) {
1673 
1674  /* skip strokes that are invalid for current view */
1675  if (ED_gpencil_stroke_can_use(C, gps) == false) {
1676  continue;
1677  }
1678 
1679  for (int i = 0; i < gps->totpoints; i++) {
1680  bGPDspoint *pt = &gps->points[i];
1681  if (gps->dvert == NULL) {
1682  continue;
1683  }
1684  MDeformVert *dvert = &gps->dvert[i];
1685 
1686  if ((pt->flag & GP_SPOINT_SELECT) && (dvert->totweight > 0)) {
1687  MDeformWeight *dw = BKE_defvert_find_index(dvert, def_nr);
1688  if (dw != NULL) {
1689  BKE_defvert_remove_group(dvert, dw);
1690  }
1691  }
1692  }
1693  }
1694  }
1695 
1696  /* if not multiedit, exit loop*/
1697  if (!is_multiedit) {
1698  break;
1699  }
1700  }
1701  }
1702  CTX_DATA_END;
1703 }
1704 
1705 /* select points of vertex group */
1707 {
1708  bGPdata *gpd = (bGPdata *)ob->data;
1709  const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
1710  const int def_nr = ob->actdef - 1;
1711  if (!BLI_findlink(&ob->defbase, def_nr)) {
1712  return;
1713  }
1714 
1715  CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
1716  bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
1717  bGPDstroke *gps = NULL;
1718 
1719  for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
1720  if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
1721  if (gpf == NULL) {
1722  continue;
1723  }
1724 
1725  for (gps = gpf->strokes.first; gps; gps = gps->next) {
1726 
1727  /* skip strokes that are invalid for current view */
1728  if (ED_gpencil_stroke_can_use(C, gps) == false) {
1729  continue;
1730  }
1731 
1732  for (int i = 0; i < gps->totpoints; i++) {
1733  bGPDspoint *pt = &gps->points[i];
1734  if (gps->dvert == NULL) {
1735  continue;
1736  }
1737  MDeformVert *dvert = &gps->dvert[i];
1738 
1739  if (BKE_defvert_find_index(dvert, def_nr) != NULL) {
1740  pt->flag |= GP_SPOINT_SELECT;
1741  gps->flag |= GP_STROKE_SELECT;
1742  }
1743  }
1744 
1745  if (gps->flag & GP_STROKE_SELECT) {
1747  }
1748  }
1749  }
1750 
1751  /* if not multiedit, exit loop*/
1752  if (!is_multiedit) {
1753  break;
1754  }
1755  }
1756  }
1757  CTX_DATA_END;
1758 }
1759 
1760 /* unselect points of vertex group */
1762 {
1763  bGPdata *gpd = (bGPdata *)ob->data;
1764  const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
1765  const int def_nr = ob->actdef - 1;
1766  if (!BLI_findlink(&ob->defbase, def_nr)) {
1767  return;
1768  }
1769 
1770  CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
1771  bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
1772  bGPDstroke *gps = NULL;
1773 
1774  for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
1775  if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
1776  if (gpf == NULL) {
1777  continue;
1778  }
1779 
1780  for (gps = gpf->strokes.first; gps; gps = gps->next) {
1781 
1782  /* skip strokes that are invalid for current view */
1783  if (ED_gpencil_stroke_can_use(C, gps) == false) {
1784  continue;
1785  }
1786 
1787  for (int i = 0; i < gps->totpoints; i++) {
1788  bGPDspoint *pt = &gps->points[i];
1789  if (gps->dvert == NULL) {
1790  continue;
1791  }
1792  MDeformVert *dvert = &gps->dvert[i];
1793 
1794  if (BKE_defvert_find_index(dvert, def_nr) != NULL) {
1795  pt->flag &= ~GP_SPOINT_SELECT;
1796  }
1797  }
1798  }
1799  }
1800 
1801  /* if not multiedit, exit loop*/
1802  if (!is_multiedit) {
1803  break;
1804  }
1805  }
1806  }
1807  CTX_DATA_END;
1808 }
1809 
1810 /* ******************************************************** */
1811 /* Cursor drawing */
1812 
1813 /* check if cursor is in drawing region */
1814 static bool gpencil_check_cursor_region(bContext *C, const int mval_i[2])
1815 {
1816  ARegion *region = CTX_wm_region(C);
1817  ScrArea *area = CTX_wm_area(C);
1819 
1820  if ((ob == NULL) || (!ELEM(ob->mode,
1825  return false;
1826  }
1827 
1828  /* TODO: add more spacetypes */
1829  if (!ELEM(area->spacetype, SPACE_VIEW3D)) {
1830  return false;
1831  }
1832  if ((region) && (region->regiontype != RGN_TYPE_WINDOW)) {
1833  return false;
1834  }
1835  if (region) {
1836  return BLI_rcti_isect_pt_v(&region->winrct, mval_i);
1837  }
1838  return false;
1839 }
1840 
1841 /* draw eraser cursor */
1842 void ED_gpencil_brush_draw_eraser(Brush *brush, int x, int y)
1843 {
1844  short radius = (short)brush->size;
1845 
1847  const uint shdr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1849 
1850  GPU_line_smooth(true);
1852 
1853  immUniformColor4ub(255, 100, 100, 20);
1854  imm_draw_circle_fill_2d(shdr_pos, x, y, radius, 40);
1855 
1856  immUnbindProgram();
1857 
1859 
1860  float viewport_size[4];
1861  GPU_viewport_size_get_f(viewport_size);
1862  immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
1863 
1864  immUniformColor4f(1.0f, 0.39f, 0.39f, 0.78f);
1865  immUniform1i("colors_len", 0); /* "simple" mode */
1866  immUniform1f("dash_width", 12.0f);
1867  immUniform1f("dash_factor", 0.5f);
1868 
1869  imm_draw_circle_wire_2d(shdr_pos,
1870  x,
1871  y,
1872  radius,
1873  /* XXX Dashed shader gives bad results with sets of small segments
1874  * currently, temp hack around the issue. :( */
1875  max_ii(8, radius / 2)); /* was fixed 40 */
1876 
1877  immUnbindProgram();
1878 
1880  GPU_line_smooth(false);
1881 }
1882 
1884 {
1886  return true;
1887  }
1888  return false;
1889 }
1890 
1894 static void gpencil_brush_cursor_draw(bContext *C, int x, int y, void *customdata)
1895 {
1898  ARegion *region = CTX_wm_region(C);
1900 
1902  Brush *brush = NULL;
1903  Material *ma = NULL;
1904  MaterialGPencilStyle *gp_style = NULL;
1905  float *last_mouse_position = customdata;
1906 
1907  /* default radius and color */
1908  float color[3] = {1.0f, 1.0f, 1.0f};
1909  float darkcolor[3];
1910  float radius = 3.0f;
1911 
1912  int mval_i[2] = {x, y};
1913  /* Check if cursor is in drawing region and has valid data-block. */
1914  if ((!gpencil_check_cursor_region(C, mval_i)) || (gpd == NULL)) {
1915  return;
1916  }
1917 
1918  /* for paint use paint brush size and color */
1919  if (gpd->flag & GP_DATA_STROKE_PAINTMODE) {
1920  brush = scene->toolsettings->gp_paint->paint.brush;
1921  if ((brush == NULL) || (brush->gpencil_settings == NULL)) {
1922  return;
1923  }
1924 
1925  /* while drawing hide */
1926  if ((gpd->runtime.sbuffer_used > 0) &&
1927  ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
1929  return;
1930  }
1931 
1932  if ((paint->flags & PAINT_SHOW_BRUSH) == 0) {
1933  return;
1934  }
1935 
1936  /* eraser has special shape and use a different shader program */
1937  if (brush->gpencil_tool == GPAINT_TOOL_ERASE) {
1938  ED_gpencil_brush_draw_eraser(brush, x, y);
1939  return;
1940  }
1941 
1942  /* get current drawing color */
1944 
1945  if (ma) {
1946  gp_style = ma->gp_style;
1947 
1948  /* after some testing, display the size of the brush is not practical because
1949  * is too disruptive and the size of cursor does not change with zoom factor.
1950  * The decision was to use a fix size, instead of brush->thickness value.
1951  */
1952  if ((gp_style) && (GPENCIL_PAINT_MODE(gpd)) &&
1953  ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
1955  (brush->gpencil_tool == GPAINT_TOOL_DRAW)) {
1956  radius = 2.0f;
1957  copy_v3_v3(color, gp_style->stroke_rgba);
1958  }
1959  else {
1960  /* Only Tint tool must show big cursor. */
1961  if (brush->gpencil_tool == GPAINT_TOOL_TINT) {
1962  radius = brush->size;
1963  copy_v3_v3(color, brush->rgb);
1964  }
1965  else {
1966  radius = 5.0f;
1967  copy_v3_v3(color, brush->add_col);
1968  }
1969  }
1970  }
1971  }
1972 
1973  /* Sculpt use sculpt brush size */
1974  if (GPENCIL_SCULPT_MODE(gpd)) {
1976  if ((brush == NULL) || (brush->gpencil_settings == NULL)) {
1977  return;
1978  }
1979  if ((paint->flags & PAINT_SHOW_BRUSH) == 0) {
1980  return;
1981  }
1982 
1983  radius = brush->size;
1984  if (brush->gpencil_settings->sculpt_flag &
1986  copy_v3_v3(color, brush->sub_col);
1987  }
1988  else {
1989  copy_v3_v3(color, brush->add_col);
1990  }
1991  }
1992 
1993  /* Weight Paint */
1994  if (GPENCIL_WEIGHT_MODE(gpd)) {
1996  if ((brush == NULL) || (brush->gpencil_settings == NULL)) {
1997  return;
1998  }
1999  if ((paint->flags & PAINT_SHOW_BRUSH) == 0) {
2000  return;
2001  }
2002 
2003  radius = brush->size;
2004  if (brush->gpencil_settings->sculpt_flag &
2006  copy_v3_v3(color, brush->sub_col);
2007  }
2008  else {
2009  copy_v3_v3(color, brush->add_col);
2010  }
2011  }
2012 
2013  /* For Vertex Paint use brush size. */
2014  if (GPENCIL_VERTEX_MODE(gpd)) {
2016  if ((brush == NULL) || (brush->gpencil_settings == NULL)) {
2017  return;
2018  }
2019  if ((paint->flags & PAINT_SHOW_BRUSH) == 0) {
2020  return;
2021  }
2022 
2023  radius = brush->size;
2024  copy_v3_v3(color, brush->rgb);
2025  }
2026 
2027  /* draw icon */
2031 
2032  GPU_line_smooth(true);
2034 
2035  /* Inner Ring: Color from UI panel */
2036  immUniformColor4f(color[0], color[1], color[2], 0.8f);
2037  if ((gp_style) && (GPENCIL_PAINT_MODE(gpd)) &&
2038  ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
2040  (brush->gpencil_tool == GPAINT_TOOL_DRAW)) {
2041  imm_draw_circle_fill_2d(pos, x, y, radius, 40);
2042  }
2043  else {
2044  imm_draw_circle_wire_2d(pos, x, y, radius, 40);
2045  }
2046 
2047  /* Outer Ring: Dark color for contrast on light backgrounds (e.g. gray on white) */
2048  mul_v3_v3fl(darkcolor, color, 0.40f);
2049  immUniformColor4f(darkcolor[0], darkcolor[1], darkcolor[2], 0.8f);
2050  imm_draw_circle_wire_2d(pos, x, y, radius + 1, 40);
2051 
2053  GPU_line_smooth(false);
2054 
2055  /* Draw line for lazy mouse */
2056  if ((last_mouse_position) && (brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP)) {
2057  GPU_line_smooth(true);
2059 
2060  copy_v3_v3(color, brush->add_col);
2061  immUniformColor4f(color[0], color[1], color[2], 0.8f);
2062 
2064  immVertex2f(pos, x, y);
2065  immVertex2f(pos,
2066  last_mouse_position[0] + region->winrct.xmin,
2067  last_mouse_position[1] + region->winrct.ymin);
2068  immEnd();
2069 
2071  GPU_line_smooth(false);
2072  }
2073 
2074  immUnbindProgram();
2075 }
2076 
2077 /* Turn brush cursor in on/off */
2078 void ED_gpencil_toggle_brush_cursor(bContext *C, bool enable, void *customdata)
2079 {
2082  float *lastpost = customdata;
2083 
2084  if (gset->paintcursor && !enable) {
2085  /* clear cursor */
2087  gset->paintcursor = NULL;
2088  }
2089  else if (enable) {
2090  /* in some situations cursor could be duplicated, so it is better disable first if exist */
2091  if (gset->paintcursor) {
2092  /* clear cursor */
2094  gset->paintcursor = NULL;
2095  }
2096  /* enable cursor */
2098  RGN_TYPE_ANY,
2101  (lastpost) ? customdata : NULL);
2102  }
2103 }
2104 
2105 /* set object modes */
2106 void ED_gpencil_setup_modes(bContext *C, bGPdata *gpd, int newmode)
2107 {
2108  if (!gpd) {
2109  return;
2110  }
2111 
2112  switch (newmode) {
2113  case OB_MODE_EDIT_GPENCIL:
2114  gpd->flag |= GP_DATA_STROKE_EDITMODE;
2115  gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
2120  break;
2121  case OB_MODE_PAINT_GPENCIL:
2122  gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
2128  break;
2130  gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
2131  gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
2136  break;
2138  gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
2139  gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
2144  break;
2146  gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
2147  gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
2152  break;
2153  default:
2154  gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
2155  gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
2160  break;
2161  }
2162 }
2163 
2168  const tGPspoint *point2D,
2169  const float origin[3],
2170  float out[3])
2171 {
2172  float mval_f[2] = {(float)point2D->x, (float)point2D->y};
2173  float mval_prj[2];
2174  float rvec[3], dvec[3];
2175  float zfac;
2176 
2177  copy_v3_v3(rvec, origin);
2178 
2179  zfac = ED_view3d_calc_zfac(region->regiondata, rvec, NULL);
2180 
2181  if (ED_view3d_project_float_global(region, rvec, mval_prj, V3D_PROJ_TEST_NOP) ==
2182  V3D_PROJ_RET_OK) {
2183  sub_v2_v2v2(mval_f, mval_prj, mval_f);
2184  ED_view3d_win_to_delta(region, mval_f, dvec, zfac);
2185  sub_v3_v3v3(out, rvec, dvec);
2186  }
2187  else {
2188  zero_v3(out);
2189  }
2190 }
2191 
2196  float origin[3],
2197  const tGPspoint *tpt,
2198  bGPDspoint *pt)
2199 {
2200  float p3d[3];
2201  /* conversion to 3d format */
2202  gpencil_stroke_convertcoords(region, tpt, origin, p3d);
2203  copy_v3_v3(&pt->x, p3d);
2204  zero_v4(pt->vert_color);
2205 
2206  pt->pressure = tpt->pressure;
2207  pt->strength = tpt->strength;
2208  pt->uv_fac = tpt->uv_fac;
2209  pt->uv_rot = tpt->uv_rot;
2210 }
2211 
2216 {
2217  Material *gps_ma = NULL;
2218  /* read all strokes */
2219  for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
2220  if (ob->type == OB_GPENCIL) {
2221  bGPdata *gpd = ob->data;
2222  if (gpd == NULL) {
2223  continue;
2224  }
2225 
2226  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
2227  /* only editable and visible layers are considered */
2228  if (BKE_gpencil_layer_is_editable(gpl)) {
2229  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
2230  LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
2231  /* check if it is editable */
2232  if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
2233  continue;
2234  }
2235  gps_ma = BKE_gpencil_material(ob, gps->mat_nr + 1);
2236  /* update */
2237  if ((gps_ma) && (gps_ma == mat)) {
2239  }
2240  }
2241  }
2242  }
2243  }
2245  }
2246  }
2247 }
2248 
2250  bGPDstroke **gps_array,
2251  GHash *all_2d,
2252  int totstrokes,
2253  const float p2d_a1[2],
2254  const float p2d_a2[2],
2255  float r_hit[2])
2256 {
2257  bool hit = false;
2258  /* check segment with all segments of all strokes */
2259  for (int s = 0; s < totstrokes; s++) {
2260  bGPDstroke *gps_iter = gps_array[s];
2261  if (gps_iter->totpoints < 2) {
2262  continue;
2263  }
2264  /* get stroke 2d version */
2265  float(*points2d)[2] = BLI_ghash_lookup(all_2d, gps_iter);
2266 
2267  for (int i2 = 0; i2 < gps_iter->totpoints - 1; i2++) {
2268  float p2d_b1[2], p2d_b2[2];
2269  copy_v2_v2(p2d_b1, points2d[i2]);
2270  copy_v2_v2(p2d_b2, points2d[i2 + 1]);
2271 
2272  /* don't self check */
2273  if (gps == gps_iter) {
2274  if (equals_v2v2(p2d_a1, p2d_b1) || equals_v2v2(p2d_a1, p2d_b2)) {
2275  continue;
2276  }
2277  if (equals_v2v2(p2d_a2, p2d_b1) || equals_v2v2(p2d_a2, p2d_b2)) {
2278  continue;
2279  }
2280  }
2281  /* check collision */
2282  int check = isect_seg_seg_v2_point(p2d_a1, p2d_a2, p2d_b1, p2d_b2, r_hit);
2283  if (check > 0) {
2284  hit = true;
2285  break;
2286  }
2287  }
2288 
2289  if (hit) {
2290  break;
2291  }
2292  }
2293 
2294  if (!hit) {
2295  zero_v2(r_hit);
2296  }
2297 
2298  return hit;
2299 }
2300 
2302  bGPDstroke *gps, bGPDspoint *pt, bGPDspoint *pt_final, int i, int i2)
2303 {
2304  /* don't copy same point */
2305  if (i == i2) {
2306  return;
2307  }
2308 
2309  copy_v3_v3(&pt_final->x, &pt->x);
2310  pt_final->pressure = pt->pressure;
2311  pt_final->strength = pt->strength;
2312  pt_final->time = pt->time;
2313  pt_final->flag = pt->flag;
2314  pt_final->uv_fac = pt->uv_fac;
2315  pt_final->uv_rot = pt->uv_rot;
2316  copy_v4_v4(pt_final->vert_color, pt->vert_color);
2317 
2318  if (gps->dvert != NULL) {
2319  MDeformVert *dvert = &gps->dvert[i];
2320  MDeformVert *dvert_final = &gps->dvert[i2];
2321  MEM_SAFE_FREE(dvert_final->dw);
2322 
2323  dvert_final->totweight = dvert->totweight;
2324  if (dvert->dw == NULL) {
2325  dvert_final->dw = NULL;
2326  dvert_final->totweight = 0;
2327  }
2328  else {
2329  dvert_final->dw = MEM_dupallocN(dvert->dw);
2330  }
2331  }
2332 }
2333 
2335  bGPDstroke *gps,
2336  bGPDspoint *a_pt,
2337  bGPDspoint *b_pt,
2338  const float co_a[3],
2339  const float co_b[3])
2340 {
2341  bGPDspoint *temp_points;
2342  int totnewpoints, oldtotpoints;
2343 
2344  totnewpoints = gps->totpoints;
2345  if (a_pt) {
2346  totnewpoints++;
2347  }
2348  if (b_pt) {
2349  totnewpoints++;
2350  }
2351 
2352  /* duplicate points in a temp area */
2353  temp_points = MEM_dupallocN(gps->points);
2354  oldtotpoints = gps->totpoints;
2355 
2356  /* look index of base points because memory is changed when resize points array */
2357  int a_idx = -1;
2358  int b_idx = -1;
2359  for (int i = 0; i < oldtotpoints; i++) {
2360  bGPDspoint *pt = &gps->points[i];
2361  if (pt == a_pt) {
2362  a_idx = i;
2363  }
2364  if (pt == b_pt) {
2365  b_idx = i;
2366  }
2367  }
2368 
2369  /* resize the points arrays */
2370  gps->totpoints = totnewpoints;
2371  gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
2372  if (gps->dvert != NULL) {
2373  gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
2374  }
2375 
2376  /* copy all points */
2377  int i2 = 0;
2378  for (int i = 0; i < oldtotpoints; i++) {
2379  bGPDspoint *pt = &temp_points[i];
2380  bGPDspoint *pt_final = &gps->points[i2];
2381  gpencil_copy_points(gps, pt, pt_final, i, i2);
2382 
2383  /* create new point duplicating point and copy location */
2384  if (ELEM(i, a_idx, b_idx)) {
2385  i2++;
2386  pt_final = &gps->points[i2];
2387  gpencil_copy_points(gps, pt, pt_final, i, i2);
2388  copy_v3_v3(&pt_final->x, (i == a_idx) ? co_a : co_b);
2389 
2390  /* Un-select. */
2391  pt_final->flag &= ~GP_SPOINT_SELECT;
2392  /* tag to avoid more checking with this point */
2393  pt_final->flag |= GP_SPOINT_TAG;
2394  }
2395 
2396  i2++;
2397  }
2398  /* Calc geometry data. */
2400 
2401  MEM_SAFE_FREE(temp_points);
2402 }
2403 
2404 static float gpencil_calc_factor(const float p2d_a1[2],
2405  const float p2d_a2[2],
2406  const float r_hit2d[2])
2407 {
2408  float dist1 = len_squared_v2v2(p2d_a1, p2d_a2);
2409  float dist2 = len_squared_v2v2(p2d_a1, r_hit2d);
2410  float f = dist1 > 0.0f ? dist2 / dist1 : 0.0f;
2411 
2412  /* apply a correction factor */
2413  float v1[2];
2414  interp_v2_v2v2(v1, p2d_a1, p2d_a2, f);
2415  float dist3 = len_squared_v2v2(p2d_a1, v1);
2416  float f1 = dist1 > 0.0f ? dist3 / dist1 : 0.0f;
2417  f = f + (f - f1);
2418 
2419  return f;
2420 }
2421 
2422 /* extend selection to stroke intersections */
2424  bGPDlayer *gpl,
2425  bGPDstroke *gps,
2426  bGPDspoint *pt,
2427  bool select,
2428  bool insert,
2429  const float scale,
2430  float r_hita[3],
2431  float r_hitb[3])
2432 {
2433  if (gps->totpoints < 2) {
2434  return 0;
2435  }
2436  const float min_factor = 0.0015f;
2437  bGPDspoint *pta1 = NULL;
2438  bGPDspoint *pta2 = NULL;
2439  float f = 0.0f;
2440  int i2 = 0;
2441 
2442  bGPDlayer *gpl_orig = (gpl->runtime.gpl_orig) ? gpl->runtime.gpl_orig : gpl;
2443  bGPDframe *gpf = gpl_orig->actframe;
2444  if (gpf == NULL) {
2445  return 0;
2446  }
2447 
2448  int memsize = BLI_listbase_count(&gpf->strokes);
2449  bGPDstroke **gps_array = MEM_callocN(sizeof(bGPDstroke *) * memsize, __func__);
2450 
2451  /* save points */
2452  bGPDspoint *oldpoints = MEM_dupallocN(gps->points);
2453 
2454  /* Save list of strokes to check */
2455  int totstrokes = 0;
2456  LISTBASE_FOREACH (bGPDstroke *, gps_iter, &gpf->strokes) {
2457  if (gps_iter->totpoints < 2) {
2458  continue;
2459  }
2460  gps_array[totstrokes] = gps_iter;
2461  totstrokes++;
2462  }
2463 
2464  if (totstrokes == 0) {
2465  return 0;
2466  }
2467 
2468  /* look for index of the current point */
2469  int cur_idx = -1;
2470  for (int i = 0; i < gps->totpoints; i++) {
2471  pta1 = &gps->points[i];
2472  if (pta1 == pt) {
2473  cur_idx = i;
2474  break;
2475  }
2476  }
2477  if (cur_idx < 0) {
2478  return 0;
2479  }
2480 
2481  /* convert all gps points to 2d and save in a hash to avoid recalculation */
2482  int direction = 0;
2483  float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints,
2484  "GP Stroke temp 2d points");
2486  gps->points, gps->totpoints, gps->points, gps->totpoints, points2d, scale, &direction);
2487 
2488  GHash *all_2d = BLI_ghash_ptr_new(__func__);
2489 
2490  for (int s = 0; s < totstrokes; s++) {
2491  bGPDstroke *gps_iter = gps_array[s];
2492  float(*points2d_iter)[2] = MEM_mallocN(sizeof(*points2d_iter) * gps_iter->totpoints, __func__);
2493 
2494  /* the extremes of the stroke are scaled to improve collision detection
2495  * for near lines */
2497  gps->totpoints,
2498  gps_iter->points,
2499  gps_iter->totpoints,
2500  points2d_iter,
2501  scale,
2502  &direction);
2503  BLI_ghash_insert(all_2d, gps_iter, points2d_iter);
2504  }
2505 
2506  bool hit_a = false;
2507  bool hit_b = false;
2508  float p2d_a1[2] = {0.0f, 0.0f};
2509  float p2d_a2[2] = {0.0f, 0.0f};
2510  float r_hit2d[2];
2511  bGPDspoint *hit_pointa = NULL;
2512  bGPDspoint *hit_pointb = NULL;
2513 
2514  /* analyze points before current */
2515  if (cur_idx > 0) {
2516  for (int i = cur_idx; i >= 0; i--) {
2517  pta1 = &gps->points[i];
2518  copy_v2_v2(p2d_a1, points2d[i]);
2519 
2520  i2 = i - 1;
2521  CLAMP_MIN(i2, 0);
2522  pta2 = &gps->points[i2];
2523  copy_v2_v2(p2d_a2, points2d[i2]);
2524 
2525  hit_a = gpencil_check_collision(gps, gps_array, all_2d, totstrokes, p2d_a1, p2d_a2, r_hit2d);
2526 
2527  if (select) {
2528  pta1->flag |= GP_SPOINT_SELECT;
2529  }
2530  else {
2531  pta1->flag &= ~GP_SPOINT_SELECT;
2532  }
2533 
2534  if (hit_a) {
2535  f = gpencil_calc_factor(p2d_a1, p2d_a2, r_hit2d);
2536  interp_v3_v3v3(r_hita, &pta1->x, &pta2->x, f);
2537  if (f > min_factor) {
2538  hit_pointa = pta2; /* first point is second (inverted loop) */
2539  }
2540  else {
2541  pta1->flag &= ~GP_SPOINT_SELECT;
2542  }
2543  break;
2544  }
2545  }
2546  }
2547 
2548  /* analyze points after current */
2549  for (int i = cur_idx; i < gps->totpoints; i++) {
2550  pta1 = &gps->points[i];
2551  copy_v2_v2(p2d_a1, points2d[i]);
2552 
2553  i2 = i + 1;
2554  CLAMP_MAX(i2, gps->totpoints - 1);
2555  pta2 = &gps->points[i2];
2556  copy_v2_v2(p2d_a2, points2d[i2]);
2557 
2558  hit_b = gpencil_check_collision(gps, gps_array, all_2d, totstrokes, p2d_a1, p2d_a2, r_hit2d);
2559 
2560  if (select) {
2561  pta1->flag |= GP_SPOINT_SELECT;
2562  }
2563  else {
2564  pta1->flag &= ~GP_SPOINT_SELECT;
2565  }
2566 
2567  if (hit_b) {
2568  f = gpencil_calc_factor(p2d_a1, p2d_a2, r_hit2d);
2569  interp_v3_v3v3(r_hitb, &pta1->x, &pta2->x, f);
2570  if (f > min_factor) {
2571  hit_pointb = pta1;
2572  }
2573  else {
2574  pta1->flag &= ~GP_SPOINT_SELECT;
2575  }
2576  break;
2577  }
2578  }
2579 
2580  /* insert new point in the collision points */
2581  if (insert) {
2582  gpencil_insert_point(gpd, gps, hit_pointa, hit_pointb, r_hita, r_hitb);
2583  }
2584 
2585  /* free memory */
2586  if (all_2d) {
2587  GHashIterator gh_iter;
2588  GHASH_ITER (gh_iter, all_2d) {
2589  float(*p2d)[2] = BLI_ghashIterator_getValue(&gh_iter);
2590  MEM_SAFE_FREE(p2d);
2591  }
2592  BLI_ghash_free(all_2d, NULL, NULL);
2593  }
2594 
2595  /* if no hit, reset selection flag */
2596  if ((!hit_a) && (!hit_b)) {
2597  for (int i = 0; i < gps->totpoints; i++) {
2598  pta1 = &gps->points[i];
2599  pta2 = &oldpoints[i];
2600  pta1->flag = pta2->flag;
2601  }
2602  }
2603 
2604  MEM_SAFE_FREE(points2d);
2605  MEM_SAFE_FREE(gps_array);
2606  MEM_SAFE_FREE(oldpoints);
2607 
2608  /* return type of hit */
2609  if ((hit_a) && (hit_b)) {
2610  return 3;
2611  }
2612  if (hit_a) {
2613  return 1;
2614  }
2615  if (hit_b) {
2616  return 2;
2617  }
2618  return 0;
2619 }
2620 
2622 {
2624  bGPdata *gpd = ob->data;
2625 
2626  /* for "toggle", test for existing selected strokes */
2627  if (action == SEL_TOGGLE) {
2628  action = SEL_SELECT;
2629 
2630  CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
2631  if (gps->flag & GP_STROKE_SELECT) {
2632  action = SEL_DESELECT;
2633  break; /* XXX: this only gets out of the inner loop. */
2634  }
2635  }
2636  CTX_DATA_END;
2637  }
2638 
2639  /* if deselecting, we need to deselect strokes across all frames
2640  * - Currently, an exception is only given for deselection
2641  * Selecting and toggling should only affect what's visible,
2642  * while deselecting helps clean up unintended/forgotten
2643  * stuff on other frames
2644  */
2645  if (action == SEL_DESELECT) {
2646  /* deselect strokes across editable layers
2647  * NOTE: we limit ourselves to editable layers, since once a layer is "locked/hidden
2648  * nothing should be able to touch it
2649  */
2650  /* Set selection index to 0. */
2651  gpd->select_last_index = 0;
2652 
2653  CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
2654 
2655  /* deselect all strokes on all frames */
2656  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
2657  bGPDstroke *gps;
2658 
2659  for (gps = gpf->strokes.first; gps; gps = gps->next) {
2660  bGPDspoint *pt;
2661  int i;
2662 
2663  /* only edit strokes that are valid in this view... */
2664  if (ED_gpencil_stroke_can_use(C, gps)) {
2665  for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
2666  pt->flag &= ~GP_SPOINT_SELECT;
2667  }
2668 
2669  gps->flag &= ~GP_STROKE_SELECT;
2671  }
2672  }
2673  }
2674  }
2675  CTX_DATA_END;
2676  }
2677  else {
2678  /* select or deselect all strokes */
2679  CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
2680  bGPDspoint *pt;
2681  int i;
2682  bool selected = false;
2683 
2684  /* Change selection status of all points, then make the stroke match */
2685  for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
2686  switch (action) {
2687  case SEL_SELECT:
2688  pt->flag |= GP_SPOINT_SELECT;
2689  break;
2690 #if 0
2691  case SEL_DESELECT:
2692  pt->flag &= ~GP_SPOINT_SELECT;
2693  break;
2694 #endif
2695  case SEL_INVERT:
2696  pt->flag ^= GP_SPOINT_SELECT;
2697  break;
2698  }
2699 
2700  if (pt->flag & GP_SPOINT_SELECT) {
2701  selected = true;
2702  }
2703  }
2704 
2705  /* Change status of stroke */
2706  if (selected) {
2707  gps->flag |= GP_STROKE_SELECT;
2709  }
2710  else {
2711  gps->flag &= ~GP_STROKE_SELECT;
2713  }
2714  }
2715  CTX_DATA_END;
2716  }
2717 }
2718 
2720 {
2721  /* if toggle, check if we need to select or deselect */
2722  if (action == SEL_TOGGLE) {
2723  action = SEL_SELECT;
2724  GP_EDITABLE_CURVES_BEGIN(gps_iter, C, gpl, gps, gpc)
2725  {
2726  if (gpc->flag & GP_CURVE_SELECT) {
2727  action = SEL_DESELECT;
2728  }
2729  }
2730  GP_EDITABLE_CURVES_END(gps_iter);
2731  }
2732 
2733  if (action == SEL_DESELECT) {
2734  /* Set selection index to 0. */
2736  bGPdata *gpd = ob->data;
2737  gpd->select_last_index = 0;
2738 
2739  GP_EDITABLE_CURVES_BEGIN(gps_iter, C, gpl, gps, gpc)
2740  {
2741  for (int i = 0; i < gpc->tot_curve_points; i++) {
2742  bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
2743  BezTriple *bezt = &gpc_pt->bezt;
2744  gpc_pt->flag &= ~GP_CURVE_POINT_SELECT;
2745  BEZT_DESEL_ALL(bezt);
2746  }
2747  gpc->flag &= ~GP_CURVE_SELECT;
2748  gps->flag &= ~GP_STROKE_SELECT;
2750  }
2751  GP_EDITABLE_CURVES_END(gps_iter);
2752  }
2753  else {
2754  GP_EDITABLE_STROKES_BEGIN (gps_iter, C, gpl, gps) {
2756  bGPdata *gpd = ob->data;
2757  bool selected = false;
2758 
2759  /* Make sure stroke has an editcurve */
2760  if (gps->editcurve == NULL) {
2761  BKE_gpencil_stroke_editcurve_update(gpd, gpl, gps);
2762  gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
2764  }
2765 
2766  bGPDcurve *gpc = gps->editcurve;
2767  for (int i = 0; i < gpc->tot_curve_points; i++) {
2768  bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
2769  BezTriple *bezt = &gpc_pt->bezt;
2770  switch (action) {
2771  case SEL_SELECT:
2772  gpc_pt->flag |= GP_CURVE_POINT_SELECT;
2773  BEZT_SEL_ALL(bezt);
2774  break;
2775  case SEL_INVERT:
2776  gpc_pt->flag ^= GP_CURVE_POINT_SELECT;
2777  BEZT_SEL_INVERT(bezt);
2778  break;
2779  default:
2780  break;
2781  }
2782 
2783  if (gpc_pt->flag & GP_CURVE_POINT_SELECT) {
2784  selected = true;
2785  }
2786  }
2787 
2788  if (selected) {
2789  gpc->flag |= GP_CURVE_SELECT;
2790  gps->flag |= GP_STROKE_SELECT;
2792  }
2793  else {
2794  gpc->flag &= ~GP_CURVE_SELECT;
2795  gps->flag &= ~GP_STROKE_SELECT;
2797  }
2798  }
2799  GP_EDITABLE_STROKES_END(gps_iter);
2800  }
2801 }
2802 
2808  int *buffer_size,
2809  int *buffer_used,
2810  const bool clear)
2811 {
2812  tGPspoint *p = NULL;
2813 
2814  /* By default a buffer is created with one block with a predefined number of free points,
2815  * if the size is not enough, the cache is reallocated adding a new block of free points.
2816  * This is done in order to keep cache small and improve speed. */
2817  if (*buffer_used + 1 > *buffer_size) {
2818  if ((*buffer_size == 0) || (buffer_array == NULL)) {
2819  p = MEM_callocN(sizeof(struct tGPspoint) * GP_STROKE_BUFFER_CHUNK, "GPencil Sbuffer");
2820  *buffer_size = GP_STROKE_BUFFER_CHUNK;
2821  }
2822  else {
2823  *buffer_size += GP_STROKE_BUFFER_CHUNK;
2824  p = MEM_recallocN(buffer_array, sizeof(struct tGPspoint) * *buffer_size);
2825  }
2826 
2827  if (p == NULL) {
2828  *buffer_size = *buffer_used = 0;
2829  }
2830 
2831  buffer_array = p;
2832  }
2833 
2834  /* clear old data */
2835  if (clear) {
2836  *buffer_used = 0;
2837  if (buffer_array != NULL) {
2838  memset(buffer_array, 0, sizeof(tGPspoint) * *buffer_size);
2839  }
2840  }
2841 
2842  return buffer_array;
2843 }
2844 
2846 {
2847  bGPdata *gpd_eval = (bGPdata *)ob_eval->data;
2848 
2849  gpd_eval->runtime.sbuffer = gpd->runtime.sbuffer;
2850  gpd_eval->runtime.sbuffer_sflag = gpd->runtime.sbuffer_sflag;
2851  gpd_eval->runtime.sbuffer_used = gpd->runtime.sbuffer_used;
2852  gpd_eval->runtime.sbuffer_size = gpd->runtime.sbuffer_size;
2853  gpd_eval->runtime.tot_cp_points = gpd->runtime.tot_cp_points;
2854  gpd_eval->runtime.cp_points = gpd->runtime.cp_points;
2855 }
2856 
2861 {
2862  /* Mark all grease pencil data-blocks of the scene. */
2863  FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
2865  if (ob->type == OB_GPENCIL) {
2866  bGPdata *gpd = (bGPdata *)ob->data;
2867  gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
2869  }
2870  }
2872  }
2874 
2876 
2878 }
2879 
2881 {
2882  const bool is_vertex = (GPENCIL_USE_VERTEX_COLOR_FILL(ts, brush) &&
2884  (!GPENCIL_USE_VERTEX_COLOR_FILL(ts, brush) &&
2886  if (is_vertex) {
2887  copy_v3_v3(gps->vert_color_fill, brush->rgb);
2890  }
2891  else {
2892  zero_v4(gps->vert_color_fill);
2893  }
2894 }
2895 
2897  Brush *brush,
2898  bGPDspoint *pt,
2899  tGPspoint *tpt)
2900 {
2901  const bool is_vertex = (GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush) &&
2903  (!GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush) &&
2905 
2906  if (is_vertex) {
2907  if (tpt == NULL) {
2908  copy_v3_v3(pt->vert_color, brush->rgb);
2909  pt->vert_color[3] = brush->gpencil_settings->vertex_factor;
2911  }
2912  else {
2913  copy_v3_v3(pt->vert_color, tpt->vert_color);
2914  pt->vert_color[3] = brush->gpencil_settings->vertex_factor;
2915  }
2916  }
2917  else {
2918  zero_v4(pt->vert_color);
2919  }
2920 }
2921 
2923  const int mval[2],
2924  GpRandomSettings *random_settings)
2925 {
2926  int seed = ((uint)(ceil(PIL_check_seconds_timer())) + 1) % 128;
2927  /* Use mouse position to get randomness. */
2928  int ix = mval[0] * seed;
2929  int iy = mval[1] * seed;
2930  int iz = ix + iy * seed;
2931  zero_v3(random_settings->hsv);
2932 
2933  BrushGpencilSettings *brush_settings = brush->gpencil_settings;
2934  /* Random to Hue. */
2935  if (brush_settings->random_hue > 0.0f) {
2936  float rand = BLI_hash_int_01(BLI_hash_int_2d(ix, iy)) * 2.0f - 1.0f;
2937  random_settings->hsv[0] = rand * brush_settings->random_hue * 0.5f;
2938  }
2939  /* Random to Saturation. */
2940  if (brush_settings->random_saturation > 0.0f) {
2941  float rand = BLI_hash_int_01(BLI_hash_int_2d(iy, ix)) * 2.0f - 1.0f;
2942  random_settings->hsv[1] = rand * brush_settings->random_saturation;
2943  }
2944  /* Random to Value. */
2945  if (brush_settings->random_value > 0.0f) {
2946  float rand = BLI_hash_int_01(BLI_hash_int_2d(ix * iz, iy * iz)) * 2.0f - 1.0f;
2947  random_settings->hsv[2] = rand * brush_settings->random_value;
2948  }
2949 
2950  /* Random to pressure. */
2951  if (brush_settings->draw_random_press > 0.0f) {
2952  random_settings->pressure = BLI_hash_int_01(BLI_hash_int_2d(ix + iz, iy + iz)) * 2.0f - 1.0f;
2953  }
2954 
2955  /* Random to color strength. */
2956  if (brush_settings->draw_random_strength) {
2957  random_settings->strength = BLI_hash_int_01(BLI_hash_int_2d(ix + iy, iy + iz + ix)) * 2.0f -
2958  1.0f;
2959  }
2960 
2961  /* Random to uv texture rotation. */
2962  if (brush_settings->uv_random > 0.0f) {
2963  random_settings->uv = BLI_hash_int_01(BLI_hash_int_2d(iy + iz, ix * iz)) * 2.0f - 1.0f;
2964  }
2965 }
2966 
2968  bGPdata *gpd, Brush *brush, tGPspoint *tpt, const float random_color[3], float pen_pressure)
2969 {
2970  BrushGpencilSettings *brush_settings = brush->gpencil_settings;
2971  if (brush_settings->flag & GP_BRUSH_GROUP_RANDOM) {
2972  int seed = ((uint)(ceil(PIL_check_seconds_timer())) + 1) % 128;
2973 
2974  int ix = (int)(tpt->x * seed);
2975  int iy = (int)(tpt->y * seed);
2976  int iz = ix + iy * seed;
2977  float hsv[3];
2978  float factor_value[3];
2979  zero_v3(factor_value);
2980 
2981  /* Apply randomness to Hue. */
2982  if (brush_settings->random_hue > 0.0f) {
2983  if ((brush_settings->flag2 & GP_BRUSH_USE_HUE_AT_STROKE) == 0) {
2984 
2985  float rand = BLI_hash_int_01(BLI_hash_int_2d(ix, gpd->runtime.sbuffer_used)) * 2.0f - 1.0f;
2986  factor_value[0] = rand * brush_settings->random_hue * 0.5f;
2987  }
2988  else {
2989  factor_value[0] = random_color[0];
2990  }
2991 
2992  /* Apply random curve. */
2993  if (brush_settings->flag2 & GP_BRUSH_USE_HUE_RAND_PRESS) {
2994  factor_value[0] *= BKE_curvemapping_evaluateF(
2995  brush_settings->curve_rand_hue, 0, pen_pressure);
2996  }
2997  }
2998 
2999  /* Apply randomness to Saturation. */
3000  if (brush_settings->random_saturation > 0.0f) {
3001  if ((brush_settings->flag2 & GP_BRUSH_USE_SAT_AT_STROKE) == 0) {
3002  float rand = BLI_hash_int_01(BLI_hash_int_2d(iy, gpd->runtime.sbuffer_used)) * 2.0f - 1.0f;
3003  factor_value[1] = rand * brush_settings->random_saturation;
3004  }
3005  else {
3006  factor_value[1] = random_color[1];
3007  }
3008 
3009  /* Apply random curve. */
3010  if (brush_settings->flag2 & GP_BRUSH_USE_SAT_RAND_PRESS) {
3011  factor_value[1] *= BKE_curvemapping_evaluateF(
3012  brush_settings->curve_rand_saturation, 0, pen_pressure);
3013  }
3014  }
3015 
3016  /* Apply randomness to Value. */
3017  if (brush_settings->random_value > 0.0f) {
3018  if ((brush_settings->flag2 & GP_BRUSH_USE_VAL_AT_STROKE) == 0) {
3019  float rand = BLI_hash_int_01(BLI_hash_int_2d(iz, gpd->runtime.sbuffer_used)) * 2.0f - 1.0f;
3020  factor_value[2] = rand * brush_settings->random_value;
3021  }
3022  else {
3023  factor_value[2] = random_color[2];
3024  }
3025 
3026  /* Apply random curve. */
3027  if (brush_settings->flag2 & GP_BRUSH_USE_VAL_RAND_PRESS) {
3028  factor_value[2] *= BKE_curvemapping_evaluateF(
3029  brush_settings->curve_rand_value, 0, pen_pressure);
3030  }
3031  }
3032 
3033  rgb_to_hsv_v(tpt->vert_color, hsv);
3034  add_v3_v3(hsv, factor_value);
3035  /* For Hue need to cover all range, but for Saturation and Value
3036  * is not logic because the effect is too hard, so the value is just clamped. */
3037  if (hsv[0] < 0.0f) {
3038  hsv[0] += 1.0f;
3039  }
3040  else if (hsv[0] > 1.0f) {
3041  hsv[0] -= 1.0f;
3042  }
3043 
3044  CLAMP3(hsv, 0.0f, 1.0f);
3045  hsv_to_rgb_v(hsv, tpt->vert_color);
3046  }
3047 }
3048 
3050  Object *ob,
3051  ToolSettings *ts,
3052  Brush *brush,
3053  Material *material,
3054  float random_color[3],
3055  float pen_pressure)
3056 {
3057  bGPdata *gpd = (bGPdata *)ob->data;
3058  Object *ob_eval = (Object *)DEG_get_evaluated_id(depsgraph, &ob->id);
3059  bGPdata *gpd_eval = (bGPdata *)ob_eval->data;
3060  MaterialGPencilStyle *gp_style = material->gp_style;
3061 
3062  const bool is_vertex_fill =
3063  (GPENCIL_USE_VERTEX_COLOR_FILL(ts, brush) &&
3065  (!GPENCIL_USE_VERTEX_COLOR_FILL(ts, brush) &&
3067 
3068  const bool is_vertex_stroke =
3069  (GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush) &&
3071  (!GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush) &&
3073 
3074  int idx = gpd->runtime.sbuffer_used;
3075  tGPspoint *tpt = (tGPspoint *)gpd->runtime.sbuffer + idx;
3076 
3077  float vertex_color[4];
3078  copy_v3_v3(vertex_color, brush->rgb);
3079  vertex_color[3] = brush->gpencil_settings->vertex_factor;
3080  srgb_to_linearrgb_v4(vertex_color, vertex_color);
3081 
3082  /* Copy fill vertex color. */
3083  if (is_vertex_fill) {
3084  copy_v4_v4(gpd->runtime.vert_color_fill, vertex_color);
3085  }
3086  else {
3087  copy_v4_v4(gpd->runtime.vert_color_fill, gp_style->fill_rgba);
3088  }
3089  /* Copy stroke vertex color. */
3090  if (is_vertex_stroke) {
3091  copy_v4_v4(tpt->vert_color, vertex_color);
3092  }
3093  else {
3094  copy_v4_v4(tpt->vert_color, gp_style->stroke_rgba);
3095  }
3096 
3097  /* Random Color. */
3098  gpencil_sbuffer_vertex_color_random(gpd, brush, tpt, random_color, pen_pressure);
3099 
3100  /* Copy to evaluate data because paint operators don't tag refresh until end for speedup
3101  * painting. */
3102  if (gpd_eval != NULL) {
3104  gpd_eval->runtime.matid = gpd->runtime.matid;
3105  }
3106 }
3107 
3108 /* Get the bigger 2D bound box points. */
3110  bGPDstroke *gps,
3111  const float diff_mat[4][4],
3112  float r_min[2],
3113  float r_max[2])
3114 {
3115  float bounds[8][2];
3116  BoundBox bb;
3118 
3119  /* Project 8 vertices in 2D. */
3120  for (int i = 0; i < 8; i++) {
3121  bGPDspoint pt_dummy, pt_dummy_ps;
3122  copy_v3_v3(&pt_dummy.x, bb.vec[i]);
3123  gpencil_point_to_parent_space(&pt_dummy, diff_mat, &pt_dummy_ps);
3124  gpencil_point_to_xy_fl(gsc, gps, &pt_dummy_ps, &bounds[i][0], &bounds[i][1]);
3125  }
3126 
3127  /* Take extremes. */
3128  INIT_MINMAX2(r_min, r_max);
3129  for (int i = 0; i < 8; i++) {
3130  minmax_v2v2_v2(r_min, r_max, bounds[i]);
3131  }
3132 
3133  /* Ensure the bounding box is oriented to axis. */
3134  if (r_max[0] < r_min[0]) {
3135  SWAP(float, r_min[0], r_max[0]);
3136  }
3137  if (r_max[1] < r_min[1]) {
3138  SWAP(float, r_min[1], r_max[1]);
3139  }
3140 }
3141 
3142 /* Check if the stroke collides with brush. */
3144  bGPDstroke *gps,
3145  const float mouse[2],
3146  const int radius,
3147  const float diff_mat[4][4])
3148 {
3149  const int offset = (int)ceil(sqrt((radius * radius) * 2));
3150  float boundbox_min[2];
3151  float boundbox_max[2];
3152 
3153  /* Check we have something to use (only for old files). */
3154  if (is_zero_v3(gps->boundbox_min)) {
3156  }
3157 
3158  ED_gpencil_projected_2d_bound_box(gsc, gps, diff_mat, boundbox_min, boundbox_max);
3159 
3160  rcti rect_stroke = {boundbox_min[0], boundbox_max[0], boundbox_min[1], boundbox_max[1]};
3161 
3162  /* For mouse, add a small offset to avoid false negative in corners. */
3163  rcti rect_mouse = {mouse[0] - offset, mouse[0] + offset, mouse[1] - offset, mouse[1] + offset};
3164 
3165  /* Check collision between both rectangles. */
3166  return BLI_rcti_isect(&rect_stroke, &rect_mouse, NULL);
3167 }
3168 
3179  GP_SpaceConversion *gsc,
3180  int mouse[2],
3181  const float diff_mat[4][4])
3182 {
3183  bool hit = false;
3184  if (gps->totpoints == 0) {
3185  return hit;
3186  }
3187 
3188  int(*mcoords)[2] = NULL;
3189  int len = gps->totpoints;
3190  mcoords = MEM_mallocN(sizeof(int[2]) * len, __func__);
3191 
3192  /* Convert stroke to 2D array of points. */
3193  bGPDspoint *pt;
3194  int i;
3195  for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
3196  bGPDspoint pt2;
3197  gpencil_point_to_parent_space(pt, diff_mat, &pt2);
3198  gpencil_point_to_xy(gsc, gps, &pt2, &mcoords[i][0], &mcoords[i][1]);
3199  }
3200 
3201  /* Compute bound-box of lasso (for faster testing later). */
3202  rcti rect;
3203  BLI_lasso_boundbox(&rect, mcoords, len);
3204 
3205  /* Test if point inside stroke. */
3206  hit = ((!ELEM(V2D_IS_CLIPPED, mouse[0], mouse[1])) &&
3207  BLI_rcti_isect_pt(&rect, mouse[0], mouse[1]) &&
3208  BLI_lasso_is_point_inside(mcoords, len, mouse[0], mouse[1], INT_MAX));
3209 
3210  /* Free memory. */
3211  MEM_SAFE_FREE(mcoords);
3212 
3213  return hit;
3214 }
3215 
3217  GP_SpaceConversion *gsc,
3218  bGPDlayer *gpl,
3219  bGPDframe *gpf,
3220  bGPDstroke *gps,
3221  const float radius,
3222  int *r_index)
3223 {
3226  bGPDstroke *gps_rtn = NULL;
3227  const float radius_sqr = radius * radius;
3228 
3229  /* calculate difference matrix object */
3230  float diff_mat[4][4];
3232 
3233  /* Calculate the extremes of the stroke in 2D. */
3234  bGPDspoint pt_parent;
3235  float pt2d_start[2], pt2d_end[2];
3236 
3237  bGPDspoint *pt = &gps->points[0];
3238  gpencil_point_to_parent_space(pt, diff_mat, &pt_parent);
3239  gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d_start[0], &pt2d_start[1]);
3240 
3241  pt = &gps->points[gps->totpoints - 1];
3242  gpencil_point_to_parent_space(pt, diff_mat, &pt_parent);
3243  gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d_end[0], &pt2d_end[1]);
3244 
3245  /* Loop all strokes of the active frame. */
3246  float dist_min = FLT_MAX;
3247  LISTBASE_FOREACH (bGPDstroke *, gps_target, &gpf->strokes) {
3248  /* Check if the color is editable. */
3249  if ((gps_target == gps) || (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false)) {
3250  continue;
3251  }
3252 
3253  /* Check if one of the ends is inside target stroke bounding box. */
3254  if ((!ED_gpencil_stroke_check_collision(gsc, gps_target, pt2d_start, radius, diff_mat)) &&
3255  (!ED_gpencil_stroke_check_collision(gsc, gps_target, pt2d_end, radius, diff_mat))) {
3256  continue;
3257  }
3258  /* Check the distance of the ends with the ends of target stroke to avoid middle contact.
3259  * All is done in 2D plane. */
3260  float pt2d_target_start[2], pt2d_target_end[2];
3261 
3262  pt = &gps_target->points[0];
3263  gpencil_point_to_parent_space(pt, diff_mat, &pt_parent);
3264  gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d_target_start[0], &pt2d_target_start[1]);
3265 
3266  pt = &gps_target->points[gps_target->totpoints - 1];
3267  gpencil_point_to_parent_space(pt, diff_mat, &pt_parent);
3268  gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d_target_end[0], &pt2d_target_end[1]);
3269 
3270  if ((len_squared_v2v2(pt2d_start, pt2d_target_start) > radius_sqr) &&
3271  (len_squared_v2v2(pt2d_start, pt2d_target_end) > radius_sqr) &&
3272  (len_squared_v2v2(pt2d_end, pt2d_target_start) > radius_sqr) &&
3273  (len_squared_v2v2(pt2d_end, pt2d_target_end) > radius_sqr)) {
3274  continue;
3275  }
3276 
3277  /* Loop all points and check what is the nearest point. */
3278  int i;
3279  for (i = 0, pt = gps_target->points; i < gps_target->totpoints; i++, pt++) {
3280  /* Convert point to 2D. */
3281  float pt2d[2];
3282  gpencil_point_to_parent_space(pt, diff_mat, &pt_parent);
3283  gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d[0], &pt2d[1]);
3284 
3285  /* Check with Start point. */
3286  float dist = len_squared_v2v2(pt2d, pt2d_start);
3287  if ((dist <= radius_sqr) && (dist < dist_min)) {
3288  *r_index = i;
3289  dist_min = dist;
3290  gps_rtn = gps_target;
3291  }
3292  /* Check with End point. */
3293  dist = len_squared_v2v2(pt2d, pt2d_end);
3294  if ((dist <= radius_sqr) && (dist < dist_min)) {
3295  *r_index = i;
3296  dist_min = dist;
3297  gps_rtn = gps_target;
3298  }
3299  }
3300  }
3301 
3302  return gps_rtn;
3303 }
3304 
3305 /* Join two stroke using a contact point index and trimming the rest. */
3307  bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *gps_dst, const int pt_index)
3308 {
3309  if ((gps->totpoints < 1) || (gps_dst->totpoints < 1)) {
3310  return NULL;
3311  }
3312  BLI_assert(pt_index >= 0 && pt_index < gps_dst->totpoints);
3313 
3314  bGPDspoint *pt = NULL;
3315 
3316  /* Cannot be cyclic. */
3317  gps->flag &= ~GP_STROKE_CYCLIC;
3318  gps_dst->flag &= ~GP_STROKE_CYCLIC;
3319 
3320  /* Trim stroke. */
3321  bGPDstroke *gps_final = gps_dst;
3322  if ((pt_index > 0) && (pt_index < gps_dst->totpoints - 2)) {
3323  /* Untag any pending operation. */
3324  gps_dst->flag &= ~GP_STROKE_TAG;
3325  for (int i = 0; i < gps_dst->totpoints; i++) {
3326  gps_dst->points[i].flag &= ~GP_SPOINT_TAG;
3327  }
3328 
3329  /* Delete points of the shorter extreme */
3330  pt = &gps_dst->points[0];
3331  float dist_to_start = BKE_gpencil_stroke_segment_length(gps_dst, 0, pt_index, true);
3332  pt = &gps_dst->points[gps_dst->totpoints - 1];
3333  float dist_to_end = BKE_gpencil_stroke_segment_length(
3334  gps_dst, pt_index, gps_dst->totpoints - 1, true);
3335 
3336  if (dist_to_start < dist_to_end) {
3337  for (int i = 0; i < pt_index; i++) {
3338  gps_dst->points[i].flag |= GP_SPOINT_TAG;
3339  }
3340  }
3341  else {
3342  for (int i = pt_index + 1; i < gps_dst->totpoints; i++) {
3343  gps_dst->points[i].flag |= GP_SPOINT_TAG;
3344  }
3345  }
3346  /* Remove tagged points to trim stroke. */
3348  gpd, gpf, gps_dst, gps_dst->next, GP_SPOINT_TAG, false, false, 0);
3349  }
3350 
3351  /* Join both strokes. */
3352  int totpoint = gps_final->totpoints;
3353  BKE_gpencil_stroke_join(gps_final, gps, false, true);
3354 
3355  /* Select the join points and merge if the distance is very small. */
3356  pt = &gps_final->points[totpoint - 1];
3357  pt->flag |= GP_SPOINT_SELECT;
3358 
3359  pt = &gps_final->points[totpoint];
3360  pt->flag |= GP_SPOINT_SELECT;
3361  BKE_gpencil_stroke_merge_distance(gpd, gpf, gps_final, 0.01f, false);
3362 
3363  /* Unselect all points. */
3364  for (int i = 0; i < gps_final->totpoints; i++) {
3365  gps_final->points[i].flag &= ~GP_SPOINT_SELECT;
3366  }
3367 
3368  /* Delete old stroke. */
3369  BLI_remlink(&gpf->strokes, gps);
3371 
3372  return gps_final;
3373 }
3374 
3375 /* Close if the distance between extremes is below threshold. */
3376 void ED_gpencil_stroke_close_by_distance(bGPDstroke *gps, const float threshold)
3377 {
3378  if (gps == NULL) {
3379  return;
3380  }
3381  bGPDspoint *pt_start = &gps->points[0];
3382  bGPDspoint *pt_end = &gps->points[gps->totpoints - 1];
3383 
3384  const float threshold_sqr = threshold * threshold;
3385  float dist_to_close = len_squared_v3v3(&pt_start->x, &pt_end->x);
3386  if (dist_to_close < threshold_sqr) {
3387  gps->flag |= GP_STROKE_CYCLIC;
3389  }
3390 }
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, const bool reset)
Definition: brush.c: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:1200
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:88
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:714
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
#define CTX_DATA_BEGIN(C, Type, instance, member)
Definition: BKE_context.h:252
struct bGPdata * CTX_data_gpencil_data(const bContext *C)
Definition: context.c:1371
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1424
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1279
struct bScreen * CTX_wm_screen(const bContext *C)
Definition: context.c:709
struct SpaceLink * CTX_wm_space_data(const bContext *C)
Definition: context.c:719
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
struct ToolSettings * CTX_data_tool_settings(const bContext *C)
Definition: context.c:1208
#define CTX_DATA_END
Definition: BKE_context.h:260
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:699
support for deformation groups and hooks.
struct MDeformWeight * BKE_defvert_ensure_index(struct MDeformVert *dv, const int defgroup)
Definition: deform.c:688
struct MDeformWeight * BKE_defvert_find_index(const struct MDeformVert *dv, const int defgroup)
void BKE_defvert_remove_group(struct MDeformVert *dvert, struct MDeformWeight *dw)
Definition: deform.c:754
void BKE_gpencil_stroke_select_index_set(struct bGPdata *gpd, struct bGPDstroke *gps)
Definition: gpencil.c:1203
#define GPENCIL_USE_VERTEX_COLOR_STROKE(toolsettings, brush)
Definition: BKE_gpencil.h:72
struct bGPDlayer * BKE_gpencil_layer_active_get(struct bGPdata *gpd)
Definition: gpencil.c:1650
void BKE_gpencil_stroke_select_index_reset(struct bGPDstroke *gps)
Definition: gpencil.c:1210
void BKE_gpencil_dvert_ensure(struct bGPDstroke *gps)
Definition: gpencil.c:2067
bool BKE_gpencil_layer_is_editable(const struct bGPDlayer *gpl)
void BKE_gpencil_free_stroke(struct bGPDstroke *gps)
Definition: gpencil.c:401
struct Material * BKE_gpencil_object_material_ensure_from_active_input_toolsettings(struct Main *bmain, struct Object *ob, struct ToolSettings *ts)
Definition: gpencil.c:1925
struct Material * BKE_gpencil_object_material_from_brush_get(struct Object *ob, struct Brush *brush)
Definition: gpencil.c:1893
#define GPENCIL_STRENGTH_MIN
Definition: BKE_gpencil.h:178
void BKE_gpencil_layer_transform_matrix_get(const struct Depsgraph *depsgraph, struct Object *obact, struct bGPDlayer *gpl, float diff_mat[4][4])
struct bGPDstroke * BKE_gpencil_stroke_duplicate(struct bGPDstroke *gps_src, const bool dup_points, const bool dup_curve)
Definition: gpencil.c:957
#define GPENCIL_USE_VERTEX_COLOR_FILL(toolsettings, brush)
Definition: BKE_gpencil.h:76
void BKE_gpencil_stroke_editcurve_update(struct bGPdata *gpd, struct bGPDlayer *gpl, struct bGPDstroke *gps)
void BKE_gpencil_stroke_merge_distance(struct bGPdata *gpd, struct bGPDframe *gpf, struct bGPDstroke *gps, const float threshold, const bool use_unselected)
struct bGPDstroke * BKE_gpencil_stroke_delete_tagged_points(struct bGPdata *gpd, struct bGPDframe *gpf, struct bGPDstroke *gps, struct bGPDstroke *next_stroke, int tag_flags, const bool select, const bool flat_cap, const int limit)
void BKE_gpencil_stroke_geometry_update(struct bGPdata *gpd, 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], const float scale, int *r_direction)
void BKE_gpencil_stroke_uv_update(struct bGPDstroke *gps)
void BKE_gpencil_stroke_boundingbox_calc(struct bGPDstroke *gps)
Definition: gpencil_geom.c:144
void BKE_gpencil_stroke_join(struct bGPDstroke *gps_a, struct bGPDstroke *gps_b, const bool leave_gaps, const bool fit_thickness)
float BKE_gpencil_stroke_segment_length(const struct bGPDstroke *gps, const int start_index, const int end_index, bool use_3d)
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:713
struct Material * BKE_object_material_get(struct Object *ob, short act)
Definition: material.c:697
struct Material * BKE_gpencil_material(struct Object *ob, short act)
Definition: material.c:703
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.c:3778
bool BKE_paint_ensure(struct ToolSettings *ts, struct Paint **r_paint)
Definition: paint.c:1032
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:1170
#define BLI_assert(a)
Definition: BLI_assert.h:58
sqrt(x)+1/max(0
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.h:150
#define GHASH_ITER(gh_iter_, ghash_)
Definition: BLI_ghash.h:169
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:756
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:1008
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void * BLI_ghash_lookup(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:803
BLI_INLINE float BLI_hash_int_01(unsigned int k)
Definition: BLI_hash.h:108
BLI_INLINE unsigned int BLI_hash_int_2d(unsigned int kx, unsigned int ky)
Definition: BLI_hash.h:67
void BLI_kdtree_nd_() insert(KDTree *tree, int index, const float co[KD_DIMS]) ATTR_NONNULL(1
void BLI_lasso_boundbox(struct rcti *rect, const int mcoords[][2], const unsigned int mcoords_len)
Definition: lasso_2d.c:31
bool BLI_lasso_is_point_inside(const int mcoords[][2], const unsigned int mcoords_len, const int sx, const int sy, const int error_value)
Definition: lasso_2d.c:54
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:133
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:68
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3])
Definition: math_color.c:254
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:1353
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:2191
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:262
void unit_m4(float m[4][4])
Definition: rct.c:1140
void mul_mat3_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:794
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1278
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:732
bool equals_m4m4(const float mat1[4][4], const float mat2[4][4])
Definition: math_matrix.c:2612
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:95
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:742
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:2653
MINLINE void round_v2i_v2fl(int r[2], const float a[2])
MINLINE void copy_v4_v4(float r[4], const float a[4])
void interp_v2_v2v2(float r[2], const float a[2], const float b[2], const float t)
Definition: math_vector.c:32
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], const float t)
Definition: math_vector.c:49
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_v4_v4v4(float r[4], const float a[4], const float b[4], const float t)
Definition: math_vector.c:58
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])
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:1043
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, const int x, const 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:161
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition: BLI_rect.h:165
unsigned int uint
Definition: BLI_sys_types.h:83
unsigned short ushort
Definition: BLI_sys_types.h:84
#define INIT_MINMAX2(min, max)
#define CLAMP_MAX(a, c)
#define SWAP(type, a, b)
#define UNUSED(x)
#define ELEM(...)
#define CLAMP3(vec, b, c)
#define CLAMP_MIN(a, b)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
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:599
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:654
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:611
@ 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.
@ PARSKEL
@ PAROBJECT
@ PARBONE
@ OB_GPENCIL
@ GP_LOCKAXIS_CURSOR
@ PAINT_SHOW_BRUSH
@ GP_PROJECT_VIEWSPACE
@ GP_PROJECT_CURSOR
#define RGN_TYPE_ANY
@ RGN_TYPE_WINDOW
@ 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:572
eGP_ReprojectModes
Definition: ED_gpencil.h:68
@ GP_REPROJECT_VIEW
Definition: ED_gpencil.h:74
@ GP_REPROJECT_CURSOR
Definition: ED_gpencil.h:78
@ GP_REPROJECT_SIDE
Definition: ED_gpencil.h:71
@ GP_REPROJECT_TOP
Definition: ED_gpencil.h:72
@ GP_REPROJECT_FRONT
Definition: ED_gpencil.h:70
struct Object * ED_object_add_type(struct bContext *C, const int type, const char *name, const float loc[3], const float rot[3], const bool enter_editmode, const unsigned short local_view_bits) ATTR_NONNULL(1) ATTR_RETURNS_NONNULL
Definition: object_add.c:659
@ SEL_SELECT
@ SEL_INVERT
@ SEL_DESELECT
@ SEL_TOGGLE
bool ED_transform_snap_object_project_ray(SnapObjectContext *sctx, struct Depsgraph *depsgraph, 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])
eV3DProjStatus ED_view3d_project_int_global(const struct ARegion *region, const float co[3], int r_co[2], const eV3DProjTest flag)
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, const bool no_shift)
@ V3D_PROJ_TEST_NOP
Definition: ED_view3d.h:193
@ V3D_PROJ_RET_OK
Definition: ED_view3d.h:176
void ED_view3d_win_to_delta(const struct ARegion *region, const float mval[2], float out[3], const float zfac)
@ V3D_DEPTH_NO_GPENCIL
Definition: ED_view3d.h:148
void ED_view3d_global_to_vector(const struct RegionView3D *rv3d, const float coord[3], float vec[3])
void ED_view3d_depth_override(struct Depsgraph *depsgraph, struct ARegion *region, struct View3D *v3d, struct Object *obact, eV3DDepthOverrideMode mode, bool update_cache)
Definition: view3d_draw.c:2331
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])
eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *region, const float co[3], float r_co[2], const eV3DProjTest flag)
float ED_view3d_calc_zfac(const struct RegionView3D *rv3d, const float co[3], bool *r_flip)
bool ED_view3d_win_to_ray_clipped(struct Depsgraph *depsgraph, const struct ARegion *region, const struct View3D *v3d, const float mval[2], float ray_start[3], float ray_normal[3], const bool do_clip)
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:36
@ GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR
Definition: GPU_shader.h:365
@ GPU_SHADER_2D_UNIFORM_COLOR
Definition: GPU_shader.h:171
@ GPU_BLEND_NONE
Definition: GPU_state.h:55
@ GPU_BLEND_ALPHA
Definition: GPU_state.h:57
void GPU_blend(eGPUBlend blend)
Definition: gpu_state.cc:55
void GPU_line_smooth(bool enable)
Definition: gpu_state.cc:85
void GPU_viewport_size_get_f(float coords[4])
Definition: gpu_state.cc:279
@ 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 RGB to Bright Vector Camera CLAMP
Platform independent time functions.
StructRNA RNA_SpaceImageEditor
StructRNA RNA_SpaceSequenceEditor
StructRNA RNA_Object
StructRNA RNA_MovieTrackingTrack
#define C
Definition: RandGen.cpp:39
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:40
#define NA_EDITED
Definition: WM_types.h:462
#define NC_GPENCIL
Definition: WM_types.h:300
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
#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)
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 ED_gpencil_projected_2d_bound_box(GP_SpaceConversion *gsc, bGPDstroke *gps, const float diff_mat[4][4], float r_min[2], float r_max[2])
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)
bool ED_gpencil_stroke_check_collision(GP_SpaceConversion *gsc, bGPDstroke *gps, const float mouse[2], const int radius, const float diff_mat[4][4])
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])
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)
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_point_is_inside(bGPDstroke *gps, GP_SpaceConversion *gsc, int mouse[2], const float diff_mat[4][4])
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 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)
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)
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)
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)
bGPDstroke * ED_gpencil_stroke_nearest_to_ends(bContext *C, GP_SpaceConversion *gsc, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps, const float radius, int *r_index)
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
format
Definition: logImageCore.h:47
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:42
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static ulong * next
static void clear(Message *msg)
Definition: msgfmt.c:294
static void area(int d1, int d2, int e1, int e2, float weights[2])
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:146
void RNA_id_pointer_create(ID *id, PointerRNA *r_ptr)
Definition: rna_access.c:122
void RNA_enum_item_end(EnumPropertyItem **items, int *totitem)
Definition: rna_define.c:4470
void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
Definition: rna_define.c:4416
void RNA_enum_item_add_separator(EnumPropertyItem **items, int *totitem)
Definition: rna_define.c:4442
const EnumPropertyItem DummyRNA_DEFAULT_items[]
Definition: rna_rna.c:45
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:446
struct CurveMapping * cur_falloff
struct ARegion * region
struct View2D * v2d
struct Object * ob
struct Scene * scene
struct ScrArea * area
Definition: DNA_ID.h:273
char name[66]
Definition: DNA_ID.h:283
void * last
Definition: DNA_listBase.h:47
void * first
Definition: DNA_listBase.h:47
struct MDeformWeight * dw
Definition: BKE_main.h:116
ListBase objects
Definition: BKE_main.h:148
struct PreviewImage * preview
struct MaterialGPencilStyle * gp_style
struct MovieTracking tracking
struct bGPdata * gpd
struct bGPdata * gpd
ListBase defbase
unsigned short actdef
float obmat[4][4]
void * data
struct Brush * brush
struct StructRNA * type
Definition: RNA_types.h:51
int icon_id
Definition: DNA_ID.h:400
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
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
int select_last_index
ListBase layers
bGPdata_Runtime runtime
struct bGPdata * gpd
float pose_mat[4][4]
float xmin
Definition: DNA_vec_types.h:85
float ymin
Definition: DNA_vec_types.h:86
int ymin
Definition: DNA_vec_types.h:80
int xmin
Definition: DNA_vec_types.h:79
float x
Definition: ED_gpencil.h:97
float y
Definition: ED_gpencil.h:97
float pressure
Definition: ED_gpencil.h:99
float uv_rot
Definition: ED_gpencil.h:107
float strength
Definition: ED_gpencil.h:101
float vert_color[4]
Definition: ED_gpencil.h:113
float uv_fac
Definition: ED_gpencil.h:105
double PIL_check_seconds_timer(void)
Definition: time.c:80
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: util_avxb.h:167
ccl_device_inline float3 ceil(const float3 &a)
uint len
void WM_main_add_notifier(unsigned int type, void *reference)
PointerRNA * ptr
Definition: wm_files.c:3157
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)