Panda3D
Loading...
Searching...
No Matches
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
26#include "particleSystem.h"
31#include "pStatTimer.h"
32
33using std::cout;
34using std::endl;
35using std::ostream;
36
37TypeHandle ParticleSystem::_type_handle;
38
39PStatCollector ParticleSystem::_update_collector("App:Particles:Update");
40
41/**
42 * Default Constructor.
43 */
45ParticleSystem(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 */
88ParticleSystem(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 */
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 */
134bool ParticleSystem::
135birth_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 */
202void ParticleSystem::
203birth_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 */
221void ParticleSystem::
222spawn_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 */
289void ParticleSystem::
290kill_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
318void ParticleSystem::
319resize_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 {
375 pdeque<int>::iterator i;
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
427 pdeque<int>::iterator i;
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
457update(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
547class SC_valuenamepair : public ReferenceCount {
548public:
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
555static 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
586int ParticleSystem::
587sanity_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 */
679output(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 */
689write_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 */
705write_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 */
721write(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.
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:627
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:394
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:794
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.
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...
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.