PhysicsCollisionShape.cpp 12 KB

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