1
2 /*
3 -----------------------------------------------------------------------------
4 This source file is part of GIMPACT Library.
5
6 For the latest info, see http://gimpact.sourceforge.net/
7
8 Copyright (c) 2006 Francisco Leon. C.C. 80087371.
9 email: projectileman@yahoo.com
10
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of EITHER:
13 (1) The GNU Lesser General Public License as published by the Free
14 Software Foundation; either version 2.1 of the License, or (at
15 your option) any later version. The text of the GNU Lesser
16 General Public License is included with this library in the
17 file GIMPACT-LICENSE-LGPL.TXT.
18 (2) The BSD-style license that is included with this library in
19 the file GIMPACT-LICENSE-BSD.TXT.
20
21 This library is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
24 GIMPACT-LICENSE-LGPL.TXT and GIMPACT-LICENSE-BSD.TXT for more details.
25
26 -----------------------------------------------------------------------------
27 */
28
29
30 #include <assert.h>
31 #include "GIMPACT/gim_trimesh.h"
32
gim_trimesh_get_triangle_count(GIM_TRIMESH * trimesh)33 GUINT32 gim_trimesh_get_triangle_count(GIM_TRIMESH * trimesh)
34 {
35 return trimesh->m_tri_index_buffer.m_element_count/3;
36 }
37
38 //! Creates the aabb set and the triangles cache
39 /*!
40
41 \param trimesh
42 \param vertex_array
43 \param triindex_array
44 \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.
45 \post it copies the arrays by reference, and creates the auxiliary data (m_aabbset,m_planes_cache_buffer)
46 */
gim_trimesh_create_from_arrays(GBUFFER_MANAGER_DATA buffer_managers[],GIM_TRIMESH * trimesh,GBUFFER_ARRAY * vertex_array,GBUFFER_ARRAY * triindex_array,char transformed_reply)47 void gim_trimesh_create_from_arrays(GBUFFER_MANAGER_DATA buffer_managers[],
48 GIM_TRIMESH * trimesh, GBUFFER_ARRAY * vertex_array, GBUFFER_ARRAY * triindex_array,char transformed_reply)
49 {
50 assert(trimesh);
51 assert(vertex_array);
52 assert(triindex_array);
53 gim_buffer_array_copy_ref(vertex_array,&trimesh->m_source_vertex_buffer);
54 gim_buffer_array_copy_ref(triindex_array,&trimesh->m_tri_index_buffer);
55
56 trimesh->m_mask = GIM_TRIMESH_NEED_UPDATE;//needs update
57 //Create the transformed vertices
58 if(transformed_reply==1)
59 {
60 trimesh->m_mask |= GIM_TRIMESH_TRANSFORMED_REPLY;
61 gim_buffer_array_copy_value(vertex_array,
62 buffer_managers,&trimesh->m_transformed_vertex_buffer,G_BUFFER_MANAGER_SYSTEM,G_MU_DYNAMIC_READ_WRITE);
63 }
64 else
65 {
66 gim_buffer_array_copy_ref(vertex_array,&trimesh->m_transformed_vertex_buffer);
67 }
68 //create the box set
69 GUINT32 facecount = gim_trimesh_get_triangle_count(trimesh);
70
71 gim_aabbset_alloc(&trimesh->m_aabbset,facecount);
72 //create the planes cache
73 GIM_DYNARRAY_CREATE_SIZED(GIM_TRIPLANES_CACHE,trimesh->m_planes_cache_buffer,facecount);
74 //Create the bitset
75 GIM_BITSET_CREATE_SIZED(trimesh->m_planes_cache_bitset,facecount);
76 //Callback is 0
77 trimesh->m_update_callback = 0;
78 //set to identity
79 IDENTIFY_MATRIX_4X4(trimesh->m_transform);
80 }
81
82
83
84 //! Create a trimesh from vertex array and an index array
85 /*!
86
87 \param trimesh An uninitialized GIM_TRIMESH structure
88 \param vertex_array A buffer to a vec3f array
89 \param vertex_count
90 \param triindex_array
91 \param index_count
92 \param copy_vertices If 1, it copies the source vertices in another buffer. Else (0) it constructs a reference to the data.
93 \param copy_indices If 1, it copies the source vertices in another buffer. Else (0) it constructs a reference to the data.
94 \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.
95 */
gim_trimesh_create_from_data(GBUFFER_MANAGER_DATA buffer_managers[],GIM_TRIMESH * trimesh,vec3f * vertex_array,GUINT32 vertex_count,char copy_vertices,GUINT32 * triindex_array,GUINT32 index_count,char copy_indices,char transformed_reply)96 void gim_trimesh_create_from_data(GBUFFER_MANAGER_DATA buffer_managers[],
97 GIM_TRIMESH * trimesh, vec3f * vertex_array, GUINT32 vertex_count,char copy_vertices,
98 GUINT32 * triindex_array, GUINT32 index_count,char copy_indices,char transformed_reply)
99 {
100 GBUFFER_ARRAY buffer_vertex_array;
101 GBUFFER_ARRAY buffer_triindex_array;
102
103 //Create vertices
104 if(copy_vertices == 1)
105 {
106 gim_create_common_buffer_from_data(buffer_managers,
107 vertex_array, vertex_count*sizeof(vec3f), &buffer_vertex_array.m_buffer_id);
108 }
109 else//Create a shared buffer
110 {
111 gim_create_shared_buffer_from_data(buffer_managers,
112 vertex_array, vertex_count*sizeof(vec3f), &buffer_vertex_array.m_buffer_id);
113 }
114 GIM_BUFFER_ARRAY_INIT_TYPE(vec3f,buffer_vertex_array,buffer_vertex_array.m_buffer_id,vertex_count);
115
116
117 //Create vertices
118 if(copy_indices == 1)
119 {
120 gim_create_common_buffer_from_data(buffer_managers,
121 triindex_array, index_count*sizeof(GUINT32), &buffer_triindex_array.m_buffer_id);
122 }
123 else//Create a shared buffer
124 {
125 gim_create_shared_buffer_from_data(buffer_managers,
126 triindex_array, index_count*sizeof(GUINT32), &buffer_triindex_array.m_buffer_id);
127 }
128 GIM_BUFFER_ARRAY_INIT_TYPE(GUINT32,buffer_triindex_array,buffer_triindex_array.m_buffer_id,index_count);
129
130 gim_trimesh_create_from_arrays(buffer_managers, trimesh,
131 &buffer_vertex_array, &buffer_triindex_array,transformed_reply);
132
133 ///always call this after create a buffer_array
134 GIM_BUFFER_ARRAY_DESTROY(buffer_vertex_array);
135 GIM_BUFFER_ARRAY_DESTROY(buffer_triindex_array);
136 }
137
138 //! Clears auxiliary data and releases buffer arrays
gim_trimesh_destroy(GIM_TRIMESH * trimesh)139 void gim_trimesh_destroy(GIM_TRIMESH * trimesh)
140 {
141 gim_aabbset_destroy(&trimesh->m_aabbset);
142
143 GIM_DYNARRAY_DESTROY(trimesh->m_planes_cache_buffer);
144 GIM_DYNARRAY_DESTROY(trimesh->m_planes_cache_bitset);
145
146 GIM_BUFFER_ARRAY_DESTROY(trimesh->m_transformed_vertex_buffer);
147 GIM_BUFFER_ARRAY_DESTROY(trimesh->m_source_vertex_buffer);
148 GIM_BUFFER_ARRAY_DESTROY(trimesh->m_tri_index_buffer);
149 }
150
151 //! Copies two meshes
152 /*!
153 \pre dest_trimesh shouldn't be created
154 \post dest_trimesh will be created
155 \param source_trimesh
156 \param dest_trimesh
157 \param copy_by_reference If 1, it attach a reference to the source vertices, else it copies the vertices
158 \param transformed_reply IF 1, then it forces the m_trasnformed_vertices to be a reply of the source vertices
159 */
gim_trimesh_copy(GIM_TRIMESH * source_trimesh,GBUFFER_MANAGER_DATA dest_buffer_managers[],GIM_TRIMESH * dest_trimesh,char copy_by_reference,char transformed_reply)160 void gim_trimesh_copy(GIM_TRIMESH * source_trimesh,
161 GBUFFER_MANAGER_DATA dest_buffer_managers[], GIM_TRIMESH * dest_trimesh,
162 char copy_by_reference, char transformed_reply)
163 {
164 /* -- trimesh can not be copied by reference until GBUFFER_MANAGER_DATA is rewritten
165 to be thread safe and until it is moved back to global variables.
166 if(copy_by_reference==1)
167 {
168 gim_trimesh_create_from_arrays(dest_trimesh, &source_trimesh->m_source_vertex_buffer, &source_trimesh->m_tri_index_buffer,transformed_reply);
169 }
170 else
171 */
172 {
173 GBUFFER_ARRAY buffer_vertex_array;
174 GBUFFER_ARRAY buffer_triindex_array;
175
176 gim_buffer_array_copy_value(&source_trimesh->m_source_vertex_buffer,
177 dest_buffer_managers,&buffer_vertex_array,G_BUFFER_MANAGER_SYSTEM,G_MU_DYNAMIC_READ_WRITE);
178
179 gim_buffer_array_copy_value(&source_trimesh->m_tri_index_buffer,
180 dest_buffer_managers,&buffer_triindex_array,G_BUFFER_MANAGER_SYSTEM,G_MU_DYNAMIC_READ_WRITE);
181
182 gim_trimesh_create_from_arrays(dest_buffer_managers, dest_trimesh,
183 &buffer_vertex_array, &buffer_triindex_array,transformed_reply);
184
185 ///always call this after create a buffer_array
186 GIM_BUFFER_ARRAY_DESTROY(buffer_vertex_array);
187 GIM_BUFFER_ARRAY_DESTROY(buffer_triindex_array);
188 }
189 }
190 //! Locks the trimesh for working with it
191 /*!
192 \post locks m_tri_index_buffer and m_transformed_vertex_buffer.
193 \param trimesh
194 */
gim_trimesh_locks_work_data(GIM_TRIMESH * trimesh)195 void gim_trimesh_locks_work_data(GIM_TRIMESH * trimesh)
196 {
197 GINT32 res;
198 res=gim_buffer_array_lock(&trimesh->m_tri_index_buffer,G_MA_READ_ONLY);
199 assert(res==G_BUFFER_OP_SUCCESS);
200 res=gim_buffer_array_lock(&trimesh->m_transformed_vertex_buffer,G_MA_READ_ONLY);
201 assert(res==G_BUFFER_OP_SUCCESS);
202 }
203
204 //! unlocks the trimesh
205 /*!
206 \post unlocks m_tri_index_buffer and m_transformed_vertex_buffer.
207 \param trimesh
208 */
gim_trimesh_unlocks_work_data(GIM_TRIMESH * trimesh)209 void gim_trimesh_unlocks_work_data(GIM_TRIMESH * trimesh)
210 {
211 gim_buffer_array_unlock(&trimesh->m_tri_index_buffer);
212 gim_buffer_array_unlock(&trimesh->m_transformed_vertex_buffer);
213 }
214
215
216 //! Returns 1 if the m_transformed_vertex_buffer is a reply of m_source_vertex_buffer
gim_trimesh_has_tranformed_reply(GIM_TRIMESH * trimesh)217 char gim_trimesh_has_tranformed_reply(GIM_TRIMESH * trimesh)
218 {
219 if(trimesh->m_mask&GIM_TRIMESH_TRANSFORMED_REPLY) return 1;
220 return 0;
221 }
222
223 //! Returns 1 if the trimesh needs to update their aabbset and the planes cache.
gim_trimesh_needs_update(GIM_TRIMESH * trimesh)224 char gim_trimesh_needs_update(GIM_TRIMESH * trimesh)
225 {
226 if(trimesh->m_mask&GIM_TRIMESH_NEED_UPDATE) return 1;
227 return 0;
228 }
229
230 //! Change the state of the trimesh for force it to update
231 /*!
232 Call it after made changes to the trimesh.
233 \post gim_trimesh_need_update(trimesh) will return 1
234 */
gim_trimesh_post_update(GIM_TRIMESH * trimesh)235 void gim_trimesh_post_update(GIM_TRIMESH * trimesh)
236 {
237 trimesh->m_mask |= GIM_TRIMESH_NEED_UPDATE;
238 }
239
240 //kernel
241 #define MULT_MAT_VEC4_KERNEL(_mat,_src,_dst) MAT_DOT_VEC_3X4((_dst),(_mat),(_src))
242
243 //! Updates m_transformed_vertex_buffer
244 /*!
245 \pre m_transformed_vertex_buffer must be unlocked
246 */
gim_trimesh_update_vertices(GIM_TRIMESH * trimesh)247 void gim_trimesh_update_vertices(GIM_TRIMESH * trimesh)
248 {
249 if(gim_trimesh_has_tranformed_reply(trimesh) == 0) return; //Don't perform transformation
250
251 //Vertices
252 GBUFFER_ARRAY * psource_vertex_buffer = &trimesh->m_source_vertex_buffer;
253 GBUFFER_ARRAY * ptransformed_vertex_buffer = &trimesh->m_transformed_vertex_buffer;
254 //Temp transform
255 mat4f transform;
256 COPY_MATRIX_4X4(transform,trimesh->m_transform);
257
258 GIM_PROCESS_BUFFER_ARRAY(transform,(*psource_vertex_buffer),(*ptransformed_vertex_buffer),MULT_MAT_VEC4_KERNEL,vec3f,vec3f);
259 }
260
261 //! Updates m_aabbset and m_planes_cache_bitset
262 /*!
263 \pre gim_trimesh_locks_work_data must be called before
264 */
gim_trimesh_update_aabbset(GIM_TRIMESH * trimesh)265 void gim_trimesh_update_aabbset(GIM_TRIMESH * trimesh)
266 {
267 vec3f * transformed_vertices = GIM_BUFFER_ARRAY_POINTER(vec3f,trimesh->m_transformed_vertex_buffer,0);
268 assert(transformed_vertices);
269
270 GUINT32 * triangle_indices = GIM_BUFFER_ARRAY_POINTER(GUINT32,trimesh->m_tri_index_buffer,0);
271 assert(triangle_indices);
272 // box set
273 aabb3f * paabb = trimesh->m_aabbset.m_boxes;
274 GUINT32 triangle_count = gim_trimesh_get_triangle_count(trimesh);
275 float * v1,*v2,*v3;
276 GUINT32 i;
277 for (i=0; i<triangle_count;i++)
278 {
279 v1 = &transformed_vertices[triangle_indices[0]][0];
280 v2 = &transformed_vertices[triangle_indices[1]][0];
281 v3 = &transformed_vertices[triangle_indices[2]][0];
282 COMPUTEAABB_FOR_TRIANGLE((*paabb),v1,v2,v3);
283 triangle_indices+=3;
284 paabb++;
285 }
286 //Clear planes cache
287 GIM_BITSET_CLEAR_ALL(trimesh->m_planes_cache_bitset);
288 //Sorts set
289 gim_aabbset_update(&trimesh->m_aabbset);
290 }
291
292 //! Updates the trimesh if needed
293 /*!
294 \post If gim_trimesh_needs_update returns 1, then it calls gim_trimesh_update_vertices and gim_trimesh_update_aabbset
295 */
gim_trimesh_update(GIM_TRIMESH * trimesh)296 void gim_trimesh_update(GIM_TRIMESH * trimesh)
297 {
298 if(gim_trimesh_needs_update(trimesh)==0) return;
299 gim_trimesh_update_vertices(trimesh);
300 gim_trimesh_locks_work_data(trimesh);
301 gim_trimesh_update_aabbset(trimesh);
302 gim_trimesh_unlocks_work_data(trimesh);
303
304 //Clear update flag
305 trimesh->m_mask &= ~GIM_TRIMESH_NEED_UPDATE;
306 }
307
gim_trimesh_set_tranform(GIM_TRIMESH * trimesh,mat4f transform)308 void gim_trimesh_set_tranform(GIM_TRIMESH * trimesh, mat4f transform)
309 {
310 GREAL diff = 0.0f;
311 float * originaltrans = &trimesh->m_transform[0][0];
312 float * newtrans = &transform[0][0];
313 GUINT32 i;
314 for (i=0;i<16;i++)
315 {
316 diff += fabs(originaltrans[i]-newtrans[i]);
317 }
318
319 // if(IS_ZERO(diff)) return ;///don't need to update
320 if(diff< 0.00001f) return ;///don't need to update
321
322 COPY_MATRIX_4X4(trimesh->m_transform,transform);
323
324 gim_trimesh_post_update(trimesh);
325 }
326
gim_trimesh_get_triangle_data(GIM_TRIMESH * trimesh,GUINT32 triangle_index,GIM_TRIANGLE_DATA * tri_data)327 void gim_trimesh_get_triangle_data(GIM_TRIMESH * trimesh, GUINT32 triangle_index, GIM_TRIANGLE_DATA * tri_data)
328 {
329 vec3f * transformed_vertices = GIM_BUFFER_ARRAY_POINTER(vec3f,trimesh->m_transformed_vertex_buffer,0);
330
331 GUINT32 * triangle_indices = GIM_BUFFER_ARRAY_POINTER(GUINT32,trimesh->m_tri_index_buffer,triangle_index*3);
332
333
334 //Copy the vertices
335 VEC_COPY(tri_data->m_vertices[0],transformed_vertices[triangle_indices[0]]);
336 VEC_COPY(tri_data->m_vertices[1],transformed_vertices[triangle_indices[1]]);
337 VEC_COPY(tri_data->m_vertices[2],transformed_vertices[triangle_indices[2]]);
338
339 //Get the planes
340 GIM_TRIPLANES_CACHE * planes = GIM_DYNARRAY_POINTER(GIM_TRIPLANES_CACHE,trimesh->m_planes_cache_buffer);
341 planes += triangle_index;
342
343 //verify planes cache
344 GUINT32 bit_eval;
345 GIM_BITSET_GET(trimesh->m_planes_cache_bitset,triangle_index,bit_eval);
346 if(bit_eval == 0)// Needs to calc the planes
347 {
348 //Calc the face plane
349 TRIANGLE_PLANE(tri_data->m_vertices[0],tri_data->m_vertices[1],tri_data->m_vertices[2],planes->m_planes[0]);
350 //Calc the edge 1
351 EDGE_PLANE(tri_data->m_vertices[0],tri_data->m_vertices[1],(planes->m_planes[0]),(planes->m_planes[1]));
352
353 //Calc the edge 2
354 EDGE_PLANE(tri_data->m_vertices[1],tri_data->m_vertices[2],(planes->m_planes[0]),(planes->m_planes[2]));
355
356 //Calc the edge 3
357 EDGE_PLANE(tri_data->m_vertices[2],tri_data->m_vertices[0],(planes->m_planes[0]), (planes->m_planes[3]));
358
359 //mark
360 GIM_BITSET_SET(trimesh->m_planes_cache_bitset,triangle_index);
361 }
362
363
364 VEC_COPY_4((tri_data->m_planes.m_planes[0]),(planes->m_planes[0]));//face plane
365 VEC_COPY_4((tri_data->m_planes.m_planes[1]),(planes->m_planes[1]));//edge1
366 VEC_COPY_4((tri_data->m_planes.m_planes[2]),(planes->m_planes[2]));//edge2
367 VEC_COPY_4((tri_data->m_planes.m_planes[3]),(planes->m_planes[3]));//edge3
368 }
369
gim_trimesh_get_triangle_vertices(GIM_TRIMESH * trimesh,GUINT32 triangle_index,vec3f v1,vec3f v2,vec3f v3)370 void gim_trimesh_get_triangle_vertices(GIM_TRIMESH * trimesh, GUINT32 triangle_index, vec3f v1,vec3f v2,vec3f v3)
371 {
372 vec3f * transformed_vertices = GIM_BUFFER_ARRAY_POINTER(vec3f,trimesh->m_transformed_vertex_buffer,0);
373
374 GUINT32 * triangle_indices = GIM_BUFFER_ARRAY_POINTER(GUINT32,trimesh->m_tri_index_buffer,triangle_index*3);
375
376 //Copy the vertices
377 VEC_COPY(v1,transformed_vertices[triangle_indices[0]]);
378 VEC_COPY(v2,transformed_vertices[triangle_indices[1]]);
379 VEC_COPY(v3,transformed_vertices[triangle_indices[2]]);
380 }
381