Panda3D
|
00001 // Filename: renderEffects.cxx 00002 // Created by: drose (14Mar02) 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 "renderEffects.h" 00016 #include "billboardEffect.h" 00017 #include "decalEffect.h" 00018 #include "compassEffect.h" 00019 #include "polylightEffect.h" 00020 #include "showBoundsEffect.h" 00021 #include "config_pgraph.h" 00022 #include "bamReader.h" 00023 #include "bamWriter.h" 00024 #include "datagramIterator.h" 00025 #include "indent.h" 00026 #include "compareTo.h" 00027 #include "lightReMutexHolder.h" 00028 #include "lightMutexHolder.h" 00029 #include "thread.h" 00030 00031 #include <iterator> 00032 00033 LightReMutex *RenderEffects::_states_lock = NULL; 00034 RenderEffects::States *RenderEffects::_states = NULL; 00035 CPT(RenderEffects) RenderEffects::_empty_state; 00036 TypeHandle RenderEffects::_type_handle; 00037 00038 //////////////////////////////////////////////////////////////////// 00039 // Function: RenderEffects::Constructor 00040 // Access: Protected 00041 // Description: Actually, this could be a private constructor, since 00042 // no one inherits from RenderEffects, but gcc gives us a 00043 // spurious warning if all constructors are private. 00044 //////////////////////////////////////////////////////////////////// 00045 RenderEffects:: 00046 RenderEffects() : _lock("RenderEffects") { 00047 if (_states == (States *)NULL) { 00048 init_states(); 00049 } 00050 _saved_entry = _states->end(); 00051 _flags = 0; 00052 } 00053 00054 //////////////////////////////////////////////////////////////////// 00055 // Function: RenderEffects::Copy Constructor 00056 // Access: Private 00057 // Description: RenderEffects are not meant to be copied. 00058 //////////////////////////////////////////////////////////////////// 00059 RenderEffects:: 00060 RenderEffects(const RenderEffects &) { 00061 nassertv(false); 00062 } 00063 00064 //////////////////////////////////////////////////////////////////// 00065 // Function: RenderEffects::Copy Assignment Operator 00066 // Access: Private 00067 // Description: RenderEffects are not meant to be copied. 00068 //////////////////////////////////////////////////////////////////// 00069 void RenderEffects:: 00070 operator = (const RenderEffects &) { 00071 nassertv(false); 00072 } 00073 00074 //////////////////////////////////////////////////////////////////// 00075 // Function: RenderEffects::Destructor 00076 // Access: Public, Virtual 00077 // Description: The destructor is responsible for removing the 00078 // RenderEffects from the global set if it is there. 00079 //////////////////////////////////////////////////////////////////// 00080 RenderEffects:: 00081 ~RenderEffects() { 00082 // Remove the deleted RenderEffects object from the global pool. 00083 LightReMutexHolder holder(*_states_lock); 00084 00085 // unref() should have cleared this. 00086 nassertv(_saved_entry == _states->end()); 00087 } 00088 00089 //////////////////////////////////////////////////////////////////// 00090 // Function: RenderEffects::safe_to_transform 00091 // Access: Public 00092 // Description: Returns true if all of the effects in this set can 00093 // safely be transformed, and therefore the complete set 00094 // can be transformed, by calling xform(). 00095 //////////////////////////////////////////////////////////////////// 00096 bool RenderEffects:: 00097 safe_to_transform() const { 00098 Effects::const_iterator ai; 00099 for (ai = _effects.begin(); ai != _effects.end(); ++ai) { 00100 const Effect &effect = (*ai); 00101 if (!effect._effect->safe_to_transform()) { 00102 return false; 00103 } 00104 } 00105 00106 return true; 00107 } 00108 00109 //////////////////////////////////////////////////////////////////// 00110 // Function: RenderEffects::prepare_flatten_transform 00111 // Access: Public, Virtual 00112 // Description: Preprocesses the accumulated transform that is about 00113 // to be applied to (or through) this node due to a 00114 // flatten operation. The returned value will be used 00115 // instead. 00116 //////////////////////////////////////////////////////////////////// 00117 CPT(TransformState) RenderEffects:: 00118 prepare_flatten_transform(const TransformState *net_transform) const { 00119 CPT(TransformState) result = net_transform; 00120 Effects::const_iterator ai; 00121 for (ai = _effects.begin(); ai != _effects.end(); ++ai) { 00122 const Effect &effect = (*ai); 00123 result = effect._effect->prepare_flatten_transform(result); 00124 } 00125 00126 return result; 00127 } 00128 00129 //////////////////////////////////////////////////////////////////// 00130 // Function: RenderEffects::safe_to_combine 00131 // Access: Public 00132 // Description: Returns true if all of the effects in this set can 00133 // safely be shared with a sibling node that has the 00134 // exact same set of effects, or false if this would be 00135 // bad for any of the effects. 00136 //////////////////////////////////////////////////////////////////// 00137 bool RenderEffects:: 00138 safe_to_combine() const { 00139 Effects::const_iterator ai; 00140 for (ai = _effects.begin(); ai != _effects.end(); ++ai) { 00141 const Effect &effect = (*ai); 00142 if (!effect._effect->safe_to_combine()) { 00143 return false; 00144 } 00145 } 00146 00147 return true; 00148 } 00149 00150 //////////////////////////////////////////////////////////////////// 00151 // Function: RenderEffects::xform 00152 // Access: Public, Virtual 00153 // Description: Returns a new RenderEffects transformed by the 00154 // indicated matrix. 00155 //////////////////////////////////////////////////////////////////// 00156 CPT(RenderEffects) RenderEffects:: 00157 xform(const LMatrix4 &mat) const { 00158 if (is_empty()) { 00159 return this; 00160 } 00161 00162 RenderEffects *new_state = new RenderEffects; 00163 back_insert_iterator<Effects> result = 00164 back_inserter(new_state->_effects); 00165 00166 Effects::const_iterator ai; 00167 for (ai = _effects.begin(); ai != _effects.end(); ++ai) { 00168 const Effect &effect = (*ai); 00169 Effect new_effect(effect); 00170 new_effect._effect = effect._effect->xform(mat); 00171 *result = new_effect; 00172 ++result; 00173 } 00174 00175 return return_new(new_state); 00176 } 00177 00178 //////////////////////////////////////////////////////////////////// 00179 // Function: RenderEffects::operator < 00180 // Access: Published 00181 // Description: Provides an arbitrary ordering among all unique 00182 // RenderEffects, so we can store the essentially 00183 // different ones in a big set and throw away the rest. 00184 // 00185 // This method is not needed outside of the RenderEffects 00186 // class because all equivalent RenderEffects objects are 00187 // guaranteed to share the same pointer; thus, a pointer 00188 // comparison is always sufficient. 00189 //////////////////////////////////////////////////////////////////// 00190 bool RenderEffects:: 00191 operator < (const RenderEffects &other) const { 00192 // We must compare all the properties of the effects, not just 00193 // the type; thus, we compare them one at a time using compare_to(). 00194 return lexicographical_compare(_effects.begin(), _effects.end(), 00195 other._effects.begin(), other._effects.end(), 00196 CompareTo<Effect>()); 00197 } 00198 00199 00200 //////////////////////////////////////////////////////////////////// 00201 // Function: RenderEffects::find_effect 00202 // Access: Published 00203 // Description: Searches for an effect with the indicated type in 00204 // the state, and returns its index if it is found, or 00205 // -1 if it is not. 00206 //////////////////////////////////////////////////////////////////// 00207 int RenderEffects:: 00208 find_effect(TypeHandle type) const { 00209 Effects::const_iterator ai = _effects.find(Effect(type)); 00210 if (ai == _effects.end()) { 00211 return -1; 00212 } 00213 return ai - _effects.begin(); 00214 } 00215 00216 //////////////////////////////////////////////////////////////////// 00217 // Function: RenderEffects::make_empty 00218 // Access: Published, Static 00219 // Description: Returns a RenderEffects with no effects set. 00220 //////////////////////////////////////////////////////////////////// 00221 CPT(RenderEffects) RenderEffects:: 00222 make_empty() { 00223 // The empty state is asked for so often, we make it a special case 00224 // and store a pointer forever once we find it the first time. 00225 if (_empty_state == (RenderEffects *)NULL) { 00226 RenderEffects *state = new RenderEffects; 00227 _empty_state = return_new(state); 00228 } 00229 00230 return _empty_state; 00231 } 00232 00233 //////////////////////////////////////////////////////////////////// 00234 // Function: RenderEffects::make 00235 // Access: Published, Static 00236 // Description: Returns a RenderEffects with one effect set. 00237 //////////////////////////////////////////////////////////////////// 00238 CPT(RenderEffects) RenderEffects:: 00239 make(const RenderEffect *effect) { 00240 RenderEffects *state = new RenderEffects; 00241 state->_effects.reserve(1); 00242 state->_effects.insert(Effect(effect)); 00243 return return_new(state); 00244 } 00245 00246 //////////////////////////////////////////////////////////////////// 00247 // Function: RenderEffects::make 00248 // Access: Published, Static 00249 // Description: Returns a RenderEffects with two effects set. 00250 //////////////////////////////////////////////////////////////////// 00251 CPT(RenderEffects) RenderEffects:: 00252 make(const RenderEffect *effect1, 00253 const RenderEffect *effect2) { 00254 RenderEffects *state = new RenderEffects; 00255 state->_effects.reserve(2); 00256 state->_effects.push_back(Effect(effect1)); 00257 state->_effects.push_back(Effect(effect2)); 00258 state->_effects.sort(); 00259 return return_new(state); 00260 } 00261 00262 //////////////////////////////////////////////////////////////////// 00263 // Function: RenderEffects::make 00264 // Access: Published, Static 00265 // Description: Returns a RenderEffects with three effects set. 00266 //////////////////////////////////////////////////////////////////// 00267 CPT(RenderEffects) RenderEffects:: 00268 make(const RenderEffect *effect1, 00269 const RenderEffect *effect2, 00270 const RenderEffect *effect3) { 00271 RenderEffects *state = new RenderEffects; 00272 state->_effects.reserve(2); 00273 state->_effects.push_back(Effect(effect1)); 00274 state->_effects.push_back(Effect(effect2)); 00275 state->_effects.push_back(Effect(effect3)); 00276 state->_effects.sort(); 00277 return return_new(state); 00278 } 00279 00280 //////////////////////////////////////////////////////////////////// 00281 // Function: RenderEffects::make 00282 // Access: Published, Static 00283 // Description: Returns a RenderEffects with four effects set. 00284 //////////////////////////////////////////////////////////////////// 00285 CPT(RenderEffects) RenderEffects:: 00286 make(const RenderEffect *effect1, 00287 const RenderEffect *effect2, 00288 const RenderEffect *effect3, 00289 const RenderEffect *effect4) { 00290 RenderEffects *state = new RenderEffects; 00291 state->_effects.reserve(2); 00292 state->_effects.push_back(Effect(effect1)); 00293 state->_effects.push_back(Effect(effect2)); 00294 state->_effects.push_back(Effect(effect3)); 00295 state->_effects.push_back(Effect(effect4)); 00296 state->_effects.sort(); 00297 return return_new(state); 00298 } 00299 00300 //////////////////////////////////////////////////////////////////// 00301 // Function: RenderEffects::add_effect 00302 // Access: Published 00303 // Description: Returns a new RenderEffects object that represents the 00304 // same as the source state, with the new RenderEffect 00305 // added. If there is already a RenderEffect with the 00306 // same type, it is replaced. 00307 //////////////////////////////////////////////////////////////////// 00308 CPT(RenderEffects) RenderEffects:: 00309 add_effect(const RenderEffect *effect) const { 00310 RenderEffects *new_state = new RenderEffects; 00311 back_insert_iterator<Effects> result = 00312 back_inserter(new_state->_effects); 00313 00314 Effect new_effect(effect); 00315 Effects::const_iterator ai = _effects.begin(); 00316 00317 while (ai != _effects.end() && (*ai) < new_effect) { 00318 *result = *ai; 00319 ++ai; 00320 ++result; 00321 } 00322 *result = new_effect; 00323 ++result; 00324 00325 if (ai != _effects.end() && !(new_effect < (*ai))) { 00326 // At this point we know: 00327 // !((*ai) < new_effect) && !(new_effect < (*ai)) 00328 // which means (*ai) == new_effect--so we should leave it out, 00329 // to avoid duplicating effects in the set. 00330 ++ai; 00331 } 00332 00333 while (ai != _effects.end()) { 00334 *result = *ai; 00335 ++ai; 00336 ++result; 00337 } 00338 00339 return return_new(new_state); 00340 } 00341 00342 //////////////////////////////////////////////////////////////////// 00343 // Function: RenderEffects::remove_effect 00344 // Access: Published 00345 // Description: Returns a new RenderEffects object that represents the 00346 // same as the source state, with the indicated 00347 // RenderEffect removed. 00348 //////////////////////////////////////////////////////////////////// 00349 CPT(RenderEffects) RenderEffects:: 00350 remove_effect(TypeHandle type) const { 00351 RenderEffects *new_state = new RenderEffects; 00352 back_insert_iterator<Effects> result = 00353 back_inserter(new_state->_effects); 00354 00355 Effects::const_iterator ai = _effects.begin(); 00356 00357 while (ai != _effects.end()) { 00358 if ((*ai)._type != type) { 00359 *result = *ai; 00360 ++result; 00361 } 00362 ++ai; 00363 } 00364 00365 return return_new(new_state); 00366 } 00367 00368 //////////////////////////////////////////////////////////////////// 00369 // Function: RenderEffects::get_effect 00370 // Access: Published, Virtual 00371 // Description: Looks for a RenderEffect of the indicated type in the 00372 // state, and returns it if it is found, or NULL if it 00373 // is not. 00374 //////////////////////////////////////////////////////////////////// 00375 const RenderEffect *RenderEffects:: 00376 get_effect(TypeHandle type) const { 00377 Effects::const_iterator ai; 00378 ai = _effects.find(Effect(type)); 00379 if (ai != _effects.end()) { 00380 return (*ai)._effect; 00381 } 00382 return NULL; 00383 } 00384 00385 //////////////////////////////////////////////////////////////////// 00386 // Function: RenderEffects::unref 00387 // Access: Published, Virtual 00388 // Description: This method overrides ReferenceCount::unref() to 00389 // check whether the remaining reference count is 00390 // entirely in the cache, and if so, it checks for and 00391 // breaks a cycle in the cache involving this object. 00392 // This is designed to prevent leaks from cyclical 00393 // references within the cache. 00394 // 00395 // Note that this is not a virtual method, and cannot be 00396 // because ReferenceCount itself declares no virtual 00397 // methods (it avoids the overhead of a virtual function 00398 // pointer). But this doesn't matter, because 00399 // PT(TransformState) is a template class, and will call 00400 // the appropriate method even though it is non-virtual. 00401 //////////////////////////////////////////////////////////////////// 00402 bool RenderEffects:: 00403 unref() const { 00404 LightReMutexHolder holder(*_states_lock); 00405 00406 if (ReferenceCount::unref()) { 00407 // The reference count is still nonzero. 00408 return true; 00409 } 00410 00411 // The reference count has just reached zero. Make sure the object 00412 // is removed from the global object pool, before anyone else finds 00413 // it and tries to ref it. 00414 ((RenderEffects *)this)->release_new(); 00415 00416 return false; 00417 } 00418 00419 //////////////////////////////////////////////////////////////////// 00420 // Function: RenderEffects::output 00421 // Access: Published, Virtual 00422 // Description: 00423 //////////////////////////////////////////////////////////////////// 00424 void RenderEffects:: 00425 output(ostream &out) const { 00426 out << "E:"; 00427 if (_effects.empty()) { 00428 out << "(empty)"; 00429 00430 } else { 00431 Effects::const_iterator ai = _effects.begin(); 00432 out << "(" << (*ai)._type; 00433 ++ai; 00434 while (ai != _effects.end()) { 00435 out << " " << (*ai)._type; 00436 ++ai; 00437 } 00438 out << ")"; 00439 } 00440 } 00441 00442 //////////////////////////////////////////////////////////////////// 00443 // Function: RenderEffects::write 00444 // Access: Published, Virtual 00445 // Description: 00446 //////////////////////////////////////////////////////////////////// 00447 void RenderEffects:: 00448 write(ostream &out, int indent_level) const { 00449 indent(out, indent_level) << _effects.size() << " effects:\n"; 00450 Effects::const_iterator ai; 00451 for (ai = _effects.begin(); ai != _effects.end(); ++ai) { 00452 const Effect &effect = (*ai); 00453 effect._effect->write(out, indent_level + 2); 00454 } 00455 } 00456 00457 //////////////////////////////////////////////////////////////////// 00458 // Function: RenderEffects::get_num_states 00459 // Access: Published, Static 00460 // Description: Returns the total number of unique RenderEffects 00461 // objects allocated in the world. This will go up and 00462 // down during normal operations. 00463 //////////////////////////////////////////////////////////////////// 00464 int RenderEffects:: 00465 get_num_states() { 00466 if (_states == (States *)NULL) { 00467 return 0; 00468 } 00469 LightReMutexHolder holder(*_states_lock); 00470 return _states->size(); 00471 } 00472 00473 //////////////////////////////////////////////////////////////////// 00474 // Function: RenderEffects::list_states 00475 // Access: Published, Static 00476 // Description: Lists all of the RenderEffects in the cache to the 00477 // output stream, one per line. This can be quite a lot 00478 // of output if the cache is large, so be prepared. 00479 //////////////////////////////////////////////////////////////////// 00480 void RenderEffects:: 00481 list_states(ostream &out) { 00482 out << _states->size() << " states:\n"; 00483 States::const_iterator si; 00484 for (si = _states->begin(); si != _states->end(); ++si) { 00485 const RenderEffects *state = (*si); 00486 state->write(out, 2); 00487 } 00488 } 00489 00490 //////////////////////////////////////////////////////////////////// 00491 // Function: RenderEffects::validate_states 00492 // Access: Published, Static 00493 // Description: Ensures that the cache is still stored in sorted 00494 // order. Returns true if so, false if there is a 00495 // problem (which implies someone has modified one of 00496 // the supposedly-const RenderEffects objects). 00497 //////////////////////////////////////////////////////////////////// 00498 bool RenderEffects:: 00499 validate_states() { 00500 if (_states->empty()) { 00501 return true; 00502 } 00503 LightReMutexHolder holder(*_states_lock); 00504 00505 States::const_iterator si = _states->begin(); 00506 States::const_iterator snext = si; 00507 ++snext; 00508 while (snext != _states->end()) { 00509 if (!(*(*si) < *(*snext))) { 00510 pgraph_cat.error() 00511 << "RenderEffects out of order!\n"; 00512 (*si)->write(pgraph_cat.error(false), 2); 00513 (*snext)->write(pgraph_cat.error(false), 2); 00514 return false; 00515 } 00516 if ((*(*snext) < *(*si))) { 00517 pgraph_cat.error() 00518 << "RenderEffects::operator < not defined properly!\n"; 00519 pgraph_cat.error(false) 00520 << "a < b: " << (*(*si) < *(*snext)) << "\n"; 00521 pgraph_cat.error(false) 00522 << "b < a: " << (*(*snext) < *(*si)) << "\n"; 00523 (*si)->write(pgraph_cat.error(false), 2); 00524 (*snext)->write(pgraph_cat.error(false), 2); 00525 return false; 00526 } 00527 si = snext; 00528 ++snext; 00529 } 00530 00531 return true; 00532 } 00533 00534 //////////////////////////////////////////////////////////////////// 00535 // Function: RenderEffects::cull_callback 00536 // Access: Public 00537 // Description: Calls cull_callback() on all effects. You may check 00538 // has_cull_callback() first to see if any effects 00539 // define this method to do anything useful. 00540 //////////////////////////////////////////////////////////////////// 00541 void RenderEffects:: 00542 cull_callback(CullTraverser *trav, CullTraverserData &data, 00543 CPT(TransformState) &node_transform, 00544 CPT(RenderState) &node_state) const { 00545 Effects::const_iterator ei; 00546 for (ei = _effects.begin(); ei != _effects.end(); ++ei) { 00547 (*ei)._effect->cull_callback(trav, data, node_transform, node_state); 00548 } 00549 } 00550 00551 //////////////////////////////////////////////////////////////////// 00552 // Function: RenderEffects::adjust_transform 00553 // Access: Public 00554 // Description: Calls adjust_transform() on all effects. You may check 00555 // has_adjust_transform() first to see if any effects 00556 // define this method to do anything useful. 00557 // 00558 // The order in which the individual effects are applied 00559 // is not defined, so if more than one effect applies a 00560 // change to the transform on any particular node, you 00561 // might get indeterminate results. 00562 //////////////////////////////////////////////////////////////////// 00563 void RenderEffects:: 00564 adjust_transform(CPT(TransformState) &net_transform, 00565 CPT(TransformState) &node_transform, 00566 PandaNode *node) const { 00567 Effects::const_iterator ei; 00568 for (ei = _effects.begin(); ei != _effects.end(); ++ei) { 00569 (*ei)._effect->adjust_transform(net_transform, node_transform, node); 00570 } 00571 } 00572 00573 //////////////////////////////////////////////////////////////////// 00574 // Function: RenderEffects::init_states 00575 // Access: Public, Static 00576 // Description: Make sure the global _states map is allocated. This 00577 // only has to be done once. We could make this map 00578 // static, but then we run into problems if anyone 00579 // creates a RenderEffects object at static init time; 00580 // it also seems to cause problems when the Panda shared 00581 // library is unloaded at application exit time. 00582 //////////////////////////////////////////////////////////////////// 00583 void RenderEffects:: 00584 init_states() { 00585 _states = new States; 00586 00587 // TODO: we should have a global Panda mutex to allow us to safely 00588 // create _states_lock without a startup race condition. For the 00589 // meantime, this is OK because we guarantee that this method is 00590 // called at static init time, presumably when there is still only 00591 // one thread in the world. 00592 _states_lock = new LightReMutex("RenderEffects::_states_lock"); 00593 nassertv(Thread::get_current_thread() == Thread::get_main_thread()); 00594 } 00595 00596 00597 //////////////////////////////////////////////////////////////////// 00598 // Function: RenderEffects::return_new 00599 // Access: Private, Static 00600 // Description: This function is used to share a common RenderEffects 00601 // pointer for all equivalent RenderEffects objects. 00602 // 00603 // See the similar logic in RenderEffect. The idea is 00604 // to create a new RenderEffects object and pass it 00605 // through this function, which will share the pointer 00606 // with a previously-created RenderEffects object if it is 00607 // equivalent. 00608 //////////////////////////////////////////////////////////////////// 00609 CPT(RenderEffects) RenderEffects:: 00610 return_new(RenderEffects *state) { 00611 nassertr(state != (RenderEffects *)NULL, state); 00612 00613 #ifndef NDEBUG 00614 if (!state_cache) { 00615 return state; 00616 } 00617 #endif 00618 00619 #ifndef NDEBUG 00620 if (paranoid_const) { 00621 nassertr(validate_states(), state); 00622 } 00623 #endif 00624 00625 LightReMutexHolder holder(*_states_lock); 00626 00627 // This should be a newly allocated pointer, not one that was used 00628 // for anything else. 00629 nassertr(state->_saved_entry == _states->end(), state); 00630 00631 // Save the state in a local PointerTo so that it will be freed at 00632 // the end of this function if no one else uses it. 00633 CPT(RenderEffects) pt_state = state; 00634 00635 pair<States::iterator, bool> result = _states->insert(state); 00636 if (result.second) { 00637 // The state was inserted; save the iterator and return the 00638 // input state. 00639 state->_saved_entry = result.first; 00640 nassertr(_states->find(state) == state->_saved_entry, pt_state); 00641 return pt_state; 00642 } 00643 00644 // The state was not inserted; there must be an equivalent one 00645 // already in the set. Return that one. 00646 return *(result.first); 00647 } 00648 00649 //////////////////////////////////////////////////////////////////// 00650 // Function: RenderEffects::release_new 00651 // Access: Private 00652 // Description: This inverse of return_new, this releases this object 00653 // from the global RenderEffects table. 00654 // 00655 // You must already be holding _states_lock before you 00656 // call this method. 00657 //////////////////////////////////////////////////////////////////// 00658 void RenderEffects:: 00659 release_new() { 00660 nassertv(_states_lock->debug_is_locked()); 00661 00662 if (_saved_entry != _states->end()) { 00663 nassertv(_states->find(this) == _saved_entry); 00664 _states->erase(_saved_entry); 00665 _saved_entry = _states->end(); 00666 } 00667 } 00668 00669 //////////////////////////////////////////////////////////////////// 00670 // Function: RenderEffects::determine_decal 00671 // Access: Private 00672 // Description: This is the private implementation of has_decal(). 00673 //////////////////////////////////////////////////////////////////// 00674 void RenderEffects:: 00675 determine_decal() { 00676 LightMutexHolder holder(_lock); 00677 if ((_flags & F_checked_decal) != 0) { 00678 // Someone else checked it first. 00679 return; 00680 } 00681 00682 const RenderEffect *effect = get_effect(DecalEffect::get_class_type()); 00683 if (effect != (const RenderEffect *)NULL) { 00684 _flags |= F_has_decal; 00685 } 00686 _flags |= F_checked_decal; 00687 } 00688 00689 //////////////////////////////////////////////////////////////////// 00690 // Function: RenderEffects::determine_show_bounds 00691 // Access: Private 00692 // Description: This is the private implementation of has_show_bounds(). 00693 //////////////////////////////////////////////////////////////////// 00694 void RenderEffects:: 00695 determine_show_bounds() { 00696 LightMutexHolder holder(_lock); 00697 if ((_flags & F_checked_show_bounds) != 0) { 00698 // Someone else checked it first. 00699 return; 00700 } 00701 00702 const RenderEffect *effect = get_effect(ShowBoundsEffect::get_class_type()); 00703 if (effect != (const RenderEffect *)NULL) { 00704 _flags |= F_has_show_bounds; 00705 const ShowBoundsEffect *sba = DCAST(ShowBoundsEffect, effect); 00706 if (sba->get_tight()) { 00707 _flags |= F_has_show_tight_bounds; 00708 } 00709 } 00710 _flags |= F_checked_show_bounds; 00711 } 00712 00713 //////////////////////////////////////////////////////////////////// 00714 // Function: RenderEffects::determine_cull_callback 00715 // Access: Private 00716 // Description: This is the private implementation of has_cull_callback(). 00717 //////////////////////////////////////////////////////////////////// 00718 void RenderEffects:: 00719 determine_cull_callback() { 00720 LightMutexHolder holder(_lock); 00721 if ((_flags & F_checked_cull_callback) != 0) { 00722 // Someone else checked it first. 00723 return; 00724 } 00725 00726 _flags |= F_checked_cull_callback; 00727 00728 Effects::const_iterator ei; 00729 for (ei = _effects.begin(); ei != _effects.end(); ++ei) { 00730 if ((*ei)._effect->has_cull_callback()) { 00731 _flags |= F_has_cull_callback; 00732 return; 00733 } 00734 } 00735 } 00736 00737 //////////////////////////////////////////////////////////////////// 00738 // Function: RenderEffects::determine_adjust_transform 00739 // Access: Private 00740 // Description: This is the private implementation of has_adjust_transform(). 00741 //////////////////////////////////////////////////////////////////// 00742 void RenderEffects:: 00743 determine_adjust_transform() { 00744 LightMutexHolder holder(_lock); 00745 if ((_flags & F_checked_adjust_transform) != 0) { 00746 // Someone else checked it first. 00747 return; 00748 } 00749 00750 _flags |= F_checked_adjust_transform; 00751 00752 Effects::const_iterator ei; 00753 for (ei = _effects.begin(); ei != _effects.end(); ++ei) { 00754 if ((*ei)._effect->has_adjust_transform()) { 00755 _flags |= F_has_adjust_transform; 00756 return; 00757 } 00758 } 00759 } 00760 00761 //////////////////////////////////////////////////////////////////// 00762 // Function: RenderEffects::register_with_read_factory 00763 // Access: Public, Static 00764 // Description: Tells the BamReader how to create objects of type 00765 // RenderEffects. 00766 //////////////////////////////////////////////////////////////////// 00767 void RenderEffects:: 00768 register_with_read_factory() { 00769 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); 00770 } 00771 00772 //////////////////////////////////////////////////////////////////// 00773 // Function: RenderEffects::write_datagram 00774 // Access: Public, Virtual 00775 // Description: Writes the contents of this object to the datagram 00776 // for shipping out to a Bam file. 00777 //////////////////////////////////////////////////////////////////// 00778 void RenderEffects:: 00779 write_datagram(BamWriter *manager, Datagram &dg) { 00780 TypedWritable::write_datagram(manager, dg); 00781 00782 int num_effects = _effects.size(); 00783 nassertv(num_effects == (int)(PN_uint16)num_effects); 00784 dg.add_uint16(num_effects); 00785 00786 Effects::const_iterator ai; 00787 for (ai = _effects.begin(); ai != _effects.end(); ++ai) { 00788 const Effect &effect = (*ai); 00789 00790 manager->write_pointer(dg, effect._effect); 00791 } 00792 } 00793 00794 //////////////////////////////////////////////////////////////////// 00795 // Function: RenderEffects::complete_pointers 00796 // Access: Public, Virtual 00797 // Description: Receives an array of pointers, one for each time 00798 // manager->read_pointer() was called in fillin(). 00799 // Returns the number of pointers processed. 00800 //////////////////////////////////////////////////////////////////// 00801 int RenderEffects:: 00802 complete_pointers(TypedWritable **p_list, BamReader *manager) { 00803 int pi = TypedWritable::complete_pointers(p_list, manager); 00804 00805 // Get the effect pointers. 00806 size_t i = 0; 00807 while (i < _effects.size()) { 00808 Effect &effect = _effects[i]; 00809 00810 effect._effect = DCAST(RenderEffect, p_list[pi++]); 00811 if (effect._effect == (RenderEffect *)NULL) { 00812 // Remove this bogus RenderEffect pointer (it must have been 00813 // from an unwritable class). 00814 _effects.erase(_effects.begin() + i); 00815 00816 } else { 00817 // Keep this good pointer, and increment. 00818 effect._type = effect._effect->get_type(); 00819 ++i; 00820 } 00821 } 00822 00823 // Now make sure the array is properly sorted. (It won't 00824 // necessarily preserve its correct sort after being read from bam, 00825 // because the sort is based on TypeHandle indices, which can change 00826 // from session to session.) 00827 _effects.sort(); 00828 00829 nassertr(_saved_entry == _states->end(), pi); 00830 return pi; 00831 } 00832 00833 //////////////////////////////////////////////////////////////////// 00834 // Function: RenderEffects::require_fully_complete 00835 // Access: Public, Virtual 00836 // Description: Some objects require all of their nested pointers to 00837 // have been completed before the objects themselves can 00838 // be completed. If this is the case, override this 00839 // method to return true, and be careful with circular 00840 // references (which would make the object unreadable 00841 // from a bam file). 00842 //////////////////////////////////////////////////////////////////// 00843 bool RenderEffects:: 00844 require_fully_complete() const { 00845 // Since we sort _states based on each RenderEffects' operator < 00846 // method, which in turn compares based on each nested RenderEffect 00847 // object's compare_to() method, some of which depend on the 00848 // RenderEffect's pointers having already been completed 00849 // (e.g. CharacterJointEffect), we therefore require each of out our 00850 // nested RenderEffect objects to have been completed before we can 00851 // be completed. 00852 return true; 00853 } 00854 00855 //////////////////////////////////////////////////////////////////// 00856 // Function: RenderEffects::change_this 00857 // Access: Public, Static 00858 // Description: Called immediately after complete_pointers(), this 00859 // gives the object a chance to adjust its own pointer 00860 // if desired. Most objects don't change pointers after 00861 // completion, but some need to. 00862 // 00863 // Once this function has been called, the old pointer 00864 // will no longer be accessed. 00865 //////////////////////////////////////////////////////////////////// 00866 TypedWritable *RenderEffects:: 00867 change_this(TypedWritable *old_ptr, BamReader *manager) { 00868 // First, uniquify the pointer. 00869 RenderEffects *state = DCAST(RenderEffects, old_ptr); 00870 CPT(RenderEffects) pointer = return_new(state); 00871 00872 // But now we have a problem, since we have to hold the reference 00873 // count and there's no way to return a TypedWritable while still 00874 // holding the reference count! We work around this by explicitly 00875 // upping the count, and also setting a finalize() callback to down 00876 // it later. 00877 if (pointer == state) { 00878 pointer->ref(); 00879 manager->register_finalize(state); 00880 } 00881 00882 // We have to cast the pointer back to non-const, because the bam 00883 // reader expects that. 00884 return (RenderEffects *)pointer.p(); 00885 } 00886 00887 //////////////////////////////////////////////////////////////////// 00888 // Function: RenderEffects::finalize 00889 // Access: Public, Virtual 00890 // Description: Called by the BamReader to perform any final actions 00891 // needed for setting up the object after all objects 00892 // have been read and all pointers have been completed. 00893 //////////////////////////////////////////////////////////////////// 00894 void RenderEffects:: 00895 finalize(BamReader *) { 00896 // Unref the pointer that we explicitly reffed in change_this(). 00897 unref(); 00898 00899 // We should never get back to zero after unreffing our own count, 00900 // because we expect to have been stored in a pointer somewhere. If 00901 // we do get to zero, it's a memory leak; the way to avoid this is 00902 // to call unref_delete() above instead of unref(), but this is 00903 // dangerous to do from within a virtual function. 00904 nassertv(get_ref_count() != 0); 00905 } 00906 00907 //////////////////////////////////////////////////////////////////// 00908 // Function: RenderEffects::make_from_bam 00909 // Access: Protected, Static 00910 // Description: This function is called by the BamReader's factory 00911 // when a new object of type RenderEffects is encountered 00912 // in the Bam file. It should create the RenderEffects 00913 // and extract its information from the file. 00914 //////////////////////////////////////////////////////////////////// 00915 TypedWritable *RenderEffects:: 00916 make_from_bam(const FactoryParams ¶ms) { 00917 RenderEffects *state = new RenderEffects; 00918 DatagramIterator scan; 00919 BamReader *manager; 00920 00921 parse_params(params, scan, manager); 00922 state->fillin(scan, manager); 00923 manager->register_change_this(change_this, state); 00924 00925 return state; 00926 } 00927 00928 //////////////////////////////////////////////////////////////////// 00929 // Function: RenderEffects::fillin 00930 // Access: Protected 00931 // Description: This internal function is called by make_from_bam to 00932 // read in all of the relevant data from the BamFile for 00933 // the new RenderEffects. 00934 //////////////////////////////////////////////////////////////////// 00935 void RenderEffects:: 00936 fillin(DatagramIterator &scan, BamReader *manager) { 00937 TypedWritable::fillin(scan, manager); 00938 00939 int num_effects = scan.get_uint16(); 00940 00941 // Push back a NULL pointer for each effect for now, until we get 00942 // the actual list of pointers later in complete_pointers(). 00943 _effects.reserve(num_effects); 00944 for (int i = 0; i < num_effects; i++) { 00945 manager->read_pointer(scan); 00946 _effects.push_back(Effect()); 00947 } 00948 00949 nassertv(_saved_entry == _states->end()); 00950 }