1 /*************************************************************************
3 * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. *
4 * All rights reserved. Email: russ@q12.org Web: www.q12.org *
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 *
13 * (2) The BSD-style license that is included with this library in *
14 * the file LICENSE-BSD.TXT. *
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. *
21 *************************************************************************/
23 // TriMesh code by Erwin de Vries.
25 #include <ode/collision.h>
26 #include <ode/rotation.h>
33 #include "collision_util.h"
34 #include "collision_trimesh_internal.h"
37 int dCollideRTL(dxGeom
* g1
, dxGeom
* RayGeom
, int Flags
, dContactGeom
* Contacts
, int Stride
){
38 dIASSERT (Stride
>= (int)sizeof(dContactGeom
));
39 dIASSERT (g1
->type
== dTriMeshClass
);
40 dIASSERT (RayGeom
->type
== dRayClass
);
41 dIASSERT ((Flags
& NUMC_MASK
) >= 1);
43 dxTriMesh
* TriMesh
= (dxTriMesh
*)g1
;
45 const unsigned uiTLSKind
= TriMesh
->getParentSpaceTLSKind();
46 dIASSERT(uiTLSKind
== RayGeom
->getParentSpaceTLSKind()); // The colliding spaces must use matching cleanup method
47 TrimeshCollidersCache
*pccColliderCache
= GetTrimeshCollidersCache(uiTLSKind
);
48 RayCollider
& Collider
= pccColliderCache
->m_RayCollider
;
50 dReal Length
= dGeomRayGetLength(RayGeom
);
52 int FirstContact
= dGeomRayGetFirstContact(RayGeom
);
53 int BackfaceCull
= dGeomRayGetBackfaceCull(RayGeom
);
54 int ClosestHit
= dGeomRayGetClosestHit(RayGeom
);
56 Collider
.SetFirstContact(FirstContact
!= 0);
57 Collider
.SetClosestHit(ClosestHit
!= 0);
58 Collider
.SetCulling(BackfaceCull
!= 0);
59 Collider
.SetMaxDist(Length
);
61 const dVector3
& TLPosition
= *(const dVector3
*)dGeomGetPosition(TriMesh
);
62 const dMatrix3
& TLRotation
= *(const dMatrix3
*)dGeomGetRotation(TriMesh
);
65 const dVector3 ZeroVector3
= { REAL(0.0), };
66 MakeMatrix(ZeroVector3
, TLRotation
, MeshMatrix
);
68 dVector3 Origin
, Direction
;
69 dGeomRayGet(RayGeom
, Origin
, Direction
);
71 dVector3 OffsetOrigin
;
72 dSubtractVectors3(OffsetOrigin
, Origin
, TLPosition
);
76 WorldRay
.mOrig
.Set(OffsetOrigin
[0], OffsetOrigin
[1], OffsetOrigin
[2]);
77 WorldRay
.mDir
.Set(Direction
[0], Direction
[1], Direction
[2]);
81 if (Collider
.Collide(WorldRay
, TriMesh
->retrieveMeshBVTreeRef(), &MeshMatrix
)) {
82 TriCount
= pccColliderCache
->m_Faces
.GetNbFaces();
89 const CollisionFace
* Faces
= pccColliderCache
->m_Faces
.GetFaces();
92 for (int i
= 0; i
< TriCount
; i
++) {
93 if (TriMesh
->m_RayCallback
== null
||
94 TriMesh
->m_RayCallback(TriMesh
, RayGeom
, Faces
[i
].mFaceID
,
95 Faces
[i
].mU
, Faces
[i
].mV
)) {
96 const int& TriIndex
= Faces
[i
].mFaceID
;
97 if (!TriMesh
->invokeCallback(RayGeom
, TriIndex
)) {
101 dContactGeom
* Contact
= SAFECONTACT(Flags
, Contacts
, OutTriCount
, Stride
);
104 TriMesh
->fetchMeshTriangle(dv
, TriIndex
, TLPosition
, TLRotation
);
107 vu
[0] = dv
[1][0] - dv
[0][0];
108 vu
[1] = dv
[1][1] - dv
[0][1];
109 vu
[2] = dv
[1][2] - dv
[0][2];
113 vv
[0] = dv
[2][0] - dv
[0][0];
114 vv
[1] = dv
[2][1] - dv
[0][1];
115 vv
[2] = dv
[2][2] - dv
[0][2];
118 dCalcVectorCross3(Contact
->normal
, vv
, vu
); // Reversed
120 // Even though all triangles might be initially valid,
121 // a triangle may degenerate into a segment after applying
122 // space transformation.
123 if (dSafeNormalize3(Contact
->normal
))
125 // No sense to save on single type conversion in algorithm of this size.
126 // If there would be a custom typedef for distance type it could be used
127 // instead of dReal. However using float directly is the loss of abstraction
128 // and possible loss of precision in future.
129 /*float*/ dReal T
= Faces
[i
].mDistance
;
130 Contact
->pos
[0] = Origin
[0] + (Direction
[0] * T
);
131 Contact
->pos
[1] = Origin
[1] + (Direction
[1] * T
);
132 Contact
->pos
[2] = Origin
[2] + (Direction
[2] * T
);
133 Contact
->pos
[3] = REAL(0.0);
136 Contact
->g1
= TriMesh
;
137 Contact
->g2
= RayGeom
;
138 Contact
->side1
= TriIndex
;
143 // Putting "break" at the end of loop prevents unnecessary checks on first pass and "continue"
144 if (OutTriCount
>= (Flags
& NUMC_MASK
)) {
152 #endif // dTRIMESH_OPCODE
155 int dCollideRTL(dxGeom
* g1
, dxGeom
* RayGeom
, int Flags
, dContactGeom
* Contacts
, int Stride
)
157 dIASSERT (Stride
>= (int)sizeof(dContactGeom
));
158 dIASSERT (g1
->type
== dTriMeshClass
);
159 dIASSERT (RayGeom
->type
== dRayClass
);
160 dIASSERT ((Flags
& NUMC_MASK
) >= 1);
162 dxTriMesh
* TriMesh
= (dxTriMesh
*)g1
;
164 dReal Length
= dGeomRayGetLength(RayGeom
);
165 int FirstContact
= dGeomRayGetFirstContact(RayGeom
);
166 int BackfaceCull
= dGeomRayGetBackfaceCull(RayGeom
);
167 int ClosestHit
= dGeomRayGetClosestHit(RayGeom
);
168 dVector3 Origin
, Direction
;
169 dGeomRayGet(RayGeom
, Origin
, Direction
);
172 GIM_TRIANGLE_RAY_CONTACT_DATA contact_data
;
176 intersect
= gim_trimesh_ray_closest_collisionODE(&TriMesh
->m_collision_trimesh
,Origin
,Direction
,Length
,&contact_data
);
180 intersect
= gim_trimesh_ray_collisionODE(&TriMesh
->m_collision_trimesh
,Origin
,Direction
,Length
,&contact_data
);
189 if(!TriMesh
->m_RayCallback
||
190 TriMesh
->m_RayCallback(TriMesh
, RayGeom
, contact_data
.m_face_id
, contact_data
.u
, contact_data
.v
))
192 dContactGeom
* Contact
= &( Contacts
[ 0 ] );
193 VEC_COPY(Contact
->pos
,contact_data
.m_point
);
194 VEC_COPY(Contact
->normal
,contact_data
.m_normal
);
195 Contact
->depth
= contact_data
.tparam
;
196 Contact
->g1
= TriMesh
;
197 Contact
->g2
= RayGeom
;
198 Contact
->side1
= contact_data
.m_face_id
;
205 #endif // dTRIMESH_GIMPACT
207 #endif // dTRIMESH_ENABLED