CollisionShape.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 Lasse Öörni
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Precompiled.h"
  24. #include "CollisionShape.h"
  25. #include "Geometry.h"
  26. #include "Log.h"
  27. #include "Model.h"
  28. #include "Profiler.h"
  29. #include "ResourceCache.h"
  30. #include "StringUtils.h"
  31. #include "XMLFile.h"
  32. #include <ode/ode.h>
  33. #include <hull.h>
  34. #include "DebugNew.h"
  35. std::map<std::string, SharedPtr<TriangleMeshData> > CollisionShape::sTriangleMeshCache;
  36. std::map<std::string, SharedPtr<HeightfieldData> > CollisionShape::sHeightfieldCache;
  37. void getVertexAndIndexData(const Model* model, unsigned lodLevel, SharedArrayPtr<Vector3>& destVertexData, unsigned& destVertexCount, SharedArrayPtr<unsigned>& destIndexData, unsigned& destIndexCount)
  38. {
  39. const std::vector<std::vector<SharedPtr<Geometry> > >& geometries = model->getGeometries();
  40. destVertexCount = 0;
  41. destIndexCount = 0;
  42. for (unsigned i = 0; i < geometries.size(); ++i)
  43. {
  44. unsigned subGeometryLodLevel = lodLevel;
  45. if (subGeometryLodLevel >= geometries[i].size())
  46. subGeometryLodLevel = geometries[i].size() / 2;
  47. Geometry* geom = geometries[i][subGeometryLodLevel];
  48. if (!geom)
  49. EXCEPTION("Null geometry for CollisionShape");
  50. destVertexCount += geom->getVertexCount();
  51. destIndexCount += geom->getIndexCount();
  52. }
  53. destVertexData = new Vector3[destVertexCount];
  54. destIndexData = new unsigned[destIndexCount];
  55. unsigned firstVertex = 0;
  56. unsigned firstIndex = 0;
  57. for (unsigned i = 0; i < geometries.size(); ++i)
  58. {
  59. unsigned subGeometryLodLevel = lodLevel;
  60. if (subGeometryLodLevel >= geometries[i].size())
  61. subGeometryLodLevel = geometries[i].size() / 2;
  62. Geometry* geom = geometries[i][subGeometryLodLevel];
  63. if (!geom)
  64. EXCEPTION("Null geometry for CollisionShape");
  65. const unsigned char* vertexData;
  66. const unsigned char* indexData;
  67. unsigned vertexSize;
  68. unsigned indexSize;
  69. geom->lockRawData(vertexData, vertexSize, indexData, indexSize);
  70. if ((!vertexData) || (!indexData))
  71. EXCEPTION("Raw geometry data unavailable for CollisionShape");
  72. unsigned vertexStart = geom->getVertexStart();
  73. unsigned vertexCount = geom->getVertexCount();
  74. // Copy vertex data
  75. for (unsigned j = 0; j < vertexCount; ++j)
  76. {
  77. const Vector3& v = *((const Vector3*)(&vertexData[(vertexStart + j) * vertexSize]));
  78. destVertexData[firstVertex + j] = v;
  79. }
  80. unsigned indexStart = geom->getIndexStart();
  81. unsigned indexCount = geom->getIndexCount();
  82. // 16-bit indices
  83. if (indexSize == sizeof(unsigned short))
  84. {
  85. const unsigned short* indices = (const unsigned short*)indexData;
  86. for (unsigned j = 0; j < indexCount; j += 3)
  87. {
  88. // Rebase the indices according to our vertex numbering
  89. destIndexData[firstIndex + j] = indices[indexStart + j] - vertexStart + firstVertex;
  90. destIndexData[firstIndex + j + 1] = indices[indexStart + j + 1] - vertexStart + firstVertex;
  91. destIndexData[firstIndex + j + 2] = indices[indexStart + j + 2] - vertexStart + firstVertex;
  92. }
  93. }
  94. // 32-bit indices
  95. else
  96. {
  97. const unsigned* indices = (const unsigned*)indexData;
  98. for (unsigned j = 0; j < indexCount; j += 3)
  99. {
  100. // Rebase the indices according to our vertex numbering
  101. destIndexData[firstIndex + j] = indices[indexStart + j] - vertexStart + firstVertex;
  102. destIndexData[firstIndex + j + 1] = indices[indexStart + j + 1] - vertexStart + firstVertex;
  103. destIndexData[firstIndex + j + 2] = indices[indexStart + j + 2] - vertexStart + firstVertex;
  104. }
  105. }
  106. firstVertex += vertexCount;
  107. firstIndex += indexCount;
  108. geom->unlockRawData();
  109. }
  110. }
  111. TriangleMeshData::TriangleMeshData(const Model* model, bool makeConvexHull, float skinWidth, unsigned lodLevel) :
  112. mTriMesh(0),
  113. mVertexCount(0),
  114. mIndexCount(0)
  115. {
  116. if (!model)
  117. EXCEPTION("Null model for TriangleMeshData");
  118. if (!makeConvexHull)
  119. {
  120. mID = model->getName() + toString(lodLevel);
  121. getVertexAndIndexData(model, lodLevel, mVertexData, mVertexCount, mIndexData, mIndexCount);
  122. }
  123. else
  124. {
  125. mID = model->getName() + toString(lodLevel) + "hull" + toString(skinWidth);
  126. SharedArrayPtr<Vector3> originalVertices;
  127. SharedArrayPtr<unsigned> originalIndices;
  128. unsigned originalVertexCount;
  129. unsigned originalIndexCount;
  130. getVertexAndIndexData(model, lodLevel, originalVertices, originalVertexCount, originalIndices, originalIndexCount);
  131. // Build the convex hull from the raw geometry
  132. StanHull::HullDesc desc;
  133. desc.SetHullFlag(StanHull::QF_TRIANGLES);
  134. desc.mVcount = originalVertexCount;
  135. desc.mVertices = (float*)originalVertices.getPtr();
  136. desc.mVertexStride = 3 * sizeof(float);
  137. StanHull::HullLibrary lib;
  138. StanHull::HullResult result;
  139. lib.CreateConvexHull(desc, result);
  140. mVertexCount = result.mNumOutputVertices;
  141. mIndexCount = result.mNumIndices;
  142. // Copy vertex data
  143. mVertexData = new Vector3[mVertexCount];
  144. memcpy(mVertexData.getPtr(), result.mOutputVertices, mVertexCount * sizeof(Vector3));
  145. // Copy index data
  146. mIndexData = new unsigned[mIndexCount];
  147. memcpy(mIndexData.getPtr(), result.mIndices, mIndexCount * sizeof(unsigned));
  148. }
  149. mTriMesh = dGeomTriMeshDataCreate();
  150. dGeomTriMeshDataBuildSingle(mTriMesh, mVertexData.getPtr(), sizeof(Vector3), mVertexCount,
  151. mIndexData.getPtr(), mIndexCount, 3 * sizeof(unsigned));
  152. mMemoryUse = sizeof(TriangleMeshData) + mVertexCount * sizeof(Vector3) + mIndexCount * sizeof(unsigned);
  153. }
  154. TriangleMeshData::TriangleMeshData(const TriangleMeshData* source, const Vector3& scale) :
  155. mTriMesh(0)
  156. {
  157. if (!source)
  158. EXCEPTION("Null TriangleMeshData source");
  159. mID = source->mID + toString(scale);
  160. mVertexCount = source->mVertexCount;
  161. mIndexCount = source->mIndexCount;
  162. mVertexData = new Vector3[mVertexCount];
  163. mIndexData = source->mIndexData;
  164. // Copy and scale vertex data
  165. for (unsigned i = 0; i < mVertexCount; ++i)
  166. mVertexData[i] = scale * source->mVertexData[i];
  167. mTriMesh = dGeomTriMeshDataCreate();
  168. dGeomTriMeshDataBuildSingle(mTriMesh, mVertexData.getPtr(), sizeof(Vector3), mVertexCount,
  169. mIndexData.getPtr(), mIndexCount, 3 * sizeof(unsigned));
  170. // Indices are re-used, so account only for the scaled vertices
  171. mMemoryUse = sizeof(TriangleMeshData) + mVertexCount * sizeof(Vector3);
  172. }
  173. TriangleMeshData::~TriangleMeshData()
  174. {
  175. if (mTriMesh)
  176. {
  177. dGeomTriMeshDataDestroy(mTriMesh);
  178. mTriMesh = 0;
  179. }
  180. }
  181. HeightfieldData::HeightfieldData(const Model* model, unsigned xPoints, unsigned zPoints, float thickness, unsigned lodLevel) :
  182. mHeightfield(0),
  183. mThickness(thickness)
  184. {
  185. if (!model)
  186. EXCEPTION("Null model for HeightfieldData");
  187. mID = model->getName() + toString(mThickness) + toString(lodLevel);
  188. const std::vector<std::vector<SharedPtr<Geometry> > >& geometries = model->getGeometries();
  189. if (!geometries.size())
  190. EXCEPTION("No geometries for HeightfieldData");
  191. if (lodLevel >= geometries[0].size())
  192. lodLevel = geometries[0].size() / 2;
  193. Geometry* geom = geometries[0][lodLevel];
  194. if (!geom)
  195. EXCEPTION("Null geometry for HeightfieldData");
  196. const unsigned char* vertexData;
  197. const unsigned char* indexData;
  198. unsigned vertexSize;
  199. unsigned indexSize;
  200. geom->lockRawData(vertexData, vertexSize, indexData, indexSize);
  201. if ((!vertexData) || (!indexData))
  202. EXCEPTION("Raw geometry data unavailable");
  203. unsigned indexStart = geom->getIndexStart();
  204. unsigned indexCount = geom->getIndexCount();
  205. // If x & z size not specified, try to guess them
  206. if ((!xPoints) || (!zPoints))
  207. xPoints = zPoints = (int)sqrtf((float)geom->getVertexCount());
  208. // Then allocate the heightfield
  209. mXPoints = xPoints;
  210. mZPoints = zPoints;
  211. mBoundingBox = model->getBoundingBox();
  212. mHeightData = new float[xPoints * zPoints];
  213. // Calculate spacing from model's bounding box
  214. float xSpacing = (mBoundingBox.mMax.mX - mBoundingBox.mMin.mX) / (xPoints - 1);
  215. float zSpacing = (mBoundingBox.mMax.mZ - mBoundingBox.mMin.mZ) / (zPoints - 1);
  216. // Initialize the heightfield with minimum height
  217. for (unsigned i = 0; i < xPoints * zPoints; ++i)
  218. mHeightData[i] = mBoundingBox.mMin.mY;
  219. unsigned vertexStart = geom->getVertexStart();
  220. unsigned vertexCount = geom->getVertexCount();
  221. // Now go through vertex data and fit the vertices into the heightfield
  222. for (unsigned i = vertexStart; i < vertexStart + vertexCount; ++i)
  223. {
  224. const Vector3& vertex = *((const Vector3*)(&vertexData[i * vertexSize]));
  225. unsigned x = (int)((vertex.mX - mBoundingBox.mMin.mX) / xSpacing + 0.25f);
  226. unsigned z = (int)((vertex.mZ - mBoundingBox.mMin.mZ) / zSpacing + 0.25f);
  227. if (x >= xPoints)
  228. x = xPoints - 1;
  229. if (z >= zPoints)
  230. z = zPoints - 1;
  231. if (vertex.mY > mHeightData[z * xPoints + x])
  232. mHeightData[z * xPoints + x] = vertex.mY;
  233. }
  234. geom->unlockRawData();
  235. mHeightfield = dGeomHeightfieldDataCreate();
  236. dGeomHeightfieldDataBuildSingle(mHeightfield, mHeightData.getPtr(), 0, mBoundingBox.mMax.mX - mBoundingBox.mMin.mX,
  237. mBoundingBox.mMax.mZ - mBoundingBox.mMin.mZ, mXPoints, mZPoints, 1.0f, 0.0f, mThickness, 0);
  238. dGeomHeightfieldDataSetBounds(mHeightfield, mBoundingBox.mMin.mY, mBoundingBox.mMax.mY);
  239. mMemoryUse = sizeof(HeightfieldData) + mXPoints * mZPoints * sizeof(float);
  240. }
  241. HeightfieldData::HeightfieldData(const HeightfieldData* source, const Vector3& scale) :
  242. mHeightfield(0)
  243. {
  244. if (!source)
  245. EXCEPTION("Null HeightfieldData source");
  246. mID = source->mID + toString(scale);
  247. mXPoints = source->mXPoints;
  248. mZPoints = source->mZPoints;
  249. mThickness = source->mThickness * scale.mY;
  250. mBoundingBox = source->mBoundingBox;
  251. mHeightData = new float[mXPoints * mZPoints];
  252. // Adjust bounding box, and copy & scale the height data
  253. mBoundingBox.mMin *= scale;
  254. mBoundingBox.mMax *= scale;
  255. for (unsigned i = 0; i < mXPoints * mZPoints; ++i)
  256. mHeightData[i] = source->mHeightData[i] * scale.mY;
  257. mHeightfield = dGeomHeightfieldDataCreate();
  258. dGeomHeightfieldDataBuildSingle(mHeightfield, mHeightData.getPtr(), 0, mBoundingBox.mMax.mX - mBoundingBox.mMin.mX,
  259. mBoundingBox.mMax.mZ - mBoundingBox.mMin.mZ, mXPoints, mZPoints, 1.0f, 0.0f, mThickness, 0);
  260. dGeomHeightfieldDataSetBounds(mHeightfield, mBoundingBox.mMin.mY, mBoundingBox.mMax.mY);
  261. mMemoryUse = sizeof(HeightfieldData) + mXPoints * mZPoints * sizeof(float);
  262. }
  263. HeightfieldData::~HeightfieldData()
  264. {
  265. if (mHeightfield)
  266. {
  267. dGeomHeightfieldDataDestroy(mHeightfield);
  268. mHeightfield = 0;
  269. }
  270. }
  271. CollisionShape::CollisionShape(const std::string& name) :
  272. Resource(name)
  273. {
  274. }
  275. CollisionShape::~CollisionShape()
  276. {
  277. clear();
  278. }
  279. void CollisionShape::load(Deserializer& source, ResourceCache* cache)
  280. {
  281. clear();
  282. XMLFile xml;
  283. xml.load(source, cache);
  284. XMLElement rootElem = xml.getRootElement();
  285. XMLElement shapeElem = rootElem.getChildElement("");
  286. while (shapeElem)
  287. {
  288. std::string type = shapeElem.getName();
  289. Vector3 position = Vector3::sZero;
  290. Quaternion rotation = Quaternion::sIdentity;
  291. if (shapeElem.hasAttribute("position"))
  292. position = shapeElem.getVector3("position");
  293. if (shapeElem.hasAttribute("rotation"))
  294. rotation = shapeElem.getQuaternion("rotation");
  295. if (type == "sphere")
  296. addSphere(shapeElem.getFloat("radius"), position, rotation);
  297. if (type == "box")
  298. {
  299. Vector3 size = Vector3::sZero;
  300. if (shapeElem.hasAttribute("size"))
  301. size = shapeElem.getVector3("size");
  302. else if (shapeElem.hasAttribute("halfsize"))
  303. size = shapeElem.getVector3("halfsize") * 2.0f;
  304. addBox(size, position, rotation);
  305. }
  306. if (type == "cylinder")
  307. addCylinder(shapeElem.getFloat("radius"), shapeElem.getFloat("height"), position, rotation);
  308. if (type == "capsule")
  309. addCapsule(shapeElem.getFloat("radius"), shapeElem.getFloat("height"), position, rotation);
  310. if (type == "trianglemesh")
  311. {
  312. Model* model = cache->getResource<Model>(shapeElem.getString("name"));
  313. unsigned lodLevel = model->getCollisionLodLevel();
  314. if (shapeElem.hasAttribute("lodlevel"))
  315. lodLevel = shapeElem.getInt("lodlevel");
  316. addTriangleMesh(model, lodLevel, position, rotation);
  317. }
  318. if (type == "heightfield")
  319. {
  320. Model* model = cache->getResource<Model>(shapeElem.getString("name"));
  321. unsigned xSize = 0;
  322. unsigned zSize = 0;
  323. float thickness = 1.0f;
  324. unsigned lodLevel = model->getCollisionLodLevel();
  325. if (shapeElem.hasAttribute("xsize"))
  326. xSize = shapeElem.getInt("xsize");
  327. if (shapeElem.hasAttribute("zsize"))
  328. zSize = shapeElem.getInt("zsize");
  329. if (shapeElem.hasAttribute("xpoints"))
  330. xSize = shapeElem.getInt("xpoints");
  331. if (shapeElem.hasAttribute("zpoints"))
  332. zSize = shapeElem.getInt("zpoints");
  333. if (shapeElem.hasAttribute("lodlevel"))
  334. lodLevel = shapeElem.getInt("lodlevel");
  335. if (shapeElem.hasAttribute("thickness"))
  336. thickness = shapeElem.getFloat("thickness");
  337. addHeightfield(model, xSize, zSize, thickness, lodLevel, position, rotation);
  338. }
  339. if (type == "convexhull")
  340. {
  341. Model* model = cache->getResource<Model>(shapeElem.getString("name"));
  342. unsigned lodLevel = model->getCollisionLodLevel();
  343. float skinWidth = 0.0f;
  344. if (shapeElem.hasAttribute("lodlevel"))
  345. lodLevel = shapeElem.getInt("lodlevel");
  346. if (shapeElem.hasAttribute("skinwidth"))
  347. skinWidth = shapeElem.getFloat("skinwidth");
  348. addConvexHull(model, skinWidth, lodLevel, position, rotation);
  349. }
  350. shapeElem = shapeElem.getNextElement();
  351. }
  352. }
  353. void CollisionShape::addSphere(float radius, const Vector3& position, const Quaternion& rotation)
  354. {
  355. CollisionSubShape newShape;
  356. newShape.mType = SHAPE_SPHERE;
  357. newShape.mPosition = position;
  358. newShape.mRotation = rotation;
  359. newShape.mSize = Vector3(radius, radius, radius);
  360. mSubShapes.push_back(newShape);
  361. setMemoryUse(getMemoryUse() + sizeof(CollisionSubShape));
  362. }
  363. void CollisionShape::addBox(const Vector3& size, const Vector3& position, const Quaternion& rotation)
  364. {
  365. CollisionSubShape newShape;
  366. newShape.mType = SHAPE_BOX;
  367. newShape.mPosition = position;
  368. newShape.mRotation = rotation;
  369. newShape.mSize = size;
  370. mSubShapes.push_back(newShape);
  371. setMemoryUse(getMemoryUse() + sizeof(CollisionSubShape));
  372. }
  373. void CollisionShape::addCapsule(float radius, float height, const Vector3& position, const Quaternion& rotation)
  374. {
  375. CollisionSubShape newShape;
  376. newShape.mType = SHAPE_CAPSULE;
  377. newShape.mPosition = position;
  378. newShape.mRotation = rotation;
  379. newShape.mSize = Vector3(radius, radius, height);
  380. mSubShapes.push_back(newShape);
  381. setMemoryUse(getMemoryUse() + sizeof(CollisionSubShape));
  382. }
  383. void CollisionShape::addCylinder(float radius, float height, const Vector3& position, const Quaternion& rotation)
  384. {
  385. CollisionSubShape newShape;
  386. newShape.mType = SHAPE_CYLINDER;
  387. newShape.mPosition = position;
  388. newShape.mRotation = rotation;
  389. newShape.mSize = Vector3(radius, radius, height);
  390. mSubShapes.push_back(newShape);
  391. setMemoryUse(getMemoryUse() + sizeof(CollisionSubShape));
  392. }
  393. void CollisionShape::addTriangleMesh(const Model* model, unsigned lodLevel, const Vector3& position, const Quaternion& rotation)
  394. {
  395. PROFILE(Physics_AddTriangleMesh);
  396. if (!model)
  397. {
  398. LOGERROR("Null model for addTriangleMesh");
  399. return;
  400. }
  401. CollisionSubShape newShape;
  402. newShape.mType = SHAPE_TRIANGLEMESH;
  403. newShape.mPosition = position;
  404. newShape.mRotation = rotation;
  405. newShape.mSize = model->getBoundingBox().getSize();
  406. // Check cache
  407. std::string id = model->getName() + toString(lodLevel);
  408. std::map<std::string, SharedPtr<TriangleMeshData> >::iterator i = sTriangleMeshCache.find(id);
  409. if (i != sTriangleMeshCache.end())
  410. newShape.mGeometryData = staticCast<CollisionGeometryData>(i->second);
  411. else
  412. {
  413. SharedPtr<TriangleMeshData> newData(new TriangleMeshData(model, false, 0.0f, lodLevel));
  414. sTriangleMeshCache[id] = newData;
  415. newShape.mGeometryData = staticCast<CollisionGeometryData>(newData);
  416. }
  417. mSubShapes.push_back(newShape);
  418. setMemoryUse(getMemoryUse() + sizeof(CollisionSubShape) + newShape.mGeometryData->mMemoryUse);
  419. }
  420. void CollisionShape::addHeightfield(const Model* model, unsigned xPoints, unsigned zPoints, float thickness, unsigned lodLevel, const Vector3& position, const Quaternion& rotation)
  421. {
  422. PROFILE(Physics_AddTriangleMesh);
  423. if (!model)
  424. {
  425. LOGERROR("Null model for addHeightField");
  426. return;
  427. }
  428. CollisionSubShape newShape;
  429. newShape.mType = SHAPE_HEIGHTFIELD;
  430. newShape.mPosition = position;
  431. newShape.mRotation = rotation;
  432. newShape.mSize = model->getBoundingBox().getSize();
  433. // Check cache
  434. std::string id = model->getName() + toString(thickness) + toString(lodLevel);
  435. std::map<std::string, SharedPtr<HeightfieldData> >::iterator i = sHeightfieldCache.find(id);
  436. if (i != sHeightfieldCache.end())
  437. newShape.mGeometryData = staticCast<CollisionGeometryData>(i->second);
  438. else
  439. {
  440. SharedPtr<HeightfieldData> newData(new HeightfieldData(model, xPoints, zPoints, thickness, lodLevel));
  441. sHeightfieldCache[id] = newData;
  442. newShape.mGeometryData = staticCast<CollisionGeometryData>(newData);
  443. }
  444. mSubShapes.push_back(newShape);
  445. setMemoryUse(getMemoryUse() + sizeof(CollisionSubShape) + newShape.mGeometryData->mMemoryUse);
  446. }
  447. void CollisionShape::addConvexHull(const Model* model, float skinWidth, unsigned lodLevel, const Vector3& position, const Quaternion& rotation)
  448. {
  449. PROFILE(Physics_AddConvexHull);
  450. if (!model)
  451. {
  452. LOGERROR("Null model for addConvexHull");
  453. return;
  454. }
  455. CollisionSubShape newShape;
  456. newShape.mType = SHAPE_TRIANGLEMESH;
  457. newShape.mPosition = position;
  458. newShape.mRotation = rotation;
  459. newShape.mSize = model->getBoundingBox().getSize();
  460. // Check cache
  461. std::string id = model->getName() + toString(lodLevel) + "hull" + toString(skinWidth);
  462. std::map<std::string, SharedPtr<TriangleMeshData> >::iterator i = sTriangleMeshCache.find(id);
  463. if (i != sTriangleMeshCache.end())
  464. newShape.mGeometryData = staticCast<CollisionGeometryData>(i->second);
  465. else
  466. {
  467. SharedPtr<TriangleMeshData> newData(new TriangleMeshData(model, true, skinWidth, lodLevel));
  468. sTriangleMeshCache[id] = newData;
  469. newShape.mGeometryData = staticCast<CollisionGeometryData>(newData);
  470. }
  471. mSubShapes.push_back(newShape);
  472. setMemoryUse(getMemoryUse() + sizeof(CollisionSubShape) + newShape.mGeometryData->mMemoryUse);
  473. }
  474. void CollisionShape::clear()
  475. {
  476. mSubShapes.clear();
  477. setMemoryUse(sizeof(CollisionShape));
  478. cleanupCaches();
  479. }
  480. void CollisionShape::createGeometries(std::vector<dGeomID>& geoms, std::vector<SharedPtr<CollisionGeometryData> >& geomDatas, dSpaceID space, const Vector3& scale)
  481. {
  482. PROFILE(Physics_CreateGeometries);
  483. for (unsigned i = 0; i < mSubShapes.size(); ++i)
  484. {
  485. const CollisionSubShape& shape = mSubShapes[i];
  486. Vector3 size = shape.mSize * scale;
  487. dGeomID newGeom = 0;
  488. switch (shape.mType)
  489. {
  490. case SHAPE_BOX:
  491. newGeom = dCreateBox(space, size.mX, size.mY, size.mZ);
  492. break;
  493. case SHAPE_SPHERE:
  494. newGeom = dCreateSphere(space, size.mX);
  495. break;
  496. case SHAPE_CAPSULE:
  497. newGeom = dCreateCapsule(space, size.mX, size.mZ);
  498. break;
  499. case SHAPE_CYLINDER:
  500. newGeom = dCreateCylinder(space, size.mX, size.mZ);
  501. break;
  502. case SHAPE_TRIANGLEMESH:
  503. if (scale == Vector3::sUnity)
  504. newGeom = dCreateTriMesh(space, staticCast<TriangleMeshData>(shape.mGeometryData)->mTriMesh, 0, 0, 0);
  505. else
  506. {
  507. // If the mesh is scaled, need to create an unique copy of the geometry
  508. // Check cache first
  509. std::string id = shape.mGeometryData->mID + toString(scale);
  510. std::map<std::string, SharedPtr<TriangleMeshData> >::iterator j = sTriangleMeshCache.find(id);
  511. if (j != sTriangleMeshCache.end())
  512. {
  513. newGeom = dCreateTriMesh(space, j->second->mTriMesh, 0, 0, 0);
  514. geomDatas.push_back(staticCast<CollisionGeometryData>(j->second));
  515. }
  516. else
  517. {
  518. LOGDEBUG("Creating unique copy of collision mesh, scale " + toString(scale));
  519. SharedPtr<TriangleMeshData> newData(new TriangleMeshData(staticCast<TriangleMeshData>(shape.mGeometryData), scale));
  520. sTriangleMeshCache[id] = newData;
  521. newGeom = dCreateTriMesh(space, newData->mTriMesh, 0, 0, 0);
  522. geomDatas.push_back(staticCast<CollisionGeometryData>(newData));
  523. }
  524. }
  525. break;
  526. case SHAPE_HEIGHTFIELD:
  527. if (scale == Vector3::sUnity)
  528. newGeom = dCreateHeightfield(space, staticCast<HeightfieldData>(shape.mGeometryData)->mHeightfield, 1);
  529. else
  530. {
  531. // If the heightfield is scaled, need to create an unique copy of the geometry
  532. // Check cache first
  533. std::string id = shape.mGeometryData->mID + toString(scale);
  534. std::map<std::string, SharedPtr<HeightfieldData> >::iterator j = sHeightfieldCache.find(id);
  535. if (j != sHeightfieldCache.end())
  536. {
  537. newGeom = dCreateHeightfield(space, j->second->mHeightfield, 1);
  538. geomDatas.push_back(staticCast<CollisionGeometryData>(j->second));
  539. }
  540. else
  541. {
  542. LOGDEBUG("Creating unique copy of heightfield, scale " + toString(scale));
  543. SharedPtr<HeightfieldData> newData(new HeightfieldData(staticCast<HeightfieldData>(shape.mGeometryData), scale));
  544. sHeightfieldCache[id] = newData;
  545. newGeom = dCreateHeightfield(space, newData->mHeightfield, 1);
  546. geomDatas.push_back(staticCast<CollisionGeometryData>(newData));
  547. }
  548. }
  549. break;
  550. }
  551. if (newGeom)
  552. geoms.push_back(newGeom);
  553. }
  554. }
  555. void CollisionShape::setBodyAndTransforms(const std::vector<dGeomID>& geoms, dBodyID body, const Vector3& position, const Quaternion& rotation, const Vector3& scale)
  556. {
  557. for (unsigned i = 0; (i < mSubShapes.size()) && (i < geoms.size()); ++i)
  558. {
  559. const CollisionSubShape& shape = mSubShapes[i];
  560. dGeomSetBody(geoms[i], body);
  561. // If using a body, can set geometry offset. If not, have to calculate the full transform manually
  562. if (body)
  563. {
  564. if ((shape.mPosition != Vector3::sZero) || (shape.mRotation != Quaternion::sIdentity))
  565. {
  566. Vector3 offset = scale * shape.mPosition;
  567. dGeomSetOffsetPosition(geoms[i], offset.mX, offset.mY, offset.mZ);
  568. dGeomSetOffsetQuaternion(geoms[i], shape.mRotation.getData());
  569. }
  570. }
  571. else
  572. {
  573. Vector3 worldPos = position + (rotation * (scale * shape.mPosition));
  574. Quaternion worldRot = rotation * shape.mRotation;
  575. dGeomSetPosition(geoms[i], worldPos.mX, worldPos.mY, worldPos.mZ);
  576. dGeomSetQuaternion(geoms[i], worldRot.getData());
  577. }
  578. }
  579. }
  580. void CollisionShape::calculateMass(void* dest, const std::vector<dGeomID>& geoms, float density, const Vector3& scale)
  581. {
  582. dMass* mass = (dMass*)dest;
  583. if (!mass)
  584. return;
  585. dMassSetZero(mass);
  586. for (unsigned i = 0; (i < mSubShapes.size()) && (i < geoms.size()); ++i)
  587. {
  588. const CollisionSubShape& shape = mSubShapes[i];
  589. dMass subMass;
  590. Vector3 size = shape.mSize * scale;
  591. Vector3 offset = shape.mPosition * scale;
  592. switch (shape.mType)
  593. {
  594. case SHAPE_BOX:
  595. dMassSetBox(&subMass, density, size.mX, size.mY, size.mZ);
  596. break;
  597. case SHAPE_SPHERE:
  598. dMassSetSphere(&subMass, density, size.mX);
  599. break;
  600. case SHAPE_CYLINDER:
  601. dMassSetCylinder(&subMass, density, 2, size.mX, size.mZ);
  602. break;
  603. case SHAPE_CAPSULE:
  604. dMassSetCapsule(&subMass, density, 2, size.mX, size.mZ);
  605. break;
  606. case SHAPE_TRIANGLEMESH:
  607. dMassSetBox(&subMass, density, size.mX, size.mY, size.mZ);
  608. break;
  609. }
  610. dMatrix3 rotMatrix;
  611. dRfromQ(rotMatrix, shape.mRotation.getData());
  612. dMassTranslate(&subMass, offset.mX, offset.mY, offset.mZ);
  613. dMassRotate(&subMass, rotMatrix);
  614. dMassAdd(mass, &subMass);
  615. }
  616. // Translate final mass to center; anything else is unsupported in ODE
  617. dMassTranslate(mass, -mass->c[0], -mass->c[1], -mass->c[2]);
  618. }
  619. void CollisionShape::cleanupCaches()
  620. {
  621. // Clear cached shapes whose only reference is the cache itself
  622. for (std::map<std::string, SharedPtr<TriangleMeshData> >::iterator i = sTriangleMeshCache.begin();
  623. i != sTriangleMeshCache.end();)
  624. {
  625. std::map<std::string, SharedPtr<TriangleMeshData> >::iterator current = i++;
  626. if (current->second.getRefCount() == 1)
  627. sTriangleMeshCache.erase(current);
  628. }
  629. for (std::map<std::string, SharedPtr<HeightfieldData> >::iterator i = sHeightfieldCache.begin();
  630. i != sHeightfieldCache.end();)
  631. {
  632. std::map<std::string, SharedPtr<HeightfieldData> >::iterator current = i++;
  633. if (current->second.getRefCount() == 1)
  634. sHeightfieldCache.erase(current);
  635. }
  636. }