aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/ode-0.9/GIMPACT/src/gim_trimesh.cpp
blob: 1872592e754dab2d505cc3269e468cc52c9b14f1 (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
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364

/*
-----------------------------------------------------------------------------
This source file is part of GIMPACT Library.

For the latest info, see http://gimpact.sourceforge.net/

Copyright (c) 2006 Francisco Leon. C.C. 80087371.
email: projectileman@yahoo.com

 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 GIMPACT-LICENSE-LGPL.TXT.
   (2) The BSD-style license that is included with this library in
       the file GIMPACT-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
 GIMPACT-LICENSE-LGPL.TXT and GIMPACT-LICENSE-BSD.TXT for more details.

-----------------------------------------------------------------------------
*/


#include <assert.h>
#include "GIMPACT/gim_trimesh.h"

GUINT gim_trimesh_get_triangle_count(GIM_TRIMESH * trimesh)
{
    return trimesh->m_tri_index_buffer.m_element_count/3;
}

//! Creates the aabb set and the triangles cache
/*!

\param trimesh
\param vertex_array
\param triindex_array
\param transformed_reply If 1, then the m_transformed_vertices is a reply of the source vertices. Else it just be a reference to the original array.
\post it copies the arrays by reference, and creates the auxiliary data (m_aabbset,m_planes_cache_buffer)
*/
void gim_trimesh_create_from_arrays(GIM_TRIMESH * trimesh, GBUFFER_ARRAY * vertex_array, GBUFFER_ARRAY * triindex_array,char transformed_reply)
{
    assert(trimesh);
    assert(vertex_array);
    assert(triindex_array);
    gim_buffer_array_copy_ref(vertex_array,&trimesh->m_source_vertex_buffer);
    gim_buffer_array_copy_ref(triindex_array,&trimesh->m_tri_index_buffer);

    trimesh->m_mask = GIM_TRIMESH_NEED_UPDATE;//needs update
    //Create the transformed vertices
    if(transformed_reply==1)
    {
        trimesh->m_mask |= GIM_TRIMESH_TRANSFORMED_REPLY;
        gim_buffer_array_copy_value(vertex_array,&trimesh->m_transformed_vertex_buffer,G_BUFFER_MANAGER_SYSTEM,G_MU_DYNAMIC_READ_WRITE);
    }
    else
    {
        gim_buffer_array_copy_ref(vertex_array,&trimesh->m_transformed_vertex_buffer);
    }
    //create the box set
    GUINT facecount = gim_trimesh_get_triangle_count(trimesh);

    gim_aabbset_alloc(&trimesh->m_aabbset,facecount);
    //create the planes cache
    GIM_DYNARRAY_CREATE_SIZED(GIM_TRIPLANES_CACHE,trimesh->m_planes_cache_buffer,facecount);
    //Create the bitset
    GIM_BITSET_CREATE_SIZED(trimesh->m_planes_cache_bitset,facecount);
    //Callback is 0
    trimesh->m_update_callback = 0;
    //set to identity
    IDENTIFY_MATRIX_4X4(trimesh->m_transform);
}



//! Create a trimesh from vertex array and an index array
/*!

\param trimesh An uninitialized GIM_TRIMESH  structure
\param vertex_array A buffer to a vec3f array
\param vertex_count
\param triindex_array
\param index_count
\param copy_vertices If 1, it copies the source vertices in another buffer. Else (0) it constructs a reference to the data.
\param copy_indices If 1, it copies the source vertices in another buffer. Else (0) it constructs a reference to the data.
\param transformed_reply If , then the m_transformed_vertices is a reply of the source vertices. Else it just be a reference to the original array.
*/
void gim_trimesh_create_from_data(GIM_TRIMESH * trimesh, vec3f * vertex_array, GUINT vertex_count,char copy_vertices, GUINT * triindex_array, GUINT index_count,char copy_indices,char transformed_reply)
{
    GBUFFER_ARRAY buffer_vertex_array;
    GBUFFER_ARRAY buffer_triindex_array;

    //Create vertices
    if(copy_vertices == 1)
    {
        gim_create_common_buffer_from_data(vertex_array, vertex_count*sizeof(vec3f), &buffer_vertex_array.m_buffer_id);
    }
    else//Create a shared buffer
    {
        gim_create_shared_buffer_from_data(vertex_array, vertex_count*sizeof(vec3f), &buffer_vertex_array.m_buffer_id);
    }
    GIM_BUFFER_ARRAY_INIT_TYPE(vec3f,buffer_vertex_array,buffer_vertex_array.m_buffer_id,vertex_count);


    //Create vertices
    if(copy_indices == 1)
    {
        gim_create_common_buffer_from_data(triindex_array, index_count*sizeof(GUINT), &buffer_triindex_array.m_buffer_id);
    }
    else//Create a shared buffer
    {
        gim_create_shared_buffer_from_data(triindex_array, index_count*sizeof(GUINT), &buffer_triindex_array.m_buffer_id);
    }
    GIM_BUFFER_ARRAY_INIT_TYPE(GUINT,buffer_triindex_array,buffer_triindex_array.m_buffer_id,index_count);

    gim_trimesh_create_from_arrays(trimesh, &buffer_vertex_array, &buffer_triindex_array,transformed_reply);

    ///always call this after create a buffer_array
    GIM_BUFFER_ARRAY_DESTROY(buffer_vertex_array);
    GIM_BUFFER_ARRAY_DESTROY(buffer_triindex_array);
}

//! Clears auxiliary data and releases buffer arrays
void gim_trimesh_destroy(GIM_TRIMESH * trimesh)
{
    gim_aabbset_destroy(&trimesh->m_aabbset);

    GIM_DYNARRAY_DESTROY(trimesh->m_planes_cache_buffer);
    GIM_DYNARRAY_DESTROY(trimesh->m_planes_cache_bitset);

    GIM_BUFFER_ARRAY_DESTROY(trimesh->m_transformed_vertex_buffer);
    GIM_BUFFER_ARRAY_DESTROY(trimesh->m_source_vertex_buffer);
    GIM_BUFFER_ARRAY_DESTROY(trimesh->m_tri_index_buffer);
}

//! Copies two meshes
/*!
\pre dest_trimesh shouldn't be created
\post dest_trimesh will be created
\param source_trimesh
\param dest_trimesh
\param copy_by_reference If 1, it attach a reference to the source vertices, else it copies the vertices
\param transformed_reply IF 1, then it forces the m_trasnformed_vertices to be  a reply of the source vertices
*/
void gim_trimesh_copy(GIM_TRIMESH * source_trimesh,GIM_TRIMESH * dest_trimesh, char copy_by_reference, char transformed_reply)
{
    if(copy_by_reference==1)
    {
        gim_trimesh_create_from_arrays(dest_trimesh, &source_trimesh->m_source_vertex_buffer, &source_trimesh->m_tri_index_buffer,transformed_reply);
    }
    else
    {
        GBUFFER_ARRAY buffer_vertex_array;
        GBUFFER_ARRAY buffer_triindex_array;

        gim_buffer_array_copy_value(&source_trimesh->m_source_vertex_buffer,&buffer_vertex_array,G_BUFFER_MANAGER_SYSTEM,G_MU_DYNAMIC_READ_WRITE);

        gim_buffer_array_copy_value(&source_trimesh->m_tri_index_buffer,&buffer_triindex_array,G_BUFFER_MANAGER_SYSTEM,G_MU_DYNAMIC_READ_WRITE);

        gim_trimesh_create_from_arrays(dest_trimesh, &buffer_vertex_array, &buffer_triindex_array,transformed_reply);

        ///always call this after create a buffer_array
        GIM_BUFFER_ARRAY_DESTROY(buffer_vertex_array);
        GIM_BUFFER_ARRAY_DESTROY(buffer_triindex_array);
    }
}

//! Locks the trimesh for working with it
/*!
\post locks m_tri_index_buffer and m_transformed_vertex_buffer.
\param trimesh
*/
void gim_trimesh_locks_work_data(GIM_TRIMESH * trimesh)
{
    GINT res;
    res=gim_buffer_array_lock(&trimesh->m_tri_index_buffer,G_MA_READ_ONLY);
    assert(res==G_BUFFER_OP_SUCCESS);
    res=gim_buffer_array_lock(&trimesh->m_transformed_vertex_buffer,G_MA_READ_ONLY);
    assert(res==G_BUFFER_OP_SUCCESS);
}

//! unlocks the trimesh
/*!
\post unlocks m_tri_index_buffer and m_transformed_vertex_buffer.
\param trimesh
*/
void gim_trimesh_unlocks_work_data(GIM_TRIMESH * trimesh)
{
    gim_buffer_array_unlock(&trimesh->m_tri_index_buffer);
    gim_buffer_array_unlock(&trimesh->m_transformed_vertex_buffer);
}


//! Returns 1 if the m_transformed_vertex_buffer is a reply of m_source_vertex_buffer
char gim_trimesh_has_tranformed_reply(GIM_TRIMESH * trimesh)
{
    if(trimesh->m_mask&GIM_TRIMESH_TRANSFORMED_REPLY) return 1;
    return 0;
}

//! Returns 1 if the trimesh needs to update their aabbset and the planes cache.
char gim_trimesh_needs_update(GIM_TRIMESH * trimesh)
{
    if(trimesh->m_mask&GIM_TRIMESH_NEED_UPDATE) return 1;
    return 0;
}

//! Change the state of the trimesh for force it to update
/*!
Call it after made changes to the trimesh.
\post gim_trimesh_need_update(trimesh) will return 1
*/
void gim_trimesh_post_update(GIM_TRIMESH * trimesh)
{
    trimesh->m_mask |= GIM_TRIMESH_NEED_UPDATE;
}

//kernel
#define MULT_MAT_VEC4_KERNEL(_mat,_src,_dst) MAT_DOT_VEC_3X4((_dst),(_mat),(_src))

//! Updates m_transformed_vertex_buffer
/*!
\pre m_transformed_vertex_buffer must be unlocked
*/
void gim_trimesh_update_vertices(GIM_TRIMESH * trimesh)
{
    if(gim_trimesh_has_tranformed_reply(trimesh) == 0) return; //Don't perform transformation

    //Vertices
    GBUFFER_ARRAY * psource_vertex_buffer = &trimesh->m_source_vertex_buffer;
    GBUFFER_ARRAY * ptransformed_vertex_buffer = &trimesh->m_transformed_vertex_buffer;
    //Temp transform
    mat4f transform;
    COPY_MATRIX_4X4(transform,trimesh->m_transform);

    GIM_PROCESS_BUFFER_ARRAY(transform,(*psource_vertex_buffer),(*ptransformed_vertex_buffer),MULT_MAT_VEC4_KERNEL,vec3f,vec3f);
}

//! Updates m_aabbset and m_planes_cache_bitset
/*!
\pre gim_trimesh_locks_work_data must be called before
*/
void gim_trimesh_update_aabbset(GIM_TRIMESH * trimesh)
{
    vec3f * transformed_vertices = GIM_BUFFER_ARRAY_POINTER(vec3f,trimesh->m_transformed_vertex_buffer,0);
    assert(transformed_vertices);

    GUINT * triangle_indices = GIM_BUFFER_ARRAY_POINTER(GUINT,trimesh->m_tri_index_buffer,0);
    assert(triangle_indices);
    // box set
    aabb3f * paabb = trimesh->m_aabbset.m_boxes;
    GUINT triangle_count = gim_trimesh_get_triangle_count(trimesh);
    float * v1,*v2,*v3;
    GUINT i;
    for (i=0; i<triangle_count;i++)
    {
        v1 = &transformed_vertices[triangle_indices[0]][0];
        v2 = &transformed_vertices[triangle_indices[1]][0];
        v3 = &transformed_vertices[triangle_indices[2]][0];
        COMPUTEAABB_FOR_TRIANGLE((*paabb),v1,v2,v3);
        triangle_indices+=3;
        paabb++;
    }
    //Clear planes cache
    GIM_BITSET_CLEAR_ALL(trimesh->m_planes_cache_bitset);
    //Sorts set
    gim_aabbset_update(&trimesh->m_aabbset);
}

//! Updates the trimesh if needed
/*!
\post If gim_trimesh_needs_update returns 1, then it calls  gim_trimesh_update_vertices and gim_trimesh_update_aabbset
*/
void gim_trimesh_update(GIM_TRIMESH * trimesh)
{
    if(gim_trimesh_needs_update(trimesh)==0) return;
    gim_trimesh_update_vertices(trimesh);
    gim_trimesh_locks_work_data(trimesh);
    gim_trimesh_update_aabbset(trimesh);
    gim_trimesh_unlocks_work_data(trimesh);

    //Clear update flag
     trimesh->m_mask &= ~GIM_TRIMESH_NEED_UPDATE;
}

void gim_trimesh_set_tranform(GIM_TRIMESH * trimesh, mat4f transform)
{
    GREAL diff = 0.0f;
    float * originaltrans = &trimesh->m_transform[0][0];
    float * newtrans = &transform[0][0];
    GUINT i;
    for (i=0;i<16;i++)
    {
    	diff += fabs(originaltrans[i]-newtrans[i]);
    }

//    if(IS_ZERO(diff)) return ;///don't need to update
    if(diff< 0.00001f) return ;///don't need to update

    COPY_MATRIX_4X4(trimesh->m_transform,transform);

    gim_trimesh_post_update(trimesh);
}

void gim_trimesh_get_triangle_data(GIM_TRIMESH * trimesh, GUINT triangle_index, GIM_TRIANGLE_DATA * tri_data)
{
    vec3f * transformed_vertices = GIM_BUFFER_ARRAY_POINTER(vec3f,trimesh->m_transformed_vertex_buffer,0);

    GUINT * triangle_indices = GIM_BUFFER_ARRAY_POINTER(GUINT,trimesh->m_tri_index_buffer,triangle_index*3);


    //Copy the vertices
    VEC_COPY(tri_data->m_vertices[0],transformed_vertices[triangle_indices[0]]);
    VEC_COPY(tri_data->m_vertices[1],transformed_vertices[triangle_indices[1]]);
    VEC_COPY(tri_data->m_vertices[2],transformed_vertices[triangle_indices[2]]);

    //Get the planes
    GIM_TRIPLANES_CACHE * planes = GIM_DYNARRAY_POINTER(GIM_TRIPLANES_CACHE,trimesh->m_planes_cache_buffer);
    planes += triangle_index;

    //verify planes cache
    GUINT bit_eval;
    GIM_BITSET_GET(trimesh->m_planes_cache_bitset,triangle_index,bit_eval);
    if(bit_eval == 0)// Needs to calc the planes
    {
        //Calc the face plane
        TRIANGLE_PLANE(tri_data->m_vertices[0],tri_data->m_vertices[1],tri_data->m_vertices[2],planes->m_planes[0]);
        //Calc the edge 1
        EDGE_PLANE(tri_data->m_vertices[0],tri_data->m_vertices[1],(planes->m_planes[0]),(planes->m_planes[1]));

        //Calc the edge 2
        EDGE_PLANE(tri_data->m_vertices[1],tri_data->m_vertices[2],(planes->m_planes[0]),(planes->m_planes[2]));

        //Calc the edge 3
        EDGE_PLANE(tri_data->m_vertices[2],tri_data->m_vertices[0],(planes->m_planes[0]), (planes->m_planes[3]));

        //mark
        GIM_BITSET_SET(trimesh->m_planes_cache_bitset,triangle_index);
    }


    VEC_COPY_4((tri_data->m_planes.m_planes[0]),(planes->m_planes[0]));//face plane
    VEC_COPY_4((tri_data->m_planes.m_planes[1]),(planes->m_planes[1]));//edge1
    VEC_COPY_4((tri_data->m_planes.m_planes[2]),(planes->m_planes[2]));//edge2
    VEC_COPY_4((tri_data->m_planes.m_planes[3]),(planes->m_planes[3]));//edge3
}

void gim_trimesh_get_triangle_vertices(GIM_TRIMESH * trimesh, GUINT triangle_index, vec3f v1,vec3f v2,vec3f v3)
{
    vec3f * transformed_vertices = GIM_BUFFER_ARRAY_POINTER(vec3f,trimesh->m_transformed_vertex_buffer,0);

    GUINT * triangle_indices = GIM_BUFFER_ARRAY_POINTER(GUINT,trimesh->m_tri_index_buffer,triangle_index*3);

    //Copy the vertices
    VEC_COPY(v1,transformed_vertices[triangle_indices[0]]);
    VEC_COPY(v2,transformed_vertices[triangle_indices[1]]);
    VEC_COPY(v3,transformed_vertices[triangle_indices[2]]);
}