Blender V4.3
gpencil_curve_legacy.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cmath>
10#include <cstddef>
11#include <cstdio>
12#include <cstdlib>
13#include <cstring>
14
15#include "MEM_guardedalloc.h"
16
17#include "BLI_math_color.h"
18#include "BLI_math_vector.h"
19
20#include "BLT_translation.hh"
21
24#include "DNA_material_types.h"
25#include "DNA_meshdata_types.h"
26#include "DNA_scene_types.h"
27
28#include "BKE_collection.hh"
29#include "BKE_curve.hh"
32#include "BKE_gpencil_legacy.h"
33#include "BKE_material.h"
34
35extern "C" {
36#include "curve_fit_nd.h"
37}
38
40
41#define COORD_FITTING_INFLUENCE 20.0f
42
43/* -------------------------------------------------------------------- */
48{
49 for (int i = 0; i < gpc->tot_curve_points; i++) {
50 bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
51 BezTriple *bezt = &gpc_pt->bezt;
52 gpc_pt->flag &= ~GP_CURVE_POINT_SELECT;
53 BEZT_DESEL_ALL(bezt);
54 }
55 gpc->flag &= ~GP_CURVE_SELECT;
56}
57
60/* -------------------------------------------------------------------- */
65 const float stroke_radius)
66{
67 BLI_assert(gps->totpoints < 3);
68
69 if (gps->totpoints == 1) {
71 bGPDspoint *pt = &gps->points[0];
72 bGPDcurve_point *cpt = &editcurve->curve_points[0];
73 BezTriple *bezt = &cpt->bezt;
74
75 /* Handles are twice as long as the radius of the point. */
76 float offset = (pt->pressure * stroke_radius) * 2.0f;
77
78 float tmp_vec[3];
79 for (int j = 0; j < 3; j++) {
80 copy_v3_v3(tmp_vec, &pt->x);
81 /* Move handles along the x-axis away from the control point */
82 tmp_vec[0] += float(j - 1) * offset;
83 copy_v3_v3(bezt->vec[j], tmp_vec);
84 }
85
86 cpt->pressure = pt->pressure;
87 cpt->strength = pt->strength;
89
90 /* default handle type */
91 bezt->h1 = HD_FREE;
92 bezt->h2 = HD_FREE;
93
94 cpt->point_index = 0;
95
96 return editcurve;
97 }
98 if (gps->totpoints == 2) {
100 bGPDspoint *first_pt = &gps->points[0];
101 bGPDspoint *last_pt = &gps->points[1];
102
103 float length = len_v3v3(&first_pt->x, &last_pt->x);
104 float offset = length / 3;
105 float dir[3];
106 sub_v3_v3v3(dir, &last_pt->x, &first_pt->x);
107
108 for (int i = 0; i < 2; i++) {
109 bGPDspoint *pt = &gps->points[i];
110 bGPDcurve_point *cpt = &editcurve->curve_points[i];
111 BezTriple *bezt = &cpt->bezt;
112
113 float tmp_vec[3];
114 for (int j = 0; j < 3; j++) {
115 copy_v3_v3(tmp_vec, dir);
116 normalize_v3_length(tmp_vec, float(j - 1) * offset);
117 add_v3_v3v3(bezt->vec[j], &pt->x, tmp_vec);
118 }
119
120 cpt->pressure = pt->pressure;
121 cpt->strength = pt->strength;
123
124 /* default handle type */
125 bezt->h1 = HD_VECT;
126 bezt->h2 = HD_VECT;
127
128 cpt->point_index = 0;
129 }
130
131 return editcurve;
132 }
133
134 return nullptr;
135}
136
138 const float error_threshold,
139 const float corner_angle,
140 const float stroke_radius)
141{
142 if (gps->totpoints < 3) {
143 return gpencil_stroke_editcurve_generate_edgecases(gps, stroke_radius);
144 }
145#define POINT_DIM 9
146
147 float *points = static_cast<float *>(
148 MEM_callocN(sizeof(float) * gps->totpoints * POINT_DIM, __func__));
149 float diag_length = len_v3v3(gps->boundbox_min, gps->boundbox_max);
150 float tmp_vec[3];
151
152 for (int i = 0; i < gps->totpoints; i++) {
153 bGPDspoint *pt = &gps->points[i];
154 int row = i * POINT_DIM;
155
156 /* normalize coordinate to 0..1 */
157 sub_v3_v3v3(tmp_vec, &pt->x, gps->boundbox_min);
158 mul_v3_v3fl(&points[row], tmp_vec, COORD_FITTING_INFLUENCE / diag_length);
159 points[row + 3] = pt->pressure / diag_length;
160
161 /* strength and color are already normalized */
162 points[row + 4] = pt->strength / diag_length;
163 mul_v4_v4fl(&points[row + 5], pt->vert_color, 1.0f / diag_length);
164 }
165
166 uint calc_flag = CURVE_FIT_CALC_HIGH_QUALIY;
167 if (gps->totpoints > 2 && gps->flag & GP_STROKE_CYCLIC) {
168 calc_flag |= CURVE_FIT_CALC_CYCLIC;
169 }
170
171 float *r_cubic_array = nullptr;
172 uint r_cubic_array_len = 0;
173 uint *r_cubic_orig_index = nullptr;
174 uint *r_corners_index_array = nullptr;
175 uint r_corners_index_len = 0;
176 int r = curve_fit_cubic_to_points_refit_fl(points,
177 gps->totpoints,
178 POINT_DIM,
179 error_threshold,
180 calc_flag,
181 nullptr,
182 0,
183 corner_angle,
184 &r_cubic_array,
185 &r_cubic_array_len,
186 &r_cubic_orig_index,
187 &r_corners_index_array,
188 &r_corners_index_len);
189
190 if (r != 0 || r_cubic_array_len < 1) {
191 return nullptr;
192 }
193
194 uint curve_point_size = 3 * POINT_DIM;
195
196 bGPDcurve *editcurve = BKE_gpencil_stroke_editcurve_new(r_cubic_array_len);
197
198 for (int i = 0; i < r_cubic_array_len; i++) {
199 bGPDcurve_point *cpt = &editcurve->curve_points[i];
200 BezTriple *bezt = &cpt->bezt;
201 float *curve_point = &r_cubic_array[i * curve_point_size];
202
203 for (int j = 0; j < 3; j++) {
204 float *bez = &curve_point[j * POINT_DIM];
205 madd_v3_v3v3fl(bezt->vec[j], gps->boundbox_min, bez, diag_length / COORD_FITTING_INFLUENCE);
206 }
207
208 float *ctrl_point = &curve_point[1 * POINT_DIM];
209 cpt->pressure = ctrl_point[3] * diag_length;
210 cpt->strength = ctrl_point[4] * diag_length;
211 mul_v4_v4fl(cpt->vert_color, &ctrl_point[5], diag_length);
212
213 /* default handle type */
214 bezt->h1 = HD_ALIGN;
215 bezt->h2 = HD_ALIGN;
216
217 cpt->point_index = r_cubic_orig_index[i];
218 }
219
220 if (r_corners_index_len > 0 && r_corners_index_array != nullptr) {
221 int start = 0, end = r_corners_index_len;
222 if ((r_corners_index_len > 1) && (calc_flag & CURVE_FIT_CALC_CYCLIC) == 0) {
223 start = 1;
224 end = r_corners_index_len - 1;
225 }
226 for (int i = start; i < end; i++) {
227 bGPDcurve_point *cpt = &editcurve->curve_points[r_corners_index_array[i]];
228 BezTriple *bezt = &cpt->bezt;
229 bezt->h1 = HD_FREE;
230 bezt->h2 = HD_FREE;
231 }
232 }
233
234 MEM_freeN(points);
235 if (r_cubic_array) {
236 free(r_cubic_array);
237 }
238 if (r_corners_index_array) {
239 free(r_corners_index_array);
240 }
241 if (r_cubic_orig_index) {
242 free(r_cubic_orig_index);
243 }
244
245#undef POINT_DIM
246 return editcurve;
247}
248
250 bGPDstroke *gps,
251 bGPDcurve *gpc)
252{
253 if (gps->flag & GP_STROKE_SELECT) {
254 gpc->flag |= GP_CURVE_SELECT;
255
256 for (int i = 0; i < gpc->tot_curve_points; i++) {
257 bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
258 bGPDspoint *pt = &gps->points[gpc_pt->point_index];
259 if (pt->flag & GP_SPOINT_SELECT) {
260 gpc_pt->flag |= GP_CURVE_POINT_SELECT;
261 BEZT_SEL_ALL(&gpc_pt->bezt);
262 }
263 else {
264 gpc_pt->flag &= ~GP_CURVE_POINT_SELECT;
265 BEZT_DESEL_ALL(&gpc_pt->bezt);
266 }
267 }
268 }
269 else {
270 gpc->flag &= ~GP_CURVE_SELECT;
272 }
273}
274
276{
277 if (gps == nullptr || gps->editcurve == nullptr) {
278 return;
279 }
280
281 bool changed = false;
282 bGPDcurve *gpc = gps->editcurve;
283 if (gpc->tot_curve_points < 2) {
284 return;
285 }
286
287 if (gpc->tot_curve_points == 1) {
289 &(gpc->curve_points[0].bezt), nullptr, &(gpc->curve_points[0].bezt), false, 0);
291 }
292
293 for (int i = 1; i < gpc->tot_curve_points - 1; i++) {
294 bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
295 bGPDcurve_point *gpc_pt_prev = &gpc->curve_points[i - 1];
296 bGPDcurve_point *gpc_pt_next = &gpc->curve_points[i + 1];
297 /* update handle if point or neighbor is selected */
298 if (gpc_pt->flag & GP_CURVE_POINT_SELECT || gpc_pt_prev->flag & GP_CURVE_POINT_SELECT ||
299 gpc_pt_next->flag & GP_CURVE_POINT_SELECT)
300 {
301 BezTriple *bezt = &gpc_pt->bezt;
302 BezTriple *bezt_prev = &gpc_pt_prev->bezt;
303 BezTriple *bezt_next = &gpc_pt_next->bezt;
304
305 BKE_nurb_handle_calc(bezt, bezt_prev, bezt_next, false, 0);
306 changed = true;
307 }
308 }
309
310 bGPDcurve_point *gpc_first = &gpc->curve_points[0];
311 bGPDcurve_point *gpc_last = &gpc->curve_points[gpc->tot_curve_points - 1];
312 bGPDcurve_point *gpc_first_next = &gpc->curve_points[1];
313 bGPDcurve_point *gpc_last_prev = &gpc->curve_points[gpc->tot_curve_points - 2];
314 if (gps->flag & GP_STROKE_CYCLIC) {
315 if (gpc_first->flag & GP_CURVE_POINT_SELECT || gpc_last->flag & GP_CURVE_POINT_SELECT) {
316 BezTriple *bezt_first = &gpc_first->bezt;
317 BezTriple *bezt_last = &gpc_last->bezt;
318 BezTriple *bezt_first_next = &gpc_first_next->bezt;
319 BezTriple *bezt_last_prev = &gpc_last_prev->bezt;
320
321 BKE_nurb_handle_calc(bezt_first, bezt_last, bezt_first_next, false, 0);
322 BKE_nurb_handle_calc(bezt_last, bezt_last_prev, bezt_first, false, 0);
323 changed = true;
324 }
325 }
326 else {
327 if (gpc_first->flag & GP_CURVE_POINT_SELECT || gpc_last->flag & GP_CURVE_POINT_SELECT) {
328 BezTriple *bezt_first = &gpc_first->bezt;
329 BezTriple *bezt_last = &gpc_last->bezt;
330 BezTriple *bezt_first_next = &gpc_first_next->bezt;
331 BezTriple *bezt_last_prev = &gpc_last_prev->bezt;
332
333 BKE_nurb_handle_calc(bezt_first, nullptr, bezt_first_next, false, 0);
334 BKE_nurb_handle_calc(bezt_last, bezt_last_prev, nullptr, false, 0);
335 changed = true;
336 }
337 }
338
339 if (changed) {
341 }
342}
343
344/* Helper: count how many new curve points must be generated. */
346{
347 int count = 0;
348 for (int i = 0; i < gpc->tot_curve_points - 1; i++) {
349 bGPDcurve_point *cpt = &gpc->curve_points[i];
350 bGPDcurve_point *cpt_next = &gpc->curve_points[i + 1];
351
352 if (cpt->flag & GP_CURVE_POINT_SELECT && cpt_next->flag & GP_CURVE_POINT_SELECT) {
353 count++;
354 }
355 }
356
357 if (is_cyclic) {
358 bGPDcurve_point *cpt = &gpc->curve_points[0];
359 bGPDcurve_point *cpt_next = &gpc->curve_points[gpc->tot_curve_points - 1];
360
361 if (cpt->flag & GP_CURVE_POINT_SELECT && cpt_next->flag & GP_CURVE_POINT_SELECT) {
362 count++;
363 }
364 }
365
366 return count;
367}
368
370 bGPDcurve_point *cpt_end,
371 bGPDcurve_point *cpt_new)
372{
373 BezTriple *bezt_start = &cpt_start->bezt;
374 BezTriple *bezt_end = &cpt_end->bezt;
375 BezTriple *bezt_new = &cpt_new->bezt;
376 for (int axis = 0; axis < 3; axis++) {
377 float p0, p1, p2, p3, m0, m1, q0, q1, b;
378 p0 = bezt_start->vec[1][axis];
379 p1 = bezt_start->vec[2][axis];
380 p2 = bezt_end->vec[0][axis];
381 p3 = bezt_end->vec[1][axis];
382
383 m0 = (p0 + p1) / 2;
384 q0 = (p0 + 2 * p1 + p2) / 4;
385 b = (p0 + 3 * p1 + 3 * p2 + p3) / 8;
386 q1 = (p1 + 2 * p2 + p3) / 4;
387 m1 = (p2 + p3) / 2;
388
389 bezt_new->vec[0][axis] = q0;
390 bezt_new->vec[2][axis] = q1;
391 bezt_new->vec[1][axis] = b;
392
393 bezt_start->vec[2][axis] = m0;
394 bezt_end->vec[0][axis] = m1;
395 }
396
397 cpt_new->pressure = interpf(cpt_end->pressure, cpt_start->pressure, 0.5f);
398 cpt_new->strength = interpf(cpt_end->strength, cpt_start->strength, 0.5f);
399 interp_v4_v4v4(cpt_new->vert_color, cpt_start->vert_color, cpt_end->vert_color, 0.5f);
400}
401
403{
404 bGPDcurve *gpc = gps->editcurve;
405 if (gpc == nullptr || gpc->tot_curve_points < 2) {
406 return;
407 }
408 bool is_cyclic = gps->flag & GP_STROKE_CYCLIC;
409
410 /* repeat for number of cuts */
411 for (int s = 0; s < cuts; s++) {
412 int old_tot_curve_points = gpc->tot_curve_points;
413 int new_num_curve_points = gpencil_editcurve_subdivide_count(gpc, is_cyclic);
414 if (new_num_curve_points == 0) {
415 break;
416 }
417 int new_tot_curve_points = old_tot_curve_points + new_num_curve_points;
418
419 bGPDcurve_point *temp_curve_points = (bGPDcurve_point *)MEM_callocN(
420 sizeof(bGPDcurve_point) * new_tot_curve_points, __func__);
421
422 bool prev_subdivided = false;
423 int j = 0;
424 for (int i = 0; i < old_tot_curve_points - 1; i++, j++) {
425 bGPDcurve_point *cpt = &gpc->curve_points[i];
426 bGPDcurve_point *cpt_next = &gpc->curve_points[i + 1];
427
428 if (cpt->flag & GP_CURVE_POINT_SELECT && cpt_next->flag & GP_CURVE_POINT_SELECT) {
429 bGPDcurve_point *cpt_new = &temp_curve_points[j + 1];
430 gpencil_editcurve_subdivide_curve_segment(cpt, cpt_next, cpt_new);
431
432 memcpy(&temp_curve_points[j], cpt, sizeof(bGPDcurve_point));
433 memcpy(&temp_curve_points[j + 2], cpt_next, sizeof(bGPDcurve_point));
434
435 cpt_new->flag |= GP_CURVE_POINT_SELECT;
436 cpt_new->bezt.h1 = HD_ALIGN;
437 cpt_new->bezt.h2 = HD_ALIGN;
438 BEZT_SEL_ALL(&cpt_new->bezt);
439
440 prev_subdivided = true;
441 j++;
442 }
443 else if (!prev_subdivided) {
444 memcpy(&temp_curve_points[j], cpt, sizeof(bGPDcurve_point));
445 prev_subdivided = false;
446 }
447 else {
448 prev_subdivided = false;
449 }
450 }
451
452 if (is_cyclic) {
453 bGPDcurve_point *cpt = &gpc->curve_points[old_tot_curve_points - 1];
454 bGPDcurve_point *cpt_next = &gpc->curve_points[0];
455
456 if (cpt->flag & GP_CURVE_POINT_SELECT && cpt_next->flag & GP_CURVE_POINT_SELECT) {
457 bGPDcurve_point *cpt_new = &temp_curve_points[j + 1];
458 gpencil_editcurve_subdivide_curve_segment(cpt, cpt_next, cpt_new);
459
460 memcpy(&temp_curve_points[j], cpt, sizeof(bGPDcurve_point));
461 memcpy(&temp_curve_points[0], cpt_next, sizeof(bGPDcurve_point));
462
463 cpt_new->flag |= GP_CURVE_POINT_SELECT;
464 cpt_new->bezt.h1 = HD_ALIGN;
465 cpt_new->bezt.h2 = HD_ALIGN;
466 BEZT_SEL_ALL(&cpt_new->bezt);
467 }
468 else if (!prev_subdivided) {
469 memcpy(&temp_curve_points[j], cpt, sizeof(bGPDcurve_point));
470 }
471 }
472 else {
473 bGPDcurve_point *cpt = &gpc->curve_points[old_tot_curve_points - 1];
474 memcpy(&temp_curve_points[j], cpt, sizeof(bGPDcurve_point));
475 }
476
478 gpc->curve_points = temp_curve_points;
479 gpc->tot_curve_points = new_tot_curve_points;
480 }
481}
482
void BKE_nurb_handle_calc(BezTriple *bezt, BezTriple *prev, BezTriple *next, bool is_fcurve, char smoothing)
Definition curve.cc:3938
struct bGPDcurve * BKE_gpencil_stroke_editcurve_new(int tot_curve_points)
General operations, lookup, etc. for materials.
#define BLI_assert(a)
Definition BLI_assert.h:50
void BLI_kdtree_nd_ free(KDTree *tree)
MINLINE float interpf(float target, float origin, float t)
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:45
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE float normalize_v3_length(float n[3], float unit_length)
unsigned int uint
Object groups, one object can be in many groups at once.
#define BEZT_SEL_ALL(bezt)
#define BEZT_DESEL_ALL(bezt)
@ HD_VECT
@ HD_FREE
@ HD_ALIGN
@ GP_STROKE_NEEDS_CURVE_UPDATE
@ GP_CURVE_POINT_SELECT
Read Guarded memory(de)allocation.
local_group_size(16, 16) .push_constant(Type b
static bool is_cyclic(const Nurb *nu)
draw_view in_light_buf[] float
void BKE_gpencil_editcurve_stroke_sync_selection(bGPdata *, bGPDstroke *gps, bGPDcurve *gpc)
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)
static bGPDcurve * gpencil_stroke_editcurve_generate_edgecases(bGPDstroke *gps, const float stroke_radius)
#define COORD_FITTING_INFLUENCE
static void gpencil_editstroke_deselect_all(bGPDcurve *gpc)
bGPDcurve * BKE_gpencil_stroke_editcurve_generate(bGPDstroke *gps, const float error_threshold, const float corner_angle, const float stroke_radius)
void BKE_gpencil_editcurve_recalculate_handles(bGPDstroke *gps)
#define POINT_DIM
static int gpencil_editcurve_subdivide_count(bGPDcurve *gpc, bool is_cyclic)
int count
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
float vec[3][3]
bGPDcurve_point * curve_points
struct bGPDcurve * editcurve