Blender  V3.3
curve_bevel.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
10 #include <string.h>
11 
12 #include "BLI_alloca.h"
13 #include "BLI_listbase.h"
14 #include "BLI_math_base.h"
15 
16 #include "MEM_guardedalloc.h"
17 
18 #include "DNA_curve_types.h"
19 #include "DNA_curveprofile_types.h"
20 #include "DNA_object_types.h"
21 
22 #include "BKE_curve.h"
23 #include "BKE_curveprofile.h"
24 #include "BKE_displist.h"
25 
26 typedef enum CurveBevelFillType {
27  BACK = 0,
32 
34 {
35  if (!(curve->flag & (CU_FRONT | CU_BACK))) {
36  return FULL;
37  }
38  if ((curve->flag & CU_FRONT) && (curve->flag & CU_BACK)) {
39  return HALF;
40  }
41 
42  return (curve->flag & CU_FRONT) ? FRONT : BACK;
43 }
44 
45 static void bevel_quarter_fill(const Curve *curve,
46  float *quarter_coords_x,
47  float *quarter_coords_y)
48 {
50  float angle = 0.0f;
51  const float dangle = (float)M_PI_2 / (curve->bevresol + 1);
52  for (int i = 0; i < curve->bevresol + 1; i++) {
53  quarter_coords_x[i] = (float)(cosf(angle) * (curve->bevel_radius));
54  quarter_coords_y[i] = (float)(sinf(angle) * (curve->bevel_radius));
55  angle += dangle;
56  }
57  }
58  else {
59  /* The curve profile evaluation should be done when the resolution is set. */
62 
63  /* If there aren't enough samples, the curveprofile won't
64  * sample the start vertex, so set it manually instead. */
65  quarter_coords_x[0] = curve->bevel_radius;
66  quarter_coords_y[0] = 0.0f;
67  for (int i = 1; i < curve->bevresol + 1; i++) {
68  quarter_coords_x[i] = (float)(curve->bevel_profile->segments[i].x * (curve->bevel_radius));
69  quarter_coords_y[i] = (float)(curve->bevel_profile->segments[i].y * (curve->bevel_radius));
70  }
71  }
72 }
73 
75  ListBase *disp,
76  const bool use_extrude,
77  const CurveBevelFillType fill_type)
78 {
79  DispList *dl = MEM_callocN(sizeof(DispList), __func__);
80 
81  /* Calculate the profile of the bevel once to reuse it for each quarter. We will need
82  * to flip around the indices for every other section in order to build around the circle
83  * in a consistent direction.
84  *
85  * These should be small enough for stack allocations because the current limit
86  * for #Curve.bevresol is 32. */
87  float *quarter_coords_x = alloca(sizeof(float) * (cu->bevresol + 1));
88  float *quarter_coords_y = alloca(sizeof(float) * (cu->bevresol + 1));
89  bevel_quarter_fill(cu, quarter_coords_x, quarter_coords_y);
90 
91  int nr;
92  if (fill_type == FULL) {
93  /* The full loop. */
94  nr = 4 * cu->bevresol + (use_extrude ? 6 : 4);
96  }
97  else if (fill_type == HALF) {
98  /* Half the loop. */
99  nr = 2 * (cu->bevresol + 1) + (use_extrude ? 2 : 1);
101  }
102  else {
103  /* One quarter of the loop (just front or back). */
104  nr = use_extrude ? cu->bevresol + 3 : cu->bevresol + 2;
105  dl->flag = (fill_type == FRONT) ? DL_FRONT_CURVE : DL_BACK_CURVE;
106  }
107 
108  dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), __func__);
109  BLI_addtail(disp, dl);
110  /* Use a different type depending on whether the loop is complete or not. */
111  dl->type = (fill_type == FULL) ? DL_POLY : DL_SEGM;
112  dl->parts = 1;
113  dl->nr = nr;
114 
115  float *fp = dl->verts;
116 
117  /* Build the back section. */
118  if (ELEM(fill_type, BACK, HALF, FULL)) {
119  /* Add the bottom vertex. */
120  fp[0] = 0.0f;
121  fp[1] = 0.0f;
122  fp[2] = -cu->extrude - cu->bevel_radius;
123  fp += 3;
124 
125  for (int i = cu->bevresol; i >= 0; i--) {
126  fp[0] = 0.0f;
127  fp[1] = quarter_coords_x[i];
128  fp[2] = -quarter_coords_y[i] - cu->extrude;
129  fp += 3;
130  }
131  }
132 
133  /* Add the extrusion if we're only building either the back or the front. */
134  if (use_extrude && ELEM(fill_type, FRONT, BACK)) {
135  fp[0] = 0.0f;
136  fp[1] = cu->bevel_radius;
137  fp[2] = (fill_type == FRONT) ? -cu->extrude : cu->extrude;
138  fp += 3;
139  }
140 
141  /* Build the front section. */
142  if (ELEM(fill_type, FRONT, HALF, FULL)) {
143  /* Don't duplicate the last back vertex. */
144  const int front_start = (!use_extrude && ELEM(fill_type, HALF, FULL)) ? 1 : 0;
145  for (int i = front_start; i < cu->bevresol + 1; i++) {
146  fp[0] = 0.0f;
147  fp[1] = quarter_coords_x[i];
148  fp[2] = quarter_coords_y[i] + cu->extrude;
149  fp += 3;
150  }
151  /* Add the top vertex. */
152  fp[0] = 0.0f;
153  fp[1] = 0.0f;
154  fp[2] = cu->extrude + cu->bevel_radius;
155  fp += 3;
156  }
157 
158  /* Build the other half only if we're building the full loop. */
159  if (fill_type == FULL) {
160  for (int i = cu->bevresol; i > 0; i--) {
161  fp[0] = 0.0f;
162  fp[1] = -quarter_coords_x[i];
163  fp[2] = quarter_coords_y[i] + cu->extrude;
164  fp += 3;
165  }
166 
167  if (use_extrude) {
168  /* Add the extrusion. */
169  fp[0] = 0.0f;
170  fp[1] = -cu->bevel_radius;
171  fp[2] = cu->extrude;
172  fp += 3;
173  }
174 
175  for (int i = 0; i < cu->bevresol + 1; i++) {
176  fp[0] = 0.0f;
177  fp[1] = -quarter_coords_x[i];
178  fp[2] = -quarter_coords_y[i] - cu->extrude;
179  fp += 3;
180  }
181  }
182 }
183 
184 static void curve_bevel_make_full_circle(const Curve *cu, ListBase *disp)
185 {
186  const int nr = 4 + 2 * cu->bevresol;
187 
188  DispList *dl = MEM_callocN(sizeof(DispList), __func__);
189  dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), __func__);
190  BLI_addtail(disp, dl);
191  dl->type = DL_POLY;
192  dl->parts = 1;
193  dl->flag = DL_BACK_CURVE;
194  dl->nr = nr;
195 
196  float *fp = dl->verts;
197  const float dangle = (2.0f * (float)M_PI / (nr));
198  float angle = -(nr - 1) * dangle;
199 
200  for (int i = 0; i < nr; i++) {
201  fp[0] = 0.0;
202  fp[1] = (cosf(angle) * (cu->bevel_radius));
203  fp[2] = (sinf(angle) * (cu->bevel_radius)) - cu->extrude;
204  angle += dangle;
205  fp += 3;
206  }
207 }
208 
209 static void curve_bevel_make_only_extrude(const Curve *cu, ListBase *disp)
210 {
211  DispList *dl = MEM_callocN(sizeof(DispList), __func__);
212  dl->verts = MEM_malloc_arrayN(2, sizeof(float[3]), __func__);
213  BLI_addtail(disp, dl);
214  dl->type = DL_SEGM;
215  dl->parts = 1;
217  dl->nr = 2;
218 
219  float *fp = dl->verts;
220  fp[0] = fp[1] = 0.0;
221  fp[2] = -cu->extrude;
222  fp[3] = fp[4] = 0.0;
223  fp[5] = cu->extrude;
224 }
225 
226 static void curve_bevel_make_from_object(const Curve *cu, ListBase *disp)
227 {
228  if (cu->bevobj == NULL) {
229  return;
230  }
231  if (cu->bevobj->type != OB_CURVES_LEGACY) {
232  return;
233  }
234 
235  Curve *bevcu = cu->bevobj->data;
236  if (bevcu->extrude == 0.0f && bevcu->bevel_radius == 0.0f) {
237  ListBase bevdisp = {NULL, NULL};
238  float facx = cu->bevobj->scale[0];
239  float facy = cu->bevobj->scale[1];
240 
241  DispList *dl;
242  if (cu->bevobj->runtime.curve_cache) {
243  dl = cu->bevobj->runtime.curve_cache->disp.first;
244  }
245  else {
247  dl = NULL;
248  }
249 
250  while (dl) {
251  if (ELEM(dl->type, DL_POLY, DL_SEGM)) {
252  DispList *dlnew = MEM_mallocN(sizeof(DispList), __func__);
253  *dlnew = *dl;
254  dlnew->verts = MEM_malloc_arrayN(dl->parts * dl->nr, sizeof(float[3]), __func__);
255  memcpy(dlnew->verts, dl->verts, sizeof(float[3]) * dl->parts * dl->nr);
256 
257  if (dlnew->type == DL_SEGM) {
258  dlnew->flag |= (DL_FRONT_CURVE | DL_BACK_CURVE);
259  }
260 
261  BLI_addtail(disp, dlnew);
262  float *fp = dlnew->verts;
263  int nr = dlnew->parts * dlnew->nr;
264  while (nr--) {
265  fp[2] = fp[1] * facy;
266  fp[1] = -fp[0] * facx;
267  fp[0] = 0.0;
268  fp += 3;
269  }
270  }
271  dl = dl->next;
272  }
273 
274  BKE_displist_free(&bevdisp);
275  }
276 }
277 
279 {
280  ListBase bevel_shape = {NULL, NULL};
281 
283  if (curve->bevobj != NULL) {
284  curve_bevel_make_from_object(curve, &bevel_shape);
285  }
286  }
287  else {
288  const bool use_extrude = curve->extrude != 0.0f;
289  const bool use_bevel = curve->bevel_radius != 0.0f;
290  /* Pass. */
291  if (use_extrude && !use_bevel) {
292  curve_bevel_make_only_extrude(curve, &bevel_shape);
293  }
294  else if (use_extrude || use_bevel) {
296 
297  if (!use_extrude && fill_type == FULL && curve->bevel_mode == CU_BEV_MODE_ROUND) {
298  curve_bevel_make_full_circle(curve, &bevel_shape);
299  }
300  else {
301  /* The general case for nonzero extrusion or an incomplete loop. */
302  curve_bevel_make_extrude_and_fill(curve, &bevel_shape, use_extrude, fill_type);
303  }
304  }
305  }
306 
307  return bevel_shape;
308 }
typedef float(TangentPoint)[2]
display list (or rather multi purpose list) stuff.
void BKE_displist_free(struct ListBase *lb)
Definition: displist.cc:69
@ DL_BACK_CURVE
Definition: BKE_displist.h:41
@ DL_FRONT_CURVE
Definition: BKE_displist.h:40
@ DL_POLY
Definition: BKE_displist.h:20
@ DL_SEGM
Definition: BKE_displist.h:22
#define BLI_assert(a)
Definition: BLI_assert.h:46
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
#define M_PI_2
Definition: BLI_math_base.h:23
#define M_PI
Definition: BLI_math_base.h:20
#define ELEM(...)
@ CU_BEV_MODE_OBJECT
@ CU_BEV_MODE_ROUND
@ CU_FRONT
@ CU_BACK
Object is a sort of wrapper for general info.
@ OB_CURVES_LEGACY
Read Guarded memory(de)allocation.
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
#define sinf(x)
Definition: cuda/compat.h:102
#define cosf(x)
Definition: cuda/compat.h:101
static void curve_bevel_make_extrude_and_fill(const Curve *cu, ListBase *disp, const bool use_extrude, const CurveBevelFillType fill_type)
Definition: curve_bevel.c:74
CurveBevelFillType
Definition: curve_bevel.c:26
@ HALF
Definition: curve_bevel.c:29
@ FRONT
Definition: curve_bevel.c:28
@ BACK
Definition: curve_bevel.c:27
@ FULL
Definition: curve_bevel.c:30
static void curve_bevel_make_only_extrude(const Curve *cu, ListBase *disp)
Definition: curve_bevel.c:209
static CurveBevelFillType curve_bevel_get_fill_type(const Curve *curve)
Definition: curve_bevel.c:33
ListBase BKE_curve_bevel_make(const Curve *curve)
Definition: curve_bevel.c:278
static void curve_bevel_make_from_object(const Curve *cu, ListBase *disp)
Definition: curve_bevel.c:226
static void bevel_quarter_fill(const Curve *curve, float *quarter_coords_x, float *quarter_coords_y)
Definition: curve_bevel.c:45
static void curve_bevel_make_full_circle(const Curve *cu, ListBase *disp)
Definition: curve_bevel.c:184
Curve curve
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:34
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
ListBase disp
Definition: BKE_curve.h:33
CurveProfilePoint * segments
struct Object * bevobj
struct CurveProfile * bevel_profile
short bevresol
float extrude
float bevel_radius
char bevel_mode
short type
Definition: BKE_displist.h:55
float * verts
Definition: BKE_displist.h:58
struct DispList * next
Definition: BKE_displist.h:54
short flag
Definition: BKE_displist.h:55
void * first
Definition: DNA_listBase.h:31
struct CurveCache * curve_cache
float scale[3]
Object_Runtime runtime
void * data