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