diff options
author | sanine <sanine.not@pm.me> | 2022-10-01 20:59:36 -0500 |
---|---|---|
committer | sanine <sanine.not@pm.me> | 2022-10-01 20:59:36 -0500 |
commit | c5fc66ee58f2c60f2d226868bb1cf5b91badaf53 (patch) | |
tree | 277dd280daf10bf77013236b8edfa5f88708c7e0 /libs/ode-0.16.1/OPCODE/OPC_MeshInterface.cpp | |
parent | 1cf9cc3408af7008451f9133fb95af66a9697d15 (diff) |
add ode
Diffstat (limited to 'libs/ode-0.16.1/OPCODE/OPC_MeshInterface.cpp')
-rw-r--r-- | libs/ode-0.16.1/OPCODE/OPC_MeshInterface.cpp | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/libs/ode-0.16.1/OPCODE/OPC_MeshInterface.cpp b/libs/ode-0.16.1/OPCODE/OPC_MeshInterface.cpp new file mode 100644 index 0000000..157464e --- /dev/null +++ b/libs/ode-0.16.1/OPCODE/OPC_MeshInterface.cpp @@ -0,0 +1,393 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains a mesh interface. + * \file OPC_MeshInterface.cpp + * \author Pierre Terdiman + * \date November, 27, 2002 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * This structure holds 3 vertex-pointers. It's mainly used by collision callbacks so that the app doesn't have + * to return 3 vertices to OPCODE (36 bytes) but only 3 pointers (12 bytes). It seems better but I never profiled + * the alternative. + * + * \class VertexPointers + * \author Pierre Terdiman + * \version 1.3 + * \date March, 20, 2001 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * This class is an interface between us and user-defined meshes. Meshes can be defined in a lot of ways, and here we + * try to support most of them. + * + * Basically you have two options: + * - callbacks, if OPC_USE_CALLBACKS is defined in OPC_Settings.h. + * - else pointers. + * + * If using pointers, you can also use strides or not. Strides are used when OPC_USE_STRIDE is defined. + * + * + * CALLBACKS: + * + * Using callbacks is the most generic way to feed OPCODE with your meshes. Indeed, you just have to give + * access to three vertices at the end of the day. It's up to you to fetch them from your database, using + * whatever method you want. Hence your meshes can lie in system memory or AGP, be indexed or not, use 16 + * or 32-bits indices, you can decompress them on-the-fly if needed, etc. On the other hand, a callback is + * called each time OPCODE needs access to a particular triangle, so there might be a slight overhead. + * + * To make things clear: geometry & topology are NOT stored in the collision system, + * in order to save some ram. So, when the system needs them to perform accurate intersection + * tests, you're requested to provide the triangle-vertices corresponding to a given face index. + * + * Ex: + * + * \code + * static void ColCallback(udword triangle_index, VertexPointers& triangle, udword user_data) + * { + * // Get back Mesh0 or Mesh1 (you also can use 2 different callbacks) + * Mesh* MyMesh = (Mesh*)user_data; + * // Get correct triangle in the app-controlled database + * const Triangle* Tri = MyMesh->GetTriangle(triangle_index); + * // Setup pointers to vertices for the collision system + * triangle.Vertex[0] = MyMesh->GetVertex(Tri->mVRef[0]); + * triangle.Vertex[1] = MyMesh->GetVertex(Tri->mVRef[1]); + * triangle.Vertex[2] = MyMesh->GetVertex(Tri->mVRef[2]); + * } + * + * // Setup callbacks + * MeshInterface0->SetCallback(ColCallback, udword(Mesh0)); + * MeshInterface1->SetCallback(ColCallback, udword(Mesh1)); + * \endcode + * + * Of course, you should make this callback as fast as possible. And you're also not supposed + * to modify the geometry *after* the collision trees have been built. The alternative was to + * store the geometry & topology in the collision system as well (as in RAPID) but we have found + * this approach to waste a lot of ram in many cases. + * + * + * POINTERS: + * + * If you're internally using the following canonical structures: + * - a vertex made of three 32-bits floating point values + * - a triangle made of three 32-bits integer vertex references + * ...then you may want to use pointers instead of callbacks. This is the same, except OPCODE will directly + * use provided pointers to access the topology and geometry, without using a callback. It might be faster, + * but probably not as safe. Pointers have been introduced in OPCODE 1.2. + * + * Ex: + * + * \code + * // Setup pointers + * MeshInterface0->SetPointers(Mesh0->GetFaces(), Mesh0->GetVerts()); + * MeshInterface1->SetPointers(Mesh1->GetFaces(), Mesh1->GetVerts()); + * \endcode + * + * + * STRIDES: + * + * If your vertices are D3D-like entities interleaving a position, a normal and/or texture coordinates + * (i.e. if your vertices are FVFs), you might want to use a vertex stride to skip extra data OPCODE + * doesn't need. Using a stride shouldn't be notably slower than not using it, but it might increase + * cache misses. Please also note that you *shouldn't* read from AGP or video-memory buffers ! + * + * + * In any case, compilation flags are here to select callbacks/pointers/strides at compile time, so + * choose what's best for your application. All of this has been wrapped into this MeshInterface. + * + * \class MeshInterface + * \author Pierre Terdiman + * \version 1.3 + * \date November, 27, 2002 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "Stdafx.h" + +using namespace Opcode; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +MeshInterface::MeshInterface() : + mNbTris (0), + mNbVerts (0), +#ifdef OPC_USE_CALLBACKS + mUserData (null), + mObjCallback (null), + mExUserData (null), + mObjExCallback (null), +#else + #ifdef OPC_USE_STRIDE + mTriStride (sizeof(IndexedTriangle)), + mVertexStride (sizeof(Point)), + mFetchTriangle (&MeshInterface::FetchTriangleFromSingles), + mFetchExTriangle (&MeshInterface::FetchExTriangleFromSingles), + #endif + mTris (null), + mVerts (null) +#endif +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +MeshInterface::~MeshInterface() +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Checks the mesh interface is valid, i.e. things have been setup correctly. + * \return true if valid + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool MeshInterface::IsValid() const +{ + if(!mNbTris || !mNbVerts) return false; +#ifdef OPC_USE_CALLBACKS + if(!mObjCallback) return false; +#else + if(!mTris || !mVerts) return false; +#endif + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Checks the mesh itself is valid. + * Currently we only look for degenerate faces. + * \return number of degenerate faces + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +udword MeshInterface::CheckTopology() const +{ + // Check topology. If the model contains degenerate faces, collision report can be wrong in some cases. + // e.g. it happens with the standard MAX teapot. So clean your meshes first... If you don't have a mesh cleaner + // you can try this: www.codercorner.com/Consolidation.zip + + udword NbDegenerate = 0; + + VertexPointers VP; + ConversionArea VC; + + // Using callbacks, we don't have access to vertex indices. Nevertheless we still can check for + // redundant vertex pointers, which cover all possibilities (callbacks/pointers/strides). + for(udword i=0;i<mNbTris;i++) + { + GetTriangle(VP, i, VC); + + if( (VP.Vertex[0]==VP.Vertex[1]) + || (VP.Vertex[1]==VP.Vertex[2]) + || (VP.Vertex[2]==VP.Vertex[0])) NbDegenerate++; + } + + return NbDegenerate; +} + +#ifdef OPC_USE_CALLBACKS +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * 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 MeshInterface::SetCallback(RequestCallback callback, void* user_data) +{ + if(!callback) return SetIceError("MeshInterface::SetCallback: callback pointer is null"); + + mObjCallback = callback; + mUserData = user_data; + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** +* Callback control: setups object ex-callback. Must provide triangle-vertices and vertex indice for a given triangle index. +* \param callback [in] user-defined callback +* \param user_data [in] user-defined data +* \return true if success +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool MeshInterface::SetExCallback(RequestExCallback callback, void* user_data) +{ +// if(!callback) -- allow nulls + + mObjExCallback = callback; + mExUserData = user_data; + return true; +} +#else +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * 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 MeshInterface::SetPointers(const IndexedTriangle* tris, const Point* verts) +{ + if(!tris || !verts) return SetIceError("MeshInterface::SetPointers: pointer is null", null); + + mTris = tris; + mVerts = verts; + return true; +} +#ifdef OPC_USE_STRIDE +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * 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 MeshInterface::SetStrides(udword tri_stride, udword vertex_stride) +{ + if(tri_stride<sizeof(IndexedTriangle)) return SetIceError("MeshInterface::SetStrides: invalid triangle stride", null); + if(vertex_stride<sizeof(Point)) return SetIceError("MeshInterface::SetStrides: invalid vertex stride", null); + + mTriStride = tri_stride; + mVertexStride = vertex_stride; + return true; +} +#endif +#endif + +#ifndef OPC_USE_CALLBACKS +#ifdef OPC_USE_STRIDE +void MeshInterface::FetchTriangleFromSingles(VertexPointers& vp, udword index, ConversionArea vc) const +{ + const IndexedTriangle* T = (const IndexedTriangle*)(((ubyte*)mTris) + index * mTriStride); + + const Point* Verts = GetVerts(); + udword VertexStride = GetVertexStride(); + vp.Vertex[0] = (const Point*)(((ubyte*)Verts) + T->mVRef[0] * VertexStride); + vp.Vertex[1] = (const Point*)(((ubyte*)Verts) + T->mVRef[1] * VertexStride); + vp.Vertex[2] = (const Point*)(((ubyte*)Verts) + T->mVRef[2] * VertexStride); +} + +void MeshInterface::FetchTriangleFromDoubles(VertexPointers& vp, udword index, ConversionArea vc) const +{ + const IndexedTriangle* T = (const IndexedTriangle*)(((ubyte*)mTris) + index * mTriStride); + + const Point* Verts = GetVerts(); + udword VertexStride = GetVertexStride(); + + for (int i = 0; i < 3; i++){ + const double* v = (const double*)(((ubyte*)Verts) + T->mVRef[i] * VertexStride); + + vc[i].x = (float)v[0]; + vc[i].y = (float)v[1]; + vc[i].z = (float)v[2]; + vp.Vertex[i] = &vc[i]; + } +} + +void MeshInterface::FetchExTriangleFromSingles(VertexPointersEx& vpe, udword index, ConversionArea vc) const +{ + const IndexedTriangle* T = (const IndexedTriangle*)(((ubyte*)mTris) + index * mTriStride); + + const Point* Verts = GetVerts(); + udword VertexStride = GetVertexStride(); + + dTriIndex VertIndex0 = T->mVRef[0]; + vpe.Index[0] = VertIndex0; + vpe.vp.Vertex[0] = (const Point*)(((ubyte*)Verts) + VertIndex0 * VertexStride); + + dTriIndex VertIndex1 = T->mVRef[1]; + vpe.Index[1] = VertIndex1; + vpe.vp.Vertex[1] = (const Point*)(((ubyte*)Verts) + VertIndex1 * VertexStride); + + dTriIndex VertIndex2 = T->mVRef[2]; + vpe.Index[2] = VertIndex2; + vpe.vp.Vertex[2] = (const Point*)(((ubyte*)Verts) + VertIndex2 * VertexStride); +} + +void MeshInterface::FetchExTriangleFromDoubles(VertexPointersEx& vpe, udword index, ConversionArea vc) const +{ + const IndexedTriangle* T = (const IndexedTriangle*)(((ubyte*)mTris) + index * mTriStride); + + const Point* Verts = GetVerts(); + udword VertexStride = GetVertexStride(); + + for (int i = 0; i < 3; i++){ + dTriIndex VertIndex = T->mVRef[i]; + vpe.Index[i] = VertIndex; + + const double* v = (const double*)(((ubyte*)Verts) + VertIndex * VertexStride); + vc[i].x = (float)v[0]; + vc[i].y = (float)v[1]; + vc[i].z = (float)v[2]; + vpe.vp.Vertex[i] = &vc[i]; + } +} +#endif +#endif + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * 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 MeshInterface::RemapClient(udword nb_indices, const dTriIndex* permutation) const +{ + // Checkings + if(!nb_indices || !permutation) return false; + if(nb_indices!=mNbTris) return false; + +#ifdef OPC_USE_CALLBACKS + // We can't really do that using callbacks + return false; +#else + IndexedTriangle* Tmp = new IndexedTriangle[mNbTris]; + CHECKALLOC(Tmp); + + #ifdef OPC_USE_STRIDE + udword Stride = mTriStride; + #else + udword Stride = sizeof(IndexedTriangle); + #endif + + for(udword i=0;i<mNbTris;i++) + { + const IndexedTriangle* T = (const IndexedTriangle*)(((ubyte*)mTris) + i * Stride); + Tmp[i] = *T; + } + + for(udword i=0;i<mNbTris;i++) + { + IndexedTriangle* T = (IndexedTriangle*)(((ubyte*)mTris) + i * Stride); + *T = Tmp[permutation[i]]; + } + + DELETEARRAY(Tmp); +#endif + return true; +} |