1 #ifndef GIM_TRIMESH_H_INCLUDED 2 #define GIM_TRIMESH_H_INCLUDED 3 /*! \file gim_trimesh.h 4 \author Francisco Le�n 5 */ 6 /* 7 ----------------------------------------------------------------------------- 8 This source file is part of GIMPACT Library. 9 10 For the latest info, see http://gimpact.sourceforge.net/ 11 12 Copyright (c) 2006 Francisco Leon. C.C. 80087371. 13 email: projectileman@yahoo.com 14 15 This library is free software; you can redistribute it and/or 16 modify it under the terms of EITHER: 17 (1) The GNU Lesser General Public License as published by the Free 18 Software Foundation; either version 2.1 of the License, or (at 19 your option) any later version. The text of the GNU Lesser 20 General Public License is included with this library in the 21 file GIMPACT-LICENSE-LGPL.TXT. 22 (2) The BSD-style license that is included with this library in 23 the file GIMPACT-LICENSE-BSD.TXT. 24 25 This library is distributed in the hope that it will be useful, 26 but WITHOUT ANY WARRANTY; without even the implied warranty of 27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files 28 GIMPACT-LICENSE-LGPL.TXT and GIMPACT-LICENSE-BSD.TXT for more details. 29 30 ----------------------------------------------------------------------------- 31 */ 32 33 #include "GIMPACT/gim_boxpruning.h" 34 #include "GIMPACT/gim_contact.h" 35 36 37 ///MAsk defines 38 #define GIM_TRIMESH_TRANSFORMED_REPLY 1 39 #define GIM_TRIMESH_NEED_UPDATE 2 40 41 /*! \addtogroup TRIMESH 42 \brief 43 A Trimesh is the basic geometric structure for representing solid objects. 44 <p><strong>CREATING TRIMESHES</strong></p> 45 <ul> 46 <li> For creating trimeshes, you must initialize Buffer managers by calling \ref gimpact_init 47 <li> Then you must define the vertex and index sources by creating them with \ref BUFFER_ARRAYS routines, and then call \ref gim_trimesh_create_from_arrays. 48 <li> An alternative way for creaing trimesh objects is calling \ref gim_trimesh_create_from_data. 49 <li> For access to the trimesh data (vertices, triangle indices), you must call \ref gim_trimesh_locks_work_data , and \ref gim_trimesh_unlocks_work_data for finish the access. 50 <li> Each time when the trimesh data is modified, you must call \ref gim_trimesh_update after. 51 <li> When a trimesh is no longer needed, you must call \ref gim_trimesh_destroy. 52 </ul> 53 54 <p>This is an example of how to create a deformable trimesh that shares vertices with the user application:</p> 55 \code 56 //Declaration of vertices 57 vec3f trimeshvertices[200]; 58 //Declaration of indices 59 GUINT trimeshindices[100]; 60 61 ... Initializing vertices and triangle indices at beginning 62 63 //Then create trimesh 64 GIM_TRIMESH mytrimesh; 65 66 //Calling trimesh create function 67 68 gim_trimesh_create_from_data( 69 &mytrimesh, 70 trimeshvertices,200, 71 0 ,//copy_vertices is 0 72 trimeshindices, 73 100, 74 0, //copy_indices is 0 75 0 //transformed_reply is 0 76 ); 77 \endcode 78 <p>Note that parameter transformed_reply is 0, that means that m_transformed_vertex_buffer is a reference to m_source_vertex on the trimesh, and transformations are not avaliable. Use that configuration if you have to simulate a deformable trimesh like cloth or elastic bodies.</p> 79 <p>When the trimesh is no longer needed, destroy it safely with gim_trimesh_destroy()</p> 80 <p><strong>UPDATING TRIMESHES</strong></p> 81 <p>On simulation loops, is needed to update trimeshes every time for update vertices althought updating triangle boxes and planes cache. There is two ways for update trimeshes: </p> 82 <ul> 83 <li> Updating vertices directly. You need to access to the \ref GIM_TRIMESH.m_source_vertex_buffer member; a vertex buffer which has access to the source vertices. 84 \code 85 // Access to the source vertices 86 gim_buffer_array_lock(&mytrimesh.m_source_vertex_buffer, G_MA_READ_WRITE); 87 88 //Get a pointer to the vertex buffer 89 vec3f * vertexpointer = GIM_BUFFER_ARRAY_POINTER(vec3f,mytrimesh.m_source_vertex_buffer,0); 90 91 //Get the amount of vertices 92 int veccount = mytrimesh.m_source_vertex_buffer.m_element_count; 93 94 //Modify vertices 95 for (int i=0;i<veccount ;i++ ) 96 { 97 ..... 98 ..... 99 processing vertices 100 ..... 101 ..... 102 } 103 104 // Don't forget to unlock the source vertex array 105 gim_buffer_array_unlock(&mytrimesh.m_source_vertex_buffer); 106 107 // Notify that the state of the trimesh is changed 108 gim_trimesh_post_update(&mytrimesh.m_source_vertex_buffer); 109 110 \endcode 111 For making trimeshes that allow to update their vertices, use \ref gim_trimesh_create_from_data with parameter <strong>transformed_reply</strong> = 0. 112 </ul> 113 <ul> 114 <li> Aplying a transformation. Simply use \ref gim_trimesh_set_tranform . Remember that with this method trimeshes must be created with \ref gim_trimesh_create_from_data with parameter <strong>transformed_reply</strong> = 1. 115 </ul> 116 <p> After updating vertices, you must call \ref gim_trimesh_update()</p> 117 <p><strong>TRIMESHES COLLISION</strong></p> 118 <p>Before collide trimeshes, you need to update them first.</p> 119 <p>Then you must use \ref gim_trimesh_trimesh_collision().</p> 120 121 */ 122 //! @{ 123 124 //! Prototype for updating vertices 125 typedef void * gim_update_trimesh_function(struct _GIM_TRIMESH *); 126 127 //! Trimesh 128 struct GIM_TRIMESH 129 { 130 ///Original 131 //@{ 132 GBUFFER_ARRAY m_source_vertex_buffer;//!< Buffer of vec3f coordinates 133 134 //! (GUINT) Indices of triangles,groups of three elements. 135 /*! 136 Array of GUINT. Triangle indices. Each triple contains indices of the vertices for each triangle. 137 \invariant must be aligned 138 */ 139 GBUFFER_ARRAY m_tri_index_buffer; 140 //@} 141 ///Allocated 142 //@{ 143 char m_mask;//!< Don't use directly 144 145 //! Allocated transformed vertices vec3f 146 /*! 147 Array of vec3f.If gim_trimesh_has_tranformed_reply(this) == 1 then it refers to the m_source_vertex_buffer 148 \invariant must be aligned 149 */ 150 GBUFFER_ARRAY m_transformed_vertex_buffer; 151 //@} 152 ///Auxiliary data 153 //@{ 154 GIM_AABB_SET m_aabbset; 155 GDYNAMIC_ARRAY m_planes_cache_buffer;//! Allocated GIM_TRIPLANES_CACHE 156 GDYNAMIC_ARRAY m_planes_cache_bitset; 157 gim_update_trimesh_function * m_update_callback;//! If null, then m_transform is applied. 158 mat4f m_transform; 159 //@} 160 }; 161 //typedef struct _GIM_TRIMESH GIM_TRIMESH; 162 163 /// Info about mesh 164 //! Return the trimesh triangle count 165 GUINT32 gim_trimesh_get_triangle_count(GIM_TRIMESH * trimesh); 166 167 //! Returns 1 if the m_transformed_vertex_buffer is a reply of m_source_vertex_buffer 168 char gim_trimesh_has_tranformed_reply(GIM_TRIMESH * trimesh); 169 170 //! Returns 1 if the trimesh needs to update their aabbset and the planes cache. 171 char gim_trimesh_needs_update(GIM_TRIMESH * trimesh); 172 173 //! Change the state of the trimesh for force it to update 174 /*! 175 Call it after made changes to the trimesh. 176 \post gim_trimesh_need_update(trimesh) will return 1 177 \sa gim_trimesh_needs_update,gim_trimesh_has_tranformed_reply 178 */ 179 void gim_trimesh_post_update(GIM_TRIMESH * trimesh); 180 181 //! Creates the aabb set and the triangles cache 182 /*! 183 184 \param trimesh 185 \param vertex_array 186 \param triindex_array 187 \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. 188 \post it copies the arrays by reference, and creates the auxiliary data (m_aabbset,m_planes_cache_buffer) 189 */ 190 void gim_trimesh_create_from_arrays(GBUFFER_MANAGER_DATA buffer_managers[], 191 GIM_TRIMESH * trimesh, GBUFFER_ARRAY * vertex_array, GBUFFER_ARRAY * triindex_array,char transformed_reply); 192 193 194 195 //! Create a trimesh from vertex array and an index array 196 /*! 197 \param trimesh An uninitialized GIM_TRIMESH structure 198 \param vertex_array A buffer to a vec3f array 199 \param vertex_count 200 \param triindex_array 201 \param index_count 202 \param copy_vertices If 1, it copies the source vertices in another buffer. Else (0) it constructs a reference to the data. 203 \param copy_indices If 1, it copies the source vertices in another buffer. Else (0) it constructs a reference to the data. 204 \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. Use 1 if you will apply transformations to the trimesh. See \ref gim_trimesh_set_tranform(). 205 */ 206 void gim_trimesh_create_from_data(GBUFFER_MANAGER_DATA buffer_managers[], 207 GIM_TRIMESH * trimesh, vec3f * vertex_array, GUINT32 vertex_count,char copy_vertices, 208 GUINT32 * triindex_array, GUINT32 index_count,char copy_indices,char transformed_reply); 209 210 //! Clears auxiliary data and releases buffer arrays 211 void gim_trimesh_destroy(GIM_TRIMESH * trimesh); 212 213 //! Copies two meshes 214 /*! 215 \param source_trimesh 216 \param dest_trimesh 217 \param copy_by_reference If 1, it attach a reference to the source vertices, else it copies the vertices 218 \param transformed_reply If 1, transformed vertices are reply of source vertives. 1 Is recommended 219 */ 220 void gim_trimesh_copy(GIM_TRIMESH * source_trimesh, 221 GBUFFER_MANAGER_DATA dest_buffer_managers[], GIM_TRIMESH * dest_trimesh, 222 char copy_by_reference, char transformed_reply); 223 224 225 //! Locks the trimesh for working with it 226 /*! 227 \post locks m_tri_index_buffer and m_transformed_vertex_buffer. 228 \param trimesh 229 */ 230 void gim_trimesh_locks_work_data(GIM_TRIMESH * trimesh); 231 232 233 //! unlocks the trimesh 234 /*! 235 \post unlocks m_tri_index_buffer and m_transformed_vertex_buffer. 236 \param trimesh 237 */ 238 void gim_trimesh_unlocks_work_data(GIM_TRIMESH * trimesh); 239 240 //! Updates m_transformed_vertex_buffer 241 /*! 242 \pre m_transformed_vertex_buffer must be unlocked 243 */ 244 void gim_trimesh_update_vertices(GIM_TRIMESH * trimesh); 245 246 //! Updates m_aabbset and m_planes_cache_bitset 247 /*! 248 \pre gim_trimesh_locks_work_data must be called before 249 */ 250 void gim_trimesh_update_aabbset(GIM_TRIMESH * trimesh); 251 252 //! Calls before perfom collisions. Updates the trimesh if needed 253 /*! 254 \post If gim_trimesh_needs_update returns 1, then it calls gim_trimesh_update_vertices and gim_trimesh_update_aabbset 255 */ 256 void gim_trimesh_update(GIM_TRIMESH * trimesh); 257 258 //! Set the transform of a trimesh 259 /*! 260 \post This function calls to gim_trimesh_post_update 261 */ 262 void gim_trimesh_set_tranform(GIM_TRIMESH * trimesh, mat4f transform); 263 264 //! Fetch triangle data 265 /*! 266 \pre gim_trimesh_locks_work_data must be called before 267 */ 268 void gim_trimesh_get_triangle_data(GIM_TRIMESH * trimesh, GUINT32 triangle_index, GIM_TRIANGLE_DATA * tri_data); 269 270 //! Fetch triangle vertices 271 /*! 272 \pre gim_trimesh_locks_work_data must be called before 273 */ 274 void gim_trimesh_get_triangle_vertices(GIM_TRIMESH * trimesh, GUINT32 triangle_index, vec3f v1,vec3f v2,vec3f v3); 275 276 //! Trimesh Trimesh Collisions 277 /*! 278 Before use this function you must update each trimesh: 279 \code 280 gim_trimesh_update(TriMesh1); 281 gim_trimesh_update(TriMesh2); 282 \endcode 283 Then you must use the trimesh collision in this way: 284 \code 285 int collide_trimeshes(GIM_TRIMESH * TriMesh1, GIM_TRIMESH * TriMesh2) 286 { 287 //Create contact list 288 GDYNAMIC_ARRAY trimeshcontacts; 289 GIM_CREATE_CONTACT_LIST(trimeshcontacts); 290 291 //Collide trimeshes 292 gim_trimesh_trimesh_collision(TriMesh1,TriMesh2,&trimeshcontacts); 293 294 if(trimeshcontacts.m_size == 0) //do nothing 295 { 296 GIM_DYNARRAY_DESTROY(trimeshcontacts);//clean contact array 297 return 0; 298 } 299 300 //Getting a pointer to the contact array 301 GIM_CONTACT * ptrimeshcontacts = GIM_DYNARRAY_POINTER(GIM_CONTACT,trimeshcontacts); 302 303 int contactcount = trimeshcontacts.m_size; 304 int i; 305 //Process contacts 306 for (i=0;i<contactcount ;i++) 307 { 308 //Do something with the contact (ptrimeshcontacts) 309 ...... 310 ...... 311 // Like creating joints or anything else 312 ...... 313 ...... 314 ptrimeshcontacts++; 315 } 316 GIM_DYNARRAY_DESTROY(trimeshcontacts); 317 return contactcount; 318 } 319 \endcode 320 In each contact 321 <ul> 322 <li> m_handle1 points to trimesh1. 323 <li> m_handle2 points to trimesh2. 324 <li> m_feature1 Is a triangle index of trimesh1. 325 <li> m_feature2 Is a triangle index of trimesh2. 326 </ul> 327 328 \param trimesh1 Collider 329 \param trimesh2 Collidee 330 \param contacts A GIM_CONTACT array. Must be initialized 331 */ 332 void gim_trimesh_trimesh_collision(GIM_TRIMESH * trimesh1, GIM_TRIMESH * trimesh2, GDYNAMIC_ARRAY * contacts); 333 334 335 //! Trimesh Sphere Collisions 336 /*! 337 Before use this function you must update the trimesh: 338 \code 339 gim_trimesh_update(trimesh); 340 \endcode 341 Then you must use this function in this way: 342 \code 343 int collide_trimesh_sphere(GIM_TRIMESH * trimesh, vec3f center,GREAL radius) 344 { 345 //Create contact list 346 GDYNAMIC_ARRAY trimeshcontacts; 347 GIM_CREATE_CONTACT_LIST(trimeshcontacts); 348 349 //Collide trimeshes 350 gim_trimesh_sphere_collision(trimesh,center,radius,&trimeshcontacts); 351 352 if(trimeshcontacts.m_size == 0) //do nothing 353 { 354 GIM_DYNARRAY_DESTROY(trimeshcontacts);//clean contact array 355 return 0; 356 } 357 358 //Getting a pointer to the contact array 359 GIM_CONTACT * ptrimeshcontacts = GIM_DYNARRAY_POINTER(GIM_CONTACT,trimeshcontacts); 360 361 int contactcount = trimeshcontacts.m_size; 362 int i; 363 //Process contacts 364 for (i=0;i<contactcount ;i++) 365 { 366 //Do something with the contact (ptrimeshcontacts) 367 ...... 368 ...... 369 // Like creating joints or anything else 370 ...... 371 ...... 372 ptrimeshcontacts++; 373 } 374 GIM_DYNARRAY_DESTROY(trimeshcontacts); 375 return contactcount; 376 } 377 \endcode 378 379 In each contact 380 <ul> 381 <li> m_handle1 points to trimesh. 382 <li> m_handle2 points to NULL. 383 <li> m_feature1 Is a triangle index of trimesh. 384 </ul> 385 386 \param trimesh 387 \param center 388 \param radius 389 \param contacts A GIM_CONTACT array. Must be initialized 390 */ 391 void gim_trimesh_sphere_collision(GIM_TRIMESH * trimesh,vec3f center,GREAL radius, GDYNAMIC_ARRAY * contacts); 392 393 394 //! Trimesh Capsule collision 395 /*! 396 Find the closest primitive collided by the ray. 397 398 Before use this function you must update the trimesh: 399 \code 400 gim_trimesh_update(trimesh); 401 \endcode 402 Then you must use this function in this way: 403 \code 404 int collide_trimesh_capsule(GIM_TRIMESH * trimesh, GIM_CAPSULE_DATA * capsule) 405 { 406 //Create contact list 407 GDYNAMIC_ARRAY trimeshcontacts; 408 GIM_CREATE_CONTACT_LIST(trimeshcontacts); 409 410 //Collide trimeshes 411 gim_trimesh_capsule_collision(trimesh,capsule,&trimeshcontacts); 412 413 if(trimeshcontacts.m_size == 0) //do nothing 414 { 415 GIM_DYNARRAY_DESTROY(trimeshcontacts);//clean contact array 416 return 0; 417 } 418 419 //Getting a pointer to the contact array 420 GIM_CONTACT * ptrimeshcontacts = GIM_DYNARRAY_POINTER(GIM_CONTACT,trimeshcontacts); 421 422 int contactcount = trimeshcontacts.m_size; 423 int i; 424 //Process contacts 425 for (i=0;i<contactcount ;i++) 426 { 427 //Do something with the contact (ptrimeshcontacts) 428 ...... 429 ...... 430 // Like creating joints or anything else 431 ...... 432 ...... 433 ptrimeshcontacts++; 434 } 435 GIM_DYNARRAY_DESTROY(trimeshcontacts); 436 return contactcount; 437 } 438 \endcode 439 440 In each contact 441 <ul> 442 <li> m_handle1 points to trimesh. 443 <li> m_handle2 points to NULL. 444 <li> m_feature1 Is a triangle index of trimesh. 445 </ul> 446 447 \param trimesh 448 \param capsule 449 \param contacts A GIM_CONTACT array. Must be initialized 450 */ 451 void gim_trimesh_capsule_collision(GIM_TRIMESH * trimesh, GIM_CAPSULE_DATA * capsule, GDYNAMIC_ARRAY * contacts); 452 453 454 ///Function for create Trimesh Plane collision result 455 #define GIM_CREATE_TRIMESHPLANE_CONTACTS(dynarray) GIM_DYNARRAY_CREATE(vec4f,dynarray,G_ARRAY_GROW_SIZE) 456 457 //! Trimesh Plane Collisions 458 /*! 459 460 Before use this function you must update the trimesh: 461 \code 462 gim_trimesh_update(trimesh); 463 \endcode 464 Then you must use this function in this way: 465 \code 466 int collide_trimesh_plane(GIM_TRIMESH * trimesh, vec4f plane) 467 { 468 //Create contact list 469 GDYNAMIC_ARRAY tri_plane_contacts; 470 GIM_CREATE_TRIMESHPLANE_CONTACTS(tri_plane_contacts); 471 472 //Collide trimeshes 473 gim_trimesh_plane_collision(trimesh,plane,&tri_plane_contacts); 474 475 if(tri_plane_contacts.m_size == 0) //do nothing 476 { 477 GIM_DYNARRAY_DESTROY(tri_plane_contacts);//clean contact array 478 return 0; 479 } 480 481 //Getting a pointer to the contact array 482 vec4f * planecontacts = GIM_DYNARRAY_POINTER(vec4f,tri_plane_contacts); 483 484 int contactcount = tri_plane_contacts.m_size; 485 int i; 486 //Process contacts 487 for (i=0;i<contactcount ;i++) 488 { 489 vec3f contactpoint; 490 GREAL contactdis; 491 492 VEC_COPY(contactpoint,planecontacts[i]); //Get contact point 493 contactdis = planecontacts[i][3]; // Get distance depth 494 495 //Do something with the contact 496 ...... 497 ...... 498 // Like creating joints or anything else 499 ...... 500 ...... 501 } 502 GIM_DYNARRAY_DESTROY(tri_plane_contacts); 503 return contactcount; 504 } 505 \endcode 506 507 In each contact the 3 first coordinates refers to the contact point, the fourth refers to the distance depth and the normal is the normal of the plane. 508 509 \param trimesh 510 \param plane vec4f plane 511 \param contacts A vec4f array. Must be initialized (~100). Each element have the coordinate point in the first 3 elements, and vec4f[3] has the penetration depth. 512 */ 513 void gim_trimesh_plane_collision(GIM_TRIMESH * trimesh,vec4f plane, GDYNAMIC_ARRAY * contacts); 514 515 516 //! Trimesh Ray Collisions 517 /*! 518 \param trimesh 519 \param origin 520 \param dir 521 \param tmax 522 \param contact 523 \return 1 if the ray collides, else 0 524 */ 525 int gim_trimesh_ray_collision(GIM_TRIMESH * trimesh,vec3f origin,vec3f dir, GREAL tmax, GIM_TRIANGLE_RAY_CONTACT_DATA * contact); 526 527 528 //! Trimesh Ray Collisions closest 529 /*! 530 Find the closest primitive collided by the ray 531 \param trimesh 532 \param origin 533 \param dir 534 \param tmax 535 \param contact 536 \return 1 if the ray collides, else 0 537 */ 538 int gim_trimesh_ray_closest_collision(GIM_TRIMESH * trimesh,vec3f origin,vec3f dir, GREAL tmax, GIM_TRIANGLE_RAY_CONTACT_DATA * contact); 539 540 //! @} 541 542 543 544 #endif // GIM_TRIMESH_H_INCLUDED 545