19 #include "clockObject.h" 20 #include "physicsManager.h" 21 #include "physicalNode.h" 22 #include "nearly_zero.h" 23 #include "transformState.h" 26 #include "config_particlesystem.h" 27 #include "particleSystem.h" 28 #include "particleSystemManager.h" 29 #include "pointParticleRenderer.h" 30 #include "pointParticleFactory.h" 31 #include "sphereSurfaceEmitter.h" 32 #include "pStatTimer.h" 36 PStatCollector ParticleSystem::_update_collector(
"App:Particles:Update");
48 _cur_birth_rate = _birth_rate;
49 _soft_birth_rate = HUGE_VAL;
50 _tics_since_birth = 0.0;
53 _living_particles = 0;
54 _active_system_flag =
true;
55 _local_velocity_flag =
true;
56 _spawn_on_death_flag =
false;
57 _system_grows_older_flag =
false;
58 _system_lifespan = 0.0f;
59 _i_was_spawned_flag =
false;
60 _particle_pool_size = 0;
70 _render_parent =
NodePath(
"ParticleSystem default render parent");
80 set_pool_size(pool_size);
92 _template_system_flag(false)
94 _birth_rate = copy._birth_rate;
95 _cur_birth_rate = copy._cur_birth_rate;
96 _litter_size = copy._litter_size;
97 _litter_spread = copy._litter_spread;
98 _active_system_flag = copy._active_system_flag;
99 _local_velocity_flag = copy._local_velocity_flag;
100 _spawn_on_death_flag = copy._spawn_on_death_flag;
101 _i_was_spawned_flag = copy._i_was_spawned_flag;
102 _system_grows_older_flag = copy._system_grows_older_flag;
103 _emitter = copy._emitter;
104 _renderer = copy._renderer->make_copy();
105 _factory = copy._factory;
107 _render_parent = copy._render_parent;
108 _render_node_path = _renderer->get_render_node_path();
111 _tics_since_birth = 0.0;
112 _system_lifespan = copy._system_lifespan;
113 _living_particles = 0;
115 set_pool_size(copy._particle_pool_size);
127 if (!_template_system_flag) {
139 bool ParticleSystem::
144 if (_living_particles >= _particle_pool_size) {
146 if (_living_particles > _particle_pool_size) {
147 cout <<
"_living_particles > _particle_pool_size" << endl;
154 if (0 == _free_particle_fifo.size()) {
155 cout <<
"Error: _free_particle_fifo is empty, but _living_particles < _particle_pool_size" << endl;
160 pool_index = _free_particle_fifo.back();
161 _free_particle_fifo.pop_back();
167 _factory->populate_particle(bp);
177 _emitter->generate(new_pos, new_vel);
180 NodePath physical_np = get_physical_node_path();
181 NodePath render_np = _renderer->get_render_node_path();
183 CPT(TransformState) transform = physical_np.
get_transform(render_np);
184 const LMatrix4 &birth_to_render_xform = transform->get_mat();
185 world_pos = new_pos * birth_to_render_xform;
190 if (_local_velocity_flag ==
false)
191 new_vel = new_vel * birth_to_render_xform;
199 _renderer->birth_particle(pool_index);
209 void ParticleSystem::
213 litter_size = _litter_size;
215 if (_litter_spread != 0)
216 litter_size += I_SPREAD(_litter_spread);
218 for (i = 0; i < litter_size; ++i) {
219 if (birth_particle() ==
false)
231 void ParticleSystem::
237 physics_cat.error() <<
"ParticleSystem::spawn_child_system: " 238 <<
"Spawning system is not in the scene graph," 239 <<
" aborting." << endl;
244 physics_cat.error() <<
"ParticleSystem::spawn_child_system: " 245 <<
"PhysicalNode this system is contained in " 246 <<
"has no parent, aborting." << endl;
250 if (_spawn_templates.size() == 0) {
251 physics_cat.error() <<
"ParticleSystem::spawn_child_system: " 252 <<
"no spawn templates present." << endl;
256 NodePath physical_np = get_physical_node_path();
262 int new_ps_index = rand() % _spawn_templates.size();
267 new_ps->_i_was_spawned_flag =
true;
270 new_ps->_render_parent = _spawn_render_node_path;
271 new_ps->_render_node_path = new_ps->_renderer->get_render_node_path();
272 new_ps->_render_node_path.
reparent_to(new_ps->_render_parent);
276 new_pn->add_physical(new_ps);
281 parent->add_child(new_pn);
283 CPT(TransformState) transform = physical_np.
get_transform(parent_np);
284 const LMatrix4 &old_system_to_parent_xform = transform->get_mat();
286 LMatrix4 child_space_xform = old_system_to_parent_xform *
289 new_pn->set_transform(TransformState::make_mat(child_space_xform));
292 _manager->attach_particlesystem(new_ps);
302 void ParticleSystem::
303 kill_particle(
int pool_index) {
308 if (_spawn_on_death_flag ==
true) {
309 spawn_child_system(bp);
313 bp->set_alive(
false);
317 _free_particle_fifo.push_back(pool_index);
320 _renderer->kill_particle(pool_index);
331 #define PARTICLE_SYSTEM_RESIZE_POOL_SENTRIES 333 void ParticleSystem::
334 resize_pool(
int size) {
336 int delta = size - _particle_pool_size;
337 int po_delta = _particle_pool_size - _physics_objects.size();
339 #ifdef PARTICLE_SYSTEM_RESIZE_POOL_SENTRIES 340 cout <<
"resizing particle pool from " << _particle_pool_size
341 <<
" to " << size << endl;
344 if (_factory.is_null()) {
345 particlesystem_cat.error() <<
"ParticleSystem::resize_pool" 346 <<
" called with null _factory." << endl;
350 if (_renderer.is_null()) {
351 particlesystem_cat.error() <<
"ParticleSystem::resize_pool" 352 <<
" called with null _renderer." << endl;
356 _particle_pool_size = size;
361 for (i = 0; i < po_delta; i++)
365 BaseParticle *new_particle = _factory->alloc_particle();
367 _factory->populate_particle(new_particle);
369 _physics_objects.push_back(new_particle);
372 cout <<
"Error allocating new particle" << endl;
373 _particle_pool_size--;
379 cout <<
"physics_object array is too large??" << endl;
380 _particle_pool_size--;
382 po_delta = -po_delta;
383 for (i = 0; i < po_delta; i++) {
384 int delete_index = _physics_objects.size()-1;
386 if (bp->get_alive()) {
387 kill_particle(delete_index);
388 _free_particle_fifo.pop_back();
391 i = find(_free_particle_fifo.begin(), _free_particle_fifo.end(), delete_index);
392 if (i != _free_particle_fifo.end()) {
393 _free_particle_fifo.erase(i);
396 _physics_objects.pop_back();
408 for (i = 0; i < delta; i++)
410 int free_index = _physics_objects.size();
412 BaseParticle *new_particle = _factory->alloc_particle();
414 _factory->populate_particle(new_particle);
416 _physics_objects.push_back(new_particle);
417 _free_particle_fifo.push_back(free_index);
420 cout <<
"Error allocating new particle" << endl;
421 _particle_pool_size--;
428 for (i = 0; i < delta; i++) {
429 int delete_index = _physics_objects.size()-1;
432 if (bp->get_alive()) {
434 cout <<
"WAS ALIVE" << endl;
436 kill_particle(delete_index);
437 _free_particle_fifo.pop_back();
440 cout <<
"WAS NOT ALIVE" << endl;
443 i = find(_free_particle_fifo.begin(), _free_particle_fifo.end(), delete_index);
444 if (i != _free_particle_fifo.end()) {
445 _free_particle_fifo.erase(i);
449 cout <<
"particle not found in free FIFO!!!!!!!!" << endl;
454 _physics_objects.pop_back();
458 _renderer->resize_pool(_particle_pool_size);
460 #ifdef PARTICLE_SYSTEM_RESIZE_POOL_SENTRIES 461 cout <<
"particle pool resized" << endl;
477 int ttl_updates_left = _living_particles;
478 int current_index = 0, index_counter = 0;
484 if (sanity_check())
return;
487 #ifdef PARTICLE_SYSTEM_UPDATE_SENTRIES 488 cout <<
"UPDATE: pool size: " << _particle_pool_size
489 <<
", live particles: " << _living_particles << endl;
493 while (ttl_updates_left) {
494 current_index = index_counter;
498 if (current_index >= _particle_pool_size) {
499 cout <<
"ERROR: _living_particles is out of sync (too large)" << endl;
500 cout <<
"pool size: " << _particle_pool_size
501 <<
", live particles: " << _living_particles
502 <<
", updates left: " << ttl_updates_left << endl;
508 bp = (
BaseParticle *) _physics_objects[current_index].p();
512 cout <<
"NULL ptr at index " << current_index << endl;
517 if (bp->get_alive() ==
false)
520 age = bp->get_age() + dt;
524 if (age >= bp->get_lifespan()) {
525 kill_particle(current_index);
526 }
else if (get_floor_z() != -HUGE_VAL
530 kill_particle(current_index);
541 _tics_since_birth += dt;
543 while (_tics_since_birth >= _cur_birth_rate) {
545 _tics_since_birth -= _cur_birth_rate;
548 #ifdef PARTICLE_SYSTEM_UPDATE_SENTRIES 549 cout <<
"particle update complete" << endl;
569 SC_valuenamepair(
int v,
char *s) : value(v), name(s) {}
573 static int check_free_live_total_particles(
pvector< PT(SC_valuenamepair) > live_counts,
574 pvector< PT(SC_valuenamepair) > dead_counts,
pvector< PT(SC_valuenamepair) > total_counts,
580 for(l = 0; l < live_counts.size(); l++) {
581 for(d = 0; d < dead_counts.size(); d++) {
582 for(t = 0; t < total_counts.size(); t++) {
583 int live = live_counts[l]->value;
584 int dead = dead_counts[d]->value;
585 int total = total_counts[t]->value;
586 if ((live + dead) != total) {
588 cout <<
"free/live/total count: " 589 << live_counts[l]->name <<
" (" << live <<
") + " 590 << dead_counts[d]->name <<
" (" << dead <<
") = " 591 << live + dead <<
", != " 592 << total_counts[t]->name <<
" (" << total <<
")" 613 if (_particle_pool_size != _physics_objects.size()) {
615 cout <<
"_particle_pool_size (" << _particle_pool_size
616 <<
") != particle array size (" << _physics_objects.size() <<
")" << endl;
620 pool_size = min(_particle_pool_size, _physics_objects.size());
625 int real_live_particle_count = 0;
626 int real_dead_particle_count = 0;
628 for (i = 0; i < _physics_objects.size(); i++) {
630 if (
true == bp->get_alive()) {
631 real_live_particle_count++;
633 real_dead_particle_count++;
637 if (real_live_particle_count != _living_particles) {
639 cout <<
"manually counted live particle count (" << real_live_particle_count
640 <<
") != _living_particles (" << _living_particles <<
")" << endl;
645 if (real_dead_particle_count != _free_particle_fifo.size()) {
647 cout <<
"manually counted dead particle count (" << real_dead_particle_count
648 <<
") != free particle fifo size (" << _free_particle_fifo.size() <<
")" << endl;
656 for (i = 0; i < _free_particle_fifo.size(); i++) {
657 int index = _free_particle_fifo[i];
660 if (index >= pool_size) {
662 cout <<
"index from free particle fifo (" << index
663 <<
") is too large; pool size is " << pool_size << endl;
671 if (
true == bp->get_alive()) {
673 cout <<
"particle " << index <<
" in free fifo is not dead" << endl;
686 live_counts.push_back(
new SC_valuenamepair(real_live_particle_count,
"real_live_particle_count"));
688 dead_counts.push_back(
new SC_valuenamepair(real_dead_particle_count,
"real_dead_particle_count"));
689 dead_counts.push_back(
new SC_valuenamepair(_free_particle_fifo.size(),
"free particle fifo size"));
691 total_counts.push_back(
new SC_valuenamepair(_particle_pool_size,
"_particle_pool_size"));
692 total_counts.push_back(
new SC_valuenamepair(_physics_objects.size(),
"actual particle pool size"));
694 result += check_free_live_total_particles(live_counts, dead_counts, total_counts);
710 out<<
"ParticleSystem";
724 out<<
""<<
"_free_particle_fifo ("<<_free_particle_fifo.size()<<
" forces)\n";
726 i != _free_particle_fifo.end();
728 out.width(indent+2); out<<
""; out<<(*i)<<
"\n";
743 out<<
""<<
"_spawn_templates ("<<_spawn_templates.size()<<
" templates)\n";
745 i != _spawn_templates.end();
747 (*i)->write(out, indent+2);
759 write(ostream &out,
int indent)
const {
761 out.width(indent); out<<
""; out<<
"ParticleSystem:\n";
762 out.width(indent+2); out<<
""; out<<
"_particle_pool_size "<<_particle_pool_size<<
"\n";
763 out.width(indent+2); out<<
""; out<<
"_living_particles "<<_living_particles<<
"\n";
764 out.width(indent+2); out<<
""; out<<
"_tics_since_birth "<<_tics_since_birth<<
"\n";
765 out.width(indent+2); out<<
""; out<<
"_litter_size "<<_litter_size<<
"\n";
766 out.width(indent+2); out<<
""; out<<
"_litter_spread "<<_litter_spread<<
"\n";
767 out.width(indent+2); out<<
""; out<<
"_system_age "<<_system_age<<
"\n";
768 out.width(indent+2); out<<
""; out<<
"_system_lifespan "<<_system_lifespan<<
"\n";
769 out.width(indent+2); out<<
""; out<<
"_factory "<<_factory<<
"\n";
770 out.width(indent+2); out<<
""; out<<
"_emitter "<<_emitter<<
"\n";
771 out.width(indent+2); out<<
""; out<<
"_renderer "<<_renderer<<
"\n";
772 out.width(indent+2); out<<
""; out<<
"_manager "<<_manager<<
"\n";
773 out.width(indent+2); out<<
""; out<<
"_template_system_flag "<<_template_system_flag<<
"\n";
774 out.width(indent+2); out<<
""; out<<
"_render_parent "<<_render_parent<<
"\n";
775 out.width(indent+2); out<<
""; out<<
"_render_node "<<_render_node_path<<
"\n";
776 out.width(indent+2); out<<
""; out<<
"_active_system_flag "<<_active_system_flag<<
"\n";
777 out.width(indent+2); out<<
""; out<<
"_local_velocity_flag "<<_local_velocity_flag<<
"\n";
778 out.width(indent+2); out<<
""; out<<
"_system_grows_older_flag "<<_system_grows_older_flag<<
"\n";
779 out.width(indent+2); out<<
""; out<<
"_spawn_on_death_flag "<<_spawn_on_death_flag<<
"\n";
780 out.width(indent+2); out<<
""; out<<
"_spawn_render_node "<<_spawn_render_node_path<<
"\n";
781 out.width(indent+2); out<<
""; out<<
"_i_was_spawned_flag "<<_i_was_spawned_flag<<
"\n";
A basic node of the scene graph or data graph.
void reset_position(const LPoint3 &pos)
use this to place an object in a completely new position, that has nothing to do with its last positi...
virtual void write_spawn_templates(ostream &out, int indent=0) const
Write a string representation of this instance to <out>.
Describes a curved space in which particles are generated.
~ParticleSystem()
You get the ankles and I'll get the wrists.
void set_velocity(const LVector3 &vel)
Vector velocity assignment.
void attach_physical(Physical *p)
Registers a Physical class with the manager.
Creates point particles to user specs.
void clear_physics_objects()
Erases the object list.
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
This is our own Panda specialization on the default STL deque.
This is our own Panda specialization on the default STL vector.
Graph node that encapsulated a series of physical objects.
void set_active(bool flag)
Process Flag assignment.
A lightweight class that represents a single element that may be timed and/or counted via stats...
Contains and manages a particle system.
void reparent_to(const NodePath &other, int sort=0, Thread *current_thread=Thread::get_current_thread())
Removes the referenced node of the NodePath from its current parent and attaches it to the referenced...
This is a 4-by-4 transform matrix.
virtual void write(ostream &out=cout, unsigned int indent=0) const
Write a string representation of this instance to <out>.
Simple point/point particle renderer.
virtual void output(ostream &out) const
Write a string representation of this instance to <out>.
Defines a set of physically modeled attributes.
virtual void write(ostream &out, int indent=0) const
Write a string representation of this instance to <out>.
ParticleSystem(int pool_size=0)
Default Constructor.
int get_num_parents(Thread *current_thread=Thread::get_current_thread()) const
Returns the number of parent nodes this node has.
A base class for all things that want to be reference-counted.
PandaNode * node() const
Returns the referenced node of the path.
An individual, physically-modelable particle abstract base class.
void remove_node(Thread *current_thread=Thread::get_current_thread())
Disconnects the referenced node from the scene graph.
virtual void write_free_particle_fifo(ostream &out, int indent=0) const
Write a string representation of this instance to <out>.
LPoint3 get_position() const
Position Query.
NodePath get_parent(Thread *current_thread=Thread::get_current_thread()) const
Returns the NodePath to the parent of the referenced node: that is, this NodePath, shortened by one node.
void update(PN_stdfloat dt)
Updates the particle system.
TypeHandle is the identifier used to differentiate C++ class types.
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
virtual LMatrix4 get_lcs() const
returns a transform matrix to this object's local coordinate system.