00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <stdlib.h>
00020
00021 #include "luse.h"
00022 #include "lmat_ops.h"
00023 #include "clockObject.h"
00024 #include "physicsManager.h"
00025 #include "physicalNode.h"
00026 #include "nearly_zero.h"
00027 #include "transformState.h"
00028 #include "nodePath.h"
00029
00030 #include "config_particlesystem.h"
00031 #include "particleSystem.h"
00032 #include "particleSystemManager.h"
00033 #include "pointParticleRenderer.h"
00034 #include "pointParticleFactory.h"
00035 #include "sphereSurfaceEmitter.h"
00036
00037
00038
00039
00040
00041
00042 ParticleSystem::
00043 ParticleSystem(int pool_size) :
00044 Physical(pool_size, false)
00045 {
00046 _birth_rate = 0.5f;
00047 _tics_since_birth = _birth_rate;
00048 _litter_size = 1;
00049 _litter_spread = 0;
00050 _living_particles = 0;
00051 _active_system_flag = true;
00052 _local_velocity_flag = true;
00053 _spawn_on_death_flag = false;
00054 _system_grows_older_flag = false;
00055 _system_lifespan = 0.0f;
00056 _i_was_spawned_flag = false;
00057 _particle_pool_size = 0;
00058
00059
00060
00061
00062
00063
00064
00065 _render_node.clear();
00066 _render_parent = new PandaNode("ParticleSystem default render parent");
00067
00068 set_emitter(new SphereSurfaceEmitter);
00069
00070 set_renderer(new PointParticleRenderer);
00071
00072
00073 _factory = new PointParticleFactory;
00074 clear_physics_objects();
00075
00076 set_pool_size(pool_size);
00077 }
00078
00079
00080
00081
00082
00083
00084 ParticleSystem::
00085 ParticleSystem(const ParticleSystem& copy) :
00086 Physical(copy),
00087 _system_age(0.0f),
00088 _template_system_flag(false)
00089 {
00090 _birth_rate = copy._birth_rate;
00091 _litter_size = copy._litter_size;
00092 _litter_spread = copy._litter_spread;
00093 _active_system_flag = copy._active_system_flag;
00094 _local_velocity_flag = copy._local_velocity_flag;
00095 _spawn_on_death_flag = copy._spawn_on_death_flag;
00096 _i_was_spawned_flag = copy._i_was_spawned_flag;
00097 _system_grows_older_flag = copy._system_grows_older_flag;
00098 _emitter = copy._emitter;
00099 _renderer = copy._renderer->make_copy();
00100 _factory = copy._factory;
00101
00102 _render_parent = copy._render_parent;
00103 _render_node = _renderer->get_render_node();
00104 _render_parent->add_child(_render_node);
00105
00106 _tics_since_birth = _birth_rate;
00107 _system_lifespan = copy._system_lifespan;
00108 _living_particles = 0;
00109
00110 set_pool_size(copy._particle_pool_size);
00111 }
00112
00113
00114
00115
00116
00117
00118 ParticleSystem::
00119 ~ParticleSystem(void) {
00120 set_pool_size(0);
00121
00122 if (!_template_system_flag) {
00123 _renderer.clear();
00124
00125 if (!_render_node.is_null())
00126 _render_parent->remove_child(_render_node);
00127 }
00128 }
00129
00130
00131
00132
00133
00134
00135
00136 bool ParticleSystem::
00137 birth_particle(void) {
00138 int pool_index;
00139
00140
00141 if (_living_particles >= _particle_pool_size) {
00142 #ifdef PSDEBUG
00143 if (_living_particles > _particle_pool_size) {
00144 cout << "_living_particles > _particle_pool_size" << endl;
00145 }
00146 #endif
00147 return false;
00148 }
00149
00150 #ifdef PSDEBUG
00151 if (0 == _free_particle_fifo.size()) {
00152 cout << "Error: _free_particle_fifo is empty, but _living_particles < _particle_pool_size" << endl;
00153 return false;
00154 }
00155 #endif
00156
00157 pool_index = _free_particle_fifo.back();
00158 _free_particle_fifo.pop_back();
00159
00160
00161 BaseParticle *bp = (BaseParticle *) _physics_objects[pool_index].p();
00162
00163
00164 _factory->populate_particle(bp);
00165
00166 bp->set_alive(true);
00167 bp->set_active(true);
00168 bp->init();
00169
00170
00171 LPoint3f new_pos, world_pos;
00172 LVector3f new_vel;
00173 GeomNode *render_node;
00174
00175 _emitter->generate(new_pos, new_vel);
00176 render_node = _renderer->get_render_node();
00177
00178
00179 NodePath physical_np(get_physical_node());
00180 NodePath render_np(render_node);
00181 const LMatrix4f &birth_to_render_xform = physical_np.get_mat(render_np);
00182 world_pos = new_pos * birth_to_render_xform;
00183
00184
00185
00186
00187 if (_local_velocity_flag == false)
00188 new_vel = new_vel * birth_to_render_xform;
00189
00190 bp->set_position_HandOfGod(world_pos);
00191 bp->set_velocity(new_vel);
00192
00193 _living_particles++;
00194
00195
00196 _renderer->birth_particle(pool_index);
00197
00198 return true;
00199 }
00200
00201
00202
00203
00204
00205
00206 void ParticleSystem::
00207 birth_litter(void) {
00208 int litter_size, i;
00209
00210 litter_size = _litter_size;
00211
00212 if (_litter_spread != 0)
00213 litter_size += I_SPREAD(_litter_spread);
00214
00215 for (i = 0; i < litter_size; i++) {
00216 if (birth_particle() == false)
00217 return;
00218 }
00219 }
00220
00221
00222
00223
00224
00225
00226
00227
00228 void ParticleSystem::
00229 spawn_child_system(BaseParticle *bp) {
00230
00231
00232 PhysicalNode *this_pn = get_physical_node();
00233 if (!this_pn) {
00234 physics_cat.error() << "ParticleSystem::spawn_child_system: "
00235 << "Spawning system is not in the scene graph,"
00236 << " aborting." << endl;
00237 return;
00238 }
00239
00240 if (this_pn->get_num_parents() == 0) {
00241 physics_cat.error() << "ParticleSystem::spawn_child_system: "
00242 << "PhysicalNode this system is contained in "
00243 << "has no parent, aborting." << endl;
00244 return;
00245 }
00246
00247 PandaNode *parent = this_pn->get_parent(0);
00248
00249
00250 int new_ps_index = rand() % _spawn_templates.size();
00251 ParticleSystem *ps_template = _spawn_templates[new_ps_index];
00252
00253
00254 PT(ParticleSystem) new_ps = new ParticleSystem(*ps_template);
00255 new_ps->_i_was_spawned_flag = true;
00256
00257
00258 new_ps->_render_parent = _spawn_render_node;
00259 new_ps->_render_node = new_ps->_renderer->get_render_node();
00260 new_ps->_render_parent->add_child(new_ps->_render_node);
00261
00262
00263 PT(PhysicalNode) new_pn = new PhysicalNode("new_pn");
00264 new_pn->add_physical(new_ps);
00265
00266
00267
00268
00269 parent->add_child(new_pn);
00270
00271 NodePath parent_np(parent);
00272 NodePath physical_np(get_physical_node());
00273
00274 const LMatrix4f &old_system_to_parent_xform = physical_np.get_mat(parent_np);
00275
00276 LMatrix4f child_space_xform = old_system_to_parent_xform *
00277 bp->get_lcs();
00278
00279 new_pn->set_transform(TransformState::make_mat(child_space_xform));
00280
00281
00282 _manager->attach_particlesystem(new_ps);
00283 get_physics_manager()->attach_physical(new_ps);
00284 }
00285
00286
00287
00288
00289
00290
00291
00292 void ParticleSystem::
00293 kill_particle(int pool_index) {
00294
00295 BaseParticle *bp = (BaseParticle *) _physics_objects[pool_index].p();
00296
00297
00298 if (_spawn_on_death_flag == true)
00299 spawn_child_system(bp);
00300
00301
00302 bp->set_alive(false);
00303 bp->set_active(false);
00304 bp->die();
00305
00306 _free_particle_fifo.push_back(pool_index);
00307
00308
00309 _renderer->kill_particle(pool_index);
00310
00311 _living_particles--;
00312 }
00313
00314
00315
00316
00317
00318
00319 #ifdef PSDEBUG
00320 #define PARTICLE_SYSTEM_RESIZE_POOL_SENTRIES
00321 #endif
00322 void ParticleSystem::
00323 resize_pool(int size) {
00324 int i;
00325 int delta = size - _particle_pool_size;
00326 int po_delta = _particle_pool_size - _physics_objects.size();
00327
00328 #ifdef PARTICLE_SYSTEM_RESIZE_POOL_SENTRIES
00329 cout << "resizing particle pool from " << _particle_pool_size
00330 << " to " << size << endl;
00331 #endif
00332
00333 if (_factory.is_null()) {
00334 particlesystem_cat.error() << "ParticleSystem::resize_pool"
00335 << " called with null _factory." << endl;
00336 return;
00337 }
00338
00339 if (_renderer.is_null()) {
00340 particlesystem_cat.error() << "ParticleSystem::resize_pool"
00341 << " called with null _renderer." << endl;
00342 return;
00343 }
00344
00345 _particle_pool_size = size;
00346
00347
00348 if (po_delta) {
00349 if (po_delta > 0) {
00350 for (i = 0; i < po_delta; i++)
00351 {
00352
00353
00354 BaseParticle *new_particle = _factory->alloc_particle();
00355 if (new_particle) {
00356 _factory->populate_particle(new_particle);
00357
00358 _physics_objects.push_back(new_particle);
00359 } else {
00360 #ifdef PSDEBUG
00361 cout << "Error allocating new particle" << endl;
00362 _particle_pool_size--;
00363 #endif
00364 }
00365 }
00366 } else {
00367 #ifdef PSDEBUG
00368 cout << "physics_object array is too large??" << endl;
00369 _particle_pool_size--;
00370 #endif
00371 po_delta = -po_delta;
00372 for (i = 0; i < po_delta; i++) {
00373 int delete_index = _physics_objects.size()-1;
00374 BaseParticle *bp = (BaseParticle *) _physics_objects[delete_index].p();
00375 if (bp->get_alive()) {
00376 kill_particle(delete_index);
00377 _free_particle_fifo.pop_back();
00378 } else {
00379 pdeque<int>::iterator i;
00380 i = find(_free_particle_fifo.begin(), _free_particle_fifo.end(), delete_index);
00381 if (i != _free_particle_fifo.end()) {
00382 _free_particle_fifo.erase(i);
00383 }
00384 }
00385 _physics_objects.pop_back();
00386 }
00387 }
00388 }
00389
00390
00391 if (delta == 0)
00392 return;
00393
00394
00395 if (delta > 0) {
00396
00397 for (i = 0; i < delta; i++)
00398 {
00399 int free_index = _physics_objects.size();
00400
00401 BaseParticle *new_particle = _factory->alloc_particle();
00402 if (new_particle) {
00403 _factory->populate_particle(new_particle);
00404
00405 _physics_objects.push_back(new_particle);
00406 _free_particle_fifo.push_back(free_index);
00407 } else {
00408 #ifdef PSDEBUG
00409 cout << "Error allocating new particle" << endl;
00410 _particle_pool_size--;
00411 #endif
00412 }
00413 }
00414 } else {
00415
00416 delta = -delta;
00417 for (i = 0; i < delta; i++) {
00418 int delete_index = _physics_objects.size()-1;
00419 BaseParticle *bp = (BaseParticle *) _physics_objects[delete_index].p();
00420
00421 if (bp->get_alive()) {
00422 #ifdef PSDEBUG
00423 cout << "WAS ALIVE" << endl;
00424 #endif
00425 kill_particle(delete_index);
00426 _free_particle_fifo.pop_back();
00427 } else {
00428 #ifdef PSDEBUG
00429 cout << "WAS NOT ALIVE" << endl;
00430 #endif
00431 pdeque<int>::iterator i;
00432 i = find(_free_particle_fifo.begin(), _free_particle_fifo.end(), delete_index);
00433 if (i != _free_particle_fifo.end()) {
00434 _free_particle_fifo.erase(i);
00435 }
00436 #ifdef PSDEBUG
00437 else {
00438 cout << "particle not found in free FIFO!!!!!!!!" << endl;
00439 }
00440 #endif
00441 }
00442
00443 _physics_objects.pop_back();
00444 }
00445 }
00446
00447 _renderer->resize_pool(_particle_pool_size);
00448
00449 #ifdef PARTICLE_SYSTEM_RESIZE_POOL_SENTRIES
00450 cout << "particle pool resized" << endl;
00451 #endif
00452 }
00453
00454
00455
00456
00457
00458
00459 #ifdef PSDEBUG
00460
00461 #endif
00462 void ParticleSystem::
00463 update(float dt) {
00464 int ttl_updates_left = _living_particles;
00465 int current_index = 0, index_counter = 0;
00466 BaseParticle *bp;
00467 float age;
00468
00469 #ifdef PSSANITYCHECK
00470
00471 if (sanity_check()) return;
00472 #endif
00473
00474 #ifdef PARTICLE_SYSTEM_UPDATE_SENTRIES
00475 cout << "UPDATE: pool size: " << _particle_pool_size
00476 << ", live particles: " << _living_particles << endl;
00477 #endif
00478
00479
00480 while (ttl_updates_left) {
00481 current_index = index_counter;
00482 index_counter++;
00483
00484 #ifdef PSDEBUG
00485 if (current_index >= _particle_pool_size) {
00486 cout << "ERROR: _living_particles is out of sync (too large)" << endl;
00487 cout << "pool size: " << _particle_pool_size
00488 << ", live particles: " << _living_particles
00489 << ", updates left: " << ttl_updates_left << endl;
00490 break;
00491 }
00492 #endif
00493
00494
00495 bp = (BaseParticle *) _physics_objects[current_index].p();
00496
00497 #ifdef PSDEBUG
00498 if (!bp) {
00499 cout << "NULL ptr at index " << current_index << endl;
00500 continue;
00501 }
00502 #endif
00503
00504 if (bp->get_alive() == false)
00505 continue;
00506
00507 age = bp->get_age() + dt;
00508 bp->set_age(age);
00509
00510 if (age >= bp->get_lifespan())
00511 kill_particle(current_index);
00512 else
00513 bp->update();
00514
00515
00516 ttl_updates_left--;
00517 }
00518
00519
00520
00521 _tics_since_birth += dt;
00522
00523 while (_tics_since_birth >= _birth_rate) {
00524 birth_litter();
00525 _tics_since_birth -= _birth_rate;
00526 }
00527
00528 #ifdef PARTICLE_SYSTEM_UPDATE_SENTRIES
00529 cout << "particle update complete" << endl;
00530 #endif
00531
00532 }
00533
00534 #ifdef PSSANITYCHECK
00535
00536
00537
00538
00539
00540
00541 #ifndef NDEBUG
00542 #define PSSCVERBOSE
00543 #endif
00544
00545 class SC_valuenamepair : public ReferenceCount {
00546 public:
00547 int value;
00548 char *name;
00549 SC_valuenamepair(int v, char *s) : value(v), name(s) {}
00550 };
00551
00552
00553 static int check_free_live_total_particles(pvector< PT(SC_valuenamepair) > live_counts,
00554 pvector< PT(SC_valuenamepair) > dead_counts, pvector< PT(SC_valuenamepair) > total_counts,
00555 int print_all = 0) {
00556
00557 int val = 0;
00558 int l, d, t;
00559
00560 for(l = 0; l < live_counts.size(); l++) {
00561 for(d = 0; d < dead_counts.size(); d++) {
00562 for(t = 0; t < total_counts.size(); t++) {
00563 int live = live_counts[l]->value;
00564 int dead = dead_counts[d]->value;
00565 int total = total_counts[t]->value;
00566 if ((live + dead) != total) {
00567 #ifdef PSSCVERBOSE
00568 cout << "free/live/total count: "
00569 << live_counts[l]->name << " (" << live << ") + "
00570 << dead_counts[d]->name << " (" << dead << ") = "
00571 << live + dead << ", != "
00572 << total_counts[t]->name << " (" << total << ")"
00573 << endl;
00574 #endif
00575 val++;
00576 }
00577 }
00578 }
00579 }
00580
00581 return val;
00582 }
00583
00584 int ParticleSystem::
00585 sanity_check() {
00586 int result = 0;
00587 int i;
00588 BaseParticle *bp;
00589 int pool_size;
00590
00591
00592
00593 if (_particle_pool_size != _physics_objects.size()) {
00594 #ifdef PSSCVERBOSE
00595 cout << "_particle_pool_size (" << _particle_pool_size
00596 << ") != particle array size (" << _physics_objects.size() << ")" << endl;
00597 #endif
00598 result++;
00599 }
00600 pool_size = min(_particle_pool_size, _physics_objects.size());
00601
00602
00603
00604
00605 int real_live_particle_count = 0;
00606 int real_dead_particle_count = 0;
00607
00608 for (i = 0; i < _physics_objects.size(); i++) {
00609 bp = (BaseParticle *) _physics_objects[i].p();
00610 if (true == bp->get_alive()) {
00611 real_live_particle_count++;
00612 } else {
00613 real_dead_particle_count++;
00614 }
00615 }
00616
00617 if (real_live_particle_count != _living_particles) {
00618 #ifdef PSSCVERBOSE
00619 cout << "manually counted live particle count (" << real_live_particle_count
00620 << ") != _living_particles (" << _living_particles << ")" << endl;
00621 #endif
00622 result++;
00623 }
00624
00625 if (real_dead_particle_count != _free_particle_fifo.size()) {
00626 #ifdef PSSCVERBOSE
00627 cout << "manually counted dead particle count (" << real_dead_particle_count
00628 << ") != free particle fifo size (" << _free_particle_fifo.size() << ")" << endl;
00629 #endif
00630 result++;
00631 }
00632
00633
00634
00635
00636 for (i = 0; i < _free_particle_fifo.size(); i++) {
00637 int index = _free_particle_fifo[i];
00638
00639
00640 if (index >= pool_size) {
00641 #ifdef PSSCVERBOSE
00642 cout << "index from free particle fifo (" << index
00643 << ") is too large; pool size is " << pool_size << endl;
00644 #endif
00645 result++;
00646 continue;
00647 }
00648
00649
00650 bp = (BaseParticle *) _physics_objects[index].p();
00651 if (true == bp->get_alive()) {
00652 #ifdef PSSCVERBOSE
00653 cout << "particle " << index << " in free fifo is not dead" << endl;
00654 #endif
00655 result++;
00656 }
00657 }
00658
00659
00660
00661
00662 pvector< PT(SC_valuenamepair) > live_counts;
00663 pvector< PT(SC_valuenamepair) > dead_counts;
00664 pvector< PT(SC_valuenamepair) > total_counts;
00665
00666 live_counts.push_back(new SC_valuenamepair(real_live_particle_count, "real_live_particle_count"));
00667
00668 dead_counts.push_back(new SC_valuenamepair(real_dead_particle_count, "real_dead_particle_count"));
00669 dead_counts.push_back(new SC_valuenamepair(_free_particle_fifo.size(), "free particle fifo size"));
00670
00671 total_counts.push_back(new SC_valuenamepair(_particle_pool_size, "_particle_pool_size"));
00672 total_counts.push_back(new SC_valuenamepair(_physics_objects.size(), "actual particle pool size"));
00673
00674 result += check_free_live_total_particles(live_counts, dead_counts, total_counts);
00675
00676
00677 return result;
00678 }
00679 #endif