PhysicsCollisionShape.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. #include "Base.h"
  2. #include "PhysicsCollisionShape.h"
  3. #include "Node.h"
  4. #include "Image.h"
  5. #include "Properties.h"
  6. #include "FileSystem.h"
  7. #include "HeightField.h"
  8. namespace gameplay
  9. {
  10. PhysicsCollisionShape::PhysicsCollisionShape(Type type, btCollisionShape* shape, btStridingMeshInterface* meshInterface)
  11. : _type(type), _shape(shape), _meshInterface(meshInterface)
  12. {
  13. memset(&_shapeData, 0, sizeof(_shapeData));
  14. }
  15. PhysicsCollisionShape::~PhysicsCollisionShape()
  16. {
  17. if (_shape)
  18. {
  19. // Cleanup shape-specific cached data.
  20. switch (_type)
  21. {
  22. case SHAPE_MESH:
  23. if (_shapeData.meshData)
  24. {
  25. SAFE_DELETE_ARRAY(_shapeData.meshData->vertexData);
  26. for (unsigned int i = 0; i < _shapeData.meshData->indexData.size(); i++)
  27. {
  28. SAFE_DELETE_ARRAY(_shapeData.meshData->indexData[i]);
  29. }
  30. SAFE_DELETE(_shapeData.meshData);
  31. }
  32. // Also need to delete the btTriangleIndexVertexArray, if it exists.
  33. SAFE_DELETE(_meshInterface);
  34. break;
  35. case SHAPE_HEIGHTFIELD:
  36. if (_shapeData.heightfieldData)
  37. {
  38. SAFE_RELEASE(_shapeData.heightfieldData->heightfield);
  39. SAFE_DELETE(_shapeData.heightfieldData);
  40. }
  41. break;
  42. }
  43. // Free the bullet shape.
  44. SAFE_DELETE(_shape);
  45. }
  46. }
  47. PhysicsCollisionShape::Type PhysicsCollisionShape::getType() const
  48. {
  49. return _type;
  50. }
  51. PhysicsCollisionShape::Definition::Definition()
  52. : type(SHAPE_NONE), isExplicit(false), centerAbsolute(false)
  53. {
  54. memset(&data, 0, sizeof(data));
  55. }
  56. PhysicsCollisionShape::Definition::Definition(const Definition& definition)
  57. {
  58. // Bitwise-copy the definition object (equivalent to default copy constructor).
  59. memcpy(this, &definition, sizeof(PhysicsCollisionShape::Definition));
  60. // Handle the types that have reference-counted members.
  61. switch (type)
  62. {
  63. case PhysicsCollisionShape::SHAPE_HEIGHTFIELD:
  64. if (data.heightfield)
  65. data.heightfield->addRef();
  66. break;
  67. case PhysicsCollisionShape::SHAPE_MESH:
  68. GP_ASSERT(data.mesh);
  69. data.mesh->addRef();
  70. break;
  71. }
  72. }
  73. PhysicsCollisionShape::Definition::~Definition()
  74. {
  75. switch (type)
  76. {
  77. case PhysicsCollisionShape::SHAPE_HEIGHTFIELD:
  78. SAFE_RELEASE(data.heightfield);
  79. break;
  80. case PhysicsCollisionShape::SHAPE_MESH:
  81. SAFE_RELEASE(data.mesh);
  82. break;
  83. }
  84. }
  85. PhysicsCollisionShape::Definition& PhysicsCollisionShape::Definition::operator=(const Definition& definition)
  86. {
  87. if (this != &definition)
  88. {
  89. // Bitwise-copy the definition object (equivalent to default copy constructor).
  90. memcpy(this, &definition, sizeof(PhysicsCollisionShape::Definition));
  91. // Handle the types that have reference-counted members.
  92. switch (type)
  93. {
  94. case PhysicsCollisionShape::SHAPE_HEIGHTFIELD:
  95. if (data.heightfield)
  96. data.heightfield->addRef();
  97. break;
  98. case PhysicsCollisionShape::SHAPE_MESH:
  99. GP_ASSERT(data.mesh);
  100. data.mesh->addRef();
  101. break;
  102. }
  103. }
  104. return *this;
  105. }
  106. bool PhysicsCollisionShape::Definition::isEmpty() const
  107. {
  108. return type == SHAPE_NONE;
  109. }
  110. PhysicsCollisionShape::Definition PhysicsCollisionShape::Definition::create(Node* node, Properties* properties)
  111. {
  112. GP_ASSERT(node);
  113. // Check if the properties is valid and has a valid namespace.
  114. if (!properties || !(strcmp(properties->getNamespace(), "collisionObject") == 0))
  115. {
  116. GP_ERROR("Failed to load physics collision shape from properties object: must be non-null object and have namespace equal to 'collisionObject'.");
  117. return Definition();
  118. }
  119. // Set values to their defaults.
  120. PhysicsCollisionShape::Type type = PhysicsCollisionShape::SHAPE_BOX;
  121. Vector3 extents, center;
  122. bool extentsSpecified = false;
  123. bool centerSpecified = false;
  124. float radius = -1.0f;
  125. float width = -1.0f;
  126. float height = -1.0f;
  127. bool centerIsAbsolute = false;
  128. const char* imagePath = NULL;
  129. float maxHeight = 0;
  130. float minHeight = 0;
  131. bool shapeSpecified = false;
  132. // Load the defined properties.
  133. properties->rewind();
  134. const char* name;
  135. while (name = properties->getNextProperty())
  136. {
  137. if (strcmp(name, "shape") == 0)
  138. {
  139. std::string shapeStr = properties->getString();
  140. if (shapeStr == "BOX")
  141. type = SHAPE_BOX;
  142. else if (shapeStr == "SPHERE")
  143. type = SHAPE_SPHERE;
  144. else if (shapeStr == "MESH")
  145. type = SHAPE_MESH;
  146. else if (shapeStr == "HEIGHTFIELD")
  147. type = SHAPE_HEIGHTFIELD;
  148. else if (shapeStr == "CAPSULE")
  149. type = SHAPE_CAPSULE;
  150. else
  151. {
  152. GP_ERROR("Could not create physics collision shape; unsupported value for collision shape type: '%s'.", shapeStr.c_str());
  153. return Definition();
  154. }
  155. shapeSpecified = true;
  156. }
  157. else if (strcmp(name, "image") == 0)
  158. {
  159. imagePath = properties->getString();
  160. }
  161. else if (strcmp(name, "maxHeight") == 0)
  162. {
  163. maxHeight = properties->getFloat();
  164. }
  165. else if (strcmp(name, "minHeight") == 0)
  166. {
  167. minHeight = properties->getFloat();
  168. }
  169. else if (strcmp(name, "radius") == 0)
  170. {
  171. radius = properties->getFloat();
  172. }
  173. else if (strcmp(name, "width") == 0)
  174. {
  175. width = properties->getFloat();
  176. }
  177. else if (strcmp(name, "height") == 0)
  178. {
  179. height = properties->getFloat();
  180. }
  181. else if (strcmp(name, "extents") == 0)
  182. {
  183. properties->getVector3("extents", &extents);
  184. extentsSpecified = true;
  185. }
  186. else if (strcmp(name, "center") == 0)
  187. {
  188. properties->getVector3("center", &center);
  189. centerSpecified = true;
  190. }
  191. else if (strcmp(name, "centerAbsolute") == 0)
  192. {
  193. centerIsAbsolute = properties->getBool();
  194. }
  195. else
  196. {
  197. // Ignore this case (these are the properties for the rigid body, character, or ghost object that this collision shape is for).
  198. }
  199. }
  200. if (!shapeSpecified)
  201. {
  202. GP_ERROR("Missing 'shape' specifier for collision shape definition.");
  203. return Definition();
  204. }
  205. // Create the collision shape.
  206. Definition shape;
  207. switch (type)
  208. {
  209. case SHAPE_BOX:
  210. if (extentsSpecified)
  211. {
  212. if (centerSpecified)
  213. {
  214. shape = box(extents, center, centerIsAbsolute);
  215. }
  216. else
  217. {
  218. shape = box(extents);
  219. }
  220. }
  221. else
  222. {
  223. shape = box();
  224. }
  225. break;
  226. case SHAPE_SPHERE:
  227. if (radius != -1.0f)
  228. {
  229. if (centerSpecified)
  230. {
  231. shape = sphere(radius, center, centerIsAbsolute);
  232. }
  233. else
  234. {
  235. shape = sphere(radius);
  236. }
  237. }
  238. else
  239. {
  240. shape = sphere();
  241. }
  242. break;
  243. case SHAPE_CAPSULE:
  244. if (radius != -1.0f && height != -1.0f)
  245. {
  246. if (centerSpecified)
  247. {
  248. shape = capsule(radius, height, center, centerIsAbsolute);
  249. }
  250. else
  251. {
  252. shape = capsule(radius, height);
  253. }
  254. }
  255. else
  256. {
  257. shape = capsule();
  258. }
  259. break;
  260. case SHAPE_MESH:
  261. {
  262. // Mesh is required on node.
  263. Mesh* nodeMesh = node->getModel() ? node->getModel()->getMesh() : NULL;
  264. if (nodeMesh == NULL)
  265. {
  266. GP_ERROR("Cannot create mesh collision object for node without model/mesh.");
  267. }
  268. else
  269. {
  270. // Check that the node's mesh's primitive type is supported.
  271. switch (nodeMesh->getPrimitiveType())
  272. {
  273. case Mesh::TRIANGLES:
  274. shape = mesh(nodeMesh);
  275. break;
  276. case Mesh::LINES:
  277. case Mesh::LINE_STRIP:
  278. case Mesh::POINTS:
  279. case Mesh::TRIANGLE_STRIP:
  280. GP_ERROR("Mesh collision objects are currently only supported on meshes with primitive type equal to TRIANGLES.");
  281. break;
  282. }
  283. }
  284. }
  285. break;
  286. case SHAPE_HEIGHTFIELD:
  287. {
  288. if (imagePath == NULL)
  289. {
  290. // Node requires a valid terrain
  291. if (node->getTerrain() == NULL)
  292. {
  293. GP_ERROR("Heightfield collision objects can only be specified on nodes that have a valid terrain, or that specify an image path.");
  294. }
  295. else
  296. {
  297. shape = PhysicsCollisionShape::heightfield();
  298. }
  299. }
  300. else
  301. {
  302. std::string ext = FileSystem::getExtension(imagePath);
  303. HeightField* heightfield = NULL;
  304. if (ext == ".PNG")
  305. heightfield = HeightField::createFromImage(imagePath, minHeight, maxHeight);
  306. else if (ext == ".RAW" || ext == ".R16")
  307. heightfield = HeightField::createFromRAW(imagePath, (unsigned int)width, (unsigned int)height, minHeight, maxHeight);
  308. if (heightfield)
  309. {
  310. shape = PhysicsCollisionShape::heightfield(heightfield);
  311. SAFE_RELEASE(heightfield);
  312. }
  313. }
  314. }
  315. break;
  316. default:
  317. GP_ERROR("Unsupported physics collision shape type (%d).", type);
  318. break;
  319. }
  320. return shape;
  321. }
  322. PhysicsCollisionShape::Definition PhysicsCollisionShape::box()
  323. {
  324. Definition d;
  325. d.type = SHAPE_BOX;
  326. d.isExplicit = false;
  327. d.centerAbsolute = false;
  328. return d;
  329. }
  330. PhysicsCollisionShape::Definition PhysicsCollisionShape::box(const Vector3& extents, const Vector3& center, bool absolute)
  331. {
  332. Definition d;
  333. d.type = SHAPE_BOX;
  334. memcpy(d.data.box.extents, &extents.x, sizeof(float) * 3);
  335. memcpy(d.data.box.center, &center.x, sizeof(float) * 3);
  336. d.isExplicit = true;
  337. d.centerAbsolute = absolute;
  338. return d;
  339. }
  340. PhysicsCollisionShape::Definition PhysicsCollisionShape::sphere()
  341. {
  342. Definition d;
  343. d.type = SHAPE_SPHERE;
  344. d.isExplicit = false;
  345. d.centerAbsolute = false;
  346. return d;
  347. }
  348. PhysicsCollisionShape::Definition PhysicsCollisionShape::sphere(float radius, const Vector3& center, bool absolute)
  349. {
  350. Definition d;
  351. d.type = SHAPE_SPHERE;
  352. d.data.sphere.radius = radius;
  353. memcpy(d.data.sphere.center, &center.x, sizeof(float) * 3);
  354. d.isExplicit = true;
  355. d.centerAbsolute = absolute;
  356. return d;
  357. }
  358. PhysicsCollisionShape::Definition PhysicsCollisionShape::capsule()
  359. {
  360. Definition d;
  361. d.type = SHAPE_CAPSULE;
  362. d.isExplicit = false;
  363. d.centerAbsolute = false;
  364. return d;
  365. }
  366. PhysicsCollisionShape::Definition PhysicsCollisionShape::capsule(float radius, float height, const Vector3& center, bool absolute)
  367. {
  368. Definition d;
  369. d.type = SHAPE_CAPSULE;
  370. d.data.capsule.radius = radius;
  371. d.data.capsule.height = height;
  372. memcpy(d.data.capsule.center, &center.x, sizeof(float) * 3);
  373. d.isExplicit = true;
  374. d.centerAbsolute = absolute;
  375. return d;
  376. }
  377. PhysicsCollisionShape::Definition PhysicsCollisionShape::heightfield()
  378. {
  379. Definition d;
  380. d.type = SHAPE_HEIGHTFIELD;
  381. d.isExplicit = false;
  382. d.centerAbsolute = false;
  383. return d;
  384. }
  385. PhysicsCollisionShape::Definition PhysicsCollisionShape::heightfield(HeightField* heightfield)
  386. {
  387. GP_ASSERT(heightfield);
  388. heightfield->addRef();
  389. Definition d;
  390. d.type = SHAPE_HEIGHTFIELD;
  391. d.data.heightfield = heightfield;
  392. d.isExplicit = true;
  393. d.centerAbsolute = false;
  394. return d;
  395. }
  396. PhysicsCollisionShape::Definition PhysicsCollisionShape::mesh(Mesh* mesh)
  397. {
  398. GP_ASSERT(mesh);
  399. mesh->addRef();
  400. Definition d;
  401. d.type = SHAPE_MESH;
  402. d.data.mesh = mesh;
  403. d.isExplicit = true;
  404. d.centerAbsolute = false;
  405. return d;
  406. }
  407. }