[216] | 1 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 2 | /* |
---|
| 3 | * OPCODE - Optimized Collision Detection |
---|
| 4 | * Copyright (C) 2001 Pierre Terdiman |
---|
| 5 | * Homepage: http://www.codercorner.com/Opcode.htm |
---|
| 6 | */ |
---|
| 7 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 8 | |
---|
| 9 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 10 | /** |
---|
| 11 | * Contains a mesh interface. |
---|
| 12 | * \file OPC_MeshInterface.cpp |
---|
| 13 | * \author Pierre Terdiman |
---|
| 14 | * \date November, 27, 2002 |
---|
| 15 | */ |
---|
| 16 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 17 | |
---|
| 18 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 19 | /** |
---|
| 20 | * This structure holds 3 vertex-pointers. It's mainly used by collision callbacks so that the app doesn't have |
---|
| 21 | * to return 3 vertices to OPCODE (36 bytes) but only 3 pointers (12 bytes). It seems better but I never profiled |
---|
| 22 | * the alternative. |
---|
| 23 | * |
---|
| 24 | * \class VertexPointers |
---|
| 25 | * \author Pierre Terdiman |
---|
| 26 | * \version 1.3 |
---|
| 27 | * \date March, 20, 2001 |
---|
| 28 | */ |
---|
| 29 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 30 | |
---|
| 31 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 32 | /** |
---|
| 33 | * This class is an interface between us and user-defined meshes. Meshes can be defined in a lot of ways, and here we |
---|
| 34 | * try to support most of them. |
---|
| 35 | * |
---|
| 36 | * Basically you have two options: |
---|
| 37 | * - callbacks, if OPC_USE_CALLBACKS is defined in OPC_Settings.h. |
---|
| 38 | * - else pointers. |
---|
| 39 | * |
---|
| 40 | * If using pointers, you can also use strides or not. Strides are used when OPC_USE_STRIDE is defined. |
---|
| 41 | * |
---|
| 42 | * |
---|
| 43 | * CALLBACKS: |
---|
| 44 | * |
---|
| 45 | * Using callbacks is the most generic way to feed OPCODE with your meshes. Indeed, you just have to give |
---|
| 46 | * access to three vertices at the end of the day. It's up to you to fetch them from your database, using |
---|
| 47 | * whatever method you want. Hence your meshes can lie in system memory or AGP, be indexed or not, use 16 |
---|
| 48 | * or 32-bits indices, you can decompress them on-the-fly if needed, etc. On the other hand, a callback is |
---|
| 49 | * called each time OPCODE needs access to a particular triangle, so there might be a slight overhead. |
---|
| 50 | * |
---|
| 51 | * To make things clear: geometry & topology are NOT stored in the collision system, |
---|
| 52 | * in order to save some ram. So, when the system needs them to perform accurate intersection |
---|
| 53 | * tests, you're requested to provide the triangle-vertices corresponding to a given face index. |
---|
| 54 | * |
---|
| 55 | * Ex: |
---|
| 56 | * |
---|
| 57 | * \code |
---|
| 58 | * static void ColCallback(udword triangle_index, VertexPointers& triangle, udword user_data) |
---|
| 59 | * { |
---|
| 60 | * // Get back Mesh0 or Mesh1 (you also can use 2 different callbacks) |
---|
| 61 | * Mesh* MyMesh = (Mesh*)user_data; |
---|
| 62 | * // Get correct triangle in the app-controlled database |
---|
| 63 | * const Triangle* Tri = MyMesh->GetTriangle(triangle_index); |
---|
| 64 | * // Setup pointers to vertices for the collision system |
---|
| 65 | * triangle.Vertex[0] = MyMesh->GetVertex(Tri->mVRef[0]); |
---|
| 66 | * triangle.Vertex[1] = MyMesh->GetVertex(Tri->mVRef[1]); |
---|
| 67 | * triangle.Vertex[2] = MyMesh->GetVertex(Tri->mVRef[2]); |
---|
| 68 | * } |
---|
| 69 | * |
---|
| 70 | * // Setup callbacks |
---|
| 71 | * MeshInterface0->SetCallback(ColCallback, udword(Mesh0)); |
---|
| 72 | * MeshInterface1->SetCallback(ColCallback, udword(Mesh1)); |
---|
| 73 | * \endcode |
---|
| 74 | * |
---|
| 75 | * Of course, you should make this callback as fast as possible. And you're also not supposed |
---|
| 76 | * to modify the geometry *after* the collision trees have been built. The alternative was to |
---|
| 77 | * store the geometry & topology in the collision system as well (as in RAPID) but we have found |
---|
| 78 | * this approach to waste a lot of ram in many cases. |
---|
| 79 | * |
---|
| 80 | * |
---|
| 81 | * POINTERS: |
---|
| 82 | * |
---|
| 83 | * If you're internally using the following canonical structures: |
---|
| 84 | * - a vertex made of three 32-bits floating point values |
---|
| 85 | * - a triangle made of three 32-bits integer vertex references |
---|
| 86 | * ...then you may want to use pointers instead of callbacks. This is the same, except OPCODE will directly |
---|
| 87 | * use provided pointers to access the topology and geometry, without using a callback. It might be faster, |
---|
| 88 | * but probably not as safe. Pointers have been introduced in OPCODE 1.2. |
---|
| 89 | * |
---|
| 90 | * Ex: |
---|
| 91 | * |
---|
| 92 | * \code |
---|
| 93 | * // Setup pointers |
---|
| 94 | * MeshInterface0->SetPointers(Mesh0->GetFaces(), Mesh0->GetVerts()); |
---|
| 95 | * MeshInterface1->SetPointers(Mesh1->GetFaces(), Mesh1->GetVerts()); |
---|
| 96 | * \endcode |
---|
| 97 | * |
---|
| 98 | * |
---|
| 99 | * STRIDES: |
---|
| 100 | * |
---|
| 101 | * If your vertices are D3D-like entities interleaving a position, a normal and/or texture coordinates |
---|
| 102 | * (i.e. if your vertices are FVFs), you might want to use a vertex stride to skip extra data OPCODE |
---|
| 103 | * doesn't need. Using a stride shouldn't be notably slower than not using it, but it might increase |
---|
| 104 | * cache misses. Please also note that you *shouldn't* read from AGP or video-memory buffers ! |
---|
| 105 | * |
---|
| 106 | * |
---|
| 107 | * In any case, compilation flags are here to select callbacks/pointers/strides at compile time, so |
---|
| 108 | * choose what's best for your application. All of this has been wrapped into this MeshInterface. |
---|
| 109 | * |
---|
| 110 | * \class MeshInterface |
---|
| 111 | * \author Pierre Terdiman |
---|
| 112 | * \version 1.3 |
---|
| 113 | * \date November, 27, 2002 |
---|
| 114 | */ |
---|
| 115 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 116 | |
---|
| 117 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 118 | // Precompiled Header |
---|
| 119 | #include "Stdafx.h" |
---|
| 120 | |
---|
| 121 | using namespace Opcode; |
---|
| 122 | |
---|
| 123 | Point MeshInterface::VertexCache[3]; |
---|
| 124 | |
---|
| 125 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 126 | /** |
---|
| 127 | * Constructor. |
---|
| 128 | */ |
---|
| 129 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 130 | MeshInterface::MeshInterface() : |
---|
| 131 | #ifdef OPC_USE_CALLBACKS |
---|
| 132 | mUserData (null), |
---|
| 133 | mObjCallback (null), |
---|
| 134 | #else |
---|
| 135 | mTris (null), |
---|
| 136 | mVerts (null), |
---|
| 137 | #ifdef OPC_USE_STRIDE |
---|
| 138 | mTriStride (sizeof(IndexedTriangle)), |
---|
| 139 | mVertexStride (sizeof(Point)), |
---|
| 140 | #endif |
---|
| 141 | #endif |
---|
| 142 | mNbTris (0), |
---|
| 143 | mNbVerts (0), |
---|
| 144 | |
---|
| 145 | Single(true) |
---|
| 146 | { |
---|
| 147 | } |
---|
| 148 | |
---|
| 149 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 150 | /** |
---|
| 151 | * Destructor. |
---|
| 152 | */ |
---|
| 153 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 154 | MeshInterface::~MeshInterface() |
---|
| 155 | { |
---|
| 156 | } |
---|
| 157 | |
---|
| 158 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 159 | /** |
---|
| 160 | * Checks the mesh interface is valid, i.e. things have been setup correctly. |
---|
| 161 | * \return true if valid |
---|
| 162 | */ |
---|
| 163 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 164 | bool MeshInterface::IsValid() const |
---|
| 165 | { |
---|
| 166 | if(!mNbTris || !mNbVerts) return false; |
---|
| 167 | #ifdef OPC_USE_CALLBACKS |
---|
| 168 | if(!mObjCallback) return false; |
---|
| 169 | #else |
---|
| 170 | if(!mTris || !mVerts) return false; |
---|
| 171 | #endif |
---|
| 172 | return true; |
---|
| 173 | } |
---|
| 174 | |
---|
| 175 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 176 | /** |
---|
| 177 | * Checks the mesh itself is valid. |
---|
| 178 | * Currently we only look for degenerate faces. |
---|
| 179 | * \return number of degenerate faces |
---|
| 180 | */ |
---|
| 181 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 182 | udword MeshInterface::CheckTopology() const |
---|
| 183 | { |
---|
| 184 | // Check topology. If the model contains degenerate faces, collision report can be wrong in some cases. |
---|
| 185 | // e.g. it happens with the standard MAX teapot. So clean your meshes first... If you don't have a mesh cleaner |
---|
| 186 | // you can try this: www.codercorner.com/Consolidation.zip |
---|
| 187 | |
---|
| 188 | udword NbDegenerate = 0; |
---|
| 189 | |
---|
| 190 | VertexPointers VP; |
---|
| 191 | |
---|
| 192 | // Using callbacks, we don't have access to vertex indices. Nevertheless we still can check for |
---|
| 193 | // redundant vertex pointers, which cover all possibilities (callbacks/pointers/strides). |
---|
| 194 | for(udword i=0;i<mNbTris;i++) |
---|
| 195 | { |
---|
| 196 | GetTriangle(VP, i); |
---|
| 197 | |
---|
| 198 | if( (VP.Vertex[0]==VP.Vertex[1]) |
---|
| 199 | || (VP.Vertex[1]==VP.Vertex[2]) |
---|
| 200 | || (VP.Vertex[2]==VP.Vertex[0])) NbDegenerate++; |
---|
| 201 | } |
---|
| 202 | |
---|
| 203 | return NbDegenerate; |
---|
| 204 | } |
---|
| 205 | |
---|
| 206 | #ifdef OPC_USE_CALLBACKS |
---|
| 207 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 208 | /** |
---|
| 209 | * Callback control: setups object callback. Must provide triangle-vertices for a given triangle index. |
---|
| 210 | * \param callback [in] user-defined callback |
---|
| 211 | * \param user_data [in] user-defined data |
---|
| 212 | * \return true if success |
---|
| 213 | */ |
---|
| 214 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 215 | bool MeshInterface::SetCallback(RequestCallback callback, void* user_data) |
---|
| 216 | { |
---|
| 217 | if(!callback) return SetIceError("MeshInterface::SetCallback: callback pointer is null"); |
---|
| 218 | |
---|
| 219 | mObjCallback = callback; |
---|
| 220 | mUserData = user_data; |
---|
| 221 | return true; |
---|
| 222 | } |
---|
| 223 | #else |
---|
| 224 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 225 | /** |
---|
| 226 | * Pointers control: setups object pointers. Must provide access to faces and vertices for a given object. |
---|
| 227 | * \param tris [in] pointer to triangles |
---|
| 228 | * \param verts [in] pointer to vertices |
---|
| 229 | * \return true if success |
---|
| 230 | */ |
---|
| 231 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 232 | bool MeshInterface::SetPointers(const IndexedTriangle* tris, const Point* verts) |
---|
| 233 | { |
---|
| 234 | if(!tris || !verts) return SetIceError("MeshInterface::SetPointers: pointer is null", null); |
---|
| 235 | |
---|
| 236 | mTris = tris; |
---|
| 237 | mVerts = verts; |
---|
| 238 | return true; |
---|
| 239 | } |
---|
| 240 | #ifdef OPC_USE_STRIDE |
---|
| 241 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 242 | /** |
---|
| 243 | * Strides control |
---|
| 244 | * \param tri_stride [in] size of a triangle in bytes. The first sizeof(IndexedTriangle) bytes are used to get vertex indices. |
---|
| 245 | * \param vertex_stride [in] size of a vertex in bytes. The first sizeof(Point) bytes are used to get vertex position. |
---|
| 246 | * \return true if success |
---|
| 247 | */ |
---|
| 248 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 249 | bool MeshInterface::SetStrides(udword tri_stride, udword vertex_stride) |
---|
| 250 | { |
---|
| 251 | if(tri_stride<sizeof(IndexedTriangle)) return SetIceError("MeshInterface::SetStrides: invalid triangle stride", null); |
---|
| 252 | if(vertex_stride<sizeof(Point)) return SetIceError("MeshInterface::SetStrides: invalid vertex stride", null); |
---|
| 253 | |
---|
| 254 | mTriStride = tri_stride; |
---|
| 255 | mVertexStride = vertex_stride; |
---|
| 256 | return true; |
---|
| 257 | } |
---|
| 258 | #endif |
---|
| 259 | #endif |
---|
| 260 | |
---|
| 261 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 262 | /** |
---|
| 263 | * Remaps client's mesh according to a permutation. |
---|
| 264 | * \param nb_indices [in] number of indices in the permutation (will be checked against number of triangles) |
---|
| 265 | * \param permutation [in] list of triangle indices |
---|
| 266 | * \return true if success |
---|
| 267 | */ |
---|
| 268 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 269 | bool MeshInterface::RemapClient(udword nb_indices, const udword* permutation) const |
---|
| 270 | { |
---|
| 271 | // Checkings |
---|
| 272 | if(!nb_indices || !permutation) return false; |
---|
| 273 | if(nb_indices!=mNbTris) return false; |
---|
| 274 | |
---|
| 275 | #ifdef OPC_USE_CALLBACKS |
---|
| 276 | // We can't really do that using callbacks |
---|
| 277 | return false; |
---|
| 278 | #else |
---|
| 279 | IndexedTriangle* Tmp = new IndexedTriangle[mNbTris]; |
---|
| 280 | CHECKALLOC(Tmp); |
---|
| 281 | |
---|
| 282 | #ifdef OPC_USE_STRIDE |
---|
| 283 | udword Stride = mTriStride; |
---|
| 284 | #else |
---|
| 285 | udword Stride = sizeof(IndexedTriangle); |
---|
| 286 | #endif |
---|
| 287 | |
---|
| 288 | for(udword i=0;i<mNbTris;i++) |
---|
| 289 | { |
---|
| 290 | const IndexedTriangle* T = (const IndexedTriangle*)(((ubyte*)mTris) + i * Stride); |
---|
| 291 | Tmp[i] = *T; |
---|
| 292 | } |
---|
| 293 | |
---|
| 294 | for(udword i=0;i<mNbTris;i++) |
---|
| 295 | { |
---|
| 296 | IndexedTriangle* T = (IndexedTriangle*)(((ubyte*)mTris) + i * Stride); |
---|
| 297 | *T = Tmp[permutation[i]]; |
---|
| 298 | } |
---|
| 299 | |
---|
| 300 | DELETEARRAY(Tmp); |
---|
| 301 | #endif |
---|
| 302 | return true; |
---|
| 303 | } |
---|