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