Panda3D
particleSystem.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file particleSystem.cxx
10  * @author charles
11  * @date 2000-06-14
12  */
13 
14 #include <stdlib.h>
15 
16 #include "luse.h"
17 #include "lmat_ops.h"
18 #include "clockObject.h"
19 #include "physicsManager.h"
20 #include "physicalNode.h"
21 #include "nearly_zero.h"
22 #include "transformState.h"
23 #include "nodePath.h"
24 
25 #include "config_particlesystem.h"
26 #include "particleSystem.h"
27 #include "particleSystemManager.h"
28 #include "pointParticleRenderer.h"
29 #include "pointParticleFactory.h"
30 #include "sphereSurfaceEmitter.h"
31 #include "pStatTimer.h"
32 
33 using std::cout;
34 using std::endl;
35 using std::ostream;
36 
37 TypeHandle ParticleSystem::_type_handle;
38 
39 PStatCollector ParticleSystem::_update_collector("App:Particles:Update");
40 
41 /**
42  * Default Constructor.
43  */
45 ParticleSystem(int pool_size) :
46  Physical(pool_size, false)
47 {
48  _birth_rate = 0.5f;
49  _cur_birth_rate = _birth_rate;
50  _soft_birth_rate = HUGE_VAL;
51  _tics_since_birth = 0.0;
52  _litter_size = 1;
53  _litter_spread = 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;
62  _floor_z = -HUGE_VAL;
63 
64  // just in case someone tries to do something that requires the use of an
65  // emitter, renderer, or factory before they've actually assigned one. This
66  // is ok, because assigning them (set_renderer(), set_emitter(), etc...)
67  // forces them to set themselves up for the system, keeping the pool sizes
68  // consistent.
69 
70  _render_node_path = NodePath();
71  _render_parent = NodePath("ParticleSystem default render parent");
72 
73  set_emitter(new SphereSurfaceEmitter);
74 
75  set_renderer(new PointParticleRenderer);
76 
77  // set_factory(new PointParticleFactory);
78  _factory = new PointParticleFactory;
80 
81  set_pool_size(pool_size);
82 }
83 
84 /**
85  * Copy Constructor.
86  */
89  Physical(copy),
90  _system_age(0.0f),
91  _template_system_flag(false)
92 {
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;
105 
106  _render_parent = copy._render_parent;
107  _render_node_path = _renderer->get_render_node_path();
108  _render_node_path.reparent_to(_render_parent);
109 
110  _tics_since_birth = 0.0;
111  _system_lifespan = copy._system_lifespan;
112  _living_particles = 0;
113 
114  set_pool_size(copy._particle_pool_size);
115 }
116 
117 /**
118  * You get the ankles and I'll get the wrists.
119  */
122  set_pool_size(0);
123 
124  if (!_template_system_flag) {
125  _renderer.clear();
126  _render_node_path.remove_node();
127  }
128 }
129 
130 /**
131  * A new particle is born. This doesn't allocate, resets an element from the
132  * particle pool.
133  */
134 bool ParticleSystem::
135 birth_particle() {
136  int pool_index;
137 
138  // make sure there's room for a new particle
139  if (_living_particles >= _particle_pool_size) {
140  #ifdef PSDEBUG
141  if (_living_particles > _particle_pool_size) {
142  cout << "_living_particles > _particle_pool_size" << endl;
143  }
144  #endif
145  return false;
146  }
147 
148  #ifdef PSDEBUG
149  if (0 == _free_particle_fifo.size()) {
150  cout << "Error: _free_particle_fifo is empty, but _living_particles < _particle_pool_size" << endl;
151  return false;
152  }
153  #endif
154 
155  pool_index = _free_particle_fifo.back();
156  _free_particle_fifo.pop_back();
157 
158  // get a handle on our particle.
159  BaseParticle *bp = (BaseParticle *) _physics_objects[pool_index].p();
160 
161  // start filling out the variables.
162  _factory->populate_particle(bp);
163 
164  bp->set_alive(true);
165  bp->set_active(true);
166  bp->init();
167 
168  // get the location of the new particle.
169  LPoint3 new_pos, world_pos;
170  LVector3 new_vel;
171 
172  _emitter->generate(new_pos, new_vel);
173 
174  // go from birth space to render space
175  NodePath physical_np = get_physical_node_path();
176  NodePath render_np = _renderer->get_render_node_path();
177 
178  CPT(TransformState) transform = physical_np.get_transform(render_np);
179  const LMatrix4 &birth_to_render_xform = transform->get_mat();
180  world_pos = new_pos * birth_to_render_xform;
181 
182  // cout << "New particle at " << world_pos << endl;
183 
184  // possibly transform the initial velocity as well.
185  if (_local_velocity_flag == false)
186  new_vel = new_vel * birth_to_render_xform;
187 
188  bp->reset_position(world_pos/* + (NORMALIZED_RAND() * new_vel)*/);
189  bp->set_velocity(new_vel);
190 
191  ++_living_particles;
192 
193  // propogate information down to renderer
194  _renderer->birth_particle(pool_index);
195 
196  return true;
197 }
198 
199 /**
200  * spawns a new batch of particles
201  */
202 void ParticleSystem::
203 birth_litter() {
204  int litter_size, i;
205 
206  litter_size = _litter_size;
207 
208  if (_litter_spread != 0)
209  litter_size += I_SPREAD(_litter_spread);
210 
211  for (i = 0; i < litter_size; ++i) {
212  if (birth_particle() == false)
213  return;
214  }
215 }
216 
217 /**
218  * Creates a new particle system based on local template info and adds it to
219  * the ps and physics managers
220  */
221 void ParticleSystem::
222 spawn_child_system(BaseParticle *bp) {
223  // first, make sure that the system exists in the graph via a physicalnode
224  // reference.
225  PhysicalNode *this_pn = get_physical_node();
226  if (!this_pn) {
227  physics_cat.error() << "ParticleSystem::spawn_child_system: "
228  << "Spawning system is not in the scene graph,"
229  << " aborting." << endl;
230  return;
231  }
232 
233  if (this_pn->get_num_parents() == 0) {
234  physics_cat.error() << "ParticleSystem::spawn_child_system: "
235  << "PhysicalNode this system is contained in "
236  << "has no parent, aborting." << endl;
237  return;
238  }
239 
240  if (_spawn_templates.size() == 0) {
241  physics_cat.error() << "ParticleSystem::spawn_child_system: "
242  << "no spawn templates present." << endl;
243  return;
244  }
245 
246  NodePath physical_np = get_physical_node_path();
247  NodePath parent_np = physical_np.get_parent();
248 
249  PandaNode *parent = parent_np.node();
250 
251  // handle the spawn templates
252  int new_ps_index = rand() % _spawn_templates.size();
253  ParticleSystem *ps_template = _spawn_templates[new_ps_index];
254 
255  // create a new particle system
256  PT(ParticleSystem) new_ps = new ParticleSystem(*ps_template);
257  new_ps->_i_was_spawned_flag = true;
258 
259  // first, set up the render node info.
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);
263 
264  // now set up the new system's PhysicalNode.
265  PT(PhysicalNode) new_pn = new PhysicalNode("new_pn");
266  new_pn->add_physical(new_ps);
267 
268  // the transform on the new child has to represent the transform from the
269  // current system up to its parent, and then subsequently down to the new
270  // child.
271  parent->add_child(new_pn);
272 
273  CPT(TransformState) transform = physical_np.get_transform(parent_np);
274  const LMatrix4 &old_system_to_parent_xform = transform->get_mat();
275 
276  LMatrix4 child_space_xform = old_system_to_parent_xform *
277  bp->get_lcs();
278 
279  new_pn->set_transform(TransformState::make_mat(child_space_xform));
280 
281  // tack the new system onto the managers
282  _manager->attach_particlesystem(new_ps);
283  get_physics_manager()->attach_physical(new_ps);
284 }
285 
286 /**
287  * Kills a particle, returns its slot to the empty stack.
288  */
289 void ParticleSystem::
290 kill_particle(int pool_index) {
291  // get a handle on our particle
292  BaseParticle *bp = (BaseParticle *) _physics_objects[pool_index].p();
293 
294  // create a new system where this one died, maybe.
295  if (_spawn_on_death_flag == true) {
296  spawn_child_system(bp);
297  }
298 
299  // tell everyone that it's dead
300  bp->set_alive(false);
301  bp->set_active(false);
302  bp->die();
303 
304  _free_particle_fifo.push_back(pool_index);
305 
306  // tell renderer
307  _renderer->kill_particle(pool_index);
308 
309  _living_particles--;
310 }
311 
312 /**
313  * Resizes the particle pool
314  */
315 #ifdef PSDEBUG
316 #define PARTICLE_SYSTEM_RESIZE_POOL_SENTRIES
317 #endif
318 void ParticleSystem::
319 resize_pool(int size) {
320  int i;
321  int delta = size - _particle_pool_size;
322  int po_delta = _particle_pool_size - _physics_objects.size();
323 
324  #ifdef PARTICLE_SYSTEM_RESIZE_POOL_SENTRIES
325  cout << "resizing particle pool from " << _particle_pool_size
326  << " to " << size << endl;
327  #endif
328 
329  if (_factory.is_null()) {
330  particlesystem_cat.error() << "ParticleSystem::resize_pool"
331  << " called with null _factory." << endl;
332  return;
333  }
334 
335  if (_renderer.is_null()) {
336  particlesystem_cat.error() << "ParticleSystem::resize_pool"
337  << " called with null _renderer." << endl;
338  return;
339  }
340 
341  _particle_pool_size = size;
342 
343  // make sure the physics_objects array is OK
344  if (po_delta) {
345  if (po_delta > 0) {
346  for (i = 0; i < po_delta; i++)
347  {
348  // int free_index = _physics_objects.size();
349 
350  BaseParticle *new_particle = _factory->alloc_particle();
351  if (new_particle) {
352  _factory->populate_particle(new_particle);
353 
354  _physics_objects.push_back(new_particle);
355  } else {
356  #ifdef PSDEBUG
357  cout << "Error allocating new particle" << endl;
358  _particle_pool_size--;
359  #endif
360  }
361  }
362  } else {
363  #ifdef PSDEBUG
364  cout << "physics_object array is too large??" << endl;
365  _particle_pool_size--;
366  #endif
367  po_delta = -po_delta;
368  for (i = 0; i < po_delta; i++) {
369  int delete_index = _physics_objects.size()-1;
370  BaseParticle *bp = (BaseParticle *) _physics_objects[delete_index].p();
371  if (bp->get_alive()) {
372  kill_particle(delete_index);
373  _free_particle_fifo.pop_back();
374  } else {
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);
379  }
380  }
381  _physics_objects.pop_back();
382  }
383  }
384  }
385 
386  // disregard no change
387  if (delta == 0)
388  return;
389 
390  // update the pool
391  if (delta > 0) {
392  // add elements
393  for (i = 0; i < delta; i++)
394  {
395  int free_index = _physics_objects.size();
396 
397  BaseParticle *new_particle = _factory->alloc_particle();
398  if (new_particle) {
399  _factory->populate_particle(new_particle);
400 
401  _physics_objects.push_back(new_particle);
402  _free_particle_fifo.push_back(free_index);
403  } else {
404  #ifdef PSDEBUG
405  cout << "Error allocating new particle" << endl;
406  _particle_pool_size--;
407  #endif
408  }
409  }
410  } else {
411  // subtract elements
412  delta = -delta;
413  for (i = 0; i < delta; i++) {
414  int delete_index = _physics_objects.size()-1;
415  BaseParticle *bp = (BaseParticle *) _physics_objects[delete_index].p();
416 
417  if (bp->get_alive()) {
418  #ifdef PSDEBUG
419  cout << "WAS ALIVE" << endl;
420  #endif
421  kill_particle(delete_index);
422  _free_particle_fifo.pop_back();
423  } else {
424  #ifdef PSDEBUG
425  cout << "WAS NOT ALIVE" << endl;
426  #endif
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);
431  }
432  #ifdef PSDEBUG
433  else {
434  cout << "particle not found in free FIFO!!!!!!!!" << endl;
435  }
436  #endif
437  }
438 
439  _physics_objects.pop_back();
440  }
441  }
442 
443  _renderer->resize_pool(_particle_pool_size);
444 
445  #ifdef PARTICLE_SYSTEM_RESIZE_POOL_SENTRIES
446  cout << "particle pool resized" << endl;
447  #endif
448 }
449 
450 /**
451  * Updates the particle system. Call once per frame.
452  */
453 #ifdef PSDEBUG
454 // #define PARTICLE_SYSTEM_UPDATE_SENTRIES
455 #endif
456 void ParticleSystem::
457 update(PN_stdfloat dt) {
458  PStatTimer t1(_update_collector);
459 
460  int ttl_updates_left = _living_particles;
461  int current_index = 0, index_counter = 0;
462  BaseParticle *bp;
463  PN_stdfloat age;
464 
465  #ifdef PSSANITYCHECK
466  // check up on things
467  if (sanity_check()) return;
468  #endif
469 
470  #ifdef PARTICLE_SYSTEM_UPDATE_SENTRIES
471  cout << "UPDATE: pool size: " << _particle_pool_size
472  << ", live particles: " << _living_particles << endl;
473  #endif
474 
475  // run through the particle array
476  while (ttl_updates_left) {
477  current_index = index_counter;
478  index_counter++;
479 
480  #ifdef PSDEBUG
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;
486  break;
487  }
488  #endif
489 
490  // get the current particle.
491  bp = (BaseParticle *) _physics_objects[current_index].p();
492 
493  #ifdef PSDEBUG
494  if (!bp) {
495  cout << "NULL ptr at index " << current_index << endl;
496  continue;
497  }
498  #endif
499 
500  if (bp->get_alive() == false)
501  continue;
502 
503  age = bp->get_age() + dt;
504  bp->set_age(age);
505 
506  // cerr<<"bp->get_position().get_z() returning
507  // "<<bp->get_position().get_z()<<endl;
508  if (age >= bp->get_lifespan()) {
509  kill_particle(current_index);
510  } else if (get_floor_z() != -HUGE_VAL
511  && bp->get_position().get_z() <= get_floor_z()) {
512  // ...the particle is going under the floor. Maybe tell the particle to
513  // bounce: bp->bounce()?
514  kill_particle(current_index);
515  } else {
516  bp->update();
517  }
518 
519  // break out early if we're lucky
520  ttl_updates_left--;
521  }
522 
523 
524  // generate new particles if necessary.
525  _tics_since_birth += dt;
526 
527  while (_tics_since_birth >= _cur_birth_rate) {
528  birth_litter();
529  _tics_since_birth -= _cur_birth_rate;
530  }
531 
532  #ifdef PARTICLE_SYSTEM_UPDATE_SENTRIES
533  cout << "particle update complete" << endl;
534  #endif
535 
536 }
537 
538 #ifdef PSSANITYCHECK
539 /**
540  * Checks consistency of live particle count, free particle list, etc.
541  * returns 0 if everything is normal
542  */
543 #ifndef NDEBUG
544 #define PSSCVERBOSE
545 #endif
546 
547 class SC_valuenamepair : public ReferenceCount {
548 public:
549  int value;
550  char *name;
551  SC_valuenamepair(int v, char *s) : value(v), name(s) {}
552 };
553 
554 // returns 0 if OK, # of errors if not OK
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,
557  int print_all = 0) {
558 
559  int val = 0;
560  int l, d, t;
561 
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) {
569  #ifdef PSSCVERBOSE
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 << ")"
575  << endl;
576  #endif
577  val++;
578  }
579  }
580  }
581  }
582 
583  return val;
584 }
585 
586 int ParticleSystem::
587 sanity_check() {
588  int result = 0;
589  int i;
590  BaseParticle *bp;
591  int pool_size;
592 
593  // check pool size
594  if (_particle_pool_size != _physics_objects.size()) {
595  #ifdef PSSCVERBOSE
596  cout << "_particle_pool_size (" << _particle_pool_size
597  << ") != particle array size (" << _physics_objects.size() << ")" << endl;
598  #endif
599  result++;
600  }
601  pool_size = std::min(_particle_pool_size, _physics_objects.size());
602 
603  // find out how many particles are REALLY alive and dead
604  int real_live_particle_count = 0;
605  int real_dead_particle_count = 0;
606 
607  for (i = 0; i < _physics_objects.size(); i++) {
608  bp = (BaseParticle *) _physics_objects[i].p();
609  if (true == bp->get_alive()) {
610  real_live_particle_count++;
611  } else {
612  real_dead_particle_count++;
613  }
614  }
615 
616  if (real_live_particle_count != _living_particles) {
617  #ifdef PSSCVERBOSE
618  cout << "manually counted live particle count (" << real_live_particle_count
619  << ") != _living_particles (" << _living_particles << ")" << endl;
620  #endif
621  result++;
622  }
623 
624  if (real_dead_particle_count != _free_particle_fifo.size()) {
625  #ifdef PSSCVERBOSE
626  cout << "manually counted dead particle count (" << real_dead_particle_count
627  << ") != free particle fifo size (" << _free_particle_fifo.size() << ")" << endl;
628  #endif
629  result++;
630  }
631 
632  // check the free particle pool
633  for (i = 0; i < _free_particle_fifo.size(); i++) {
634  int index = _free_particle_fifo[i];
635 
636  // check that we're in bounds
637  if (index >= pool_size) {
638  #ifdef PSSCVERBOSE
639  cout << "index from free particle fifo (" << index
640  << ") is too large; pool size is " << pool_size << endl;
641  #endif
642  result++;
643  continue;
644  }
645 
646  // check that the particle is indeed dead
647  bp = (BaseParticle *) _physics_objects[index].p();
648  if (true == bp->get_alive()) {
649  #ifdef PSSCVERBOSE
650  cout << "particle " << index << " in free fifo is not dead" << endl;
651  #endif
652  result++;
653  }
654  }
655 
656  // check the numbers of free particles, live particles, and total particles
657  pvector< PT(SC_valuenamepair) > live_counts;
658  pvector< PT(SC_valuenamepair) > dead_counts;
659  pvector< PT(SC_valuenamepair) > total_counts;
660 
661  live_counts.push_back(new SC_valuenamepair(real_live_particle_count, "real_live_particle_count"));
662 
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"));
665 
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"));
668 
669  result += check_free_live_total_particles(live_counts, dead_counts, total_counts);
670 
671  return result;
672 }
673 #endif
674 
675 /**
676  * Write a string representation of this instance to <out>.
677  */
678 void ParticleSystem::
679 output(ostream &out) const {
680  #ifndef NDEBUG //[
681  out<<"ParticleSystem";
682  #endif //] NDEBUG
683 }
684 
685 /**
686  * Write a string representation of this instance to <out>.
687  */
688 void ParticleSystem::
689 write_free_particle_fifo(ostream &out, int indent) const {
690  #ifndef NDEBUG //[
691  out.width(indent);
692  out<<""<<"_free_particle_fifo ("<<_free_particle_fifo.size()<<" forces)\n";
693  for (pdeque< int >::const_iterator i=_free_particle_fifo.begin();
694  i != _free_particle_fifo.end();
695  ++i) {
696  out.width(indent+2); out<<""; out<<(*i)<<"\n";
697  }
698  #endif //] NDEBUG
699 }
700 
701 /**
702  * Write a string representation of this instance to <out>.
703  */
704 void ParticleSystem::
705 write_spawn_templates(ostream &out, int indent) const {
706  #ifndef NDEBUG //[
707  out.width(indent);
708  out<<""<<"_spawn_templates ("<<_spawn_templates.size()<<" templates)\n";
709  for (pvector< PT(ParticleSystem) >::const_iterator i=_spawn_templates.begin();
710  i != _spawn_templates.end();
711  ++i) {
712  (*i)->write(out, indent+2);
713  }
714  #endif //] NDEBUG
715 }
716 
717 /**
718  * Write a string representation of this instance to <out>.
719  */
720 void ParticleSystem::
721 write(ostream &out, int indent) const {
722  #ifndef NDEBUG //[
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";
746  Physical::write(out, indent+2);
747  #endif //] NDEBUG
748 }
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.
Definition: pandaNode.h:64
Indicates a coordinate-system transform on vertices.
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...
Definition: physicsObject.I:46
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.
Definition: pandaNode.h:118
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.
Definition: physicsObject.I:75
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.
Definition: physical.I:38
get_parent
Returns the NodePath to the parent of the referenced node: that is, this NodePath,...
Definition: nodePath.h:244
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:30
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
Definition: pdeque.h:36
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_mat
Returns the matrix that describes the transform.
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.
Definition: pvector.h:42
Graph node that encapsulated a series of physical objects.
Definition: physicalNode.h:28
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...
Definition: nodePath.cxx:391
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
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.
Definition: physical.h:37
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.
Definition: nodePath.I:227
An individual, physically-modelable particle abstract base class.
Definition: baseParticle.h:23
void remove_node(Thread *current_thread=Thread::get_current_thread())
Disconnects the referenced node from the scene graph.
Definition: nodePath.cxx:591
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>.
Definition: physical.cxx:187
void update(PN_stdfloat dt)
Updates the particle system.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
Definition: nodePath.cxx:758
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:161
virtual LMatrix4 get_lcs() const
returns a transform matrix to this object's local coordinate system.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.