39 PStatCollector ParticleSystem::_update_collector(
"App:Particles:Update");
49 _cur_birth_rate = _birth_rate;
50 _soft_birth_rate = HUGE_VAL;
51 _tics_since_birth = 0.0;
54 _living_particles = 0;
55 _active_system_flag =
true;
56 _local_velocity_flag =
true;
57 _spawn_on_death_flag =
false;
58 _system_grows_older_flag =
false;
59 _system_lifespan = 0.0f;
60 _i_was_spawned_flag =
false;
61 _particle_pool_size = 0;
71 _render_parent =
NodePath(
"ParticleSystem default render parent");
81 set_pool_size(pool_size);
91 _template_system_flag(false)
93 _birth_rate = copy._birth_rate;
94 _cur_birth_rate = copy._cur_birth_rate;
95 _litter_size = copy._litter_size;
96 _litter_spread = copy._litter_spread;
97 _active_system_flag = copy._active_system_flag;
98 _local_velocity_flag = copy._local_velocity_flag;
99 _spawn_on_death_flag = copy._spawn_on_death_flag;
100 _i_was_spawned_flag = copy._i_was_spawned_flag;
101 _system_grows_older_flag = copy._system_grows_older_flag;
102 _emitter = copy._emitter;
103 _renderer = copy._renderer->make_copy();
104 _factory = copy._factory;
106 _render_parent = copy._render_parent;
107 _render_node_path = _renderer->get_render_node_path();
110 _tics_since_birth = 0.0;
111 _system_lifespan = copy._system_lifespan;
112 _living_particles = 0;
114 set_pool_size(copy._particle_pool_size);
124 if (!_template_system_flag) {
134 bool ParticleSystem::
139 if (_living_particles >= _particle_pool_size) {
141 if (_living_particles > _particle_pool_size) {
142 cout <<
"_living_particles > _particle_pool_size" << endl;
149 if (0 == _free_particle_fifo.size()) {
150 cout <<
"Error: _free_particle_fifo is empty, but _living_particles < _particle_pool_size" << endl;
155 pool_index = _free_particle_fifo.back();
156 _free_particle_fifo.pop_back();
162 _factory->populate_particle(bp);
169 LPoint3 new_pos, world_pos;
172 _emitter->generate(new_pos, new_vel);
175 NodePath physical_np = get_physical_node_path();
176 NodePath render_np = _renderer->get_render_node_path();
179 const LMatrix4 &birth_to_render_xform = transform->
get_mat();
180 world_pos = new_pos * birth_to_render_xform;
185 if (_local_velocity_flag ==
false)
186 new_vel = new_vel * birth_to_render_xform;
194 _renderer->birth_particle(pool_index);
202 void ParticleSystem::
206 litter_size = _litter_size;
208 if (_litter_spread != 0)
209 litter_size += I_SPREAD(_litter_spread);
211 for (i = 0; i < litter_size; ++i) {
212 if (birth_particle() ==
false)
221 void ParticleSystem::
227 physics_cat.error() <<
"ParticleSystem::spawn_child_system: " 228 <<
"Spawning system is not in the scene graph," 229 <<
" aborting." << endl;
234 physics_cat.error() <<
"ParticleSystem::spawn_child_system: " 235 <<
"PhysicalNode this system is contained in " 236 <<
"has no parent, aborting." << endl;
240 if (_spawn_templates.size() == 0) {
241 physics_cat.error() <<
"ParticleSystem::spawn_child_system: " 242 <<
"no spawn templates present." << endl;
246 NodePath physical_np = get_physical_node_path();
252 int new_ps_index = rand() % _spawn_templates.size();
257 new_ps->_i_was_spawned_flag =
true;
260 new_ps->_render_parent = _spawn_render_node_path;
261 new_ps->_render_node_path = new_ps->_renderer->get_render_node_path();
262 new_ps->_render_node_path.
reparent_to(new_ps->_render_parent);
266 new_pn->add_physical(new_ps);
271 parent->add_child(new_pn);
274 const LMatrix4 &old_system_to_parent_xform = transform->
get_mat();
276 LMatrix4 child_space_xform = old_system_to_parent_xform *
279 new_pn->set_transform(TransformState::make_mat(child_space_xform));
282 _manager->attach_particlesystem(new_ps);
289 void ParticleSystem::
290 kill_particle(
int pool_index) {
295 if (_spawn_on_death_flag ==
true) {
296 spawn_child_system(bp);
300 bp->set_alive(
false);
304 _free_particle_fifo.push_back(pool_index);
307 _renderer->kill_particle(pool_index);
316 #define PARTICLE_SYSTEM_RESIZE_POOL_SENTRIES 318 void ParticleSystem::
319 resize_pool(
int size) {
321 int delta = size - _particle_pool_size;
322 int po_delta = _particle_pool_size - _physics_objects.size();
324 #ifdef PARTICLE_SYSTEM_RESIZE_POOL_SENTRIES 325 cout <<
"resizing particle pool from " << _particle_pool_size
326 <<
" to " << size << endl;
329 if (_factory.is_null()) {
330 particlesystem_cat.error() <<
"ParticleSystem::resize_pool" 331 <<
" called with null _factory." << endl;
335 if (_renderer.is_null()) {
336 particlesystem_cat.error() <<
"ParticleSystem::resize_pool" 337 <<
" called with null _renderer." << endl;
341 _particle_pool_size = size;
346 for (i = 0; i < po_delta; i++)
350 BaseParticle *new_particle = _factory->alloc_particle();
352 _factory->populate_particle(new_particle);
354 _physics_objects.push_back(new_particle);
357 cout <<
"Error allocating new particle" << endl;
358 _particle_pool_size--;
364 cout <<
"physics_object array is too large??" << endl;
365 _particle_pool_size--;
367 po_delta = -po_delta;
368 for (i = 0; i < po_delta; i++) {
369 int delete_index = _physics_objects.size()-1;
371 if (bp->get_alive()) {
372 kill_particle(delete_index);
373 _free_particle_fifo.pop_back();
376 i = find(_free_particle_fifo.begin(), _free_particle_fifo.end(), delete_index);
377 if (i != _free_particle_fifo.end()) {
378 _free_particle_fifo.erase(i);
381 _physics_objects.pop_back();
393 for (i = 0; i < delta; i++)
395 int free_index = _physics_objects.size();
397 BaseParticle *new_particle = _factory->alloc_particle();
399 _factory->populate_particle(new_particle);
401 _physics_objects.push_back(new_particle);
402 _free_particle_fifo.push_back(free_index);
405 cout <<
"Error allocating new particle" << endl;
406 _particle_pool_size--;
413 for (i = 0; i < delta; i++) {
414 int delete_index = _physics_objects.size()-1;
417 if (bp->get_alive()) {
419 cout <<
"WAS ALIVE" << endl;
421 kill_particle(delete_index);
422 _free_particle_fifo.pop_back();
425 cout <<
"WAS NOT ALIVE" << endl;
428 i = find(_free_particle_fifo.begin(), _free_particle_fifo.end(), delete_index);
429 if (i != _free_particle_fifo.end()) {
430 _free_particle_fifo.erase(i);
434 cout <<
"particle not found in free FIFO!!!!!!!!" << endl;
439 _physics_objects.pop_back();
443 _renderer->resize_pool(_particle_pool_size);
445 #ifdef PARTICLE_SYSTEM_RESIZE_POOL_SENTRIES 446 cout <<
"particle pool resized" << endl;
460 int ttl_updates_left = _living_particles;
461 int current_index = 0, index_counter = 0;
467 if (sanity_check())
return;
470 #ifdef PARTICLE_SYSTEM_UPDATE_SENTRIES 471 cout <<
"UPDATE: pool size: " << _particle_pool_size
472 <<
", live particles: " << _living_particles << endl;
476 while (ttl_updates_left) {
477 current_index = index_counter;
481 if (current_index >= _particle_pool_size) {
482 cout <<
"ERROR: _living_particles is out of sync (too large)" << endl;
483 cout <<
"pool size: " << _particle_pool_size
484 <<
", live particles: " << _living_particles
485 <<
", updates left: " << ttl_updates_left << endl;
491 bp = (
BaseParticle *) _physics_objects[current_index].p();
495 cout <<
"NULL ptr at index " << current_index << endl;
500 if (bp->get_alive() ==
false)
503 age = bp->get_age() + dt;
508 if (age >= bp->get_lifespan()) {
509 kill_particle(current_index);
510 }
else if (get_floor_z() != -HUGE_VAL
514 kill_particle(current_index);
525 _tics_since_birth += dt;
527 while (_tics_since_birth >= _cur_birth_rate) {
529 _tics_since_birth -= _cur_birth_rate;
532 #ifdef PARTICLE_SYSTEM_UPDATE_SENTRIES 533 cout <<
"particle update complete" << endl;
551 SC_valuenamepair(
int v,
char *s) : value(v), name(s) {}
555 static int check_free_live_total_particles(
pvector< PT(SC_valuenamepair) > live_counts,
556 pvector< PT(SC_valuenamepair) > dead_counts,
pvector< PT(SC_valuenamepair) > total_counts,
562 for(l = 0; l < live_counts.size(); l++) {
563 for(d = 0; d < dead_counts.size(); d++) {
564 for(t = 0; t < total_counts.size(); t++) {
565 int live = live_counts[l]->value;
566 int dead = dead_counts[d]->value;
567 int total = total_counts[t]->value;
568 if ((live + dead) != total) {
570 cout <<
"free/live/total count: " 571 << live_counts[l]->name <<
" (" << live <<
") + " 572 << dead_counts[d]->name <<
" (" << dead <<
") = " 573 << live + dead <<
", != " 574 << total_counts[t]->name <<
" (" << total <<
")" 594 if (_particle_pool_size != _physics_objects.size()) {
596 cout <<
"_particle_pool_size (" << _particle_pool_size
597 <<
") != particle array size (" << _physics_objects.size() <<
")" << endl;
601 pool_size = std::min(_particle_pool_size, _physics_objects.size());
604 int real_live_particle_count = 0;
605 int real_dead_particle_count = 0;
607 for (i = 0; i < _physics_objects.size(); i++) {
609 if (
true == bp->get_alive()) {
610 real_live_particle_count++;
612 real_dead_particle_count++;
616 if (real_live_particle_count != _living_particles) {
618 cout <<
"manually counted live particle count (" << real_live_particle_count
619 <<
") != _living_particles (" << _living_particles <<
")" << endl;
624 if (real_dead_particle_count != _free_particle_fifo.size()) {
626 cout <<
"manually counted dead particle count (" << real_dead_particle_count
627 <<
") != free particle fifo size (" << _free_particle_fifo.size() <<
")" << endl;
633 for (i = 0; i < _free_particle_fifo.size(); i++) {
634 int index = _free_particle_fifo[i];
637 if (index >= pool_size) {
639 cout <<
"index from free particle fifo (" << index
640 <<
") is too large; pool size is " << pool_size << endl;
648 if (
true == bp->get_alive()) {
650 cout <<
"particle " << index <<
" in free fifo is not dead" << endl;
657 pvector< PT(SC_valuenamepair) > live_counts;
658 pvector< PT(SC_valuenamepair) > dead_counts;
659 pvector< PT(SC_valuenamepair) > total_counts;
661 live_counts.push_back(
new SC_valuenamepair(real_live_particle_count,
"real_live_particle_count"));
663 dead_counts.push_back(
new SC_valuenamepair(real_dead_particle_count,
"real_dead_particle_count"));
664 dead_counts.push_back(
new SC_valuenamepair(_free_particle_fifo.size(),
"free particle fifo size"));
666 total_counts.push_back(
new SC_valuenamepair(_particle_pool_size,
"_particle_pool_size"));
667 total_counts.push_back(
new SC_valuenamepair(_physics_objects.size(),
"actual particle pool size"));
669 result += check_free_live_total_particles(live_counts, dead_counts, total_counts);
681 out<<
"ParticleSystem";
692 out<<
""<<
"_free_particle_fifo ("<<_free_particle_fifo.size()<<
" forces)\n";
694 i != _free_particle_fifo.end();
696 out.width(
indent+2); out<<
""; out<<(*i)<<
"\n";
708 out<<
""<<
"_spawn_templates ("<<_spawn_templates.size()<<
" templates)\n";
710 i != _spawn_templates.end();
712 (*i)->write(out,
indent+2);
723 out.width(
indent); out<<
""; out<<
"ParticleSystem:\n";
724 out.width(
indent+2); out<<
""; out<<
"_particle_pool_size "<<_particle_pool_size<<
"\n";
725 out.width(
indent+2); out<<
""; out<<
"_living_particles "<<_living_particles<<
"\n";
726 out.width(
indent+2); out<<
""; out<<
"_tics_since_birth "<<_tics_since_birth<<
"\n";
727 out.width(
indent+2); out<<
""; out<<
"_litter_size "<<_litter_size<<
"\n";
728 out.width(
indent+2); out<<
""; out<<
"_litter_spread "<<_litter_spread<<
"\n";
729 out.width(
indent+2); out<<
""; out<<
"_system_age "<<_system_age<<
"\n";
730 out.width(
indent+2); out<<
""; out<<
"_system_lifespan "<<_system_lifespan<<
"\n";
731 out.width(
indent+2); out<<
""; out<<
"_factory "<<_factory<<
"\n";
732 out.width(
indent+2); out<<
""; out<<
"_emitter "<<_emitter<<
"\n";
733 out.width(
indent+2); out<<
""; out<<
"_renderer "<<_renderer<<
"\n";
734 out.width(
indent+2); out<<
""; out<<
"_manager "<<_manager<<
"\n";
735 out.width(
indent+2); out<<
""; out<<
"_template_system_flag "<<_template_system_flag<<
"\n";
736 out.width(
indent+2); out<<
""; out<<
"_render_parent "<<_render_parent<<
"\n";
737 out.width(
indent+2); out<<
""; out<<
"_render_node "<<_render_node_path<<
"\n";
738 out.width(
indent+2); out<<
""; out<<
"_active_system_flag "<<_active_system_flag<<
"\n";
739 out.width(
indent+2); out<<
""; out<<
"_local_velocity_flag "<<_local_velocity_flag<<
"\n";
740 out.width(
indent+2); out<<
""; out<<
"_system_grows_older_flag "<<_system_grows_older_flag<<
"\n";
741 out.width(
indent+2); out<<
""; out<<
"_spawn_on_death_flag "<<_spawn_on_death_flag<<
"\n";
742 out.width(
indent+2); out<<
""; out<<
"_spawn_render_node "<<_spawn_render_node_path<<
"\n";
743 out.width(
indent+2); out<<
""; out<<
"_i_was_spawned_flag "<<_i_was_spawned_flag<<
"\n";
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void write_spawn_templates(std::ostream &out, int indent=0) const
Write a string representation of this instance to <out>.
A basic node of the scene graph or data graph.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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 output(std::ostream &out) const
Write a string representation of this instance to <out>.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_num_parents
Returns the number of parent nodes this node has.
Describes a curved space in which particles are generated.
~ParticleSystem()
You get the ankles and I'll get the wrists.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
get_parent
Returns the NodePath to the parent of the referenced node: that is, this NodePath,...
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void write(std::ostream &out, int indent=0) const
Write a string representation of this instance to <out>.
This is our own Panda specialization on the default STL deque.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void write_free_particle_fifo(std::ostream &out, int indent=0) const
Write a string representation of this instance to <out>.
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...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Simple point/point particle renderer.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
LPoint3 get_position() const
Position Query.
virtual void write(std::ostream &out=std::cout, int indent=0) const
Write a string representation of this instance to <out>.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.