Panda3D

collisionSolid.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 collisionSolid.cxx
10 * @author drose
11 * @date 2000-04-24
12 */
13
14 #include "collisionSolid.h"
15 #include "config_collide.h"
16 #include "collisionSphere.h"
17 #include "collisionLine.h"
18 #include "collisionRay.h"
19 #include "collisionSegment.h"
20 #include "collisionCapsule.h"
21 #include "collisionParabola.h"
22 #include "collisionBox.h"
23 #include "collisionEntry.h"
24 #include "boundingSphere.h"
25 #include "datagram.h"
26 #include "datagramIterator.h"
27 #include "bamReader.h"
28 #include "bamWriter.h"
29 #include "indent.h"
30 #include "cullFaceAttrib.h"
31 #include "colorAttrib.h"
32 #include "renderModeAttrib.h"
33 #include "transparencyAttrib.h"
34 #include "geomNode.h"
35
36 PStatCollector CollisionSolid::_volume_pcollector(
37 "Collision Volumes:CollisionSolid");
38 PStatCollector CollisionSolid::_test_pcollector(
39 "Collision Tests:CollisionSolid");
40 TypeHandle CollisionSolid::_type_handle;
41
42 /**
43 *
44 */
45 CollisionSolid::
46 CollisionSolid() : _lock("CollisionSolid") {
47 _flags = F_viz_geom_stale | F_tangible | F_internal_bounds_stale;
48 }
49
50 /**
51 *
52 */
53 CollisionSolid::
54 CollisionSolid(const CollisionSolid &copy) :
55 CopyOnWriteObject(copy),
56 _effective_normal(copy._effective_normal),
57 _internal_bounds(copy._internal_bounds),
58 _flags(copy._flags),
59 _lock("CollisionSolid")
60 {
61 _flags |= F_viz_geom_stale;
62 }
63
64 /**
65 *
66 */
67 CollisionSolid::
68 ~CollisionSolid() {
69 }
70
71 /**
72 * Required to implement CopyOnWriteObject.
73 */
74 PT(CopyOnWriteObject) CollisionSolid::
75 make_cow_copy() {
76 return make_copy();
77 }
78
79 /**
80 * Returns the solid's bounding volume.
81 */
82 CPT(BoundingVolume) CollisionSolid::
83 get_bounds() const {
84 LightMutexHolder holder(_lock);
85 if (_flags & F_internal_bounds_stale) {
86 ((CollisionSolid *)this)->_internal_bounds = compute_internal_bounds();
87 ((CollisionSolid *)this)->_flags &= ~F_internal_bounds_stale;
88 }
89 return _internal_bounds;
90 }
91
92 /**
93 * Returns the solid's bounding volume.
94 */
95 void CollisionSolid::
96 set_bounds(const BoundingVolume &bounding_volume) {
97 LightMutexHolder holder(_lock);
98 ((CollisionSolid *)this)->_internal_bounds = bounding_volume.make_copy();
99 ((CollisionSolid *)this)->_flags &= ~F_internal_bounds_stale;
100 }
101
102 /**
103 * Tests for a collision between this object (which is also the "from" object
104 * in the entry) and the "into" object. If a collision is detected, returns a
105 * new CollisionEntry object that records the collision; otherwise, returns
106 * NULL.
107 */
108 PT(CollisionEntry) CollisionSolid::
109 test_intersection(const CollisionEntry &) const {
110 report_undefined_from_intersection(get_type());
111 return nullptr;
112 }
113
114 /**
115 * Transforms the solid by the indicated matrix.
116 */
117 void CollisionSolid::
118 xform(const LMatrix4 &mat) {
119 LightMutexHolder holder(_lock);
120 if ((_flags & F_effective_normal) != 0) {
121 _effective_normal = _effective_normal * mat;
122 _effective_normal.normalize();
123 }
124
125 _flags |= F_viz_geom_stale | F_internal_bounds_stale;
126 }
127
128 /**
129 * Returns a GeomNode that may be rendered to visualize the CollisionSolid.
130 * This is used during the cull traversal to render the CollisionNodes that
131 * have been made visible.
132 */
133 PT(PandaNode) CollisionSolid::
134 get_viz(const CullTraverser *, const CullTraverserData &, bool bounds_only) const {
135 LightMutexHolder holder(_lock);
136 if ((_flags & F_viz_geom_stale) != 0) {
137 if (_viz_geom == nullptr) {
138 ((CollisionSolid *)this)->_viz_geom = new GeomNode("viz");
139 ((CollisionSolid *)this)->_bounds_viz_geom = new GeomNode("bounds_viz");
140 } else {
141 _viz_geom->remove_all_geoms();
142 _bounds_viz_geom->remove_all_geoms();
143 }
144 ((CollisionSolid *)this)->fill_viz_geom();
145 ((CollisionSolid *)this)->_flags &= ~F_viz_geom_stale;
146 }
147
148 if (bounds_only) {
149 return _bounds_viz_geom;
150 } else {
151 return _viz_geom;
152 }
153 }
154
155 /**
156 * Returns a PStatCollector that is used to count the number of bounding
157 * volume tests made against a solid of this type in a given frame.
158 */
159 PStatCollector &CollisionSolid::
160 get_volume_pcollector() {
161 return _volume_pcollector;
162 }
163
164 /**
165 * Returns a PStatCollector that is used to count the number of intersection
166 * tests made against a solid of this type in a given frame.
167 */
168 PStatCollector &CollisionSolid::
169 get_test_pcollector() {
170 return _test_pcollector;
171 }
172
173 /**
174 *
175 */
176 void CollisionSolid::
177 output(std::ostream &out) const {
178 out << get_type();
179 }
180
181 /**
182 *
183 */
184 void CollisionSolid::
185 write(std::ostream &out, int indent_level) const {
186 indent(out, indent_level) << (*this) << "\n";
187 }
188
189 /**
190 *
191 */
192 PT(BoundingVolume) CollisionSolid::
193 compute_internal_bounds() const {
194 return new BoundingSphere;
195 }
196
197 /**
198 * This is part of the double-dispatch implementation of test_intersection().
199 * It is called when the "from" object is a sphere.
200 */
201 PT(CollisionEntry) CollisionSolid::
202 test_intersection_from_sphere(const CollisionEntry &) const {
203 report_undefined_intersection_test(CollisionSphere::get_class_type(),
204 get_type());
205 return nullptr;
206 }
207
208 /**
209 * This is part of the double-dispatch implementation of test_intersection().
210 * It is called when the "from" object is a line.
211 */
212 PT(CollisionEntry) CollisionSolid::
213 test_intersection_from_line(const CollisionEntry &) const {
214 report_undefined_intersection_test(CollisionLine::get_class_type(),
215 get_type());
216 return nullptr;
217 }
218
219 /**
220 * This is part of the double-dispatch implementation of test_intersection().
221 * It is called when the "from" object is a ray.
222 */
223 PT(CollisionEntry) CollisionSolid::
224 test_intersection_from_ray(const CollisionEntry &) const {
225 report_undefined_intersection_test(CollisionRay::get_class_type(),
226 get_type());
227 return nullptr;
228 }
229
230 /**
231 * This is part of the double-dispatch implementation of test_intersection().
232 * It is called when the "from" object is a segment.
233 */
234 PT(CollisionEntry) CollisionSolid::
235 test_intersection_from_segment(const CollisionEntry &) const {
236 report_undefined_intersection_test(CollisionSegment::get_class_type(),
237 get_type());
238 return nullptr;
239 }
240
241 /**
242 * This is part of the double-dispatch implementation of test_intersection().
243 * It is called when the "from" object is a capsule.
244 */
245 PT(CollisionEntry) CollisionSolid::
246 test_intersection_from_capsule(const CollisionEntry &) const {
247 report_undefined_intersection_test(CollisionCapsule::get_class_type(),
248 get_type());
249 return nullptr;
250 }
251
252 /**
253 * This is part of the double-dispatch implementation of test_intersection().
254 * It is called when the "from" object is a parabola.
255 */
256 PT(CollisionEntry) CollisionSolid::
257 test_intersection_from_parabola(const CollisionEntry &) const {
258 report_undefined_intersection_test(CollisionParabola::get_class_type(),
259 get_type());
260 return nullptr;
261 }
262
263 /**
264 * This is part of the double-dispatch implementation of test_intersection().
265 * It is called when the "from" object is a box.
266 */
267 PT(CollisionEntry) CollisionSolid::
268 test_intersection_from_box(const CollisionEntry &) const {
269 report_undefined_intersection_test(CollisionBox::get_class_type(),
270 get_type());
271 return nullptr;
272 }
273
274
275 #ifndef NDEBUG
276 class CollisionSolidUndefinedPair {
277 public:
278 CollisionSolidUndefinedPair(TypeHandle a, TypeHandle b) :
279 _a(a), _b(b)
280 {}
281 bool operator < (const CollisionSolidUndefinedPair &other) const {
282 if (_a != other._a) {
283 return _a < other._a;
284 }
285 return _b < other._b;
286 }
287
288 TypeHandle _a;
289 TypeHandle _b;
290 };
291 #endif // NDEBUG
292
293 /**
294 * Outputs a message the first time an intersection test is attempted that
295 * isn't defined, and explains a bit about what it means.
296 */
297 void CollisionSolid::
298 report_undefined_intersection_test(TypeHandle from_type, TypeHandle into_type) {
299 #ifndef NDEBUG
300 typedef pset<CollisionSolidUndefinedPair> Reported;
301 static Reported reported;
302
303 if (reported.insert(CollisionSolidUndefinedPair(from_type, into_type)).second) {
304 collide_cat.error()
305 << "Invalid attempt to detect collision from " << from_type << " into "
306 << into_type << "!\n\n"
307
308 "This means that a " << from_type << " object attempted to test for an\n"
309 "intersection into a " << into_type << " object. This intersection\n"
310 "test has not yet been defined; it is possible the " << into_type << "\n"
311 "object is not intended to be collidable. Consider calling\n"
312 "set_into_collide_mask(0) on the " << into_type << " object, or\n"
313 "set_from_collide_mask(0) on the " << from_type << " object.\n\n";
314 }
315 #endif // NDEBUG
316 }
317
318 /**
319 * Outputs a message the first time an intersection test is attempted that
320 * isn't defined, and explains a bit about what it means.
321 */
322 void CollisionSolid::
323 report_undefined_from_intersection(TypeHandle from_type) {
324 #ifndef NDEBUG
325 typedef pset<TypeHandle> Reported;
326 static Reported reported;
327
328 if (reported.insert(from_type).second) {
329 collide_cat.error()
330 << "Invalid attempt to detect collision from " << from_type << "!\n\n"
331
332 "This means that a " << from_type << " object was added to a\n"
333 "CollisionTraverser as if it were a colliding object. However,\n"
334 "no implementation for this kind of object has yet been defined\n"
335 "to collide with other objects.\n\n";
336 }
337 #endif // NDEBUG
338 }
339
340 /**
341 * Function to write the important information in the particular object to a
342 * Datagram
343 */
344 void CollisionSolid::
345 write_datagram(BamWriter *, Datagram &me) {
346 // For now, we need only 8 bits of flags. If we need to expand this later,
347 // we will have to increase the bam version.
348 LightMutexHolder holder(_lock);
349 me.add_uint8(_flags);
350 if ((_flags & F_effective_normal) != 0) {
351 _effective_normal.write_datagram(me);
352 }
353 }
354
355 /**
356 * Function that reads out of the datagram (or asks manager to read) all of
357 * the data that is needed to re-create this object and stores it in the
358 * appropiate place
359 */
360 void CollisionSolid::
361 fillin(DatagramIterator &scan, BamReader *manager) {
362 _flags = scan.get_uint8();
363 if ((_flags & F_effective_normal) != 0) {
364 _effective_normal.read_datagram(scan);
365 }
366
367 // The viz is always stale after reading from a bam file. So is the
368 // bounding volume.
369 _flags |= F_viz_geom_stale | F_internal_bounds_stale;
370 }
371
372
373 /**
374 * Fills the _viz_geom GeomNode up with Geoms suitable for rendering this
375 * solid.
376 */
377 void CollisionSolid::
378 fill_viz_geom() {
379 }
380
381 /**
382 * Returns a RenderState for rendering collision visualizations in solid.
383 * This automatically returns the appropriate state according to the setting
384 * of _tangible.
385 *
386 * Assumes the lock is already held.
387 */
388 CPT(RenderState) CollisionSolid::
389 get_solid_viz_state() {
390 // Once someone asks for this pointer, we hold its reference count and never
391 // free it.
392 static CPT(RenderState) base_state = nullptr;
393 if (base_state == nullptr) {
394 base_state = RenderState::make
395 (CullFaceAttrib::make(CullFaceAttrib::M_cull_clockwise),
396 RenderModeAttrib::make(RenderModeAttrib::M_filled),
397 TransparencyAttrib::make(TransparencyAttrib::M_alpha));
398 }
399
400 if (!do_is_tangible()) {
401 static CPT(RenderState) intangible_state = nullptr;
402 if (intangible_state == nullptr) {
403 intangible_state = base_state->add_attrib
404 (ColorAttrib::make_flat(LColor(1.0f, 0.3, 0.5f, 0.5f)));
405 }
406 return intangible_state;
407
408 } else if (do_has_effective_normal()) {
409 static CPT(RenderState) fakenormal_state = nullptr;
410 if (fakenormal_state == nullptr) {
411 fakenormal_state = base_state->add_attrib
412 (ColorAttrib::make_flat(LColor(0.5f, 0.5f, 1.0f, 0.5f)));
413 }
414 return fakenormal_state;
415
416 } else {
417 static CPT(RenderState) tangible_state = nullptr;
418 if (tangible_state == nullptr) {
419 tangible_state = base_state->add_attrib
420 (ColorAttrib::make_flat(LColor(1.0f, 1.0f, 1.0f, 0.5f)));
421 }
422 return tangible_state;
423 }
424 }
425
426
427 /**
428 * Returns a RenderState for rendering collision visualizations in wireframe.
429 * This automatically returns the appropriate state according to the setting
430 * of _tangible.
431 *
432 * Assumes the lock is already held.
433 */
434 CPT(RenderState) CollisionSolid::
435 get_wireframe_viz_state() {
436 // Once someone asks for this pointer, we hold its reference count and never
437 // free it.
438 static CPT(RenderState) base_state = nullptr;
439 if (base_state == nullptr) {
440 base_state = RenderState::make
441 (CullFaceAttrib::make(CullFaceAttrib::M_cull_none),
442 RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
443 TransparencyAttrib::make(TransparencyAttrib::M_none));
444 }
445
446 if (!do_is_tangible()) {
447 static CPT(RenderState) intangible_state = nullptr;
448 if (intangible_state == nullptr) {
449 intangible_state = base_state->add_attrib
450 (ColorAttrib::make_flat(LColor(1.0f, 1.0f, 0.0f, 1.0f)));
451 }
452 return intangible_state;
453
454 } else if (do_has_effective_normal()) {
455 static CPT(RenderState) fakenormal_state = nullptr;
456 if (fakenormal_state == nullptr) {
457 fakenormal_state = base_state->add_attrib
458 (ColorAttrib::make_flat(LColor(0.0f, 0.0f, 1.0f, 1.0f)));
459 }
460 return fakenormal_state;
461
462 } else {
463 static CPT(RenderState) tangible_state = nullptr;
464 if (tangible_state == nullptr) {
465 tangible_state = base_state->add_attrib
466 (ColorAttrib::make_flat(LColor(0.0f, 0.0f, 1.0f, 1.0f)));
467 }
468 return tangible_state;
469 }
470 }
471
472
473 /**
474 * Returns a RenderState for rendering collision visualizations for things
475 * that are neither solid nor exactly wireframe, like rays and segments.
476 *
477 * Assumes the lock is already held.
478 */
479 CPT(RenderState) CollisionSolid::
480 get_other_viz_state() {
481 // Once someone asks for this pointer, we hold its reference count and never
482 // free it.
483 static CPT(RenderState) base_state = nullptr;
484 if (base_state == nullptr) {
485 base_state = RenderState::make
486 (CullFaceAttrib::make(CullFaceAttrib::M_cull_clockwise),
487 RenderModeAttrib::make(RenderModeAttrib::M_filled),
488 TransparencyAttrib::make(TransparencyAttrib::M_alpha));
489 }
490
491 // We don't bother to make a distinction here between tangible and
492 // intangible.
493 return base_state;
494 }
495
496 /**
497 * Returns a RenderState for rendering collision visualizations in solid.
498 * This automatically returns the appropriate state according to the setting
499 * of _tangible.
500 *
501 * Assumes the lock is already held.
502 */
503 CPT(RenderState) CollisionSolid::
504 get_solid_bounds_viz_state() {
505 // Once someone asks for this pointer, we hold its reference count and never
506 // free it.
507 static CPT(RenderState) base_state = nullptr;
508 if (base_state == nullptr) {
509 base_state = RenderState::make
510 (CullFaceAttrib::make(CullFaceAttrib::M_cull_clockwise),
511 RenderModeAttrib::make(RenderModeAttrib::M_filled),
512 TransparencyAttrib::make(TransparencyAttrib::M_alpha));
513 }
514
515 if (!do_is_tangible()) {
516 static CPT(RenderState) intangible_state = nullptr;
517 if (intangible_state == nullptr) {
518 intangible_state = base_state->add_attrib
519 (ColorAttrib::make_flat(LColor(1.0f, 1.0f, 0.5f, 0.3)));
520 }
521 return intangible_state;
522
523 } else if (do_has_effective_normal()) {
524 static CPT(RenderState) fakenormal_state = nullptr;
525 if (fakenormal_state == nullptr) {
526 fakenormal_state = base_state->add_attrib
527 (ColorAttrib::make_flat(LColor(0.5f, 0.5f, 1.0f, 0.3)));
528 }
529 return fakenormal_state;
530
531 } else {
532 static CPT(RenderState) tangible_state = nullptr;
533 if (tangible_state == nullptr) {
534 tangible_state = base_state->add_attrib
535 (ColorAttrib::make_flat(LColor(1.0f, 1.0f, 0.5f, 0.3)));
536 }
537 return tangible_state;
538 }
539 }
540
541
542 /**
543 * Returns a RenderState for rendering collision visualizations in wireframe.
544 * This automatically returns the appropriate state according to the setting
545 * of _tangible.
546 *
547 * Assumes the lock is already held.
548 */
549 CPT(RenderState) CollisionSolid::
550 get_wireframe_bounds_viz_state() {
551 // Once someone asks for this pointer, we hold its reference count and never
552 // free it.
553 static CPT(RenderState) base_state = nullptr;
554 if (base_state == nullptr) {
555 base_state = RenderState::make
556 (CullFaceAttrib::make(CullFaceAttrib::M_cull_none),
557 RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
558 TransparencyAttrib::make(TransparencyAttrib::M_none),
559 ColorAttrib::make_flat(LColor(1.0f, 0.0f, 0.0f, 1.0f)));
560 }
561
562 return base_state;
563 }
564
565
566 /**
567 * Returns a RenderState for rendering collision visualizations for things
568 * that are neither solid nor exactly wireframe, like rays and segments.
569 *
570 * Assumes the lock is already held.
571 */
572 CPT(RenderState) CollisionSolid::
573 get_other_bounds_viz_state() {
574 // Once someone asks for this pointer, we hold its reference count and never
575 // free it.
576 static CPT(RenderState) base_state = nullptr;
577 if (base_state == nullptr) {
578 base_state = RenderState::make
579 (CullFaceAttrib::make(CullFaceAttrib::M_cull_clockwise),
580 RenderModeAttrib::make(RenderModeAttrib::M_filled),
581 TransparencyAttrib::make(TransparencyAttrib::M_alpha));
582 }
583
584 // We don't bother to make a distinction here between tangible and
585 // intangible.
586 return base_state;
587 }
bamReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bamWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
boundingSphere.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BamReader
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
BamWriter
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
BoundingSphere
This defines a bounding sphere, consisting of a center and a radius.
Definition: boundingSphere.h:25
BoundingVolume
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
Definition: boundingVolume.h:41
CollisionEntry
Defines a single collision event.
Definition: collisionEntry.h:42
CollisionSolid
The abstract base class for all things that can collide with other things in the world,...
Definition: collisionSolid.h:45
CollisionSolid::write_datagram
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
Definition: collisionSolid.cxx:345
CollisionSolid::get_test_pcollector
virtual PStatCollector & get_test_pcollector()
Returns a PStatCollector that is used to count the number of intersection tests made against a solid ...
Definition: collisionSolid.cxx:169
CopyOnWriteObject
This base class provides basic reference counting, but also can be used with a CopyOnWritePointer to ...
Definition: copyOnWriteObject.h:41
CullTraverserData
This collects together the pieces of data that are accumulated for each node while walking the scene ...
Definition: cullTraverserData.h:40
CullTraverser
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Definition: cullTraverser.h:45
DatagramIterator
A class to retrieve the individual data elements previously stored in a Datagram.
Definition: datagramIterator.h:27
DatagramIterator::get_uint8
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
Definition: datagramIterator.I:72
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
Datagram::add_uint8
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
Definition: datagram.I:50
GeomNode
A node that holds Geom objects, renderable pieces of geometry.
Definition: geomNode.h:34
LightMutexHolder
Similar to MutexHolder, but for a light mutex.
Definition: lightMutexHolder.h:25
PStatCollector
A lightweight class that represents a single element that may be timed and/or counted via stats.
Definition: pStatCollector.h:43
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
RenderState
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
pset
This is our own Panda specialization on the default STL set.
Definition: pset.h:49
collisionBox.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
collisionCapsule.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
collisionEntry.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
collisionLine.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
collisionParabola.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
collisionRay.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
collisionSegment.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CPT
CPT(BoundingVolume) CollisionSolid
Returns the solid's bounding volume.
Definition: collisionSolid.cxx:82
PT
PT(CopyOnWriteObject) CollisionSolid
Required to implement CopyOnWriteObject.
Definition: collisionSolid.cxx:74
collisionSolid.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
collisionSphere.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
colorAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
config_collide.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
cullFaceAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
datagramIterator.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
datagram.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
geomNode.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
indent
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
indent.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
renderModeAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
transparencyAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.