a few more changes to ubode ( STILL BAD ON LINUX )

This commit is contained in:
UbitUmarov
2022-07-18 19:45:56 +01:00
parent 03c900cdcf
commit e790d36bb8
5 changed files with 455 additions and 485 deletions
@@ -20,133 +20,133 @@
#ifndef __OPC_BASEMODEL_H__
#define __OPC_BASEMODEL_H__
//! Model creation structure
struct OPCODE_API OPCODECREATE
{
//! Constructor
OPCODECREATE();
//! Model creation structure
struct OPCODE_API OPCODECREATE
{
//! Constructor
OPCODECREATE();
MeshInterface* mIMesh; //!< Mesh interface (access to triangles & vertices) (*)
BuildSettings mSettings; //!< Builder's settings
bool mKeepOriginal; //!< true => keep a copy of the original tree (debug purpose)
bool mCanRemap; //!< true => allows OPCODE to reorganize client arrays
MeshInterface* mIMesh; //!< Mesh interface (access to triangles & vertices) (*)
BuildSettings mSettings; //!< Builder's settings
bool mKeepOriginal; //!< true => keep a copy of the original tree (debug purpose)
bool mCanRemap; //!< true => allows OPCODE to reorganize client arrays
// (*) This pointer is saved internally and used by OPCODE until collision structures are released,
// so beware of the object's lifetime.
};
// (*) This pointer is saved internally and used by OPCODE until collision structures are released,
// so beware of the object's lifetime.
};
enum ModelFlag
{
OPC_SINGLE_NODE = (1<<2) //!< Special case for 1-node models
};
enum ModelFlag
{
OPC_SINGLE_NODE = (1 << 2) //!< Special case for 1-node models
};
class OPCODE_API BaseModel
{
public:
// Constructor/Destructor
BaseModel();
virtual ~BaseModel();
class OPCODE_API BaseModel
{
public:
// Constructor/Destructor
BaseModel();
virtual ~BaseModel();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Builds a collision model.
* \param create [in] model creation structure
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual bool Build(const OPCODECREATE& create) = 0;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Builds a collision model.
* \param create [in] model creation structure
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual bool Build(const OPCODECREATE& create) = 0;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the number of bytes used by the tree.
* \return amount of bytes used
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual udword GetUsedBytes() const = 0;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the number of bytes used by the tree.
* \return amount of bytes used
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual udword GetUsedBytes() const = 0;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Refits the collision model. This can be used to handle dynamic meshes. Usage is:
* 1. modify your mesh vertices (keep the topology constant!)
* 2. refit the tree (call this method)
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual bool Refit();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Refits the collision model. This can be used to handle dynamic meshes. Usage is:
* 1. modify your mesh vertices (keep the topology constant!)
* 2. refit the tree (call this method)
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual bool Refit();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the source tree.
* \return generic tree
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ const AABBTree* GetSourceTree() const { return mSource; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the source tree.
* \return generic tree
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ const AABBTree* GetSourceTree() const { return mSource; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the tree.
* \return the collision tree
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ const AABBOptimizedTree* GetTree() const { return mTree; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the tree.
* \return the collision tree
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ const AABBOptimizedTree* GetTree() const { return mTree; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the tree.
* \return the collision tree
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ AABBOptimizedTree* GetTree() { return mTree; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the tree.
* \return the collision tree
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ AABBOptimizedTree* GetTree() { return mTree; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the number of nodes in the tree.
* Should be 2*N-1 for normal trees and N-1 for optimized ones.
* \return number of nodes
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetNbNodes() const { return mTree->GetNbNodes(); }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the number of nodes in the tree.
* Should be 2*N-1 for normal trees and N-1 for optimized ones.
* \return number of nodes
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetNbNodes() const { return mTree->GetNbNodes(); }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks whether the model has a single node or not. This special case must be handled separately.
* \return true if the model has only 1 node
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL HasSingleNode() const { return mModelCode & OPC_SINGLE_NODE; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks whether the model has a single node or not. This special case must be handled separately.
* \return true if the model has only 1 node
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL HasSingleNode() const { return mModelCode & OPC_SINGLE_NODE; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the model's code.
* \return model's code
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetModelCode() const { return mModelCode; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the model's code.
* \return model's code
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetModelCode() const { return mModelCode; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the mesh interface.
* \return mesh interface
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ const MeshInterface* GetMeshInterface() const { return mIMesh; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the mesh interface.
* \return mesh interface
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ const MeshInterface* GetMeshInterface() const { return mIMesh; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Sets the mesh interface.
* \param imesh [in] mesh interface
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetMeshInterface(const MeshInterface* imesh) { mIMesh = imesh; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Sets the mesh interface.
* \param imesh [in] mesh interface
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetMeshInterface(const MeshInterface* imesh) { mIMesh = imesh; }
protected:
const MeshInterface* mIMesh; //!< User-defined mesh interface
udword mModelCode; //!< Model code = combination of ModelFlag(s)
AABBTree* mSource; //!< Original source tree
AABBOptimizedTree* mTree; //!< Optimized tree owned by the model
// Internal methods
void ReleaseBase();
bool CreateTree();
};
protected:
const MeshInterface* mIMesh; //!< User-defined mesh interface
udword mModelCode; //!< Model code = combination of ModelFlag(s)
AABBTree* mSource; //!< Original source tree
AABBOptimizedTree* mTree; //!< Optimized tree owned by the model
// Internal methods
void ReleaseBase();
bool CreateTree();
};
#endif //__OPC_BASEMODEL_H__
@@ -20,157 +20,155 @@
#ifndef __OPC_COLLIDER_H__
#define __OPC_COLLIDER_H__
enum CollisionFlag
{
OPC_FIRST_CONTACT = (1<<0), //!< Report all contacts (false) or only first one (true)
OPC_TEMPORAL_COHERENCE = (1<<1), //!< Use temporal coherence or not
OPC_CONTACT = (1<<2), //!< Final contact status after a collision query
OPC_TEMPORAL_HIT = (1<<3), //!< There has been an early exit due to temporal coherence
OPC_NO_PRIMITIVE_TESTS = (1<<4), //!< Keep or discard primitive-bv tests in leaf nodes (volume-mesh queries)
enum CollisionFlag
{
OPC_FIRST_CONTACT = (1 << 0), //!< Report all contacts (false) or only first one (true)
OPC_TEMPORAL_COHERENCE = (1 << 1), //!< Use temporal coherence or not
OPC_CONTACT = (1 << 2), //!< Final contact status after a collision query
OPC_TEMPORAL_HIT = (1 << 3), //!< There has been an early exit due to temporal coherence
OPC_NO_PRIMITIVE_TESTS = (1 << 4), //!< Keep or discard primitive-bv tests in leaf nodes (volume-mesh queries)
OPC_CONTACT_FOUND = OPC_FIRST_CONTACT | OPC_CONTACT,
OPC_TEMPORAL_CONTACT = OPC_TEMPORAL_HIT | OPC_CONTACT,
OPC_CONTACT_FOUND = OPC_FIRST_CONTACT | OPC_CONTACT,
OPC_TEMPORAL_CONTACT = OPC_TEMPORAL_HIT | OPC_CONTACT,
OPC_FORCE_DWORD = 0x7fffffff
};
OPC_FORCE_DWORD = 0x7fffffff
};
class OPCODE_API Collider
{
public:
// Constructor / Destructor
Collider();
virtual ~Collider();
class OPCODE_API Collider
{
public:
// Constructor / Destructor
Collider();
virtual ~Collider();
// Collision report
// Collision report
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the last collision status after a collision query.
* \return true if a collision occured
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL GetContactStatus() const { return mFlags & OPC_CONTACT; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the last collision status after a collision query.
* \return true if a collision occured
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL GetContactStatus() const { return mFlags & OPC_CONTACT; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the "first contact" mode.
* \return true if "first contact" mode is on
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL FirstContactEnabled() const { return mFlags & OPC_FIRST_CONTACT; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the "first contact" mode.
* \return true if "first contact" mode is on
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL FirstContactEnabled() const { return mFlags & OPC_FIRST_CONTACT; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the temporal coherence mode.
* \return true if temporal coherence is on
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL TemporalCoherenceEnabled() const { return mFlags & OPC_TEMPORAL_COHERENCE; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the temporal coherence mode.
* \return true if temporal coherence is on
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL TemporalCoherenceEnabled() const { return mFlags & OPC_TEMPORAL_COHERENCE; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks a first contact has already been found.
* \return true if a first contact has been found and we can stop a query
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL ContactFound() const { return (mFlags&OPC_CONTACT_FOUND) == OPC_CONTACT_FOUND; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks a first contact has already been found.
* \return true if a first contact has been found and we can stop a query
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL ContactFound() const { return (mFlags&OPC_CONTACT_FOUND)==OPC_CONTACT_FOUND; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks there's been an early exit due to temporal coherence;
* \return true if a temporal hit has occured
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL TemporalHit() const { return mFlags & OPC_TEMPORAL_HIT; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks there's been an early exit due to temporal coherence;
* \return true if a temporal hit has occured
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL TemporalHit() const { return mFlags & OPC_TEMPORAL_HIT; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks primitive tests are enabled;
* \return true if primitive tests must be skipped
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL SkipPrimitiveTests() const { return mFlags & OPC_NO_PRIMITIVE_TESTS; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks primitive tests are enabled;
* \return true if primitive tests must be skipped
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL SkipPrimitiveTests() const { return mFlags & OPC_NO_PRIMITIVE_TESTS; }
// Settings
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Reports all contacts (false) or first contact only (true)
* \param flag [in] true for first contact, false for all contacts
* \see SetTemporalCoherence(bool flag)
* \see ValidateSettings()
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetFirstContact(bool flag)
{
if (flag) mFlags |= OPC_FIRST_CONTACT;
else mFlags &= ~OPC_FIRST_CONTACT;
}
// Settings
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Enable/disable temporal coherence.
* \param flag [in] true to enable temporal coherence, false to discard it
* \see SetFirstContact(bool flag)
* \see ValidateSettings()
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetTemporalCoherence(bool flag)
{
if (flag) mFlags |= OPC_TEMPORAL_COHERENCE;
else mFlags &= ~OPC_TEMPORAL_COHERENCE;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Reports all contacts (false) or first contact only (true)
* \param flag [in] true for first contact, false for all contacts
* \see SetTemporalCoherence(bool flag)
* \see ValidateSettings()
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetFirstContact(bool flag)
{
if(flag) mFlags |= OPC_FIRST_CONTACT;
else mFlags &= ~OPC_FIRST_CONTACT;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Enable/disable primitive tests.
* \param flag [in] true to enable primitive tests, false to discard them
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetPrimitiveTests(bool flag)
{
if (!flag) mFlags |= OPC_NO_PRIMITIVE_TESTS;
else mFlags &= ~OPC_NO_PRIMITIVE_TESTS;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Enable/disable temporal coherence.
* \param flag [in] true to enable temporal coherence, false to discard it
* \see SetFirstContact(bool flag)
* \see ValidateSettings()
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetTemporalCoherence(bool flag)
{
if(flag) mFlags |= OPC_TEMPORAL_COHERENCE;
else mFlags &= ~OPC_TEMPORAL_COHERENCE;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Validates current settings. You should call this method after all the settings / callbacks have been defined for a collider.
* \return null if everything is ok, else a string describing the problem
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual const char* ValidateSettings() = 0;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Enable/disable primitive tests.
* \param flag [in] true to enable primitive tests, false to discard them
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetPrimitiveTests(bool flag)
{
if(!flag) mFlags |= OPC_NO_PRIMITIVE_TESTS;
else mFlags &= ~OPC_NO_PRIMITIVE_TESTS;
}
protected:
udword mFlags; //!< Bit flags
const BaseModel* mCurrentModel; //!< Current model for collision query (owner of touched faces)
// User mesh interface
const MeshInterface* mIMesh; //!< User-defined mesh interface
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Validates current settings. You should call this method after all the settings / callbacks have been defined for a collider.
* \return null if everything is ok, else a string describing the problem
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual const char* ValidateSettings() = 0;
// Internal methods
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Setups current collision model
* \param model [in] current collision model
* \return TRUE if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL Setup(const BaseModel* model)
{
// Keep track of current model
mCurrentModel = model;
if (!mCurrentModel) return FALSE;
protected:
udword mFlags; //!< Bit flags
const BaseModel* mCurrentModel; //!< Current model for collision query (owner of touched faces)
// User mesh interface
const MeshInterface* mIMesh; //!< User-defined mesh interface
mIMesh = model->GetMeshInterface();
return mIMesh != null;
}
// Internal methods
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Setups current collision model
* \param model [in] current collision model
* \return TRUE if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL Setup(const BaseModel* model)
{
// Keep track of current model
mCurrentModel = model;
if(!mCurrentModel) return FALSE;
mIMesh = model->GetMeshInterface();
return mIMesh!=null;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Initializes a query
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual inline_ void InitQuery() { mFlags &= ~OPC_TEMPORAL_CONTACT; }
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Initializes a query
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual inline_ void InitQuery() { mFlags &= ~OPC_TEMPORAL_CONTACT; }
};
#endif // __OPC_COLLIDER_H__
@@ -41,79 +41,71 @@ ODE_PURE_INLINE bool avxBoxesOverlap(const dReal* acenter, const dReal* bcenter
}
#endif
class OPCODE_API CollisionAABB
{
public:
//! Constructor
inline_ CollisionAABB() {}
//! Constructor
inline_ CollisionAABB(const AABB& b) { b.GetCenter(mCenter); b.GetExtents(mExtents); }
//! Destructor
inline_ ~CollisionAABB() {}
class OPCODE_API CollisionAABB
{
public:
//! Constructor
inline_ CollisionAABB() {}
//! Constructor
inline_ CollisionAABB(const AABB& b) { b.GetCenter(mCenter); b.GetExtents(mExtents); }
//! Destructor
inline_ ~CollisionAABB() {}
//! Get min point of the box
inline_ void GetMin(Point& min) const { min = mCenter - mExtents; }
//! Get max point of the box
inline_ void GetMax(Point& max) const { max = mCenter + mExtents; }
//! Get min point of the box
inline_ void GetMin(Point& min) const { min = mCenter - mExtents; }
//! Get max point of the box
inline_ void GetMax(Point& max) const { max = mCenter + mExtents; }
//! Get component of the box's min point along a given axis
inline_ float GetMin(udword axis) const { return mCenter[axis] - mExtents[axis]; }
//! Get component of the box's max point along a given axis
inline_ float GetMax(udword axis) const { return mCenter[axis] + mExtents[axis]; }
//! Get component of the box's min point along a given axis
inline_ float GetMin(udword axis) const { return mCenter[axis] - mExtents[axis]; }
//! Get component of the box's max point along a given axis
inline_ float GetMax(udword axis) const { return mCenter[axis] + mExtents[axis]; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Setups an AABB from min & max vectors.
* \param min [in] the min point
* \param max [in] the max point
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetMinMax(const Point& min, const Point& max) { mCenter = (max + min)*0.5f; mExtents = (max - min)*0.5f; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Setups an AABB from min & max vectors.
* \param min [in] the min point
* \param max [in] the max point
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetMinMax(const Point& min, const Point& max)
{
mCenter = (max + min)*0.5f;
mExtents = (max - min)*0.5f;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks a box is inside another box.
* \param box [in] the other box
* \return true if current box is inside input box
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL IsInside(const CollisionAABB& box) const
{
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks a box is inside another box.
* \param box [in] the other box
* \return true if current box is inside input box
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL IsInside(const CollisionAABB& box) const
{
#if defined (__AVX__)
return avxBoxesOverlap(&(box.mCenter.x), &(mCenter.x), &(box.mExtents.x), &(mExtents.x));
return avxBoxesOverlap(&(box.mCenter.x), &(mCenter.x), &(box.mExtents.x), &(mExtents.x));
#else
if(box.GetMin(0)>GetMin(0)) return FALSE;
if(box.GetMin(1)>GetMin(1)) return FALSE;
if(box.GetMin(2)>GetMin(2)) return FALSE;
if(box.GetMax(0)<GetMax(0)) return FALSE;
if(box.GetMax(1)<GetMax(1)) return FALSE;
if(box.GetMax(2)<GetMax(2)) return FALSE;
return TRUE;
if (box.GetMin(0) > GetMin(0)) return FALSE;
if (box.GetMin(1) > GetMin(1)) return FALSE;
if (box.GetMin(2) > GetMin(2)) return FALSE;
if (box.GetMax(0) < GetMax(0)) return FALSE;
if (box.GetMax(1) < GetMax(1)) return FALSE;
if (box.GetMax(2) < GetMax(2)) return FALSE;
return TRUE;
#endif
}
}
Point mCenter; //!< Box center
Point mExtents; //!< Box extents
};
Point mCenter; //!< Box center
Point mExtents; //!< Box extents
};
class OPCODE_API QuantizedAABB
{
public:
//! Constructor
inline_ QuantizedAABB() {}
//! Destructor
inline_ ~QuantizedAABB() {}
sword mCenter[3]; //!< Quantized center
uword mExtents[3]; //!< Quantized extents
};
//! Quickly rotates & translates a vector
inline_ void TransformPoint(Point& dest, const Point& source, const Matrix3x3& rot, const Point& trans)
{
dest.x = trans.x + source.x * rot.m[0][0] + source.y * rot.m[1][0] + source.z * rot.m[2][0];
dest.y = trans.y + source.x * rot.m[0][1] + source.y * rot.m[1][1] + source.z * rot.m[2][1];
dest.z = trans.z + source.x * rot.m[0][2] + source.y * rot.m[1][2] + source.z * rot.m[2][2];
}
//! Quickly rotates & translates a vector
inline_ void TransformPoint(Point& dest, const Point& source, const Matrix3x3& rot, const Point& trans)
{
dest.x = trans.x + source.x * rot.m[0][0] + source.y * rot.m[1][0] + source.z * rot.m[2][0];
dest.y = trans.y + source.x * rot.m[0][1] + source.y * rot.m[1][1] + source.z * rot.m[2][1];
dest.z = trans.z + source.x * rot.m[0][2] + source.y * rot.m[1][2] + source.z * rot.m[2][2];
}
#endif //__OPC_COMMON_H__
@@ -83,22 +83,6 @@
// good strategy.
};
class OPCODE_API AABBQuantizedNode
{
IMPLEMENT_IMPLICIT_NODE(AABBQuantizedNode, QuantizedAABB)
inline_ uword GetSize() const
{
const uword* Bits = mAABB.mExtents;
uword Max = Bits[0];
if(Bits[1]>Max) Max = Bits[1];
if(Bits[2]>Max) Max = Bits[2];
return Max;
}
// NB: for quantized nodes I don't feel like computing a square-magnitude with integers all
// over the place.......!
};
class OPCODE_API AABBNoLeafNode
{
IMPLEMENT_NOLEAF_NODE(AABBNoLeafNode, CollisionAABB)
@@ -20,211 +20,207 @@
#ifndef __OPC_RAYCOLLIDER_H__
#define __OPC_RAYCOLLIDER_H__
class OPCODE_API CollisionFace
{
public:
//! Constructor
inline_ CollisionFace() {}
//! Destructor
inline_ ~CollisionFace() {}
class OPCODE_API CollisionFace
{
public:
inline_ CollisionFace() {}
inline_ ~CollisionFace() {}
udword mFaceID; //!< Index of touched face
float mDistance; //!< Distance from collider to hitpoint
float mU, mV; //!< Impact barycentric coordinates
};
udword mFaceID; //!< Index of touched face
float mDistance; //!< Distance from collider to hitpoint
float mU, mV; //!< Impact barycentric coordinates
};
class OPCODE_API CollisionFaces : public Container
{
public:
//! Constructor
CollisionFaces() {}
//! Destructor
~CollisionFaces() {}
class OPCODE_API CollisionFaces : public Container
{
public:
inline_ CollisionFaces() {}
inline_ ~CollisionFaces() {}
inline_ udword GetNbFaces() const
inline_ udword GetNbFaces()
{
return GetNbEntries() >> 2;
}
inline_ const CollisionFace* GetFaces() const
inline_ CollisionFace* GetFaces()
{
return (const CollisionFace*)GetEntries();
return (CollisionFace*)GetEntries();
}
inline_ void Reset()
inline_ void Reset()
{
Container::Reset();
}
inline_ void AddFace(const CollisionFace& face)
inline_ void AddFace(CollisionFace& face)
{
Add(face.mFaceID).Add(face.mDistance).Add(face.mU).Add(face.mV);
}
};
};
class OPCODE_API RayCollider : public Collider
{
public:
// Constructor / Destructor
class OPCODE_API RayCollider : public Collider
{
public:
// Constructor / Destructor
RayCollider();
virtual ~RayCollider();
virtual ~RayCollider();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Generic stabbing query for generic OPCODE models. After the call, access the results:
* - with GetContactStatus()
* - in the user-provided destination array
*
* \param world_ray [in] stabbing ray in world space
* \param model [in] Opcode model to collide with
* \param world [in] model's world matrix, or null
* \param cache [in] a possibly cached face index, or null
* \return true if success
* \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Collide(const Ray& world_ray, const Model& model, const Matrix4x4* world=null, udword* cache=null);
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Generic stabbing query for generic OPCODE models. After the call, access the results:
* - with GetContactStatus()
* - in the user-provided destination array
*
* \param world_ray [in] stabbing ray in world space
* \param model [in] Opcode model to collide with
* \param world [in] model's world matrix, or null
* \param cache [in] a possibly cached face index, or null
* \return true if success
* \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Collide(const Ray& world_ray, const Model& model, const Matrix4x4* world = null, udword* cache = null);
//
bool Collide(const Ray& world_ray, const AABBTree* tree, Container& box_indices);
// Settings
// Settings
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Settings: enable or disable "closest hit" mode.
* \param flag [in] true to report closest hit only
* \see SetCulling(bool flag)
* \see SetMaxDist(float max_dist)
* \see SetDestination(StabbedFaces* sf)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetClosestHit(bool flag)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Settings: enable or disable "closest hit" mode.
* \param flag [in] true to report closest hit only
* \see SetCulling(bool flag)
* \see SetMaxDist(float max_dist)
* \see SetDestination(StabbedFaces* sf)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetClosestHit(bool flag)
{
mClosestHit = flag;
mClosestHit = flag;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Settings: enable or disable backface culling.
* \param flag [in] true to enable backface culling
* \see SetClosestHit(bool flag)
* \see SetMaxDist(float max_dist)
* \see SetDestination(StabbedFaces* sf)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetCulling(bool flag)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Settings: enable or disable backface culling.
* \param flag [in] true to enable backface culling
* \see SetClosestHit(bool flag)
* \see SetMaxDist(float max_dist)
* \see SetDestination(StabbedFaces* sf)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetCulling(bool flag)
{
mCulling = flag;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Settings: sets the higher distance bound.
* \param max_dist [in] higher distance bound. Default = maximal value, for ray queries (else segment)
* \see SetClosestHit(bool flag)
* \see SetCulling(bool flag)
* \see SetDestination(StabbedFaces* sf)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetMaxDist(float max_dist = MAX_FLOAT)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Settings: sets the higher distance bound.
* \param max_dist [in] higher distance bound. Default = maximal value, for ray queries (else segment)
* \see SetClosestHit(bool flag)
* \see SetCulling(bool flag)
* \see SetDestination(StabbedFaces* sf)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetMaxDist(float max_dist = MAX_FLOAT)
{
mMaxDist = max_dist;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Settings: sets the destination array for stabbed faces.
* \param cf [in] destination array, filled during queries
* \see SetClosestHit(bool flag)
* \see SetCulling(bool flag)
* \see SetMaxDist(float max_dist)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetDestination(CollisionFaces* cf)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Settings: sets the destination array for stabbed faces.
* \param cf [in] destination array, filled during queries
* \see SetClosestHit(bool flag)
* \see SetCulling(bool flag)
* \see SetMaxDist(float max_dist)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetDestination(CollisionFaces* cf)
{
mStabbedFaces = cf;
}
// Stats
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Stats: gets the number of Ray-BV overlap tests after a collision query.
* \see GetNbRayPrimTests()
* \see GetNbIntersections()
* \return the number of Ray-BV tests performed during last query
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetNbRayBVTests() const
// Stats
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Stats: gets the number of Ray-BV overlap tests after a collision query.
* \see GetNbRayPrimTests()
* \see GetNbIntersections()
* \return the number of Ray-BV tests performed during last query
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetNbRayBVTests() const
{
return mNbRayBVTests;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Stats: gets the number of Ray-Triangle overlap tests after a collision query.
* \see GetNbRayBVTests()
* \see GetNbIntersections()
* \return the number of Ray-Triangle tests performed during last query
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetNbRayPrimTests() const
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Stats: gets the number of Ray-Triangle overlap tests after a collision query.
* \see GetNbRayBVTests()
* \see GetNbIntersections()
* \return the number of Ray-Triangle tests performed during last query
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetNbRayPrimTests() const
{
return mNbRayPrimTests;
}
// In-out test
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Stats: gets the number of intersection found after a collision query. Can be used for in/out tests.
* \see GetNbRayBVTests()
* \see GetNbRayPrimTests()
* \return the number of valid intersections during last query
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetNbIntersections() const
// In-out test
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Stats: gets the number of intersection found after a collision query. Can be used for in/out tests.
* \see GetNbRayBVTests()
* \see GetNbRayPrimTests()
* \return the number of valid intersections during last query
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetNbIntersections() const
{
return mNbIntersections;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Validates current settings. You should call this method after all the settings and callbacks have been defined for a collider.
* \return null if everything is ok, else a string describing the problem
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
override(Collider) const char* ValidateSettings();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Validates current settings. You should call this method after all the settings and callbacks have been defined for a collider.
* \return null if everything is ok, else a string describing the problem
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
override(Collider) const char* ValidateSettings();
protected:
// Ray in local space
Point mOrigin; //!< Ray origin
Point mDir; //!< Ray direction (normalized)
Point mFDir; //!< fabsf(mDir)
Point mData, mData2;
// Stabbed faces
CollisionFace mStabbedFace; //!< Current stabbed face
CollisionFaces* mStabbedFaces; //!< List of stabbed faces
bool mClosestHit; //!< Report closest hit only
// Stats
udword mNbRayBVTests; //!< Number of Ray-BV tests
udword mNbRayPrimTests; //!< Number of Ray-Primitive tests
// In-out test
udword mNbIntersections; //!< Number of valid intersections
// Dequantization coeffs
Point mCenterCoeff;
Point mExtentsCoeff;
// Settings
float mMaxDist; //!< Valid segment on the ray
protected:
// Ray in local space
Point mOrigin; //!< Ray origin
Point mDir; //!< Ray direction (normalized)
Point mFDir; //!< fabsf(mDir)
Point mData, mData2;
// Stabbed faces
CollisionFace mStabbedFace; //!< Current stabbed face
CollisionFaces* mStabbedFaces; //!< List of stabbed faces
bool mClosestHit; //!< Report closest hit only
// Stats
udword mNbRayBVTests; //!< Number of Ray-BV tests
udword mNbRayPrimTests; //!< Number of Ray-Primitive tests
// In-out test
udword mNbIntersections; //!< Number of valid intersections
// Dequantization coeffs
Point mCenterCoeff;
Point mExtentsCoeff;
// Settings
float mMaxDist; //!< Valid segment on the ray
bool mCulling; //!< Stab culled faces or not
// Internal methods
void _SegmentStab(const AABBCollisionNode* node);
void _SegmentStab(const AABBNoLeafNode* node);
void _SegmentStab(const AABBTreeNode* node, Container& box_indices);
void _RayStab(const AABBCollisionNode* node);
void _RayStab(const AABBNoLeafNode* node);
void _RayStab(const AABBTreeNode* node, Container& box_indices);
// Overlap tests
inline_ BOOL RayAABBOverlap(const Point& center, const Point& extents);
inline_ BOOL SegmentAABBOverlap(const Point& center, const Point& extents);
inline_ BOOL RayTriOverlap(const Point& vert0, const Point& vert1, const Point& vert2);
// Init methods
BOOL InitQuery(const Ray& world_ray, const Matrix4x4* world=null, udword* face_id=null);
};
// Internal methods
void _SegmentStab(const AABBCollisionNode* node);
void _SegmentStab(const AABBNoLeafNode* node);
void _SegmentStab(const AABBTreeNode* node, Container& box_indices);
void _RayStab(const AABBCollisionNode* node);
void _RayStab(const AABBNoLeafNode* node);
void _RayStab(const AABBTreeNode* node, Container& box_indices);
// Overlap tests
inline_ BOOL RayAABBOverlap(const Point& center, const Point& extents);
inline_ BOOL SegmentAABBOverlap(const Point& center, const Point& extents);
inline_ BOOL RayTriOverlap(const Point& vert0, const Point& vert1, const Point& vert2);
// Init methods
BOOL InitQuery(const Ray& world_ray, const Matrix4x4* world = null, udword* face_id = null);
};
#endif // __OPC_RAYCOLLIDER_H__