#include "Base.h" #include "PhysicsCollisionShape.h" #include "Node.h" #include "Properties.h" namespace gameplay { PhysicsCollisionShape::PhysicsCollisionShape(Type type, btCollisionShape* shape) : _type(type), _shape(shape) { memset(&_shapeData, 0, sizeof(_shapeData)); } PhysicsCollisionShape::PhysicsCollisionShape(const PhysicsCollisionShape& copy) { // hidden } PhysicsCollisionShape::~PhysicsCollisionShape() { if (_shape) { // Cleanup shape-specific cached data switch (_type) { case SHAPE_MESH: if (_shapeData.meshData) { SAFE_DELETE_ARRAY(_shapeData.meshData->vertexData); for (unsigned int i = 0; i < _shapeData.meshData->indexData.size(); i++) { SAFE_DELETE_ARRAY(_shapeData.meshData->indexData[i]); } SAFE_DELETE(_shapeData.meshData); } break; case SHAPE_HEIGHTFIELD: if (_shapeData.heightfieldData) { SAFE_DELETE_ARRAY(_shapeData.heightfieldData->heightData); SAFE_DELETE(_shapeData.heightfieldData); } break; } // Free the bullet shape SAFE_DELETE(_shape); } } PhysicsCollisionShape::Type PhysicsCollisionShape::getType() const { return _type; } PhysicsCollisionShape::Definition::Definition() : isExplicit(false), centerAbsolute(false) { memset(&data, 0, sizeof(data)); } PhysicsCollisionShape::Definition::Definition(const Definition& definition) { // Bitwise-copy the definition object (equivalent to default copy constructor). memcpy(this, &definition, sizeof(PhysicsCollisionShape::Definition)); // Handle the types that have reference-counted members. switch (type) { case PhysicsCollisionShape::SHAPE_HEIGHTFIELD: data.heightfield->addRef(); break; case PhysicsCollisionShape::SHAPE_MESH: data.mesh->addRef(); break; } } PhysicsCollisionShape::Definition::~Definition() { switch (type) { case PhysicsCollisionShape::SHAPE_HEIGHTFIELD: SAFE_RELEASE(data.heightfield); break; case PhysicsCollisionShape::SHAPE_MESH: SAFE_RELEASE(data.mesh); break; } } PhysicsCollisionShape::Definition& PhysicsCollisionShape::Definition::operator=(const Definition& definition) { if (this != &definition) { // Bitwise-copy the definition object (equivalent to default copy constructor). memcpy(this, &definition, sizeof(PhysicsCollisionShape::Definition)); // Handle the types that have reference-counted members. switch (type) { case PhysicsCollisionShape::SHAPE_HEIGHTFIELD: data.heightfield->addRef(); break; case PhysicsCollisionShape::SHAPE_MESH: data.mesh->addRef(); break; } } return *this; } PhysicsCollisionShape::Definition* PhysicsCollisionShape::Definition::create(Node* node, Properties* properties) { // Check if the properties is valid and has a valid namespace. assert(properties); if (!properties || !(strcmp(properties->getNamespace(), "character") == 0 || strcmp(properties->getNamespace(), "ghost") == 0 || strcmp(properties->getNamespace(), "rigidbody") == 0)) { WARN("Failed to load physics collision shape from properties object: must be non-null object and have namespace equal to \'character\', \'ghost\', or \'rigidbody\'."); return NULL; } // Set values to their defaults. PhysicsCollisionShape::Type type = PhysicsCollisionShape::SHAPE_BOX; Vector3* extents = NULL; Vector3* center = NULL; float radius = -1.0f; float height = -1.0f; bool centerIsAbsolute = false; const char* imagePath = NULL; bool typeSpecified = false; // Load the defined properties. properties->rewind(); const char* name; while (name = properties->getNextProperty()) { if (strcmp(name, "type") == 0) { std::string typeStr = properties->getString(); if (typeStr == "BOX") type = SHAPE_BOX; else if (typeStr == "SPHERE") type = SHAPE_SPHERE; else if (typeStr == "MESH") type = SHAPE_MESH; else if (typeStr == "HEIGHTFIELD") type = SHAPE_HEIGHTFIELD; else if (typeStr == "CAPSULE") type = SHAPE_CAPSULE; else { WARN_VARG("Could not create physics collision shape; unsupported value for collision shape type: '%s'.", typeStr.c_str()); return NULL; } typeSpecified = true; } else if (strcmp(name, "image") == 0) { imagePath = properties->getString(); } else if (strcmp(name, "radius") == 0) { radius = properties->getFloat(); } else if (strcmp(name, "height") == 0) { height = properties->getFloat(); } else if (strcmp(name, "extents") == 0) { extents = new Vector3(); properties->getVector3("extents", extents); } else if (strcmp(name, "center") == 0) { center = new Vector3(); properties->getVector3("center", center); } else if (strcmp(name, "center-absolute") == 0) { centerIsAbsolute = properties->getBool(); } } if (!typeSpecified) { WARN("Missing 'type' specifier for collision shape definition."); return NULL; } // Create the collision shape. PhysicsCollisionShape::Definition* shape = new PhysicsCollisionShape::Definition(); switch (type) { case SHAPE_BOX: if (extents) { if (center) { *shape = box(*extents, *center, centerIsAbsolute); } else { *shape = box(*extents); } } else { *shape = box(); } break; case SHAPE_SPHERE: if (radius != -1.0f) { if (center) { *shape = sphere(radius, *center, centerIsAbsolute); } else { *shape = sphere(radius); } } else { *shape = sphere(); } break; case SHAPE_CAPSULE: if (radius != -1.0f && height != -1.0f) { if (center) { *shape = capsule(radius, height, *center, centerIsAbsolute); } else { *shape = capsule(radius, height); } } else { *shape = capsule(); } break; case SHAPE_MESH: { // Mesh is required on node Mesh* nodeMesh = node->getModel() ? node->getModel()->getMesh() : NULL; if (nodeMesh == NULL) { WARN("Cannot create mesh rigid body for node without mode/mesh."); return NULL; } // Check that the node's mesh's primitive type is supported. switch (nodeMesh->getPrimitiveType()) { case Mesh::TRIANGLES: { *shape = mesh(nodeMesh); break; } case Mesh::LINES: case Mesh::LINE_STRIP: case Mesh::POINTS: case Mesh::TRIANGLE_STRIP: WARN("Mesh rigid bodies are currently only supported on meshes with primitive type equal to TRIANGLES."); SAFE_DELETE(shape); break; } break; } case SHAPE_HEIGHTFIELD: if (imagePath == NULL) { WARN("Heightfield rigid body requires an image path."); } else { // Load the image data from the given file path. Image* image = Image::create(imagePath); if (!image) return NULL; // Ensure that the image's pixel format is supported. switch (image->getFormat()) { case Image::RGB: case Image::RGBA: break; default: WARN_VARG("Heightmap: pixel format is not supported: %d", image->getFormat()); return NULL; } *shape = PhysicsCollisionShape::heightfield(image); SAFE_RELEASE(image); } break; default: WARN("Unsupported value for physics collision shape type."); break; } SAFE_DELETE(extents); SAFE_DELETE(center); return shape; } PhysicsCollisionShape::Definition PhysicsCollisionShape::box() { Definition d; d.type = SHAPE_BOX; d.isExplicit = false; d.centerAbsolute = false; return d; } PhysicsCollisionShape::Definition PhysicsCollisionShape::box(const Vector3& extents, const Vector3& center, bool absolute) { Definition d; d.type = SHAPE_BOX; memcpy(d.data.box.extents, &extents.x, sizeof(float) * 3); memcpy(d.data.box.center, ¢er.x, sizeof(float) * 3); d.isExplicit = true; d.centerAbsolute = absolute; return d; } PhysicsCollisionShape::Definition PhysicsCollisionShape::sphere() { Definition d; d.type = SHAPE_SPHERE; d.isExplicit = false; d.centerAbsolute = false; return d; } PhysicsCollisionShape::Definition PhysicsCollisionShape::sphere(float radius, const Vector3& center, bool absolute) { Definition d; d.type = SHAPE_SPHERE; d.data.sphere.radius = radius; memcpy(d.data.sphere.center, ¢er.x, sizeof(float) * 3); d.isExplicit = true; d.centerAbsolute = absolute; return d; } PhysicsCollisionShape::Definition PhysicsCollisionShape::capsule() { Definition d; d.type = SHAPE_CAPSULE; d.isExplicit = false; d.centerAbsolute = false; return d; } PhysicsCollisionShape::Definition PhysicsCollisionShape::capsule(float radius, float height, const Vector3& center, bool absolute) { Definition d; d.type = SHAPE_CAPSULE; d.data.capsule.radius = radius; d.data.capsule.height = height; memcpy(d.data.capsule.center, ¢er.x, sizeof(float) * 3); d.isExplicit = true; d.centerAbsolute = absolute; return d; } PhysicsCollisionShape::Definition PhysicsCollisionShape::heightfield(Image* image) { image->addRef(); Definition d; d.type = SHAPE_HEIGHTFIELD; d.data.heightfield = image; d.isExplicit = true; d.centerAbsolute = false; return d; } PhysicsCollisionShape::Definition PhysicsCollisionShape::mesh(Mesh* mesh) { mesh->addRef(); Definition d; d.type = SHAPE_MESH; d.data.mesh = mesh; d.isExplicit = true; d.centerAbsolute = false; return d; } }