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) 2001-2002 by NaN Holding BV.
17 * All rights reserved.
18 */
19
20 /** \file
21 * \ingroup bke
22 *
23 * Deform coordinates by a curve object (used by modifier).
24 */
25
26 #include <math.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "BLI_math.h"
32 #include "BLI_utildefines.h"
33
34 #include "DNA_curve_types.h"
35 #include "DNA_meshdata_types.h"
36 #include "DNA_object_types.h"
37
38 #include "BKE_anim_path.h"
39 #include "BKE_curve.h"
40 #include "BKE_editmesh.h"
41 #include "BKE_lattice.h"
42 #include "BKE_modifier.h"
43
44 #include "BKE_deform.h"
45
46 /* -------------------------------------------------------------------- */
47 /** \name Curve Deform Internal Utilities
48 * \{ */
49
50 /**
51 * Calculations is in local space of deformed object
52 * so we store matrices to transform points to/from local-space.
53 */
54 typedef struct {
55 float dmin[3], dmax[3];
56 float curvespace[4][4], objectspace[4][4], objectspace3[3][3];
57 int no_rot_axis;
58 } CurveDeform;
59
init_curve_deform(const Object * ob_curve,const Object * ob_target,CurveDeform * cd)60 static void init_curve_deform(const Object *ob_curve, const Object *ob_target, CurveDeform *cd)
61 {
62 float imat[4][4];
63 invert_m4_m4(imat, ob_target->obmat);
64 mul_m4_m4m4(cd->objectspace, imat, ob_curve->obmat);
65 invert_m4_m4(cd->curvespace, cd->objectspace);
66 copy_m3_m4(cd->objectspace3, cd->objectspace);
67 cd->no_rot_axis = 0;
68 }
69
70 /**
71 * This makes sure we can extend for non-cyclic.
72 *
73 * \return Success.
74 */
where_on_path_deform(const Object * ob_curve,float ctime,float r_vec[4],float r_dir[3],float r_quat[4],float * r_radius)75 static bool where_on_path_deform(const Object *ob_curve,
76 float ctime,
77 float r_vec[4],
78 float r_dir[3],
79 float r_quat[4],
80 float *r_radius)
81 {
82 BevList *bl;
83 float ctime1;
84 int cycl = 0;
85
86 /* test for cyclic */
87 bl = ob_curve->runtime.curve_cache->bev.first;
88 if (!bl->nr) {
89 return false;
90 }
91 if (bl->poly > -1) {
92 cycl = 1;
93 }
94
95 if (cycl == 0) {
96 ctime1 = CLAMPIS(ctime, 0.0f, 1.0f);
97 }
98 else {
99 ctime1 = ctime;
100 }
101
102 /* vec needs 4 items */
103 if (where_on_path(ob_curve, ctime1, r_vec, r_dir, r_quat, r_radius, NULL)) {
104
105 if (cycl == 0) {
106 Path *path = ob_curve->runtime.curve_cache->path;
107 float dvec[3];
108
109 if (ctime < 0.0f) {
110 sub_v3_v3v3(dvec, path->data[1].vec, path->data[0].vec);
111 mul_v3_fl(dvec, ctime * (float)path->len);
112 add_v3_v3(r_vec, dvec);
113 if (r_quat) {
114 copy_qt_qt(r_quat, path->data[0].quat);
115 }
116 if (r_radius) {
117 *r_radius = path->data[0].radius;
118 }
119 }
120 else if (ctime > 1.0f) {
121 sub_v3_v3v3(dvec, path->data[path->len - 1].vec, path->data[path->len - 2].vec);
122 mul_v3_fl(dvec, (ctime - 1.0f) * (float)path->len);
123 add_v3_v3(r_vec, dvec);
124 if (r_quat) {
125 copy_qt_qt(r_quat, path->data[path->len - 1].quat);
126 }
127 if (r_radius) {
128 *r_radius = path->data[path->len - 1].radius;
129 }
130 /* weight - not used but could be added */
131 }
132 }
133 return true;
134 }
135 return false;
136 }
137
138 /**
139 * For each point, rotate & translate to curve use path, since it has constant distances.
140 *
141 * \param co: local coord, result local too.
142 * \param r_quat: returns quaternion for rotation,
143 * using #CurveDeform.no_rot_axis axis is using another define.
144 */
calc_curve_deform(const Object * ob_curve,float co[3],const short axis,const CurveDeform * cd,float r_quat[4])145 static bool calc_curve_deform(
146 const Object *ob_curve, float co[3], const short axis, const CurveDeform *cd, float r_quat[4])
147 {
148 Curve *cu = ob_curve->data;
149 float fac, loc[4], dir[3], new_quat[4], radius;
150 short index;
151 const bool is_neg_axis = (axis > 2);
152
153 if (ob_curve->runtime.curve_cache == NULL) {
154 /* Happens with a cyclic dependencies. */
155 return false;
156 }
157
158 if (ob_curve->runtime.curve_cache->path == NULL) {
159 return false; /* happens on append, cyclic dependencies and empty curves */
160 }
161
162 /* options */
163 if (is_neg_axis) {
164 index = axis - 3;
165 if (cu->flag & CU_STRETCH) {
166 fac = -(co[index] - cd->dmax[index]) / (cd->dmax[index] - cd->dmin[index]);
167 }
168 else {
169 fac = -(co[index] - cd->dmax[index]) / (ob_curve->runtime.curve_cache->path->totdist);
170 }
171 }
172 else {
173 index = axis;
174 if (cu->flag & CU_STRETCH) {
175 fac = (co[index] - cd->dmin[index]) / (cd->dmax[index] - cd->dmin[index]);
176 }
177 else {
178 if (LIKELY(ob_curve->runtime.curve_cache->path->totdist > FLT_EPSILON)) {
179 fac = +(co[index] - cd->dmin[index]) / (ob_curve->runtime.curve_cache->path->totdist);
180 }
181 else {
182 fac = 0.0f;
183 }
184 }
185 }
186
187 if (where_on_path_deform(ob_curve, fac, loc, dir, new_quat, &radius)) { /* returns OK */
188 float quat[4], cent[3];
189
190 if (cd->no_rot_axis) { /* set by caller */
191
192 /* This is not exactly the same as 2.4x, since the axis is having rotation removed rather
193 * than changing the axis before calculating the tilt but serves much the same purpose. */
194 float dir_flat[3] = {0, 0, 0}, q[4];
195 copy_v3_v3(dir_flat, dir);
196 dir_flat[cd->no_rot_axis - 1] = 0.0f;
197
198 normalize_v3(dir);
199 normalize_v3(dir_flat);
200
201 rotation_between_vecs_to_quat(q, dir, dir_flat); /* Could this be done faster? */
202
203 mul_qt_qtqt(new_quat, q, new_quat);
204 }
205
206 /* Logic for 'cent' orientation *
207 *
208 * The way 'co' is copied to 'cent' may seem to have no meaning, but it does.
209 *
210 * Use a curve modifier to stretch a cube out, color each side RGB,
211 * positive side light, negative dark.
212 * view with X up (default), from the angle that you can see 3 faces RGB colors (light),
213 * anti-clockwise
214 * Notice X,Y,Z Up all have light colors and each ordered CCW.
215 *
216 * Now for Neg Up XYZ, the colors are all dark, and ordered clockwise - Campbell
217 *
218 * note: moved functions into quat_apply_track/vec_apply_track
219 * */
220 copy_qt_qt(quat, new_quat);
221 copy_v3_v3(cent, co);
222
223 /* zero the axis which is not used,
224 * the big block of text above now applies to these 3 lines */
225 quat_apply_track(
226 quat,
227 axis,
228 (axis == 0 || axis == 2) ? 1 : 0); /* up flag is a dummy, set so no rotation is done */
229 vec_apply_track(cent, axis);
230 cent[index] = 0.0f;
231
232 /* scale if enabled */
233 if (cu->flag & CU_PATH_RADIUS) {
234 mul_v3_fl(cent, radius);
235 }
236
237 /* local rotation */
238 normalize_qt(quat);
239 mul_qt_v3(quat, cent);
240
241 /* translation */
242 add_v3_v3v3(co, cent, loc);
243
244 if (r_quat) {
245 copy_qt_qt(r_quat, quat);
246 }
247
248 return true;
249 }
250 return false;
251 }
252
253 /** \} */
254
255 /* -------------------------------------------------------------------- */
256 /** \name Curve Deform #BKE_curve_deform_coords API
257 *
258 * #BKE_curve_deform and related functions.
259 * \{ */
260
curve_deform_coords_impl(const Object * ob_curve,const Object * ob_target,float (* vert_coords)[3],const int vert_coords_len,const MDeformVert * dvert,const int defgrp_index,const short flag,const short defaxis,BMEditMesh * em_target)261 static void curve_deform_coords_impl(const Object *ob_curve,
262 const Object *ob_target,
263 float (*vert_coords)[3],
264 const int vert_coords_len,
265 const MDeformVert *dvert,
266 const int defgrp_index,
267 const short flag,
268 const short defaxis,
269 BMEditMesh *em_target)
270 {
271 Curve *cu;
272 int a;
273 CurveDeform cd;
274 const bool is_neg_axis = (defaxis > 2);
275 const bool invert_vgroup = (flag & MOD_CURVE_INVERT_VGROUP) != 0;
276 bool use_dverts = false;
277 int cd_dvert_offset;
278
279 if (ob_curve->type != OB_CURVE) {
280 return;
281 }
282
283 cu = ob_curve->data;
284
285 init_curve_deform(ob_curve, ob_target, &cd);
286
287 if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
288 /* Dummy bounds. */
289 if (is_neg_axis == false) {
290 cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = 0.0f;
291 cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 1.0f;
292 }
293 else {
294 /* Negative, these bounds give a good rest position. */
295 cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = -1.0f;
296 cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 0.0f;
297 }
298 }
299 else {
300 /* Set mesh min/max bounds. */
301 INIT_MINMAX(cd.dmin, cd.dmax);
302 }
303
304 if (em_target != NULL) {
305 cd_dvert_offset = CustomData_get_offset(&em_target->bm->vdata, CD_MDEFORMVERT);
306 if (cd_dvert_offset != -1) {
307 use_dverts = true;
308 }
309 }
310 else {
311 if (dvert != NULL) {
312 use_dverts = true;
313 }
314 }
315
316 if (use_dverts) {
317 if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
318
319 #define DEFORM_OP(dvert) \
320 { \
321 const float weight = invert_vgroup ? 1.0f - BKE_defvert_find_weight(dvert, defgrp_index) : \
322 BKE_defvert_find_weight(dvert, defgrp_index); \
323 if (weight > 0.0f) { \
324 float vec[3]; \
325 mul_m4_v3(cd.curvespace, vert_coords[a]); \
326 copy_v3_v3(vec, vert_coords[a]); \
327 calc_curve_deform(ob_curve, vec, defaxis, &cd, NULL); \
328 interp_v3_v3v3(vert_coords[a], vert_coords[a], vec, weight); \
329 mul_m4_v3(cd.objectspace, vert_coords[a]); \
330 } \
331 } \
332 ((void)0)
333
334 if (em_target != NULL) {
335 BMIter iter;
336 BMVert *v;
337 BM_ITER_MESH_INDEX (v, &iter, em_target->bm, BM_VERTS_OF_MESH, a) {
338 dvert = BM_ELEM_CD_GET_VOID_P(v, cd_dvert_offset);
339 DEFORM_OP(dvert);
340 }
341 }
342 else {
343 for (a = 0; a < vert_coords_len; a++) {
344 DEFORM_OP(&dvert[a]);
345 }
346 }
347
348 #undef DEFORM_OP
349 }
350 else {
351
352 #define DEFORM_OP_MINMAX(dvert) \
353 { \
354 const float weight = invert_vgroup ? 1.0f - BKE_defvert_find_weight(dvert, defgrp_index) : \
355 BKE_defvert_find_weight(dvert, defgrp_index); \
356 if (weight > 0.0f) { \
357 mul_m4_v3(cd.curvespace, vert_coords[a]); \
358 minmax_v3v3_v3(cd.dmin, cd.dmax, vert_coords[a]); \
359 } \
360 } \
361 ((void)0)
362
363 /* already in 'cd.curvespace', prev for loop */
364 #define DEFORM_OP_CLAMPED(dvert) \
365 { \
366 const float weight = invert_vgroup ? 1.0f - BKE_defvert_find_weight(dvert, defgrp_index) : \
367 BKE_defvert_find_weight(dvert, defgrp_index); \
368 if (weight > 0.0f) { \
369 float vec[3]; \
370 copy_v3_v3(vec, vert_coords[a]); \
371 calc_curve_deform(ob_curve, vec, defaxis, &cd, NULL); \
372 interp_v3_v3v3(vert_coords[a], vert_coords[a], vec, weight); \
373 mul_m4_v3(cd.objectspace, vert_coords[a]); \
374 } \
375 } \
376 ((void)0)
377
378 if (em_target != NULL) {
379 BMIter iter;
380 BMVert *v;
381 BM_ITER_MESH_INDEX (v, &iter, em_target->bm, BM_VERTS_OF_MESH, a) {
382 dvert = BM_ELEM_CD_GET_VOID_P(v, cd_dvert_offset);
383 DEFORM_OP_MINMAX(dvert);
384 }
385
386 BM_ITER_MESH_INDEX (v, &iter, em_target->bm, BM_VERTS_OF_MESH, a) {
387 dvert = BM_ELEM_CD_GET_VOID_P(v, cd_dvert_offset);
388 DEFORM_OP_CLAMPED(dvert);
389 }
390 }
391 else {
392
393 for (a = 0; a < vert_coords_len; a++) {
394 DEFORM_OP_MINMAX(&dvert[a]);
395 }
396
397 for (a = 0; a < vert_coords_len; a++) {
398 DEFORM_OP_CLAMPED(&dvert[a]);
399 }
400 }
401 }
402
403 #undef DEFORM_OP_MINMAX
404 #undef DEFORM_OP_CLAMPED
405 }
406 else {
407 if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
408 for (a = 0; a < vert_coords_len; a++) {
409 mul_m4_v3(cd.curvespace, vert_coords[a]);
410 calc_curve_deform(ob_curve, vert_coords[a], defaxis, &cd, NULL);
411 mul_m4_v3(cd.objectspace, vert_coords[a]);
412 }
413 }
414 else {
415 for (a = 0; a < vert_coords_len; a++) {
416 mul_m4_v3(cd.curvespace, vert_coords[a]);
417 minmax_v3v3_v3(cd.dmin, cd.dmax, vert_coords[a]);
418 }
419
420 for (a = 0; a < vert_coords_len; a++) {
421 /* already in 'cd.curvespace', prev for loop */
422 calc_curve_deform(ob_curve, vert_coords[a], defaxis, &cd, NULL);
423 mul_m4_v3(cd.objectspace, vert_coords[a]);
424 }
425 }
426 }
427 }
428
BKE_curve_deform_coords(const Object * ob_curve,const Object * ob_target,float (* vert_coords)[3],const int vert_coords_len,const MDeformVert * dvert,const int defgrp_index,const short flag,const short defaxis)429 void BKE_curve_deform_coords(const Object *ob_curve,
430 const Object *ob_target,
431 float (*vert_coords)[3],
432 const int vert_coords_len,
433 const MDeformVert *dvert,
434 const int defgrp_index,
435 const short flag,
436 const short defaxis)
437 {
438 curve_deform_coords_impl(
439 ob_curve, ob_target, vert_coords, vert_coords_len, dvert, defgrp_index, flag, defaxis, NULL);
440 }
441
BKE_curve_deform_coords_with_editmesh(const Object * ob_curve,const Object * ob_target,float (* vert_coords)[3],const int vert_coords_len,const int defgrp_index,const short flag,const short defaxis,BMEditMesh * em_target)442 void BKE_curve_deform_coords_with_editmesh(const Object *ob_curve,
443 const Object *ob_target,
444 float (*vert_coords)[3],
445 const int vert_coords_len,
446 const int defgrp_index,
447 const short flag,
448 const short defaxis,
449 BMEditMesh *em_target)
450 {
451 curve_deform_coords_impl(ob_curve,
452 ob_target,
453 vert_coords,
454 vert_coords_len,
455 NULL,
456 defgrp_index,
457 flag,
458 defaxis,
459 em_target);
460 }
461
462 /**
463 * \param orco: Input vec and orco = local coord in curve space
464 * orco is original not-animated or deformed reference point.
465 *
466 * The result written in vec and r_mat.
467 */
BKE_curve_deform_co(const Object * ob_curve,const Object * ob_target,const float orco[3],float vec[3],const int no_rot_axis,float r_mat[3][3])468 void BKE_curve_deform_co(const Object *ob_curve,
469 const Object *ob_target,
470 const float orco[3],
471 float vec[3],
472 const int no_rot_axis,
473 float r_mat[3][3])
474 {
475 CurveDeform cd;
476 float quat[4];
477
478 if (ob_curve->type != OB_CURVE) {
479 unit_m3(r_mat);
480 return;
481 }
482
483 init_curve_deform(ob_curve, ob_target, &cd);
484 cd.no_rot_axis = no_rot_axis; /* option to only rotate for XY, for example */
485
486 copy_v3_v3(cd.dmin, orco);
487 copy_v3_v3(cd.dmax, orco);
488
489 mul_m4_v3(cd.curvespace, vec);
490
491 if (calc_curve_deform(ob_curve, vec, ob_target->trackflag, &cd, quat)) {
492 float qmat[3][3];
493
494 quat_to_mat3(qmat, quat);
495 mul_m3_m3m3(r_mat, qmat, cd.objectspace3);
496 }
497 else {
498 unit_m3(r_mat);
499 }
500
501 mul_m4_v3(cd.objectspace, vec);
502 }
503
504 /** \} */
505