Blender  V3.3
gpencil_merge.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2019 Blender Foundation. */
3 
9 #include <stdio.h>
10 
11 #include "MEM_guardedalloc.h"
12 
13 #include "BLI_blenlib.h"
14 #include "BLI_ghash.h"
15 #include "BLI_math.h"
16 
17 #include "DNA_gpencil_types.h"
18 #include "DNA_material_types.h"
19 
20 #include "BKE_brush.h"
21 #include "BKE_context.h"
22 #include "BKE_gpencil.h"
23 #include "BKE_gpencil_geom.h"
24 #include "BKE_main.h"
25 #include "BKE_material.h"
26 #include "BKE_report.h"
27 
28 #include "WM_api.h"
29 #include "WM_types.h"
30 
31 #include "RNA_access.h"
32 #include "RNA_define.h"
33 
34 #include "ED_gpencil.h"
35 #include "ED_screen.h"
36 
37 #include "DEG_depsgraph.h"
38 
39 #include "gpencil_intern.h"
40 
41 typedef struct tGPencilPointCache {
42  float factor; /* value to sort */
44  float x, y, z;
45  float pressure;
46  float strength;
47  float vert_color[4];
49 
50 /* helper function to sort points */
51 static int gpencil_sort_points(const void *a1, const void *a2)
52 {
53  const tGPencilPointCache *ps1 = a1, *ps2 = a2;
54 
55  if (ps1->factor < ps2->factor) {
56  return -1;
57  }
58 
59  if (ps1->factor > ps2->factor) {
60  return 1;
61  }
62 
63  return 0;
64 }
65 
67  tGPencilPointCache *points_array,
68  int totpoints)
69 {
70  tGPencilPointCache *point_elem = NULL;
71 
72  for (int i = 0; i < totpoints; i++) {
73  point_elem = &points_array[i];
74  bGPDspoint *pt_dst = &gps->points[i];
75 
76  copy_v3_v3(&pt_dst->x, &point_elem->x);
77  pt_dst->pressure = point_elem->pressure;
78  pt_dst->strength = point_elem->strength;
79  pt_dst->uv_fac = 1.0f;
80  pt_dst->uv_rot = 0;
81  pt_dst->flag |= GP_SPOINT_SELECT;
82  copy_v4_v4(pt_dst->vert_color, point_elem->vert_color);
83  }
84 }
85 
86 static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpoints)
87 {
88  Main *bmain = CTX_data_main(C);
91  bGPdata *gpd = ob->data;
93 
95 
96  const bool back = RNA_boolean_get(op->ptr, "back");
97  const bool additive = RNA_boolean_get(op->ptr, "additive");
98  const bool cyclic = RNA_boolean_get(op->ptr, "cyclic");
99 
100  Paint *paint = &ts->gp_paint->paint;
101  /* if not exist, create a new one */
102  if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
103  /* create new brushes */
104  BKE_brush_gpencil_paint_presets(bmain, ts, false);
105  }
106  Brush *brush = paint->brush;
107 
108  /* frame */
109  short add_frame_mode;
110  if (additive) {
111  add_frame_mode = GP_GETFRAME_ADD_COPY;
112  }
113  else {
114  add_frame_mode = GP_GETFRAME_ADD_NEW;
115  }
116  bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, add_frame_mode);
117 
118  /* stroke */
119  bGPDstroke *gps = BKE_gpencil_stroke_new(MAX2(ob->actcol - 1, 0), totpoints, brush->size);
120  gps->flag |= GP_STROKE_SELECT;
122 
123  if (cyclic) {
124  gps->flag |= GP_STROKE_CYCLIC;
125  }
126 
127  /* add new stroke to frame */
128  if (back) {
129  BLI_addhead(&gpf->strokes, gps);
130  }
131  else {
132  BLI_addtail(&gpf->strokes, gps);
133  }
134 
135  return gps;
136 }
137 
138 static void gpencil_get_elements_len(bContext *C, int *totstrokes, int *totpoints)
139 {
140  bGPDspoint *pt;
141  int i;
142 
143  /* count number of strokes and selected points */
144  CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
145  if (gps->flag & GP_STROKE_SELECT) {
146  *totstrokes += 1;
147  for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
148  if (pt->flag & GP_SPOINT_SELECT) {
149  *totpoints += 1;
150  }
151  }
152  }
153  }
154  CTX_DATA_END;
155 }
156 
158 {
160  bGPdata *gpd = ob->data;
161 
162  CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
163  bGPDframe *gpf = gpl->actframe;
164  if (gpf == NULL) {
165  continue;
166  }
167 
170  gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, false, 0);
171  }
172  }
173  CTX_DATA_END;
174 }
175 
176 /* Calc a factor of each selected point and fill an array with all the data.
177  *
178  * The factor is calculated using an imaginary circle, using the angle relative
179  * to this circle and the distance to the calculated center of the selected points.
180  *
181  * All the data is saved to be sorted and used later.
182  */
184  const int mode,
185  int totpoints,
186  const bool clear_point,
187  const bool clear_stroke,
188  tGPencilPointCache *src_array)
189 {
190  bGPDspoint *pt;
191  int idx = 0;
192 
193  /* create selected point array an fill it */
194  bGPDstroke **gps_array = MEM_callocN(sizeof(bGPDstroke *) * totpoints, __func__);
195  bGPDspoint *pt_array = MEM_callocN(sizeof(bGPDspoint) * totpoints, __func__);
196 
197  CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
198  bGPDframe *gpf = gpl->actframe;
199  if (gpf == NULL) {
200  continue;
201  }
202  LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
203  if (gps->flag & GP_STROKE_SELECT) {
204  int i;
205  for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
206  if (clear_stroke) {
207  pt->flag |= GP_SPOINT_TAG;
208  }
209  else {
210  pt->flag &= ~GP_SPOINT_TAG;
211  }
212 
213  if (pt->flag & GP_SPOINT_SELECT) {
214  bGPDspoint *pt2 = &pt_array[idx];
215  copy_v3_v3(&pt2->x, &pt->x);
216  pt2->pressure = pt->pressure;
217  pt2->strength = pt->strength;
218  copy_v4_v4(pt2->vert_color, pt->vert_color);
219  pt->flag &= ~GP_SPOINT_SELECT;
220  if (clear_point) {
221  pt->flag |= GP_SPOINT_TAG;
222  }
223 
224  /* save stroke */
225  gps_array[idx] = gps;
226 
227  idx++;
228  }
229  }
230  gps->flag &= ~GP_STROKE_SELECT;
232  }
233  }
234  }
235  CTX_DATA_END;
236 
237  /* project in 2d plane */
238  int direction = 0;
239  float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * totpoints, "GP Stroke temp 2d points");
240  BKE_gpencil_stroke_2d_flat(pt_array, totpoints, points2d, &direction);
241 
242  /* calc center */
243  float center[2] = {0.0f, 0.0f};
244  for (int i = 0; i < totpoints; i++) {
245  center[0] += points2d[i][0];
246  center[1] += points2d[i][1];
247  }
248  mul_v2_fl(center, 1.0f / totpoints);
249 
250  /* calc angle and distance to center for each point */
251  const float axis[2] = {1.0f, 0.0f};
252  float v1[3];
253  for (int i = 0; i < totpoints; i++) {
254  float ln = len_v2v2(center, points2d[i]);
255  sub_v2_v2v2(v1, points2d[i], center);
256  float angle = angle_signed_v2v2(axis, v1);
257  if (angle < 0.0f) {
258  angle = fabsf(angle);
259  }
260  else {
261  angle = (M_PI * 2.0) - angle;
262  }
263  tGPencilPointCache *sort_pt = &src_array[i];
264  bGPDspoint *pt2 = &pt_array[i];
265 
266  copy_v3_v3(&sort_pt->x, &pt2->x);
267  sort_pt->pressure = pt2->pressure;
268  sort_pt->strength = pt2->strength;
269  copy_v4_v4(sort_pt->vert_color, pt2->vert_color);
270 
271  sort_pt->gps = gps_array[i];
272 
273  if (mode == GP_MERGE_STROKE) {
274  sort_pt->factor = angle;
275  }
276  else {
277  sort_pt->factor = (angle * 100000.0f) + ln;
278  }
279  }
280  MEM_SAFE_FREE(points2d);
281  MEM_SAFE_FREE(gps_array);
282  MEM_SAFE_FREE(pt_array);
283 }
284 
285 /* insert a group of points in destination array */
287  tGPencilPointCache *dst_array,
288  int totpoints,
289  bGPDstroke *gps_filter,
290  bool reverse,
291  int last)
292 {
293  tGPencilPointCache *src_elem = NULL;
294  tGPencilPointCache *dst_elem = NULL;
295  int idx = 0;
296 
297  for (int i = 0; i < totpoints; i++) {
298  if (!reverse) {
299  idx = i;
300  }
301  else {
302  idx = totpoints - i - 1;
303  }
304  src_elem = &src_array[idx];
305  /* check if all points or only a stroke */
306  if (!ELEM(gps_filter, NULL, src_elem->gps)) {
307  continue;
308  }
309 
310  dst_elem = &dst_array[last];
311  last++;
312 
313  copy_v3_v3(&dst_elem->x, &src_elem->x);
314  dst_elem->gps = src_elem->gps;
315  dst_elem->pressure = src_elem->pressure;
316  dst_elem->strength = src_elem->strength;
317  dst_elem->factor = src_elem->factor;
318  copy_v4_v4(dst_elem->vert_color, src_elem->vert_color);
319  }
320 
321  return last;
322 }
323 
324 /* get first and last point location */
326  tGPencilPointCache *src_array, int totpoints, bGPDstroke *gps_filter, float *start, float *end)
327 {
328  tGPencilPointCache *array_pt = NULL;
329 
330  /* find first point */
331  for (int i = 0; i < totpoints; i++) {
332  array_pt = &src_array[i];
333  if (gps_filter == array_pt->gps) {
334  copy_v3_v3(start, &array_pt->x);
335  break;
336  }
337  }
338  /* find last point */
339  for (int i = totpoints - 1; i >= 0; i--) {
340  array_pt = &src_array[i];
341  if (gps_filter == array_pt->gps) {
342  copy_v3_v3(end, &array_pt->x);
343  break;
344  }
345  }
346 }
347 
349  int totstrokes,
350  int totpoints,
351  tGPencilPointCache *dst_array)
352 {
353  int i;
354  int last = 0;
355  GHash *all_strokes = BLI_ghash_ptr_new(__func__);
356  /* add first stroke to array */
357  tGPencilPointCache *sort_pt = &src_array[0];
358  bGPDstroke *gps = sort_pt->gps;
359  last = gpencil_insert_to_array(src_array, dst_array, totpoints, gps, false, last);
360  float start[3];
361  float end[3];
362  float end_prv[3];
363  gpencil_get_extremes(src_array, totpoints, gps, start, end);
364  copy_v3_v3(end_prv, end);
365  BLI_ghash_insert(all_strokes, sort_pt->gps, sort_pt->gps);
366 
367  /* look for near stroke */
368  bool loop = (bool)(totstrokes > 1);
369  while (loop) {
370  bGPDstroke *gps_next = NULL;
371  GHash *strokes = BLI_ghash_ptr_new(__func__);
372  float dist_start = 0.0f;
373  float dist_end = 0.0f;
374  float dist = FLT_MAX;
375  bool reverse = false;
376 
377  for (i = 0; i < totpoints; i++) {
378  sort_pt = &src_array[i];
379  /* avoid dups */
380  if (BLI_ghash_haskey(all_strokes, sort_pt->gps)) {
381  continue;
382  }
383  if (!BLI_ghash_haskey(strokes, sort_pt->gps)) {
384  gpencil_get_extremes(src_array, totpoints, sort_pt->gps, start, end);
385  /* distances to previous end */
386  dist_start = len_v3v3(end_prv, start);
387  dist_end = len_v3v3(end_prv, end);
388 
389  if (dist > dist_start) {
390  gps_next = sort_pt->gps;
391  dist = dist_start;
392  reverse = false;
393  }
394  if (dist > dist_end) {
395  gps_next = sort_pt->gps;
396  dist = dist_end;
397  reverse = true;
398  }
399  BLI_ghash_insert(strokes, sort_pt->gps, sort_pt->gps);
400  }
401  }
402  BLI_ghash_free(strokes, NULL, NULL);
403 
404  /* add the stroke to array */
405  if (gps_next != NULL) {
406  BLI_ghash_insert(all_strokes, gps_next, gps_next);
407  last = gpencil_insert_to_array(src_array, dst_array, totpoints, gps_next, reverse, last);
408  /* replace last end */
409  sort_pt = &dst_array[last - 1];
410  copy_v3_v3(end_prv, &sort_pt->x);
411  }
412 
413  /* loop exit */
414  if (last >= totpoints) {
415  loop = false;
416  }
417  }
418 
419  BLI_ghash_free(all_strokes, NULL, NULL);
420  return last;
421 }
422 
424 {
425  /* only supported with grease pencil objects */
427  if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
428  return false;
429  }
430 
431  /* check material */
432  Material *ma = NULL;
433  ma = BKE_gpencil_material(ob, ob->actcol);
434  if ((ma == NULL) || (ma->gp_style == NULL)) {
435  return false;
436  }
437 
438  /* check hidden or locked materials */
439  MaterialGPencilStyle *gp_style = ma->gp_style;
440  if ((gp_style->flag & GP_MATERIAL_HIDE) || (gp_style->flag & GP_MATERIAL_LOCKED)) {
441  return false;
442  }
443 
444  /* check layer */
446  if ((gpl == NULL) || (gpl->flag & GP_LAYER_LOCKED) || (gpl->flag & GP_LAYER_HIDE)) {
447  return false;
448  }
449 
450  /* NOTE: this is a bit slower, but is the most accurate... */
451  return (CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0) && ED_operator_view3d_active(C);
452 }
453 
455 {
456  const int mode = RNA_enum_get(op->ptr, "mode");
457  const bool clear_point = RNA_boolean_get(op->ptr, "clear_point");
458  const bool clear_stroke = RNA_boolean_get(op->ptr, "clear_stroke");
459 
461  /* sanity checks */
462  if (!ob || ob->type != OB_GPENCIL) {
463  return OPERATOR_CANCELLED;
464  }
465 
466  bGPdata *gpd = (bGPdata *)ob->data;
468  if (gpl == NULL) {
469  return OPERATOR_CANCELLED;
470  }
471 
472  int totstrokes = 0;
473  int totpoints = 0;
474 
475  /* count number of strokes and selected points */
476  gpencil_get_elements_len(C, &totstrokes, &totpoints);
477 
478  if (totpoints == 0) {
479  return OPERATOR_CANCELLED;
480  }
481 
482  /* calc factor of each point and fill an array with all data */
483  tGPencilPointCache *sorted_array = NULL;
484  tGPencilPointCache *original_array = MEM_callocN(sizeof(tGPencilPointCache) * totpoints,
485  __func__);
486  gpencil_calc_points_factor(C, mode, totpoints, clear_point, clear_stroke, original_array);
487 
488  /* for strokes analyze strokes and load sorted array */
489  if (mode == GP_MERGE_STROKE) {
490  sorted_array = MEM_callocN(sizeof(tGPencilPointCache) * totpoints, __func__);
491  totpoints = gpencil_analyze_strokes(original_array, totstrokes, totpoints, sorted_array);
492  }
493  else {
494  /* make a copy to sort */
495  sorted_array = MEM_dupallocN(original_array);
496  /* sort by factor around center */
497  qsort(sorted_array, totpoints, sizeof(tGPencilPointCache), gpencil_sort_points);
498  }
499 
500  /* prepare the new stroke */
501  bGPDstroke *gps = gpencil_prepare_stroke(C, op, totpoints);
502 
503  /* copy original points to final stroke */
504  gpencil_insert_points_to_stroke(gps, sorted_array, totpoints);
505 
506  /* dissolve all tagged points */
507  if ((clear_point) || (clear_stroke)) {
509  }
510 
512 
513  /* free memory */
514  MEM_SAFE_FREE(original_array);
515  MEM_SAFE_FREE(sorted_array);
516 
517  /* notifiers */
520 
521  return OPERATOR_FINISHED;
522 }
523 
525 {
526  static const EnumPropertyItem mode_type[] = {
527  {GP_MERGE_STROKE, "STROKE", 0, "Stroke", ""},
528  {GP_MERGE_POINT, "POINT", 0, "Point", ""},
529  {0, NULL, 0, NULL, NULL},
530  };
531 
532  /* identifiers */
533  ot->name = "Merge Strokes";
534  ot->idname = "GPENCIL_OT_stroke_merge";
535  ot->description = "Create a new stroke with the selected stroke points";
536 
537  /* api callbacks */
540 
541  /* flags */
543 
544  /* properties */
545  ot->prop = RNA_def_enum(ot->srna, "mode", mode_type, GP_MERGE_STROKE, "Mode", "");
547  ot->srna, "back", 0, "Draw on Back", "Draw new stroke below all previous strokes");
548  RNA_def_boolean(ot->srna, "additive", 0, "Additive Drawing", "Add to previous drawing");
549  RNA_def_boolean(ot->srna, "cyclic", 0, "Cyclic", "Close new stroke");
550  RNA_def_boolean(ot->srna, "clear_point", 0, "Dissolve Points", "Dissolve old selected points");
551  RNA_def_boolean(ot->srna, "clear_stroke", 0, "Delete Strokes", "Delete old selected strokes");
552 }
553 
554 /* Merge similar materials. */
556 {
557  /* only supported with grease pencil objects */
559  if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
560  return false;
561  }
562 
563  return true;
564 }
565 
567 {
569  bGPdata *gpd = (bGPdata *)ob->data;
570  const float hue_threshold = RNA_float_get(op->ptr, "hue_threshold");
571  const float sat_threshold = RNA_float_get(op->ptr, "sat_threshold");
572  const float val_threshold = RNA_float_get(op->ptr, "val_threshold");
573 
574  /* Review materials. */
575  short *totcol = BKE_object_material_len_p(ob);
576  if (totcol == 0) {
577  return OPERATOR_CANCELLED;
578  }
579 
580  int removed;
581  bool changed = BKE_gpencil_merge_materials(
582  ob, hue_threshold, sat_threshold, val_threshold, &removed);
583 
584  /* notifiers */
585  if (changed) {
586  BKE_reportf(op->reports, RPT_INFO, "Merged %d materials of %d", removed, *totcol);
589  }
590  else {
591  BKE_report(op->reports, RPT_INFO, "Nothing to merge");
592  }
593  return OPERATOR_FINISHED;
594 }
595 
597 {
598  PropertyRNA *prop;
599 
600  /* identifiers */
601  ot->name = "Merge Grease Pencil Materials";
602  ot->idname = "GPENCIL_OT_stroke_merge_material";
603  ot->description = "Replace materials in strokes merging similar";
604 
605  /* api callbacks */
608 
609  /* flags */
611 
612  /* properties */
613  prop = RNA_def_float(
614  ot->srna, "hue_threshold", 0.001f, 0.0f, 1.0f, "Hue Threshold", "", 0.0f, 1.0f);
615  prop = RNA_def_float(
616  ot->srna, "sat_threshold", 0.001f, 0.0f, 1.0f, "Saturation Threshold", "", 0.0f, 1.0f);
617  prop = RNA_def_float(
618  ot->srna, "val_threshold", 0.001f, 0.0f, 1.0f, "Value Threshold", "", 0.0f, 1.0f);
619  /* avoid re-using last var */
621 }
typedef float(TangentPoint)[2]
void BKE_brush_gpencil_paint_presets(struct Main *bmain, struct ToolSettings *ts, bool reset)
Definition: brush.cc:1308
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
#define CTX_DATA_BEGIN(C, Type, instance, member)
Definition: BKE_context.h:269
struct bGPDlayer * CTX_data_active_gpencil_layer(const bContext *C)
Definition: context.c:1450
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1353
#define CTX_DATA_COUNT(C, member)
Definition: BKE_context.h:290
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
struct ToolSettings * CTX_data_tool_settings(const bContext *C)
Definition: context.c:1282
#define CTX_DATA_END
Definition: BKE_context.h:278
void BKE_gpencil_stroke_select_index_set(struct bGPdata *gpd, struct bGPDstroke *gps)
Definition: gpencil.c:1155
void BKE_gpencil_stroke_select_index_reset(struct bGPDstroke *gps)
Definition: gpencil.c:1161
struct bGPDstroke * BKE_gpencil_stroke_new(int mat_idx, int totpoints, short thickness)
Definition: gpencil.c:756
bool BKE_gpencil_merge_materials(struct Object *ob, float hue_threshold, float sat_threshold, float val_threshold, int *r_removed)
Definition: gpencil.c:2122
struct bGPDframe * BKE_gpencil_layer_frame_get(struct bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew)
Definition: gpencil.c:1232
@ GP_GETFRAME_ADD_NEW
Definition: BKE_gpencil.h:341
@ GP_GETFRAME_ADD_COPY
Definition: BKE_gpencil.h:343
void BKE_gpencil_stroke_2d_flat(const struct bGPDspoint *points, int totpoints, float(*points2d)[2], int *r_direction)
void BKE_gpencil_stroke_geometry_update(struct bGPdata *gpd, struct bGPDstroke *gps)
struct bGPDstroke * BKE_gpencil_stroke_delete_tagged_points(struct bGPdata *gpd, struct bGPDframe *gpf, struct bGPDstroke *gps, struct bGPDstroke *next_stroke, int tag_flags, bool select, bool flat_cap, int limit)
General operations, lookup, etc. for materials.
struct Material * BKE_gpencil_material(struct Object *ob, short act)
Definition: material.c:795
short * BKE_object_material_len_p(struct Object *ob)
Definition: material.c:344
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
bool BLI_ghash_haskey(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:822
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:710
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:863
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:60
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:354
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
#define M_PI
Definition: BLI_math_base.h:20
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
float angle_signed_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:439
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE float len_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
#define MAX2(a, b)
#define ELEM(...)
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_TRANSFORM
Definition: DNA_ID.h:771
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
@ GP_STROKE_SELECT
@ GP_STROKE_CYCLIC
@ GP_LAYER_LOCKED
@ GP_LAYER_HIDE
@ GP_SPOINT_TAG
@ GP_SPOINT_SELECT
@ GP_MATERIAL_LOCKED
@ GP_MATERIAL_HIDE
@ OB_GPENCIL
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
bool ED_operator_view3d_active(struct bContext *C)
Definition: screen_ops.c:225
NSNotificationCenter * center
_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
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
static void clear_stroke(bGPDframe *gpf, bGPDstroke *gps)
@ PROP_SKIP_SAVE
Definition: RNA_types.h:218
#define C
Definition: RandGen.cpp:25
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
#define ND_DATA
Definition: WM_types.h:456
#define NA_EDITED
Definition: WM_types.h:523
#define NC_GPENCIL
Definition: WM_types.h:349
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
Scene scene
@ GP_MERGE_POINT
@ GP_MERGE_STROKE
void GPENCIL_OT_stroke_merge(wmOperatorType *ot)
static void gpencil_get_elements_len(bContext *C, int *totstrokes, int *totpoints)
static int gpencil_analyze_strokes(tGPencilPointCache *src_array, int totstrokes, int totpoints, tGPencilPointCache *dst_array)
static int gpencil_stroke_merge_material_exec(bContext *C, wmOperator *op)
static int gpencil_sort_points(const void *a1, const void *a2)
Definition: gpencil_merge.c:51
void GPENCIL_OT_stroke_merge_material(wmOperatorType *ot)
static int gpencil_stroke_merge_exec(bContext *C, wmOperator *op)
static void gpencil_insert_points_to_stroke(bGPDstroke *gps, tGPencilPointCache *points_array, int totpoints)
Definition: gpencil_merge.c:66
static bool gpencil_strokes_merge_poll(bContext *C)
static void gpencil_dissolve_points(bContext *C)
static bGPDstroke * gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpoints)
Definition: gpencil_merge.c:86
static void gpencil_get_extremes(tGPencilPointCache *src_array, int totpoints, bGPDstroke *gps_filter, float *start, float *end)
static bool gpencil_stroke_merge_material_poll(bContext *C)
static void gpencil_calc_points_factor(bContext *C, const int mode, int totpoints, const bool clear_point, const bool clear_stroke, tGPencilPointCache *src_array)
static int gpencil_insert_to_array(tGPencilPointCache *src_array, tGPencilPointCache *dst_array, int totpoints, bGPDstroke *gps_filter, bool reverse, int last)
struct tGPencilPointCache tGPencilPointCache
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:28
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
#define fabsf(x)
Definition: metal/compat.h:219
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4957
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3836
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3493
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1490
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3783
struct BrushGpencilSettings * gpencil_settings
Definition: BKE_main.h:121
struct MaterialGPencilStyle * gp_style
void * data
struct Brush * brush
struct RenderData r
GpPaint * gp_paint
struct bGPDframe * next
ListBase strokes
float vert_color[4]
bGPDspoint * points
bGPDstroke * gps
Definition: gpencil_merge.c:43
const char * name
Definition: WM_types.h:888
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
PropertyRNA * prop
Definition: WM_types.h:981
struct ReportList * reports
struct PointerRNA * ptr
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition: wm_files.c:3479