allow-collider-bitarray
This commit is contained in:
parent
05b0adcbb5
commit
5e86a1c8b3
|
|
@ -22,6 +22,7 @@
|
|||
collisionDSSolid.I collisionDSSolid.h \
|
||||
collisionInvSphere.I collisionInvSphere.h \
|
||||
collisionLine.I collisionLine.h \
|
||||
collisionLevelStateBase.I collisionLevelStateBase.h \
|
||||
collisionLevelState.I collisionLevelState.h \
|
||||
collisionNode.I collisionNode.h \
|
||||
collisionPlane.I collisionPlane.h \
|
||||
|
|
@ -46,6 +47,7 @@
|
|||
collisionHandlerPhysical.cxx \
|
||||
collisionHandlerPusher.cxx \
|
||||
collisionHandlerQueue.cxx \
|
||||
collisionLevelStateBase.cxx \
|
||||
collisionLevelState.cxx \
|
||||
collisionDSSolid.cxx \
|
||||
collisionInvSphere.cxx \
|
||||
|
|
@ -75,6 +77,7 @@
|
|||
collisionHandlerQueue.h \
|
||||
collisionDSSolid.I collisionDSSolid.h \
|
||||
collisionInvSphere.I collisionInvSphere.h \
|
||||
collisionLevelStateBase.I collisionLevelStateBase.h \
|
||||
collisionLevelState.I collisionLevelState.h \
|
||||
collisionLine.I collisionLine.h \
|
||||
collisionNode.I collisionNode.h \
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "collisionHandlerQueue.cxx"
|
||||
#include "collisionDSSolid.cxx"
|
||||
#include "collisionInvSphere.cxx"
|
||||
#include "collisionLevelStateBase.cxx"
|
||||
#include "collisionLevelState.cxx"
|
||||
#include "collisionLine.cxx"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// Filename: collisionLevelState.I
|
||||
// Created by: drose (16Mar02)
|
||||
// Created by: drose (05Apr07)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
|
@ -16,19 +16,20 @@
|
|||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#ifndef CPPPARSER // interrogate has trouble with these initializers.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelState::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CollisionLevelState::
|
||||
template<class MaskType>
|
||||
INLINE CollisionLevelState<MaskType>::
|
||||
CollisionLevelState(const NodePath &node_path) :
|
||||
_node_path(node_path),
|
||||
_current(CollisionLevelState::CurrentMask::all_off()),
|
||||
_include_mask(CollideMask::all_on())
|
||||
CollisionLevelStateBase(node_path),
|
||||
_current(CurrentMask::all_off())
|
||||
{
|
||||
}
|
||||
#endif // CPPPARSER
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelState::Constructor
|
||||
|
|
@ -36,13 +37,11 @@ CollisionLevelState(const NodePath &node_path) :
|
|||
// Description: This constructor goes to the next child node in the
|
||||
// traversal.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CollisionLevelState::
|
||||
CollisionLevelState(const CollisionLevelState &parent, PandaNode *child) :
|
||||
_node_path(parent._node_path, child),
|
||||
_colliders(parent._colliders),
|
||||
_current(parent._current),
|
||||
_include_mask(parent._include_mask),
|
||||
_local_bounds(parent._local_bounds)
|
||||
template<class MaskType>
|
||||
INLINE CollisionLevelState<MaskType>::
|
||||
CollisionLevelState(const CollisionLevelState<MaskType> &parent, PandaNode *child) :
|
||||
CollisionLevelStateBase(parent, child),
|
||||
_current(parent._current)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -51,14 +50,11 @@ CollisionLevelState(const CollisionLevelState &parent, PandaNode *child) :
|
|||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CollisionLevelState::
|
||||
CollisionLevelState(const CollisionLevelState ©) :
|
||||
_node_path(copy._node_path),
|
||||
_colliders(copy._colliders),
|
||||
_current(copy._current),
|
||||
_include_mask(copy._include_mask),
|
||||
_local_bounds(copy._local_bounds),
|
||||
_parent_bounds(copy._parent_bounds)
|
||||
template<class MaskType>
|
||||
INLINE CollisionLevelState<MaskType>::
|
||||
CollisionLevelState(const CollisionLevelState<MaskType> ©) :
|
||||
CollisionLevelStateBase(copy),
|
||||
_current(copy._current)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -67,66 +63,203 @@ CollisionLevelState(const CollisionLevelState ©) :
|
|||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void CollisionLevelState::
|
||||
operator = (const CollisionLevelState ©) {
|
||||
_node_path = copy._node_path;
|
||||
_colliders = copy._colliders;
|
||||
template<class MaskType>
|
||||
INLINE void CollisionLevelState<MaskType>::
|
||||
operator = (const CollisionLevelState<MaskType> ©) {
|
||||
CollisionLevelStateBase::operator = (copy);
|
||||
_current = copy._current;
|
||||
_include_mask = copy._include_mask;
|
||||
_local_bounds = copy._local_bounds;
|
||||
_parent_bounds = copy._parent_bounds;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelState::clear
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
template<class MaskType>
|
||||
INLINE void CollisionLevelState<MaskType>::
|
||||
clear() {
|
||||
CollisionLevelStateBase::clear();
|
||||
_current.clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelState::prepare_collider
|
||||
// Access: Public
|
||||
// Description: Adds the indicated Collider to the set of Colliders
|
||||
// in the current level state.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
template<class MaskType>
|
||||
INLINE void CollisionLevelState<MaskType>::
|
||||
prepare_collider(const ColliderDef &def, const NodePath &root) {
|
||||
int index = (int)_colliders.size();
|
||||
nassertv(!CurrentMask::has_max_num_bits() ||
|
||||
index <= CurrentMask::get_max_num_bits());
|
||||
|
||||
CollisionLevelStateBase::prepare_collider(def, root);
|
||||
_current.set_bit(index);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelState::any_in_bounds
|
||||
// Access: Public
|
||||
// Description: Checks the bounding volume of the current node
|
||||
// against each of our colliders. Eliminates from the
|
||||
// current collider list any that are outside of the
|
||||
// bounding volume. Returns true if any colliders
|
||||
// remain, false if all of them fall outside this node's
|
||||
// bounding volume.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
template<class MaskType>
|
||||
bool CollisionLevelState<MaskType>::
|
||||
any_in_bounds() {
|
||||
#ifndef NDEBUG
|
||||
int indent_level = 0;
|
||||
if (collide_cat.is_spam()) {
|
||||
indent_level = _node_path.get_num_nodes() * 2;
|
||||
collide_cat.spam();
|
||||
indent(collide_cat.spam(false), indent_level)
|
||||
<< "Considering " << _node_path.get_node_path() << "\n";
|
||||
}
|
||||
#endif // NDEBUG
|
||||
|
||||
CPT(BoundingVolume) node_bv = node()->get_bounds();
|
||||
if (node_bv->is_of_type(GeometricBoundingVolume::get_class_type())) {
|
||||
const GeometricBoundingVolume *node_gbv;
|
||||
DCAST_INTO_R(node_gbv, node_bv, false);
|
||||
|
||||
int num_colliders = get_num_colliders();
|
||||
for (int c = 0; c < num_colliders; c++) {
|
||||
if (has_collider(c)) {
|
||||
CollisionNode *cnode = get_collider_node(c);
|
||||
bool is_in = false;
|
||||
|
||||
// Don't even bother testing the bounding volume if there are
|
||||
// no collide bits in common between our collider and this
|
||||
// node.
|
||||
CollideMask from_mask = cnode->get_from_collide_mask() & _include_mask;
|
||||
if (!(from_mask & node()->get_net_collide_mask()).is_zero()) {
|
||||
// There are bits in common, so go ahead and try the
|
||||
// bounding volume.
|
||||
const GeometricBoundingVolume *col_gbv =
|
||||
get_local_bound(c);
|
||||
if (col_gbv != (GeometricBoundingVolume *)NULL) {
|
||||
is_in = (node_gbv->contains(col_gbv) != 0);
|
||||
_node_volume_pcollector.add_level(1);
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (collide_cat.is_spam()) {
|
||||
collide_cat.spam();
|
||||
indent(collide_cat.spam(false), indent_level)
|
||||
<< "Comparing " << c << ": " << *col_gbv
|
||||
<< " to " << *node_gbv << ", is_in = " << is_in << "\n";
|
||||
}
|
||||
#endif // NDEBUG
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_in) {
|
||||
// This collider cannot intersect with any geometry at
|
||||
// this node or below.
|
||||
omit_collider(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (collide_cat.is_spam()) {
|
||||
int num_active_colliders = 0;
|
||||
int num_colliders = get_num_colliders();
|
||||
for (int c = 0; c < num_colliders; c++) {
|
||||
if (has_collider(c)) {
|
||||
num_active_colliders++;
|
||||
}
|
||||
}
|
||||
|
||||
collide_cat.spam();
|
||||
indent(collide_cat.spam(false), indent_level)
|
||||
<< _node_path.get_node_path() << " has " << num_active_colliders
|
||||
<< " interested colliders.\n";
|
||||
}
|
||||
#endif // NDEBUG
|
||||
return has_any_collider();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelStateBase::apply_transform
|
||||
// Access: Public
|
||||
// Description: Applies the inverse transform from the current node,
|
||||
// if any, onto all the colliders in the level state.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
template<class MaskType>
|
||||
void CollisionLevelState<MaskType>::
|
||||
apply_transform() {
|
||||
// The "parent" bounds list remembers the bounds list of the
|
||||
// previous node.
|
||||
_parent_bounds = _local_bounds;
|
||||
|
||||
// Recompute the bounds list of this node (if we have a transform).
|
||||
const TransformState *node_transform = node()->get_transform();
|
||||
if (!node_transform->is_identity()) {
|
||||
CPT(TransformState) inv_transform =
|
||||
node_transform->invert_compose(TransformState::make_identity());
|
||||
const LMatrix4f &mat = inv_transform->get_mat();
|
||||
|
||||
// Now build the new bounding volumes list.
|
||||
BoundingVolumes new_bounds;
|
||||
|
||||
int num_colliders = get_num_colliders();
|
||||
new_bounds.reserve(num_colliders);
|
||||
for (int c = 0; c < num_colliders; c++) {
|
||||
if (!has_collider(c) ||
|
||||
get_local_bound(c) == (GeometricBoundingVolume *)NULL) {
|
||||
new_bounds.push_back((GeometricBoundingVolume *)NULL);
|
||||
} else {
|
||||
const GeometricBoundingVolume *old_bound = get_local_bound(c);
|
||||
GeometricBoundingVolume *new_bound =
|
||||
DCAST(GeometricBoundingVolume, old_bound->make_copy());
|
||||
new_bound->xform(mat);
|
||||
new_bounds.push_back(new_bound);
|
||||
}
|
||||
}
|
||||
|
||||
_local_bounds = new_bounds;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelState::has_max_colliders
|
||||
// Access: Public, Static
|
||||
// Description: Returns true if there is any the maximum number of
|
||||
// colliders that may be added to the
|
||||
// CollisionLevelStateBase at any one time.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
template<class MaskType>
|
||||
INLINE bool CollisionLevelState<MaskType>::
|
||||
has_max_colliders() {
|
||||
return CurrentMask::has_max_num_bits();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelState::get_max_colliders
|
||||
// Access: Public, Static
|
||||
// Description: Returns the maximum number of colliders that may be
|
||||
// added to the CollisionLevelState at any one time.
|
||||
// added to the CollisionLevelStateBase at any one time.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int CollisionLevelState::
|
||||
template<class MaskType>
|
||||
INLINE int CollisionLevelState<MaskType>::
|
||||
get_max_colliders() {
|
||||
return CurrentMask::get_max_num_bits();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelState::get_node_path
|
||||
// Access: Public
|
||||
// Description: Returns the NodePath representing the node instance
|
||||
// we have traversed to.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE NodePath CollisionLevelState::
|
||||
get_node_path() const {
|
||||
return _node_path.get_node_path();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelState::node
|
||||
// Access: Public
|
||||
// Description: Returns the PandaNode pointer of the node we have
|
||||
// traversed to.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PandaNode *CollisionLevelState::
|
||||
node() const {
|
||||
return _node_path.node();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelState::get_num_colliders
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int CollisionLevelState::
|
||||
get_num_colliders() const {
|
||||
return _colliders.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelState::has_collider
|
||||
// Access: Public
|
||||
// Description: Returns true if the nth collider in the LevelState is
|
||||
// still part of the level.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool CollisionLevelState::
|
||||
template<class MaskType>
|
||||
INLINE bool CollisionLevelState<MaskType>::
|
||||
has_collider(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_colliders.size(), false);
|
||||
return (_current.get_bit(n));
|
||||
|
|
@ -137,134 +270,22 @@ has_collider(int n) const {
|
|||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool CollisionLevelState::
|
||||
template<class MaskType>
|
||||
INLINE bool CollisionLevelState<MaskType>::
|
||||
has_any_collider() const {
|
||||
return !_current.is_zero();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelState::get_collider
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CollisionSolid *CollisionLevelState::
|
||||
get_collider(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_colliders.size(), NULL);
|
||||
nassertr(has_collider(n), NULL);
|
||||
|
||||
return _colliders[n]._collider;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelState::get_collider_node
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CollisionNode *CollisionLevelState::
|
||||
get_collider_node(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_colliders.size(), NULL);
|
||||
nassertr(has_collider(n), NULL);
|
||||
|
||||
return _colliders[n]._node;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelState::get_collider_node_path
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE NodePath CollisionLevelState::
|
||||
get_collider_node_path(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_colliders.size(), NodePath::fail());
|
||||
nassertr(has_collider(n), NodePath::fail());
|
||||
|
||||
return _colliders[n]._node_path;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelState::get_local_bound
|
||||
// Access: Public
|
||||
// Description: Returns the bounding volume of the indicated
|
||||
// collider, transformed into the current node's
|
||||
// transform space.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const GeometricBoundingVolume *CollisionLevelState::
|
||||
get_local_bound(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_colliders.size(), NULL);
|
||||
nassertr(has_collider(n), NULL);
|
||||
nassertr(n >= 0 && n < (int)_local_bounds.size(), NULL);
|
||||
|
||||
// For whatever reason, the Intel compiler can't figure this line
|
||||
// out.
|
||||
//return _local_bounds[n];
|
||||
|
||||
// But it can figure out this equivalent line.
|
||||
return *(_local_bounds + n);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelState::get_parent_bound
|
||||
// Access: Public
|
||||
// Description: Returns the bounding volume of the indicated
|
||||
// collider, transformed into the previous node's
|
||||
// transform space, but not transformed by the current
|
||||
// node's transform. This is appropriate for testing
|
||||
// against the bounding volume of the current node
|
||||
// (which does not have its own transform applied to
|
||||
// it).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const GeometricBoundingVolume *CollisionLevelState::
|
||||
get_parent_bound(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_colliders.size(), NULL);
|
||||
nassertr(has_collider(n), NULL);
|
||||
nassertr(n >= 0 && n < (int)_parent_bounds.size(), NULL);
|
||||
|
||||
// But it can figure out this equivalent line.
|
||||
return *(_parent_bounds + n);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelState::omit_collider
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void CollisionLevelState::
|
||||
template<class MaskType>
|
||||
INLINE void CollisionLevelState<MaskType>::
|
||||
omit_collider(int n) {
|
||||
nassertv(n >= 0 && n < (int)_colliders.size());
|
||||
nassertv(has_collider(n));
|
||||
|
||||
_current.clear_bit(n);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelState::set_include_mask
|
||||
// Access: Public
|
||||
// Description: Specifies the mask that is applied to the into
|
||||
// CollideMask of nodes in the scene graph before
|
||||
// testing for bits in common with the from CollideMask
|
||||
// of colliders. This is normally all bits on, but you
|
||||
// may set it to some other mask to restrict certain
|
||||
// bits from consideration.
|
||||
//
|
||||
// This is used by the CollisionTraverser to restrict
|
||||
// collision with geometry except under the lowest level
|
||||
// of LOD.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void CollisionLevelState::
|
||||
set_include_mask(CollideMask include_mask) {
|
||||
_include_mask = include_mask;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelState::get_include_mask
|
||||
// Access: Public
|
||||
// Description: Returns the mask that is applied to the into
|
||||
// CollideMask of nodes in the scene graph before
|
||||
// testing for bits in common with the from CollideMask
|
||||
// of colliders. See set_include_mask().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CollideMask CollisionLevelState::
|
||||
get_include_mask() const {
|
||||
return _include_mask;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// Filename: collisionLevelState.cxx
|
||||
// Created by: drose (16Mar02)
|
||||
// Created by: drose (05Apr07)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
|
@ -17,211 +17,3 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "collisionLevelState.h"
|
||||
#include "collisionSolid.h"
|
||||
#include "collisionNode.h"
|
||||
#include "dcast.h"
|
||||
|
||||
PStatCollector CollisionLevelState::_node_volume_pcollector("Collision Volumes:PandaNode");
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelState::clear
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CollisionLevelState::
|
||||
clear() {
|
||||
_colliders.clear();
|
||||
_local_bounds.clear();
|
||||
_parent_bounds.clear();
|
||||
_current.clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelState::reserve
|
||||
// Access: Public
|
||||
// Description: Indicates an intention to add the indicated number of
|
||||
// colliders to the level state.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CollisionLevelState::
|
||||
reserve(int num_colliders) {
|
||||
nassertv(!CurrentMask::has_max_num_bits() ||
|
||||
num_colliders <= CurrentMask::get_max_num_bits());
|
||||
_colliders.reserve(num_colliders);
|
||||
_local_bounds.reserve(num_colliders);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelState::prepare_collider
|
||||
// Access: Public
|
||||
// Description: Adds the indicated Collider to the set of Colliders
|
||||
// in the current level state.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CollisionLevelState::
|
||||
prepare_collider(const ColliderDef &def, const NodePath &root) {
|
||||
int index = (int)_colliders.size();
|
||||
nassertv(!CurrentMask::has_max_num_bits() ||
|
||||
index <= CurrentMask::get_max_num_bits());
|
||||
_colliders.push_back(def);
|
||||
|
||||
CollisionSolid *collider = def._collider;
|
||||
CPT(BoundingVolume) bv = collider->get_bounds();
|
||||
if (!bv->is_of_type(GeometricBoundingVolume::get_class_type())) {
|
||||
_local_bounds.push_back((GeometricBoundingVolume *)NULL);
|
||||
} else {
|
||||
GeometricBoundingVolume *gbv;
|
||||
DCAST_INTO_V(gbv, bv->make_copy());
|
||||
|
||||
// TODO: we need to make this logic work in the new relative
|
||||
// world. The bounding volume should be extended by the object's
|
||||
// motion relative to each object it is considering a collision
|
||||
// with. That makes things complicated!
|
||||
/*
|
||||
if (def._delta != LVector3f::zero()) {
|
||||
// If the node has a delta, we have to include the starting
|
||||
// point in the volume as well.
|
||||
|
||||
// Strictly speaking, we should actually transform gbv backward
|
||||
// by the delta(), and extend by *that* volume, instead of
|
||||
// just extending by the single point at -get_velocity().
|
||||
// However, assuming the solids within a moving CollisionNode
|
||||
// tend to be near the origin, this will generally produce the
|
||||
// same results, and is much easier to compute.
|
||||
gbv->extend_by(LPoint3f(-def._delta));
|
||||
}
|
||||
*/
|
||||
|
||||
CPT(TransformState) rel_transform = def._node_path.get_transform(root.get_parent());
|
||||
gbv->xform(rel_transform->get_mat());
|
||||
_local_bounds.push_back(gbv);
|
||||
}
|
||||
|
||||
_current.set_bit(index);
|
||||
|
||||
_parent_bounds = _local_bounds;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelState::any_in_bounds
|
||||
// Access: Public
|
||||
// Description: Checks the bounding volume of the current node
|
||||
// against each of our colliders. Eliminates from the
|
||||
// current collider list any that are outside of the
|
||||
// bounding volume. Returns true if any colliders
|
||||
// remain, false if all of them fall outside this node's
|
||||
// bounding volume.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool CollisionLevelState::
|
||||
any_in_bounds() {
|
||||
#ifndef NDEBUG
|
||||
int indent_level = 0;
|
||||
if (collide_cat.is_spam()) {
|
||||
indent_level = _node_path.get_num_nodes() * 2;
|
||||
collide_cat.spam();
|
||||
indent(collide_cat.spam(false), indent_level)
|
||||
<< "Considering " << _node_path.get_node_path() << "\n";
|
||||
}
|
||||
#endif // NDEBUG
|
||||
|
||||
CPT(BoundingVolume) node_bv = node()->get_bounds();
|
||||
if (node_bv->is_of_type(GeometricBoundingVolume::get_class_type())) {
|
||||
const GeometricBoundingVolume *node_gbv;
|
||||
DCAST_INTO_R(node_gbv, node_bv, false);
|
||||
|
||||
int num_colliders = get_num_colliders();
|
||||
for (int c = 0; c < num_colliders; c++) {
|
||||
if (has_collider(c)) {
|
||||
CollisionNode *cnode = get_collider_node(c);
|
||||
bool is_in = false;
|
||||
|
||||
// Don't even bother testing the bounding volume if there are
|
||||
// no collide bits in common between our collider and this
|
||||
// node.
|
||||
CollideMask from_mask = cnode->get_from_collide_mask() & _include_mask;
|
||||
if (!(from_mask & node()->get_net_collide_mask()).is_zero()) {
|
||||
// There are bits in common, so go ahead and try the
|
||||
// bounding volume.
|
||||
const GeometricBoundingVolume *col_gbv =
|
||||
get_local_bound(c);
|
||||
if (col_gbv != (GeometricBoundingVolume *)NULL) {
|
||||
is_in = (node_gbv->contains(col_gbv) != 0);
|
||||
_node_volume_pcollector.add_level(1);
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (collide_cat.is_spam()) {
|
||||
collide_cat.spam();
|
||||
indent(collide_cat.spam(false), indent_level)
|
||||
<< "Comparing " << c << ": " << *col_gbv
|
||||
<< " to " << *node_gbv << ", is_in = " << is_in << "\n";
|
||||
}
|
||||
#endif // NDEBUG
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_in) {
|
||||
// This collider cannot intersect with any geometry at
|
||||
// this node or below.
|
||||
omit_collider(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (collide_cat.is_spam()) {
|
||||
int num_active_colliders = 0;
|
||||
int num_colliders = get_num_colliders();
|
||||
for (int c = 0; c < num_colliders; c++) {
|
||||
if (has_collider(c)) {
|
||||
num_active_colliders++;
|
||||
}
|
||||
}
|
||||
|
||||
collide_cat.spam();
|
||||
indent(collide_cat.spam(false), indent_level)
|
||||
<< _node_path.get_node_path() << " has " << num_active_colliders
|
||||
<< " interested colliders.\n";
|
||||
}
|
||||
#endif // NDEBUG
|
||||
return has_any_collider();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelState::apply_transform
|
||||
// Access: Public
|
||||
// Description: Applies the inverse transform from the current node,
|
||||
// if any, onto all the colliders in the level state.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CollisionLevelState::
|
||||
apply_transform() {
|
||||
// The "parent" bounds list remembers the bounds list of the
|
||||
// previous node.
|
||||
_parent_bounds = _local_bounds;
|
||||
|
||||
// Recompute the bounds list of this node (if we have a transform).
|
||||
const TransformState *node_transform = node()->get_transform();
|
||||
if (!node_transform->is_identity()) {
|
||||
CPT(TransformState) inv_transform =
|
||||
node_transform->invert_compose(TransformState::make_identity());
|
||||
const LMatrix4f &mat = inv_transform->get_mat();
|
||||
|
||||
// Now build the new bounding volumes list.
|
||||
BoundingVolumes new_bounds;
|
||||
|
||||
int num_colliders = get_num_colliders();
|
||||
new_bounds.reserve(num_colliders);
|
||||
for (int c = 0; c < num_colliders; c++) {
|
||||
if (!has_collider(c) ||
|
||||
get_local_bound(c) == (GeometricBoundingVolume *)NULL) {
|
||||
new_bounds.push_back((GeometricBoundingVolume *)NULL);
|
||||
} else {
|
||||
const GeometricBoundingVolume *old_bound = get_local_bound(c);
|
||||
GeometricBoundingVolume *new_bound =
|
||||
DCAST(GeometricBoundingVolume, old_bound->make_copy());
|
||||
new_bound->xform(mat);
|
||||
new_bounds.push_back(new_bound);
|
||||
}
|
||||
}
|
||||
|
||||
_local_bounds = new_bounds;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,93 +21,68 @@
|
|||
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "luse.h"
|
||||
#include "pointerToArray.h"
|
||||
#include "geometricBoundingVolume.h"
|
||||
#include "nodePath.h"
|
||||
#include "workingNodePath.h"
|
||||
#include "pointerTo.h"
|
||||
#include "plist.h"
|
||||
#include "pStatCollector.h"
|
||||
#include "collisionLevelStateBase.h"
|
||||
#include "collisionNode.h"
|
||||
#include "bitMask.h"
|
||||
|
||||
class CollisionSolid;
|
||||
class CollisionNode;
|
||||
#include "bitArray.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : CollisionLevelState
|
||||
// Description : This is the state information the
|
||||
// CollisionTraverser retains for each level during
|
||||
// traversal.
|
||||
//
|
||||
// This is the template class that specifies the
|
||||
// CurrentMask type: the type of bitmask that is used to
|
||||
// keep track of the set of active colliders for each
|
||||
// node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class CollisionLevelState {
|
||||
template<class MaskType>
|
||||
class CollisionLevelState : public CollisionLevelStateBase {
|
||||
public:
|
||||
class ColliderDef {
|
||||
public:
|
||||
CollisionSolid *_collider;
|
||||
CollisionNode *_node;
|
||||
NodePath _node_path;
|
||||
};
|
||||
|
||||
INLINE CollisionLevelState(const NodePath &node_path);
|
||||
INLINE CollisionLevelState(const CollisionLevelState &parent,
|
||||
INLINE CollisionLevelState(const CollisionLevelState<MaskType> &parent,
|
||||
PandaNode *child);
|
||||
INLINE CollisionLevelState(const CollisionLevelState ©);
|
||||
INLINE void operator = (const CollisionLevelState ©);
|
||||
INLINE CollisionLevelState(const CollisionLevelState<MaskType> ©);
|
||||
INLINE void operator = (const CollisionLevelState<MaskType> ©);
|
||||
|
||||
void clear();
|
||||
void reserve(int num_colliders);
|
||||
void prepare_collider(const ColliderDef &def, const NodePath &root);
|
||||
|
||||
INLINE static int get_max_colliders();
|
||||
INLINE void clear();
|
||||
INLINE void prepare_collider(const ColliderDef &def, const NodePath &root);
|
||||
|
||||
bool any_in_bounds();
|
||||
void apply_transform();
|
||||
|
||||
INLINE NodePath get_node_path() const;
|
||||
INLINE PandaNode *node() const;
|
||||
|
||||
INLINE int get_num_colliders() const;
|
||||
INLINE static bool has_max_colliders();
|
||||
INLINE static int get_max_colliders();
|
||||
|
||||
INLINE bool has_collider(int n) const;
|
||||
INLINE bool has_any_collider() const;
|
||||
|
||||
INLINE CollisionSolid *get_collider(int n) const;
|
||||
INLINE CollisionNode *get_collider_node(int n) const;
|
||||
INLINE NodePath get_collider_node_path(int n) const;
|
||||
INLINE const GeometricBoundingVolume *get_local_bound(int n) const;
|
||||
INLINE const GeometricBoundingVolume *get_parent_bound(int n) const;
|
||||
|
||||
INLINE void omit_collider(int n);
|
||||
|
||||
INLINE void set_include_mask(CollideMask include_mask);
|
||||
INLINE CollideMask get_include_mask() const;
|
||||
|
||||
private:
|
||||
// CurrentMask here is a locally-defined value that simply serves
|
||||
// to keep track of the colliders that are still interested in the
|
||||
// current node. Don't confuse it with CollideMask, which is a set
|
||||
// of user-defined bits that specify which CollisionSolids may
|
||||
// possibly intersect with each other.
|
||||
typedef BitMaskNative CurrentMask;
|
||||
|
||||
WorkingNodePath _node_path;
|
||||
|
||||
typedef PTA(ColliderDef) Colliders;
|
||||
Colliders _colliders;
|
||||
typedef MaskType CurrentMask;
|
||||
CurrentMask _current;
|
||||
CollideMask _include_mask;
|
||||
|
||||
typedef PTA(CPT(GeometricBoundingVolume)) BoundingVolumes;
|
||||
BoundingVolumes _local_bounds;
|
||||
BoundingVolumes _parent_bounds;
|
||||
|
||||
static PStatCollector _node_volume_pcollector;
|
||||
|
||||
friend class CollisionTraverser;
|
||||
};
|
||||
|
||||
#include "collisionLevelState.I"
|
||||
|
||||
// Now instantiate a pair of implementations of CollisionLevelState:
|
||||
// one that uses a word-at-a-time bitmask to track the active
|
||||
// colliders (and thus is limited to handling 32 or 64 colliders in a
|
||||
// given pass), and another that uses an infinite BitArray to track
|
||||
// these colliders (and thus has no particular limit).
|
||||
|
||||
typedef CollisionLevelState<BitMaskNative> CollisionLevelStateWord;
|
||||
typedef CollisionLevelState<BitArray> CollisionLevelStateArray;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,215 @@
|
|||
// Filename: collisionLevelStateBase.I
|
||||
// Created by: drose (16Mar02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelStateBase::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CollisionLevelStateBase::
|
||||
CollisionLevelStateBase(const NodePath &node_path) :
|
||||
_node_path(node_path),
|
||||
_include_mask(CollideMask::all_on())
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelStateBase::Constructor
|
||||
// Access: Public
|
||||
// Description: This constructor goes to the next child node in the
|
||||
// traversal.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CollisionLevelStateBase::
|
||||
CollisionLevelStateBase(const CollisionLevelStateBase &parent, PandaNode *child) :
|
||||
_node_path(parent._node_path, child),
|
||||
_colliders(parent._colliders),
|
||||
_include_mask(parent._include_mask),
|
||||
_local_bounds(parent._local_bounds)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelStateBase::Copy Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CollisionLevelStateBase::
|
||||
CollisionLevelStateBase(const CollisionLevelStateBase ©) :
|
||||
_node_path(copy._node_path),
|
||||
_colliders(copy._colliders),
|
||||
_include_mask(copy._include_mask),
|
||||
_local_bounds(copy._local_bounds),
|
||||
_parent_bounds(copy._parent_bounds)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelStateBase::Copy Assignment Operator
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void CollisionLevelStateBase::
|
||||
operator = (const CollisionLevelStateBase ©) {
|
||||
_node_path = copy._node_path;
|
||||
_colliders = copy._colliders;
|
||||
_include_mask = copy._include_mask;
|
||||
_local_bounds = copy._local_bounds;
|
||||
_parent_bounds = copy._parent_bounds;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelStateBase::get_node_path
|
||||
// Access: Public
|
||||
// Description: Returns the NodePath representing the node instance
|
||||
// we have traversed to.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE NodePath CollisionLevelStateBase::
|
||||
get_node_path() const {
|
||||
return _node_path.get_node_path();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelStateBase::node
|
||||
// Access: Public
|
||||
// Description: Returns the PandaNode pointer of the node we have
|
||||
// traversed to.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PandaNode *CollisionLevelStateBase::
|
||||
node() const {
|
||||
return _node_path.node();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelStateBase::get_num_colliders
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int CollisionLevelStateBase::
|
||||
get_num_colliders() const {
|
||||
return _colliders.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelStateBase::get_collider
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CollisionSolid *CollisionLevelStateBase::
|
||||
get_collider(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_colliders.size(), NULL);
|
||||
|
||||
return _colliders[n]._collider;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelStateBase::get_collider_node
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CollisionNode *CollisionLevelStateBase::
|
||||
get_collider_node(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_colliders.size(), NULL);
|
||||
|
||||
return _colliders[n]._node;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelStateBase::get_collider_node_path
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE NodePath CollisionLevelStateBase::
|
||||
get_collider_node_path(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_colliders.size(), NodePath::fail());
|
||||
|
||||
return _colliders[n]._node_path;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelStateBase::get_local_bound
|
||||
// Access: Public
|
||||
// Description: Returns the bounding volume of the indicated
|
||||
// collider, transformed into the current node's
|
||||
// transform space.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const GeometricBoundingVolume *CollisionLevelStateBase::
|
||||
get_local_bound(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_colliders.size(), NULL);
|
||||
nassertr(n >= 0 && n < (int)_local_bounds.size(), NULL);
|
||||
|
||||
// For whatever reason, the Intel compiler can't figure this line
|
||||
// out.
|
||||
//return _local_bounds[n];
|
||||
|
||||
// But it can figure out this equivalent line.
|
||||
return *(_local_bounds + n);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelStateBase::get_parent_bound
|
||||
// Access: Public
|
||||
// Description: Returns the bounding volume of the indicated
|
||||
// collider, transformed into the previous node's
|
||||
// transform space, but not transformed by the current
|
||||
// node's transform. This is appropriate for testing
|
||||
// against the bounding volume of the current node
|
||||
// (which does not have its own transform applied to
|
||||
// it).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const GeometricBoundingVolume *CollisionLevelStateBase::
|
||||
get_parent_bound(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_colliders.size(), NULL);
|
||||
nassertr(n >= 0 && n < (int)_parent_bounds.size(), NULL);
|
||||
|
||||
// But it can figure out this equivalent line.
|
||||
return *(_parent_bounds + n);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelStateBase::set_include_mask
|
||||
// Access: Public
|
||||
// Description: Specifies the mask that is applied to the into
|
||||
// CollideMask of nodes in the scene graph before
|
||||
// testing for bits in common with the from CollideMask
|
||||
// of colliders. This is normally all bits on, but you
|
||||
// may set it to some other mask to restrict certain
|
||||
// bits from consideration.
|
||||
//
|
||||
// This is used by the CollisionTraverser to restrict
|
||||
// collision with geometry except under the lowest level
|
||||
// of LOD.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void CollisionLevelStateBase::
|
||||
set_include_mask(CollideMask include_mask) {
|
||||
_include_mask = include_mask;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelStateBase::get_include_mask
|
||||
// Access: Public
|
||||
// Description: Returns the mask that is applied to the into
|
||||
// CollideMask of nodes in the scene graph before
|
||||
// testing for bits in common with the from CollideMask
|
||||
// of colliders. See set_include_mask().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CollideMask CollisionLevelStateBase::
|
||||
get_include_mask() const {
|
||||
return _include_mask;
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
// Filename: collisionLevelStateBase.cxx
|
||||
// Created by: drose (16Mar02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "collisionLevelStateBase.h"
|
||||
#include "collisionSolid.h"
|
||||
#include "collisionNode.h"
|
||||
#include "dcast.h"
|
||||
|
||||
PStatCollector CollisionLevelStateBase::_node_volume_pcollector("Collision Volumes:PandaNode");
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelStateBase::clear
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CollisionLevelStateBase::
|
||||
clear() {
|
||||
_colliders.clear();
|
||||
_local_bounds.clear();
|
||||
_parent_bounds.clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelStateBase::reserve
|
||||
// Access: Public
|
||||
// Description: Indicates an intention to add the indicated number of
|
||||
// colliders to the level state.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CollisionLevelStateBase::
|
||||
reserve(int num_colliders) {
|
||||
_colliders.reserve(num_colliders);
|
||||
_local_bounds.reserve(num_colliders);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionLevelStateBase::prepare_collider
|
||||
// Access: Public
|
||||
// Description: Adds the indicated Collider to the set of Colliders
|
||||
// in the current level state.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CollisionLevelStateBase::
|
||||
prepare_collider(const ColliderDef &def, const NodePath &root) {
|
||||
_colliders.push_back(def);
|
||||
|
||||
CollisionSolid *collider = def._collider;
|
||||
CPT(BoundingVolume) bv = collider->get_bounds();
|
||||
if (!bv->is_of_type(GeometricBoundingVolume::get_class_type())) {
|
||||
_local_bounds.push_back((GeometricBoundingVolume *)NULL);
|
||||
} else {
|
||||
GeometricBoundingVolume *gbv;
|
||||
DCAST_INTO_V(gbv, bv->make_copy());
|
||||
|
||||
// TODO: we need to make this logic work in the new relative
|
||||
// world. The bounding volume should be extended by the object's
|
||||
// motion relative to each object it is considering a collision
|
||||
// with. That makes things complicated!
|
||||
/*
|
||||
if (def._delta != LVector3f::zero()) {
|
||||
// If the node has a delta, we have to include the starting
|
||||
// point in the volume as well.
|
||||
|
||||
// Strictly speaking, we should actually transform gbv backward
|
||||
// by the delta(), and extend by *that* volume, instead of
|
||||
// just extending by the single point at -get_velocity().
|
||||
// However, assuming the solids within a moving CollisionNode
|
||||
// tend to be near the origin, this will generally produce the
|
||||
// same results, and is much easier to compute.
|
||||
gbv->extend_by(LPoint3f(-def._delta));
|
||||
}
|
||||
*/
|
||||
|
||||
CPT(TransformState) rel_transform = def._node_path.get_transform(root.get_parent());
|
||||
gbv->xform(rel_transform->get_mat());
|
||||
_local_bounds.push_back(gbv);
|
||||
}
|
||||
|
||||
_parent_bounds = _local_bounds;
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
// Filename: collisionLevelStateBase.h
|
||||
// Created by: drose (16Mar02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef COLLISIONLEVELSTATEBASE_H
|
||||
#define COLLISIONLEVELSTATEBASE_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "luse.h"
|
||||
#include "pointerToArray.h"
|
||||
#include "geometricBoundingVolume.h"
|
||||
#include "nodePath.h"
|
||||
#include "workingNodePath.h"
|
||||
#include "pointerTo.h"
|
||||
#include "plist.h"
|
||||
#include "pStatCollector.h"
|
||||
#include "bitMask.h"
|
||||
|
||||
class CollisionSolid;
|
||||
class CollisionNode;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : CollisionLevelStateBase
|
||||
// Description : This is the state information the
|
||||
// CollisionTraverser retains for each level during
|
||||
// traversal.
|
||||
//
|
||||
// The CollisionLevelStateBase is the non-template base
|
||||
// class. The template version further specifies this
|
||||
// on CurrentMask type.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class CollisionLevelStateBase {
|
||||
public:
|
||||
class ColliderDef {
|
||||
public:
|
||||
CollisionSolid *_collider;
|
||||
CollisionNode *_node;
|
||||
NodePath _node_path;
|
||||
};
|
||||
|
||||
INLINE CollisionLevelStateBase(const NodePath &node_path);
|
||||
INLINE CollisionLevelStateBase(const CollisionLevelStateBase &parent,
|
||||
PandaNode *child);
|
||||
INLINE CollisionLevelStateBase(const CollisionLevelStateBase ©);
|
||||
INLINE void operator = (const CollisionLevelStateBase ©);
|
||||
|
||||
void clear();
|
||||
void reserve(int num_colliders);
|
||||
void prepare_collider(const ColliderDef &def, const NodePath &root);
|
||||
|
||||
INLINE NodePath get_node_path() const;
|
||||
INLINE PandaNode *node() const;
|
||||
|
||||
INLINE int get_num_colliders() const;
|
||||
|
||||
INLINE CollisionSolid *get_collider(int n) const;
|
||||
INLINE CollisionNode *get_collider_node(int n) const;
|
||||
INLINE NodePath get_collider_node_path(int n) const;
|
||||
INLINE const GeometricBoundingVolume *get_local_bound(int n) const;
|
||||
INLINE const GeometricBoundingVolume *get_parent_bound(int n) const;
|
||||
|
||||
INLINE void set_include_mask(CollideMask include_mask);
|
||||
INLINE CollideMask get_include_mask() const;
|
||||
|
||||
protected:
|
||||
WorkingNodePath _node_path;
|
||||
|
||||
typedef PTA(ColliderDef) Colliders;
|
||||
Colliders _colliders;
|
||||
CollideMask _include_mask;
|
||||
|
||||
typedef PTA(CPT(GeometricBoundingVolume)) BoundingVolumes;
|
||||
BoundingVolumes _local_bounds;
|
||||
BoundingVolumes _parent_bounds;
|
||||
|
||||
static PStatCollector _node_volume_pcollector;
|
||||
|
||||
friend class CollisionTraverser;
|
||||
};
|
||||
|
||||
#include "collisionLevelStateBase.I"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -275,22 +275,43 @@ traverse(const NodePath &root) {
|
|||
get_recorder()->begin_traversal();
|
||||
}
|
||||
#endif // DO_COLLISION_RECORDING
|
||||
|
||||
LevelStates level_states;
|
||||
prepare_colliders(level_states, root);
|
||||
|
||||
Handlers::iterator hi;
|
||||
for (hi = _handlers.begin(); hi != _handlers.end(); ++hi) {
|
||||
(*hi).first->begin_group();
|
||||
}
|
||||
|
||||
// Make a number of passes, one for each group of 32 Colliders (or
|
||||
// whatever number of bits we have available in CurrentMask).
|
||||
for (size_t pass = 0; pass < level_states.size(); ++pass) {
|
||||
#ifdef DO_PSTATS
|
||||
PStatTimer pass_timer(get_pass_collector(pass));
|
||||
#endif
|
||||
r_traverse(level_states[pass], pass);
|
||||
bool do_array_pass = true;
|
||||
if (_colliders.size() <= CollisionLevelStateWord::get_max_colliders() ||
|
||||
!allow_collider_bitarray) {
|
||||
// Use the word-at-a-time traverser, which might need to make
|
||||
// several passes.
|
||||
LevelStatesWord level_states;
|
||||
prepare_colliders_word(level_states, root);
|
||||
|
||||
if (level_states.size() == 1 || !allow_collider_bitarray) {
|
||||
do_array_pass = false;
|
||||
// Make a number of passes, one for each group of 32 Colliders (or
|
||||
// whatever number of bits we have available in CurrentMask).
|
||||
for (size_t pass = 0; pass < level_states.size(); ++pass) {
|
||||
#ifdef DO_PSTATS
|
||||
PStatTimer pass_timer(get_pass_collector(pass));
|
||||
#endif
|
||||
r_traverse_word(level_states[pass], pass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (do_array_pass) {
|
||||
// Use the array-at-a-time traverser, which can do the whole thing
|
||||
// at once, even if there are many colliders.
|
||||
CollisionLevelStateArray level_state(root);
|
||||
prepare_colliders_array(level_state, root);
|
||||
|
||||
#ifdef DO_PSTATS
|
||||
PStatTimer pass_timer(get_pass_collector(0));
|
||||
#endif
|
||||
r_traverse_array(level_state);
|
||||
}
|
||||
|
||||
hi = _handlers.begin();
|
||||
|
|
@ -309,7 +330,7 @@ traverse(const NodePath &root) {
|
|||
}
|
||||
#endif // DO_COLLISION_RECORDING
|
||||
|
||||
CollisionLevelState::_node_volume_pcollector.flush_level();
|
||||
CollisionLevelStateBase::_node_volume_pcollector.flush_level();
|
||||
_cnode_volume_pcollector.flush_level();
|
||||
_gnode_volume_pcollector.flush_level();
|
||||
_geom_volume_pcollector.flush_level();
|
||||
|
|
@ -459,17 +480,22 @@ write(ostream &out, int indent_level) const {
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionTraverser::prepare_colliders
|
||||
// Function: CollisionTraverser::prepare_colliders_word
|
||||
// Access: Private
|
||||
// Description:
|
||||
// Description: Fills up the set of LevelStates corresponding to the
|
||||
// active colliders in use.
|
||||
//
|
||||
// This flavor uses a CollisionLevelStateWord, which is
|
||||
// limited to a certain number of colliders per pass
|
||||
// (typically 32).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CollisionTraverser::
|
||||
prepare_colliders(CollisionTraverser::LevelStates &level_states,
|
||||
const NodePath &root) {
|
||||
prepare_colliders_word(CollisionTraverser::LevelStatesWord &level_states,
|
||||
const NodePath &root) {
|
||||
int num_colliders = _colliders.size();
|
||||
int max_colliders = CollisionLevelState::get_max_colliders();
|
||||
int max_colliders = CollisionLevelStateWord::get_max_colliders();
|
||||
|
||||
CollisionLevelState level_state(root);
|
||||
CollisionLevelStateWord level_state(root);
|
||||
// This reserve() call is only correct if there is exactly one solid
|
||||
// per collider added to the traverser, which is the normal case.
|
||||
// If there is more than one solid in any of the colliders, this
|
||||
|
|
@ -497,7 +523,7 @@ prepare_colliders(CollisionTraverser::LevelStates &level_states,
|
|||
(*oci)._in_graph = true;
|
||||
CollisionNode *cnode = DCAST(CollisionNode, cnode_path.node());
|
||||
|
||||
CollisionLevelState::ColliderDef def;
|
||||
CollisionLevelStateWord::ColliderDef def;
|
||||
def._node = cnode;
|
||||
def._node_path = cnode_path;
|
||||
|
||||
|
|
@ -528,12 +554,12 @@ prepare_colliders(CollisionTraverser::LevelStates &level_states,
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionTraverser::r_traverse
|
||||
// Function: CollisionTraverser::r_traverse_word
|
||||
// Access: Private
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CollisionTraverser::
|
||||
r_traverse(CollisionLevelState &level_state, size_t pass) {
|
||||
r_traverse_word(CollisionLevelStateWord &level_state, size_t pass) {
|
||||
if (!level_state.any_in_bounds()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -629,8 +655,8 @@ r_traverse(CollisionLevelState &level_state, size_t pass) {
|
|||
// visible child.
|
||||
int index = node->get_visible_child();
|
||||
if (index >= 0 && index < node->get_num_children()) {
|
||||
CollisionLevelState next_state(level_state, node->get_child(index));
|
||||
r_traverse(next_state, pass);
|
||||
CollisionLevelStateWord next_state(level_state, node->get_child(index));
|
||||
r_traverse_word(next_state, pass);
|
||||
}
|
||||
|
||||
} else if (node->is_lod_node()) {
|
||||
|
|
@ -643,20 +669,214 @@ r_traverse(CollisionLevelState &level_state, size_t pass) {
|
|||
int index = DCAST(LODNode, node)->get_lowest_switch();
|
||||
int num_children = node->get_num_children();
|
||||
for (int i = 0; i < num_children; ++i) {
|
||||
CollisionLevelState next_state(level_state, node->get_child(i));
|
||||
CollisionLevelStateWord next_state(level_state, node->get_child(i));
|
||||
if (i != index) {
|
||||
next_state.set_include_mask(next_state.get_include_mask() &
|
||||
~GeomNode::get_default_collide_mask());
|
||||
}
|
||||
r_traverse(next_state, pass);
|
||||
r_traverse_word(next_state, pass);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Otherwise, visit all the children.
|
||||
int num_children = node->get_num_children();
|
||||
for (int i = 0; i < num_children; ++i) {
|
||||
CollisionLevelState next_state(level_state, node->get_child(i));
|
||||
r_traverse(next_state, pass);
|
||||
CollisionLevelStateWord next_state(level_state, node->get_child(i));
|
||||
r_traverse_word(next_state, pass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionTraverser::prepare_colliders_array
|
||||
// Access: Private
|
||||
// Description: Fills up the set of LevelStates corresponding to the
|
||||
// active colliders in use.
|
||||
//
|
||||
// This flavor uses a CollisionLevelStateArray, which
|
||||
// has no limit in the number of colliders it can handle
|
||||
// in one pass.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CollisionTraverser::
|
||||
prepare_colliders_array(CollisionLevelStateArray &level_state,
|
||||
const NodePath &root) {
|
||||
int num_colliders = _colliders.size();
|
||||
// This reserve() call is only correct if there is exactly one solid
|
||||
// per collider added to the traverser, which is the normal case.
|
||||
// If there is more than one solid in any of the colliders, this
|
||||
// reserve() call won't reserve enough, but the code is otherwise
|
||||
// correct.
|
||||
level_state.reserve(num_colliders);
|
||||
|
||||
OrderedColliders sorted = _ordered_colliders;
|
||||
sort(sorted.begin(), sorted.end(), SortByColliderSort());
|
||||
|
||||
OrderedColliders::iterator oci;
|
||||
for (oci = sorted.begin(); oci != sorted.end(); ++oci) {
|
||||
NodePath cnode_path = (*oci)._node_path;
|
||||
|
||||
if (!cnode_path.is_same_graph(root)) {
|
||||
if ((*oci)._in_graph) {
|
||||
// Only report this warning once.
|
||||
collide_cat.info()
|
||||
<< "Collider " << cnode_path
|
||||
<< " is not in scene graph. Ignoring.\n";
|
||||
(*oci)._in_graph = false;
|
||||
}
|
||||
|
||||
} else {
|
||||
(*oci)._in_graph = true;
|
||||
CollisionNode *cnode = DCAST(CollisionNode, cnode_path.node());
|
||||
|
||||
CollisionLevelStateArray::ColliderDef def;
|
||||
def._node = cnode;
|
||||
def._node_path = cnode_path;
|
||||
|
||||
int num_solids = cnode->get_num_solids();
|
||||
for (int s = 0; s < num_solids; ++s) {
|
||||
CollisionSolid *collider = cnode->get_solid(s);
|
||||
def._collider = collider;
|
||||
level_state.prepare_collider(def, root);
|
||||
}
|
||||
}
|
||||
|
||||
--num_colliders;
|
||||
nassertv(num_colliders >= 0);
|
||||
}
|
||||
|
||||
nassertv(num_colliders == 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionTraverser::r_traverse_array
|
||||
// Access: Private
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CollisionTraverser::
|
||||
r_traverse_array(CollisionLevelStateArray &level_state) {
|
||||
if (!level_state.any_in_bounds()) {
|
||||
return;
|
||||
}
|
||||
level_state.apply_transform();
|
||||
|
||||
PandaNode *node = level_state.node();
|
||||
if (node->is_exact_type(CollisionNode::get_class_type())) {
|
||||
CollisionNode *cnode;
|
||||
DCAST_INTO_V(cnode, node);
|
||||
CPT(BoundingVolume) node_bv = cnode->get_bounds();
|
||||
const GeometricBoundingVolume *node_gbv = NULL;
|
||||
if (node_bv->is_of_type(GeometricBoundingVolume::get_class_type())) {
|
||||
DCAST_INTO_V(node_gbv, node_bv);
|
||||
}
|
||||
|
||||
CollisionEntry entry;
|
||||
entry._into_node = cnode;
|
||||
entry._into_node_path = level_state.get_node_path();
|
||||
if (_respect_prev_transform) {
|
||||
entry._flags |= CollisionEntry::F_respect_prev_transform;
|
||||
}
|
||||
|
||||
int num_colliders = level_state.get_num_colliders();
|
||||
for (int c = 0; c < num_colliders; ++c) {
|
||||
if (level_state.has_collider(c)) {
|
||||
entry._from_node = level_state.get_collider_node(c);
|
||||
|
||||
if ((entry._from_node->get_from_collide_mask() &
|
||||
cnode->get_into_collide_mask()) != 0) {
|
||||
#ifdef DO_PSTATS
|
||||
PStatTimer collide_timer(_solid_collide_collectors[0]);
|
||||
#endif
|
||||
entry._from_node_path = level_state.get_collider_node_path(c);
|
||||
entry._from = level_state.get_collider(c);
|
||||
|
||||
compare_collider_to_node(
|
||||
entry,
|
||||
level_state.get_parent_bound(c),
|
||||
level_state.get_local_bound(c),
|
||||
node_gbv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (node->is_geom_node()) {
|
||||
#ifndef NDEBUG
|
||||
if (collide_cat.is_spam()) {
|
||||
collide_cat.spam()
|
||||
<< "Reached " << *node << "\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
GeomNode *gnode;
|
||||
DCAST_INTO_V(gnode, node);
|
||||
CPT(BoundingVolume) node_bv = gnode->get_bounds();
|
||||
const GeometricBoundingVolume *node_gbv = NULL;
|
||||
if (node_bv->is_of_type(GeometricBoundingVolume::get_class_type())) {
|
||||
DCAST_INTO_V(node_gbv, node_bv);
|
||||
}
|
||||
|
||||
CollisionEntry entry;
|
||||
entry._into_node = gnode;
|
||||
entry._into_node_path = level_state.get_node_path();
|
||||
if (_respect_prev_transform) {
|
||||
entry._flags |= CollisionEntry::F_respect_prev_transform;
|
||||
}
|
||||
|
||||
int num_colliders = level_state.get_num_colliders();
|
||||
for (int c = 0; c < num_colliders; ++c) {
|
||||
if (level_state.has_collider(c)) {
|
||||
entry._from_node = level_state.get_collider_node(c);
|
||||
|
||||
if ((entry._from_node->get_from_collide_mask() &
|
||||
gnode->get_into_collide_mask()) != 0) {
|
||||
#ifdef DO_PSTATS
|
||||
PStatTimer collide_timer(_solid_collide_collectors[0]);
|
||||
#endif
|
||||
entry._from_node_path = level_state.get_collider_node_path(c);
|
||||
entry._from = level_state.get_collider(c);
|
||||
|
||||
compare_collider_to_geom_node(
|
||||
entry,
|
||||
level_state.get_parent_bound(c),
|
||||
level_state.get_local_bound(c),
|
||||
node_gbv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (node->has_single_child_visibility()) {
|
||||
// If it's a switch node or sequence node, visit just the one
|
||||
// visible child.
|
||||
int index = node->get_visible_child();
|
||||
if (index >= 0 && index < node->get_num_children()) {
|
||||
CollisionLevelStateArray next_state(level_state, node->get_child(index));
|
||||
r_traverse_array(next_state);
|
||||
}
|
||||
|
||||
} else if (node->is_lod_node()) {
|
||||
// If it's an LODNode, visit the lowest level of detail with all
|
||||
// bits, allowing collision with geometry under the lowest level
|
||||
// of default; and visit all other levels without
|
||||
// GeomNode::get_default_collide_mask(), allowing only collision
|
||||
// with CollisionNodes and special geometry under higher levels of
|
||||
// detail.
|
||||
int index = DCAST(LODNode, node)->get_lowest_switch();
|
||||
int num_children = node->get_num_children();
|
||||
for (int i = 0; i < num_children; ++i) {
|
||||
CollisionLevelStateArray next_state(level_state, node->get_child(i));
|
||||
if (i != index) {
|
||||
next_state.set_include_mask(next_state.get_include_mask() &
|
||||
~GeomNode::get_default_collide_mask());
|
||||
}
|
||||
r_traverse_array(next_state);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Otherwise, visit all the children.
|
||||
int num_children = node->get_num_children();
|
||||
for (int i = 0; i < num_children; ++i) {
|
||||
CollisionLevelStateArray next_state(level_state, node->get_child(i));
|
||||
r_traverse_array(next_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,10 +81,12 @@ PUBLISHED:
|
|||
void write(ostream &out, int indent_level) const;
|
||||
|
||||
private:
|
||||
typedef pvector<CollisionLevelState> LevelStates;
|
||||
void prepare_colliders(LevelStates &level_states, const NodePath &root);
|
||||
typedef pvector<CollisionLevelStateWord> LevelStatesWord;
|
||||
void prepare_colliders_word(LevelStatesWord &level_states, const NodePath &root);
|
||||
void r_traverse_word(CollisionLevelStateWord &level_state, size_t pass);
|
||||
|
||||
void r_traverse(CollisionLevelState &level_state, size_t pass);
|
||||
void prepare_colliders_array(CollisionLevelStateArray &level_state, const NodePath &root);
|
||||
void r_traverse_array(CollisionLevelStateArray &level_state);
|
||||
|
||||
void compare_collider_to_node(CollisionEntry &entry,
|
||||
const GeometricBoundingVolume *from_parent_gbv,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,13 @@ ConfigVariableBool respect_effective_normal
|
|||
"collision solids (including polygons and planes) use their actual "
|
||||
"normal for intersection and physics tests."));
|
||||
|
||||
ConfigVariableBool allow_collider_bitarray
|
||||
("allow-collider-bitarray", true,
|
||||
PRC_DESC("Set this true to enable the use of a BitArray to manage many "
|
||||
"colliders added to a single traverser in one pass. If this is "
|
||||
"false, a finite BitMask is always used instead, which is faster "
|
||||
"per node visited, but may require multiple passes."));
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: init_libcollide
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ NotifyCategoryDecl(collide, EXPCL_PANDA, EXPTP_PANDA);
|
|||
|
||||
extern EXPCL_PANDA ConfigVariableBool respect_prev_transform;
|
||||
extern EXPCL_PANDA ConfigVariableBool respect_effective_normal;
|
||||
extern EXPCL_PANDA ConfigVariableBool allow_collider_bitarray;
|
||||
|
||||
extern EXPCL_PANDA void init_libcollide();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue