Panda3D
Loading...
Searching...
No Matches
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
36PStatCollector CollisionSolid::_volume_pcollector(
37 "Collision Volumes:CollisionSolid");
38PStatCollector CollisionSolid::_test_pcollector(
39 "Collision Tests:CollisionSolid");
40TypeHandle CollisionSolid::_type_handle;
41
42/**
43 *
44 */
45CollisionSolid::
46CollisionSolid() : _lock("CollisionSolid") {
47 _flags = F_viz_geom_stale | F_tangible | F_internal_bounds_stale;
48}
49
50/**
51 *
52 */
53CollisionSolid::
54CollisionSolid(const CollisionSolid &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 */
67CollisionSolid::
68~CollisionSolid() {
69}
70
71/**
72 * Required to implement CopyOnWriteObject.
73 */
74PT(CopyOnWriteObject) CollisionSolid::
75make_cow_copy() {
76 return make_copy();
77}
78
79/**
80 * Returns the solid's bounding volume.
81 */
82CPT(BoundingVolume) CollisionSolid::
83get_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 */
95void CollisionSolid::
96set_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 */
108PT(CollisionEntry) CollisionSolid::
109test_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 */
117void CollisionSolid::
118xform(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 */
133PT(PandaNode) CollisionSolid::
134get_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 */
159PStatCollector &CollisionSolid::
160get_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 */
170 return _test_pcollector;
171}
172
173/**
174 *
175 */
176void CollisionSolid::
177output(std::ostream &out) const {
178 out << get_type();
179}
180
181/**
182 *
183 */
184void CollisionSolid::
185write(std::ostream &out, int indent_level) const {
186 indent(out, indent_level) << (*this) << "\n";
187}
188
189/**
190 *
191 */
192PT(BoundingVolume) CollisionSolid::
193compute_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 */
201PT(CollisionEntry) CollisionSolid::
202test_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 */
212PT(CollisionEntry) CollisionSolid::
213test_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 */
223PT(CollisionEntry) CollisionSolid::
224test_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 */
234PT(CollisionEntry) CollisionSolid::
235test_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 */
245PT(CollisionEntry) CollisionSolid::
246test_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 */
256PT(CollisionEntry) CollisionSolid::
257test_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 */
267PT(CollisionEntry) CollisionSolid::
268test_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
276class CollisionSolidUndefinedPair {
277public:
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 */
297void CollisionSolid::
298report_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 */
322void CollisionSolid::
323report_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 */
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 */
360void CollisionSolid::
361fillin(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 */
377void CollisionSolid::
378fill_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 */
388CPT(RenderState) CollisionSolid::
389get_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 */
434CPT(RenderState) CollisionSolid::
435get_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 */
479CPT(RenderState) CollisionSolid::
480get_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 */
503CPT(RenderState) CollisionSolid::
504get_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 */
549CPT(RenderState) CollisionSolid::
550get_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 */
572CPT(RenderState) CollisionSolid::
573get_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}
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition bamReader.h:110
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition bamWriter.h:63
This defines a bounding sphere, consisting of a center and a radius.
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
Defines a single collision event.
The abstract base class for all things that can collide with other things in the world,...
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
virtual PStatCollector & get_test_pcollector()
Returns a PStatCollector that is used to count the number of intersection tests made against a solid ...
This base class provides basic reference counting, but also can be used with a CopyOnWritePointer to ...
This collects together the pieces of data that are accumulated for each node while walking the scene ...
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
A class to retrieve the individual data elements previously stored in a Datagram.
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition datagram.h:38
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
Definition datagram.I:50
A node that holds Geom objects, renderable pieces of geometry.
Definition geomNode.h:34
Similar to MutexHolder, but for a light mutex.
A lightweight class that represents a single element that may be timed and/or counted via stats.
A basic node of the scene graph or data graph.
Definition pandaNode.h:65
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition renderState.h:47
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
This is our own Panda specialization on the default STL set.
Definition pset.h:49
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.
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.