Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

direct/src/interval/cLerpNodePathInterval.cxx

Go to the documentation of this file.
00001 // Filename: cLerpNodePathInterval.cxx
00002 // Created by:  drose (27Aug02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "cLerpNodePathInterval.h"
00020 #include "lerp_helpers.h"
00021 #include "transformState.h"
00022 #include "renderState.h"
00023 #include "colorAttrib.h"
00024 #include "colorScaleAttrib.h"
00025 #include "dcast.h"
00026 #include "config_interval.h"
00027 
00028 TypeHandle CLerpNodePathInterval::_type_handle;
00029 
00030 ////////////////////////////////////////////////////////////////////
00031 //     Function: CLerpNodePathInterval::Constructor
00032 //       Access: Published
00033 //  Description: Constructs a lerp interval that will lerp some
00034 //               properties on the indicated node, possibly relative
00035 //               to the indicated other node (if other is nonempty).
00036 //
00037 //               You must call set_end_pos(), etc. for the various
00038 //               properties you wish to lerp before the first call to
00039 //               priv_initialize().  If you want to set a starting value
00040 //               for any of the properties, you may call
00041 //               set_start_pos(), etc.; otherwise, the starting value
00042 //               is taken from the actual node's value at the time the
00043 //               lerp is performed.
00044 //
00045 //               The starting values may be explicitly specified or
00046 //               omitted.  The value of bake_in_start determines the
00047 //               behavior if the starting values are omitted.  If
00048 //               bake_in_start is true, the values are obtained the
00049 //               first time the lerp runs, and thenceforth are stored
00050 //               within the interval.  If bake_in_start is false, the
00051 //               starting value is computed each frame, based on
00052 //               assuming the current value represents the value set
00053 //               from the last time the interval was run.  This
00054 //               "smart" behavior allows code to manipulate the object
00055 //               event while it is being lerped, and the lerp
00056 //               continues to apply in a sensible way.
00057 ////////////////////////////////////////////////////////////////////
00058 CLerpNodePathInterval::
00059 CLerpNodePathInterval(const string &name, double duration, 
00060                       CLerpInterval::BlendType blend_type,
00061                       bool bake_in_start,
00062                       const NodePath &node, const NodePath &other) :
00063   CLerpInterval(name, duration, blend_type),
00064   _node(node),
00065   _other(other),
00066   _flags(0)
00067 {
00068   if (bake_in_start) {
00069     _flags |= F_bake_in_start;
00070   }
00071   _prev_d = 0.0;
00072 }
00073 
00074 ////////////////////////////////////////////////////////////////////
00075 //     Function: CLerpNodePathInterval::initialize
00076 //       Access: Published, Virtual
00077 //  Description: This replaces the first call to priv_step(), and indicates
00078 //               that the interval has just begun.  This may be
00079 //               overridden by derived classes that need to do some
00080 //               explicit initialization on the first call.
00081 ////////////////////////////////////////////////////////////////////
00082 void CLerpNodePathInterval::
00083 priv_initialize(double t) {
00084   check_stopped(get_class_type(), "priv_initialize");
00085   recompute();
00086   _prev_d = 0.0;
00087   _state = S_started;
00088   priv_step(t);
00089 }
00090 
00091 ////////////////////////////////////////////////////////////////////
00092 //     Function: CLerpNodePathInterval::instant
00093 //       Access: Published, Virtual
00094 //  Description: This is called in lieu of priv_initialize() .. priv_step()
00095 //               .. priv_finalize(), when everything is to happen within
00096 //               one frame.  The interval should initialize itself,
00097 //               then leave itself in the final state.
00098 ////////////////////////////////////////////////////////////////////
00099 void CLerpNodePathInterval::
00100 priv_instant() {
00101   check_stopped(get_class_type(), "priv_instant");
00102   recompute();
00103   _prev_d = 0.0;
00104   _state = S_started;
00105   priv_step(get_duration());
00106   _state = S_final;
00107 }
00108 
00109 ////////////////////////////////////////////////////////////////////
00110 //     Function: CLerpNodePathInterval::step
00111 //       Access: Published, Virtual
00112 //  Description: Advances the time on the interval.  The time may
00113 //               either increase (the normal case) or decrease
00114 //               (e.g. if the interval is being played by a slider).
00115 ////////////////////////////////////////////////////////////////////
00116 void CLerpNodePathInterval::
00117 priv_step(double t) {
00118   check_started(get_class_type(), "priv_step");
00119   _state = S_started;
00120   double d = compute_delta(t);
00121 
00122   if ((_flags & (F_end_pos | F_end_hpr | F_end_scale)) != 0) {
00123     // We have some transform lerp.
00124     CPT(TransformState) transform;
00125 
00126     if (_other.is_empty()) {
00127       // If there is no other node, it's a local transform lerp.
00128       transform = _node.get_transform();
00129     } else {
00130       // If there *is* another node, we get the transform relative to
00131       // that node.
00132       transform = _node.get_transform(_other);
00133     }
00134     
00135     LPoint3f pos;
00136     LVecBase3f hpr;
00137     LVecBase3f scale;
00138 
00139     if ((_flags & F_end_pos) != 0) {
00140       if ((_flags & F_start_pos) != 0) {
00141         lerp_value(pos, d, _start_pos, _end_pos);
00142 
00143       } else if ((_flags & F_bake_in_start) != 0) {
00144         // Get the current starting pos, and bake it in.
00145         set_start_pos(transform->get_pos());
00146         lerp_value(pos, d, _start_pos, _end_pos);
00147 
00148       } else {
00149         // "smart" lerp from the current pos to the new pos.
00150         pos = transform->get_pos();
00151         lerp_value_from_prev(pos, d, _prev_d, pos, _end_pos);
00152       }
00153     }
00154     if ((_flags & F_end_hpr) != 0) {
00155       if ((_flags & F_start_hpr) != 0) {
00156         lerp_value(hpr, d, _start_hpr, _end_hpr);
00157 
00158       } else if ((_flags & F_bake_in_start) != 0) {
00159         set_start_hpr(transform->get_hpr());
00160         lerp_value(hpr, d, _start_hpr, _end_hpr);
00161 
00162       } else {
00163         hpr = transform->get_hpr();
00164         lerp_value_from_prev(hpr, d, _prev_d, hpr, _end_hpr);
00165       }
00166     }
00167     if ((_flags & F_end_scale) != 0) {
00168       if ((_flags & F_start_scale) != 0) {
00169         lerp_value(scale, d, _start_scale, _end_scale);
00170 
00171       } else if ((_flags & F_bake_in_start) != 0) {
00172         set_start_scale(transform->get_scale());
00173         lerp_value(scale, d, _start_scale, _end_scale);
00174 
00175       } else {
00176         scale = transform->get_scale();
00177         lerp_value_from_prev(scale, d, _prev_d, scale, _end_scale);
00178       }
00179     }
00180 
00181     // Now apply the modifications back to the transform.  We want to
00182     // be a little careful here, because we don't want to assume the
00183     // transform has hpr/scale components if they're not needed.  And
00184     // in any case, we only want to apply the components that we
00185     // computed, above.
00186     switch (_flags & (F_end_pos | F_end_hpr | F_end_scale)) {
00187     case F_end_pos:
00188       transform = transform->set_pos(pos);
00189       break;
00190 
00191     case F_end_hpr:
00192       transform = transform->set_hpr(hpr);
00193       break;
00194 
00195     case F_end_scale:
00196       transform = transform->set_scale(scale);
00197       break;
00198 
00199     case F_end_hpr | F_end_scale:
00200       transform = TransformState::make_pos_hpr_scale(transform->get_pos(), hpr, scale);
00201       break;
00202 
00203     case F_end_pos | F_end_hpr:
00204       transform = TransformState::make_pos_hpr_scale(pos, hpr, transform->get_scale());
00205       break;
00206 
00207     case F_end_pos | F_end_scale:
00208       if (transform->quat_given()) {
00209         transform = TransformState::make_pos_quat_scale(pos, transform->get_quat(), scale);
00210       } else {
00211         transform = TransformState::make_pos_hpr_scale(pos, transform->get_hpr(), scale);
00212       }
00213       break;
00214 
00215     case F_end_pos | F_end_hpr | F_end_scale:
00216       transform = TransformState::make_pos_hpr_scale(pos, hpr, scale);
00217       break;
00218 
00219     default:
00220       interval_cat.error()
00221         << "Internal error in CLerpNodePathInterval::priv_step().\n";
00222     }
00223 
00224     // Now apply the new transform back to the node.
00225     if (_other.is_empty()) {
00226       _node.set_transform(transform);
00227     } else {
00228       _node.set_transform(_other, transform);
00229     }
00230   }
00231 
00232   if ((_flags & (F_end_color | F_end_color_scale)) != 0) {
00233     // We have some render state lerp.
00234     CPT(RenderState) state;
00235 
00236     if (_other.is_empty()) {
00237       // If there is no other node, it's a local state lerp.  This is
00238       // most common.
00239       state = _node.get_state();
00240     } else {
00241       // If there *is* another node, we get the state relative to that
00242       // node.  This is weird, but you could lerp color (for instance)
00243       // relative to some other node's color.
00244       state = _node.get_state(_other);
00245     }
00246     
00247     // Unlike in the transform case above, we can go ahead and modify
00248     // the state immediately with each attribute change, since these
00249     // attributes don't interrelate.
00250 
00251     if ((_flags & F_end_color) != 0) {
00252       Colorf color;
00253 
00254       if ((_flags & F_start_color) != 0) {
00255         lerp_value(color, d, _start_color, _end_color);
00256 
00257       } else {
00258         // Get the previous color.
00259         color.set(1.0f, 1.0f, 1.0f, 1.0f);
00260         const RenderAttrib *attrib =
00261           state->get_attrib(ColorAttrib::get_class_type());
00262         if (attrib != (const RenderAttrib *)NULL) {
00263           const ColorAttrib *ca = DCAST(ColorAttrib, attrib);
00264           if (ca->get_color_type() == ColorAttrib::T_flat) {
00265             color = ca->get_color();
00266           }
00267         }
00268 
00269         lerp_value_from_prev(color, d, _prev_d, color, _end_color);
00270       }
00271 
00272       state = state->add_attrib(ColorAttrib::make_flat(color));
00273     }
00274 
00275     if ((_flags & F_end_color_scale) != 0) {
00276       LVecBase4f color_scale;
00277 
00278       if ((_flags & F_start_color_scale) != 0) {
00279         lerp_value(color_scale, d, _start_color_scale, _end_color_scale);
00280 
00281       } else {
00282         // Get the previous color scale.
00283         color_scale.set(1.0f, 1.0f, 1.0f, 1.0f);
00284         const RenderAttrib *attrib =
00285           state->get_attrib(ColorScaleAttrib::get_class_type());
00286         if (attrib != (const RenderAttrib *)NULL) {
00287           const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
00288           color_scale = csa->get_scale();
00289         }
00290 
00291         lerp_value_from_prev(color_scale, d, _prev_d, color_scale, _end_color_scale);
00292       }
00293 
00294       state = state->add_attrib(ColorScaleAttrib::make(color_scale));
00295     }    
00296 
00297     // Now apply the new state back to the node.
00298     if (_other.is_empty()) {
00299       _node.set_state(state);
00300     } else {
00301       _node.set_state(_other, state);
00302     }
00303   }
00304 
00305   _prev_d = d;
00306   _curr_t = t;
00307 }
00308 
00309 ////////////////////////////////////////////////////////////////////
00310 //     Function: CLerpNodePathInterval::reverse_initialize
00311 //       Access: Published, Virtual
00312 //  Description: Similar to priv_initialize(), but this is called when the
00313 //               interval is being played backwards; it indicates that
00314 //               the interval should start at the finishing state and
00315 //               undo any intervening intervals.
00316 ////////////////////////////////////////////////////////////////////
00317 void CLerpNodePathInterval::
00318 priv_reverse_initialize(double t) {
00319   check_stopped(get_class_type(), "priv_reverse_initialize");
00320   recompute();
00321   _state = S_started;
00322   _prev_d = 1.0;
00323   priv_step(t);
00324 }
00325 
00326 ////////////////////////////////////////////////////////////////////
00327 //     Function: CLerpNodePathInterval::reverse_instant
00328 //       Access: Published, Virtual
00329 //  Description: This is called in lieu of priv_reverse_initialize()
00330 //               .. priv_step() .. priv_reverse_finalize(), when everything is
00331 //               to happen within one frame.  The interval should
00332 //               initialize itself, then leave itself in the initial
00333 //               state.
00334 ////////////////////////////////////////////////////////////////////
00335 void CLerpNodePathInterval::
00336 priv_reverse_instant() {
00337   check_stopped(get_class_type(), "priv_reverse_initialize");
00338   recompute();
00339   _state = S_started;
00340   _prev_d = 1.0;
00341   priv_step(0.0);
00342   _state = S_initial;
00343 }
00344 
00345 ////////////////////////////////////////////////////////////////////
00346 //     Function: CLerpNodePathInterval::output
00347 //       Access: Published, Virtual
00348 //  Description: 
00349 ////////////////////////////////////////////////////////////////////
00350 void CLerpNodePathInterval::
00351 output(ostream &out) const {
00352   out << get_name() << ":";
00353 
00354   if ((_flags & F_end_pos) != 0) {
00355     out << " pos";
00356     if ((_flags & F_start_pos) != 0) {
00357       out << " from " << _start_pos;
00358     }
00359     out << " to " << _end_pos;
00360   }
00361 
00362   if ((_flags & F_end_hpr) != 0) {
00363     out << " hpr";
00364     if ((_flags & F_start_hpr) != 0) {
00365       out << " from " << _start_hpr;
00366     }
00367     out << " to " << _end_hpr;
00368   }
00369 
00370   if ((_flags & F_end_scale) != 0) {
00371     out << " scale";
00372     if ((_flags & F_start_scale) != 0) {
00373       out << " from " << _start_scale;
00374     }
00375     out << " to " << _end_scale;
00376   }
00377 
00378   if ((_flags & F_end_color) != 0) {
00379     out << " color";
00380     if ((_flags & F_start_color) != 0) {
00381       out << " from " << _start_color;
00382     }
00383     out << " to " << _end_color;
00384   }
00385 
00386   if ((_flags & F_end_color_scale) != 0) {
00387     out << " color_scale";
00388     if ((_flags & F_start_color_scale) != 0) {
00389       out << " from " << _start_color_scale;
00390     }
00391     out << " to " << _end_color_scale;
00392   }
00393 
00394   out << " dur " << get_duration();
00395 }

Generated on Fri May 2 01:37:44 2003 for Direct by doxygen1.3