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