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