Panda3D
 All Classes Functions Variables Enumerations
texProjectorEffect.cxx
00001 // Filename: texProjectorEffect.cxx
00002 // Created by:  drose (25Jul04)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "texProjectorEffect.h"
00016 #include "cullTraverserData.h"
00017 #include "texMatrixAttrib.h"
00018 #include "lensNode.h"
00019 #include "config_pgraph.h"
00020 #include "nodePath.h"
00021 #include "bamReader.h"
00022 #include "bamWriter.h"
00023 #include "datagram.h"
00024 #include "datagramIterator.h"
00025 
00026 CPT(RenderEffect) TexProjectorEffect::_empty_effect;
00027 TypeHandle TexProjectorEffect::_type_handle;
00028 
00029 ////////////////////////////////////////////////////////////////////
00030 //     Function: TexProjectorEffect::Destructor
00031 //       Access: Public, Virtual
00032 //  Description: 
00033 ////////////////////////////////////////////////////////////////////
00034 TexProjectorEffect::
00035 ~TexProjectorEffect() {
00036 }
00037 
00038 ////////////////////////////////////////////////////////////////////
00039 //     Function: TexProjectorEffect::make
00040 //       Access: Published, Static
00041 //  Description: Constructs a TexProjectorEffect that modifies
00042 //               no stages at all.
00043 ////////////////////////////////////////////////////////////////////
00044 CPT(RenderEffect) TexProjectorEffect::
00045 make() {
00046   // We make it a special case and store a pointer to the empty effect
00047   // forever once we find it the first time, as an optimization.
00048   if (_empty_effect == (RenderEffect *)NULL) {
00049     _empty_effect = return_new(new TexProjectorEffect);
00050   }
00051 
00052   return _empty_effect;
00053 }
00054 
00055 ////////////////////////////////////////////////////////////////////
00056 //     Function: TexProjectorEffect::add_stage
00057 //       Access: Published, Static
00058 //  Description: Returns a new TexProjectorEffect just like this one,
00059 //               with the indicated projection for the given stage.
00060 //               If this stage already exists, its projection
00061 //               definition is replaced.
00062 //
00063 //               The relative transform between the "from" and the
00064 //               "to" nodes is automatically applied to the texture
00065 //               transform each frame.
00066 //
00067 //               Furthermore, if the "to" node is a LensNode, its
00068 //               projection matrix is also applied to the texture
00069 //               transform.
00070 ////////////////////////////////////////////////////////////////////
00071 CPT(RenderEffect) TexProjectorEffect::
00072 add_stage(TextureStage *stage, const NodePath &from, const NodePath &to) const {
00073   TexProjectorEffect *effect = new TexProjectorEffect(*this);
00074   StageDef &def = effect->_stages[stage];
00075   def.set_from(from);
00076   def.set_to(to);
00077   return return_new(effect);
00078 }
00079 
00080 ////////////////////////////////////////////////////////////////////
00081 //     Function: TexProjectorEffect::remove_stage
00082 //       Access: Published, Static
00083 //  Description: Returns a new TexProjectorEffect just like this one,
00084 //               with the indicated stage removed.
00085 ////////////////////////////////////////////////////////////////////
00086 CPT(RenderEffect) TexProjectorEffect::
00087 remove_stage(TextureStage *stage) const {
00088   TexProjectorEffect *effect = new TexProjectorEffect(*this);
00089   effect->_stages.erase(stage);
00090   return return_new(effect);
00091 }
00092 
00093 ////////////////////////////////////////////////////////////////////
00094 //     Function: TexProjectorEffect::is_empty
00095 //       Access: Published
00096 //  Description: Returns true if no stages are defined in the
00097 //               TexProjectorEffect, false if at least one is.
00098 ////////////////////////////////////////////////////////////////////
00099 bool TexProjectorEffect::
00100 is_empty() const {
00101   return _stages.empty();
00102 }
00103 
00104 ////////////////////////////////////////////////////////////////////
00105 //     Function: TexProjectorEffect::has_stage
00106 //       Access: Published
00107 //  Description: Returns true if there is a transform associated with
00108 //               the indicated stage, or false otherwise (in which
00109 //               case get_transform(stage) will return the identity
00110 //               transform).
00111 ////////////////////////////////////////////////////////////////////
00112 bool TexProjectorEffect::
00113 has_stage(TextureStage *stage) const {
00114   Stages::const_iterator mi = _stages.find(stage);
00115   return (mi != _stages.end());
00116 }
00117 
00118 ////////////////////////////////////////////////////////////////////
00119 //     Function: TexProjectorEffect::get_from
00120 //       Access: Published
00121 //  Description: Returns the "from" node associated with the
00122 //               TexProjectorEffect on the indicated stage.  The
00123 //               relative transform between the "from" and the "to"
00124 //               nodes is automatically applied to the texture
00125 //               transform each frame.
00126 ////////////////////////////////////////////////////////////////////
00127 NodePath TexProjectorEffect::
00128 get_from(TextureStage *stage) const {
00129   Stages::const_iterator mi = _stages.find(stage);
00130   nassertr(mi != _stages.end(), NodePath::fail());
00131   return (*mi).second._from;
00132 }
00133 
00134 ////////////////////////////////////////////////////////////////////
00135 //     Function: TexProjectorEffect::get_to
00136 //       Access: Published
00137 //  Description: Returns the "to" node associated with the
00138 //               TexProjectorEffect on the indicated stage.  The
00139 //               relative transform between the "from" and the "to"
00140 //               nodes is automatically applied to the texture
00141 //               transform each frame.
00142 //
00143 //               Furthermore, if the "to" node is a LensNode, its
00144 //               projection matrix is also applied to the texture
00145 //               transform.
00146 ////////////////////////////////////////////////////////////////////
00147 NodePath TexProjectorEffect::
00148 get_to(TextureStage *stage) const {
00149   Stages::const_iterator mi = _stages.find(stage);
00150   nassertr(mi != _stages.end(), NodePath::fail());
00151   return (*mi).second._to;
00152 }
00153 
00154 ////////////////////////////////////////////////////////////////////
00155 //     Function: TexProjectorEffect::output
00156 //       Access: Public, Virtual
00157 //  Description: 
00158 ////////////////////////////////////////////////////////////////////
00159 void TexProjectorEffect::
00160 output(ostream &out) const {
00161   out << get_type() << ":";
00162 
00163   Stages::const_iterator mi;
00164   for (mi = _stages.begin(); mi != _stages.end(); ++mi) {
00165     TextureStage *stage = (*mi).first;
00166     const StageDef &def = (*mi).second;
00167     out << " " << stage->get_name() << "(" << def._to
00168         << ", " << def._from << ")";
00169   }
00170 }
00171 
00172 ////////////////////////////////////////////////////////////////////
00173 //     Function: TexProjectorEffect::has_cull_callback
00174 //       Access: Public, Virtual
00175 //  Description: Should be overridden by derived classes to return
00176 //               true if cull_callback() has been defined.  Otherwise,
00177 //               returns false to indicate cull_callback() does not
00178 //               need to be called for this effect during the cull
00179 //               traversal.
00180 ////////////////////////////////////////////////////////////////////
00181 bool TexProjectorEffect::
00182 has_cull_callback() const {
00183   return !_stages.empty();
00184 }
00185 
00186 ////////////////////////////////////////////////////////////////////
00187 //     Function: TexProjectorEffect::cull_callback
00188 //       Access: Public, Virtual
00189 //  Description: If has_cull_callback() returns true, this function
00190 //               will be called during the cull traversal to perform
00191 //               any additional operations that should be performed at
00192 //               cull time.  This may include additional manipulation
00193 //               of render state or additional visible/invisible
00194 //               decisions, or any other arbitrary operation.
00195 //
00196 //               At the time this function is called, the current
00197 //               node's transform and state have not yet been applied
00198 //               to the net_transform and net_state.  This callback
00199 //               may modify the node_transform and node_state to apply
00200 //               an effective change to the render state at this
00201 //               level.
00202 ////////////////////////////////////////////////////////////////////
00203 void TexProjectorEffect::
00204 cull_callback(CullTraverser *trav, CullTraverserData &data,
00205               CPT(TransformState) &node_transform,
00206               CPT(RenderState) &node_state) const {
00207   CPT(TexMatrixAttrib) tex_matrix = DCAST(TexMatrixAttrib, TexMatrixAttrib::make());
00208 
00209   Stages::const_iterator mi;
00210   for (mi = _stages.begin(); mi != _stages.end(); ++mi) {
00211     TextureStage *stage = (*mi).first;
00212     const StageDef &def = (*mi).second;
00213 
00214     CPT(TransformState) transform = def._from.get_transform(def._to);
00215 
00216     if (def._to_lens_node != (LensNode *)NULL &&
00217         def._to_lens_node->get_lens() != (Lens *)NULL) {
00218       
00219       // Get the lens's projection matrix, as a TransformState.
00220       CPT(TransformState) projmat = TransformState::make_mat(def._to_lens_node->get_lens()->get_projection_mat());
00221 
00222       // We need a special transform to convert the -0.5, 0.5
00223       // centering of the lens's projection matrix to UV's in the
00224       // range of (0, 1).
00225       static CPT(TransformState) fixmat;
00226       if (fixmat == (TransformState *)NULL) {
00227         fixmat = TransformState::make_pos_hpr_scale
00228           (LVecBase3(0.5f, 0.5f, 0.0f),
00229            LVecBase3(0.0f, 0.0f, 0.0f),
00230            LVecBase3(0.5f, 0.5f, 1.0f));
00231       }
00232 
00233       // Now apply both to the current transform.
00234       transform = fixmat->compose(projmat)->compose(transform);
00235     }
00236 
00237     if (!transform->is_identity()) {
00238       tex_matrix = DCAST(TexMatrixAttrib, 
00239                          tex_matrix->add_stage(stage, transform));
00240     }
00241   }
00242 
00243   if (!tex_matrix->is_empty()) {
00244     node_state = node_state->compose(RenderState::make(tex_matrix));
00245   }
00246 }
00247 
00248 ////////////////////////////////////////////////////////////////////
00249 //     Function: TexProjectorEffect::compare_to_impl
00250 //       Access: Protected, Virtual
00251 //  Description: Intended to be overridden by derived TexProjectorEffect
00252 //               types to return a unique number indicating whether
00253 //               this TexProjectorEffect is equivalent to the other one.
00254 //
00255 //               This should return 0 if the two TexProjectorEffect objects
00256 //               are equivalent, a number less than zero if this one
00257 //               should be sorted before the other one, and a number
00258 //               greater than zero otherwise.
00259 //
00260 //               This will only be called with two TexProjectorEffect
00261 //               objects whose get_type() functions return the same.
00262 ////////////////////////////////////////////////////////////////////
00263 int TexProjectorEffect::
00264 compare_to_impl(const RenderEffect *other) const {
00265   const TexProjectorEffect *ta;
00266   DCAST_INTO_R(ta, other, 0);
00267   
00268   Stages::const_iterator ai, bi;
00269   ai = _stages.begin();
00270   bi = ta->_stages.begin();
00271   while (ai != _stages.end() && bi != ta->_stages.end()) {
00272     if ((*ai).first < (*bi).first) {
00273       // This stage is in a but not in b.
00274       return -1;
00275 
00276     } else if ((*bi).first < (*ai).first) {
00277       // This stage is in b but not in a.
00278       return 1;
00279 
00280     } else {
00281       // This stage is in both; compare the stages.
00282       int compare = (*ai).second.compare_to((*bi).second);
00283       if (compare != 0) {
00284         return compare;
00285       }
00286       ++ai;
00287       ++bi;
00288     }
00289   }
00290 
00291   if (bi != ta->_stages.end()) {
00292     // a ran out first; b was longer.
00293     return -1;
00294   }
00295 
00296   if (ai != _stages.end()) {
00297     // b ran out first; a was longer.
00298     return 1;
00299   }
00300 
00301   return 0;
00302 }
00303 
00304 ////////////////////////////////////////////////////////////////////
00305 //     Function: TexProjectorEffect::register_with_read_factory
00306 //       Access: Public, Static
00307 //  Description: Tells the BamReader how to create objects of type
00308 //               TexProjectorEffect.
00309 ////////////////////////////////////////////////////////////////////
00310 void TexProjectorEffect::
00311 register_with_read_factory() {
00312   BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
00313 }
00314 
00315 ////////////////////////////////////////////////////////////////////
00316 //     Function: TexProjectorEffect::write_datagram
00317 //       Access: Public, Virtual
00318 //  Description: Writes the contents of this object to the datagram
00319 //               for shipping out to a Bam file.
00320 ////////////////////////////////////////////////////////////////////
00321 void TexProjectorEffect::
00322 write_datagram(BamWriter *manager, Datagram &dg) {
00323   RenderEffect::write_datagram(manager, dg);
00324 
00325   // For now, we don't write anything to the bam file for a
00326   // TexProjectorEffect, except a bogus 0 "size" which may one day
00327   // indicate the number of stages in the map that we might write out.
00328   dg.add_uint16(0);
00329 
00330   // One day we will write the whole map out.  We don't do this yet,
00331   // because (a) we don't have an interface for writing out NodePaths
00332   // to a bam file, and (b) it won't matter until we have the
00333   // Panda-monium system in place, since you can't load a
00334   // TexProjectorEffect from an egg file.
00335 }
00336 
00337 ////////////////////////////////////////////////////////////////////
00338 //     Function: TexProjectorEffect::complete_pointers
00339 //       Access: Public, Virtual
00340 //  Description: Receives an array of pointers, one for each time
00341 //               manager->read_pointer() was called in fillin().
00342 //               Returns the number of pointers processed.
00343 ////////////////////////////////////////////////////////////////////
00344 int TexProjectorEffect::
00345 complete_pointers(TypedWritable **p_list, BamReader *manager) {
00346   int pi = RenderEffect::complete_pointers(p_list, manager);
00347 
00348   return pi;
00349 }
00350 
00351 ////////////////////////////////////////////////////////////////////
00352 //     Function: TexProjectorEffect::make_from_bam
00353 //       Access: Protected, Static
00354 //  Description: This function is called by the BamReader's factory
00355 //               when a new object of type TexProjectorEffect is encountered
00356 //               in the Bam file.  It should create the TexProjectorEffect
00357 //               and extract its information from the file.
00358 ////////////////////////////////////////////////////////////////////
00359 TypedWritable *TexProjectorEffect::
00360 make_from_bam(const FactoryParams &params) {
00361   TexProjectorEffect *effect = new TexProjectorEffect;
00362   DatagramIterator scan;
00363   BamReader *manager;
00364 
00365   parse_params(params, scan, manager);
00366   effect->fillin(scan, manager);
00367 
00368   return effect;
00369 }
00370 
00371 ////////////////////////////////////////////////////////////////////
00372 //     Function: TexProjectorEffect::fillin
00373 //       Access: Protected
00374 //  Description: This internal function is called by make_from_bam to
00375 //               read in all of the relevant data from the BamFile for
00376 //               the new TexProjectorEffect.
00377 ////////////////////////////////////////////////////////////////////
00378 void TexProjectorEffect::
00379 fillin(DatagramIterator &scan, BamReader *manager) {
00380   RenderEffect::fillin(scan, manager);
00381 
00382   size_t num_stages = scan.get_uint16();
00383 
00384   // Since we don't support full reading and writing of
00385   // TexProjectorEffects yet, this value had better be zero.  If it's
00386   // not, maybe we're trying to read a bam file that was generated by
00387   // some future version of Panda that does support these things.
00388   nassertv(num_stages == 0);
00389 }
00390 
00391 ////////////////////////////////////////////////////////////////////
00392 //     Function: TexProjectorEffect::StageDef::set_to
00393 //       Access: Public
00394 //  Description: 
00395 ////////////////////////////////////////////////////////////////////
00396 void TexProjectorEffect::StageDef::
00397 set_to(const NodePath &to) {
00398   _to = to;
00399   if (!_to.is_empty() && _to.node()->is_of_type(LensNode::get_class_type())) {
00400     DCAST_INTO_V(_to_lens_node, _to.node());
00401   } else {
00402     _to_lens_node = (LensNode *)NULL;
00403   }
00404 }
 All Classes Functions Variables Enumerations