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;
193 bp->reset_position(world_pos);
194 bp->set_velocity(new_vel);
199 _renderer->birth_particle(pool_index);
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 NodePath physical_np = get_physical_node_path();
256 int new_ps_index = rand() % _spawn_templates.size();
261 new_ps->_i_was_spawned_flag = true;
264 new_ps->_render_parent = _spawn_render_node_path;
265 new_ps->_render_node_path = new_ps->_renderer->get_render_node_path();
266 new_ps->_render_node_path.reparent_to(new_ps->_render_parent);
270 new_pn->add_physical(new_ps);
275 parent->add_child(new_pn);
277 CPT(TransformState) transform = physical_np.get_transform(parent_np);
278 const
LMatrix4 &old_system_to_parent_xform = transform->get_mat();
280 LMatrix4 child_space_xform = old_system_to_parent_xform *
283 new_pn->set_transform(TransformState::make_mat(child_space_xform));
286 _manager->attach_particlesystem(new_ps);
287 get_physics_manager()->attach_physical(new_ps);
297 kill_particle(
int pool_index) {
302 if (_spawn_on_death_flag ==
true) {
303 spawn_child_system(bp);
307 bp->set_alive(
false);
311 _free_particle_fifo.push_back(pool_index);
314 _renderer->kill_particle(pool_index);
325 #define PARTICLE_SYSTEM_RESIZE_POOL_SENTRIES
327 void ParticleSystem::
328 resize_pool(
int size) {
330 int delta = size - _particle_pool_size;
331 int po_delta = _particle_pool_size - _physics_objects.size();
333 #ifdef PARTICLE_SYSTEM_RESIZE_POOL_SENTRIES
334 cout <<
"resizing particle pool from " << _particle_pool_size
335 <<
" to " << size << endl;
338 if (_factory.is_null()) {
339 particlesystem_cat.error() <<
"ParticleSystem::resize_pool"
340 <<
" called with null _factory." << endl;
344 if (_renderer.is_null()) {
345 particlesystem_cat.error() <<
"ParticleSystem::resize_pool"
346 <<
" called with null _renderer." << endl;
350 _particle_pool_size = size;
355 for (i = 0; i < po_delta; i++)
359 BaseParticle *new_particle = _factory->alloc_particle();
361 _factory->populate_particle(new_particle);
363 _physics_objects.push_back(new_particle);
366 cout <<
"Error allocating new particle" << endl;
367 _particle_pool_size--;
373 cout <<
"physics_object array is too large??" << endl;
374 _particle_pool_size--;
376 po_delta = -po_delta;
377 for (i = 0; i < po_delta; i++) {
378 int delete_index = _physics_objects.size()-1;
380 if (bp->get_alive()) {
381 kill_particle(delete_index);
382 _free_particle_fifo.pop_back();
385 i = find(_free_particle_fifo.begin(), _free_particle_fifo.end(), delete_index);
386 if (i != _free_particle_fifo.end()) {
387 _free_particle_fifo.erase(i);
390 _physics_objects.pop_back();
402 for (i = 0; i < delta; i++)
404 int free_index = _physics_objects.size();
406 BaseParticle *new_particle = _factory->alloc_particle();
408 _factory->populate_particle(new_particle);
410 _physics_objects.push_back(new_particle);
411 _free_particle_fifo.push_back(free_index);
414 cout <<
"Error allocating new particle" << endl;
415 _particle_pool_size--;
422 for (i = 0; i < delta; i++) {
423 int delete_index = _physics_objects.size()-1;
426 if (bp->get_alive()) {
428 cout <<
"WAS ALIVE" << endl;
430 kill_particle(delete_index);
431 _free_particle_fifo.pop_back();
434 cout <<
"WAS NOT ALIVE" << endl;
437 i = find(_free_particle_fifo.begin(), _free_particle_fifo.end(), delete_index);
438 if (i != _free_particle_fifo.end()) {
439 _free_particle_fifo.erase(i);
443 cout <<
"particle not found in free FIFO!!!!!!!!" << endl;
448 _physics_objects.pop_back();
452 _renderer->resize_pool(_particle_pool_size);
454 #ifdef PARTICLE_SYSTEM_RESIZE_POOL_SENTRIES
455 cout <<
"particle pool resized" << endl;
471 int ttl_updates_left = _living_particles;
472 int current_index = 0, index_counter = 0;
478 if (sanity_check())
return;
481 #ifdef PARTICLE_SYSTEM_UPDATE_SENTRIES
482 cout <<
"UPDATE: pool size: " << _particle_pool_size
483 <<
", live particles: " << _living_particles << endl;
487 while (ttl_updates_left) {
488 current_index = index_counter;
492 if (current_index >= _particle_pool_size) {
493 cout <<
"ERROR: _living_particles is out of sync (too large)" << endl;
494 cout <<
"pool size: " << _particle_pool_size
495 <<
", live particles: " << _living_particles
496 <<
", updates left: " << ttl_updates_left << endl;
502 bp = (
BaseParticle *) _physics_objects[current_index].p();
506 cout <<
"NULL ptr at index " << current_index << endl;
511 if (bp->get_alive() ==
false)
514 age = bp->get_age() + dt;
518 if (age >= bp->get_lifespan()) {
519 kill_particle(current_index);
520 }
else if (get_floor_z() != -HUGE_VAL
524 kill_particle(current_index);
535 _tics_since_birth += dt;
537 while (_tics_since_birth >= _cur_birth_rate) {
539 _tics_since_birth -= _cur_birth_rate;
542 #ifdef PARTICLE_SYSTEM_UPDATE_SENTRIES
543 cout <<
"particle update complete" << endl;
563 SC_valuenamepair(
int v,
char *s) : value(v), name(s) {}
567 static int check_free_live_total_particles(
pvector< PT(SC_valuenamepair) > live_counts,
568 pvector< PT(SC_valuenamepair) > dead_counts,
pvector< PT(SC_valuenamepair) > total_counts,
574 for(l = 0; l < live_counts.size(); l++) {
575 for(d = 0; d < dead_counts.size(); d++) {
576 for(t = 0; t < total_counts.size(); t++) {
577 int live = live_counts[l]->value;
578 int dead = dead_counts[d]->value;
579 int total = total_counts[t]->value;
580 if ((live + dead) != total) {
582 cout <<
"free/live/total count: "
583 << live_counts[l]->name <<
" (" << live <<
") + "
584 << dead_counts[d]->name <<
" (" << dead <<
") = "
585 << live + dead <<
", != "
586 << total_counts[t]->name <<
" (" << total <<
")"
607 if (_particle_pool_size != _physics_objects.size()) {
609 cout <<
"_particle_pool_size (" << _particle_pool_size
610 <<
") != particle array size (" << _physics_objects.size() <<
")" << endl;
614 pool_size = min(_particle_pool_size, _physics_objects.size());
619 int real_live_particle_count = 0;
620 int real_dead_particle_count = 0;
622 for (i = 0; i < _physics_objects.size(); i++) {
624 if (
true == bp->get_alive()) {
625 real_live_particle_count++;
627 real_dead_particle_count++;
631 if (real_live_particle_count != _living_particles) {
633 cout <<
"manually counted live particle count (" << real_live_particle_count
634 <<
") != _living_particles (" << _living_particles <<
")" << endl;
639 if (real_dead_particle_count != _free_particle_fifo.size()) {
641 cout <<
"manually counted dead particle count (" << real_dead_particle_count
642 <<
") != free particle fifo size (" << _free_particle_fifo.size() <<
")" << endl;
650 for (i = 0; i < _free_particle_fifo.size(); i++) {
651 int index = _free_particle_fifo[i];
654 if (index >= pool_size) {
656 cout <<
"index from free particle fifo (" << index
657 <<
") is too large; pool size is " << pool_size << endl;
665 if (
true == bp->get_alive()) {
667 cout <<
"particle " << index <<
" in free fifo is not dead" << endl;
680 live_counts.push_back(
new SC_valuenamepair(real_live_particle_count,
"real_live_particle_count"));
682 dead_counts.push_back(
new SC_valuenamepair(real_dead_particle_count,
"real_dead_particle_count"));
683 dead_counts.push_back(
new SC_valuenamepair(_free_particle_fifo.size(),
"free particle fifo size"));
685 total_counts.push_back(
new SC_valuenamepair(_particle_pool_size,
"_particle_pool_size"));
686 total_counts.push_back(
new SC_valuenamepair(_physics_objects.size(),
"actual particle pool size"));
688 result += check_free_live_total_particles(live_counts, dead_counts, total_counts);
704 out<<
"ParticleSystem";
718 out<<
""<<
"_free_particle_fifo ("<<_free_particle_fifo.size()<<
" forces)\n";
720 i != _free_particle_fifo.end();
722 out.width(indent+2); out<<
""; out<<(*i)<<
"\n";
737 out<<
""<<
"_spawn_templates ("<<_spawn_templates.size()<<
" templates)\n";
739 i != _spawn_templates.end();
741 (*i)->write(out, indent+2);
753 write(ostream &out,
int indent)
const {
755 out.width(indent); out<<
""; out<<
"ParticleSystem:\n";
756 out.width(indent+2); out<<
""; out<<
"_particle_pool_size "<<_particle_pool_size<<
"\n";
757 out.width(indent+2); out<<
""; out<<
"_living_particles "<<_living_particles<<
"\n";
758 out.width(indent+2); out<<
""; out<<
"_tics_since_birth "<<_tics_since_birth<<
"\n";
759 out.width(indent+2); out<<
""; out<<
"_litter_size "<<_litter_size<<
"\n";
760 out.width(indent+2); out<<
""; out<<
"_litter_spread "<<_litter_spread<<
"\n";
761 out.width(indent+2); out<<
""; out<<
"_system_age "<<_system_age<<
"\n";
762 out.width(indent+2); out<<
""; out<<
"_system_lifespan "<<_system_lifespan<<
"\n";
763 out.width(indent+2); out<<
""; out<<
"_factory "<<_factory<<
"\n";
764 out.width(indent+2); out<<
""; out<<
"_emitter "<<_emitter<<
"\n";
765 out.width(indent+2); out<<
""; out<<
"_renderer "<<_renderer<<
"\n";
766 out.width(indent+2); out<<
""; out<<
"_manager "<<_manager<<
"\n";
767 out.width(indent+2); out<<
""; out<<
"_template_system_flag "<<_template_system_flag<<
"\n";
768 out.width(indent+2); out<<
""; out<<
"_render_parent "<<_render_parent<<
"\n";
769 out.width(indent+2); out<<
""; out<<
"_render_node "<<_render_node_path<<
"\n";
770 out.width(indent+2); out<<
""; out<<
"_active_system_flag "<<_active_system_flag<<
"\n";
771 out.width(indent+2); out<<
""; out<<
"_local_velocity_flag "<<_local_velocity_flag<<
"\n";
772 out.width(indent+2); out<<
""; out<<
"_system_grows_older_flag "<<_system_grows_older_flag<<
"\n";
773 out.width(indent+2); out<<
""; out<<
"_spawn_on_death_flag "<<_spawn_on_death_flag<<
"\n";
774 out.width(indent+2); out<<
""; out<<
"_spawn_render_node "<<_spawn_render_node_path<<
"\n";
775 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.
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.
Describes a curved space in which particles are generated.
~ParticleSystem()
You get the ankles and I'll get the wrists.
virtual void output(ostream &out) const
Write a string representation of this instance to <out>.
Creates point particles to user specs.
PandaNode * node() const
Returns the referenced node of the path.
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, int indent=0) const
Write a string representation of this instance to <out>.
Simple point/point particle renderer.
Defines a set of physically modeled attributes.
ParticleSystem(int pool_size=0)
Default Constructor.
A base class for all things that want to be reference-counted.
An individual, physically-modelable particle abstract base class.
virtual void write_spawn_templates(ostream &out, int indent=0) const
Write a string representation of this instance to <out>.
void remove_node(Thread *current_thread=Thread::get_current_thread())
Disconnects the referenced node from the scene graph.
void update(PN_stdfloat dt)
Updates the particle system.
virtual void write_free_particle_fifo(ostream &out, int indent=0) const
Write a string representation of this instance to <out>.
TypeHandle is the identifier used to differentiate C++ class types.
int get_num_parents(Thread *current_thread=Thread::get_current_thread()) const
Returns the number of parent nodes this node has.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
virtual void write(ostream &out=cout, unsigned int indent=0) const
Write a string representation of this instance to <out>.