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);
679 output(ostream &out)
const {
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";
An individual, physically-modelable particle abstract base class.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
void remove_node(Thread *current_thread=Thread::get_current_thread())
Disconnects the referenced node from the scene graph.
PandaNode * node() const
Returns the referenced node of the path.
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...
get_parent
Returns the NodePath to the parent of the referenced node: that is, this NodePath,...
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
A lightweight class that represents a single element that may be timed and/or counted via stats.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
A basic node of the scene graph or data graph.
get_num_parents
Returns the number of parent nodes this node has.
Contains and manages a particle system.
virtual void write(std::ostream &out, int indent=0) const
Write a string representation of this instance to <out>.
~ParticleSystem()
You get the ankles and I'll get the wrists.
virtual void write_free_particle_fifo(std::ostream &out, int indent=0) const
Write a string representation of this instance to <out>.
void update(PN_stdfloat dt)
Updates the particle system.
virtual void write_spawn_templates(std::ostream &out, int indent=0) const
Write a string representation of this instance to <out>.
ParticleSystem(int pool_size=0)
Default Constructor.
virtual void output(std::ostream &out) const
Write a string representation of this instance to <out>.
Graph node that encapsulated a series of physical objects.
Defines a set of physically modeled attributes.
void clear_physics_objects()
Erases the object list.
virtual void write(std::ostream &out=std::cout, int indent=0) const
Write a string representation of this instance to <out>.
void attach_physical(Physical *p)
Registers a Physical class with the manager.
get_position
Position Query.
set_active
Process Flag assignment.
set_velocity
Vector velocity assignment.
virtual LMatrix4 get_lcs() const
returns a transform matrix to this object's local coordinate system.
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...
Creates point particles to user specs.
Simple point/point particle renderer.
A base class for all things that want to be reference-counted.
Describes a curved space in which particles are generated.
TypeHandle is the identifier used to differentiate C++ class types.
This is our own Panda specialization on the default STL deque.
This is our own Panda specialization on the default STL vector.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.