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 ¶ms) { 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 }