aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/ode-0.9/ode/src/collision_trimesh_opcode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/ode-0.9/ode/src/collision_trimesh_opcode.cpp')
-rw-r--r--libraries/ode-0.9/ode/src/collision_trimesh_opcode.cpp833
1 files changed, 833 insertions, 0 deletions
diff --git a/libraries/ode-0.9/ode/src/collision_trimesh_opcode.cpp b/libraries/ode-0.9/ode/src/collision_trimesh_opcode.cpp
new file mode 100644
index 0000000..07f3f8a
--- /dev/null
+++ b/libraries/ode-0.9/ode/src/collision_trimesh_opcode.cpp
@@ -0,0 +1,833 @@
1/*************************************************************************
2 * *
3 * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. *
4 * All rights reserved. Email: russ@q12.org Web: www.q12.org *
5 * *
6 * This library is free software; you can redistribute it and/or *
7 * modify it under the terms of EITHER: *
8 * (1) The GNU Lesser General Public License as published by the Free *
9 * Software Foundation; either version 2.1 of the License, or (at *
10 * your option) any later version. The text of the GNU Lesser *
11 * General Public License is included with this library in the *
12 * file LICENSE.TXT. *
13 * (2) The BSD-style license that is included with this library in *
14 * the file LICENSE-BSD.TXT. *
15 * *
16 * This library is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
19 * LICENSE.TXT and LICENSE-BSD.TXT for more details. *
20 * *
21 *************************************************************************/
22
23// TriMesh code by Erwin de Vries.
24
25#include <ode/collision.h>
26#include <ode/matrix.h>
27#include <ode/rotation.h>
28#include <ode/odemath.h>
29#include "collision_util.h"
30#define TRIMESH_INTERNAL
31#include "collision_trimesh_internal.h"
32
33#if dTRIMESH_ENABLED
34#if dTRIMESH_OPCODE
35
36// Trimesh data
37dxTriMeshData::dxTriMeshData() : UseFlags( NULL )
38{
39#if !dTRIMESH_ENABLED
40 dUASSERT(false, "dTRIMESH_ENABLED is not defined. Trimesh geoms will not work");
41#endif
42}
43
44dxTriMeshData::~dxTriMeshData()
45{
46 if ( UseFlags )
47 delete [] UseFlags;
48}
49
50void
51dxTriMeshData::Build(const void* Vertices, int VertexStide, int VertexCount,
52 const void* Indices, int IndexCount, int TriStride,
53 const void* in_Normals,
54 bool Single)
55{
56#if dTRIMESH_ENABLED
57
58 Mesh.SetNbTriangles(IndexCount / 3);
59 Mesh.SetNbVertices(VertexCount);
60 Mesh.SetPointers((IndexedTriangle*)Indices, (Point*)Vertices);
61 Mesh.SetStrides(TriStride, VertexStide);
62 Mesh.Single = Single;
63
64 // Build tree
65 BuildSettings Settings;
66 // recommended in Opcode User Manual
67 //Settings.mRules = SPLIT_COMPLETE | SPLIT_SPLATTERPOINTS | SPLIT_GEOMCENTER;
68 // used in ODE, why?
69 //Settings.mRules = SPLIT_BEST_AXIS;
70
71 // best compromise?
72 Settings.mRules = SPLIT_BEST_AXIS | SPLIT_SPLATTER_POINTS | SPLIT_GEOM_CENTER;
73
74
75 OPCODECREATE TreeBuilder;
76 TreeBuilder.mIMesh = &Mesh;
77
78 TreeBuilder.mSettings = Settings;
79 TreeBuilder.mNoLeaf = true;
80 TreeBuilder.mQuantized = false;
81
82 TreeBuilder.mKeepOriginal = false;
83 TreeBuilder.mCanRemap = false;
84
85
86
87 BVTree.Build(TreeBuilder);
88
89 // compute model space AABB
90 dVector3 AABBMax, AABBMin;
91 AABBMax[0] = AABBMax[1] = AABBMax[2] = (dReal) -dInfinity;
92 AABBMin[0] = AABBMin[1] = AABBMin[2] = (dReal) dInfinity;
93 if( Single ) {
94 const char* verts = (const char*)Vertices;
95 for( int i = 0; i < VertexCount; ++i ) {
96 const float* v = (const float*)verts;
97 if( v[0] > AABBMax[0] ) AABBMax[0] = v[0];
98 if( v[1] > AABBMax[1] ) AABBMax[1] = v[1];
99 if( v[2] > AABBMax[2] ) AABBMax[2] = v[2];
100 if( v[0] < AABBMin[0] ) AABBMin[0] = v[0];
101 if( v[1] < AABBMin[1] ) AABBMin[1] = v[1];
102 if( v[2] < AABBMin[2] ) AABBMin[2] = v[2];
103 verts += VertexStide;
104 }
105 } else {
106 const char* verts = (const char*)Vertices;
107 for( int i = 0; i < VertexCount; ++i ) {
108 const double* v = (const double*)verts;
109 if( v[0] > AABBMax[0] ) AABBMax[0] = (dReal) v[0];
110 if( v[1] > AABBMax[1] ) AABBMax[1] = (dReal) v[1];
111 if( v[2] > AABBMax[2] ) AABBMax[2] = (dReal) v[2];
112 if( v[0] < AABBMin[0] ) AABBMin[0] = (dReal) v[0];
113 if( v[1] < AABBMin[1] ) AABBMin[1] = (dReal) v[1];
114 if( v[2] < AABBMin[2] ) AABBMin[2] = (dReal) v[2];
115 verts += VertexStide;
116 }
117 }
118 AABBCenter[0] = (AABBMin[0] + AABBMax[0]) * REAL(0.5);
119 AABBCenter[1] = (AABBMin[1] + AABBMax[1]) * REAL(0.5);
120 AABBCenter[2] = (AABBMin[2] + AABBMax[2]) * REAL(0.5);
121 AABBExtents[0] = AABBMax[0] - AABBCenter[0];
122 AABBExtents[1] = AABBMax[1] - AABBCenter[1];
123 AABBExtents[2] = AABBMax[2] - AABBCenter[2];
124
125 // user data (not used by OPCODE)
126 Normals = (dReal *) in_Normals;
127
128 UseFlags = 0;
129
130#endif // dTRIMESH_ENABLED
131}
132
133struct EdgeRecord
134{
135 int VertIdx1; // Index into vertex array for this edges vertices
136 int VertIdx2;
137 int TriIdx; // Index into triangle array for triangle this edge belongs to
138
139 uint8 EdgeFlags;
140 uint8 Vert1Flags;
141 uint8 Vert2Flags;
142 bool Concave;
143};
144
145// Edge comparison function for qsort
146static int EdgeCompare(const void* edge1, const void* edge2)
147{
148 EdgeRecord* e1 = (EdgeRecord*)edge1;
149 EdgeRecord* e2 = (EdgeRecord*)edge2;
150
151 if (e1->VertIdx1 == e2->VertIdx1)
152 return e1->VertIdx2 - e2->VertIdx2;
153 else
154 return e1->VertIdx1 - e2->VertIdx1;
155}
156
157void SetupEdge(EdgeRecord* edge, int edgeIdx, int triIdx, const unsigned int* vertIdxs)
158{
159 if (edgeIdx == 0)
160 {
161 edge->EdgeFlags = dxTriMeshData::kEdge0;
162 edge->Vert1Flags = dxTriMeshData::kVert0;
163 edge->Vert2Flags = dxTriMeshData::kVert1;
164 edge->VertIdx1 = vertIdxs[0];
165 edge->VertIdx2 = vertIdxs[1];
166 }
167 else if (edgeIdx == 1)
168 {
169 edge->EdgeFlags = dxTriMeshData::kEdge1;
170 edge->Vert1Flags = dxTriMeshData::kVert1;
171 edge->Vert2Flags = dxTriMeshData::kVert2;
172 edge->VertIdx1 = vertIdxs[1];
173 edge->VertIdx2 = vertIdxs[2];
174 }
175 else if (edgeIdx == 2)
176 {
177 edge->EdgeFlags = dxTriMeshData::kEdge2;
178 edge->Vert1Flags = dxTriMeshData::kVert2;
179 edge->Vert2Flags = dxTriMeshData::kVert0;
180 edge->VertIdx1 = vertIdxs[2];
181 edge->VertIdx2 = vertIdxs[0];
182 }
183
184 // Make sure vert index 1 is less than index 2 (for easier sorting)
185 if (edge->VertIdx1 > edge->VertIdx2)
186 {
187 unsigned int tempIdx = edge->VertIdx1;
188 edge->VertIdx1 = edge->VertIdx2;
189 edge->VertIdx2 = tempIdx;
190
191 uint8 tempFlags = edge->Vert1Flags;
192 edge->Vert1Flags = edge->Vert2Flags;
193 edge->Vert2Flags = tempFlags;
194 }
195
196 edge->TriIdx = triIdx;
197 edge->Concave = false;
198}
199
200#if dTRIMESH_ENABLED
201
202// Get the vertex opposite this edge in the triangle
203inline Point GetOppositeVert(EdgeRecord* edge, const Point* vertices[])
204{
205 if ((edge->Vert1Flags == dxTriMeshData::kVert0 && edge->Vert2Flags == dxTriMeshData::kVert1) ||
206 (edge->Vert1Flags == dxTriMeshData::kVert1 && edge->Vert2Flags == dxTriMeshData::kVert0))
207 {
208 return *vertices[2];
209 }
210 else if ((edge->Vert1Flags == dxTriMeshData::kVert1 && edge->Vert2Flags == dxTriMeshData::kVert2) ||
211 (edge->Vert1Flags == dxTriMeshData::kVert2 && edge->Vert2Flags == dxTriMeshData::kVert1))
212 {
213 return *vertices[0];
214 }
215 else
216 return *vertices[1];
217}
218
219#endif // dTRIMESH_ENABLED
220
221void dxTriMeshData::Preprocess()
222{
223
224#if dTRIMESH_ENABLED
225
226 // If this mesh has already been preprocessed, exit
227 if (UseFlags)
228 return;
229
230 udword numTris = Mesh.GetNbTriangles();
231 udword numEdges = numTris * 3;
232
233 UseFlags = new uint8[numTris];
234 memset(UseFlags, 0, sizeof(uint8) * numTris);
235
236 EdgeRecord* records = new EdgeRecord[numEdges];
237
238 // Make a list of every edge in the mesh
239 const IndexedTriangle* tris = Mesh.GetTris();
240 for (unsigned int i = 0; i < numTris; i++)
241 {
242 SetupEdge(&records[i*3], 0, i, tris->mVRef);
243 SetupEdge(&records[i*3+1], 1, i, tris->mVRef);
244 SetupEdge(&records[i*3+2], 2, i, tris->mVRef);
245
246 tris = (const IndexedTriangle*)(((uint8*)tris) + Mesh.GetTriStride());
247 }
248
249 // Sort the edges, so the ones sharing the same verts are beside each other
250 qsort(records, numEdges, sizeof(EdgeRecord), EdgeCompare);
251
252 // Go through the sorted list of edges and flag all the edges and vertices that we need to use
253 for (unsigned int i = 0; i < numEdges; i++)
254 {
255 EdgeRecord* rec1 = &records[i];
256 EdgeRecord* rec2 = 0;
257 if (i < numEdges - 1)
258 rec2 = &records[i+1];
259
260 if (rec2 &&
261 rec1->VertIdx1 == rec2->VertIdx1 &&
262 rec1->VertIdx2 == rec2->VertIdx2)
263 {
264 VertexPointers vp;
265 Mesh.GetTriangle(vp, rec1->TriIdx);
266
267 // Get the normal of the first triangle
268 Point triNorm = (*vp.Vertex[2] - *vp.Vertex[1]) ^ (*vp.Vertex[0] - *vp.Vertex[1]);
269 triNorm.Normalize();
270
271 // Get the vert opposite this edge in the first triangle
272 Point oppositeVert1 = GetOppositeVert(rec1, vp.Vertex);
273
274 // Get the vert opposite this edge in the second triangle
275 Mesh.GetTriangle(vp, rec2->TriIdx);
276 Point oppositeVert2 = GetOppositeVert(rec2, vp.Vertex);
277
278 float dot = triNorm.Dot((oppositeVert2 - oppositeVert1).Normalize());
279
280 // We let the dot threshold for concavity get slightly negative to allow for rounding errors
281 static const float kConcaveThresh = -0.000001f;
282
283 // This is a concave edge, leave it for the next pass
284 if (dot >= kConcaveThresh)
285 rec1->Concave = true;
286 // If this is a convex edge, mark its vertices and edge as used
287 else
288 UseFlags[rec1->TriIdx] |= rec1->Vert1Flags | rec1->Vert2Flags | rec1->EdgeFlags;
289
290 // Skip the second edge
291 i++;
292 }
293 // This is a boundary edge
294 else
295 {
296 UseFlags[rec1->TriIdx] |= rec1->Vert1Flags | rec1->Vert2Flags | rec1->EdgeFlags;
297 }
298 }
299
300 // Go through the list once more, and take any edge we marked as concave and
301 // clear it's vertices flags in any triangles they're used in
302 for (unsigned int i = 0; i < numEdges; i++)
303 {
304 EdgeRecord& er = records[i];
305
306 if (er.Concave)
307 {
308 for (unsigned int j = 0; j < numEdges; j++)
309 {
310 EdgeRecord& curER = records[j];
311
312 if (curER.VertIdx1 == er.VertIdx1 ||
313 curER.VertIdx1 == er.VertIdx2)
314 UseFlags[curER.TriIdx] &= ~curER.Vert1Flags;
315
316 if (curER.VertIdx2 == er.VertIdx1 ||
317 curER.VertIdx2 == er.VertIdx2)
318 UseFlags[curER.TriIdx] &= ~curER.Vert2Flags;
319 }
320 }
321 }
322
323 delete [] records;
324
325#endif // dTRIMESH_ENABLED
326
327}
328
329dTriMeshDataID dGeomTriMeshDataCreate(){
330 return new dxTriMeshData();
331}
332
333void dGeomTriMeshDataDestroy(dTriMeshDataID g){
334 delete g;
335}
336
337
338
339
340void dGeomTriMeshSetLastTransform( dxGeom* g, dMatrix4 last_trans )
341{
342 dAASSERT(g)
343 dUASSERT(g->type == dTriMeshClass, "geom not trimesh");
344
345 for (int i=0; i<16; i++)
346 (((dxTriMesh*)g)->last_trans)[ i ] = last_trans[ i ];
347
348 return;
349}
350
351
352dReal* dGeomTriMeshGetLastTransform( dxGeom* g )
353{
354 dAASSERT(g)
355 dUASSERT(g->type == dTriMeshClass, "geom not trimesh");
356
357 return (dReal*)(((dxTriMesh*)g)->last_trans);
358}
359
360
361
362
363void dGeomTriMeshDataSet(dTriMeshDataID g, int data_id, void* in_data)
364{
365 dUASSERT(g, "argument not trimesh data");
366
367 switch (data_id)
368 {
369 case TRIMESH_FACE_NORMALS:
370 g->Normals = (dReal *) in_data;
371 break;
372
373 default:
374 dUASSERT(data_id, "invalid data type");
375 break;
376 }
377
378 return;
379}
380
381
382
383void* dGeomTriMeshDataGet(dTriMeshDataID g, int data_id)
384{
385 dUASSERT(g, "argument not trimesh data");
386
387 switch (data_id)
388 {
389 case TRIMESH_FACE_NORMALS:
390 return (void *) g->Normals;
391 break;
392
393 default:
394 dUASSERT(data_id, "invalid data type");
395 break;
396 }
397
398 return NULL;
399}
400
401
402void dGeomTriMeshDataBuildSingle1(dTriMeshDataID g,
403 const void* Vertices, int VertexStride, int VertexCount,
404 const void* Indices, int IndexCount, int TriStride,
405 const void* Normals)
406{
407 dUASSERT(g, "argument not trimesh data");
408
409 g->Build(Vertices, VertexStride, VertexCount,
410 Indices, IndexCount, TriStride,
411 Normals,
412 true);
413}
414
415
416void dGeomTriMeshDataBuildSingle(dTriMeshDataID g,
417 const void* Vertices, int VertexStride, int VertexCount,
418 const void* Indices, int IndexCount, int TriStride)
419{
420 dGeomTriMeshDataBuildSingle1(g, Vertices, VertexStride, VertexCount,
421 Indices, IndexCount, TriStride, (void*)NULL);
422}
423
424
425void dGeomTriMeshDataBuildDouble1(dTriMeshDataID g,
426 const void* Vertices, int VertexStride, int VertexCount,
427 const void* Indices, int IndexCount, int TriStride,
428 const void* Normals)
429{
430 dUASSERT(g, "argument not trimesh data");
431
432 g->Build(Vertices, VertexStride, VertexCount,
433 Indices, IndexCount, TriStride,
434 Normals,
435 false);
436}
437
438
439void dGeomTriMeshDataBuildDouble(dTriMeshDataID g,
440 const void* Vertices, int VertexStride, int VertexCount,
441 const void* Indices, int IndexCount, int TriStride) {
442 dGeomTriMeshDataBuildDouble1(g, Vertices, VertexStride, VertexCount,
443 Indices, IndexCount, TriStride, NULL);
444}
445
446
447void dGeomTriMeshDataBuildSimple1(dTriMeshDataID g,
448 const dReal* Vertices, int VertexCount,
449 const int* Indices, int IndexCount,
450 const int* Normals){
451#ifdef dSINGLE
452 dGeomTriMeshDataBuildSingle1(g,
453 Vertices, 4 * sizeof(dReal), VertexCount,
454 Indices, IndexCount, 3 * sizeof(unsigned int),
455 Normals);
456#else
457 dGeomTriMeshDataBuildDouble1(g, Vertices, 4 * sizeof(dReal), VertexCount,
458 Indices, IndexCount, 3 * sizeof(unsigned int),
459 Normals);
460#endif
461}
462
463
464void dGeomTriMeshDataBuildSimple(dTriMeshDataID g,
465 const dReal* Vertices, int VertexCount,
466 const int* Indices, int IndexCount) {
467 dGeomTriMeshDataBuildSimple1(g,
468 Vertices, VertexCount, Indices, IndexCount,
469 (const int*)NULL);
470}
471
472void dGeomTriMeshDataPreprocess(dTriMeshDataID g)
473{
474 dUASSERT(g, "argument not trimesh data");
475 g->Preprocess();
476}
477
478void dGeomTriMeshDataGetBuffer(dTriMeshDataID g, unsigned char** buf, int* bufLen)
479{
480 dUASSERT(g, "argument not trimesh data");
481#if dTRIMESH_ENABLED
482 *buf = g->UseFlags;
483 *bufLen = g->Mesh.GetNbTriangles();
484#endif // dTRIMESH_ENABLED
485}
486
487void dGeomTriMeshDataSetBuffer(dTriMeshDataID g, unsigned char* buf)
488{
489 dUASSERT(g, "argument not trimesh data");
490 g->UseFlags = buf;
491}
492
493
494#if dTRIMESH_ENABLED
495
496// Trimesh Class Statics
497PlanesCollider dxTriMesh::_PlanesCollider;
498SphereCollider dxTriMesh::_SphereCollider;
499OBBCollider dxTriMesh::_OBBCollider;
500RayCollider dxTriMesh::_RayCollider;
501AABBTreeCollider dxTriMesh::_AABBTreeCollider;
502LSSCollider dxTriMesh::_LSSCollider;
503
504SphereCache dxTriMesh::defaultSphereCache;
505OBBCache dxTriMesh::defaultBoxCache;
506LSSCache dxTriMesh::defaultCapsuleCache;
507
508CollisionFaces dxTriMesh::Faces;
509
510#endif // dTRIMESH_ENABLED
511
512
513dxTriMesh::dxTriMesh(dSpaceID Space, dTriMeshDataID Data) : dxGeom(Space, 1)
514{
515 type = dTriMeshClass;
516
517 this->Data = Data;
518
519#if dTRIMESH_ENABLED
520
521 _RayCollider.SetDestination(&Faces);
522
523 _PlanesCollider.SetTemporalCoherence(true);
524
525 _SphereCollider.SetTemporalCoherence(true);
526 _SphereCollider.SetPrimitiveTests(false);
527
528 _OBBCollider.SetTemporalCoherence(true);
529
530 // no first-contact test (i.e. return full contact info)
531 _AABBTreeCollider.SetFirstContact( false );
532 // temporal coherence only works with "first conact" tests
533 _AABBTreeCollider.SetTemporalCoherence(false);
534 // Perform full BV-BV tests (true) or SAT-lite tests (false)
535 _AABBTreeCollider.SetFullBoxBoxTest( true );
536 // Perform full Primitive-BV tests (true) or SAT-lite tests (false)
537 _AABBTreeCollider.SetFullPrimBoxTest( true );
538 _LSSCollider.SetTemporalCoherence(false);
539
540#endif // dTRIMESH_ENABLED
541
542 /* TC has speed/space 'issues' that don't make it a clear
543 win by default on spheres/boxes. */
544 this->doSphereTC = false;
545 this->doBoxTC = false;
546 this->doCapsuleTC = false;
547
548#if dTRIMESH_ENABLED
549
550 const char* msg;
551 if ((msg =_AABBTreeCollider.ValidateSettings()))
552 dDebug (d_ERR_UASSERT, msg, " (%s:%d)", __FILE__,__LINE__);
553 _LSSCollider.SetPrimitiveTests(false);
554 _LSSCollider.SetFirstContact(false);
555
556#endif // dTRIMESH_ENABLED
557
558 for (int i=0; i<16; i++)
559 last_trans[i] = REAL( 0.0 );
560}
561
562dxTriMesh::~dxTriMesh(){
563 //
564}
565
566// Cleanup for allocations when shutting down ODE
567void opcode_collider_cleanup()
568{
569#if dTRIMESH_ENABLED
570
571 // Clear TC caches
572 dxTriMesh::Faces.Empty();
573 dxTriMesh::defaultSphereCache.TouchedPrimitives.Empty();
574 dxTriMesh::defaultBoxCache.TouchedPrimitives.Empty();
575 dxTriMesh::defaultCapsuleCache.TouchedPrimitives.Empty();
576
577#endif // dTRIMESH_ENABLED
578}
579
580
581
582void dxTriMesh::ClearTCCache()
583{
584#if dTRIMESH_ENABLED
585 /* dxTriMesh::ClearTCCache uses dArray's setSize(0) to clear the caches -
586 but the destructor isn't called when doing this, so we would leak.
587 So, call the previous caches' containers' destructors by hand first. */
588 int i, n;
589 n = SphereTCCache.size();
590 for( i = 0; i < n; ++i ) {
591 SphereTCCache[i].~SphereTC();
592 }
593 SphereTCCache.setSize(0);
594 n = BoxTCCache.size();
595 for( i = 0; i < n; ++i ) {
596 BoxTCCache[i].~BoxTC();
597 }
598 BoxTCCache.setSize(0);
599 n = CapsuleTCCache.size();
600 for( i = 0; i < n; ++i ) {
601 CapsuleTCCache[i].~CapsuleTC();
602 }
603 CapsuleTCCache.setSize(0);
604#endif // dTRIMESH_ENABLED
605}
606
607
608int dxTriMesh::AABBTest(dxGeom* g, dReal aabb[6]){
609 return 1;
610}
611
612
613void dxTriMesh::computeAABB() {
614 const dxTriMeshData* d = Data;
615 dVector3 c;
616 const dMatrix3& R = final_posr->R;
617 const dVector3& pos = final_posr->pos;
618
619 dMULTIPLY0_331( c, R, d->AABBCenter );
620
621 dReal xrange = dFabs(R[0] * Data->AABBExtents[0]) +
622 dFabs(R[1] * Data->AABBExtents[1]) +
623 dFabs(R[2] * Data->AABBExtents[2]);
624 dReal yrange = dFabs(R[4] * Data->AABBExtents[0]) +
625 dFabs(R[5] * Data->AABBExtents[1]) +
626 dFabs(R[6] * Data->AABBExtents[2]);
627 dReal zrange = dFabs(R[8] * Data->AABBExtents[0]) +
628 dFabs(R[9] * Data->AABBExtents[1]) +
629 dFabs(R[10] * Data->AABBExtents[2]);
630
631 aabb[0] = c[0] + pos[0] - xrange;
632 aabb[1] = c[0] + pos[0] + xrange;
633 aabb[2] = c[1] + pos[1] - yrange;
634 aabb[3] = c[1] + pos[1] + yrange;
635 aabb[4] = c[2] + pos[2] - zrange;
636 aabb[5] = c[2] + pos[2] + zrange;
637}
638
639
640void dxTriMeshData::UpdateData()
641{
642#if dTRIMESH_ENABLED
643 BVTree.Refit();
644#endif // dTRIMESH_ENABLED
645}
646
647
648dGeomID dCreateTriMesh(dSpaceID space,
649 dTriMeshDataID Data,
650 dTriCallback* Callback,
651 dTriArrayCallback* ArrayCallback,
652 dTriRayCallback* RayCallback)
653{
654 dxTriMesh* Geom = new dxTriMesh(space, Data);
655 Geom->Callback = Callback;
656 Geom->ArrayCallback = ArrayCallback;
657 Geom->RayCallback = RayCallback;
658
659 return Geom;
660}
661
662void dGeomTriMeshSetCallback(dGeomID g, dTriCallback* Callback)
663{
664 dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
665 ((dxTriMesh*)g)->Callback = Callback;
666}
667
668dTriCallback* dGeomTriMeshGetCallback(dGeomID g)
669{
670 dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
671 return ((dxTriMesh*)g)->Callback;
672}
673
674void dGeomTriMeshSetArrayCallback(dGeomID g, dTriArrayCallback* ArrayCallback)
675{
676 dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
677 ((dxTriMesh*)g)->ArrayCallback = ArrayCallback;
678}
679
680dTriArrayCallback* dGeomTriMeshGetArrayCallback(dGeomID g)
681{
682 dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
683 return ((dxTriMesh*)g)->ArrayCallback;
684}
685
686void dGeomTriMeshSetRayCallback(dGeomID g, dTriRayCallback* Callback)
687{
688 dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
689 ((dxTriMesh*)g)->RayCallback = Callback;
690}
691
692dTriRayCallback* dGeomTriMeshGetRayCallback(dGeomID g)
693{
694 dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
695 return ((dxTriMesh*)g)->RayCallback;
696}
697
698void dGeomTriMeshSetData(dGeomID g, dTriMeshDataID Data)
699{
700 dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
701 ((dxTriMesh*)g)->Data = Data;
702 // I changed my data -- I know nothing about my own AABB anymore.
703 ((dxTriMesh*)g)->gflags |= (GEOM_DIRTY|GEOM_AABB_BAD);
704}
705
706dTriMeshDataID dGeomTriMeshGetData(dGeomID g)
707{
708 dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
709 return ((dxTriMesh*)g)->Data;
710}
711
712
713
714void dGeomTriMeshEnableTC(dGeomID g, int geomClass, int enable)
715{
716 dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
717
718 switch (geomClass)
719 {
720 case dSphereClass:
721 ((dxTriMesh*)g)->doSphereTC = (1 == enable);
722 break;
723 case dBoxClass:
724 ((dxTriMesh*)g)->doBoxTC = (1 == enable);
725 break;
726 case dCapsuleClass:
727 ((dxTriMesh*)g)->doCapsuleTC = (1 == enable);
728 break;
729 }
730}
731
732int dGeomTriMeshIsTCEnabled(dGeomID g, int geomClass)
733{
734 dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
735
736 switch (geomClass)
737 {
738 case dSphereClass:
739 if (((dxTriMesh*)g)->doSphereTC)
740 return 1;
741 break;
742 case dBoxClass:
743 if (((dxTriMesh*)g)->doBoxTC)
744 return 1;
745 break;
746 case dCapsuleClass:
747 if (((dxTriMesh*)g)->doCapsuleTC)
748 return 1;
749 break;
750 }
751 return 0;
752}
753
754void dGeomTriMeshClearTCCache(dGeomID g){
755 dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
756
757 dxTriMesh* Geom = (dxTriMesh*)g;
758 Geom->ClearTCCache();
759}
760
761/*
762 * returns the TriMeshDataID
763 */
764dTriMeshDataID
765dGeomTriMeshGetTriMeshDataID(dGeomID g)
766{
767 dxTriMesh* Geom = (dxTriMesh*) g;
768 return Geom->Data;
769}
770
771// Getting data
772void dGeomTriMeshGetTriangle(dGeomID g, int Index, dVector3* v0, dVector3* v1, dVector3* v2){
773 dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
774
775 dxTriMesh* Geom = (dxTriMesh*)g;
776
777 const dVector3& Position = *(const dVector3*)dGeomGetPosition(g);
778 const dMatrix3& Rotation = *(const dMatrix3*)dGeomGetRotation(g);
779
780 dVector3 v[3];
781 FetchTriangle(Geom, Index, Position, Rotation, v);
782
783 if (v0){
784 (*v0)[0] = v[0][0];
785 (*v0)[1] = v[0][1];
786 (*v0)[2] = v[0][2];
787 (*v0)[3] = v[0][3];
788 }
789 if (v1){
790 (*v1)[0] = v[1][0];
791 (*v1)[1] = v[1][1];
792 (*v1)[2] = v[1][2];
793 (*v1)[3] = v[1][3];
794 }
795 if (v2){
796 (*v2)[0] = v[2][0];
797 (*v2)[1] = v[2][1];
798 (*v2)[2] = v[2][2];
799 (*v2)[3] = v[2][3];
800 }
801}
802
803void dGeomTriMeshGetPoint(dGeomID g, int Index, dReal u, dReal v, dVector3 Out){
804 dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
805
806 dxTriMesh* Geom = (dxTriMesh*)g;
807
808 const dVector3& Position = *(const dVector3*)dGeomGetPosition(g);
809 const dMatrix3& Rotation = *(const dMatrix3*)dGeomGetRotation(g);
810
811 dVector3 dv[3];
812 FetchTriangle(Geom, Index, Position, Rotation, dv);
813
814 GetPointFromBarycentric(dv, u, v, Out);
815}
816
817int dGeomTriMeshGetTriangleCount (dGeomID g)
818{
819#if dTRIMESH_ENABLED
820 dxTriMesh* Geom = (dxTriMesh*)g;
821 return Geom->Data->Mesh.GetNbTriangles();
822#else
823 return 0;
824#endif // dTRIMESH_ENABLED
825}
826
827void dGeomTriMeshDataUpdate(dTriMeshDataID g) {
828 dUASSERT(g, "argument not trimesh data");
829 g->UpdateData();
830}
831
832#endif // dTRIMESH_OPCODE
833#endif // dTRIMESH_ENABLED