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  */
88 ParticleSystem(const ParticleSystem& copy) :
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  */
121 ~ParticleSystem() {
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
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  */
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  */
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  */
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  */
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 }
An individual, physically-modelable particle abstract base class.
Definition: baseParticle.h:23
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
void remove_node(Thread *current_thread=Thread::get_current_thread())
Disconnects the referenced node from the scene graph.
Definition: nodePath.cxx:628
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:227
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:395
get_parent
Returns the NodePath to the parent of the referenced node: that is, this NodePath,...
Definition: nodePath.h:242
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
Definition: nodePath.cxx:795
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...
Definition: pStatTimer.h:30
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
get_num_parents
Returns the number of parent nodes this node has.
Definition: pandaNode.h:118
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.
Definition: physicalNode.h:28
Defines a set of physically modeled attributes.
Definition: physical.h:37
void clear_physics_objects()
Erases the object list.
Definition: physical.I:38
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 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...
Definition: physicsObject.I:46
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.
Indicates a coordinate-system transform on vertices.
get_mat
Returns the matrix that describes the transform.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
This is our own Panda specialization on the default STL deque.
Definition: pdeque.h:36
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
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.
Definition: indent.cxx:20
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.