mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-17 12:12:10 -04:00
408 lines
15 KiB
C++
408 lines
15 KiB
C++
// Filename: collisionSolid.cxx
|
|
// Created by: drose (24Apr00)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
|
//
|
|
// All use of this software is subject to the terms of the Panda 3d
|
|
// Software license. You should have received a copy of this license
|
|
// along with this source code; you will also find a current copy of
|
|
// the license at http://www.panda3d.org/license.txt .
|
|
//
|
|
// To contact the maintainers of this program write to
|
|
// panda3d@yahoogroups.com .
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "collisionSolid.h"
|
|
#include "config_collide.h"
|
|
#include "collisionSphere.h"
|
|
#include "collisionRay.h"
|
|
#include "collisionSegment.h"
|
|
|
|
#include "datagram.h"
|
|
#include "datagramIterator.h"
|
|
#include "bamReader.h"
|
|
#include "bamWriter.h"
|
|
#include "indent.h"
|
|
#include "cullFaceAttrib.h"
|
|
#include "colorAttrib.h"
|
|
#include "renderModeAttrib.h"
|
|
#include "transparencyAttrib.h"
|
|
#include "geomNode.h"
|
|
|
|
TypeHandle CollisionSolid::_type_handle;
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CollisionSolid::Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
CollisionSolid::
|
|
CollisionSolid() {
|
|
_flags = F_viz_geom_stale | F_tangible;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CollisionSolid::Copy Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
CollisionSolid::
|
|
CollisionSolid(const CollisionSolid ©) :
|
|
_effective_normal(copy._effective_normal),
|
|
_flags(copy._flags)
|
|
{
|
|
_flags |= F_viz_geom_stale;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CollisionSolid::Destructor
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
CollisionSolid::
|
|
~CollisionSolid() {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CollisionSolid::test_intersection
|
|
// Access: Public, Virtual
|
|
// Description: Tests for a collision between this object (which is
|
|
// also the "from" object in the entry) and the "into"
|
|
// object. If a collision is detected, returns a new
|
|
// CollisionEntry object that records the collision;
|
|
// otherwise, returns NULL.
|
|
////////////////////////////////////////////////////////////////////
|
|
PT(CollisionEntry) CollisionSolid::
|
|
test_intersection(const CollisionEntry &) const {
|
|
report_undefined_from_intersection(get_type());
|
|
return NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CollisionSolid::xform
|
|
// Access: Public, Virtual
|
|
// Description: Transforms the solid by the indicated matrix.
|
|
////////////////////////////////////////////////////////////////////
|
|
void CollisionSolid::
|
|
xform(const LMatrix4f &mat) {
|
|
if (has_effective_normal()) {
|
|
_effective_normal = _effective_normal * mat;
|
|
}
|
|
|
|
mark_viz_stale();
|
|
mark_bound_stale();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CollisionSolid::get_viz
|
|
// Access: Public, Virtual
|
|
// Description: Returns a GeomNode that may be rendered to visualize
|
|
// the CollisionSolid. This is used during the cull
|
|
// traversal to render the CollisionNodes that have been
|
|
// made visible.
|
|
////////////////////////////////////////////////////////////////////
|
|
PT(PandaNode) CollisionSolid::
|
|
get_viz(const CullTraverserData &) const {
|
|
if ((_flags & F_viz_geom_stale) != 0) {
|
|
if (_viz_geom == (GeomNode *)NULL) {
|
|
((CollisionSolid *)this)->_viz_geom = new GeomNode("viz");
|
|
} else {
|
|
_viz_geom->remove_all_geoms();
|
|
}
|
|
((CollisionSolid *)this)->fill_viz_geom();
|
|
((CollisionSolid *)this)->_flags &= ~F_viz_geom_stale;
|
|
}
|
|
return _viz_geom.p();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CollisionSolid::output
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void CollisionSolid::
|
|
output(ostream &out) const {
|
|
out << get_type();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CollisionSolid::write
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void CollisionSolid::
|
|
write(ostream &out, int indent_level) const {
|
|
indent(out, indent_level) << (*this) << "\n";
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CollisionSolid::test_intersection_from_sphere
|
|
// Access: Protected, Virtual
|
|
// Description: This is part of the double-dispatch implementation of
|
|
// test_intersection(). It is called when the "from"
|
|
// object is a sphere.
|
|
////////////////////////////////////////////////////////////////////
|
|
PT(CollisionEntry) CollisionSolid::
|
|
test_intersection_from_sphere(const CollisionEntry &) const {
|
|
report_undefined_intersection_test(CollisionSphere::get_class_type(),
|
|
get_type());
|
|
return NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CollisionSolid::test_intersection_from_ray
|
|
// Access: Protected, Virtual
|
|
// Description: This is part of the double-dispatch implementation of
|
|
// test_intersection(). It is called when the "from"
|
|
// object is a ray.
|
|
////////////////////////////////////////////////////////////////////
|
|
PT(CollisionEntry) CollisionSolid::
|
|
test_intersection_from_ray(const CollisionEntry &) const {
|
|
report_undefined_intersection_test(CollisionRay::get_class_type(),
|
|
get_type());
|
|
return NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CollisionSolid::test_intersection_from_segment
|
|
// Access: Protected, Virtual
|
|
// Description: This is part of the double-dispatch implementation of
|
|
// test_intersection(). It is called when the "from"
|
|
// object is a segment.
|
|
////////////////////////////////////////////////////////////////////
|
|
PT(CollisionEntry) CollisionSolid::
|
|
test_intersection_from_segment(const CollisionEntry &) const {
|
|
report_undefined_intersection_test(CollisionSegment::get_class_type(),
|
|
get_type());
|
|
return NULL;
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
class CollisionSolidUndefinedPair {
|
|
public:
|
|
CollisionSolidUndefinedPair(TypeHandle a, TypeHandle b) :
|
|
_a(a), _b(b)
|
|
{}
|
|
bool operator < (const CollisionSolidUndefinedPair &other) const {
|
|
if (_a != other._a) {
|
|
return _a < other._a;
|
|
}
|
|
return _b < other._b;
|
|
}
|
|
|
|
TypeHandle _a;
|
|
TypeHandle _b;
|
|
};
|
|
#endif // NDEBUG
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CollisionSolid::report_undefined_intersection_test
|
|
// Access: Protected, Static
|
|
// Description: Outputs a message the first time an intersection test
|
|
// is attempted that isn't defined, and explains a bit
|
|
// about what it means.
|
|
////////////////////////////////////////////////////////////////////
|
|
void CollisionSolid::
|
|
report_undefined_intersection_test(TypeHandle from_type, TypeHandle into_type) {
|
|
#ifndef NDEBUG
|
|
typedef pset<CollisionSolidUndefinedPair> Reported;
|
|
static Reported reported;
|
|
|
|
if (reported.insert(CollisionSolidUndefinedPair(from_type, into_type)).second) {
|
|
collide_cat.error()
|
|
<< "Invalid attempt to detect collision from " << from_type << " into "
|
|
<< into_type << "!\n\n"
|
|
|
|
"This means that a " << from_type << " object attempted to test for an\n"
|
|
"intersection into a " << into_type << " object. This intersection\n"
|
|
"test has not yet been defined; it is possible the " << into_type << "\n"
|
|
"object is not intended to be collidable. Consider calling\n"
|
|
"set_into_collide_mask(0) on the " << into_type << " object, or\n"
|
|
"set_from_collide_mask(0) on the " << from_type << " object.\n\n";
|
|
}
|
|
#endif // NDEBUG
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CollisionSolid::report_undefined_from_intersection
|
|
// Access: Protected, Static
|
|
// Description: Outputs a message the first time an intersection test
|
|
// is attempted that isn't defined, and explains a bit
|
|
// about what it means.
|
|
////////////////////////////////////////////////////////////////////
|
|
void CollisionSolid::
|
|
report_undefined_from_intersection(TypeHandle from_type) {
|
|
#ifndef NDEBUG
|
|
typedef pset<TypeHandle> Reported;
|
|
static Reported reported;
|
|
|
|
if (reported.insert(from_type).second) {
|
|
collide_cat.error()
|
|
<< "Invalid attempt to detect collision from " << from_type << "!\n\n"
|
|
|
|
"This means that a " << from_type << " object was added to a\n"
|
|
"CollisionTraverser as if it were a colliding object. However,\n"
|
|
"no implementation for this kind of object has yet been defined\n"
|
|
"to collide with other objects.\n\n";
|
|
}
|
|
#endif // NDEBUG
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CollisionSolid::write_datagram
|
|
// Access: Public
|
|
// Description: Function to write the important information in
|
|
// the particular object to a Datagram
|
|
////////////////////////////////////////////////////////////////////
|
|
void CollisionSolid::
|
|
write_datagram(BamWriter *, Datagram &me) {
|
|
// For now, we need only 8 bits of flags. If we need to expand this
|
|
// later, we will have to increase the bam version.
|
|
me.add_uint8(_flags);
|
|
if ((_flags & F_effective_normal) != 0) {
|
|
_effective_normal.write_datagram(me);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CollisionSolid::fillin
|
|
// Access: Protected
|
|
// Description: Function that reads out of the datagram (or asks
|
|
// manager to read) all of the data that is needed to
|
|
// re-create this object and stores it in the appropiate
|
|
// place
|
|
////////////////////////////////////////////////////////////////////
|
|
void CollisionSolid::
|
|
fillin(DatagramIterator &scan, BamReader*) {
|
|
_flags = scan.get_uint8();
|
|
if ((_flags & F_effective_normal) != 0) {
|
|
_effective_normal.read_datagram(scan);
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CollisionSolid::fill_viz_geom
|
|
// Access: Protected, Virtual
|
|
// Description: Fills the _viz_geom GeomNode up with Geoms suitable
|
|
// for rendering this solid.
|
|
////////////////////////////////////////////////////////////////////
|
|
void CollisionSolid::
|
|
fill_viz_geom() {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CollisionSolid::get_solid_viz_state
|
|
// Access: Protected
|
|
// Description: Returns a RenderState for rendering collision
|
|
// visualizations in solid. This automatically returns
|
|
// the appropriate state according to the setting of
|
|
// _tangible.
|
|
////////////////////////////////////////////////////////////////////
|
|
CPT(RenderState) CollisionSolid::
|
|
get_solid_viz_state() {
|
|
// Once someone asks for this pointer, we hold its reference count
|
|
// and never free it.
|
|
static CPT(RenderState) base_state = (const RenderState *)NULL;
|
|
if (base_state == (const RenderState *)NULL) {
|
|
base_state = RenderState::make
|
|
(CullFaceAttrib::make(CullFaceAttrib::M_cull_clockwise),
|
|
RenderModeAttrib::make(RenderModeAttrib::M_filled),
|
|
TransparencyAttrib::make(TransparencyAttrib::M_alpha));
|
|
}
|
|
|
|
if (!is_tangible()) {
|
|
static CPT(RenderState) intangible_state = (const RenderState *)NULL;
|
|
if (intangible_state == (const RenderState *)NULL) {
|
|
intangible_state = base_state->add_attrib
|
|
(ColorAttrib::make_flat(Colorf(1.0f, 0.3f, 0.5f, 0.5f)));
|
|
}
|
|
return intangible_state;
|
|
|
|
} else if (has_effective_normal()) {
|
|
static CPT(RenderState) fakenormal_state = (const RenderState *)NULL;
|
|
if (fakenormal_state == (const RenderState *)NULL) {
|
|
fakenormal_state = base_state->add_attrib
|
|
(ColorAttrib::make_flat(Colorf(0.5f, 0.5f, 1.0f, 0.5f)));
|
|
}
|
|
return fakenormal_state;
|
|
|
|
} else {
|
|
static CPT(RenderState) tangible_state = (const RenderState *)NULL;
|
|
if (tangible_state == (const RenderState *)NULL) {
|
|
tangible_state = base_state->add_attrib
|
|
(ColorAttrib::make_flat(Colorf(1.0f, 1.0f, 1.0f, 0.5f)));
|
|
}
|
|
return tangible_state;
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CollisionSolid::get_wireframe_viz_state
|
|
// Access: Protected
|
|
// Description: Returns a RenderState for rendering collision
|
|
// visualizations in wireframe. This automatically returns
|
|
// the appropriate state according to the setting of
|
|
// _tangible.
|
|
////////////////////////////////////////////////////////////////////
|
|
CPT(RenderState) CollisionSolid::
|
|
get_wireframe_viz_state() {
|
|
// Once someone asks for this pointer, we hold its reference count
|
|
// and never free it.
|
|
static CPT(RenderState) base_state = (const RenderState *)NULL;
|
|
if (base_state == (const RenderState *)NULL) {
|
|
base_state = RenderState::make
|
|
(CullFaceAttrib::make(CullFaceAttrib::M_cull_none),
|
|
RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
|
|
TransparencyAttrib::make(TransparencyAttrib::M_none));
|
|
}
|
|
|
|
if (is_tangible()) {
|
|
static CPT(RenderState) tangible_state = (const RenderState *)NULL;
|
|
if (tangible_state == (const RenderState *)NULL) {
|
|
tangible_state = base_state->add_attrib
|
|
(ColorAttrib::make_flat(Colorf(0.0f, 0.0f, 1.0f, 1.0f)));
|
|
}
|
|
return tangible_state;
|
|
|
|
} else {
|
|
static CPT(RenderState) intangible_state = (const RenderState *)NULL;
|
|
if (intangible_state == (const RenderState *)NULL) {
|
|
intangible_state = base_state->add_attrib
|
|
(ColorAttrib::make_flat(Colorf(1.0f, 1.0f, 0.0f, 1.0f)));
|
|
}
|
|
return intangible_state;
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CollisionSolid::get_other_viz_state
|
|
// Access: Protected
|
|
// Description: Returns a RenderState for rendering collision
|
|
// visualizations for things that are neither solid nor
|
|
// exactly wireframe, like rays and segments.
|
|
////////////////////////////////////////////////////////////////////
|
|
CPT(RenderState) CollisionSolid::
|
|
get_other_viz_state() {
|
|
// Once someone asks for this pointer, we hold its reference count
|
|
// and never free it.
|
|
static CPT(RenderState) base_state = (const RenderState *)NULL;
|
|
if (base_state == (const RenderState *)NULL) {
|
|
base_state = RenderState::make
|
|
(CullFaceAttrib::make(CullFaceAttrib::M_cull_clockwise),
|
|
RenderModeAttrib::make(RenderModeAttrib::M_filled),
|
|
TransparencyAttrib::make(TransparencyAttrib::M_alpha));
|
|
}
|
|
|
|
// We don't bother to make a distinction here between tangible and
|
|
// intangible.
|
|
return base_state;
|
|
}
|
|
|