Blender  V2.93
anim_path.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  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19 
24 #include "MEM_guardedalloc.h"
25 
26 #include <float.h>
27 
28 #include "DNA_curve_types.h"
29 #include "DNA_key_types.h"
30 #include "DNA_object_types.h"
31 
32 #include "BLI_math_vector.h"
33 
34 #include "BKE_anim_path.h"
35 #include "BKE_curve.h"
36 #include "BKE_key.h"
37 
38 #include "CLG_log.h"
39 
40 static CLG_LogRef LOG = {"bke.anim"};
41 
42 /* ******************************************************************** */
43 /* Curve Paths - for curve deforms and/or curve following */
44 
45 static int get_bevlist_seg_array_size(const BevList *bl)
46 {
47  if (bl->poly >= 0) {
48  /* Cyclic curve. */
49  return bl->nr;
50  }
51 
52  return bl->nr - 1;
53 }
54 
56 {
57  BLI_assert(curve_cache != NULL);
58 
59  BevList *bl = curve_cache->bev.first;
60 
61  BLI_assert(bl != NULL && bl->nr > 1);
62 
63  return get_bevlist_seg_array_size(bl);
64 }
65 
66 float BKE_anim_path_get_length(const CurveCache *curve_cache)
67 {
68  const int seg_size = BKE_anim_path_get_array_size(curve_cache);
69  return curve_cache->anim_path_accum_length[seg_size - 1];
70 }
71 
73 {
74  if (ob == NULL || ob->type != OB_CURVE) {
75  return;
76  }
77  if (ob->runtime.curve_cache == NULL) {
78  CLOG_WARN(&LOG, "No curve cache!");
79  return;
80  }
81  /* We only use the first curve. */
82  BevList *bl = ob->runtime.curve_cache->bev.first;
83  if (bl == NULL || !bl->nr) {
84  CLOG_WARN(&LOG, "No bev list data!");
85  return;
86  }
87 
88  /* Free old data. */
91  }
92 
93  /* We assume that we have at least two points.
94  * If there is less than two points in the curve,
95  * no BevList should have been generated.
96  */
97  BLI_assert(bl->nr > 1);
98 
99  const int seg_size = get_bevlist_seg_array_size(bl);
100  float *len_data = (float *)MEM_mallocN(sizeof(float) * seg_size, "calcpathdist");
102 
103  BevPoint *bp_arr = bl->bevpoints;
104  float prev_len = 0.0f;
105  for (int i = 0; i < bl->nr - 1; i++) {
106  prev_len += len_v3v3(bp_arr[i].vec, bp_arr[i + 1].vec);
107  len_data[i] = prev_len;
108  }
109 
110  if (bl->poly >= 0) {
111  /* Cyclic curve. */
112  len_data[seg_size - 1] = prev_len + len_v3v3(bp_arr[0].vec, bp_arr[bl->nr - 1].vec);
113  }
114 }
115 
116 static void get_curve_points_from_idx(const int idx,
117  const BevList *bl,
118  const bool is_cyclic,
119  BevPoint const **r_p0,
120  BevPoint const **r_p1,
121  BevPoint const **r_p2,
122  BevPoint const **r_p3)
123 {
124  BLI_assert(idx >= 0);
125  BLI_assert(idx < bl->nr - 1 || (is_cyclic && idx < bl->nr));
126  BLI_assert(bl->nr > 1);
127 
128  const BevPoint *bp_arr = bl->bevpoints;
129 
130  /* First segment. */
131  if (idx == 0) {
132  *r_p1 = &bp_arr[0];
133  if (is_cyclic) {
134  *r_p0 = &bp_arr[bl->nr - 1];
135  }
136  else {
137  *r_p0 = *r_p1;
138  }
139 
140  *r_p2 = &bp_arr[1];
141 
142  if (bl->nr > 2) {
143  *r_p3 = &bp_arr[2];
144  }
145  else {
146  *r_p3 = *r_p2;
147  }
148  return;
149  }
150 
151  /* Last segment (or next to last in a cyclic curve). */
152  if (idx == bl->nr - 2) {
153  /* The case when the bl->nr == 2 falls in to the "first segment" check above.
154  * So here we can assume that bl->nr > 2.
155  */
156  *r_p0 = &bp_arr[idx - 1];
157  *r_p1 = &bp_arr[idx];
158  *r_p2 = &bp_arr[idx + 1];
159 
160  if (is_cyclic) {
161  *r_p3 = &bp_arr[0];
162  }
163  else {
164  *r_p3 = *r_p2;
165  }
166  return;
167  }
168 
169  if (idx == bl->nr - 1) {
170  /* Last segment in a cyclic curve. This should only trigger if the curve is cyclic
171  * as it gets an extra segment between the end and the start point. */
172  *r_p0 = &bp_arr[idx - 1];
173  *r_p1 = &bp_arr[idx];
174  *r_p2 = &bp_arr[0];
175  *r_p3 = &bp_arr[1];
176  return;
177  }
178 
179  /* To get here the curve has to have four curve points or more and idx can't
180  * be the first or the last segment.
181  * So we can assume that we can get four points without any special checks.
182  */
183  *r_p0 = &bp_arr[idx - 1];
184  *r_p1 = &bp_arr[idx];
185  *r_p2 = &bp_arr[idx + 1];
186  *r_p3 = &bp_arr[idx + 2];
187 }
188 
189 static bool binary_search_anim_path(const float *accum_len_arr,
190  const int seg_size,
191  const float goal_len,
192  int *r_idx,
193  float *r_frac)
194 {
195  float left_len, right_len;
196  int cur_idx = 0, cur_base = 0;
197  int cur_step = seg_size - 1;
198 
199  while (true) {
200  cur_idx = cur_base + cur_step / 2;
201  left_len = accum_len_arr[cur_idx];
202  right_len = accum_len_arr[cur_idx + 1];
203 
204  if (left_len <= goal_len && right_len > goal_len) {
205  *r_idx = cur_idx + 1;
206  *r_frac = (goal_len - left_len) / (right_len - left_len);
207  return true;
208  }
209  if (cur_idx == 0) {
210  /* We ended up at the first segment. The point must be in here. */
211  *r_idx = 0;
212  *r_frac = goal_len / accum_len_arr[0];
213  return true;
214  }
215 
216  if (UNLIKELY(cur_step == 0)) {
217  /* This should never happen unless there is something horribly wrong. */
218  CLOG_ERROR(&LOG, "Couldn't find any valid point on the animation path!");
219  BLI_assert(!"Couldn't find any valid point on the animation path!");
220  return false;
221  }
222 
223  if (left_len < goal_len) {
224  /* Go to the right. */
225  cur_base = cur_idx + 1;
226  cur_step--;
227  } /* Else, go to the left. */
228 
229  cur_step /= 2;
230  }
231 }
232 
241 bool BKE_where_on_path(const Object *ob,
242  float ctime,
243  float r_vec[4],
244  float r_dir[3],
245  float r_quat[4],
246  float *r_radius,
247  float *r_weight)
248 {
249  if (ob == NULL || ob->type != OB_CURVE) {
250  return false;
251  }
252  Curve *cu = ob->data;
253  if (ob->runtime.curve_cache == NULL) {
254  CLOG_WARN(&LOG, "No curve cache!");
255  return false;
256  }
258  CLOG_WARN(&LOG, "No anim path!");
259  return false;
260  }
261  /* We only use the first curve. */
262  BevList *bl = ob->runtime.curve_cache->bev.first;
263  if (bl == NULL || !bl->nr) {
264  CLOG_WARN(&LOG, "No bev list data!");
265  return false;
266  }
267 
268  /* Test for cyclic curve. */
269  const bool is_cyclic = bl->poly >= 0;
270 
271  if (is_cyclic) {
272  /* Wrap the time into a 0.0 - 1.0 range. */
273  if (ctime < 0.0f || ctime > 1.0f) {
274  ctime -= floorf(ctime);
275  }
276  }
277 
278  /* The curve points for this ctime value. */
279  const BevPoint *p0, *p1, *p2, *p3;
280 
281  float frac;
282  const int seg_size = get_bevlist_seg_array_size(bl);
283  const float *accum_len_arr = ob->runtime.curve_cache->anim_path_accum_length;
284  const float goal_len = ctime * accum_len_arr[seg_size - 1];
285 
286  /* Are we simply trying to get the start/end point? */
287  if (ctime <= 0.0f || ctime >= 1.0f) {
288  const float clamp_time = clamp_f(ctime, 0.0f, 1.0f);
289  const int idx = clamp_time * (seg_size - 1);
290  get_curve_points_from_idx(idx, bl, is_cyclic, &p0, &p1, &p2, &p3);
291 
292  if (idx == 0) {
293  frac = goal_len / accum_len_arr[0];
294  }
295  else {
296  frac = (goal_len - accum_len_arr[idx - 1]) / (accum_len_arr[idx] - accum_len_arr[idx - 1]);
297  }
298  }
299  else {
300  /* Do binary search to get the correct segment. */
301  int idx;
302  const bool found_idx = binary_search_anim_path(accum_len_arr, seg_size, goal_len, &idx, &frac);
303 
304  if (UNLIKELY(!found_idx)) {
305  return false;
306  }
307  get_curve_points_from_idx(idx, bl, is_cyclic, &p0, &p1, &p2, &p3);
308  }
309 
310  /* NOTE: commented out for follow constraint
311  *
312  * If it's ever be uncommented watch out for BKE_curve_deform_coords()
313  * which used to temporary set CU_FOLLOW flag for the curve and no
314  * longer does it (because of threading issues of such a thing.
315  */
316  // if (cu->flag & CU_FOLLOW) {
317 
318  float w[4];
319 
321 
322  interp_v3_v3v3v3v3(r_dir, p0->vec, p1->vec, p2->vec, p3->vec, w);
323 
324  /* Make compatible with #vec_to_quat. */
325  negate_v3(r_dir);
326  //}
327 
328  const ListBase *nurbs = BKE_curve_editNurbs_get(cu);
329  if (!nurbs) {
330  nurbs = &cu->nurb;
331  }
332  const Nurb *nu = nurbs->first;
333 
334  /* make sure that first and last frame are included in the vectors here */
335  if (ELEM(nu->type, CU_POLY, CU_BEZIER, CU_NURBS)) {
337  }
338  else if (p2 == p3) {
340  }
341  else {
343  }
344 
345  r_vec[0] = /* X */
346  w[0] * p0->vec[0] + w[1] * p1->vec[0] + w[2] * p2->vec[0] + w[3] * p3->vec[0];
347  r_vec[1] = /* Y */
348  w[0] * p0->vec[1] + w[1] * p1->vec[1] + w[2] * p2->vec[1] + w[3] * p3->vec[1];
349  r_vec[2] = /* Z */
350  w[0] * p0->vec[2] + w[1] * p1->vec[2] + w[2] * p2->vec[2] + w[3] * p3->vec[2];
351 
352  /* Clamp weights to 0-1 as we don't want to extrapolate other values than position. */
353  clamp_v4(w, 0.0f, 1.0f);
354 
355  /* Tilt, should not be needed since we have quat still used. */
356  r_vec[3] = w[0] * p0->tilt + w[1] * p1->tilt + w[2] * p2->tilt + w[3] * p3->tilt;
357 
358  if (r_quat) {
359  float totfac, q1[4], q2[4];
360 
361  totfac = w[0] + w[3];
362  if (totfac > FLT_EPSILON) {
363  interp_qt_qtqt(q1, p0->quat, p3->quat, w[3] / totfac);
364  }
365  else {
366  copy_qt_qt(q1, p1->quat);
367  }
368 
369  totfac = w[1] + w[2];
370  if (totfac > FLT_EPSILON) {
371  interp_qt_qtqt(q2, p1->quat, p2->quat, w[2] / totfac);
372  }
373  else {
374  copy_qt_qt(q2, p3->quat);
375  }
376 
377  totfac = w[0] + w[1] + w[2] + w[3];
378  if (totfac > FLT_EPSILON) {
379  interp_qt_qtqt(r_quat, q1, q2, (w[1] + w[2]) / totfac);
380  }
381  else {
382  copy_qt_qt(r_quat, q2);
383  }
384  }
385 
386  if (r_radius) {
387  *r_radius = w[0] * p0->radius + w[1] * p1->radius + w[2] * p2->radius + w[3] * p3->radius;
388  }
389 
390  if (r_weight) {
391  *r_weight = w[0] * p0->weight + w[1] * p1->weight + w[2] * p2->weight + w[3] * p3->weight;
392  }
393 
394  return true;
395 }
struct ListBase * BKE_curve_editNurbs_get(struct Curve *cu)
Definition: curve.c:437
void key_curve_tangent_weights(float t, float data[4], int type)
Definition: key.c:390
void key_curve_position_weights(float t, float data[4], int type)
Definition: key.c:348
#define BLI_assert(a)
Definition: BLI_assert.h:58
MINLINE float clamp_f(float value, float min, float max)
void interp_qt_qtqt(float q[4], const float a[4], const float b[4], const float t)
void copy_qt_qt(float q[4], const float a[4])
Definition: math_rotation.c:52
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void negate_v3(float r[3])
void interp_v3_v3v3v3v3(float p[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3], const float w[4])
Definition: math_vector.c:201
MINLINE void clamp_v4(float vec[4], const float min, const float max)
#define UNLIKELY(x)
#define ELEM(...)
#define CLOG_ERROR(clg_ref,...)
Definition: CLG_log.h:204
#define CLOG_WARN(clg_ref,...)
Definition: CLG_log.h:203
@ CU_BEZIER
@ CU_POLY
@ CU_NURBS
@ KEY_LINEAR
@ KEY_CARDINAL
@ KEY_BSPLINE
Object is a sort of wrapper for general info.
@ OB_CURVE
Read Guarded memory(de)allocation.
int BKE_anim_path_get_array_size(const CurveCache *curve_cache)
Definition: anim_path.c:55
bool BKE_where_on_path(const Object *ob, float ctime, float r_vec[4], float r_dir[3], float r_quat[4], float *r_radius, float *r_weight)
Definition: anim_path.c:241
static bool binary_search_anim_path(const float *accum_len_arr, const int seg_size, const float goal_len, int *r_idx, float *r_frac)
Definition: anim_path.c:189
static void get_curve_points_from_idx(const int idx, const BevList *bl, const bool is_cyclic, BevPoint const **r_p0, BevPoint const **r_p1, BevPoint const **r_p2, BevPoint const **r_p3)
Definition: anim_path.c:116
float BKE_anim_path_get_length(const CurveCache *curve_cache)
Definition: anim_path.c:66
static CLG_LogRef LOG
Definition: anim_path.c:40
void BKE_anim_path_calc_data(Object *ob)
Definition: anim_path.c:72
static int get_bevlist_seg_array_size(const BevList *bl)
Definition: anim_path.c:45
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
#define floorf(x)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
ccl_device_inline float frac(float x, int *ix)
BevPoint * bevpoints
float radius
float quat[4]
float weight
float vec[3]
ListBase bev
Definition: BKE_curve.h:50
const float * anim_path_accum_length
Definition: BKE_curve.h:58
ListBase nurb
void * first
Definition: DNA_listBase.h:47
short type
struct CurveCache * curve_cache
Object_Runtime runtime
void * data