Panda3D
 All Classes Functions Variables Enumerations
particleSystem.cxx
00001 // Filename: particleSystem.cxx
00002 // Created by:  charles (14Jun00)
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 <stdlib.h>
00016 
00017 #include "luse.h"
00018 #include "lmat_ops.h"
00019 #include "clockObject.h"
00020 #include "physicsManager.h"
00021 #include "physicalNode.h"
00022 #include "nearly_zero.h"
00023 #include "transformState.h"
00024 #include "nodePath.h"
00025 
00026 #include "config_particlesystem.h"
00027 #include "particleSystem.h"
00028 #include "particleSystemManager.h"
00029 #include "pointParticleRenderer.h"
00030 #include "pointParticleFactory.h"
00031 #include "sphereSurfaceEmitter.h"
00032 #include "pStatTimer.h"
00033 
00034 TypeHandle ParticleSystem::_type_handle;
00035 
00036 PStatCollector ParticleSystem::_update_collector("App:Particles:Update");
00037 
00038 ////////////////////////////////////////////////////////////////////
00039 //    Function : ParticleSystem
00040 //      Access : Public
00041 // Description : Default Constructor.
00042 ////////////////////////////////////////////////////////////////////
00043 ParticleSystem::
00044 ParticleSystem(int pool_size) :
00045   Physical(pool_size, false)
00046 {
00047   _birth_rate = 0.5f;
00048   _cur_birth_rate = _birth_rate;
00049   _soft_birth_rate = HUGE_VAL;
00050   _tics_since_birth = 0.0;
00051   _litter_size = 1;
00052   _litter_spread = 0;
00053   _living_particles = 0;
00054   _active_system_flag = true;
00055   _local_velocity_flag = true;
00056   _spawn_on_death_flag = false;
00057   _system_grows_older_flag = false;
00058   _system_lifespan = 0.0f;
00059   _i_was_spawned_flag = false;
00060   _particle_pool_size = 0;
00061   _floor_z = -HUGE_VAL;
00062 
00063   // just in case someone tries to do something that requires the
00064   // use of an emitter, renderer, or factory before they've actually
00065   // assigned one.  This is ok, because assigning them (set_renderer(),
00066   // set_emitter(), etc...) forces them to set themselves up for the
00067   // system, keeping the pool sizes consistent.
00068 
00069   _render_node_path = NodePath();
00070   _render_parent = NodePath("ParticleSystem default render parent");
00071 
00072   set_emitter(new SphereSurfaceEmitter);
00073 
00074   set_renderer(new PointParticleRenderer);
00075 
00076   //set_factory(new PointParticleFactory);
00077   _factory = new PointParticleFactory;
00078   clear_physics_objects();
00079 
00080   set_pool_size(pool_size);
00081 }
00082 
00083 ////////////////////////////////////////////////////////////////////
00084 //    Function : ParticleSystem
00085 //      Access : Public
00086 // Description : Copy Constructor.
00087 ////////////////////////////////////////////////////////////////////
00088 ParticleSystem::
00089 ParticleSystem(const ParticleSystem& copy) :
00090   Physical(copy),
00091   _system_age(0.0f),
00092   _template_system_flag(false)
00093 {
00094   _birth_rate = copy._birth_rate;
00095   _cur_birth_rate = copy._cur_birth_rate;
00096   _litter_size = copy._litter_size;
00097   _litter_spread = copy._litter_spread;
00098   _active_system_flag = copy._active_system_flag;
00099   _local_velocity_flag = copy._local_velocity_flag;
00100   _spawn_on_death_flag = copy._spawn_on_death_flag;
00101   _i_was_spawned_flag = copy._i_was_spawned_flag;
00102   _system_grows_older_flag = copy._system_grows_older_flag;
00103   _emitter = copy._emitter;
00104   _renderer = copy._renderer->make_copy();
00105   _factory = copy._factory;
00106 
00107   _render_parent = copy._render_parent;
00108   _render_node_path = _renderer->get_render_node_path();
00109   _render_node_path.reparent_to(_render_parent);
00110 
00111   _tics_since_birth = 0.0;
00112   _system_lifespan = copy._system_lifespan;
00113   _living_particles = 0;
00114 
00115   set_pool_size(copy._particle_pool_size);
00116 }
00117 
00118 ////////////////////////////////////////////////////////////////////
00119 //    Function : ~ParticleSystem
00120 //      Access : Public
00121 // Description : You get the ankles and I'll get the wrists.
00122 ////////////////////////////////////////////////////////////////////
00123 ParticleSystem::
00124 ~ParticleSystem() {
00125   set_pool_size(0);
00126 
00127   if (!_template_system_flag) {
00128     _renderer.clear();
00129     _render_node_path.remove_node();
00130   }
00131 }
00132 
00133 ////////////////////////////////////////////////////////////////////
00134 //    Function : birth_particle
00135 //      Access : Private
00136 // Description : A new particle is born.  This doesn't allocate,
00137 //               resets an element from the particle pool.
00138 ////////////////////////////////////////////////////////////////////
00139 bool ParticleSystem::
00140 birth_particle() {
00141   int pool_index;
00142 
00143   // make sure there's room for a new particle
00144   if (_living_particles >= _particle_pool_size) {
00145     #ifdef PSDEBUG
00146     if (_living_particles > _particle_pool_size) {
00147       cout << "_living_particles > _particle_pool_size" << endl;
00148     }
00149     #endif
00150     return false;
00151   }
00152 
00153   #ifdef PSDEBUG
00154   if (0 == _free_particle_fifo.size()) {
00155     cout << "Error: _free_particle_fifo is empty, but _living_particles < _particle_pool_size" << endl;
00156     return false;
00157   }
00158   #endif
00159 
00160   pool_index = _free_particle_fifo.back();
00161   _free_particle_fifo.pop_back();
00162 
00163   // get a handle on our particle.
00164   BaseParticle *bp = (BaseParticle *) _physics_objects[pool_index].p();
00165 
00166   // start filling out the variables.
00167   _factory->populate_particle(bp);
00168 
00169   bp->set_alive(true);
00170   bp->set_active(true);
00171   bp->init();
00172 
00173   // get the location of the new particle.
00174   LPoint3 new_pos, world_pos;
00175   LVector3 new_vel;
00176 
00177   _emitter->generate(new_pos, new_vel);
00178 
00179   // go from birth space to render space
00180   NodePath physical_np = get_physical_node_path();
00181   NodePath render_np = _renderer->get_render_node_path();
00182 
00183   CPT(TransformState) transform = physical_np.get_transform(render_np);
00184   const LMatrix4 &birth_to_render_xform = transform->get_mat();
00185   world_pos = new_pos * birth_to_render_xform;
00186 
00187   //  cout << "New particle at " << world_pos << endl;
00188 
00189   // possibly transform the initial velocity as well.
00190   if (_local_velocity_flag == false)
00191     new_vel = new_vel * birth_to_render_xform;
00192 
00193   bp->reset_position(world_pos/* + (NORMALIZED_RAND() * new_vel)*/);
00194   bp->set_velocity(new_vel);
00195 
00196   ++_living_particles;
00197 
00198   // propogate information down to renderer
00199   _renderer->birth_particle(pool_index);
00200 
00201   return true;
00202 }
00203 
00204 ////////////////////////////////////////////////////////////////////
00205 //    Function : birth_litter
00206 //      Access : Private
00207 // Description : spawns a new batch of particles
00208 ////////////////////////////////////////////////////////////////////
00209 void ParticleSystem::
00210 birth_litter() {
00211   int litter_size, i;
00212 
00213   litter_size = _litter_size;
00214 
00215   if (_litter_spread != 0)
00216     litter_size += I_SPREAD(_litter_spread);
00217 
00218   for (i = 0; i < litter_size; ++i) {
00219     if (birth_particle() == false)
00220       return;
00221   }
00222 }
00223 
00224 ////////////////////////////////////////////////////////////////////
00225 //    Function : spawn_child_system
00226 //      Access : private
00227 // Description : Creates a new particle system based on local
00228 //               template info and adds it to the ps and physics
00229 //               managers
00230 ////////////////////////////////////////////////////////////////////
00231 void ParticleSystem::
00232 spawn_child_system(BaseParticle *bp) {
00233   // first, make sure that the system exists in the graph via a
00234   // physicalnode reference.
00235   PhysicalNode *this_pn = get_physical_node();
00236   if (!this_pn) {
00237     physics_cat.error() << "ParticleSystem::spawn_child_system: "
00238                         << "Spawning system is not in the scene graph,"
00239                         << " aborting." << endl;
00240     return;
00241   }
00242 
00243   if (this_pn->get_num_parents() == 0) {
00244     physics_cat.error() << "ParticleSystem::spawn_child_system: "
00245                         << "PhysicalNode this system is contained in "
00246                         << "has no parent, aborting." << endl;
00247     return;
00248   }
00249 
00250   NodePath physical_np = get_physical_node_path();
00251   NodePath parent_np = physical_np.get_parent();
00252 
00253   PandaNode *parent = parent_np.node();
00254 
00255   // handle the spawn templates
00256   int new_ps_index = rand() % _spawn_templates.size();
00257   ParticleSystem *ps_template = _spawn_templates[new_ps_index];
00258 
00259   // create a new particle system
00260   PT(ParticleSystem) new_ps = new ParticleSystem(*ps_template);
00261   new_ps->_i_was_spawned_flag = true;
00262 
00263   // first, set up the render node info.
00264   new_ps->_render_parent = _spawn_render_node_path;
00265   new_ps->_render_node_path = new_ps->_renderer->get_render_node_path();
00266   new_ps->_render_node_path.reparent_to(new_ps->_render_parent);
00267 
00268   // now set up the new system's PhysicalNode.
00269   PT(PhysicalNode) new_pn = new PhysicalNode("new_pn");
00270   new_pn->add_physical(new_ps);
00271 
00272   // the transform on the new child has to represent the transform
00273   // from the current system up to its parent, and then subsequently
00274   // down to the new child.
00275   parent->add_child(new_pn);
00276 
00277   CPT(TransformState) transform = physical_np.get_transform(parent_np);
00278   const LMatrix4 &old_system_to_parent_xform = transform->get_mat();
00279 
00280   LMatrix4 child_space_xform = old_system_to_parent_xform *
00281     bp->get_lcs();
00282 
00283   new_pn->set_transform(TransformState::make_mat(child_space_xform));
00284 
00285   // tack the new system onto the managers
00286   _manager->attach_particlesystem(new_ps);
00287   get_physics_manager()->attach_physical(new_ps);
00288 }
00289 
00290 ////////////////////////////////////////////////////////////////////
00291 //    Function : kill_particle
00292 //      Access : Private
00293 // Description : Kills a particle, returns its slot to the empty
00294 //               stack.
00295 ////////////////////////////////////////////////////////////////////
00296 void ParticleSystem::
00297 kill_particle(int pool_index) {
00298   // get a handle on our particle
00299   BaseParticle *bp = (BaseParticle *) _physics_objects[pool_index].p();
00300 
00301   // create a new system where this one died, maybe.
00302   if (_spawn_on_death_flag == true) {
00303     spawn_child_system(bp);
00304   }
00305 
00306   // tell everyone that it's dead
00307   bp->set_alive(false);
00308   bp->set_active(false);
00309   bp->die();
00310 
00311   _free_particle_fifo.push_back(pool_index);
00312 
00313   // tell renderer
00314   _renderer->kill_particle(pool_index);
00315 
00316   _living_particles--;
00317 }
00318 
00319 ////////////////////////////////////////////////////////////////////
00320 //    Function : resize_pool
00321 //      Access : Private
00322 // Description : Resizes the particle pool
00323 ////////////////////////////////////////////////////////////////////
00324 #ifdef PSDEBUG
00325 #define PARTICLE_SYSTEM_RESIZE_POOL_SENTRIES
00326 #endif
00327 void ParticleSystem::
00328 resize_pool(int size) {
00329   int i;
00330   int delta = size - _particle_pool_size;
00331   int po_delta = _particle_pool_size - _physics_objects.size();
00332 
00333   #ifdef PARTICLE_SYSTEM_RESIZE_POOL_SENTRIES
00334   cout << "resizing particle pool from " << _particle_pool_size
00335        << " to " << size << endl;
00336   #endif
00337 
00338   if (_factory.is_null()) {
00339     particlesystem_cat.error() << "ParticleSystem::resize_pool"
00340                                << " called with null _factory." << endl;
00341     return;
00342   }
00343 
00344   if (_renderer.is_null()) {
00345     particlesystem_cat.error() << "ParticleSystem::resize_pool"
00346                                << " called with null _renderer." << endl;
00347     return;
00348   }
00349 
00350   _particle_pool_size = size;
00351 
00352   // make sure the physics_objects array is OK
00353   if (po_delta) {
00354     if (po_delta > 0) {
00355       for (i = 0; i < po_delta; i++)
00356       {
00357         //        int free_index = _physics_objects.size();
00358 
00359         BaseParticle *new_particle = _factory->alloc_particle();
00360         if (new_particle) {
00361           _factory->populate_particle(new_particle);
00362 
00363           _physics_objects.push_back(new_particle);
00364         } else {
00365           #ifdef PSDEBUG
00366           cout << "Error allocating new particle" << endl;
00367           _particle_pool_size--;
00368           #endif
00369         }
00370       }
00371     } else {
00372       #ifdef PSDEBUG
00373       cout << "physics_object array is too large??" << endl;
00374       _particle_pool_size--;
00375       #endif
00376       po_delta = -po_delta;
00377       for (i = 0; i < po_delta; i++) {
00378         int delete_index = _physics_objects.size()-1;
00379         BaseParticle *bp = (BaseParticle *) _physics_objects[delete_index].p();
00380         if (bp->get_alive()) {
00381           kill_particle(delete_index);
00382           _free_particle_fifo.pop_back();
00383         } else {
00384           pdeque<int>::iterator i;
00385           i = find(_free_particle_fifo.begin(), _free_particle_fifo.end(), delete_index);
00386           if (i != _free_particle_fifo.end()) {
00387             _free_particle_fifo.erase(i);
00388           }
00389         }
00390         _physics_objects.pop_back();
00391       }
00392     }
00393   }
00394 
00395   // disregard no change
00396   if (delta == 0)
00397     return;
00398 
00399   // update the pool
00400   if (delta > 0) {
00401     // add elements
00402     for (i = 0; i < delta; i++)
00403     {
00404       int free_index = _physics_objects.size();
00405 
00406       BaseParticle *new_particle = _factory->alloc_particle();
00407       if (new_particle) {
00408         _factory->populate_particle(new_particle);
00409 
00410         _physics_objects.push_back(new_particle);
00411         _free_particle_fifo.push_back(free_index);
00412       } else {
00413         #ifdef PSDEBUG
00414         cout << "Error allocating new particle" << endl;
00415         _particle_pool_size--;
00416         #endif
00417       }
00418     }
00419   } else {
00420     // subtract elements
00421     delta = -delta;
00422     for (i = 0; i < delta; i++) {
00423       int delete_index = _physics_objects.size()-1;
00424       BaseParticle *bp = (BaseParticle *) _physics_objects[delete_index].p();
00425 
00426       if (bp->get_alive()) {
00427         #ifdef PSDEBUG
00428         cout << "WAS ALIVE" << endl;
00429         #endif
00430         kill_particle(delete_index);
00431         _free_particle_fifo.pop_back();
00432       } else {
00433         #ifdef PSDEBUG
00434         cout << "WAS NOT ALIVE" << endl;
00435         #endif
00436         pdeque<int>::iterator i;
00437         i = find(_free_particle_fifo.begin(), _free_particle_fifo.end(), delete_index);
00438         if (i != _free_particle_fifo.end()) {
00439           _free_particle_fifo.erase(i);
00440         }
00441         #ifdef PSDEBUG
00442         else {
00443           cout << "particle not found in free FIFO!!!!!!!!" << endl;
00444         }
00445         #endif
00446       }
00447 
00448       _physics_objects.pop_back();
00449     }
00450   }
00451 
00452   _renderer->resize_pool(_particle_pool_size);
00453 
00454   #ifdef PARTICLE_SYSTEM_RESIZE_POOL_SENTRIES
00455   cout << "particle pool resized" << endl;
00456   #endif
00457 }
00458 
00459 //////////////////////////////////////////////////////////////////////
00460 //    Function : update
00461 //      Access : Public
00462 // Description : Updates the particle system.  Call once per frame.
00463 //////////////////////////////////////////////////////////////////////
00464 #ifdef PSDEBUG
00465 //#define PARTICLE_SYSTEM_UPDATE_SENTRIES
00466 #endif
00467 void ParticleSystem::
00468 update(PN_stdfloat dt) {
00469   PStatTimer t1(_update_collector);
00470 
00471   int ttl_updates_left = _living_particles;
00472   int current_index = 0, index_counter = 0;
00473   BaseParticle *bp;
00474   PN_stdfloat age;
00475 
00476   #ifdef PSSANITYCHECK
00477   // check up on things
00478   if (sanity_check()) return;
00479   #endif
00480 
00481   #ifdef PARTICLE_SYSTEM_UPDATE_SENTRIES
00482   cout << "UPDATE: pool size: " << _particle_pool_size
00483        << ", live particles: " << _living_particles << endl;
00484   #endif
00485 
00486   // run through the particle array
00487   while (ttl_updates_left) {
00488     current_index = index_counter;
00489     index_counter++;
00490 
00491     #ifdef PSDEBUG
00492     if (current_index >= _particle_pool_size) {
00493       cout << "ERROR: _living_particles is out of sync (too large)" << endl;
00494       cout << "pool size: " << _particle_pool_size
00495            << ", live particles: " << _living_particles
00496            << ", updates left: " << ttl_updates_left << endl;
00497       break;
00498     }
00499     #endif
00500 
00501     // get the current particle.
00502     bp = (BaseParticle *) _physics_objects[current_index].p();
00503 
00504     #ifdef PSDEBUG
00505     if (!bp) {
00506       cout << "NULL ptr at index " << current_index << endl;
00507       continue;
00508     }
00509     #endif
00510 
00511     if (bp->get_alive() == false)
00512       continue;
00513 
00514     age = bp->get_age() + dt;
00515     bp->set_age(age);
00516 
00517     //cerr<<"bp->get_position().get_z() returning "<<bp->get_position().get_z()<<endl;
00518     if (age >= bp->get_lifespan()) {
00519       kill_particle(current_index);
00520     } else if (get_floor_z() != -HUGE_VAL
00521             && bp->get_position().get_z() <= get_floor_z()) {
00522       // ...the particle is going under the floor.
00523       // Maybe tell the particle to bounce: bp->bounce()?
00524       kill_particle(current_index);
00525     } else {
00526       bp->update();
00527     }
00528       
00529     // break out early if we're lucky
00530     ttl_updates_left--;
00531   }
00532 
00533 
00534   // generate new particles if necessary.
00535   _tics_since_birth += dt;
00536 
00537   while (_tics_since_birth >= _cur_birth_rate) {
00538     birth_litter();
00539     _tics_since_birth -= _cur_birth_rate;
00540   }
00541 
00542   #ifdef PARTICLE_SYSTEM_UPDATE_SENTRIES
00543   cout << "particle update complete" << endl;
00544   #endif
00545 
00546 }
00547 
00548 #ifdef PSSANITYCHECK
00549 //////////////////////////////////////////////////////////////////////
00550 //    Function : sanity_check
00551 //      Access : Private
00552 // Description : Checks consistency of live particle count, free
00553 //               particle list, etc. returns 0 if everything is normal
00554 //////////////////////////////////////////////////////////////////////
00555 #ifndef NDEBUG
00556 #define PSSCVERBOSE
00557 #endif
00558 
00559 class SC_valuenamepair : public ReferenceCount {
00560 public:
00561   int value;
00562   char *name;
00563   SC_valuenamepair(int v, char *s) : value(v), name(s) {}
00564 };
00565 
00566 // returns 0 if OK, # of errors if not OK
00567 static int check_free_live_total_particles(pvector< PT(SC_valuenamepair) > live_counts,
00568   pvector< PT(SC_valuenamepair) > dead_counts, pvector< PT(SC_valuenamepair) > total_counts,
00569   int print_all = 0) {
00570 
00571   int val = 0;
00572   int l, d, t;
00573 
00574   for(l = 0; l < live_counts.size(); l++) {
00575     for(d = 0; d < dead_counts.size(); d++) {
00576       for(t = 0; t < total_counts.size(); t++) {
00577         int live = live_counts[l]->value;
00578         int dead = dead_counts[d]->value;
00579         int total = total_counts[t]->value;
00580         if ((live + dead) != total) {
00581           #ifdef PSSCVERBOSE
00582           cout << "free/live/total count: "
00583                << live_counts[l]->name << " (" << live << ") + "
00584                << dead_counts[d]->name << " (" << dead << ") = "
00585                << live + dead << ", != "
00586                << total_counts[t]->name << " (" << total << ")"
00587                << endl;
00588           #endif
00589           val++;
00590         }
00591       }
00592     }
00593   }
00594 
00595   return val;
00596 }
00597 
00598 int ParticleSystem::
00599 sanity_check() {
00600   int result = 0;
00601   int i;
00602   BaseParticle *bp;
00603   int pool_size;
00604 
00605   ///////////////////////////////////////////////////////////////////
00606   // check pool size
00607   if (_particle_pool_size != _physics_objects.size()) {
00608     #ifdef PSSCVERBOSE
00609     cout << "_particle_pool_size (" << _particle_pool_size
00610          << ") != particle array size (" << _physics_objects.size() << ")" << endl;
00611     #endif
00612     result++;
00613   }
00614   pool_size = min(_particle_pool_size, _physics_objects.size());
00615   ///////////////////////////////////////////////////////////////////
00616 
00617   ///////////////////////////////////////////////////////////////////
00618   // find out how many particles are REALLY alive and dead
00619   int real_live_particle_count = 0;
00620   int real_dead_particle_count = 0;
00621 
00622   for (i = 0; i < _physics_objects.size(); i++) {
00623     bp = (BaseParticle *) _physics_objects[i].p();
00624     if (true == bp->get_alive()) {
00625       real_live_particle_count++;
00626     } else {
00627       real_dead_particle_count++;
00628     }
00629   }
00630 
00631   if (real_live_particle_count != _living_particles) {
00632     #ifdef PSSCVERBOSE
00633     cout << "manually counted live particle count (" << real_live_particle_count
00634          << ") != _living_particles (" << _living_particles << ")" << endl;
00635     #endif
00636     result++;
00637   }
00638 
00639   if (real_dead_particle_count != _free_particle_fifo.size()) {
00640     #ifdef PSSCVERBOSE
00641     cout << "manually counted dead particle count (" << real_dead_particle_count
00642          << ") != free particle fifo size (" << _free_particle_fifo.size() << ")" << endl;
00643     #endif
00644     result++;
00645   }
00646   ///////////////////////////////////////////////////////////////////
00647 
00648   ///////////////////////////////////////////////////////////////////
00649   // check the free particle pool
00650   for (i = 0; i < _free_particle_fifo.size(); i++) {
00651     int index = _free_particle_fifo[i];
00652 
00653     // check that we're in bounds
00654     if (index >= pool_size) {
00655       #ifdef PSSCVERBOSE
00656       cout << "index from free particle fifo (" << index
00657            << ") is too large; pool size is " << pool_size << endl;
00658       #endif
00659       result++;
00660       continue;
00661     }
00662 
00663     // check that the particle is indeed dead
00664     bp = (BaseParticle *) _physics_objects[index].p();
00665     if (true == bp->get_alive()) {
00666       #ifdef PSSCVERBOSE
00667       cout << "particle " << index << " in free fifo is not dead" << endl;
00668       #endif
00669       result++;
00670     }
00671   }
00672   ///////////////////////////////////////////////////////////////////
00673 
00674   ///////////////////////////////////////////////////////////////////
00675   // check the numbers of free particles, live particles, and total particles
00676   pvector< PT(SC_valuenamepair) > live_counts;
00677   pvector< PT(SC_valuenamepair) > dead_counts;
00678   pvector< PT(SC_valuenamepair) > total_counts;
00679 
00680   live_counts.push_back(new SC_valuenamepair(real_live_particle_count, "real_live_particle_count"));
00681 
00682   dead_counts.push_back(new SC_valuenamepair(real_dead_particle_count, "real_dead_particle_count"));
00683   dead_counts.push_back(new SC_valuenamepair(_free_particle_fifo.size(), "free particle fifo size"));
00684 
00685   total_counts.push_back(new SC_valuenamepair(_particle_pool_size, "_particle_pool_size"));
00686   total_counts.push_back(new SC_valuenamepair(_physics_objects.size(), "actual particle pool size"));
00687 
00688   result += check_free_live_total_particles(live_counts, dead_counts, total_counts);
00689   ///////////////////////////////////////////////////////////////////
00690 
00691   return result;
00692 }
00693 #endif
00694 
00695 ////////////////////////////////////////////////////////////////////
00696 //     Function : output
00697 //       Access : Public
00698 //  Description : Write a string representation of this instance to
00699 //                <out>.
00700 ////////////////////////////////////////////////////////////////////
00701 void ParticleSystem::
00702 output(ostream &out) const {
00703   #ifndef NDEBUG //[
00704   out<<"ParticleSystem";
00705   #endif //] NDEBUG
00706 }
00707 
00708 ////////////////////////////////////////////////////////////////////
00709 //     Function : write_free_particle_fifo
00710 //       Access : Public
00711 //  Description : Write a string representation of this instance to
00712 //                <out>.
00713 ////////////////////////////////////////////////////////////////////
00714 void ParticleSystem::
00715 write_free_particle_fifo(ostream &out, int indent) const {
00716   #ifndef NDEBUG //[
00717   out.width(indent);
00718   out<<""<<"_free_particle_fifo ("<<_free_particle_fifo.size()<<" forces)\n";
00719   for (pdeque< int >::const_iterator i=_free_particle_fifo.begin();
00720        i != _free_particle_fifo.end();
00721        ++i) {
00722     out.width(indent+2); out<<""; out<<(*i)<<"\n";
00723   }
00724   #endif //] NDEBUG
00725 }
00726 
00727 ////////////////////////////////////////////////////////////////////
00728 //     Function : write_spawn_templates
00729 //       Access : Public
00730 //  Description : Write a string representation of this instance to
00731 //                <out>.
00732 ////////////////////////////////////////////////////////////////////
00733 void ParticleSystem::
00734 write_spawn_templates(ostream &out, int indent) const {
00735   #ifndef NDEBUG //[
00736   out.width(indent);
00737   out<<""<<"_spawn_templates ("<<_spawn_templates.size()<<" templates)\n";
00738   for (pvector< PT(ParticleSystem) >::const_iterator i=_spawn_templates.begin();
00739        i != _spawn_templates.end();
00740        ++i) {
00741     (*i)->write(out, indent+2);
00742   }
00743   #endif //] NDEBUG
00744 }
00745 
00746 ////////////////////////////////////////////////////////////////////
00747 //     Function : write
00748 //       Access : Public
00749 //  Description : Write a string representation of this instance to
00750 //                <out>.
00751 ////////////////////////////////////////////////////////////////////
00752 void ParticleSystem::
00753 write(ostream &out, int indent) const {
00754   #ifndef NDEBUG //[
00755   out.width(indent); out<<""; out<<"ParticleSystem:\n";
00756   out.width(indent+2); out<<""; out<<"_particle_pool_size "<<_particle_pool_size<<"\n";
00757   out.width(indent+2); out<<""; out<<"_living_particles "<<_living_particles<<"\n";
00758   out.width(indent+2); out<<""; out<<"_tics_since_birth "<<_tics_since_birth<<"\n";
00759   out.width(indent+2); out<<""; out<<"_litter_size "<<_litter_size<<"\n";
00760   out.width(indent+2); out<<""; out<<"_litter_spread "<<_litter_spread<<"\n";
00761   out.width(indent+2); out<<""; out<<"_system_age "<<_system_age<<"\n";
00762   out.width(indent+2); out<<""; out<<"_system_lifespan "<<_system_lifespan<<"\n";
00763   out.width(indent+2); out<<""; out<<"_factory "<<_factory<<"\n";
00764   out.width(indent+2); out<<""; out<<"_emitter "<<_emitter<<"\n";
00765   out.width(indent+2); out<<""; out<<"_renderer "<<_renderer<<"\n";
00766   out.width(indent+2); out<<""; out<<"_manager "<<_manager<<"\n";
00767   out.width(indent+2); out<<""; out<<"_template_system_flag "<<_template_system_flag<<"\n";
00768   out.width(indent+2); out<<""; out<<"_render_parent "<<_render_parent<<"\n";
00769   out.width(indent+2); out<<""; out<<"_render_node "<<_render_node_path<<"\n";
00770   out.width(indent+2); out<<""; out<<"_active_system_flag "<<_active_system_flag<<"\n";
00771   out.width(indent+2); out<<""; out<<"_local_velocity_flag "<<_local_velocity_flag<<"\n";
00772   out.width(indent+2); out<<""; out<<"_system_grows_older_flag "<<_system_grows_older_flag<<"\n";
00773   out.width(indent+2); out<<""; out<<"_spawn_on_death_flag "<<_spawn_on_death_flag<<"\n";
00774   out.width(indent+2); out<<""; out<<"_spawn_render_node "<<_spawn_render_node_path<<"\n";
00775   out.width(indent+2); out<<""; out<<"_i_was_spawned_flag "<<_i_was_spawned_flag<<"\n";
00776   write_free_particle_fifo(out, indent+2);
00777   write_spawn_templates(out, indent+2);
00778   Physical::write(out, indent+2);
00779   #endif //] NDEBUG
00780 }
 All Classes Functions Variables Enumerations