Panda3D
Loading...
Searching...
No Matches
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
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
24TypeHandle 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 */
50CLerpNodePathInterval(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 */
77priv_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 */
106priv_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_norm_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_norm_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 */
519priv_reverse_initialize(double t) {
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 */
546void CLerpNodePathInterval::
547output(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 */
614void CLerpNodePathInterval::
615setup_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 */
660void CLerpNodePathInterval::
661slerp_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 */
682void CLerpNodePathInterval::
683slerp_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 */
706void CLerpNodePathInterval::
707slerp_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}
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_name
Returns the interval's name.
Definition cInterval.h:126
get_duration
Returns the duration of the interval in seconds.
Definition cInterval.h:127
The base class for a family of intervals that linearly interpolate one or more numeric values over ti...
void set_start_scale(const LVecBase3 &scale)
Indicates the initial scale of the lerped node.
void set_start_hpr(const LVecBase3 &hpr)
Indicates the initial rotation of the lerped node.
virtual void priv_instant()
This is called in lieu of priv_initialize() .
virtual void priv_initialize(double t)
This replaces the first call to priv_step(), and indicates that the interval has just begun.
virtual void priv_reverse_initialize(double t)
Similar to priv_initialize(), but this is called when the interval is being played backwards; it indi...
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...
void set_start_quat(const LQuaternion &quat)
Indicates the initial rotation of the lerped node.
virtual void priv_step(double t)
Advances the time on the interval.
virtual void priv_reverse_instant()
This is called in lieu of priv_reverse_initialize() .
void set_start_pos(const LVecBase3 &pos)
Indicates the initial position of the lerped node.
void set_start_shear(const LVecBase3 &shear)
Indicates the initial shear of the lerped node.
Indicates what color should be applied to renderable geometry.
Definition colorAttrib.h:27
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
get_color_type
Returns the type of color specified by this ColorAttrib.
Definition colorAttrib.h:46
Applies a scale to colors in the scene graph and on vertices.
get_scale
Returns the scale to be applied to colors.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition nodePath.h:159
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
void set_quat(const LQuaternion &quat)
Sets the rotation component of the transform, leaving translation and scale untouched.
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.
LVecBase3 get_hpr() const
Retrieves the rotation component of the transform.
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.
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:882
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
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition nodePath.I:188
void set_pos_quat(const LVecBase3 &pos, const LQuaternion &quat)
Sets the translation and rotation component of the transform, leaving scale untouched.
LQuaternion get_quat() const
Retrieves the rotation component of the transform.
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
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.
const RenderState * get_state(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete state object set on this node.
Definition nodePath.cxx:722
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
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
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
Definition nodePath.cxx:794
void set_scale(PN_stdfloat scale)
Sets the scale component of the transform, leaving translation and rotation untouched.
Definition nodePath.I:675
void set_quat_scale(const LQuaternion &quat, const LVecBase3 &scale)
Sets the rotation and scale components of the transform, leaving translation untouched.
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
This is the base class for a number of render attributes (other than transform) that may be set on sc...
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.
Defines the properties of a named stage of the multitexture pipeline.
Indicates a coordinate-system transform on vertices.
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
float csin_over_x(float v)
Computes sin(x) / x, well-behaved as x approaches 0.
Definition cmath.I:77
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.