summaryrefslogtreecommitdiff
path: root/libs/ode-0.16.1/ode/src/collision_trimesh_gimpact.h
blob: b928e9702d3085f32b515b7e490daab6683b8643 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
/*************************************************************************
 *                                                                       *
 * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith.       *
 * All rights reserved.  Email: russ@q12.org   Web: www.q12.org          *
 *                                                                       *
 * This library is free software; you can redistribute it and/or         *
 * modify it under the terms of EITHER:                                  *
 *   (1) The GNU Lesser General Public License as published by the Free  *
 *       Software Foundation; either version 2.1 of the License, or (at  *
 *       your option) any later version. The text of the GNU Lesser      *
 *       General Public License is included with this library in the     *
 *       file LICENSE.TXT.                                               *
 *   (2) The BSD-style license that is included with this library in     *
 *       the file LICENSE-BSD.TXT.                                       *
 *                                                                       *
 * This library is distributed in the hope that it will be useful,       *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files    *
 * LICENSE.TXT and LICENSE-BSD.TXT for more details.                     *
 *                                                                       *
 *************************************************************************/

// TriMesh code by Erwin de Vries.
// Modified for FreeSOLID Compatibility by Rodrigo Hernandez
// Trimesh caches separation by Oleh Derevenko
// TriMesh storage classes refactoring and face angle computation code by Oleh Derevenko (C) 2016-2019


#ifndef _ODE_COLLISION_TRIMESH_GIMPACT_H_
#define _ODE_COLLISION_TRIMESH_GIMPACT_H_


#if dTRIMESH_ENABLED && dTRIMESH_GIMPACT


//****************************************************************************
// dxTriMesh class


#include "collision_kernel.h"
#include "collision_trimesh_colliders.h"
#include "collision_util.h"
#include <ode/collision_trimesh.h>

#include "collision_trimesh_internal.h"
#include <GIMPACT/gimpact.h>


struct TrimeshCollidersCache // Required for compatibility with OPCODE
{
};


typedef dxTriDataBase dxTriMeshData_Parent;
struct dxTriMeshData:
    public dxTriMeshData_Parent
{
public:
    dxTriMeshData():
        dxTriMeshData_Parent()
    {
    }

    ~dxTriMeshData() { /* Do nothing */ }

    using dxTriMeshData_Parent::buildData;
    
    /* Setup the UseFlags array and/or build face angles*/
    bool preprocessData(bool buildUseFlags/*=false*/, FaceAngleStorageMethod faceAndgesRequirement/*=ASM__INVALID*/);
    
private:
    bool meaningfulPreprocessData(FaceAngleStorageMethod faceAndgesRequirement/*=ASM__INVALID*/);

public:
    /* For when app changes the vertices */
    void updateData() { /* Do nothing */ }

public:
    const vec3f *retrieveVertexInstances() const { return (const vec3f *)dxTriMeshData_Parent::retrieveVertexInstances(); }
    const GUINT32 *retrieveTriangleVertexIndices() const { return (const GUINT32 *)dxTriMeshData_Parent::retrieveTriangleVertexIndices(); }

public:
    void assignNormals(const dReal *normals) { dxTriMeshData_Parent::assignNormals(normals); }
    const dReal *retrieveNormals() const { return (const dReal *)dxTriMeshData_Parent::retrieveNormals(); }
    sizeint calculateNormalsMemoryRequirement() const { return retrieveTriangleCount() * (sizeof(dReal) * dSA__MAX); }
};



#ifdef dDOUBLE
// To use GIMPACT with doubles, we need to patch a couple of the GIMPACT functions to 
// convert arguments to floats before sending them in


/// Convert an gimpact vec3f to a ODE dVector3d:   dVector3[i] = vec3f[i]
#define dVECTOR3_VEC3F_COPY(b,a) { \
    (b)[0] = (a)[0];              \
    (b)[1] = (a)[1];              \
    (b)[2] = (a)[2];              \
    (b)[3] = 0;                   \
}

static inline 
void gim_trimesh_get_triangle_verticesODE(GIM_TRIMESH * trimesh, GUINT32 triangle_index, dVector3 v1, dVector3 v2, dVector3 v3)
{
    vec3f src1, src2, src3;
    GREAL *psrc1 = v1 != NULL ? src1 : NULL;
    GREAL *psrc2 = v2 != NULL ? src2 : NULL;
    GREAL *psrc3 = v3 != NULL ? src3 : NULL;
    gim_trimesh_get_triangle_vertices(trimesh, triangle_index, psrc1, psrc2, psrc3);

    if (v1 != NULL)
    {
        dVECTOR3_VEC3F_COPY(v1, src1);
    }

    if (v2 != NULL)
    {
        dVECTOR3_VEC3F_COPY(v2, src2);
    }

    if (v3 != NULL)
    {
        dVECTOR3_VEC3F_COPY(v3, src3);
    }
}

// Anything calling gim_trimesh_get_triangle_vertices from within ODE 
// should be patched through to the dDOUBLE version above

#define gim_trimesh_get_triangle_vertices gim_trimesh_get_triangle_verticesODE

static inline 
int gim_trimesh_ray_closest_collisionODE( GIM_TRIMESH *mesh, dVector3 origin, dVector3 dir, dReal tmax, GIM_TRIANGLE_RAY_CONTACT_DATA *contact )
{
    vec3f dir_vec3f    = { (GREAL)dir[ 0 ],    (GREAL)dir[ 1 ],    (GREAL)dir[ 2 ]    };
    vec3f origin_vec3f = { (GREAL)origin[ 0 ], (GREAL)origin[ 1 ], (GREAL)origin[ 2 ] };

    return gim_trimesh_ray_closest_collision( mesh, origin_vec3f, dir_vec3f, (GREAL)tmax, contact );
}

static inline 
int gim_trimesh_ray_collisionODE( GIM_TRIMESH *mesh, const dVector3 origin, const dVector3 dir, dReal tmax, GIM_TRIANGLE_RAY_CONTACT_DATA *contact )
{
    vec3f dir_vec3f    = { (GREAL)dir[ 0 ],    (GREAL)dir[ 1 ],    (GREAL)dir[ 2 ]    };
    vec3f origin_vec3f = { (GREAL)origin[ 0 ], (GREAL)origin[ 1 ], (GREAL)origin[ 2 ] };

    return gim_trimesh_ray_collision( mesh, origin_vec3f, dir_vec3f, (GREAL)tmax, contact );
}

static inline 
void gim_trimesh_sphere_collisionODE( GIM_TRIMESH *mesh, const dVector3 Position, dReal Radius, GDYNAMIC_ARRAY *contact )
{
    vec3f pos_vec3f = { (GREAL)Position[ 0 ], (GREAL)Position[ 1 ], (GREAL)Position[ 2 ] };
    gim_trimesh_sphere_collision( mesh, pos_vec3f, (GREAL)Radius, contact );
}

static inline 
void gim_trimesh_plane_collisionODE( GIM_TRIMESH *mesh, const dVector4 plane, GDYNAMIC_ARRAY *contact )
{
    vec4f plane_vec4f = { (GREAL)plane[ 0 ], (GREAL)plane[ 1 ], (GREAL)plane[ 2 ], (GREAL)plane[ 3 ] }; \
    gim_trimesh_plane_collision( mesh, plane_vec4f, contact );	    \
}

#define GIM_AABB_COPY( src, dst ) {		\
    (dst)[ 0 ]= (src) -> minX;			\
    (dst)[ 1 ]= (src) -> maxX;			\
    (dst)[ 2 ]= (src) -> minY;			\
    (dst)[ 3 ]= (src) -> maxY;			\
    (dst)[ 4 ]= (src) -> minZ;			\
    (dst)[ 5 ]= (src) -> maxZ;			\
}


#else // #ifdef !dDOUBLE

// With single precision, we can pass native ODE vectors directly to GIMPACT

#define gim_trimesh_ray_closest_collisionODE 	gim_trimesh_ray_closest_collision
#define gim_trimesh_ray_collisionODE 			gim_trimesh_ray_collision
#define gim_trimesh_sphere_collisionODE 		gim_trimesh_sphere_collision
#define gim_trimesh_plane_collisionODE 			gim_trimesh_plane_collision

#define GIM_AABB_COPY( src, dst ) 	memcpy( dst, src, 6 * sizeof( GREAL ) )


#endif // #ifdef !dDOUBLE


typedef dxMeshBase dxTriMesh_Parent;
struct dxTriMesh: 
    public dxTriMesh_Parent
{
public:
    // Functions
    dxTriMesh(dxSpace *Space, dxTriMeshData *Data,
        dTriCallback *Callback, dTriArrayCallback *ArrayCallback, dTriRayCallback *RayCallback):
        dxTriMesh_Parent(Space, NULL, Callback, ArrayCallback, RayCallback, true) // TC has speed/space 'issues' that don't make it a clear win by default on spheres/boxes.
    {
        gim_init_buffer_managers(m_buffer_managers);
        assignMeshData(Data);
    }

    ~dxTriMesh();

    void clearTCCache() { /* do nothing */ }

    virtual void computeAABB();

public:
    dxTriMeshData *retrieveMeshData() const { return getMeshData(); }

    unsigned getMeshTriangleCount() const { return gim_trimesh_get_triangle_count(const_cast<GIM_TRIMESH *>(&m_collision_trimesh)); }

    void fetchMeshTransformedTriangle(dVector3 *const pout_triangle[3], unsigned index)
    {
        gim_trimesh_locks_work_data(&m_collision_trimesh);
        gim_trimesh_get_triangle_vertices(&m_collision_trimesh, (GUINT32)index, *pout_triangle[0], *pout_triangle[1], *pout_triangle[2]);
        gim_trimesh_unlocks_work_data(&m_collision_trimesh);
    }

    void fetchMeshTransformedTriangle(dVector3 out_triangle[3], unsigned index)
    {
        gim_trimesh_locks_work_data(&m_collision_trimesh);
        gim_trimesh_get_triangle_vertices(&m_collision_trimesh, (GUINT32)index, out_triangle[0], out_triangle[1], out_triangle[2]);
        gim_trimesh_unlocks_work_data(&m_collision_trimesh);
    }

private:
    dxTriMeshData *getMeshData() const { return static_cast<dxTriMeshData *>(dxTriMesh_Parent::getMeshData()); }

public:
    enum
    {
        VERTEXINSTANCE_STRIDE = sizeof(vec3f),
        TRIANGLEINDEX_STRIDE = sizeof(GUINT32) * dMTV__MAX,
    };

    void assignMeshData(dxTriMeshData *Data);

public:
    GIM_TRIMESH  m_collision_trimesh;
    GBUFFER_MANAGER_DATA m_buffer_managers[G_BUFFER_MANAGER__MAX];
};


static inline 
void MakeMatrix(const dVector3 position, const dMatrix3 rotation, mat4f m)
{
    m[0][0] = (GREAL)rotation[dM3E_XX];
    m[0][1] = (GREAL)rotation[dM3E_XY];
    m[0][2] = (GREAL)rotation[dM3E_XZ];

    m[1][0] = (GREAL)rotation[dM3E_YX];
    m[1][1] = (GREAL)rotation[dM3E_YY];
    m[1][2] = (GREAL)rotation[dM3E_YZ];

    m[2][0] = (GREAL)rotation[dM3E_ZX];
    m[2][1] = (GREAL)rotation[dM3E_ZY];
    m[2][2] = (GREAL)rotation[dM3E_ZZ];

    m[0][3] = (GREAL)position[dV3E_X];
    m[1][3] = (GREAL)position[dV3E_Y];
    m[2][3] = (GREAL)position[dV3E_Z];
}

static inline 
void MakeMatrix(dxGeom *g, mat4f m)
{
    const dVector3 &position = g->buildUpdatedPosition();
    const dMatrix3 &rotation = g->buildUpdatedRotation();
    MakeMatrix(position, rotation, m);
}


#endif // #if dTRIMESH_ENABLED && dTRIMESH_GIMPACT

#endif	//_ODE_COLLISION_TRIMESH_GIMPACT_H_