Panda3D
|
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 }