00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
00040
00041
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
00064
00065
00066
00067
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
00077 _factory = new PointParticleFactory;
00078 clear_physics_objects();
00079
00080 set_pool_size(pool_size);
00081 }
00082
00083
00084
00085
00086
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
00120
00121
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
00135
00136
00137
00138
00139 bool ParticleSystem::
00140 birth_particle() {
00141 int pool_index;
00142
00143
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
00164 BaseParticle *bp = (BaseParticle *) _physics_objects[pool_index].p();
00165
00166
00167 _factory->populate_particle(bp);
00168
00169 bp->set_alive(true);
00170 bp->set_active(true);
00171 bp->init();
00172
00173
00174 LPoint3 new_pos, world_pos;
00175 LVector3 new_vel;
00176
00177 _emitter->generate(new_pos, new_vel);
00178
00179
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
00188
00189
00190 if (_local_velocity_flag == false)
00191 new_vel = new_vel * birth_to_render_xform;
00192
00193 bp->reset_position(world_pos);
00194 bp->set_velocity(new_vel);
00195
00196 ++_living_particles;
00197
00198
00199 _renderer->birth_particle(pool_index);
00200
00201 return true;
00202 }
00203
00204
00205
00206
00207
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
00226
00227
00228
00229
00230
00231 void ParticleSystem::
00232 spawn_child_system(BaseParticle *bp) {
00233
00234
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
00256 int new_ps_index = rand() % _spawn_templates.size();
00257 ParticleSystem *ps_template = _spawn_templates[new_ps_index];
00258
00259
00260 PT(ParticleSystem) new_ps = new ParticleSystem(*ps_template);
00261 new_ps->_i_was_spawned_flag = true;
00262
00263
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
00269 PT(PhysicalNode) new_pn = new PhysicalNode("new_pn");
00270 new_pn->add_physical(new_ps);
00271
00272
00273
00274
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
00286 _manager->attach_particlesystem(new_ps);
00287 get_physics_manager()->attach_physical(new_ps);
00288 }
00289
00290
00291
00292
00293
00294
00295
00296 void ParticleSystem::
00297 kill_particle(int pool_index) {
00298
00299 BaseParticle *bp = (BaseParticle *) _physics_objects[pool_index].p();
00300
00301
00302 if (_spawn_on_death_flag == true) {
00303 spawn_child_system(bp);
00304 }
00305
00306
00307 bp->set_alive(false);
00308 bp->set_active(false);
00309 bp->die();
00310
00311 _free_particle_fifo.push_back(pool_index);
00312
00313
00314 _renderer->kill_particle(pool_index);
00315
00316 _living_particles--;
00317 }
00318
00319
00320
00321
00322
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
00353 if (po_delta) {
00354 if (po_delta > 0) {
00355 for (i = 0; i < po_delta; i++)
00356 {
00357
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
00396 if (delta == 0)
00397 return;
00398
00399
00400 if (delta > 0) {
00401
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
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
00461
00462
00463
00464 #ifdef PSDEBUG
00465
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
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
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
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
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
00523
00524 kill_particle(current_index);
00525 } else {
00526 bp->update();
00527 }
00528
00529
00530 ttl_updates_left--;
00531 }
00532
00533
00534
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
00551
00552
00553
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
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
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
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
00650 for (i = 0; i < _free_particle_fifo.size(); i++) {
00651 int index = _free_particle_fifo[i];
00652
00653
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
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
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
00697
00698
00699
00700
00701 void ParticleSystem::
00702 output(ostream &out) const {
00703 #ifndef NDEBUG //[
00704 out<<"ParticleSystem";
00705 #endif //] NDEBUG
00706 }
00707
00708
00709
00710
00711
00712
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
00729
00730
00731
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
00748
00749
00750
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 }