collision_trimesh_gimpact.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. /*************************************************************************
  2. * *
  3. * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. *
  4. * All rights reserved. Email: [email protected] Web: www.q12.org *
  5. * *
  6. * This library is free software; you can redistribute it and/or *
  7. * modify it under the terms of EITHER: *
  8. * (1) The GNU Lesser General Public License as published by the Free *
  9. * Software Foundation; either version 2.1 of the License, or (at *
  10. * your option) any later version. The text of the GNU Lesser *
  11. * General Public License is included with this library in the *
  12. * file LICENSE.TXT. *
  13. * (2) The BSD-style license that is included with this library in *
  14. * the file LICENSE-BSD.TXT. *
  15. * *
  16. * This library is distributed in the hope that it will be useful, *
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
  19. * LICENSE.TXT and LICENSE-BSD.TXT for more details. *
  20. * *
  21. *************************************************************************/
  22. // TriMesh storage classes refactoring and face angle computation code by Oleh Derevenko (C) 2016-2017
  23. #include <ode/collision.h>
  24. #include <ode/rotation.h>
  25. #include "config.h"
  26. #include "matrix.h"
  27. #include "odemath.h"
  28. #include "util.h"
  29. #if dTRIMESH_ENABLED && dTRIMESH_GIMPACT
  30. #include "collision_util.h"
  31. #include "collision_trimesh_gimpact.h"
  32. #include "collision_trimesh_internal_impl.h"
  33. //////////////////////////////////////////////////////////////////////////
  34. // dxTriMeshData
  35. bool dxTriMeshData::preprocessData(bool /*buildUseFlags*//*=false*/, FaceAngleStorageMethod faceAndgesRequirement/*=ASM__INVALID*/)
  36. {
  37. FaceAngleStorageMethod faceAndgesRequirementToUse = faceAndgesRequirement;
  38. if (faceAndgesRequirement != ASM__INVALID && haveFaceAnglesBeenBuilt())
  39. {
  40. dUASSERT(false, "Another request to build face angles after they had already been built");
  41. faceAndgesRequirementToUse = ASM__INVALID;
  42. }
  43. // If this mesh has already been preprocessed, exit
  44. bool result = faceAndgesRequirementToUse == ASM__INVALID || retrieveTriangleCount() == 0
  45. || meaningfulPreprocessData(faceAndgesRequirementToUse);
  46. return result;
  47. }
  48. struct TrimeshDataVertexIndexAccessor_GIMPACT
  49. {
  50. enum
  51. {
  52. TRIANGLEINDEX_STRIDE = dxTriMesh::TRIANGLEINDEX_STRIDE,
  53. };
  54. explicit TrimeshDataVertexIndexAccessor_GIMPACT(dxTriMeshData *meshData):
  55. m_TriangleVertexIndices(meshData->retrieveTriangleVertexIndices())
  56. {
  57. dIASSERT(meshData->retrieveTriangleStride() == TRIANGLEINDEX_STRIDE);
  58. }
  59. void getTriangleVertexIndices(unsigned out_VertexIndices[dMTV__MAX], unsigned triangleIdx) const
  60. {
  61. const GUINT32 *triIndicesBegin = m_TriangleVertexIndices;
  62. const unsigned triStride = TRIANGLEINDEX_STRIDE;
  63. const GUINT32 *triIndicesOfInterest = (const GUINT32 *)((const uint8 *)triIndicesBegin + (sizeint)triangleIdx * triStride);
  64. std::copy(triIndicesOfInterest, triIndicesOfInterest + dMTV__MAX, out_VertexIndices);
  65. }
  66. const GUINT32 *m_TriangleVertexIndices;
  67. };
  68. struct TrimeshDataTrianglePointAccessor_GIMPACT
  69. {
  70. enum
  71. {
  72. VERTEXINSTANCE_STRIDE = dxTriMesh::VERTEXINSTANCE_STRIDE,
  73. TRIANGLEINDEX_STRIDE = dxTriMesh::TRIANGLEINDEX_STRIDE,
  74. };
  75. TrimeshDataTrianglePointAccessor_GIMPACT(dxTriMeshData *meshData):
  76. m_VertexInstances(meshData->retrieveVertexInstances()),
  77. m_TriangleVertexIndices(meshData->retrieveTriangleVertexIndices())
  78. {
  79. dIASSERT((unsigned)meshData->retrieveVertexStride() == (unsigned)VERTEXINSTANCE_STRIDE);
  80. dIASSERT((unsigned)meshData->retrieveTriangleStride() == (unsigned)TRIANGLEINDEX_STRIDE);
  81. }
  82. void getTriangleVertexPoints(dVector3 out_Points[dMTV__MAX], unsigned triangleIndex) const
  83. {
  84. dxTriMeshData::retrieveTriangleVertexPoints(out_Points, triangleIndex,
  85. &m_VertexInstances[0][0], VERTEXINSTANCE_STRIDE, m_TriangleVertexIndices, TRIANGLEINDEX_STRIDE);
  86. }
  87. const vec3f *m_VertexInstances;
  88. const GUINT32 *m_TriangleVertexIndices;
  89. };
  90. bool dxTriMeshData::meaningfulPreprocessData(FaceAngleStorageMethod faceAndgesRequirement/*=ASM__INVALID*/)
  91. {
  92. const bool buildFaceAngles = true; dIASSERT(faceAndgesRequirement != ASM__INVALID);
  93. // dIASSERT(buildFaceAngles);
  94. dIASSERT(/*!buildFaceAngles || */!haveFaceAnglesBeenBuilt());
  95. bool result = false;
  96. bool anglesAllocated = false;
  97. do
  98. {
  99. if (buildFaceAngles)
  100. {
  101. if (!allocateFaceAngles(faceAndgesRequirement))
  102. {
  103. break;
  104. }
  105. }
  106. anglesAllocated = true;
  107. const unsigned int numTris = retrieveTriangleCount();
  108. const unsigned int numVertices = retrieveVertexCount();
  109. sizeint numEdges = (sizeint)numTris * dMTV__MAX;
  110. dIASSERT(numVertices <= numEdges); // Edge records are going to be used for vertex data as well
  111. const sizeint recordsMemoryRequired = dEFFICIENT_SIZE(numEdges * sizeof(EdgeRecord));
  112. const sizeint verticesMemoryRequired = /*dEFFICIENT_SIZE*/(numVertices * sizeof(VertexRecord)); // Skip alignment for the last chunk
  113. const sizeint totalTempMemoryRequired = recordsMemoryRequired + verticesMemoryRequired;
  114. void *tempBuffer = dAlloc(totalTempMemoryRequired);
  115. if (tempBuffer == NULL)
  116. {
  117. break;
  118. }
  119. EdgeRecord *edges = (EdgeRecord *)tempBuffer;
  120. VertexRecord *vertices = (VertexRecord *)((uint8 *)tempBuffer + recordsMemoryRequired);
  121. TrimeshDataVertexIndexAccessor_GIMPACT indexAccessor(this);
  122. meaningfulPreprocess_SetupEdgeRecords(edges, numEdges, indexAccessor);
  123. // Sort the edges, so the ones sharing the same verts are beside each other
  124. std::sort(edges, edges + numEdges);
  125. TrimeshDataTrianglePointAccessor_GIMPACT pointAccessor(this);
  126. const dReal *const externalNormals = retrieveNormals();
  127. IFaceAngleStorageControl *faceAngles = retrieveFaceAngles();
  128. meaningfulPreprocess_buildEdgeFlags(NULL, faceAngles, edges, numEdges, vertices, externalNormals, pointAccessor);
  129. dFree(tempBuffer, totalTempMemoryRequired);
  130. result = true;
  131. }
  132. while (false);
  133. if (!result)
  134. {
  135. if (anglesAllocated)
  136. {
  137. if (buildFaceAngles)
  138. {
  139. freeFaceAngles();
  140. }
  141. }
  142. }
  143. return result;
  144. }
  145. //////////////////////////////////////////////////////////////////////////
  146. // Trimesh
  147. dxTriMesh::~dxTriMesh()
  148. {
  149. //Terminate Trimesh
  150. gim_trimesh_destroy(&m_collision_trimesh);
  151. gim_terminate_buffer_managers(m_buffer_managers);
  152. }
  153. /*virtual */
  154. void dxTriMesh::computeAABB()
  155. {
  156. //update trimesh transform
  157. mat4f transform;
  158. IDENTIFY_MATRIX_4X4(transform);
  159. MakeMatrix(this, transform);
  160. gim_trimesh_set_tranform(&m_collision_trimesh, transform);
  161. //Update trimesh boxes
  162. gim_trimesh_update(&m_collision_trimesh);
  163. GIM_AABB_COPY( &m_collision_trimesh.m_aabbset.m_global_bound, aabb );
  164. }
  165. void dxTriMesh::assignMeshData(dxTriMeshData *Data)
  166. {
  167. // GIMPACT only supports stride 12, so we need to catch the error early.
  168. dUASSERT(
  169. (unsigned int)Data->retrieveVertexStride() == (unsigned)VERTEXINSTANCE_STRIDE
  170. && (unsigned int)Data->retrieveTriangleStride() == (unsigned)TRIANGLEINDEX_STRIDE,
  171. "Gimpact trimesh only supports a stride of 3 float/int\n"
  172. "This means that you cannot use dGeomTriMeshDataBuildSimple() with Gimpact.\n"
  173. "Change the stride, or use Opcode trimeshes instead.\n"
  174. );
  175. dxTriMesh_Parent::assignMeshData(Data);
  176. //Create trimesh
  177. const vec3f *vertexInstances = Data->retrieveVertexInstances();
  178. if ( vertexInstances != NULL )
  179. {
  180. const GUINT32 *triangleVertexIndices = Data->retrieveTriangleVertexIndices();
  181. sizeint vertexInstanceCount = Data->retrieveVertexCount();
  182. sizeint triangleVertexCount = (sizeint)Data->retrieveTriangleCount() * dMTV__MAX;
  183. gim_trimesh_create_from_data(
  184. m_buffer_managers,
  185. &m_collision_trimesh, // gimpact mesh
  186. const_cast<vec3f *>(vertexInstances), // vertices
  187. dCAST_TO_SMALLER(GUINT32, vertexInstanceCount), // nr of verts
  188. 0, // copy verts?
  189. const_cast<GUINT32 *>(triangleVertexIndices), // indices
  190. dCAST_TO_SMALLER(GUINT32, triangleVertexCount), // nr of indices
  191. 0, // copy indices?
  192. 1 // transformed reply
  193. );
  194. }
  195. }
  196. //////////////////////////////////////////////////////////////////////////
  197. /*extern */
  198. dTriMeshDataID dGeomTriMeshDataCreate()
  199. {
  200. return new dxTriMeshData();
  201. }
  202. /*extern */
  203. void dGeomTriMeshDataDestroy(dTriMeshDataID g)
  204. {
  205. dxTriMeshData *data = g;
  206. delete data;
  207. }
  208. /*extern */
  209. void dGeomTriMeshDataSet(dTriMeshDataID g, int dataId, void *pDataLocation)
  210. {
  211. dUASSERT(g, "The argument is not a trimesh data");
  212. dxTriMeshData *data = g;
  213. switch (dataId)
  214. {
  215. case dTRIMESHDATA_FACE_NORMALS:
  216. {
  217. data->assignNormals((const dReal *)pDataLocation);
  218. break;
  219. }
  220. case dTRIMESHDATA_USE_FLAGS: // Not used for GIMPACT
  221. {
  222. break;
  223. }
  224. // case dTRIMESHDATA__MAX: -- To be located by Find in Files
  225. default:
  226. {
  227. dUASSERT(dataId, "invalid data type");
  228. break;
  229. }
  230. }
  231. }
  232. static void *geomTriMeshDataGet(dTriMeshDataID g, int dataId, sizeint *pOutDataSize) ;
  233. /*extern */
  234. void *dGeomTriMeshDataGet(dTriMeshDataID g, int dataId)
  235. {
  236. return geomTriMeshDataGet(g, dataId, NULL);
  237. }
  238. /*extern */
  239. void *dGeomTriMeshDataGet2(dTriMeshDataID g, int dataId, sizeint *pOutDataSize)
  240. {
  241. return geomTriMeshDataGet(g, dataId, pOutDataSize);
  242. }
  243. static
  244. void *geomTriMeshDataGet(dTriMeshDataID g, int dataId, sizeint *pOutDataSize)
  245. {
  246. dUASSERT(g, "The argument is not a trimesh data");
  247. const dxTriMeshData *data = g;
  248. void *result = NULL;
  249. switch (dataId)
  250. {
  251. case dTRIMESHDATA_FACE_NORMALS:
  252. {
  253. if (pOutDataSize != NULL)
  254. {
  255. *pOutDataSize = data->calculateNormalsMemoryRequirement();
  256. }
  257. result = (void *)data->retrieveNormals();
  258. break;
  259. }
  260. case dTRIMESHDATA_USE_FLAGS: // Not not used for GIMPACT
  261. {
  262. if (pOutDataSize != NULL)
  263. {
  264. *pOutDataSize = 0;
  265. }
  266. break;
  267. }
  268. // case dTRIMESHDATA__MAX: -- To be located by Find in Files
  269. default:
  270. {
  271. if (pOutDataSize != NULL)
  272. {
  273. *pOutDataSize = 0;
  274. }
  275. dUASSERT(dataId, "invalid data type");
  276. break;
  277. }
  278. }
  279. return result;
  280. }
  281. /*extern */
  282. void dGeomTriMeshDataBuildSingle1(dTriMeshDataID g,
  283. const void* Vertices, int VertexStride, int VertexCount,
  284. const void* Indices, int IndexCount, int TriStride,
  285. const void* Normals)
  286. {
  287. dUASSERT(g, "The argument is not a trimesh data");
  288. dAASSERT(Vertices);
  289. dAASSERT(Indices);
  290. dxTriMeshData *data = g;
  291. data->buildData(Vertices, VertexStride, VertexCount,
  292. Indices, IndexCount, TriStride,
  293. Normals,
  294. true);
  295. }
  296. /*extern */
  297. void dGeomTriMeshDataBuildDouble1(dTriMeshDataID g,
  298. const void* Vertices, int VertexStride, int VertexCount,
  299. const void* Indices, int IndexCount, int TriStride,
  300. const void* Normals)
  301. {
  302. dUASSERT(g, "The argument is not a trimesh data");
  303. dAASSERT(Vertices);
  304. dAASSERT(Indices);
  305. dxTriMeshData *data = g;
  306. data->buildData(Vertices, VertexStride, VertexCount,
  307. Indices, IndexCount, TriStride,
  308. Normals,
  309. false);
  310. }
  311. //////////////////////////////////////////////////////////////////////////
  312. /*extern */
  313. dGeomID dCreateTriMesh(dSpaceID space,
  314. dTriMeshDataID Data,
  315. dTriCallback* Callback,
  316. dTriArrayCallback* ArrayCallback,
  317. dTriRayCallback* RayCallback)
  318. {
  319. dxTriMesh *mesh = new dxTriMesh(space, Data, Callback, ArrayCallback, RayCallback);
  320. return mesh;
  321. }
  322. /*extern */
  323. void dGeomTriMeshSetLastTransform(dGeomID g, const dMatrix4 last_trans )
  324. {
  325. dAASSERT(g);
  326. dUASSERT(g->type == dTriMeshClass, "The geom is not a trimesh");
  327. //stub
  328. }
  329. /*extern */
  330. const dReal *dGeomTriMeshGetLastTransform(dGeomID g)
  331. {
  332. dAASSERT(g);
  333. dUASSERT(g->type == dTriMeshClass, "The geom is not a trimesh");
  334. return NULL; // stub
  335. }
  336. #endif // #if dTRIMESH_ENABLED && dTRIMESH_GIMPACT