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

panda/src/pgraph/renderEffects.cxx

Go to the documentation of this file.
00001 // Filename: renderEffects.cxx
00002 // Created by:  drose (14Mar02)
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 "renderEffects.h"
00020 #include "billboardEffect.h"
00021 #include "decalEffect.h"
00022 #include "compassEffect.h"
00023 #include "showBoundsEffect.h"
00024 #include "config_pgraph.h"
00025 #include "bamReader.h"
00026 #include "bamWriter.h"
00027 #include "datagramIterator.h"
00028 #include "indent.h"
00029 #include "compareTo.h"
00030 
00031 RenderEffects::States RenderEffects::_states;
00032 CPT(RenderEffects) RenderEffects::_empty_state;
00033 TypeHandle RenderEffects::_type_handle;
00034 
00035 ////////////////////////////////////////////////////////////////////
00036 //     Function: RenderEffects::Constructor
00037 //       Access: Protected
00038 //  Description: Actually, this could be a private constructor, since
00039 //               no one inherits from RenderEffects, but gcc gives us a
00040 //               spurious warning if all constructors are private.
00041 ////////////////////////////////////////////////////////////////////
00042 RenderEffects::
00043 RenderEffects() {
00044   _saved_entry = _states.end();
00045   _flags = 0;
00046 }
00047 
00048 ////////////////////////////////////////////////////////////////////
00049 //     Function: RenderEffects::Copy Constructor
00050 //       Access: Private
00051 //  Description: RenderEffectss are not meant to be copied.
00052 ////////////////////////////////////////////////////////////////////
00053 RenderEffects::
00054 RenderEffects(const RenderEffects &) {
00055   nassertv(false);
00056 }
00057 
00058 ////////////////////////////////////////////////////////////////////
00059 //     Function: RenderEffects::Copy Assignment Operator
00060 //       Access: Private
00061 //  Description: RenderEffectss are not meant to be copied.
00062 ////////////////////////////////////////////////////////////////////
00063 void RenderEffects::
00064 operator = (const RenderEffects &) {
00065   nassertv(false);
00066 }
00067 
00068 ////////////////////////////////////////////////////////////////////
00069 //     Function: RenderEffects::Destructor
00070 //       Access: Public, Virtual
00071 //  Description: The destructor is responsible for removing the
00072 //               RenderEffects from the global set if it is there.
00073 ////////////////////////////////////////////////////////////////////
00074 RenderEffects::
00075 ~RenderEffects() {
00076   // Remove the deleted RenderEffects object from the global pool.
00077   if (_saved_entry != _states.end()) {
00078     _states.erase(_saved_entry);
00079     _saved_entry = _states.end();
00080   }
00081 }
00082 
00083 ////////////////////////////////////////////////////////////////////
00084 //     Function: RenderEffects::operator <
00085 //       Access: Public
00086 //  Description: Provides an arbitrary ordering among all unique
00087 //               RenderEffectss, so we can store the essentially
00088 //               different ones in a big set and throw away the rest.
00089 //
00090 //               This method is not needed outside of the RenderEffects
00091 //               class because all equivalent RenderEffects objects are
00092 //               guaranteed to share the same pointer; thus, a pointer
00093 //               comparison is always sufficient.
00094 ////////////////////////////////////////////////////////////////////
00095 bool RenderEffects::
00096 operator < (const RenderEffects &other) const {
00097   // We must compare all the properties of the effects, not just
00098   // the type; thus, we compare them one at a time using compare_to().
00099   return lexicographical_compare(_effects.begin(), _effects.end(),
00100                                  other._effects.begin(), other._effects.end(),
00101                                  CompareTo<Effect>());
00102 }
00103 
00104 ////////////////////////////////////////////////////////////////////
00105 //     Function: RenderEffects::safe_to_transform
00106 //       Access: Public
00107 //  Description: Returns true if all of the effects in this set can
00108 //               safely be transformed, and therefore the complete set
00109 //               can be transformed, by calling xform().
00110 ////////////////////////////////////////////////////////////////////
00111 bool RenderEffects::
00112 safe_to_transform() const {
00113   Effects::const_iterator ai;
00114   for (ai = _effects.begin(); ai != _effects.end(); ++ai) {
00115     const Effect &effect = (*ai);
00116     if (!effect._effect->safe_to_transform()) {
00117       return false;
00118     }
00119   }
00120 
00121   return true;
00122 }
00123 
00124 ////////////////////////////////////////////////////////////////////
00125 //     Function: RenderEffects::safe_to_combine
00126 //       Access: Public
00127 //  Description: Returns true if all of the effects in this set can
00128 //               safely be shared with a sibling node that has the
00129 //               exact same set of effects, or false if this would be
00130 //               bad for any of the effects.
00131 ////////////////////////////////////////////////////////////////////
00132 bool RenderEffects::
00133 safe_to_combine() const {
00134   Effects::const_iterator ai;
00135   for (ai = _effects.begin(); ai != _effects.end(); ++ai) {
00136     const Effect &effect = (*ai);
00137     if (!effect._effect->safe_to_combine()) {
00138       return false;
00139     }
00140   }
00141 
00142   return true;
00143 }
00144 
00145 ////////////////////////////////////////////////////////////////////
00146 //     Function: RenderEffects::xform
00147 //       Access: Public, Virtual
00148 //  Description: Returns a new RenderEffects transformed by the
00149 //               indicated matrix.
00150 ////////////////////////////////////////////////////////////////////
00151 CPT(RenderEffects) RenderEffects::
00152 xform(const LMatrix4f &mat) const {
00153   if (is_empty()) {
00154     return this;
00155   }
00156 
00157   RenderEffects *new_state = new RenderEffects;
00158   back_insert_iterator<Effects> result = 
00159     back_inserter(new_state->_effects);
00160 
00161   Effects::const_iterator ai;
00162   for (ai = _effects.begin(); ai != _effects.end(); ++ai) {
00163     const Effect &effect = (*ai);
00164     Effect new_effect(effect);
00165     new_effect._effect = effect._effect->xform(mat);
00166     *result = new_effect;
00167     ++result;
00168   }
00169 
00170   return return_new(new_state);
00171 }
00172 
00173 
00174 ////////////////////////////////////////////////////////////////////
00175 //     Function: RenderEffects::find_effect
00176 //       Access: Published
00177 //  Description: Searches for an effect with the indicated type in
00178 //               the state, and returns its index if it is found, or
00179 //               -1 if it is not.
00180 ////////////////////////////////////////////////////////////////////
00181 int RenderEffects::
00182 find_effect(TypeHandle type) const {
00183   Effects::const_iterator ai = _effects.find(Effect(type));
00184   if (ai == _effects.end()) {
00185     return -1;
00186   }
00187   return ai - _effects.begin();
00188 }
00189 
00190 ////////////////////////////////////////////////////////////////////
00191 //     Function: RenderEffects::make_empty
00192 //       Access: Published, Static
00193 //  Description: Returns a RenderEffects with no effects set.
00194 ////////////////////////////////////////////////////////////////////
00195 CPT(RenderEffects) RenderEffects::
00196 make_empty() {
00197   // The empty state is asked for so often, we make it a special case
00198   // and store a pointer forever once we find it the first time.
00199   if (_empty_state == (RenderEffects *)NULL) {
00200     RenderEffects *state = new RenderEffects;
00201     _empty_state = return_new(state);
00202   }
00203 
00204   return _empty_state;
00205 }
00206 
00207 ////////////////////////////////////////////////////////////////////
00208 //     Function: RenderEffects::make
00209 //       Access: Published, Static
00210 //  Description: Returns a RenderEffects with one effect set.
00211 ////////////////////////////////////////////////////////////////////
00212 CPT(RenderEffects) RenderEffects::
00213 make(const RenderEffect *effect) {
00214   RenderEffects *state = new RenderEffects;
00215   state->_effects.reserve(1);
00216   state->_effects.insert(Effect(effect));
00217   return return_new(state);
00218 }
00219 
00220 ////////////////////////////////////////////////////////////////////
00221 //     Function: RenderEffects::make
00222 //       Access: Published, Static
00223 //  Description: Returns a RenderEffects with two effects set.
00224 ////////////////////////////////////////////////////////////////////
00225 CPT(RenderEffects) RenderEffects::
00226 make(const RenderEffect *effect1,
00227      const RenderEffect *effect2) {
00228   RenderEffects *state = new RenderEffects;
00229   state->_effects.reserve(2);
00230   state->_effects.push_back(Effect(effect1));
00231   state->_effects.push_back(Effect(effect2));
00232   state->_effects.sort();
00233   return return_new(state);
00234 }
00235 
00236 ////////////////////////////////////////////////////////////////////
00237 //     Function: RenderEffects::make
00238 //       Access: Published, Static
00239 //  Description: Returns a RenderEffects with three effects set.
00240 ////////////////////////////////////////////////////////////////////
00241 CPT(RenderEffects) RenderEffects::
00242 make(const RenderEffect *effect1,
00243      const RenderEffect *effect2,
00244      const RenderEffect *effect3) {
00245   RenderEffects *state = new RenderEffects;
00246   state->_effects.reserve(2);
00247   state->_effects.push_back(Effect(effect1));
00248   state->_effects.push_back(Effect(effect2));
00249   state->_effects.push_back(Effect(effect3));
00250   state->_effects.sort();
00251   return return_new(state);
00252 }
00253 
00254 ////////////////////////////////////////////////////////////////////
00255 //     Function: RenderEffects::make
00256 //       Access: Published, Static
00257 //  Description: Returns a RenderEffects with four effects set.
00258 ////////////////////////////////////////////////////////////////////
00259 CPT(RenderEffects) RenderEffects::
00260 make(const RenderEffect *effect1,
00261      const RenderEffect *effect2,
00262      const RenderEffect *effect3,
00263      const RenderEffect *effect4) {
00264   RenderEffects *state = new RenderEffects;
00265   state->_effects.reserve(2);
00266   state->_effects.push_back(Effect(effect1));
00267   state->_effects.push_back(Effect(effect2));
00268   state->_effects.push_back(Effect(effect3));
00269   state->_effects.push_back(Effect(effect4));
00270   state->_effects.sort();
00271   return return_new(state);
00272 }
00273 
00274 ////////////////////////////////////////////////////////////////////
00275 //     Function: RenderEffects::add_effect
00276 //       Access: Published
00277 //  Description: Returns a new RenderEffects object that represents the
00278 //               same as the source state, with the new RenderEffect
00279 //               added.  If there is already a RenderEffect with the
00280 //               same type, it is replaced.
00281 ////////////////////////////////////////////////////////////////////
00282 CPT(RenderEffects) RenderEffects::
00283 add_effect(const RenderEffect *effect) const {
00284   RenderEffects *new_state = new RenderEffects;
00285   back_insert_iterator<Effects> result = 
00286     back_inserter(new_state->_effects);
00287 
00288   Effect new_effect(effect);
00289   Effects::const_iterator ai = _effects.begin();
00290 
00291   while (ai != _effects.end() && (*ai) < new_effect) {
00292     *result = *ai;
00293     ++ai;
00294     ++result;
00295   }
00296   *result = new_effect;
00297   ++result;
00298 
00299   if (ai != _effects.end() && !(new_effect < (*ai))) {
00300     // At this point we know:
00301     // !((*ai) < new_effect) && !(new_effect < (*ai))
00302     // which means (*ai) == new_effect--so we should leave it out,
00303     // to avoid duplicating effects in the set.
00304     ++ai;
00305   }
00306 
00307   while (ai != _effects.end()) {
00308     *result = *ai;
00309     ++ai;
00310     ++result;
00311   }
00312 
00313   return return_new(new_state);
00314 }
00315 
00316 ////////////////////////////////////////////////////////////////////
00317 //     Function: RenderEffects::remove_effect
00318 //       Access: Published
00319 //  Description: Returns a new RenderEffects object that represents the
00320 //               same as the source state, with the indicated
00321 //               RenderEffect removed.
00322 ////////////////////////////////////////////////////////////////////
00323 CPT(RenderEffects) RenderEffects::
00324 remove_effect(TypeHandle type) const {
00325   RenderEffects *new_state = new RenderEffects;
00326   back_insert_iterator<Effects> result = 
00327     back_inserter(new_state->_effects);
00328 
00329   Effects::const_iterator ai = _effects.begin();
00330 
00331   while (ai != _effects.end()) {
00332     if ((*ai)._type != type) {
00333       *result = *ai;
00334       ++result;
00335     }
00336     ++ai;
00337   }
00338 
00339   return return_new(new_state);
00340 }
00341 
00342 ////////////////////////////////////////////////////////////////////
00343 //     Function: RenderEffects::get_effect
00344 //       Access: Published, Virtual
00345 //  Description: Looks for a RenderEffect of the indicated type in the
00346 //               state, and returns it if it is found, or NULL if it
00347 //               is not.
00348 ////////////////////////////////////////////////////////////////////
00349 const RenderEffect *RenderEffects::
00350 get_effect(TypeHandle type) const {
00351   Effects::const_iterator ai;
00352   ai = _effects.find(Effect(type));
00353   if (ai != _effects.end()) {
00354     return (*ai)._effect;
00355   }
00356   return NULL;
00357 }
00358 
00359 ////////////////////////////////////////////////////////////////////
00360 //     Function: RenderEffects::output
00361 //       Access: Published, Virtual
00362 //  Description: 
00363 ////////////////////////////////////////////////////////////////////
00364 void RenderEffects::
00365 output(ostream &out) const {
00366   out << "E:";
00367   if (_effects.empty()) {
00368     out << "(empty)";
00369 
00370   } else {
00371     Effects::const_iterator ai = _effects.begin();
00372     out << "(" << (*ai)._type;
00373     ++ai;
00374     while (ai != _effects.end()) {
00375       out << " " << (*ai)._type;
00376       ++ai;
00377     }
00378     out << ")";
00379   }
00380 }
00381 
00382 ////////////////////////////////////////////////////////////////////
00383 //     Function: RenderEffects::write
00384 //       Access: Published, Virtual
00385 //  Description: 
00386 ////////////////////////////////////////////////////////////////////
00387 void RenderEffects::
00388 write(ostream &out, int indent_level) const {
00389   indent(out, indent_level) << _effects.size() << " effects:\n";
00390   Effects::const_iterator ai;
00391   for (ai = _effects.begin(); ai != _effects.end(); ++ai) {
00392     const Effect &effect = (*ai);
00393     effect._effect->write(out, indent_level + 2);
00394   }
00395 }
00396 
00397 ////////////////////////////////////////////////////////////////////
00398 //     Function: RenderEffects::return_new
00399 //       Access: Private, Static
00400 //  Description: This function is used to share a common RenderEffects
00401 //               pointer for all equivalent RenderEffects objects.
00402 //
00403 //               See the similar logic in RenderEffect.  The idea is
00404 //               to create a new RenderEffects object and pass it
00405 //               through this function, which will share the pointer
00406 //               with a previously-created RenderEffects object if it is
00407 //               equivalent.
00408 ////////////////////////////////////////////////////////////////////
00409 CPT(RenderEffects) RenderEffects::
00410 return_new(RenderEffects *state) {
00411   nassertr(state != (RenderEffects *)NULL, state);
00412 
00413   // This should be a newly allocated pointer, not one that was used
00414   // for anything else.
00415   nassertr(state->_saved_entry == _states.end(), state);
00416 
00417   // Save the state in a local PointerTo so that it will be freed at
00418   // the end of this function if no one else uses it.
00419   CPT(RenderEffects) pt_state = state;
00420 
00421   pair<States::iterator, bool> result = _states.insert(state);
00422   if (result.second) {
00423     // The state was inserted; save the iterator and return the
00424     // input state.
00425     state->_saved_entry = result.first;
00426     return pt_state;
00427   }
00428 
00429   // The state was not inserted; there must be an equivalent one
00430   // already in the set.  Return that one.
00431   return *(result.first);
00432 }
00433 
00434 ////////////////////////////////////////////////////////////////////
00435 //     Function: RenderEffects::determine_billboard
00436 //       Access: Private
00437 //  Description: This is the private implementation of
00438 //               get_billboard().
00439 ////////////////////////////////////////////////////////////////////
00440 void RenderEffects::
00441 determine_billboard() {
00442   const RenderEffect *effect = get_effect(BillboardEffect::get_class_type());
00443   _billboard = (const BillboardEffect *)NULL;
00444   if (effect != (const RenderEffect *)NULL) {
00445     _billboard = DCAST(BillboardEffect, effect);
00446   }
00447   _flags |= F_checked_billboard;
00448 }
00449 
00450 ////////////////////////////////////////////////////////////////////
00451 //     Function: RenderEffects::determine_decal
00452 //       Access: Private
00453 //  Description: This is the private implementation of has_decal().
00454 ////////////////////////////////////////////////////////////////////
00455 void RenderEffects::
00456 determine_decal() {
00457   const RenderEffect *effect = get_effect(DecalEffect::get_class_type());
00458   if (effect != (const RenderEffect *)NULL) {
00459     _flags |= F_has_decal;
00460   }
00461   _flags |= F_checked_decal;
00462 }
00463 
00464 ////////////////////////////////////////////////////////////////////
00465 //     Function: RenderEffects::determine_compass
00466 //       Access: Private
00467 //  Description: This is the private implementation of has_compass().
00468 ////////////////////////////////////////////////////////////////////
00469 void RenderEffects::
00470 determine_compass() {
00471   const RenderEffect *effect = get_effect(CompassEffect::get_class_type());
00472   _compass = (const CompassEffect *)NULL;
00473   if (effect != (const RenderEffect *)NULL) {
00474     _compass = DCAST(CompassEffect, effect);
00475   }
00476   _flags |= F_checked_compass;
00477 }
00478 
00479 ////////////////////////////////////////////////////////////////////
00480 //     Function: RenderEffects::determine_show_bounds
00481 //       Access: Private
00482 //  Description: This is the private implementation of has_show_bounds().
00483 ////////////////////////////////////////////////////////////////////
00484 void RenderEffects::
00485 determine_show_bounds() {
00486   const RenderEffect *effect = get_effect(ShowBoundsEffect::get_class_type());
00487   if (effect != (const RenderEffect *)NULL) {
00488     _flags |= F_has_show_bounds;
00489   }
00490   _flags |= F_checked_show_bounds;
00491 }
00492 
00493 ////////////////////////////////////////////////////////////////////
00494 //     Function: RenderEffects::register_with_read_factory
00495 //       Access: Public, Static
00496 //  Description: Tells the BamReader how to create objects of type
00497 //               RenderEffects.
00498 ////////////////////////////////////////////////////////////////////
00499 void RenderEffects::
00500 register_with_read_factory() {
00501   BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
00502 }
00503 
00504 ////////////////////////////////////////////////////////////////////
00505 //     Function: RenderEffects::write_datagram
00506 //       Access: Public, Virtual
00507 //  Description: Writes the contents of this object to the datagram
00508 //               for shipping out to a Bam file.
00509 ////////////////////////////////////////////////////////////////////
00510 void RenderEffects::
00511 write_datagram(BamWriter *manager, Datagram &dg) {
00512   TypedWritable::write_datagram(manager, dg);
00513 
00514   int num_effects = _effects.size();
00515   nassertv(num_effects == (int)(PN_uint16)num_effects);
00516   dg.add_uint16(num_effects);
00517 
00518   Effects::const_iterator ai;
00519   for (ai = _effects.begin(); ai != _effects.end(); ++ai) {
00520     const Effect &effect = (*ai);
00521 
00522     manager->write_pointer(dg, effect._effect);
00523   }
00524 }
00525 
00526 ////////////////////////////////////////////////////////////////////
00527 //     Function: RenderEffects::complete_pointers
00528 //       Access: Public, Virtual
00529 //  Description: Receives an array of pointers, one for each time
00530 //               manager->read_pointer() was called in fillin().
00531 //               Returns the number of pointers processed.
00532 ////////////////////////////////////////////////////////////////////
00533 int RenderEffects::
00534 complete_pointers(TypedWritable **p_list, BamReader *manager) {
00535   int pi = TypedWritable::complete_pointers(p_list, manager);
00536 
00537   // Get the effect pointers.
00538   Effects::iterator ai;
00539   for (ai = _effects.begin(); ai != _effects.end(); ++ai) {
00540     Effect &effect = (*ai);
00541 
00542     effect._effect = DCAST(RenderEffect, p_list[pi++]);
00543     nassertr(effect._effect != (RenderEffect *)NULL, pi);
00544     effect._type = effect._effect->get_type();
00545   }
00546 
00547   // Now make sure the array is properly sorted.  (It won't
00548   // necessarily preserve its correct sort after being read from bam,
00549   // because the sort is based on TypeHandle indices, which can change
00550   // from session to session.)
00551   _effects.sort();
00552 
00553   return pi;
00554 }
00555 
00556 ////////////////////////////////////////////////////////////////////
00557 //     Function: RenderEffects::change_this
00558 //       Access: Public, Static
00559 //  Description: Called immediately after complete_pointers(), this
00560 //               gives the object a chance to adjust its own pointer
00561 //               if desired.  Most objects don't change pointers after
00562 //               completion, but some need to.
00563 //
00564 //               Once this function has been called, the old pointer
00565 //               will no longer be accessed.
00566 ////////////////////////////////////////////////////////////////////
00567 TypedWritable *RenderEffects::
00568 change_this(TypedWritable *old_ptr, BamReader *manager) {
00569   // First, uniquify the pointer.
00570   RenderEffects *state = DCAST(RenderEffects, old_ptr);
00571   CPT(RenderEffects) pointer = return_new(state);
00572 
00573   // But now we have a problem, since we have to hold the reference
00574   // count and there's no way to return a TypedWritable while still
00575   // holding the reference count!  We work around this by explicitly
00576   // upping the count, and also setting a finalize() callback to down
00577   // it later.
00578   if (pointer == state) {
00579     pointer->ref();
00580     manager->register_finalize(state);
00581   }
00582   
00583   // We have to cast the pointer back to non-const, because the bam
00584   // reader expects that.
00585   return (RenderEffects *)pointer.p();
00586 }
00587 
00588 ////////////////////////////////////////////////////////////////////
00589 //     Function: RenderEffects::finalize
00590 //       Access: Public, Virtual
00591 //  Description: Called by the BamReader to perform any final actions
00592 //               needed for setting up the object after all objects
00593 //               have been read and all pointers have been completed.
00594 ////////////////////////////////////////////////////////////////////
00595 void RenderEffects::
00596 finalize() {
00597   // Unref the pointer that we explicitly reffed in make_from_bam().
00598   unref();
00599 
00600   // We should never get back to zero after unreffing our own count,
00601   // because we expect to have been stored in a pointer somewhere.  If
00602   // we do get to zero, it's a memory leak; the way to avoid this is
00603   // to call unref_delete() above instead of unref(), but this is
00604   // dangerous to do from within a virtual function.
00605   nassertv(get_ref_count() != 0);
00606 }
00607 
00608 ////////////////////////////////////////////////////////////////////
00609 //     Function: RenderEffects::make_from_bam
00610 //       Access: Protected, Static
00611 //  Description: This function is called by the BamReader's factory
00612 //               when a new object of type RenderEffects is encountered
00613 //               in the Bam file.  It should create the RenderEffects
00614 //               and extract its information from the file.
00615 ////////////////////////////////////////////////////////////////////
00616 TypedWritable *RenderEffects::
00617 make_from_bam(const FactoryParams &params) {
00618   RenderEffects *state = new RenderEffects;
00619   DatagramIterator scan;
00620   BamReader *manager;
00621 
00622   parse_params(params, scan, manager);
00623   state->fillin(scan, manager);
00624   manager->register_change_this(change_this, state);
00625 
00626   return state;
00627 }
00628 
00629 ////////////////////////////////////////////////////////////////////
00630 //     Function: RenderEffects::fillin
00631 //       Access: Protected
00632 //  Description: This internal function is called by make_from_bam to
00633 //               read in all of the relevant data from the BamFile for
00634 //               the new RenderEffects.
00635 ////////////////////////////////////////////////////////////////////
00636 void RenderEffects::
00637 fillin(DatagramIterator &scan, BamReader *manager) {
00638   TypedWritable::fillin(scan, manager);
00639 
00640   int num_effects = scan.get_uint16();
00641 
00642   // Push back a NULL pointer for each effect for now, until we get
00643   // the actual list of pointers later in complete_pointers().
00644   _effects.reserve(num_effects);
00645   for (int i = 0; i < num_effects; i++) {
00646     manager->read_pointer(scan);
00647     _effects.push_back(Effect());
00648   }
00649 }

Generated on Fri May 2 00:42:15 2003 for Panda by doxygen1.3