summaryrefslogtreecommitdiff
path: root/modules/bullet/shape_bullet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/bullet/shape_bullet.cpp')
-rw-r--r--modules/bullet/shape_bullet.cpp435
1 files changed, 435 insertions, 0 deletions
diff --git a/modules/bullet/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp
new file mode 100644
index 0000000000..49150484d9
--- /dev/null
+++ b/modules/bullet/shape_bullet.cpp
@@ -0,0 +1,435 @@
+/*************************************************************************/
+/* shape_bullet.cpp */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "shape_bullet.h"
+#include "BulletCollision/CollisionShapes/btConvexPointCloudShape.h"
+#include "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h"
+#include "btBulletCollisionCommon.h"
+#include "btRayShape.h"
+#include "bullet_physics_server.h"
+#include "bullet_types_converter.h"
+#include "bullet_utilities.h"
+#include "shape_owner_bullet.h"
+
+ShapeBullet::ShapeBullet() {}
+
+ShapeBullet::~ShapeBullet() {}
+
+btCollisionShape *ShapeBullet::prepare(btCollisionShape *p_btShape) const {
+ p_btShape->setUserPointer(const_cast<ShapeBullet *>(this));
+ return p_btShape;
+}
+
+void ShapeBullet::notifyShapeChanged() {
+ for (Map<ShapeOwnerBullet *, int>::Element *E = owners.front(); E; E = E->next()) {
+ static_cast<ShapeOwnerBullet *>(E->key())->on_shape_changed(this);
+ }
+}
+
+void ShapeBullet::add_owner(ShapeOwnerBullet *p_owner) {
+ Map<ShapeOwnerBullet *, int>::Element *E = owners.find(p_owner);
+ if (E) {
+ E->get()++;
+ } else {
+ owners[p_owner] = 1; // add new owner
+ }
+}
+
+void ShapeBullet::remove_owner(ShapeOwnerBullet *p_owner, bool p_permanentlyFromThisBody) {
+ Map<ShapeOwnerBullet *, int>::Element *E = owners.find(p_owner);
+ ERR_FAIL_COND(!E);
+ E->get()--;
+ if (p_permanentlyFromThisBody || 0 >= E->get()) {
+ owners.erase(E);
+ }
+}
+
+bool ShapeBullet::is_owner(ShapeOwnerBullet *p_owner) const {
+
+ return owners.has(p_owner);
+}
+
+const Map<ShapeOwnerBullet *, int> &ShapeBullet::get_owners() const {
+ return owners;
+}
+
+btEmptyShape *ShapeBullet::create_shape_empty() {
+ return bulletnew(btEmptyShape);
+}
+
+btStaticPlaneShape *ShapeBullet::create_shape_plane(const btVector3 &planeNormal, btScalar planeConstant) {
+ return bulletnew(btStaticPlaneShape(planeNormal, planeConstant));
+}
+
+btSphereShape *ShapeBullet::create_shape_sphere(btScalar radius) {
+ return bulletnew(btSphereShape(radius));
+}
+
+btBoxShape *ShapeBullet::create_shape_box(const btVector3 &boxHalfExtents) {
+ return bulletnew(btBoxShape(boxHalfExtents));
+}
+
+btCapsuleShapeZ *ShapeBullet::create_shape_capsule(btScalar radius, btScalar height) {
+ return bulletnew(btCapsuleShapeZ(radius, height));
+}
+
+btConvexPointCloudShape *ShapeBullet::create_shape_convex(btAlignedObjectArray<btVector3> &p_vertices, const btVector3 &p_local_scaling) {
+ return bulletnew(btConvexPointCloudShape(&p_vertices[0], p_vertices.size(), p_local_scaling));
+}
+
+btScaledBvhTriangleMeshShape *ShapeBullet::create_shape_concave(btBvhTriangleMeshShape *p_mesh_shape, const btVector3 &p_local_scaling) {
+ if (p_mesh_shape) {
+ return bulletnew(btScaledBvhTriangleMeshShape(p_mesh_shape, p_local_scaling));
+ } else {
+ return NULL;
+ }
+}
+
+btHeightfieldTerrainShape *ShapeBullet::create_shape_height_field(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_cell_size) {
+ const btScalar ignoredHeightScale(1);
+ const btScalar fieldHeight(500); // Meters
+ const int YAxis = 1; // 0=X, 1=Y, 2=Z
+ const bool flipQuadEdges = false;
+ const void *heightsPtr = p_heights.read().ptr();
+
+ return bulletnew(btHeightfieldTerrainShape(p_width, p_depth, heightsPtr, ignoredHeightScale, -fieldHeight, fieldHeight, YAxis, PHY_FLOAT, flipQuadEdges));
+}
+
+btRayShape *ShapeBullet::create_shape_ray(real_t p_length) {
+ return bulletnew(btRayShape(p_length));
+}
+
+/* PLANE */
+
+PlaneShapeBullet::PlaneShapeBullet()
+ : ShapeBullet() {}
+
+void PlaneShapeBullet::set_data(const Variant &p_data) {
+ setup(p_data);
+}
+
+Variant PlaneShapeBullet::get_data() const {
+ return plane;
+}
+
+PhysicsServer::ShapeType PlaneShapeBullet::get_type() const {
+ return PhysicsServer::SHAPE_PLANE;
+}
+
+void PlaneShapeBullet::setup(const Plane &p_plane) {
+ plane = p_plane;
+ notifyShapeChanged();
+}
+
+btCollisionShape *PlaneShapeBullet::create_bt_shape() {
+ btVector3 btPlaneNormal;
+ G_TO_B(plane.normal, btPlaneNormal);
+ return prepare(PlaneShapeBullet::create_shape_plane(btPlaneNormal, plane.d));
+}
+
+/* Sphere */
+
+SphereShapeBullet::SphereShapeBullet()
+ : ShapeBullet() {}
+
+void SphereShapeBullet::set_data(const Variant &p_data) {
+ setup(p_data);
+}
+
+Variant SphereShapeBullet::get_data() const {
+ return radius;
+}
+
+PhysicsServer::ShapeType SphereShapeBullet::get_type() const {
+ return PhysicsServer::SHAPE_SPHERE;
+}
+
+void SphereShapeBullet::setup(real_t p_radius) {
+ radius = p_radius;
+ notifyShapeChanged();
+}
+
+btCollisionShape *SphereShapeBullet::create_bt_shape() {
+ return prepare(ShapeBullet::create_shape_sphere(radius));
+}
+
+/* Box */
+BoxShapeBullet::BoxShapeBullet()
+ : ShapeBullet() {}
+
+void BoxShapeBullet::set_data(const Variant &p_data) {
+ setup(p_data);
+}
+
+Variant BoxShapeBullet::get_data() const {
+ Vector3 g_half_extents;
+ B_TO_G(half_extents, g_half_extents);
+ return g_half_extents;
+}
+
+PhysicsServer::ShapeType BoxShapeBullet::get_type() const {
+ return PhysicsServer::SHAPE_BOX;
+}
+
+void BoxShapeBullet::setup(const Vector3 &p_half_extents) {
+ G_TO_B(p_half_extents, half_extents);
+ notifyShapeChanged();
+}
+
+btCollisionShape *BoxShapeBullet::create_bt_shape() {
+ return prepare(ShapeBullet::create_shape_box(half_extents));
+}
+
+/* Capsule */
+
+CapsuleShapeBullet::CapsuleShapeBullet()
+ : ShapeBullet() {}
+
+void CapsuleShapeBullet::set_data(const Variant &p_data) {
+ Dictionary d = p_data;
+ ERR_FAIL_COND(!d.has("radius"));
+ ERR_FAIL_COND(!d.has("height"));
+ setup(d["height"], d["radius"]);
+}
+
+Variant CapsuleShapeBullet::get_data() const {
+ Dictionary d;
+ d["radius"] = radius;
+ d["height"] = height;
+ return d;
+}
+
+PhysicsServer::ShapeType CapsuleShapeBullet::get_type() const {
+ return PhysicsServer::SHAPE_CAPSULE;
+}
+
+void CapsuleShapeBullet::setup(real_t p_height, real_t p_radius) {
+ radius = p_radius;
+ height = p_height;
+ notifyShapeChanged();
+}
+
+btCollisionShape *CapsuleShapeBullet::create_bt_shape() {
+ return prepare(ShapeBullet::create_shape_capsule(radius, height));
+}
+
+/* Convex polygon */
+
+ConvexPolygonShapeBullet::ConvexPolygonShapeBullet()
+ : ShapeBullet() {}
+
+void ConvexPolygonShapeBullet::set_data(const Variant &p_data) {
+ setup(p_data);
+}
+
+void ConvexPolygonShapeBullet::get_vertices(Vector<Vector3> &out_vertices) {
+ const int n_of_vertices = vertices.size();
+ out_vertices.resize(n_of_vertices);
+ for (int i = n_of_vertices - 1; 0 <= i; --i) {
+ B_TO_G(vertices[i], out_vertices[i]);
+ }
+}
+
+Variant ConvexPolygonShapeBullet::get_data() const {
+ ConvexPolygonShapeBullet *variable_self = const_cast<ConvexPolygonShapeBullet *>(this);
+ Vector<Vector3> out_vertices;
+ variable_self->get_vertices(out_vertices);
+ return out_vertices;
+}
+
+PhysicsServer::ShapeType ConvexPolygonShapeBullet::get_type() const {
+ return PhysicsServer::SHAPE_CONVEX_POLYGON;
+}
+
+void ConvexPolygonShapeBullet::setup(const Vector<Vector3> &p_vertices) {
+ // Make a copy of verticies
+ const int n_of_vertices = p_vertices.size();
+ vertices.resize(n_of_vertices);
+ for (int i = n_of_vertices - 1; 0 <= i; --i) {
+ G_TO_B(p_vertices[i], vertices[i]);
+ }
+ notifyShapeChanged();
+}
+
+btCollisionShape *ConvexPolygonShapeBullet::create_bt_shape() {
+ return prepare(ShapeBullet::create_shape_convex(vertices));
+}
+
+/* Concave polygon */
+
+ConcavePolygonShapeBullet::ConcavePolygonShapeBullet()
+ : ShapeBullet(), meshShape(NULL) {}
+
+ConcavePolygonShapeBullet::~ConcavePolygonShapeBullet() {
+ if (meshShape) {
+ delete meshShape->getMeshInterface();
+ delete meshShape;
+ }
+ faces = PoolVector<Vector3>();
+}
+
+void ConcavePolygonShapeBullet::set_data(const Variant &p_data) {
+ setup(p_data);
+}
+
+Variant ConcavePolygonShapeBullet::get_data() const {
+ return faces;
+}
+
+PhysicsServer::ShapeType ConcavePolygonShapeBullet::get_type() const {
+ return PhysicsServer::SHAPE_CONCAVE_POLYGON;
+}
+
+void ConcavePolygonShapeBullet::setup(PoolVector<Vector3> p_faces) {
+ faces = p_faces;
+ if (meshShape) {
+ /// Clear previous created shape
+ delete meshShape->getMeshInterface();
+ bulletdelete(meshShape);
+ }
+ int src_face_count = faces.size();
+ if (0 < src_face_count) {
+
+ btTriangleMesh *shapeInterface = bulletnew(btTriangleMesh);
+
+ // It counts the faces and assert the array contains the correct number of vertices.
+ ERR_FAIL_COND(src_face_count % 3);
+ src_face_count /= 3;
+ PoolVector<Vector3>::Read r = p_faces.read();
+ const Vector3 *facesr = r.ptr();
+
+ btVector3 supVec_0;
+ btVector3 supVec_1;
+ btVector3 supVec_2;
+ for (int i = 0; i < src_face_count; ++i) {
+ G_TO_B(facesr[i * 3], supVec_0);
+ G_TO_B(facesr[i * 3 + 1], supVec_1);
+ G_TO_B(facesr[i * 3 + 2], supVec_2);
+
+ shapeInterface->addTriangle(supVec_0, supVec_1, supVec_2);
+ }
+
+ const bool useQuantizedAabbCompression = true;
+
+ meshShape = bulletnew(btBvhTriangleMeshShape(shapeInterface, useQuantizedAabbCompression));
+ } else {
+ meshShape = NULL;
+ ERR_PRINT("The faces count are 0, the mesh shape cannot be created");
+ }
+ notifyShapeChanged();
+}
+
+btCollisionShape *ConcavePolygonShapeBullet::create_bt_shape() {
+ btCollisionShape *cs = ShapeBullet::create_shape_concave(meshShape);
+ if (!cs) {
+ // This is necessary since if 0 faces the creation of concave return NULL
+ cs = ShapeBullet::create_shape_empty();
+ }
+ return prepare(cs);
+}
+
+/* Height map shape */
+
+HeightMapShapeBullet::HeightMapShapeBullet()
+ : ShapeBullet() {}
+
+void HeightMapShapeBullet::set_data(const Variant &p_data) {
+ ERR_FAIL_COND(p_data.get_type() != Variant::DICTIONARY);
+ Dictionary d = p_data;
+ ERR_FAIL_COND(!d.has("width"));
+ ERR_FAIL_COND(!d.has("depth"));
+ ERR_FAIL_COND(!d.has("cell_size"));
+ ERR_FAIL_COND(!d.has("heights"));
+
+ int l_width = d["width"];
+ int l_depth = d["depth"];
+ real_t l_cell_size = d["cell_size"];
+ PoolVector<real_t> l_heights = d["heights"];
+
+ ERR_FAIL_COND(l_width <= 0);
+ ERR_FAIL_COND(l_depth <= 0);
+ ERR_FAIL_COND(l_cell_size <= CMP_EPSILON);
+ ERR_FAIL_COND(l_heights.size() != (width * depth));
+ setup(heights, width, depth, cell_size);
+}
+
+Variant HeightMapShapeBullet::get_data() const {
+ ERR_FAIL_V(Variant());
+}
+
+PhysicsServer::ShapeType HeightMapShapeBullet::get_type() const {
+ return PhysicsServer::SHAPE_HEIGHTMAP;
+}
+
+void HeightMapShapeBullet::setup(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_cell_size) {
+ { // Copy
+ const int heights_size = p_heights.size();
+ heights.resize(heights_size);
+ PoolVector<real_t>::Read p_heights_r = p_heights.read();
+ PoolVector<real_t>::Write heights_w = heights.write();
+ for (int i = heights_size - 1; 0 <= i; --i) {
+ heights_w[i] = p_heights_r[i];
+ }
+ }
+ width = p_width;
+ depth = p_depth;
+ cell_size = p_cell_size;
+ notifyShapeChanged();
+}
+
+btCollisionShape *HeightMapShapeBullet::create_bt_shape() {
+ return prepare(ShapeBullet::create_shape_height_field(heights, width, depth, cell_size));
+}
+
+/* Ray shape */
+RayShapeBullet::RayShapeBullet()
+ : ShapeBullet(), length(1) {}
+
+void RayShapeBullet::set_data(const Variant &p_data) {
+ setup(p_data);
+}
+
+Variant RayShapeBullet::get_data() const {
+ return length;
+}
+
+PhysicsServer::ShapeType RayShapeBullet::get_type() const {
+ return PhysicsServer::SHAPE_RAY;
+}
+
+void RayShapeBullet::setup(real_t p_length) {
+ length = p_length;
+ notifyShapeChanged();
+}
+
+btCollisionShape *RayShapeBullet::create_bt_shape() {
+ return prepare(ShapeBullet::create_shape_ray(length));
+}