Blender  V3.3
gpencil_curve.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2008 Blender Foundation. */
3 
8 #include <math.h>
9 #include <stddef.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 
14 #include "CLG_log.h"
15 
16 #include "MEM_guardedalloc.h"
17 
18 #include "BLI_blenlib.h"
19 #include "BLI_math_vector.h"
20 
21 #include "BLT_translation.h"
22 
23 #include "DNA_collection_types.h"
24 #include "DNA_gpencil_types.h"
25 #include "DNA_material_types.h"
26 #include "DNA_meshdata_types.h"
27 #include "DNA_scene_types.h"
28 
29 #include "BKE_collection.h"
30 #include "BKE_context.h"
31 #include "BKE_curve.h"
32 #include "BKE_gpencil.h"
33 #include "BKE_gpencil_curve.h"
34 #include "BKE_gpencil_geom.h"
35 #include "BKE_main.h"
36 #include "BKE_material.h"
37 #include "BKE_object.h"
38 
39 #include "curve_fit_nd.h"
40 
41 #include "DEG_depsgraph_query.h"
42 
43 #define COORD_FITTING_INFLUENCE 20.0f
44 
45 /* -------------------------------------------------------------------- */
49 /* Helper: Check materials with same color. */
51  const float color_stroke[4],
52  const float color_fill[4],
53  const bool do_stroke,
54  const bool do_fill,
55  Material **r_mat)
56 {
57  int index = -1;
58  Material *ma = NULL;
59  *r_mat = NULL;
60  float color_cu[4];
61  float hsv_stroke[4], hsv_fill[4];
62 
63  copy_v4_v4(color_cu, color_stroke);
64  zero_v3(hsv_stroke);
65  rgb_to_hsv_v(color_cu, hsv_stroke);
66  hsv_stroke[3] = color_stroke[3];
67 
68  copy_v4_v4(color_cu, color_fill);
69  zero_v3(hsv_fill);
70  rgb_to_hsv_v(color_cu, hsv_fill);
71  hsv_fill[3] = color_fill[3];
72 
73  bool match_stroke = false;
74  bool match_fill = false;
75 
76  for (int i = 1; i <= ob_gp->totcol; i++) {
77  ma = BKE_object_material_get(ob_gp, i);
78  MaterialGPencilStyle *gp_style = ma->gp_style;
79  const bool fill = (gp_style->fill_style == GP_MATERIAL_FILL_STYLE_SOLID);
80  const bool stroke = (gp_style->fill_style == GP_MATERIAL_STROKE_STYLE_SOLID);
81 
82  if (do_fill && !fill) {
83  continue;
84  }
85 
86  if (do_stroke && !stroke) {
87  continue;
88  }
89 
90  /* Check color with small tolerance (better result in HSV). */
91  float hsv2[4];
92  if (do_fill) {
93  zero_v3(hsv2);
94  rgb_to_hsv_v(gp_style->fill_rgba, hsv2);
95  hsv2[3] = gp_style->fill_rgba[3];
96  if (compare_v4v4(hsv_fill, hsv2, 0.01f)) {
97  *r_mat = ma;
98  index = i - 1;
99  match_fill = true;
100  }
101  }
102  else {
103  match_fill = true;
104  }
105 
106  if (do_stroke) {
107  zero_v3(hsv2);
108  rgb_to_hsv_v(gp_style->stroke_rgba, hsv2);
109  hsv2[3] = gp_style->stroke_rgba[3];
110  if (compare_v4v4(hsv_stroke, hsv2, 0.01f)) {
111  *r_mat = ma;
112  index = i - 1;
113  match_stroke = true;
114  }
115  }
116  else {
117  match_stroke = true;
118  }
119 
120  /* If match, don't look for more. */
121  if (match_stroke || match_fill) {
122  break;
123  }
124  }
125 
126  if (!match_stroke || !match_fill) {
127  *r_mat = NULL;
128  index = -1;
129  }
130 
131  return index;
132 }
133 
134 /* Helper: Add gpencil material using curve material as base. */
136  Object *ob_gp,
137  const float stroke_color[4],
138  const float fill_color[4],
139  const bool stroke,
140  const bool fill,
141  int *r_idx)
142 {
143  Material *mat_gp = BKE_gpencil_object_material_new(bmain, ob_gp, "Material", r_idx);
144  MaterialGPencilStyle *gp_style = mat_gp->gp_style;
145 
146  /* Stroke color. */
147  if (stroke) {
148  copy_v4_v4(mat_gp->gp_style->stroke_rgba, stroke_color);
149  gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
150  }
151 
152  /* Fill color. */
153  if (fill) {
154  copy_v4_v4(mat_gp->gp_style->fill_rgba, fill_color);
155  gp_style->flag |= GP_MATERIAL_FILL_SHOW;
156  }
157 
158  /* Check at least one is enabled. */
159  if (((gp_style->flag & GP_MATERIAL_STROKE_SHOW) == 0) &&
160  ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0)) {
161  gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
162  }
163 
164  return mat_gp;
165 }
166 
167 /* Helper: Create new stroke section. */
169  const float *coord_array,
170  const float pressure_start,
171  const float pressure_end,
172  const int init,
173  const int totpoints,
174  const float init_co[3],
175  const bool last)
176 {
177  BLI_assert(totpoints > 0);
178 
179  const float step = 1.0f / ((float)totpoints - 1.0f);
180  float factor = 0.0f;
181  for (int i = 0; i < totpoints; i++) {
182  bGPDspoint *pt = &gps->points[i + init];
183  copy_v3_v3(&pt->x, &coord_array[3 * i]);
184  /* Be sure the last point is not on top of the first point of the curve or
185  * the close of the stroke will produce glitches. */
186  if ((last) && (i > 0) && (i == totpoints - 1)) {
187  float dist = len_v3v3(init_co, &pt->x);
188  if (dist < 0.1f) {
189  /* Interpolate between previous point and current to back slightly. */
190  bGPDspoint *pt_prev = &gps->points[i + init - 1];
191  interp_v3_v3v3(&pt->x, &pt_prev->x, &pt->x, 0.95f);
192  }
193  }
194 
195  pt->strength = 1.0f;
196  pt->pressure = interpf(pressure_end, pressure_start, factor);
197  factor += step;
198  }
199 }
200 
201 /* Helper: Get the first collection that includes the object. */
203 {
204  Collection *mycol = NULL;
205  FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
206  LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
207  if ((mycol == NULL) && (cob->ob == ob)) {
208  mycol = collection;
209  }
210  }
211  }
213 
214  return mycol;
215 }
217  Main *bmain, Object *ob_gp, Object *ob_cu, bool *do_stroke, bool *do_fill)
218 {
219  Curve *cu = (Curve *)ob_cu->data;
220 
221  Material *mat_gp = NULL;
222  Material *mat_curve_stroke = NULL;
223  Material *mat_curve_fill = NULL;
224 
225  float color_stroke[4] = {0.0f, 0.0f, 0.0f, 0.0f};
226  float color_fill[4] = {0.0f, 0.0f, 0.0f, 0.0f};
227 
228  /* If the curve has 2 materials, the first is considered as Fill and the second as Stroke.
229  * If the has only one material, if the name contains "_stroke",
230  * it's used as a stroke, otherwise as fill. */
231  if (ob_cu->totcol >= 2) {
232  *do_stroke = true;
233  *do_fill = true;
234  mat_curve_fill = BKE_object_material_get(ob_cu, 1);
235  mat_curve_stroke = BKE_object_material_get(ob_cu, 2);
236  }
237  else if (ob_cu->totcol == 1) {
238  mat_curve_stroke = BKE_object_material_get(ob_cu, 1);
239  if ((mat_curve_stroke) && (strstr(mat_curve_stroke->id.name, "_stroke") != NULL)) {
240  *do_stroke = true;
241  *do_fill = false;
242  mat_curve_fill = NULL;
243  }
244  else {
245  *do_stroke = false;
246  *do_fill = true;
247  /* Invert materials. */
248  mat_curve_fill = mat_curve_stroke;
249  mat_curve_stroke = NULL;
250  }
251  }
252  else {
253  /* No materials in the curve. */
254  *do_fill = false;
255  return -1;
256  }
257 
258  if (mat_curve_stroke) {
259  copy_v4_v4(color_stroke, &mat_curve_stroke->r);
260  }
261  if (mat_curve_fill) {
262  copy_v4_v4(color_fill, &mat_curve_fill->r);
263  }
264 
266  ob_gp, color_stroke, color_fill, *do_stroke, *do_fill, &mat_gp);
267 
268  if ((ob_gp->totcol < r_idx) || (r_idx < 0)) {
270  bmain, ob_gp, color_stroke, color_fill, *do_stroke, *do_fill, &r_idx);
271  }
272 
273  /* Set fill and stroke depending of curve type (3D or 2D). */
274  if ((cu->flag & CU_3D) || ((cu->flag & (CU_FRONT | CU_BACK)) == 0)) {
275  mat_gp->gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
276  mat_gp->gp_style->flag &= ~GP_MATERIAL_FILL_SHOW;
277  }
278  else {
279  mat_gp->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
280  mat_gp->gp_style->flag |= GP_MATERIAL_FILL_SHOW;
281  }
282 
283  return r_idx;
284 }
285 
286 /* Helper: Convert one spline to grease pencil stroke. */
287 static void gpencil_convert_spline(Main *bmain,
288  Object *ob_gp,
289  Object *ob_cu,
290  const float scale_thickness,
291  const float sample,
292  bGPDframe *gpf,
293  Nurb *nu)
294 {
295  bGPdata *gpd = (bGPdata *)ob_gp->data;
296  bool cyclic = true;
297 
298  /* Create Stroke. */
299  bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke");
300  gps->thickness = 1.0f;
301  gps->fill_opacity_fac = 1.0f;
302  gps->hardeness = 1.0f;
303  gps->uv_scale = 1.0f;
304 
305  ARRAY_SET_ITEMS(gps->aspect_ratio, 1.0f, 1.0f);
307  gps->inittime = 0.0f;
308 
309  gps->flag &= ~GP_STROKE_SELECT;
310  gps->flag |= GP_STROKE_3DSPACE;
311 
312  gps->mat_nr = 0;
313  /* Count total points
314  * The total of points must consider that last point of each segment is equal to the first
315  * point of next segment.
316  */
317  int totpoints = 0;
318  int segments = 0;
319  int resolu = nu->resolu + 1;
320  segments = nu->pntsu;
321  if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
322  segments--;
323  cyclic = false;
324  }
325  totpoints = (resolu * segments) - (segments - 1);
326 
327  /* Materials
328  * Notice: The color of the material is the color of viewport and not the final shader color.
329  */
330  bool do_stroke, do_fill;
331  int r_idx = gpencil_get_stroke_material_fromcurve(bmain, ob_gp, ob_cu, &do_stroke, &do_fill);
332  CLAMP_MIN(r_idx, 0);
333 
334  /* Assign material index to stroke. */
335  gps->mat_nr = r_idx;
336 
337  /* Add stroke to frame. */
338  BLI_addtail(&gpf->strokes, gps);
339 
340  float *coord_array = NULL;
341  float init_co[3];
342 
343  switch (nu->type) {
344  case CU_POLY: {
345  /* Allocate memory for storage points. */
346  gps->totpoints = nu->pntsu;
347  gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
348  /* Increase thickness for this type. */
349  gps->thickness = 10.0f;
350 
351  /* Get all curve points */
352  for (int s = 0; s < gps->totpoints; s++) {
353  BPoint *bp = &nu->bp[s];
354  bGPDspoint *pt = &gps->points[s];
355  copy_v3_v3(&pt->x, bp->vec);
356  pt->pressure = bp->radius;
357  pt->strength = 1.0f;
358  }
359  break;
360  }
361  case CU_BEZIER: {
362  /* Allocate memory for storage points. */
363  gps->totpoints = totpoints;
364  gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
365 
366  int init = 0;
367  resolu = nu->resolu + 1;
368  segments = nu->pntsu;
369  if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
370  segments--;
371  }
372  /* Get all interpolated curve points of Beziert */
373  for (int s = 0; s < segments; s++) {
374  int inext = (s + 1) % nu->pntsu;
375  BezTriple *prevbezt = &nu->bezt[s];
376  BezTriple *bezt = &nu->bezt[inext];
377  bool last = (bool)(s == segments - 1);
378 
379  coord_array = MEM_callocN((size_t)3 * resolu * sizeof(float), __func__);
380 
381  for (int j = 0; j < 3; j++) {
382  BKE_curve_forward_diff_bezier(prevbezt->vec[1][j],
383  prevbezt->vec[2][j],
384  bezt->vec[0][j],
385  bezt->vec[1][j],
386  coord_array + j,
387  resolu - 1,
388  sizeof(float[3]));
389  }
390  /* Save first point coordinates. */
391  if (s == 0) {
392  copy_v3_v3(init_co, &coord_array[0]);
393  }
394  /* Add points to the stroke */
395  float radius_start = prevbezt->radius * scale_thickness;
396  float radius_end = bezt->radius * scale_thickness;
397 
399  gps, coord_array, radius_start, radius_end, init, resolu, init_co, last);
400  /* Free memory. */
401  MEM_SAFE_FREE(coord_array);
402 
403  /* As the last point of segment is the first point of next segment, back one array
404  * element to avoid duplicated points on the same location.
405  */
406  init += resolu - 1;
407  }
408  break;
409  }
410  case CU_NURBS: {
411  if (nu->pntsv == 1) {
412 
413  int nurb_points;
414  if (nu->flagu & CU_NURB_CYCLIC) {
415  resolu++;
416  nurb_points = nu->pntsu * resolu;
417  }
418  else {
419  nurb_points = (nu->pntsu - 1) * resolu;
420  }
421  /* Get all curve points. */
422  coord_array = MEM_callocN(sizeof(float[3]) * nurb_points, __func__);
423  BKE_nurb_makeCurve(nu, coord_array, NULL, NULL, NULL, resolu, sizeof(float[3]));
424 
425  /* Allocate memory for storage points. */
426  gps->totpoints = nurb_points;
427  gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
428 
429  /* Add points. */
430  gpencil_add_new_points(gps, coord_array, 1.0f, 1.0f, 0, gps->totpoints, init_co, false);
431 
432  MEM_SAFE_FREE(coord_array);
433  }
434  break;
435  }
436  default: {
437  break;
438  }
439  }
440  /* Cyclic curve, close stroke. */
441  if (cyclic) {
443  }
444 
445  if (sample > 0.0f) {
446  BKE_gpencil_stroke_sample(gpd, gps, sample, false, 0);
447  }
448 
449  /* Recalc fill geometry. */
451 }
452 
454 {
455  for (int i = 0; i < gpc->tot_curve_points; i++) {
456  bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
457  BezTriple *bezt = &gpc_pt->bezt;
458  gpc_pt->flag &= ~GP_CURVE_POINT_SELECT;
459  BEZT_DESEL_ALL(bezt);
460  }
461  gpc->flag &= ~GP_CURVE_SELECT;
462 }
463 
465  Scene *scene,
466  Object *ob_gp,
467  Object *ob_cu,
468  const bool use_collections,
469  const float scale_thickness,
470  const float sample)
471 {
472  if (ELEM(NULL, ob_gp, ob_cu) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == NULL)) {
473  return;
474  }
475 
476  Curve *cu = (Curve *)ob_cu->data;
477  bGPdata *gpd = (bGPdata *)ob_gp->data;
478  bGPDlayer *gpl = NULL;
479 
480  /* If the curve is empty, cancel. */
481  if (cu->nurb.first == NULL) {
482  return;
483  }
484 
485  /* Check if there is an active layer. */
486  if (use_collections) {
487  Collection *collection = gpencil_get_parent_collection(scene, ob_cu);
488  if (collection != NULL) {
489  gpl = BKE_gpencil_layer_named_get(gpd, collection->id.name + 2);
490  if (gpl == NULL) {
491  gpl = BKE_gpencil_layer_addnew(gpd, collection->id.name + 2, true, false);
492  }
493  }
494  }
495 
496  if (gpl == NULL) {
497  gpl = BKE_gpencil_layer_active_get(gpd);
498  if (gpl == NULL) {
499  gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true, false);
500  }
501  }
502 
503  /* Check if there is an active frame and add if needed. */
505 
506  /* Read all splines of the curve and create a stroke for each. */
507  LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
508  gpencil_convert_spline(bmain, ob_gp, ob_cu, scale_thickness, sample, gpf, nu);
509  }
510 
511  /* Merge any similar material. */
512  int removed = 0;
513  BKE_gpencil_merge_materials(ob_gp, 0.001f, 0.001f, 0.001f, &removed);
514 
515  /* Remove any unused slot. */
516  int actcol = ob_gp->actcol;
517 
518  for (int slot = 1; slot <= ob_gp->totcol; slot++) {
519  while (slot <= ob_gp->totcol && !BKE_object_material_slot_used(ob_gp, slot)) {
520  ob_gp->actcol = slot;
521  BKE_object_material_slot_remove(bmain, ob_gp);
522 
523  if (actcol >= slot) {
524  actcol--;
525  }
526  }
527  }
528 
529  ob_gp->actcol = actcol;
530 
531  /* Tag for recalculation */
534 }
535 
538 /* -------------------------------------------------------------------- */
543  const float stroke_radius)
544 {
545  BLI_assert(gps->totpoints < 3);
546 
547  if (gps->totpoints == 1) {
549  bGPDspoint *pt = &gps->points[0];
550  bGPDcurve_point *cpt = &editcurve->curve_points[0];
551  BezTriple *bezt = &cpt->bezt;
552 
553  /* Handles are twice as long as the radius of the point. */
554  float offset = (pt->pressure * stroke_radius) * 2.0f;
555 
556  float tmp_vec[3];
557  for (int j = 0; j < 3; j++) {
558  copy_v3_v3(tmp_vec, &pt->x);
559  /* Move handles along the x-axis away from the control point */
560  tmp_vec[0] += (float)(j - 1) * offset;
561  copy_v3_v3(bezt->vec[j], tmp_vec);
562  }
563 
564  cpt->pressure = pt->pressure;
565  cpt->strength = pt->strength;
566  copy_v4_v4(cpt->vert_color, pt->vert_color);
567 
568  /* default handle type */
569  bezt->h1 = HD_FREE;
570  bezt->h2 = HD_FREE;
571 
572  cpt->point_index = 0;
573 
574  return editcurve;
575  }
576  if (gps->totpoints == 2) {
578  bGPDspoint *first_pt = &gps->points[0];
579  bGPDspoint *last_pt = &gps->points[1];
580 
581  float length = len_v3v3(&first_pt->x, &last_pt->x);
582  float offset = length / 3;
583  float dir[3];
584  sub_v3_v3v3(dir, &last_pt->x, &first_pt->x);
585 
586  for (int i = 0; i < 2; i++) {
587  bGPDspoint *pt = &gps->points[i];
588  bGPDcurve_point *cpt = &editcurve->curve_points[i];
589  BezTriple *bezt = &cpt->bezt;
590 
591  float tmp_vec[3];
592  for (int j = 0; j < 3; j++) {
593  copy_v3_v3(tmp_vec, dir);
594  normalize_v3_length(tmp_vec, (float)(j - 1) * offset);
595  add_v3_v3v3(bezt->vec[j], &pt->x, tmp_vec);
596  }
597 
598  cpt->pressure = pt->pressure;
599  cpt->strength = pt->strength;
600  copy_v4_v4(cpt->vert_color, pt->vert_color);
601 
602  /* default handle type */
603  bezt->h1 = HD_VECT;
604  bezt->h2 = HD_VECT;
605 
606  cpt->point_index = 0;
607  }
608 
609  return editcurve;
610  }
611 
612  return NULL;
613 }
614 
616  const float error_threshold,
617  const float corner_angle,
618  const float stroke_radius)
619 {
620  if (gps->totpoints < 3) {
621  return gpencil_stroke_editcurve_generate_edgecases(gps, stroke_radius);
622  }
623 #define POINT_DIM 9
624 
625  float *points = MEM_callocN(sizeof(float) * gps->totpoints * POINT_DIM, __func__);
626  float diag_length = len_v3v3(gps->boundbox_min, gps->boundbox_max);
627  float tmp_vec[3];
628 
629  for (int i = 0; i < gps->totpoints; i++) {
630  bGPDspoint *pt = &gps->points[i];
631  int row = i * POINT_DIM;
632 
633  /* normalize coordinate to 0..1 */
634  sub_v3_v3v3(tmp_vec, &pt->x, gps->boundbox_min);
635  mul_v3_v3fl(&points[row], tmp_vec, COORD_FITTING_INFLUENCE / diag_length);
636  points[row + 3] = pt->pressure / diag_length;
637 
638  /* strength and color are already normalized */
639  points[row + 4] = pt->strength / diag_length;
640  mul_v4_v4fl(&points[row + 5], pt->vert_color, 1.0f / diag_length);
641  }
642 
643  uint calc_flag = CURVE_FIT_CALC_HIGH_QUALIY;
644  if (gps->totpoints > 2 && gps->flag & GP_STROKE_CYCLIC) {
645  calc_flag |= CURVE_FIT_CALC_CYCLIC;
646  }
647 
648  float *r_cubic_array = NULL;
649  unsigned int r_cubic_array_len = 0;
650  unsigned int *r_cubic_orig_index = NULL;
651  unsigned int *r_corners_index_array = NULL;
652  unsigned int r_corners_index_len = 0;
653  int r = curve_fit_cubic_to_points_refit_fl(points,
654  gps->totpoints,
655  POINT_DIM,
656  error_threshold,
657  calc_flag,
658  NULL,
659  0,
660  corner_angle,
661  &r_cubic_array,
662  &r_cubic_array_len,
663  &r_cubic_orig_index,
664  &r_corners_index_array,
665  &r_corners_index_len);
666 
667  if (r != 0 || r_cubic_array_len < 1) {
668  return NULL;
669  }
670 
671  uint curve_point_size = 3 * POINT_DIM;
672 
673  bGPDcurve *editcurve = BKE_gpencil_stroke_editcurve_new(r_cubic_array_len);
674 
675  for (int i = 0; i < r_cubic_array_len; i++) {
676  bGPDcurve_point *cpt = &editcurve->curve_points[i];
677  BezTriple *bezt = &cpt->bezt;
678  float *curve_point = &r_cubic_array[i * curve_point_size];
679 
680  for (int j = 0; j < 3; j++) {
681  float *bez = &curve_point[j * POINT_DIM];
682  madd_v3_v3v3fl(bezt->vec[j], gps->boundbox_min, bez, diag_length / COORD_FITTING_INFLUENCE);
683  }
684 
685  float *ctrl_point = &curve_point[1 * POINT_DIM];
686  cpt->pressure = ctrl_point[3] * diag_length;
687  cpt->strength = ctrl_point[4] * diag_length;
688  mul_v4_v4fl(cpt->vert_color, &ctrl_point[5], diag_length);
689 
690  /* default handle type */
691  bezt->h1 = HD_ALIGN;
692  bezt->h2 = HD_ALIGN;
693 
694  cpt->point_index = r_cubic_orig_index[i];
695  }
696 
697  if (r_corners_index_len > 0 && r_corners_index_array != NULL) {
698  int start = 0, end = r_corners_index_len;
699  if ((r_corners_index_len > 1) && (calc_flag & CURVE_FIT_CALC_CYCLIC) == 0) {
700  start = 1;
701  end = r_corners_index_len - 1;
702  }
703  for (int i = start; i < end; i++) {
704  bGPDcurve_point *cpt = &editcurve->curve_points[r_corners_index_array[i]];
705  BezTriple *bezt = &cpt->bezt;
706  bezt->h1 = HD_FREE;
707  bezt->h2 = HD_FREE;
708  }
709  }
710 
711  MEM_freeN(points);
712  if (r_cubic_array) {
713  free(r_cubic_array);
714  }
715  if (r_corners_index_array) {
716  free(r_corners_index_array);
717  }
718  if (r_cubic_orig_index) {
719  free(r_cubic_orig_index);
720  }
721 
722 #undef POINT_DIM
723  return editcurve;
724 }
725 
727 {
728  if (gps == NULL || gps->totpoints < 0) {
729  return;
730  }
731 
732  if (gps->editcurve != NULL) {
734  }
735 
736  float defaultpixsize = 1000.0f / gpd->pixfactor;
737  float stroke_radius = ((gps->thickness + gpl->line_change) / defaultpixsize) / 2.0f;
738 
740  gps, gpd->curve_edit_threshold, gpd->curve_edit_corner_angle, stroke_radius);
741  if (editcurve == NULL) {
742  return;
743  }
744 
745  gps->editcurve = editcurve;
746 }
747 
749  bGPDstroke *gps,
750  bGPDcurve *gpc)
751 {
752  if (gps->flag & GP_STROKE_SELECT) {
753  gpc->flag |= GP_CURVE_SELECT;
754 
755  for (int i = 0; i < gpc->tot_curve_points; i++) {
756  bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
757  bGPDspoint *pt = &gps->points[gpc_pt->point_index];
758  if (pt->flag & GP_SPOINT_SELECT) {
759  gpc_pt->flag |= GP_CURVE_POINT_SELECT;
760  BEZT_SEL_ALL(&gpc_pt->bezt);
761  }
762  else {
763  gpc_pt->flag &= ~GP_CURVE_POINT_SELECT;
764  BEZT_DESEL_ALL(&gpc_pt->bezt);
765  }
766  }
767  }
768  else {
769  gpc->flag &= ~GP_CURVE_SELECT;
771  }
772 }
773 
775 {
776  if (gpc->flag & GP_CURVE_SELECT) {
777  gps->flag |= GP_STROKE_SELECT;
779 
780  for (int i = 0; i < gpc->tot_curve_points - 1; i++) {
781  bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
782  bGPDspoint *pt = &gps->points[gpc_pt->point_index];
783  bGPDcurve_point *gpc_pt_next = &gpc->curve_points[i + 1];
784 
785  if (gpc_pt->flag & GP_CURVE_POINT_SELECT) {
786  pt->flag |= GP_SPOINT_SELECT;
787  if (gpc_pt_next->flag & GP_CURVE_POINT_SELECT) {
788  /* select all the points after */
789  for (int j = gpc_pt->point_index + 1; j < gpc_pt_next->point_index; j++) {
790  bGPDspoint *pt_next = &gps->points[j];
791  pt_next->flag |= GP_SPOINT_SELECT;
792  }
793  }
794  }
795  else {
796  pt->flag &= ~GP_SPOINT_SELECT;
797  /* deselect all points after */
798  for (int j = gpc_pt->point_index + 1; j < gpc_pt_next->point_index; j++) {
799  bGPDspoint *pt_next = &gps->points[j];
800  pt_next->flag &= ~GP_SPOINT_SELECT;
801  }
802  }
803  }
804 
805  bGPDcurve_point *gpc_first = &gpc->curve_points[0];
806  bGPDcurve_point *gpc_last = &gpc->curve_points[gpc->tot_curve_points - 1];
807  bGPDspoint *last_pt = &gps->points[gpc_last->point_index];
808  if (gpc_last->flag & GP_CURVE_POINT_SELECT) {
809  last_pt->flag |= GP_SPOINT_SELECT;
810  }
811  else {
812  last_pt->flag &= ~GP_SPOINT_SELECT;
813  }
814 
815  if (gps->flag & GP_STROKE_CYCLIC) {
816  if (gpc_first->flag & GP_CURVE_POINT_SELECT && gpc_last->flag & GP_CURVE_POINT_SELECT) {
817  for (int i = gpc_last->point_index + 1; i < gps->totpoints; i++) {
818  bGPDspoint *pt_next = &gps->points[i];
819  pt_next->flag |= GP_SPOINT_SELECT;
820  }
821  }
822  else {
823  for (int i = gpc_last->point_index + 1; i < gps->totpoints; i++) {
824  bGPDspoint *pt_next = &gps->points[i];
825  pt_next->flag &= ~GP_SPOINT_SELECT;
826  }
827  }
828  }
829  }
830  else {
831  gps->flag &= ~GP_STROKE_SELECT;
833  for (int i = 0; i < gps->totpoints; i++) {
834  bGPDspoint *pt = &gps->points[i];
835  pt->flag &= ~GP_SPOINT_SELECT;
836  }
837  }
838 }
839 
841  float from, float to, float *point_offset, int it, int stride)
842 {
843  /* smooth interpolation */
844  float *r = point_offset;
845  for (int i = 0; i <= it; i++) {
846  float fac = (float)i / (float)it;
847  fac = 3.0f * fac * fac - 2.0f * fac * fac * fac; /* Smooth. */
848  *r = interpf(to, from, fac);
849  r = POINTER_OFFSET(r, stride);
850  }
851 }
852 
854  float from[4], float to[4], float *point_offset, int it, int stride)
855 {
856  /* smooth interpolation */
857  float *r = point_offset;
858  for (int i = 0; i <= it; i++) {
859  float fac = (float)i / (float)it;
860  fac = 3.0f * fac * fac - 2.0f * fac * fac * fac; /* Smooth. */
861  interp_v4_v4v4(r, from, to, fac);
862  r = POINTER_OFFSET(r, stride);
863  }
864 }
865 
867  bGPDcurve_point *cpt_end)
868 {
869  BezTriple *bezt_start = &cpt_start->bezt;
870  BezTriple *bezt_end = &cpt_end->bezt;
871 
872  float chord_len = len_v3v3(bezt_start->vec[1], bezt_end->vec[1]);
873  float net_len = len_v3v3(bezt_start->vec[1], bezt_start->vec[2]);
874  net_len += len_v3v3(bezt_start->vec[2], bezt_end->vec[0]);
875  net_len += len_v3v3(bezt_end->vec[0], bezt_end->vec[1]);
876 
877  return (chord_len + net_len) / 2.0f;
878 }
879 
881  bGPDcurve_point *cpt, bGPDcurve_point *cpt_next, float *points_offset, int resolu, int stride)
882 {
883  /* sample points on all 3 axis between two curve points */
884  for (uint axis = 0; axis < 3; axis++) {
885  BKE_curve_forward_diff_bezier(cpt->bezt.vec[1][axis],
886  cpt->bezt.vec[2][axis],
887  cpt_next->bezt.vec[0][axis],
888  cpt_next->bezt.vec[1][axis],
889  POINTER_OFFSET(points_offset, sizeof(float) * axis),
890  (int)resolu,
891  stride);
892  }
893 
894  /* interpolate other attributes */
896  cpt_next->pressure,
897  POINTER_OFFSET(points_offset, sizeof(float) * 3),
898  resolu,
899  stride);
901  cpt_next->strength,
902  POINTER_OFFSET(points_offset, sizeof(float) * 4),
903  resolu,
904  stride);
906  cpt_next->vert_color,
907  POINTER_OFFSET(points_offset, sizeof(float) * 5),
908  resolu,
909  stride);
910 }
911 
913  bGPDcurve_point *curve_point_array,
914  int curve_point_array_len,
915  int resolution,
916  bool is_cyclic,
917  int *r_points_len)
918 {
919  /* One stride contains: x, y, z, pressure, strength, Vr, Vg, Vb, Vmix_factor */
920  const uint stride = sizeof(float[9]);
921  const uint cpt_last = curve_point_array_len - 1;
922  const uint num_segments = (is_cyclic) ? curve_point_array_len : curve_point_array_len - 1;
923  int *segment_point_lengths = MEM_callocN(sizeof(int) * num_segments, __func__);
924 
925  uint points_len = 1;
926  for (int i = 0; i < cpt_last; i++) {
927  bGPDcurve_point *cpt = &curve_point_array[i];
928  bGPDcurve_point *cpt_next = &curve_point_array[i + 1];
929  float arclen = gpencil_approximate_curve_segment_arclength(cpt, cpt_next);
930  int segment_resolu = (int)floorf(arclen * resolution);
931  CLAMP_MIN(segment_resolu, 1);
932 
933  segment_point_lengths[i] = segment_resolu;
934  points_len += segment_resolu;
935  }
936 
937  if (is_cyclic) {
938  bGPDcurve_point *cpt = &curve_point_array[cpt_last];
939  bGPDcurve_point *cpt_next = &curve_point_array[0];
940  float arclen = gpencil_approximate_curve_segment_arclength(cpt, cpt_next);
941  int segment_resolu = (int)floorf(arclen * resolution);
942  CLAMP_MIN(segment_resolu, 1);
943 
944  segment_point_lengths[cpt_last] = segment_resolu;
945  points_len += segment_resolu;
946  }
947 
948  float(*r_points)[9] = MEM_callocN((stride * points_len * (is_cyclic ? 2 : 1)), __func__);
949  float *points_offset = &r_points[0][0];
950  int point_index = 0;
951  for (int i = 0; i < cpt_last; i++) {
952  bGPDcurve_point *cpt_curr = &curve_point_array[i];
953  bGPDcurve_point *cpt_next = &curve_point_array[i + 1];
954  int segment_resolu = segment_point_lengths[i];
956  cpt_curr, cpt_next, points_offset, segment_resolu, stride);
957  /* update the index */
958  cpt_curr->point_index = point_index;
959  point_index += segment_resolu;
960  points_offset = POINTER_OFFSET(points_offset, segment_resolu * stride);
961  }
962 
963  bGPDcurve_point *cpt_curr = &curve_point_array[cpt_last];
964  cpt_curr->point_index = point_index;
965  if (is_cyclic) {
966  bGPDcurve_point *cpt_next = &curve_point_array[0];
967  int segment_resolu = segment_point_lengths[cpt_last];
969  cpt_curr, cpt_next, points_offset, segment_resolu, stride);
970  }
971 
972  MEM_freeN(segment_point_lengths);
973 
974  *r_points_len = points_len;
975  return (float(*))r_points;
976 }
977 
982  int curve_point_array_len,
983  int resolution,
984  bool is_cyclic,
985  int *r_points_len)
986 {
987  /* One stride contains: x, y, z, pressure, strength, Vr, Vg, Vb, Vmix_factor */
988  const uint stride = sizeof(float[9]);
989  const uint array_last = curve_point_array_len - 1;
990  const uint resolu_stride = resolution * stride;
991  const uint points_len = BKE_curve_calc_coords_axis_len(
992  curve_point_array_len, resolution, is_cyclic, false);
993 
994  float(*r_points)[9] = MEM_callocN((stride * points_len * (is_cyclic ? 2 : 1)), __func__);
995  float *points_offset = &r_points[0][0];
996  for (unsigned int i = 0; i < array_last; i++) {
997  bGPDcurve_point *cpt_curr = &curve_point_array[i];
998  bGPDcurve_point *cpt_next = &curve_point_array[i + 1];
999 
1001  cpt_curr, cpt_next, points_offset, resolution, stride);
1002  /* update the index */
1003  cpt_curr->point_index = i * resolution;
1004  points_offset = POINTER_OFFSET(points_offset, resolu_stride);
1005  }
1006 
1007  bGPDcurve_point *cpt_curr = &curve_point_array[array_last];
1008  cpt_curr->point_index = array_last * resolution;
1009  if (is_cyclic) {
1010  bGPDcurve_point *cpt_next = &curve_point_array[0];
1012  cpt_curr, cpt_next, points_offset, resolution, stride);
1013  }
1014 
1015  *r_points_len = points_len;
1016  return (float(*))r_points;
1017 }
1018 
1020  const uint resolution,
1021  const bool adaptive)
1022 {
1023  if (gps == NULL || gps->editcurve == NULL) {
1024  return;
1025  }
1026 
1027  bGPDcurve *editcurve = gps->editcurve;
1028  bGPDcurve_point *curve_point_array = editcurve->curve_points;
1029  int curve_point_array_len = editcurve->tot_curve_points;
1030  if (curve_point_array_len == 0) {
1031  return;
1032  }
1033  /* Handle case for single curve point. */
1034  if (curve_point_array_len == 1) {
1035  bGPDcurve_point *cpt = &curve_point_array[0];
1036  /* resize stroke point array */
1037  gps->totpoints = 1;
1038  gps->points = MEM_recallocN(gps->points, sizeof(bGPDspoint) * gps->totpoints);
1039  if (gps->dvert != NULL) {
1040  gps->dvert = MEM_recallocN(gps->dvert, sizeof(MDeformVert) * gps->totpoints);
1041  }
1042 
1043  bGPDspoint *pt = &gps->points[0];
1044  copy_v3_v3(&pt->x, cpt->bezt.vec[1]);
1045 
1046  pt->pressure = cpt->pressure;
1047  pt->strength = cpt->strength;
1048 
1049  copy_v4_v4(pt->vert_color, cpt->vert_color);
1050 
1051  /* deselect */
1052  pt->flag &= ~GP_SPOINT_SELECT;
1053  gps->flag &= ~GP_STROKE_SELECT;
1055 
1056  return;
1057  }
1058 
1059  bool is_cyclic = gps->flag & GP_STROKE_CYCLIC;
1060 
1061  int points_len = 0;
1062  float(*points)[9] = NULL;
1063  if (adaptive) {
1065  curve_point_array, curve_point_array_len, resolution, is_cyclic, &points_len);
1066  }
1067  else {
1069  curve_point_array, curve_point_array_len, resolution, is_cyclic, &points_len);
1070  }
1071 
1072  if (points == NULL || points_len == 0) {
1073  return;
1074  }
1075 
1076  /* resize stroke point array */
1077  gps->totpoints = points_len;
1078  gps->points = MEM_recallocN(gps->points, sizeof(bGPDspoint) * gps->totpoints);
1079  if (gps->dvert != NULL) {
1080  gps->dvert = MEM_recallocN(gps->dvert, sizeof(MDeformVert) * gps->totpoints);
1081  }
1082 
1083  /* write new data to stroke point array */
1084  for (int i = 0; i < points_len; i++) {
1085  bGPDspoint *pt = &gps->points[i];
1086  copy_v3_v3(&pt->x, &points[i][0]);
1087 
1088  pt->pressure = points[i][3];
1089  pt->strength = points[i][4];
1090 
1091  copy_v4_v4(pt->vert_color, &points[i][5]);
1092 
1093  /* deselect points */
1094  pt->flag &= ~GP_SPOINT_SELECT;
1095  }
1096  gps->flag &= ~GP_STROKE_SELECT;
1098 
1099  /* free temp data */
1100  MEM_freeN(points);
1101 }
1102 
1104 {
1105  if (gps == NULL || gps->editcurve == NULL) {
1106  return;
1107  }
1108 
1109  bool changed = false;
1110  bGPDcurve *gpc = gps->editcurve;
1111  if (gpc->tot_curve_points < 2) {
1112  return;
1113  }
1114 
1115  if (gpc->tot_curve_points == 1) {
1117  &(gpc->curve_points[0].bezt), NULL, &(gpc->curve_points[0].bezt), false, 0);
1119  }
1120 
1121  for (int i = 1; i < gpc->tot_curve_points - 1; i++) {
1122  bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
1123  bGPDcurve_point *gpc_pt_prev = &gpc->curve_points[i - 1];
1124  bGPDcurve_point *gpc_pt_next = &gpc->curve_points[i + 1];
1125  /* update handle if point or neighbor is selected */
1126  if (gpc_pt->flag & GP_CURVE_POINT_SELECT || gpc_pt_prev->flag & GP_CURVE_POINT_SELECT ||
1127  gpc_pt_next->flag & GP_CURVE_POINT_SELECT) {
1128  BezTriple *bezt = &gpc_pt->bezt;
1129  BezTriple *bezt_prev = &gpc_pt_prev->bezt;
1130  BezTriple *bezt_next = &gpc_pt_next->bezt;
1131 
1132  BKE_nurb_handle_calc(bezt, bezt_prev, bezt_next, false, 0);
1133  changed = true;
1134  }
1135  }
1136 
1137  bGPDcurve_point *gpc_first = &gpc->curve_points[0];
1138  bGPDcurve_point *gpc_last = &gpc->curve_points[gpc->tot_curve_points - 1];
1139  bGPDcurve_point *gpc_first_next = &gpc->curve_points[1];
1140  bGPDcurve_point *gpc_last_prev = &gpc->curve_points[gpc->tot_curve_points - 2];
1141  if (gps->flag & GP_STROKE_CYCLIC) {
1142  if (gpc_first->flag & GP_CURVE_POINT_SELECT || gpc_last->flag & GP_CURVE_POINT_SELECT) {
1143  BezTriple *bezt_first = &gpc_first->bezt;
1144  BezTriple *bezt_last = &gpc_last->bezt;
1145  BezTriple *bezt_first_next = &gpc_first_next->bezt;
1146  BezTriple *bezt_last_prev = &gpc_last_prev->bezt;
1147 
1148  BKE_nurb_handle_calc(bezt_first, bezt_last, bezt_first_next, false, 0);
1149  BKE_nurb_handle_calc(bezt_last, bezt_last_prev, bezt_first, false, 0);
1150  changed = true;
1151  }
1152  }
1153  else {
1154  if (gpc_first->flag & GP_CURVE_POINT_SELECT || gpc_last->flag & GP_CURVE_POINT_SELECT) {
1155  BezTriple *bezt_first = &gpc_first->bezt;
1156  BezTriple *bezt_last = &gpc_last->bezt;
1157  BezTriple *bezt_first_next = &gpc_first_next->bezt;
1158  BezTriple *bezt_last_prev = &gpc_last_prev->bezt;
1159 
1160  BKE_nurb_handle_calc(bezt_first, NULL, bezt_first_next, false, 0);
1161  BKE_nurb_handle_calc(bezt_last, bezt_last_prev, NULL, false, 0);
1162  changed = true;
1163  }
1164  }
1165 
1166  if (changed) {
1168  }
1169 }
1170 
1171 /* Helper: count how many new curve points must be generated. */
1173 {
1174  int count = 0;
1175  for (int i = 0; i < gpc->tot_curve_points - 1; i++) {
1176  bGPDcurve_point *cpt = &gpc->curve_points[i];
1177  bGPDcurve_point *cpt_next = &gpc->curve_points[i + 1];
1178 
1179  if (cpt->flag & GP_CURVE_POINT_SELECT && cpt_next->flag & GP_CURVE_POINT_SELECT) {
1180  count++;
1181  }
1182  }
1183 
1184  if (is_cyclic) {
1185  bGPDcurve_point *cpt = &gpc->curve_points[0];
1186  bGPDcurve_point *cpt_next = &gpc->curve_points[gpc->tot_curve_points - 1];
1187 
1188  if (cpt->flag & GP_CURVE_POINT_SELECT && cpt_next->flag & GP_CURVE_POINT_SELECT) {
1189  count++;
1190  }
1191  }
1192 
1193  return count;
1194 }
1195 
1197  bGPDcurve_point *cpt_end,
1198  bGPDcurve_point *cpt_new)
1199 {
1200  BezTriple *bezt_start = &cpt_start->bezt;
1201  BezTriple *bezt_end = &cpt_end->bezt;
1202  BezTriple *bezt_new = &cpt_new->bezt;
1203  for (int axis = 0; axis < 3; axis++) {
1204  float p0, p1, p2, p3, m0, m1, q0, q1, b;
1205  p0 = bezt_start->vec[1][axis];
1206  p1 = bezt_start->vec[2][axis];
1207  p2 = bezt_end->vec[0][axis];
1208  p3 = bezt_end->vec[1][axis];
1209 
1210  m0 = (p0 + p1) / 2;
1211  q0 = (p0 + 2 * p1 + p2) / 4;
1212  b = (p0 + 3 * p1 + 3 * p2 + p3) / 8;
1213  q1 = (p1 + 2 * p2 + p3) / 4;
1214  m1 = (p2 + p3) / 2;
1215 
1216  bezt_new->vec[0][axis] = q0;
1217  bezt_new->vec[2][axis] = q1;
1218  bezt_new->vec[1][axis] = b;
1219 
1220  bezt_start->vec[2][axis] = m0;
1221  bezt_end->vec[0][axis] = m1;
1222  }
1223 
1224  cpt_new->pressure = interpf(cpt_end->pressure, cpt_start->pressure, 0.5f);
1225  cpt_new->strength = interpf(cpt_end->strength, cpt_start->strength, 0.5f);
1226  interp_v4_v4v4(cpt_new->vert_color, cpt_start->vert_color, cpt_end->vert_color, 0.5f);
1227 }
1228 
1230 {
1231  bGPDcurve *gpc = gps->editcurve;
1232  if (gpc == NULL || gpc->tot_curve_points < 2) {
1233  return;
1234  }
1235  bool is_cyclic = gps->flag & GP_STROKE_CYCLIC;
1236 
1237  /* repeat for number of cuts */
1238  for (int s = 0; s < cuts; s++) {
1239  int old_tot_curve_points = gpc->tot_curve_points;
1240  int new_num_curve_points = gpencil_editcurve_subdivide_count(gpc, is_cyclic);
1241  if (new_num_curve_points == 0) {
1242  break;
1243  }
1244  int new_tot_curve_points = old_tot_curve_points + new_num_curve_points;
1245 
1246  bGPDcurve_point *temp_curve_points = (bGPDcurve_point *)MEM_callocN(
1247  sizeof(bGPDcurve_point) * new_tot_curve_points, __func__);
1248 
1249  bool prev_subdivided = false;
1250  int j = 0;
1251  for (int i = 0; i < old_tot_curve_points - 1; i++, j++) {
1252  bGPDcurve_point *cpt = &gpc->curve_points[i];
1253  bGPDcurve_point *cpt_next = &gpc->curve_points[i + 1];
1254 
1255  if (cpt->flag & GP_CURVE_POINT_SELECT && cpt_next->flag & GP_CURVE_POINT_SELECT) {
1256  bGPDcurve_point *cpt_new = &temp_curve_points[j + 1];
1257  gpencil_editcurve_subdivide_curve_segment(cpt, cpt_next, cpt_new);
1258 
1259  memcpy(&temp_curve_points[j], cpt, sizeof(bGPDcurve_point));
1260  memcpy(&temp_curve_points[j + 2], cpt_next, sizeof(bGPDcurve_point));
1261 
1262  cpt_new->flag |= GP_CURVE_POINT_SELECT;
1263  cpt_new->bezt.h1 = HD_ALIGN;
1264  cpt_new->bezt.h2 = HD_ALIGN;
1265  BEZT_SEL_ALL(&cpt_new->bezt);
1266 
1267  prev_subdivided = true;
1268  j++;
1269  }
1270  else if (!prev_subdivided) {
1271  memcpy(&temp_curve_points[j], cpt, sizeof(bGPDcurve_point));
1272  prev_subdivided = false;
1273  }
1274  else {
1275  prev_subdivided = false;
1276  }
1277  }
1278 
1279  if (is_cyclic) {
1280  bGPDcurve_point *cpt = &gpc->curve_points[old_tot_curve_points - 1];
1281  bGPDcurve_point *cpt_next = &gpc->curve_points[0];
1282 
1283  if (cpt->flag & GP_CURVE_POINT_SELECT && cpt_next->flag & GP_CURVE_POINT_SELECT) {
1284  bGPDcurve_point *cpt_new = &temp_curve_points[j + 1];
1285  gpencil_editcurve_subdivide_curve_segment(cpt, cpt_next, cpt_new);
1286 
1287  memcpy(&temp_curve_points[j], cpt, sizeof(bGPDcurve_point));
1288  memcpy(&temp_curve_points[0], cpt_next, sizeof(bGPDcurve_point));
1289 
1290  cpt_new->flag |= GP_CURVE_POINT_SELECT;
1291  cpt_new->bezt.h1 = HD_ALIGN;
1292  cpt_new->bezt.h2 = HD_ALIGN;
1293  BEZT_SEL_ALL(&cpt_new->bezt);
1294  }
1295  else if (!prev_subdivided) {
1296  memcpy(&temp_curve_points[j], cpt, sizeof(bGPDcurve_point));
1297  }
1298  }
1299  else {
1300  bGPDcurve_point *cpt = &gpc->curve_points[old_tot_curve_points - 1];
1301  memcpy(&temp_curve_points[j], cpt, sizeof(bGPDcurve_point));
1302  }
1303 
1304  MEM_freeN(gpc->curve_points);
1305  gpc->curve_points = temp_curve_points;
1306  gpc->tot_curve_points = new_tot_curve_points;
1307  }
1308 }
1309 
1311 {
1312  const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
1313  /* For all selected strokes, update edit curve. */
1314  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
1315  if (!BKE_gpencil_layer_is_editable(gpl)) {
1316  continue;
1317  }
1318  bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
1319  for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
1320  if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && is_multiedit)) {
1321  LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
1322  /* skip deselected stroke */
1323  if (!(gps->flag & GP_STROKE_SELECT)) {
1324  continue;
1325  }
1326 
1327  /* Generate the curve if there is none or the stroke was changed */
1328  if (gps->editcurve == NULL) {
1329  BKE_gpencil_stroke_editcurve_update(gpd, gpl, gps);
1330  /* Continue if curve could not be generated. */
1331  if (gps->editcurve == NULL) {
1332  continue;
1333  }
1334  }
1335  else if (gps->editcurve->flag & GP_CURVE_NEEDS_STROKE_UPDATE) {
1336  BKE_gpencil_stroke_editcurve_update(gpd, gpl, gps);
1337  }
1338  /* Update the selection from the stroke to the curve. */
1339  BKE_gpencil_editcurve_stroke_sync_selection(gpd, gps, gps->editcurve);
1340 
1341  gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
1343  }
1344  }
1345  }
1346  }
1347 }
1348 
1350 {
1351  const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
1352  /* Sync selection for all strokes with editcurve. */
1353  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
1354  if (!BKE_gpencil_layer_is_editable(gpl)) {
1355  continue;
1356  }
1357  bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
1358  for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
1359  if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && is_multiedit)) {
1360  LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
1361  bGPDcurve *gpc = gps->editcurve;
1362  if (gpc != NULL) {
1363  /* Update the selection of every stroke that has an editcurve */
1365  }
1366  }
1367  }
1368  }
1369  }
1370 }
1371 
typedef float(TangentPoint)[2]
#define FOREACH_SCENE_COLLECTION_END
#define FOREACH_SCENE_COLLECTION_BEGIN(scene, _instance)
unsigned int BKE_curve_calc_coords_axis_len(unsigned int bezt_array_len, unsigned int resolu, bool is_cyclic, bool use_cyclic_duplicate_endpoint)
Definition: curve.cc:1650
void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride)
Definition: curve.cc:1717
void BKE_nurb_makeCurve(const struct Nurb *nu, float *coord_array, float *tilt_array, float *radius_array, float *weight_array, int resolu, int stride)
void BKE_nurb_handle_calc(struct BezTriple *bezt, struct BezTriple *prev, struct BezTriple *next, bool is_fcurve, char smoothing)
Definition: curve.cc:3978
void BKE_gpencil_stroke_select_index_set(struct bGPdata *gpd, struct bGPDstroke *gps)
Definition: gpencil.c:1155
struct Material * BKE_gpencil_object_material_new(struct Main *bmain, struct Object *ob, const char *name, int *r_index)
Definition: gpencil.c:1734
struct bGPDlayer * BKE_gpencil_layer_active_get(struct bGPdata *gpd)
Definition: gpencil.c:1558
struct bGPDcurve * BKE_gpencil_stroke_editcurve_new(int tot_curve_points)
Definition: gpencil.c:821
void BKE_gpencil_stroke_select_index_reset(struct bGPDstroke *gps)
Definition: gpencil.c:1161
struct bGPDlayer * BKE_gpencil_layer_addnew(struct bGPdata *gpd, const char *name, bool setactive, bool add_to_header)
Definition: gpencil.c:621
bool BKE_gpencil_layer_is_editable(const struct bGPDlayer *gpl)
void BKE_gpencil_free_stroke_editcurve(struct bGPDstroke *gps)
Definition: gpencil.c:377
struct bGPDlayer * BKE_gpencil_layer_named_get(struct bGPdata *gpd, const char *name)
Definition: gpencil.c:1419
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_COPY
Definition: BKE_gpencil.h:343
void BKE_gpencil_stroke_geometry_update(struct bGPdata *gpd, struct bGPDstroke *gps)
bool BKE_gpencil_stroke_sample(struct bGPdata *gpd, struct bGPDstroke *gps, const float dist, const bool select, const float sharp_threshold)
bool BKE_gpencil_stroke_close(struct bGPDstroke *gps)
General operations, lookup, etc. for materials.
bool BKE_object_material_slot_remove(struct Main *bmain, struct Object *ob)
Definition: material.c:1248
struct Material * BKE_object_material_get(struct Object *ob, short act)
Definition: material.c:687
bool BKE_object_material_slot_used(struct Object *object, short actcol)
Definition: material.c:452
General operations, lookup, etc. for blender objects.
#define BLI_assert(a)
Definition: BLI_assert.h:46
void BLI_kdtree_nd_() free(KDTree *tree)
Definition: kdtree_impl.h:102
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
MINLINE float interpf(float a, float b, float t)
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3])
Definition: math_color.c:232
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 sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v4_v4fl(float r[4], const float a[4], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
void interp_v4_v4v4(float r[4], const float a[4], const float b[4], float t)
Definition: math_vector.c:38
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition: math_vector.c:29
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float normalize_v3_length(float r[3], float unit_scale)
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
MINLINE void zero_v3(float r[3])
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE bool compare_v4v4(const float a[4], const float b[4], float limit) ATTR_WARN_UNUSED_RESULT
unsigned int uint
Definition: BLI_sys_types.h:67
#define ARRAY_SET_ITEMS(...)
#define UNUSED(x)
#define ELEM(...)
#define POINTER_OFFSET(v, ofs)
#define CLAMP_MIN(a, b)
#define DATA_(msgid)
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:834
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
Object groups, one object can be in many groups at once.
@ CU_BEZIER
@ CU_POLY
@ CU_NURBS
#define BEZT_SEL_ALL(bezt)
#define BEZT_DESEL_ALL(bezt)
@ CU_NURB_CYCLIC
@ HD_VECT
@ HD_FREE
@ HD_ALIGN
@ CU_3D
@ CU_FRONT
@ CU_BACK
@ GP_CURVE_NEEDS_STROKE_UPDATE
@ GP_CURVE_SELECT
@ GP_STROKE_CAP_ROUND
@ GP_STROKE_NEEDS_CURVE_UPDATE
@ GP_STROKE_SELECT
@ GP_STROKE_CYCLIC
@ GP_STROKE_3DSPACE
#define GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)
@ GP_FRAME_SELECT
@ GP_CURVE_POINT_SELECT
@ GP_SPOINT_SELECT
@ GP_MATERIAL_FILL_STYLE_SOLID
@ GP_MATERIAL_STROKE_STYLE_SOLID
@ GP_MATERIAL_STROKE_SHOW
@ GP_MATERIAL_FILL_SHOW
@ OB_GPENCIL
_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 GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble GLdouble r _GL_VOID_RET _GL_VOID GLfloat GLfloat r _GL_VOID_RET _GL_VOID GLint GLint r _GL_VOID_RET _GL_VOID GLshort GLshort r _GL_VOID_RET _GL_VOID GLdouble GLdouble r
_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 stride
Read Guarded memory(de)allocation.
#define MEM_recallocN(vmemh, len)
#define MEM_SAFE_FREE(v)
StackEntry * from
Scene scene
static bool is_cyclic(const Nurb *nu)
void BKE_gpencil_editcurve_subdivide(bGPDstroke *gps, const int cuts)
static void gpencil_editcurve_subdivide_curve_segment(bGPDcurve_point *cpt_start, bGPDcurve_point *cpt_end, bGPDcurve_point *cpt_new)
void BKE_gpencil_strokes_selected_sync_selection_editcurve(bGPdata *gpd)
void BKE_gpencil_stroke_editcurve_sync_selection(bGPdata *gpd, bGPDstroke *gps, bGPDcurve *gpc)
static void gpencil_calculate_stroke_points_curve_segment(bGPDcurve_point *cpt, bGPDcurve_point *cpt_next, float *points_offset, int resolu, int stride)
#define COORD_FITTING_INFLUENCE
Definition: gpencil_curve.c:43
void BKE_gpencil_strokes_selected_update_editcurve(bGPdata *gpd)
static int gpencil_check_same_material_color(Object *ob_gp, const float color_stroke[4], const float color_fill[4], const bool do_stroke, const bool do_fill, Material **r_mat)
Definition: gpencil_curve.c:50
bGPDcurve * BKE_gpencil_stroke_editcurve_generate(bGPDstroke *gps, const float error_threshold, const float corner_angle, const float stroke_radius)
static float * gpencil_stroke_points_from_editcurve_fixed_resolu(bGPDcurve_point *curve_point_array, int curve_point_array_len, int resolution, bool is_cyclic, int *r_points_len)
static int gpencil_get_stroke_material_fromcurve(Main *bmain, Object *ob_gp, Object *ob_cu, bool *do_stroke, bool *do_fill)
static void gpencil_editstroke_deselect_all(bGPDcurve *gpc)
static void gpencil_add_new_points(bGPDstroke *gps, const float *coord_array, const float pressure_start, const float pressure_end, const int init, const int totpoints, const float init_co[3], const bool last)
static void gpencil_convert_spline(Main *bmain, Object *ob_gp, Object *ob_cu, const float scale_thickness, const float sample, bGPDframe *gpf, Nurb *nu)
void BKE_gpencil_editcurve_recalculate_handles(bGPDstroke *gps)
void BKE_gpencil_convert_curve(Main *bmain, Scene *scene, Object *ob_gp, Object *ob_cu, const bool use_collections, const float scale_thickness, const float sample)
static float * gpencil_stroke_points_from_editcurve_adaptive_resolu(bGPDcurve_point *curve_point_array, int curve_point_array_len, int resolution, bool is_cyclic, int *r_points_len)
static void gpencil_interpolate_v4_from_to(float from[4], float to[4], float *point_offset, int it, int stride)
static void gpencil_interpolate_fl_from_to(float from, float to, float *point_offset, int it, int stride)
static float gpencil_approximate_curve_segment_arclength(bGPDcurve_point *cpt_start, bGPDcurve_point *cpt_end)
#define POINT_DIM
static int gpencil_editcurve_subdivide_count(bGPDcurve *gpc, bool is_cyclic)
static Material * gpencil_add_from_curve_material(Main *bmain, Object *ob_gp, const float stroke_color[4], const float fill_color[4], const bool stroke, const bool fill, int *r_idx)
void BKE_gpencil_stroke_editcurve_update(bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps)
static bGPDcurve * gpencil_stroke_editcurve_generate_edgecases(bGPDstroke *gps, const float stroke_radius)
void BKE_gpencil_stroke_update_geometry_from_editcurve(bGPDstroke *gps, const uint resolution, const bool adaptive)
static Collection * gpencil_get_parent_collection(Scene *scene, Object *ob)
void BKE_gpencil_editcurve_stroke_sync_selection(bGPdata *UNUSED(gpd), bGPDstroke *gps, bGPDcurve *gpc)
int count
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
#define floorf(x)
Definition: metal/compat.h:224
T length(const vec_base< T, Size > &a)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
float vec[4]
float radius
uint8_t h1
float vec[3][3]
uint8_t h2
ListBase nurb
char name[66]
Definition: DNA_ID.h:378
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
struct MaterialGPencilStyle * gp_style
short flagu
short type
BezTriple * bezt
BPoint * bp
short resolu
void * data
struct RenderData r
bGPDcurve_point * curve_points
struct bGPDframe * next
ListBase strokes
float vert_color[4]
bGPDspoint * points
float boundbox_max[3]
float boundbox_min[3]
struct bGPDcurve * editcurve
struct MDeformVert * dvert
float curve_edit_corner_angle
ListBase layers
float curve_edit_threshold