281 lines
15 KiB
C
281 lines
15 KiB
C
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/*
|
||
|
* OPCODE - Optimized Collision Detection
|
||
|
* Copyright (C) 2001 Pierre Terdiman
|
||
|
* Homepage: http://www.codercorner.com/Opcode.htm
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Contains a mesh interface.
|
||
|
* \file OPC_MeshInterface.h
|
||
|
* \author Pierre Terdiman
|
||
|
* \date November, 27, 2002
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
// Include Guard
|
||
|
#ifndef __OPC_MESHINTERFACE_H__
|
||
|
#define __OPC_MESHINTERFACE_H__
|
||
|
|
||
|
struct VertexPointers
|
||
|
{
|
||
|
const Point* Vertex[3];
|
||
|
|
||
|
bool BackfaceCulling(const Point& source)
|
||
|
{
|
||
|
const Point& p0 = *Vertex[0];
|
||
|
const Point& p1 = *Vertex[1];
|
||
|
const Point& p2 = *Vertex[2];
|
||
|
|
||
|
// Compute normal direction
|
||
|
Point Normal = (p2 - p1)^(p0 - p1);
|
||
|
|
||
|
// Backface culling
|
||
|
return (Normal | (source - p0)) >= 0.0f;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
struct VertexPointersEx
|
||
|
{
|
||
|
VertexPointers vp;
|
||
|
dTriIndex Index[3];
|
||
|
};
|
||
|
|
||
|
typedef Point ConversionArea[3];
|
||
|
|
||
|
#ifdef OPC_USE_CALLBACKS
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* User-callback, called by OPCODE to request vertices from the app.
|
||
|
* \param triangle_index [in] face index for which the system is requesting the vertices
|
||
|
* \param triangle [out] triangle's vertices (must be provided by the user)
|
||
|
* \param user_data [in] user-defined data from SetCallback()
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
typedef void (*RequestCallback) (udword triangle_index, VertexPointers& triangle, void* user_data);
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* User-callback, called by OPCODE to request vertex indices from the app.
|
||
|
* \param triangle_index [in] face index for which the system is requesting the vertices
|
||
|
* \param triangle [out] triangle's vertices with indices (must be provided by the user)
|
||
|
* \param user_data [in] user-defined data from SetExCallback()
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
typedef void (*RequestExCallback) (udword triangle_index, VertexPointersEx& triangle, void* user_data);
|
||
|
#endif
|
||
|
|
||
|
class OPCODE_API MeshInterface
|
||
|
{
|
||
|
public:
|
||
|
// Constructor / Destructor
|
||
|
MeshInterface();
|
||
|
~MeshInterface();
|
||
|
// Common settings
|
||
|
inline_ udword GetNbTriangles() const { return mNbTris; }
|
||
|
inline_ udword GetNbVertices() const { return mNbVerts; }
|
||
|
inline_ void SetNbTriangles(udword nb) { mNbTris = nb; }
|
||
|
inline_ void SetNbVertices(udword nb) { mNbVerts = nb; }
|
||
|
|
||
|
#ifdef OPC_USE_CALLBACKS
|
||
|
// Callback settings
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Callback control: setups object callback. Must provide triangle-vertices for a given triangle index.
|
||
|
* \param callback [in] user-defined callback
|
||
|
* \param user_data [in] user-defined data
|
||
|
* \return true if success
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
bool SetCallback(RequestCallback callback, void* user_data);
|
||
|
inline_ void* GetUserData() const { return mUserData; }
|
||
|
inline_ RequestCallback GetCallback() const { return mObjCallback; }
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Callback control: setups object callback. Must provide triangle-vertices for a given triangle index.
|
||
|
* \param callback [in] user-defined callback
|
||
|
* \param user_data [in] user-defined data
|
||
|
* \return true if success
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
bool SetExCallback(RequestExCallback callback, void* user_data);
|
||
|
inline_ void* GetExUserData() const { return mExUserData; }
|
||
|
inline_ RequestExCallback GetExCallback() const { return mObjExCallback; }
|
||
|
#else
|
||
|
// Pointers settings
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Pointers control: setups object pointers. Must provide access to faces and vertices for a given object.
|
||
|
* \param tris [in] pointer to triangles
|
||
|
* \param verts [in] pointer to vertices
|
||
|
* \return true if success
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
bool SetPointers(const IndexedTriangle* tris, const Point* verts);
|
||
|
inline_ const IndexedTriangle* GetTris() const { return mTris; }
|
||
|
inline_ const Point* GetVerts() const { return mVerts; }
|
||
|
|
||
|
#ifdef OPC_USE_STRIDE
|
||
|
// Strides settings
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Strides control
|
||
|
* \param tri_stride [in] size of a triangle in bytes. The first sizeof(IndexedTriangle) bytes are used to get vertex indices.
|
||
|
* \param vertex_stride [in] size of a vertex in bytes. The first sizeof(Point) bytes are used to get vertex position.
|
||
|
* \return true if success
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
bool SetStrides(udword tri_stride=sizeof(IndexedTriangle), udword vertex_stride=sizeof(Point));
|
||
|
inline_ udword GetTriStride() const { return mTriStride; }
|
||
|
inline_ udword GetVertexStride() const { return mVertexStride; }
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Single/Double control
|
||
|
* \param value [in] Indicates if mesh data is provided as array of \c single values. If \c false, data is expected to contain \c double elements.
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
inline_ void SetSingle(bool value)
|
||
|
{
|
||
|
mFetchTriangle = (value ? &MeshInterface::FetchTriangleFromSingles : &MeshInterface::FetchTriangleFromDoubles);
|
||
|
mFetchExTriangle = (value ? &MeshInterface::FetchExTriangleFromSingles : &MeshInterface::FetchExTriangleFromDoubles);
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
inline_ bool SetStrides(udword tri_stride=sizeof(IndexedTriangle), udword vertex_stride=sizeof(Point)) { return true; }
|
||
|
inline_ void SetSingle(bool value) {}
|
||
|
inline_ udword GetTriStride() const { return sizeof(IndexedTriangle); }
|
||
|
inline_ udword GetVertexStride() const { return sizeof(Point); }
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Fetches a triangle given a triangle index.
|
||
|
* \param vp [out] required triangle's vertex pointers
|
||
|
* \param index [in] triangle index
|
||
|
* \param vc [in,out] storage required for data conversion (pass local variable with same scope as \a vp, as \a vp may point to this memory on return)
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
inline_ void GetTriangle(VertexPointers& vp, udword index, ConversionArea vc) const
|
||
|
{
|
||
|
#ifdef OPC_USE_CALLBACKS
|
||
|
(mObjCallback)(index, vp, mUserData);
|
||
|
#else
|
||
|
#ifdef OPC_USE_STRIDE
|
||
|
// Since there was conditional statement "if (Single)" which was unpredictable for compiler
|
||
|
// and required both branches to be always generated what made inlining a questionable
|
||
|
// benefit, I consider it better to introduce a forced call
|
||
|
// but get rig of branching and dead code injection.
|
||
|
((*this).*mFetchTriangle)(vp, index, vc);
|
||
|
#else
|
||
|
const Point* Verts = GetVerts();
|
||
|
const IndexedTriangle* T = &mTris[index];
|
||
|
vp.Vertex[0] = &Verts[T->mVRef[0]];
|
||
|
vp.Vertex[1] = &Verts[T->mVRef[1]];
|
||
|
vp.Vertex[2] = &Verts[T->mVRef[2]];
|
||
|
#endif
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
inline_ bool GetExTriangle(VertexPointersEx& vpe, udword index, ConversionArea vc) const
|
||
|
{
|
||
|
#ifdef OPC_USE_CALLBACKS
|
||
|
if (mObjExCallback) { (mObjExCallback)(index, vpe, mUserData); return true; }
|
||
|
else { (mObjCallback)(index, vpe.vp, mUserData); return false; }
|
||
|
#else
|
||
|
#ifdef OPC_USE_STRIDE
|
||
|
// Since there was conditional statement "if (Single)" which was unpredictable for compiler
|
||
|
// and required both branches to be always generated what made inlining a questionable
|
||
|
// benefit, I consider it better to introduce a forced call
|
||
|
// but get rig of branching and dead code injection.
|
||
|
((*this).*mFetchExTriangle)(vpe, index, vc);
|
||
|
return true;
|
||
|
#else
|
||
|
const Point* Verts = GetVerts();
|
||
|
const IndexedTriangle* T = &mTris[index];
|
||
|
dTriIndex VertIndex0 = T->mVRef[0];
|
||
|
vpe.Index[0] = VertIndex0;
|
||
|
vpe.vp.Vertex[0] = &Verts[VertIndex0];
|
||
|
dTriIndex VertIndex1 = T->mVRef[1];
|
||
|
vpe.Index[1] = VertIndex1;
|
||
|
vpe.vp.Vertex[1] = &Verts[VertIndex1];
|
||
|
dTriIndex VertIndex2 = T->mVRef[2];
|
||
|
vpe.Index[2] = VertIndex2;
|
||
|
vpe.vp.Vertex[2] = &Verts[VertIndex2];
|
||
|
return true;
|
||
|
#endif
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
#ifndef OPC_USE_CALLBACKS
|
||
|
#ifdef OPC_USE_STRIDE
|
||
|
void FetchTriangleFromSingles(VertexPointers& vp, udword index, ConversionArea vc) const;
|
||
|
void FetchTriangleFromDoubles(VertexPointers& vp, udword index, ConversionArea vc) const;
|
||
|
void FetchExTriangleFromSingles(VertexPointersEx& vpe, udword index, ConversionArea vc) const;
|
||
|
void FetchExTriangleFromDoubles(VertexPointersEx& vpe, udword index, ConversionArea vc) const;
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
public:
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Remaps client's mesh according to a permutation.
|
||
|
* \param nb_indices [in] number of indices in the permutation (will be checked against number of triangles)
|
||
|
* \param permutation [in] list of triangle indices
|
||
|
* \return true if success
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
bool RemapClient(udword nb_indices, const dTriIndex* permutation) const;
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Checks the mesh interface is valid, i.e. things have been setup correctly.
|
||
|
* \return true if valid
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
bool IsValid() const;
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Checks the mesh itself is valid.
|
||
|
* Currently we only look for degenerate faces.
|
||
|
* \return number of degenerate faces
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
udword CheckTopology() const;
|
||
|
private:
|
||
|
|
||
|
udword mNbTris; //!< Number of triangles in the input model
|
||
|
udword mNbVerts; //!< Number of vertices in the input model
|
||
|
#ifdef OPC_USE_CALLBACKS
|
||
|
// User callback
|
||
|
void* mUserData; //!< User-defined data sent to callback
|
||
|
RequestCallback mObjCallback; //!< Object callback
|
||
|
void* mExUserData; //!< User-defined data sent to ex-callback
|
||
|
RequestExCallback mObjExCallback; //!< Object ex-callback
|
||
|
#else
|
||
|
// User pointers
|
||
|
#ifdef OPC_USE_STRIDE
|
||
|
udword mTriStride; //!< Possible triangle stride in bytes [Opcode 1.3]
|
||
|
udword mVertexStride; //!< Possible vertex stride in bytes [Opcode 1.3]
|
||
|
typedef void (MeshInterface:: *TriangleFetchProc)(VertexPointers& vp, udword index, ConversionArea vc) const;
|
||
|
TriangleFetchProc mFetchTriangle;
|
||
|
typedef void (MeshInterface:: *ExTriangleFetchProc)(VertexPointersEx& vpe, udword index, ConversionArea vc) const;
|
||
|
ExTriangleFetchProc mFetchExTriangle;
|
||
|
#endif
|
||
|
const IndexedTriangle* mTris; //!< Array of indexed triangles
|
||
|
const Point* mVerts; //!< Array of vertices
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
#endif //__OPC_MESHINTERFACE_H__
|