Panda3D
cLerpNodePathInterval.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file cLerpNodePathInterval.cxx
10  * @author drose
11  * @date 2002-08-27
12  */
13 
14 #include "cLerpNodePathInterval.h"
15 #include "lerp_helpers.h"
16 #include "transformState.h"
17 #include "renderState.h"
18 #include "colorAttrib.h"
19 #include "colorScaleAttrib.h"
20 #include "texMatrixAttrib.h"
21 #include "dcast.h"
22 #include "config_interval.h"
23 
24 TypeHandle CLerpNodePathInterval::_type_handle;
25 
26 /**
27  * Constructs a lerp interval that will lerp some properties on the indicated
28  * node, possibly relative to the indicated other node (if other is nonempty).
29  *
30  * You must call set_end_pos(), etc. for the various properties you wish to
31  * lerp before the first call to priv_initialize(). If you want to set a
32  * starting value for any of the properties, you may call set_start_pos(),
33  * etc.; otherwise, the starting value is taken from the actual node's value
34  * at the time the lerp is performed.
35  *
36  * The starting values may be explicitly specified or omitted. The value of
37  * bake_in_start determines the behavior if the starting values are omitted.
38  * If bake_in_start is true, the values are obtained the first time the lerp
39  * runs, and thenceforth are stored within the interval. If bake_in_start is
40  * false, the starting value is computed each frame, based on assuming the
41  * current value represents the value set from the last time the interval was
42  * run. This "smart" behavior allows code to manipulate the object event
43  * while it is being lerped, and the lerp continues to apply in a sensible
44  * way.
45  *
46  * If fluid is true, the prev_transform is not adjusted by the lerp;
47  * otherwise, it is reset.
48  */
50 CLerpNodePathInterval(const std::string &name, double duration,
51  CLerpInterval::BlendType blend_type,
52  bool bake_in_start, bool fluid,
53  const NodePath &node, const NodePath &other) :
54  CLerpInterval(name, duration, blend_type),
55  _node(node),
56  _other(other),
57  _flags(0),
58  _texture_stage(TextureStage::get_default()),
59  _override(0),
60  _slerp(nullptr)
61 {
62  if (bake_in_start) {
63  _flags |= F_bake_in_start;
64  }
65  if (fluid) {
66  _flags |= F_fluid;
67  }
68  _prev_d = 0.0;
69 }
70 
71 /**
72  * This replaces the first call to priv_step(), and indicates that the
73  * interval has just begun. This may be overridden by derived classes that
74  * need to do some explicit initialization on the first call.
75  */
77 priv_initialize(double t) {
78  check_stopped(get_class_type(), "priv_initialize");
79  recompute();
80  _prev_d = 0.0;
81  _state = S_started;
82  priv_step(t);
83 }
84 
85 /**
86  * This is called in lieu of priv_initialize() .. priv_step() ..
87  * priv_finalize(), when everything is to happen within one frame. The
88  * interval should initialize itself, then leave itself in the final state.
89  */
92  check_stopped(get_class_type(), "priv_instant");
93  recompute();
94  _prev_d = 0.0;
95  _state = S_started;
97  _state = S_final;
98 }
99 
100 /**
101  * Advances the time on the interval. The time may either increase (the
102  * normal case) or decrease (e.g. if the interval is being played by a
103  * slider).
104  */
106 priv_step(double t) {
107  check_started(get_class_type(), "priv_step");
108  _state = S_started;
109  double d = compute_delta(t);
110 
111  // Save this in case we want to restore it later.
112  CPT(TransformState) prev_transform = _node.get_prev_transform();
113 
114  if ((_flags & (F_end_pos | F_end_hpr | F_end_quat | F_end_scale | F_end_shear)) != 0) {
115  // We have some transform lerp.
116  CPT(TransformState) transform;
117 
118  if (_other.is_empty()) {
119  // If there is no other node, it's a local transform lerp.
120  transform = _node.get_transform();
121  } else {
122  // If there *is* another node, we get the transform relative to that
123  // node.
124  transform = _node.get_transform(_other);
125  }
126 
127  LPoint3 pos;
128  LVecBase3 hpr;
129  LQuaternion quat;
130  LVecBase3 scale;
131  LVecBase3 shear;
132 
133  if ((_flags & F_end_pos) != 0) {
134  if ((_flags & F_start_pos) != 0) {
135  lerp_value(pos, d, _start_pos, _end_pos);
136 
137  } else if ((_flags & F_bake_in_start) != 0) {
138  // Get the current starting pos, and bake it in.
139  set_start_pos(transform->get_pos());
140  lerp_value(pos, d, _start_pos, _end_pos);
141 
142  } else {
143  // "smart" lerp from the current pos to the new pos.
144  pos = transform->get_pos();
145  lerp_value_from_prev(pos, d, _prev_d, pos, _end_pos);
146  }
147  }
148  if ((_flags & F_end_hpr) != 0) {
149  if ((_flags & F_start_hpr) != 0) {
150  lerp_value(hpr, d, _start_hpr, _end_hpr);
151 
152  } else if ((_flags & F_start_quat) != 0) {
153  _start_hpr = _start_quat.get_hpr();
154  _flags |= F_start_hpr;
155  lerp_value(hpr, d, _start_hpr, _end_hpr);
156 
157  } else if ((_flags & F_bake_in_start) != 0) {
158  set_start_hpr(transform->get_hpr());
159  lerp_value(hpr, d, _start_hpr, _end_hpr);
160 
161  } else {
162  hpr = transform->get_hpr();
163  lerp_value_from_prev(hpr, d, _prev_d, hpr, _end_hpr);
164  }
165  }
166  if ((_flags & F_end_quat) != 0) {
167  if ((_flags & F_slerp_setup) == 0) {
168  if ((_flags & F_start_quat) != 0) {
169  setup_slerp();
170 
171  } else if ((_flags & F_start_hpr) != 0) {
172  _start_quat.set_hpr(_start_hpr);
173  _flags |= F_start_quat;
174  setup_slerp();
175 
176  } else if ((_flags & F_bake_in_start) != 0) {
177  set_start_quat(transform->get_quat());
178  setup_slerp();
179 
180  } else {
181  if (_prev_d == 1.0) {
182  _start_quat = _end_quat;
183  } else {
184  LQuaternion prev_value = transform->get_quat();
185  _start_quat = (prev_value - _prev_d * _end_quat) / (1.0 - _prev_d);
186  }
187  setup_slerp();
188 
189  // In this case, clear the slerp_setup flag because we need to re-
190  // setup the slerp each time.
191  _flags &= ~F_slerp_setup;
192  }
193  }
194  nassertv(_slerp != nullptr);
195  (this->*_slerp)(quat, d);
196  }
197  if ((_flags & F_end_scale) != 0) {
198  if ((_flags & F_start_scale) != 0) {
199  lerp_value(scale, d, _start_scale, _end_scale);
200 
201  } else if ((_flags & F_bake_in_start) != 0) {
202  set_start_scale(transform->get_scale());
203  lerp_value(scale, d, _start_scale, _end_scale);
204 
205  } else {
206  scale = transform->get_scale();
207  lerp_value_from_prev(scale, d, _prev_d, scale, _end_scale);
208  }
209  }
210  if ((_flags & F_end_shear) != 0) {
211  if ((_flags & F_start_shear) != 0) {
212  lerp_value(shear, d, _start_shear, _end_shear);
213 
214  } else if ((_flags & F_bake_in_start) != 0) {
215  set_start_shear(transform->get_shear());
216  lerp_value(shear, d, _start_shear, _end_shear);
217 
218  } else {
219  shear = transform->get_shear();
220  lerp_value_from_prev(shear, d, _prev_d, shear, _end_shear);
221  }
222  }
223 
224  // Now apply the modifications back to the transform. We want to be a
225  // little careful here, because we don't want to assume the transform has
226  // hprscale components if they're not needed. And in any case, we only
227  // want to apply the components that we computed, above.
228  unsigned int transform_flags = _flags & (F_end_pos | F_end_hpr | F_end_quat | F_end_scale);
229  switch (transform_flags) {
230  case 0:
231  break;
232 
233  case F_end_pos:
234  if (_other.is_empty()) {
235  _node.set_pos(pos);
236  } else {
237  _node.set_pos(_other, pos);
238  }
239  break;
240 
241  case F_end_hpr:
242  if (_other.is_empty()) {
243  _node.set_hpr(hpr);
244  } else {
245  _node.set_hpr(_other, hpr);
246  }
247  break;
248 
249  case F_end_quat:
250  if (_other.is_empty()) {
251  _node.set_quat(quat);
252  } else {
253  _node.set_quat(_other, quat);
254  }
255  break;
256 
257  case F_end_scale:
258  if (_other.is_empty()) {
259  _node.set_scale(scale);
260  } else {
261  _node.set_scale(_other, scale);
262  }
263  break;
264 
265  case F_end_hpr | F_end_scale:
266  if (_other.is_empty()) {
267  _node.set_hpr_scale(hpr, scale);
268  } else {
269  _node.set_hpr_scale(hpr, scale);
270  }
271  break;
272 
273  case F_end_quat | F_end_scale:
274  if (_other.is_empty()) {
275  _node.set_quat_scale(quat, scale);
276  } else {
277  _node.set_quat_scale(quat, scale);
278  }
279  break;
280 
281  case F_end_pos | F_end_hpr:
282  if (_other.is_empty()) {
283  _node.set_pos_hpr(pos, hpr);
284  } else {
285  _node.set_pos_hpr(_other, pos, hpr);
286  }
287  break;
288 
289  case F_end_pos | F_end_quat:
290  if (_other.is_empty()) {
291  _node.set_pos_quat(pos, quat);
292  } else {
293  _node.set_pos_quat(_other, pos, quat);
294  }
295  break;
296 
297  case F_end_pos | F_end_scale:
298  if (transform->quat_given()) {
299  if (_other.is_empty()) {
300  _node.set_pos_quat_scale(pos, transform->get_quat(), scale);
301  } else {
302  _node.set_pos_quat_scale(_other, pos, transform->get_quat(), scale);
303  }
304  } else {
305  if (_other.is_empty()) {
306  _node.set_pos_hpr_scale(pos, transform->get_hpr(), scale);
307  } else {
308  _node.set_pos_hpr_scale(_other, pos, transform->get_hpr(), scale);
309  }
310  }
311  break;
312 
313  case F_end_pos | F_end_hpr | F_end_scale:
314  if ((_flags & F_end_shear) != 0) {
315  // Even better: we have all four components.
316  if (_other.is_empty()) {
317  _node.set_pos_hpr_scale_shear(pos, hpr, scale, shear);
318  } else {
319  _node.set_pos_hpr_scale_shear(_other, pos, hpr, scale, shear);
320  }
321  } else {
322  // We have only the primary three components.
323  if (_other.is_empty()) {
324  _node.set_pos_hpr_scale(pos, hpr, scale);
325  } else {
326  _node.set_pos_hpr_scale(_other, pos, hpr, scale);
327  }
328  }
329  break;
330 
331  case F_end_pos | F_end_quat | F_end_scale:
332  if ((_flags & F_end_shear) != 0) {
333  // Even better: we have all four components.
334  if (_other.is_empty()) {
335  _node.set_pos_quat_scale_shear(pos, quat, scale, shear);
336  } else {
337  _node.set_pos_quat_scale_shear(_other, pos, quat, scale, shear);
338  }
339  } else {
340  // We have only the primary three components.
341  if (_other.is_empty()) {
342  _node.set_pos_quat_scale(pos, quat, scale);
343  } else {
344  _node.set_pos_quat_scale(_other, pos, quat, scale);
345  }
346  }
347  break;
348 
349  default:
350  // Some unhandled combination. We should handle this.
351  interval_cat.error()
352  << "Internal error in CLerpNodePathInterval::priv_step().\n";
353  }
354  if ((_flags & F_end_shear) != 0) {
355  // Also apply changes to shear.
356  if (transform_flags == (F_end_pos | F_end_hpr | F_end_scale) ||
357  transform_flags == (F_end_pos | F_end_quat | F_end_scale)) {
358  // Actually, we already handled this case above.
359 
360  } else {
361  if (_other.is_empty()) {
362  _node.set_shear(shear);
363  } else {
364  _node.set_shear(_other, shear);
365  }
366  }
367  }
368  }
369 
370  if ((_flags & F_fluid) != 0) {
371  // If we have the fluid flag set, we shouldn't mess with the prev
372  // transform. Therefore, restore it to what it was before we started
373  // messing with it.
374  _node.set_prev_transform(prev_transform);
375  }
376 
377  if ((_flags & (F_end_color | F_end_color_scale | F_end_tex_offset | F_end_tex_rotate | F_end_tex_scale)) != 0) {
378  // We have some render state lerp.
379  CPT(RenderState) state;
380 
381  if (_other.is_empty()) {
382  // If there is no other node, it's a local state lerp. This is most
383  // common.
384  state = _node.get_state();
385  } else {
386  // If there *is* another node, we get the state relative to that node.
387  // This is weird, but you could lerp color (for instance) relative to
388  // some other node's color.
389  state = _node.get_state(_other);
390  }
391 
392  // Unlike in the transform case above, we can go ahead and modify the
393  // state immediately with each attribute change, since these attributes
394  // don't interrelate.
395 
396  if ((_flags & F_end_color) != 0) {
397  LColor color;
398 
399  if ((_flags & F_start_color) != 0) {
400  lerp_value(color, d, _start_color, _end_color);
401 
402  } else {
403  // Get the previous color.
404  color.set(1.0f, 1.0f, 1.0f, 1.0f);
405  const RenderAttrib *attrib =
406  state->get_attrib(ColorAttrib::get_class_type());
407  if (attrib != nullptr) {
408  const ColorAttrib *ca = DCAST(ColorAttrib, attrib);
409  if (ca->get_color_type() == ColorAttrib::T_flat) {
410  color = ca->get_color();
411  }
412  }
413 
414  lerp_value_from_prev(color, d, _prev_d, color, _end_color);
415  }
416 
417  state = state->add_attrib(ColorAttrib::make_flat(color), _override);
418  }
419 
420  if ((_flags & F_end_color_scale) != 0) {
421  LVecBase4 color_scale;
422 
423  if ((_flags & F_start_color_scale) != 0) {
424  lerp_value(color_scale, d, _start_color_scale, _end_color_scale);
425 
426  } else {
427  // Get the previous color scale.
428  color_scale.set(1.0f, 1.0f, 1.0f, 1.0f);
429  const RenderAttrib *attrib =
430  state->get_attrib(ColorScaleAttrib::get_class_type());
431  if (attrib != nullptr) {
432  const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
433  color_scale = csa->get_scale();
434  }
435 
436  lerp_value_from_prev(color_scale, d, _prev_d, color_scale, _end_color_scale);
437  }
438 
439  state = state->add_attrib(ColorScaleAttrib::make(color_scale), _override);
440  }
441 
442  if ((_flags & (F_end_tex_offset | F_end_tex_rotate | F_end_tex_scale)) != 0) {
443  // We have a UV lerp.
444  CPT(TransformState) transform = TransformState::make_identity();
445 
446  const RenderAttrib *attrib =
447  state->get_attrib(TexMatrixAttrib::get_class_type());
448  CPT(TexMatrixAttrib) tma;
449  if (attrib != nullptr) {
450  tma = DCAST(TexMatrixAttrib, attrib);
451  transform = tma->get_transform(_texture_stage);
452  } else {
453  tma = DCAST(TexMatrixAttrib, TexMatrixAttrib::make());
454  }
455 
456  if ((_flags & F_end_tex_offset) != 0) {
457  LVecBase2 tex_offset;
458 
459  if ((_flags & F_start_tex_offset) != 0) {
460  lerp_value(tex_offset, d, _start_tex_offset, _end_tex_offset);
461  } else {
462  tex_offset = transform->get_pos2d();
463  lerp_value_from_prev(tex_offset, d, _prev_d, tex_offset,
464  _end_tex_offset);
465  }
466 
467  transform = transform->set_pos2d(tex_offset);
468  }
469 
470  if ((_flags & F_end_tex_rotate) != 0) {
471  PN_stdfloat tex_rotate;
472 
473  if ((_flags & F_start_tex_rotate) != 0) {
474  lerp_value(tex_rotate, d, _start_tex_rotate, _end_tex_rotate);
475  } else {
476  tex_rotate = transform->get_rotate2d();
477  lerp_value_from_prev(tex_rotate, d, _prev_d, tex_rotate,
478  _end_tex_rotate);
479  }
480 
481  transform = transform->set_rotate2d(tex_rotate);
482  }
483 
484  if ((_flags & F_end_tex_scale) != 0) {
485  LVecBase2 tex_scale;
486 
487  if ((_flags & F_start_tex_scale) != 0) {
488  lerp_value(tex_scale, d, _start_tex_scale, _end_tex_scale);
489  } else {
490  tex_scale = transform->get_scale2d();
491  lerp_value_from_prev(tex_scale, d, _prev_d, tex_scale,
492  _end_tex_scale);
493  }
494 
495  transform = transform->set_scale2d(tex_scale);
496  }
497 
498  // Apply the modified transform back to the state.
499  state = state->set_attrib(tma->add_stage(_texture_stage, transform, _override));
500  }
501 
502 
503  // Now apply the new state back to the node.
504  if (_other.is_empty()) {
505  _node.set_state(state);
506  } else {
507  _node.set_state(_other, state);
508  }
509  } _prev_d = d;
510  _curr_t = t;
511 }
512 
513 /**
514  * Similar to priv_initialize(), but this is called when the interval is being
515  * played backwards; it indicates that the interval should start at the
516  * finishing state and undo any intervening intervals.
517  */
520  check_stopped(get_class_type(), "priv_reverse_initialize");
521  recompute();
522  _state = S_started;
523  _prev_d = 1.0;
524  priv_step(t);
525 }
526 
527 /**
528  * This is called in lieu of priv_reverse_initialize() .. priv_step() ..
529  * priv_reverse_finalize(), when everything is to happen within one frame.
530  * The interval should initialize itself, then leave itself in the initial
531  * state.
532  */
535  check_stopped(get_class_type(), "priv_reverse_initialize");
536  recompute();
537  _state = S_started;
538  _prev_d = 1.0;
539  priv_step(0.0);
540  _state = S_initial;
541 }
542 
543 /**
544  *
545  */
546 void CLerpNodePathInterval::
547 output(std::ostream &out) const {
548  out << get_name() << ":";
549 
550  if ((_flags & F_end_pos) != 0) {
551  out << " pos";
552  if ((_flags & F_start_pos) != 0) {
553  out << " from " << _start_pos;
554  }
555  out << " to " << _end_pos;
556  }
557 
558  if ((_flags & F_end_hpr) != 0) {
559  out << " hpr";
560  if ((_flags & F_start_hpr) != 0) {
561  out << " from " << _start_hpr;
562  }
563  out << " to " << _end_hpr;
564  }
565 
566  if ((_flags & F_end_quat) != 0) {
567  out << " quat";
568  if ((_flags & F_start_quat) != 0) {
569  out << " from " << _start_quat;
570  }
571  out << " to " << _end_quat;
572  }
573 
574  if ((_flags & F_end_scale) != 0) {
575  out << " scale";
576  if ((_flags & F_start_scale) != 0) {
577  out << " from " << _start_scale;
578  }
579  out << " to " << _end_scale;
580  }
581 
582  if ((_flags & F_end_shear) != 0) {
583  out << " shear";
584  if ((_flags & F_start_shear) != 0) {
585  out << " from " << _start_shear;
586  }
587  out << " to " << _end_shear;
588  }
589 
590  if ((_flags & F_end_color) != 0) {
591  out << " color";
592  if ((_flags & F_start_color) != 0) {
593  out << " from " << _start_color;
594  }
595  out << " to " << _end_color;
596  }
597 
598  if ((_flags & F_end_color_scale) != 0) {
599  out << " color_scale";
600  if ((_flags & F_start_color_scale) != 0) {
601  out << " from " << _start_color_scale;
602  }
603  out << " to " << _end_color_scale;
604  }
605 
606  out << " dur " << get_duration();
607 }
608 
609 /**
610  * Sets up a spherical lerp from _start_quat to _end_quat. This precomputes
611  * some important values (like the angle between the quaternions) and sets up
612  * the _slerp method pointer.
613  */
614 void CLerpNodePathInterval::
615 setup_slerp() {
616  if (_start_quat.dot(_end_quat) < 0.0f) {
617  // Make sure both quaternions are on the same side.
618  _start_quat = -_start_quat;
619  }
620 
621  _slerp_angle = _start_quat.angle_rad(_end_quat);
622 
623  if (_slerp_angle < 0.1f) {
624  // If the angle is small, use sin(angle)angle as the denominator, to
625  // provide better behavior with small divisors. This is Don Hatch's
626  // suggestion from http:www.hadron.org~hatchrightway.php .
627  _slerp_denom = csin_over_x(_slerp_angle);
628  _slerp = &CLerpNodePathInterval::slerp_angle_0;
629 
630  } else if (_slerp_angle > 3.14) {
631  // If the angle is close to 180 degrees, the lerp is ambiguous. which
632  // plane should we lerp through? Better pick an intermediate point to
633  // resolve the ambiguity up front.
634 
635  // We pick it by choosing a linear point between the quats and normalizing
636  // it out; this will give an arbitrary point when the angle is exactly
637  // 180, but will behave sanely as the angle approaches 180.
638  _slerp_c = (_start_quat + _end_quat);
639  _slerp_c.normalize();
640  _slerp_angle = _end_quat.angle_rad(_slerp_c);
641  _slerp_denom = csin(_slerp_angle);
642 
643  _slerp = &CLerpNodePathInterval::slerp_angle_180;
644 
645  } else {
646  // Otherwise, use the original Shoemake equation for spherical lerp.
647  _slerp_denom = csin(_slerp_angle);
648  _slerp = &CLerpNodePathInterval::slerp_basic;
649  }
650 
651  nassertv(_slerp_denom != 0.0f);
652  _flags |= F_slerp_setup;
653 }
654 
655 /**
656  * Implements Ken Shoemake's spherical lerp equation. This is appropriate
657  * when the angle between the quaternions is not near one extreme or the
658  * other.
659  */
660 void CLerpNodePathInterval::
661 slerp_basic(LQuaternion &result, PN_stdfloat t) const {
662  nassertv(_slerp_denom != 0.0f);
663  PN_stdfloat ti = 1.0f - t;
664  PN_stdfloat ta = t * _slerp_angle;
665  PN_stdfloat tia = ti * _slerp_angle;
666 
667  if (interval_cat.is_spam()) {
668  interval_cat.spam()
669  << "slerp_basic, (t = " << t << "), angle = " << _slerp_angle << "\n"
670  << "_start_quat = " << _start_quat << ", _end_quat = "
671  << _end_quat << ", denom = " << _slerp_denom << "\n";
672  }
673 
674  result = (csin(tia) * _start_quat + csin(ta) * _end_quat) / _slerp_denom;
675  nassertv(!result.is_nan());
676 }
677 
678 /**
679  * Implements Don Hatch's modified spherical lerp equation, appropriate for
680  * when the angle between the quaternions approaches zero.
681  */
682 void CLerpNodePathInterval::
683 slerp_angle_0(LQuaternion &result, PN_stdfloat t) const {
684  nassertv(_slerp_denom != 0.0f);
685  PN_stdfloat ti = 1.0f - t;
686  PN_stdfloat ta = t * _slerp_angle;
687  PN_stdfloat tia = ti * _slerp_angle;
688 
689  if (interval_cat.is_spam()) {
690  interval_cat.spam()
691  << "slerp_angle_0, (t = " << t << "), angle = " << _slerp_angle
692  << "\n_start_quat = " << _start_quat << ", _end_quat = "
693  << _end_quat << ", denom = " << _slerp_denom << "\n";
694  }
695 
696  result = (csin_over_x(tia) * ti * _start_quat + csin_over_x(ta) * t * _end_quat) / _slerp_denom;
697  nassertv(!result.is_nan());
698 }
699 
700 
701 /**
702  * Implements a two-part slerp, to an intermediate point and out again,
703  * appropriate for when the angle between the quaternions approaches 180
704  * degrees.
705  */
706 void CLerpNodePathInterval::
707 slerp_angle_180(LQuaternion &result, PN_stdfloat t) const {
708  nassertv(_slerp_denom != 0.0f);
709  if (t < 0.5) {
710  // The first half of the lerp: _start_quat to _slerp_c.
711 
712  t *= 2.0f;
713 
714  PN_stdfloat ti = 1.0f - t;
715  PN_stdfloat ta = t * _slerp_angle;
716  PN_stdfloat tia = ti * _slerp_angle;
717 
718  if (interval_cat.is_spam()) {
719  interval_cat.spam()
720  << "slerp_angle_180, first half (t = " << t << "), angle = "
721  << _slerp_angle << "\n_start_quat = " << _start_quat
722  << ", _slerp_c = " << _slerp_c << ", denom = "
723  << _slerp_denom << "\n";
724  }
725 
726  result = (csin(tia) * _start_quat + csin(ta) * _slerp_c) / _slerp_denom;
727 
728  } else {
729  // The second half of the lerp: _slerp_c to _end_quat.
730  t = t * 2.0f - 1.0f;
731 
732  PN_stdfloat ti = 1.0f - t;
733  PN_stdfloat ta = t * _slerp_angle;
734  PN_stdfloat tia = ti * _slerp_angle;
735 
736  if (interval_cat.is_spam()) {
737  interval_cat.spam()
738  << "slerp_angle_180, second half (t = " << t << "), angle = "
739  << _slerp_angle << "\n_slerp_c = " << _slerp_c
740  << ", _end_quat = " << _end_quat << ", denom = "
741  << _slerp_denom << "\n";
742  }
743 
744  result = (csin(tia) * _slerp_c + csin(ta) * _end_quat) / _slerp_denom;
745  }
746 
747  nassertv(!result.is_nan());
748 }
void set_start_scale(const LVecBase3 &scale)
Indicates the initial scale of the lerped node.
void set_start_shear(const LVecBase3 &shear)
Indicates the initial shear of the lerped node.
void set_start_hpr(const LVecBase3 &hpr)
Indicates the initial rotation of the lerped node.
virtual void priv_initialize(double t)
This replaces the first call to priv_step(), and indicates that the interval has just begun.
Indicates a coordinate-system transform on vertices.
void set_hpr_scale(PN_stdfloat h, PN_stdfloat p, PN_stdfloat r, PN_stdfloat sx, PN_stdfloat sy, PN_stdfloat sz)
Sets the rotation and scale components of the transform, leaving translation untouched.
Definition: nodePath.I:737
This is the base class for a number of render attributes (other than transform) that may be set on sc...
Definition: renderAttrib.h:51
void set_pos_hpr(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z, PN_stdfloat h, PN_stdfloat p, PN_stdfloat r)
Sets the translation and rotation component of the transform, leaving scale untouched.
Definition: nodePath.I:728
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition: nodePath.I:188
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void set_scale(PN_stdfloat scale)
Sets the scale component of the transform, leaving translation and rotation untouched.
Definition: nodePath.I:675
get_color
If the type is T_flat or T_off, this returns the color that will be applied to geometry.
Definition: colorAttrib.h:47
void set_start_quat(const LQuaternion &quat)
Indicates the initial rotation of the lerped node.
float csin_over_x(float v)
Computes sin(x) / x, well-behaved as x approaches 0.
Definition: cmath.I:77
void set_quat_scale(const LQuaternion &quat, const LVecBase3 &scale)
Sets the rotation and scale components of the transform, leaving translation untouched.
Definition: nodePath.cxx:1228
void set_pos_quat(const LVecBase3 &pos, const LQuaternion &quat)
Sets the translation and rotation component of the transform, leaving scale untouched.
Definition: nodePath.cxx:1201
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void set_pos_quat_scale_shear(const LVecBase3 &pos, const LQuaternion &quat, const LVecBase3 &scale, const LVecBase3 &shear)
Completely replaces the transform with new translation, rotation, scale, and shear components.
Definition: nodePath.cxx:1280
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_scale
Returns the scale to be applied to colors.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void lerp_value_from_prev(NumericType &current_value, double d, double prev_d, const NumericType &prev_value, const NumericType &ending_value)
Applies the linear lerp computation for a single parameter, when the starting value is implicit.
Definition: lerp_helpers.h:43
void set_pos_quat_scale(const LVecBase3 &pos, const LQuaternion &quat, const LVecBase3 &scale)
Replaces the translation, rotation, and scale components, implicitly setting shear to 0.
Definition: nodePath.cxx:1254
void lerp_value(NumericType &current_value, double d, const NumericType &starting_value, const NumericType &ending_value)
Applies the linear lerp computation for a single parameter.
Definition: lerp_helpers.h:27
void set_quat(const LQuaternion &quat)
Sets the rotation component of the transform, leaving translation and scale untouched.
Definition: nodePath.cxx:1070
virtual void priv_reverse_initialize(double t)
Similar to priv_initialize(), but this is called when the interval is being played backwards; it indi...
virtual void priv_step(double t)
Advances the time on the interval.
LVecBase3 get_hpr() const
Retrieves the rotation component of the transform.
Definition: nodePath.cxx:1058
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
LQuaternion get_quat() const
Retrieves the rotation component of the transform.
Definition: nodePath.cxx:1080
Applies a scale to colors in the scene graph and on vertices.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
Applies a transform matrix to UV's before they are rendered.
void set_shear(PN_stdfloat shxy, PN_stdfloat shxz, PN_stdfloat shyz)
Sets the shear component of the transform, leaving translation, rotation, and scale untouched.
Definition: nodePath.I:704
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void set_hpr(PN_stdfloat h, PN_stdfloat p, PN_stdfloat r)
Sets the rotation component of the transform, leaving translation and scale untouched.
Definition: nodePath.I:651
void set_pos_hpr_scale_shear(const LVecBase3 &pos, const LVecBase3 &hpr, const LVecBase3 &scale, const LVecBase3 &shear)
Completely replaces the transform with new translation, rotation, scale, and shear components.
Definition: nodePath.cxx:1267
CLerpNodePathInterval(const std::string &name, double duration, BlendType blend_type, bool bake_in_start, bool fluid, const NodePath &node, const NodePath &other)
Constructs a lerp interval that will lerp some properties on the indicated node, possibly relative to...
Indicates what color should be applied to renderable geometry.
Definition: colorAttrib.h:27
void set_start_pos(const LVecBase3 &pos)
Indicates the initial position of the lerped node.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_duration
Returns the duration of the interval in seconds.
Definition: cInterval.h:124
void set_pos_hpr_scale(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z, PN_stdfloat h, PN_stdfloat p, PN_stdfloat r, PN_stdfloat sx, PN_stdfloat sy, PN_stdfloat sz)
Completely replaces the transform with new translation, rotation, and scale components.
Definition: nodePath.I:746
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
Definition: nodePath.cxx:758
Defines the properties of a named stage of the multitexture pipeline.
Definition: textureStage.h:35
get_color_type
Returns the type of color specified by this ColorAttrib.
Definition: colorAttrib.h:46
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:161
void set_state(const RenderState *state, Thread *current_thread=Thread::get_current_thread())
Changes the complete state object on this node.
Definition: nodePath.I:427
virtual void priv_reverse_instant()
This is called in lieu of priv_reverse_initialize() .
The base class for a family of intervals that linearly interpolate one or more numeric values over ti...
Definition: cLerpInterval.h:24
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const TransformState * get_prev_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the transform that has been set as this node's "previous" position.
Definition: nodePath.cxx:846
const RenderState * get_state(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete state object set on this node.
Definition: nodePath.cxx:686
virtual void priv_instant()
This is called in lieu of priv_initialize() .