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