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