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 | } |
---|