diff options
author | AndreaCatania <info@andreacatania.com> | 2017-11-04 20:52:59 +0100 |
---|---|---|
committer | AndreaCatania <info@andreacatania.com> | 2017-11-04 20:52:59 +0100 |
commit | fb4871c919571d719d27738cc4d7db496a575b57 (patch) | |
tree | a92936591e93d6904dd5bd9b3dab9cd868e0480d | |
parent | ed047261f06f814eeb88a1f6ee2dd8abd7a14034 (diff) |
Bullet physics engine implementation
This is a bullet wrapper that allows Godot to use Bullet physics and benefit about all features.
Also it support all specific Godot physics functionality like multi shape body, areas, RayShape, etc..
It improve the Joints, Trimesh shape, and add support to soft body even if Godot is not yet ready to it.
51 files changed, 9847 insertions, 1 deletions
diff --git a/modules/bullet/SCsub b/modules/bullet/SCsub new file mode 100644 index 0000000000..7a37cca130 --- /dev/null +++ b/modules/bullet/SCsub @@ -0,0 +1,191 @@ +#!/usr/bin/env python + +Import('env') + +# build only version 2 +# Bullet 2.87 +bullet_src__2_x = [ + # BulletCollision + "BulletCollision/BroadphaseCollision/btAxisSweep3.cpp" + , "BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp" + , "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.cpp" + , "BulletCollision/BroadphaseCollision/btDbvt.cpp" + , "BulletCollision/BroadphaseCollision/btDbvtBroadphase.cpp" + , "BulletCollision/BroadphaseCollision/btDispatcher.cpp" + , "BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp" + , "BulletCollision/BroadphaseCollision/btQuantizedBvh.cpp" + , "BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp" + , "BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.cpp" + , "BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.cpp" + , "BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp" + , "BulletCollision/CollisionDispatch/btBoxBoxDetector.cpp" + , "BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp" + , "BulletCollision/CollisionDispatch/btCollisionDispatcherMt.cpp" + , "BulletCollision/CollisionDispatch/btCollisionObject.cpp" + , "BulletCollision/CollisionDispatch/btCollisionWorld.cpp" + , "BulletCollision/CollisionDispatch/btCollisionWorldImporter.cpp" + , "BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp" + , "BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp" + , "BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp" + , "BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp" + , "BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.cpp" + , "BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.cpp" + , "BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp" + , "BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.cpp" + , "BulletCollision/CollisionDispatch/btGhostObject.cpp" + , "BulletCollision/CollisionDispatch/btHashedSimplePairCache.cpp" + , "BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp" + , "BulletCollision/CollisionDispatch/btManifoldResult.cpp" + , "BulletCollision/CollisionDispatch/btSimulationIslandManager.cpp" + , "BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.cpp" + , "BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp" + , "BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp" + , "BulletCollision/CollisionDispatch/btUnionFind.cpp" + , "BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp" + , "BulletCollision/CollisionShapes/btBoxShape.cpp" + , "BulletCollision/CollisionShapes/btBox2dShape.cpp" + , "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp" + , "BulletCollision/CollisionShapes/btCapsuleShape.cpp" + , "BulletCollision/CollisionShapes/btCollisionShape.cpp" + , "BulletCollision/CollisionShapes/btCompoundShape.cpp" + , "BulletCollision/CollisionShapes/btConcaveShape.cpp" + , "BulletCollision/CollisionShapes/btConeShape.cpp" + , "BulletCollision/CollisionShapes/btConvexHullShape.cpp" + , "BulletCollision/CollisionShapes/btConvexInternalShape.cpp" + , "BulletCollision/CollisionShapes/btConvexPointCloudShape.cpp" + , "BulletCollision/CollisionShapes/btConvexPolyhedron.cpp" + , "BulletCollision/CollisionShapes/btConvexShape.cpp" + , "BulletCollision/CollisionShapes/btConvex2dShape.cpp" + , "BulletCollision/CollisionShapes/btConvexTriangleMeshShape.cpp" + , "BulletCollision/CollisionShapes/btCylinderShape.cpp" + , "BulletCollision/CollisionShapes/btEmptyShape.cpp" + , "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp" + , "BulletCollision/CollisionShapes/btMinkowskiSumShape.cpp" + , "BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.cpp" + , "BulletCollision/CollisionShapes/btMultiSphereShape.cpp" + , "BulletCollision/CollisionShapes/btOptimizedBvh.cpp" + , "BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp" + , "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.cpp" + , "BulletCollision/CollisionShapes/btShapeHull.cpp" + , "BulletCollision/CollisionShapes/btSphereShape.cpp" + , "BulletCollision/CollisionShapes/btStaticPlaneShape.cpp" + , "BulletCollision/CollisionShapes/btStridingMeshInterface.cpp" + , "BulletCollision/CollisionShapes/btTetrahedronShape.cpp" + , "BulletCollision/CollisionShapes/btTriangleBuffer.cpp" + , "BulletCollision/CollisionShapes/btTriangleCallback.cpp" + , "BulletCollision/CollisionShapes/btTriangleIndexVertexArray.cpp" + , "BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.cpp" + , "BulletCollision/CollisionShapes/btTriangleMesh.cpp" + , "BulletCollision/CollisionShapes/btTriangleMeshShape.cpp" + , "BulletCollision/CollisionShapes/btUniformScalingShape.cpp" + , "BulletCollision/Gimpact/btContactProcessing.cpp" + , "BulletCollision/Gimpact/btGenericPoolAllocator.cpp" + , "BulletCollision/Gimpact/btGImpactBvh.cpp" + , "BulletCollision/Gimpact/btGImpactCollisionAlgorithm.cpp" + , "BulletCollision/Gimpact/btGImpactQuantizedBvh.cpp" + , "BulletCollision/Gimpact/btGImpactShape.cpp" + , "BulletCollision/Gimpact/btTriangleShapeEx.cpp" + , "BulletCollision/Gimpact/gim_box_set.cpp" + , "BulletCollision/Gimpact/gim_contact.cpp" + , "BulletCollision/Gimpact/gim_memory.cpp" + , "BulletCollision/Gimpact/gim_tri_collision.cpp" + , "BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.cpp" + , "BulletCollision/NarrowPhaseCollision/btConvexCast.cpp" + , "BulletCollision/NarrowPhaseCollision/btGjkConvexCast.cpp" + , "BulletCollision/NarrowPhaseCollision/btGjkEpa2.cpp" + , "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp" + , "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp" + , "BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.cpp" + , "BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp" + , "BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp" + , "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp" + , "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp" + , "BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp" + + # BulletDynamics + , "BulletDynamics/Character/btKinematicCharacterController.cpp" + , "BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp" + , "BulletDynamics/ConstraintSolver/btContactConstraint.cpp" + , "BulletDynamics/ConstraintSolver/btFixedConstraint.cpp" + , "BulletDynamics/ConstraintSolver/btGearConstraint.cpp" + , "BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp" + , "BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.cpp" + , "BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp" + , "BulletDynamics/ConstraintSolver/btHinge2Constraint.cpp" + , "BulletDynamics/ConstraintSolver/btHingeConstraint.cpp" + , "BulletDynamics/ConstraintSolver/btPoint2PointConstraint.cpp" + , "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp" + , "BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.cpp" + , "BulletDynamics/ConstraintSolver/btSliderConstraint.cpp" + , "BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.cpp" + , "BulletDynamics/ConstraintSolver/btTypedConstraint.cpp" + , "BulletDynamics/ConstraintSolver/btUniversalConstraint.cpp" + , "BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp" + , "BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.cpp" + , "BulletDynamics/Dynamics/btSimulationIslandManagerMt.cpp" + , "BulletDynamics/Dynamics/btRigidBody.cpp" + , "BulletDynamics/Dynamics/btSimpleDynamicsWorld.cpp" + #, "BulletDynamics/Dynamics/Bullet-C-API.cpp" + , "BulletDynamics/Vehicle/btRaycastVehicle.cpp" + , "BulletDynamics/Vehicle/btWheelInfo.cpp" + , "BulletDynamics/Featherstone/btMultiBody.cpp" + , "BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp" + , "BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp" + , "BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp" + , "BulletDynamics/Featherstone/btMultiBodyConstraint.cpp" + , "BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp" + , "BulletDynamics/Featherstone/btMultiBodyFixedConstraint.cpp" + , "BulletDynamics/Featherstone/btMultiBodySliderConstraint.cpp" + , "BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp" + , "BulletDynamics/Featherstone/btMultiBodyGearConstraint.cpp" + , "BulletDynamics/MLCPSolvers/btDantzigLCP.cpp" + , "BulletDynamics/MLCPSolvers/btMLCPSolver.cpp" + , "BulletDynamics/MLCPSolvers/btLemkeAlgorithm.cpp" + + # BulletInverseDynamics + , "BulletInverseDynamics/IDMath.cpp" + , "BulletInverseDynamics/MultiBodyTree.cpp" + , "BulletInverseDynamics/details/MultiBodyTreeInitCache.cpp" + , "BulletInverseDynamics/details/MultiBodyTreeImpl.cpp" + + # BulletSoftBody + , "BulletSoftBody/btSoftBody.cpp" + , "BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.cpp" + , "BulletSoftBody/btSoftBodyHelpers.cpp" + , "BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.cpp" + , "BulletSoftBody/btSoftRigidCollisionAlgorithm.cpp" + , "BulletSoftBody/btSoftRigidDynamicsWorld.cpp" + , "BulletSoftBody/btSoftMultiBodyDynamicsWorld.cpp" + , "BulletSoftBody/btSoftSoftCollisionAlgorithm.cpp" + , "BulletSoftBody/btDefaultSoftBodySolver.cpp" + + # clew + , "clew/clew.c" + + # LinearMath + , "LinearMath/btAlignedAllocator.cpp" + , "LinearMath/btConvexHull.cpp" + , "LinearMath/btConvexHullComputer.cpp" + , "LinearMath/btGeometryUtil.cpp" + , "LinearMath/btPolarDecomposition.cpp" + , "LinearMath/btQuickprof.cpp" + , "LinearMath/btSerializer.cpp" + , "LinearMath/btSerializer64.cpp" + , "LinearMath/btThreads.cpp" + , "LinearMath/btVector3.cpp" + ] + +thirdparty_dir = "#thirdparty/bullet/" +thirdparty_src = thirdparty_dir + "src/" + +bullet_sources = [thirdparty_src + file for file in bullet_src__2_x] + +# include headers +env.Append(CPPPATH=[thirdparty_src]) + +env.add_source_files(env.modules_sources, bullet_sources) + +# Godot source files +env.add_source_files(env.modules_sources, "*.cpp") + +Export('env') diff --git a/modules/bullet/SCsub_with_lib b/modules/bullet/SCsub_with_lib new file mode 100644 index 0000000000..b362a686ff --- /dev/null +++ b/modules/bullet/SCsub_with_lib @@ -0,0 +1,33 @@ +#!/usr/bin/env python + +Import('env') + +thirdparty_dir = "#thirdparty/bullet/" +thirdparty_lib = thirdparty_dir + "Win64/lib/" + +bullet_libs = [ + "Bullet2FileLoader", + "Bullet3Collision", + "Bullet3Common", + "Bullet3Dynamics", + "Bullet3Geometry", + "Bullet3OpenCL_clew", + "BulletCollision", + "BulletDynamics", + "BulletInverseDynamics", + "BulletSoftBody", + "LinearMath" + ] + +thirdparty_src = thirdparty_dir + "src/" +# include headers +env.Append(CPPPATH=[thirdparty_src]) + +# lib +env.Append(LIBPATH=[thirdparty_dir + "/Win64/lib/"]) + +bullet_libs = [file+'.lib' for file in bullet_libs] +# LIBS doesn't work in windows +env.Append(LINKFLAGS=bullet_libs) + +env.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/bullet/area_bullet.cpp b/modules/bullet/area_bullet.cpp new file mode 100644 index 0000000000..54024b4f90 --- /dev/null +++ b/modules/bullet/area_bullet.cpp @@ -0,0 +1,284 @@ +/*************************************************************************/ +/* area_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 "area_bullet.h" +#include "BulletCollision/CollisionDispatch/btGhostObject.h" +#include "btBulletCollisionCommon.h" +#include "bullet_types_converter.h" +#include "bullet_utilities.h" +#include "collision_object_bullet.h" +#include "space_bullet.h" + +AreaBullet::AreaBullet() + : RigidCollisionObjectBullet(CollisionObjectBullet::TYPE_AREA), + monitorable(true), + isScratched(false), + spOv_mode(PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED), + spOv_gravityPoint(false), + spOv_gravityPointDistanceScale(0), + spOv_gravityPointAttenuation(1), + spOv_gravityVec(0, -1, 0), + spOv_gravityMag(10), + spOv_linearDump(0.1), + spOv_angularDump(1), + spOv_priority(0) { + + btGhost = bulletnew(btGhostObject); + btGhost->setCollisionShape(compoundShape); + setupBulletCollisionObject(btGhost); + /// Collision objects with a callback still have collision response with dynamic rigid bodies. + /// In order to use collision objects as trigger, you have to disable the collision response. + set_collision_enabled(false); + + for (int i = 0; i < 5; ++i) + call_event_res_ptr[i] = &call_event_res[i]; +} + +AreaBullet::~AreaBullet() { + remove_all_overlapping_instantly(); +} + +void AreaBullet::dispatch_callbacks() { + if (!isScratched) + return; + isScratched = false; + + // Reverse order because I've to remove EXIT objects + for (int i = overlappingObjects.size() - 1; 0 <= i; --i) { + OverlappingObjectData &otherObj = overlappingObjects[i]; + + switch (otherObj.state) { + case OVERLAP_STATE_ENTER: + otherObj.state = OVERLAP_STATE_INSIDE; + call_event(otherObj.object, PhysicsServer::AREA_BODY_ADDED); + otherObj.object->on_enter_area(this); + break; + case OVERLAP_STATE_EXIT: + call_event(otherObj.object, PhysicsServer::AREA_BODY_REMOVED); + otherObj.object->on_exit_area(this); + overlappingObjects.remove(i); // Remove after callback + break; + } + } +} + +void AreaBullet::call_event(CollisionObjectBullet *p_otherObject, PhysicsServer::AreaBodyStatus p_status) { + + InOutEventCallback &event = eventsCallbacks[static_cast<int>(p_otherObject->getType())]; + Object *areaGodoObject = ObjectDB::get_instance(event.event_callback_id); + + if (!areaGodoObject) { + event.event_callback_id = 0; + return; + } + + call_event_res[0] = p_status; + call_event_res[1] = p_otherObject->get_self(); // Other body + call_event_res[2] = p_otherObject->get_instance_id(); // instance ID + call_event_res[3] = 0; // other_body_shape ID + call_event_res[4] = 0; // self_shape ID + + Variant::CallError outResp; + areaGodoObject->call(event.event_callback_method, (const Variant **)call_event_res_ptr, 5, outResp); +} + +void AreaBullet::scratch() { + if (isScratched) + return; + isScratched = true; +} + +void AreaBullet::remove_all_overlapping_instantly() { + CollisionObjectBullet *supportObject; + for (int i = overlappingObjects.size() - 1; 0 <= i; --i) { + supportObject = overlappingObjects[i].object; + call_event(supportObject, PhysicsServer::AREA_BODY_REMOVED); + supportObject->on_exit_area(this); + } + overlappingObjects.clear(); +} + +void AreaBullet::remove_overlapping_instantly(CollisionObjectBullet *p_object) { + CollisionObjectBullet *supportObject; + for (int i = overlappingObjects.size() - 1; 0 <= i; --i) { + supportObject = overlappingObjects[i].object; + if (supportObject == p_object) { + call_event(supportObject, PhysicsServer::AREA_BODY_REMOVED); + supportObject->on_exit_area(this); + overlappingObjects.remove(i); + break; + } + } +} + +int AreaBullet::find_overlapping_object(CollisionObjectBullet *p_colObj) { + const int size = overlappingObjects.size(); + for (int i = 0; i < size; ++i) { + if (overlappingObjects[i].object == p_colObj) { + return i; + } + } + return -1; +} + +void AreaBullet::set_monitorable(bool p_monitorable) { + monitorable = p_monitorable; +} + +bool AreaBullet::is_monitoring() const { + return get_godot_object_flags() & GOF_IS_MONITORING_AREA; +} + +void AreaBullet::reload_body() { + if (space) { + space->remove_area(this); + space->add_area(this); + } +} + +void AreaBullet::set_space(SpaceBullet *p_space) { + // Clear the old space if there is one + if (space) { + isScratched = false; + + // Remove this object form the physics world + space->remove_area(this); + } + + space = p_space; + + if (space) { + space->add_area(this); + } +} + +void AreaBullet::on_collision_filters_change() { + if (space) { + space->reload_collision_filters(this); + } +} + +void AreaBullet::add_overlap(CollisionObjectBullet *p_otherObject) { + scratch(); + overlappingObjects.push_back(OverlappingObjectData(p_otherObject, OVERLAP_STATE_ENTER)); + p_otherObject->notify_new_overlap(this); +} + +void AreaBullet::put_overlap_as_exit(int p_index) { + scratch(); + overlappingObjects[p_index].state = OVERLAP_STATE_EXIT; +} + +void AreaBullet::put_overlap_as_inside(int p_index) { + // This check is required to be sure this body was inside + if (OVERLAP_STATE_DIRTY == overlappingObjects[p_index].state) { + overlappingObjects[p_index].state = OVERLAP_STATE_INSIDE; + } +} + +void AreaBullet::set_param(PhysicsServer::AreaParameter p_param, const Variant &p_value) { + switch (p_param) { + case PhysicsServer::AREA_PARAM_GRAVITY: + set_spOv_gravityMag(p_value); + break; + case PhysicsServer::AREA_PARAM_GRAVITY_VECTOR: + set_spOv_gravityVec(p_value); + break; + case PhysicsServer::AREA_PARAM_LINEAR_DAMP: + set_spOv_linearDump(p_value); + break; + case PhysicsServer::AREA_PARAM_ANGULAR_DAMP: + set_spOv_angularDump(p_value); + break; + case PhysicsServer::AREA_PARAM_PRIORITY: + set_spOv_priority(p_value); + break; + case PhysicsServer::AREA_PARAM_GRAVITY_IS_POINT: + set_spOv_gravityPoint(p_value); + break; + case PhysicsServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE: + set_spOv_gravityPointDistanceScale(p_value); + break; + case PhysicsServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION: + set_spOv_gravityPointAttenuation(p_value); + break; + default: + print_line("The Bullet areas dosn't suppot this param: " + itos(p_param)); + } +} + +Variant AreaBullet::get_param(PhysicsServer::AreaParameter p_param) const { + switch (p_param) { + case PhysicsServer::AREA_PARAM_GRAVITY: + return spOv_gravityMag; + case PhysicsServer::AREA_PARAM_GRAVITY_VECTOR: + return spOv_gravityVec; + case PhysicsServer::AREA_PARAM_LINEAR_DAMP: + return spOv_linearDump; + case PhysicsServer::AREA_PARAM_ANGULAR_DAMP: + return spOv_angularDump; + case PhysicsServer::AREA_PARAM_PRIORITY: + return spOv_priority; + case PhysicsServer::AREA_PARAM_GRAVITY_IS_POINT: + return spOv_gravityPoint; + case PhysicsServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE: + return spOv_gravityPointDistanceScale; + case PhysicsServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION: + return spOv_gravityPointAttenuation; + default: + print_line("The Bullet areas dosn't suppot this param: " + itos(p_param)); + return Variant(); + } +} + +void AreaBullet::set_event_callback(Type p_callbackObjectType, ObjectID p_id, const StringName &p_method) { + InOutEventCallback &ev = eventsCallbacks[static_cast<int>(p_callbackObjectType)]; + ev.event_callback_id = p_id; + ev.event_callback_method = p_method; + + /// Set if monitoring + if (eventsCallbacks[0].event_callback_id || eventsCallbacks[1].event_callback_id) { + set_godot_object_flags(get_godot_object_flags() | GOF_IS_MONITORING_AREA); + } else { + set_godot_object_flags(get_godot_object_flags() & (~GOF_IS_MONITORING_AREA)); + } +} + +bool AreaBullet::has_event_callback(Type p_callbackObjectType) { + return eventsCallbacks[static_cast<int>(p_callbackObjectType)].event_callback_id; +} + +void AreaBullet::on_enter_area(AreaBullet *p_area) { +} + +void AreaBullet::on_exit_area(AreaBullet *p_area) { + CollisionObjectBullet::on_exit_area(p_area); +} diff --git a/modules/bullet/area_bullet.h b/modules/bullet/area_bullet.h new file mode 100644 index 0000000000..f6e3b7e902 --- /dev/null +++ b/modules/bullet/area_bullet.h @@ -0,0 +1,169 @@ +/*************************************************************************/ +/* area_bullet.h */ +/* 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. */ +/*************************************************************************/ + +#ifndef AREABULLET_H +#define AREABULLET_H + +#include "collision_object_bullet.h" +#include "core/vector.h" +#include "servers/physics_server.h" +#include "space_bullet.h" + +class btGhostObject; + +class AreaBullet : public RigidCollisionObjectBullet { + friend void SpaceBullet::check_ghost_overlaps(); + +public: + struct InOutEventCallback { + ObjectID event_callback_id; + StringName event_callback_method; + + InOutEventCallback() + : event_callback_id(0) {} + }; + + enum OverlapState { + OVERLAP_STATE_DIRTY = 0, // Mark processed overlaps + OVERLAP_STATE_INSIDE, // Mark old overlap + OVERLAP_STATE_ENTER, // Mark just enter overlap + OVERLAP_STATE_EXIT // Mark ended overlaps + }; + + struct OverlappingObjectData { + CollisionObjectBullet *object; + OverlapState state; + + OverlappingObjectData() + : object(NULL), state(OVERLAP_STATE_ENTER) {} + OverlappingObjectData(CollisionObjectBullet *p_object, OverlapState p_state) + : object(p_object), state(p_state) {} + OverlappingObjectData(const OverlappingObjectData &other) { + operator=(other); + } + void operator=(const OverlappingObjectData &other) { + object = other.object; + state = other.state; + } + }; + +private: + // These are used by function callEvent. Instead to create this each call I create if one time. + Variant call_event_res[5]; + Variant *call_event_res_ptr[5]; + + btGhostObject *btGhost; + Vector<OverlappingObjectData> overlappingObjects; + bool monitorable; + + PhysicsServer::AreaSpaceOverrideMode spOv_mode; + bool spOv_gravityPoint; + real_t spOv_gravityPointDistanceScale; + real_t spOv_gravityPointAttenuation; + Vector3 spOv_gravityVec; + real_t spOv_gravityMag; + real_t spOv_linearDump; + real_t spOv_angularDump; + int spOv_priority; + + bool isScratched; + + InOutEventCallback eventsCallbacks[2]; + +public: + AreaBullet(); + ~AreaBullet(); + + _FORCE_INLINE_ btGhostObject *get_bt_ghost() const { return btGhost; } + int find_overlapping_object(CollisionObjectBullet *p_colObj); + + void set_monitorable(bool p_monitorable); + _FORCE_INLINE_ bool is_monitorable() const { return monitorable; } + + bool is_monitoring() const; + + _FORCE_INLINE_ void set_spOv_mode(PhysicsServer::AreaSpaceOverrideMode p_mode) { spOv_mode = p_mode; } + _FORCE_INLINE_ PhysicsServer::AreaSpaceOverrideMode get_spOv_mode() { return spOv_mode; } + + _FORCE_INLINE_ void set_spOv_gravityPoint(bool p_isGP) { spOv_gravityPoint = p_isGP; } + _FORCE_INLINE_ bool is_spOv_gravityPoint() { return spOv_gravityPoint; } + + _FORCE_INLINE_ void set_spOv_gravityPointDistanceScale(real_t p_GPDS) { spOv_gravityPointDistanceScale = p_GPDS; } + _FORCE_INLINE_ real_t get_spOv_gravityPointDistanceScale() { return spOv_gravityPointDistanceScale; } + + _FORCE_INLINE_ void set_spOv_gravityPointAttenuation(real_t p_GPA) { spOv_gravityPointAttenuation = p_GPA; } + _FORCE_INLINE_ real_t get_spOv_gravityPointAttenuation() { return spOv_gravityPointAttenuation; } + + _FORCE_INLINE_ void set_spOv_gravityVec(Vector3 p_vec) { spOv_gravityVec = p_vec; } + _FORCE_INLINE_ const Vector3 &get_spOv_gravityVec() const { return spOv_gravityVec; } + + _FORCE_INLINE_ void set_spOv_gravityMag(real_t p_gravityMag) { spOv_gravityMag = p_gravityMag; } + _FORCE_INLINE_ real_t get_spOv_gravityMag() { return spOv_gravityMag; } + + _FORCE_INLINE_ void set_spOv_linearDump(real_t p_linearDump) { spOv_linearDump = p_linearDump; } + _FORCE_INLINE_ real_t get_spOv_linearDamp() { return spOv_linearDump; } + + _FORCE_INLINE_ void set_spOv_angularDump(real_t p_angularDump) { spOv_angularDump = p_angularDump; } + _FORCE_INLINE_ real_t get_spOv_angularDamp() { return spOv_angularDump; } + + _FORCE_INLINE_ void set_spOv_priority(int p_priority) { spOv_priority = p_priority; } + _FORCE_INLINE_ int get_spOv_priority() { return spOv_priority; } + + virtual void reload_body(); + virtual void set_space(SpaceBullet *p_space); + + virtual void dispatch_callbacks(); + void call_event(CollisionObjectBullet *p_otherObject, PhysicsServer::AreaBodyStatus p_status); + void set_on_state_change(ObjectID p_id, const StringName &p_method, const Variant &p_udata = Variant()); + void scratch(); + + void remove_all_overlapping_instantly(); + // Dispatch the callbacks and removes from overlapping list + void remove_overlapping_instantly(CollisionObjectBullet *p_object); + + virtual void on_collision_filters_change(); + virtual void on_collision_checker_start() {} + + void add_overlap(CollisionObjectBullet *p_otherObject); + void put_overlap_as_exit(int p_index); + void put_overlap_as_inside(int p_index); + + void set_param(PhysicsServer::AreaParameter p_param, const Variant &p_value); + Variant get_param(PhysicsServer::AreaParameter p_param) const; + + void set_event_callback(Type p_callbackObjectType, ObjectID p_id, const StringName &p_method); + bool has_event_callback(Type p_callbackObjectType); + + virtual void on_enter_area(AreaBullet *p_area); + virtual void on_exit_area(AreaBullet *p_area); +}; + +#endif diff --git a/modules/bullet/btRayShape.cpp b/modules/bullet/btRayShape.cpp new file mode 100644 index 0000000000..ac95faaac6 --- /dev/null +++ b/modules/bullet/btRayShape.cpp @@ -0,0 +1,94 @@ +/*************************************************************************/ +/* btRayShape.h */ +/* 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 "btRayShape.h" +#include "LinearMath/btAabbUtil2.h" +#include "math/math_funcs.h" + +btRayShape::btRayShape(btScalar length) + : btConvexInternalShape(), + m_shapeAxis(0, 0, 1) { + m_shapeType = CUSTOM_CONVEX_SHAPE_TYPE; + setLength(length); +} + +btRayShape::~btRayShape() { +} + +void btRayShape::setLength(btScalar p_length) { + + m_length = p_length; + reload_cache(); +} + +btVector3 btRayShape::localGetSupportingVertex(const btVector3 &vec) const { + return localGetSupportingVertexWithoutMargin(vec) + (m_shapeAxis * m_collisionMargin); +} + +btVector3 btRayShape::localGetSupportingVertexWithoutMargin(const btVector3 &vec) const { + if (vec.z() > 0) + return m_shapeAxis * m_cacheScaledLength; + else + return btVector3(0, 0, 0); +} + +void btRayShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3 *vectors, btVector3 *supportVerticesOut, int numVectors) const { + for (int i = 0; i < numVectors; ++i) { + supportVerticesOut[i] = localGetSupportingVertexWithoutMargin(vectors[i]); + } +} + +void btRayShape::getAabb(const btTransform &t, btVector3 &aabbMin, btVector3 &aabbMax) const { +#define MARGIN_BROADPHASE 0.1 + btVector3 localAabbMin(0, 0, 0); + btVector3 localAabbMax(m_shapeAxis * m_length); + btTransformAabb(localAabbMin, localAabbMax, MARGIN_BROADPHASE, t, aabbMin, aabbMax); +} + +void btRayShape::calculateLocalInertia(btScalar mass, btVector3 &inertia) const { + inertia.setZero(); +} + +int btRayShape::getNumPreferredPenetrationDirections() const { + return 0; +} + +void btRayShape::getPreferredPenetrationDirection(int index, btVector3 &penetrationVector) const { + penetrationVector.setZero(); +} + +void btRayShape::reload_cache() { + + m_cacheScaledLength = m_length * m_localScaling[2] + m_collisionMargin; + + m_cacheSupportPoint.setIdentity(); + m_cacheSupportPoint.setOrigin(m_shapeAxis * m_cacheScaledLength); +} diff --git a/modules/bullet/btRayShape.h b/modules/bullet/btRayShape.h new file mode 100644 index 0000000000..1b63fb477c --- /dev/null +++ b/modules/bullet/btRayShape.h @@ -0,0 +1,87 @@ +/*************************************************************************/ +/* btRayShape.h */ +/* 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. */ +/*************************************************************************/ + +/// IMPORTANT The class name and filename was created by following Bullet writing rules for an easy (eventually ) porting to bullet +/// This shape is a custom shape that is not present to Bullet physics engine +#ifndef BTRAYSHAPE_H +#define BTRAYSHAPE_H + +#include "BulletCollision/CollisionShapes/btConvexInternalShape.h" + +/// Ray shape around z axis +ATTRIBUTE_ALIGNED16(class) +btRayShape : public btConvexInternalShape { + + btScalar m_length; + /// The default axis is the z + btVector3 m_shapeAxis; + + btTransform m_cacheSupportPoint; + btScalar m_cacheScaledLength; + +public: + BT_DECLARE_ALIGNED_ALLOCATOR(); + + btRayShape(btScalar length); + virtual ~btRayShape(); + + void setLength(btScalar p_length); + btScalar getLength() const { return m_length; } + + const btTransform &getSupportPoint() const { return m_cacheSupportPoint; } + const btScalar &getScaledLength() const { return m_cacheScaledLength; } + + virtual btVector3 localGetSupportingVertex(const btVector3 &vec) const; +#ifndef __SPU__ + virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3 &vec) const; +#endif //#ifndef __SPU__ + + virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3 *vectors, btVector3 *supportVerticesOut, int numVectors) const; + + ///getAabb returns the axis aligned bounding box in the coordinate frame of the given transform t. + virtual void getAabb(const btTransform &t, btVector3 &aabbMin, btVector3 &aabbMax) const; + +#ifndef __SPU__ + virtual void calculateLocalInertia(btScalar mass, btVector3 & inertia) const; + + virtual const char *getName() const { + return "RayZ"; + } +#endif //__SPU__ + + virtual int getNumPreferredPenetrationDirections() const; + virtual void getPreferredPenetrationDirection(int index, btVector3 &penetrationVector) const; + +private: + void reload_cache(); +}; + +#endif // BTRAYSHAPE_H diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp new file mode 100644 index 0000000000..2656074296 --- /dev/null +++ b/modules/bullet/bullet_physics_server.cpp @@ -0,0 +1,1339 @@ +/*************************************************************************/ +/* bullet_physics_server.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 "bullet_physics_server.h" +#include "LinearMath/btVector3.h" +#include "bullet_utilities.h" +#include "class_db.h" +#include "cone_twist_joint_bullet.h" +#include "core/error_macros.h" +#include "core/ustring.h" +#include "generic_6dof_joint_bullet.h" +#include "hinge_joint_bullet.h" +#include "pin_joint_bullet.h" +#include "shape_bullet.h" +#include "slider_joint_bullet.h" +#include <assert.h> + +#define CreateThenReturnRID(owner, ridData) \ + RID rid = owner.make_rid(ridData); \ + ridData->set_self(rid); \ + ridData->_set_physics_server(this); \ + return rid; + +// <--------------- Joint creation asserts +/// Assert the body is assigned to a space +#define JointAssertSpace(body, bIndex, ret) \ + if (!body->get_space()) { \ + ERR_PRINTS("Before create a joint the Body" + String(bIndex) + " must be added to a space!"); \ + return ret; \ + } + +/// Assert the two bodies of joint are in the same space +#define JointAssertSameSpace(bodyA, bodyB, ret) \ + if (bodyA->get_space() != bodyB->get_space()) { \ + ERR_PRINT("In order to create a joint the Body_A and Body_B must be in the same space!"); \ + return RID(); \ + } + +#define AddJointToSpace(body, joint, disableCollisionsBetweenLinkedBodies) \ + body->get_space()->add_constraint(joint, disableCollisionsBetweenLinkedBodies); +// <--------------- Joint creation asserts + +btEmptyShape *BulletPhysicsServer::emptyShape(ShapeBullet::create_shape_empty()); + +btEmptyShape *BulletPhysicsServer::get_empty_shape() { + return emptyShape; +} + +void BulletPhysicsServer::_bind_methods() { + //ClassDB::bind_method(D_METHOD("DoTest"), &BulletPhysicsServer::DoTest); +} + +BulletPhysicsServer::BulletPhysicsServer() + : PhysicsServer(), + active(true), + activeSpace(NULL) {} + +BulletPhysicsServer::~BulletPhysicsServer() {} + +RID BulletPhysicsServer::shape_create(ShapeType p_shape) { + ShapeBullet *shape = NULL; + + switch (p_shape) { + case SHAPE_PLANE: { + + shape = bulletnew(PlaneShapeBullet); + } break; + case SHAPE_SPHERE: { + + shape = bulletnew(SphereShapeBullet); + } break; + case SHAPE_BOX: { + + shape = bulletnew(BoxShapeBullet); + } break; + case SHAPE_CAPSULE: { + + shape = bulletnew(CapsuleShapeBullet); + } break; + case SHAPE_CONVEX_POLYGON: { + + shape = bulletnew(ConvexPolygonShapeBullet); + } break; + case SHAPE_CONCAVE_POLYGON: { + + shape = bulletnew(ConcavePolygonShapeBullet); + } break; + case SHAPE_HEIGHTMAP: { + + shape = bulletnew(HeightMapShapeBullet); + } break; + case SHAPE_RAY: { + shape = bulletnew(RayShapeBullet); + } break; + case SHAPE_CUSTOM: + defaul: + ERR_FAIL_V(RID()); + break; + } + + CreateThenReturnRID(shape_owner, shape) +} + +void BulletPhysicsServer::shape_set_data(RID p_shape, const Variant &p_data) { + ShapeBullet *shape = shape_owner.get(p_shape); + ERR_FAIL_COND(!shape); + shape->set_data(p_data); +} + +void BulletPhysicsServer::shape_set_custom_solver_bias(RID p_shape, real_t p_bias) { + //WARN_PRINT("Bias not supported by Bullet physics engine"); +} + +PhysicsServer::ShapeType BulletPhysicsServer::shape_get_type(RID p_shape) const { + ShapeBullet *shape = shape_owner.get(p_shape); + ERR_FAIL_COND_V(!shape, PhysicsServer::SHAPE_CUSTOM); + return shape->get_type(); +} + +Variant BulletPhysicsServer::shape_get_data(RID p_shape) const { + ShapeBullet *shape = shape_owner.get(p_shape); + ERR_FAIL_COND_V(!shape, Variant()); + return shape->get_data(); +} + +real_t BulletPhysicsServer::shape_get_custom_solver_bias(RID p_shape) const { + //WARN_PRINT("Bias not supported by Bullet physics engine"); + return 0.; +} + +RID BulletPhysicsServer::space_create() { + SpaceBullet *space = bulletnew(SpaceBullet(false)); + CreateThenReturnRID(space_owner, space); +} + +void BulletPhysicsServer::space_set_active(RID p_space, bool p_active) { + if (p_active) { + if (activeSpace) { + // There is another space and this cannot be activated + ERR_PRINT("There is another space, before activate new one deactivate the current space."); + } else { + SpaceBullet *space = space_owner.get(p_space); + if (space) { + activeSpace = space; + } else { + ERR_PRINT("The passed RID is not a valid space. Please provide a RID with SpaceBullet type."); + } + } + } else { + if (!space_is_active(p_space)) { + activeSpace = NULL; + } + } +} + +bool BulletPhysicsServer::space_is_active(RID p_space) const { + return NULL != activeSpace && activeSpace == p_space.get_data(); +} + +void BulletPhysicsServer::space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) { + SpaceBullet *space = space_owner.get(p_space); + ERR_FAIL_COND(!space); + space->set_param(p_param, p_value); +} + +real_t BulletPhysicsServer::space_get_param(RID p_space, SpaceParameter p_param) const { + SpaceBullet *space = space_owner.get(p_space); + ERR_FAIL_COND_V(!space, 0); + return space->get_param(p_param); +} + +PhysicsDirectSpaceState *BulletPhysicsServer::space_get_direct_state(RID p_space) { + SpaceBullet *space = space_owner.get(p_space); + ERR_FAIL_COND_V(!space, NULL); + + return space->get_direct_state(); +} + +void BulletPhysicsServer::space_set_debug_contacts(RID p_space, int p_max_contacts) { + SpaceBullet *space = space_owner.get(p_space); + ERR_FAIL_COND(!space); + + space->set_debug_contacts(p_max_contacts); +} + +Vector<Vector3> BulletPhysicsServer::space_get_contacts(RID p_space) const { + SpaceBullet *space = space_owner.get(p_space); + ERR_FAIL_COND_V(!space, Vector<Vector3>()); + + return space->get_debug_contacts(); +} + +int BulletPhysicsServer::space_get_contact_count(RID p_space) const { + SpaceBullet *space = space_owner.get(p_space); + ERR_FAIL_COND_V(!space, 0); + + return space->get_debug_contact_count(); +} + +RID BulletPhysicsServer::area_create() { + AreaBullet *area = bulletnew(AreaBullet); + area->set_collision_layer(1); + area->set_collision_mask(1); + CreateThenReturnRID(area_owner, area) +} + +void BulletPhysicsServer::area_set_space(RID p_area, RID p_space) { + AreaBullet *area = area_owner.get(p_area); + ERR_FAIL_COND(!area); + SpaceBullet *space = NULL; + if (p_space.is_valid()) { + space = space_owner.get(p_space); + ERR_FAIL_COND(!space); + } + area->set_space(space); +} + +RID BulletPhysicsServer::area_get_space(RID p_area) const { + AreaBullet *area = area_owner.get(p_area); + return area->get_space()->get_self(); +} + +void BulletPhysicsServer::area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) { + AreaBullet *area = area_owner.get(p_area); + ERR_FAIL_COND(!area) + + area->set_spOv_mode(p_mode); +} + +PhysicsServer::AreaSpaceOverrideMode BulletPhysicsServer::area_get_space_override_mode(RID p_area) const { + AreaBullet *area = area_owner.get(p_area); + ERR_FAIL_COND_V(!area, PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED); + + return area->get_spOv_mode(); +} + +void BulletPhysicsServer::area_add_shape(RID p_area, RID p_shape, const Transform &p_transform) { + AreaBullet *area = area_owner.get(p_area); + ERR_FAIL_COND(!area); + + ShapeBullet *shape = shape_owner.get(p_shape); + ERR_FAIL_COND(!shape); + + area->add_shape(shape, p_transform); +} + +void BulletPhysicsServer::area_set_shape(RID p_area, int p_shape_idx, RID p_shape) { + AreaBullet *area = area_owner.get(p_area); + ERR_FAIL_COND(!area); + + ShapeBullet *shape = shape_owner.get(p_shape); + ERR_FAIL_COND(!shape); + + area->set_shape(p_shape_idx, shape); +} + +void BulletPhysicsServer::area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform) { + AreaBullet *area = area_owner.get(p_area); + ERR_FAIL_COND(!area); + + area->set_shape_transform(p_shape_idx, p_transform); +} + +int BulletPhysicsServer::area_get_shape_count(RID p_area) const { + AreaBullet *area = area_owner.get(p_area); + ERR_FAIL_COND_V(!area, 0); + + return area->get_shape_count(); +} + +RID BulletPhysicsServer::area_get_shape(RID p_area, int p_shape_idx) const { + AreaBullet *area = area_owner.get(p_area); + ERR_FAIL_COND_V(!area, RID()); + + return area->get_shape(p_shape_idx)->get_self(); +} + +Transform BulletPhysicsServer::area_get_shape_transform(RID p_area, int p_shape_idx) const { + AreaBullet *area = area_owner.get(p_area); + ERR_FAIL_COND_V(!area, Transform()); + + return area->get_shape_transform(p_shape_idx); +} + +void BulletPhysicsServer::area_remove_shape(RID p_area, int p_shape_idx) { + AreaBullet *area = area_owner.get(p_area); + ERR_FAIL_COND(!area); + return area->remove_shape(p_shape_idx); +} + +void BulletPhysicsServer::area_clear_shapes(RID p_area) { + AreaBullet *area = area_owner.get(p_area); + ERR_FAIL_COND(!area); + + for (int i = area->get_shape_count(); 0 < i; --i) + area->remove_shape(0); +} + +void BulletPhysicsServer::area_set_shape_disabled(RID p_area, int p_shape_idx, bool p_disabled) { + AreaBullet *area = area_owner.get(p_area); + ERR_FAIL_COND(!area); + + area->set_shape_disabled(p_shape_idx, p_disabled); +} + +void BulletPhysicsServer::area_attach_object_instance_id(RID p_area, ObjectID p_ID) { + if (space_owner.owns(p_area)) { + return; + } + AreaBullet *area = area_owner.get(p_area); + ERR_FAIL_COND(!area); + area->set_instance_id(p_ID); +} + +ObjectID BulletPhysicsServer::area_get_object_instance_id(RID p_area) const { + if (space_owner.owns(p_area)) { + return 0; + } + AreaBullet *area = area_owner.get(p_area); + ERR_FAIL_COND_V(!area, ObjectID()); + return area->get_instance_id(); +} + +void BulletPhysicsServer::area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) { + if (space_owner.owns(p_area)) { + SpaceBullet *space = space_owner.get(p_area); + if (space) { + space->set_param(p_param, p_value); + } + } else { + + AreaBullet *area = area_owner.get(p_area); + ERR_FAIL_COND(!area); + + area->set_param(p_param, p_value); + } +} + +Variant BulletPhysicsServer::area_get_param(RID p_area, AreaParameter p_param) const { + if (space_owner.owns(p_area)) { + SpaceBullet *space = space_owner.get(p_area); + return space->get_param(p_param); + } else { + AreaBullet *area = area_owner.get(p_area); + ERR_FAIL_COND_V(!area, Variant()); + + return area->get_param(p_param); + } +} + +void BulletPhysicsServer::area_set_transform(RID p_area, const Transform &p_transform) { + AreaBullet *area = area_owner.get(p_area); + ERR_FAIL_COND(!area); + area->set_transform(p_transform); +} + +Transform BulletPhysicsServer::area_get_transform(RID p_area) const { + AreaBullet *area = area_owner.get(p_area); + ERR_FAIL_COND_V(!area, Transform()); + return area->get_transform(); +} + +void BulletPhysicsServer::area_set_collision_mask(RID p_area, uint32_t p_mask) { + AreaBullet *area = area_owner.get(p_area); + ERR_FAIL_COND(!area); + area->set_collision_mask(p_mask); +} + +void BulletPhysicsServer::area_set_collision_layer(RID p_area, uint32_t p_layer) { + AreaBullet *area = area_owner.get(p_area); + ERR_FAIL_COND(!area); + area->set_collision_layer(p_layer); +} + +void BulletPhysicsServer::area_set_monitorable(RID p_area, bool p_monitorable) { + AreaBullet *area = area_owner.get(p_area); + ERR_FAIL_COND(!area); + + area->set_monitorable(p_monitorable); +} + +void BulletPhysicsServer::area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) { + AreaBullet *area = area_owner.get(p_area); + ERR_FAIL_COND(!area); + + area->set_event_callback(CollisionObjectBullet::TYPE_RIGID_BODY, p_receiver ? p_receiver->get_instance_id() : 0, p_method); +} + +void BulletPhysicsServer::area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) { + AreaBullet *area = area_owner.get(p_area); + ERR_FAIL_COND(!area); + + area->set_event_callback(CollisionObjectBullet::TYPE_AREA, p_receiver ? p_receiver->get_instance_id() : 0, p_method); +} + +void BulletPhysicsServer::area_set_ray_pickable(RID p_area, bool p_enable) { + AreaBullet *area = area_owner.get(p_area); + ERR_FAIL_COND(!area); + area->set_ray_pickable(p_enable); +} + +bool BulletPhysicsServer::area_is_ray_pickable(RID p_area) const { + AreaBullet *area = area_owner.get(p_area); + ERR_FAIL_COND_V(!area, false); + return area->is_ray_pickable(); +} + +RID BulletPhysicsServer::body_create(BodyMode p_mode, bool p_init_sleeping) { + RigidBodyBullet *body = bulletnew(RigidBodyBullet); + body->set_mode(p_mode); + body->set_collision_layer(1); + body->set_collision_mask(1); + if (p_init_sleeping) + body->set_state(BODY_STATE_SLEEPING, p_init_sleeping); + CreateThenReturnRID(rigid_body_owner, body); +} + +void BulletPhysicsServer::body_set_space(RID p_body, RID p_space) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + SpaceBullet *space = NULL; + + if (p_space.is_valid()) { + space = space_owner.get(p_space); + ERR_FAIL_COND(!space); + } + + if (body->get_space() == space) + return; //pointles + + body->set_space(space); +} + +RID BulletPhysicsServer::body_get_space(RID p_body) const { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, RID()); + + SpaceBullet *space = body->get_space(); + if (!space) + return RID(); + return space->get_self(); +} + +void BulletPhysicsServer::body_set_mode(RID p_body, PhysicsServer::BodyMode p_mode) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_mode(p_mode); +} + +PhysicsServer::BodyMode BulletPhysicsServer::body_get_mode(RID p_body) const { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, BODY_MODE_STATIC); + return body->get_mode(); +} + +void BulletPhysicsServer::body_add_shape(RID p_body, RID p_shape, const Transform &p_transform) { + + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + ShapeBullet *shape = shape_owner.get(p_shape); + ERR_FAIL_COND(!shape); + + body->add_shape(shape, p_transform); +} + +void BulletPhysicsServer::body_set_shape(RID p_body, int p_shape_idx, RID p_shape) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + ShapeBullet *shape = shape_owner.get(p_shape); + ERR_FAIL_COND(!shape); + + body->set_shape(p_shape_idx, shape); +} + +void BulletPhysicsServer::body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->set_shape_transform(p_shape_idx, p_transform); +} + +int BulletPhysicsServer::body_get_shape_count(RID p_body) const { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0); + return body->get_shape_count(); +} + +RID BulletPhysicsServer::body_get_shape(RID p_body, int p_shape_idx) const { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, RID()); + + ShapeBullet *shape = body->get_shape(p_shape_idx); + ERR_FAIL_COND_V(!shape, RID()); + + return shape->get_self(); +} + +Transform BulletPhysicsServer::body_get_shape_transform(RID p_body, int p_shape_idx) const { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, Transform()); + return body->get_shape_transform(p_shape_idx); +} + +void BulletPhysicsServer::body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->set_shape_disabled(p_shape_idx, p_disabled); +} + +void BulletPhysicsServer::body_remove_shape(RID p_body, int p_shape_idx) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->remove_shape(p_shape_idx); +} + +void BulletPhysicsServer::body_clear_shapes(RID p_body) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->remove_all_shapes(); +} + +void BulletPhysicsServer::body_attach_object_instance_id(RID p_body, uint32_t p_ID) { + CollisionObjectBullet *body = get_collisin_object(p_body); + if (!body) { + body = soft_body_owner.get(p_body); + } + ERR_FAIL_COND(!body); + + body->set_instance_id(p_ID); +} + +uint32_t BulletPhysicsServer::body_get_object_instance_id(RID p_body) const { + CollisionObjectBullet *body = get_collisin_object(p_body); + ERR_FAIL_COND_V(!body, 0); + + return body->get_instance_id(); +} + +void BulletPhysicsServer::body_set_enable_continuous_collision_detection(RID p_body, bool p_enable) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->set_continuous_collision_detection(p_enable); +} + +bool BulletPhysicsServer::body_is_continuous_collision_detection_enabled(RID p_body) const { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, false); + + return body->is_continuous_collision_detection_enabled(); +} + +void BulletPhysicsServer::body_set_collision_layer(RID p_body, uint32_t p_layer) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->set_collision_layer(p_layer); +} + +uint32_t BulletPhysicsServer::body_get_collision_layer(RID p_body) const { + const RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0); + + return body->get_collision_layer(); +} + +void BulletPhysicsServer::body_set_collision_mask(RID p_body, uint32_t p_mask) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->set_collision_mask(p_mask); +} + +uint32_t BulletPhysicsServer::body_get_collision_mask(RID p_body) const { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0); + + return body->get_collision_mask(); +} + +void BulletPhysicsServer::body_set_user_flags(RID p_body, uint32_t p_flags) { + WARN_PRINT("This function si not currently supported by bullet and Godot"); +} + +uint32_t BulletPhysicsServer::body_get_user_flags(RID p_body) const { + WARN_PRINT("This function si not currently supported by bullet and Godot"); + return 0; +} + +void BulletPhysicsServer::body_set_param(RID p_body, BodyParameter p_param, float p_value) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->set_param(p_param, p_value); +} + +float BulletPhysicsServer::body_get_param(RID p_body, BodyParameter p_param) const { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0); + + return body->get_param(p_param); +} + +void BulletPhysicsServer::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->set_state(p_state, p_variant); +} + +Variant BulletPhysicsServer::body_get_state(RID p_body, BodyState p_state) const { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, Variant()); + + return body->get_state(p_state); +} + +void BulletPhysicsServer::body_set_applied_force(RID p_body, const Vector3 &p_force) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->set_applied_force(p_force); +} + +Vector3 BulletPhysicsServer::body_get_applied_force(RID p_body) const { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, Vector3()); + return body->get_applied_force(); +} + +void BulletPhysicsServer::body_set_applied_torque(RID p_body, const Vector3 &p_torque) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->set_applied_torque(p_torque); +} + +Vector3 BulletPhysicsServer::body_get_applied_torque(RID p_body) const { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, Vector3()); + + return body->get_applied_torque(); +} + +void BulletPhysicsServer::body_apply_impulse(RID p_body, const Vector3 &p_pos, const Vector3 &p_impulse) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->apply_impulse(p_pos, p_impulse); +} + +void BulletPhysicsServer::body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->apply_torque_impulse(p_impulse); +} + +void BulletPhysicsServer::body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + Vector3 v = body->get_linear_velocity(); + Vector3 axis = p_axis_velocity.normalized(); + v -= axis * axis.dot(v); + v += p_axis_velocity; + body->set_linear_velocity(v); +} + +void BulletPhysicsServer::body_set_axis_lock(RID p_body, PhysicsServer::BodyAxisLock p_lock) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_axis_lock(p_lock); +} + +PhysicsServer::BodyAxisLock BulletPhysicsServer::body_get_axis_lock(RID p_body) const { + const RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, BODY_AXIS_LOCK_DISABLED); + return body->get_axis_lock(); +} + +void BulletPhysicsServer::body_add_collision_exception(RID p_body, RID p_body_b) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + RigidBodyBullet *other_body = rigid_body_owner.get(p_body_b); + ERR_FAIL_COND(!other_body); + + body->add_collision_exception(other_body); +} + +void BulletPhysicsServer::body_remove_collision_exception(RID p_body, RID p_body_b) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + RigidBodyBullet *other_body = rigid_body_owner.get(p_body_b); + ERR_FAIL_COND(!other_body); + + body->remove_collision_exception(other_body); +} + +void BulletPhysicsServer::body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + for (int i = 0; i < body->get_exceptions().size(); i++) { + p_exceptions->push_back(body->get_exceptions()[i]); + } +} + +void BulletPhysicsServer::body_set_max_contacts_reported(RID p_body, int p_contacts) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->set_max_collisions_detection(p_contacts); +} + +int BulletPhysicsServer::body_get_max_contacts_reported(RID p_body) const { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0); + + return body->get_max_collisions_detection(); +} + +void BulletPhysicsServer::body_set_contacts_reported_depth_threshold(RID p_body, float p_treshold) { + WARN_PRINT("Not supported by bullet and even Godot"); +} + +float BulletPhysicsServer::body_get_contacts_reported_depth_threshold(RID p_body) const { + WARN_PRINT("Not supported by bullet and even Godot"); + return 0.; +} + +void BulletPhysicsServer::body_set_omit_force_integration(RID p_body, bool p_omit) { + WARN_PRINT("Not supported by bullet"); +} + +bool BulletPhysicsServer::body_is_omitting_force_integration(RID p_body) const { + WARN_PRINT("Not supported by bullet"); + return false; +} + +void BulletPhysicsServer::body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_force_integration_callback(p_receiver->get_instance_id(), p_method, p_udata); +} + +void BulletPhysicsServer::body_set_ray_pickable(RID p_body, bool p_enable) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_ray_pickable(p_enable); +} + +bool BulletPhysicsServer::body_is_ray_pickable(RID p_body) const { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, false); + return body->is_ray_pickable(); +} + +PhysicsDirectBodyState *BulletPhysicsServer::body_get_direct_state(RID p_body) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, NULL); + return BulletPhysicsDirectBodyState::get_singleton(body); +} + +bool BulletPhysicsServer::body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, float p_margin, MotionResult *r_result) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, false); + ERR_FAIL_COND_V(!body->get_space(), false); + + return body->get_space()->test_body_motion(body, p_from, p_motion, p_margin, r_result); +} + +RID BulletPhysicsServer::soft_body_create(bool p_init_sleeping) { + SoftBodyBullet *body = bulletnew(SoftBodyBullet); + body->set_collision_layer(1); + body->set_collision_mask(1); + if (p_init_sleeping) + body->set_activation_state(false); + CreateThenReturnRID(soft_body_owner, body); +} + +void BulletPhysicsServer::soft_body_set_space(RID p_body, RID p_space) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + SpaceBullet *space = NULL; + + if (p_space.is_valid()) { + space = space_owner.get(p_space); + ERR_FAIL_COND(!space); + } + + if (body->get_space() == space) + return; //pointles + + body->set_space(space); +} + +RID BulletPhysicsServer::soft_body_get_space(RID p_body) const { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, RID()); + + SpaceBullet *space = body->get_space(); + if (!space) + return RID(); + return space->get_self(); +} + +void BulletPhysicsServer::soft_body_set_trimesh_body_shape(RID p_body, PoolVector<int> p_indices, PoolVector<Vector3> p_vertices, int p_triangles_num) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->set_trimesh_body_shape(p_indices, p_vertices, p_triangles_num); +} + +void BulletPhysicsServer::soft_body_set_collision_layer(RID p_body, uint32_t p_layer) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->set_collision_layer(p_layer); +} + +uint32_t BulletPhysicsServer::soft_body_get_collision_layer(RID p_body) const { + const SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0); + + return body->get_collision_layer(); +} + +void BulletPhysicsServer::soft_body_set_collision_mask(RID p_body, uint32_t p_mask) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->set_collision_mask(p_mask); +} + +uint32_t BulletPhysicsServer::soft_body_get_collision_mask(RID p_body) const { + const SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0); + + return body->get_collision_mask(); +} + +void BulletPhysicsServer::soft_body_add_collision_exception(RID p_body, RID p_body_b) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + CollisionObjectBullet *other_body = rigid_body_owner.get(p_body_b); + if (!other_body) { + other_body = soft_body_owner.get(p_body_b); + } + ERR_FAIL_COND(!other_body); + + body->add_collision_exception(other_body); +} + +void BulletPhysicsServer::soft_body_remove_collision_exception(RID p_body, RID p_body_b) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + CollisionObjectBullet *other_body = rigid_body_owner.get(p_body_b); + if (!other_body) { + other_body = soft_body_owner.get(p_body_b); + } + ERR_FAIL_COND(!other_body); + + body->remove_collision_exception(other_body); +} + +void BulletPhysicsServer::soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + for (int i = 0; i < body->get_exceptions().size(); i++) { + p_exceptions->push_back(body->get_exceptions()[i]); + } +} + +void BulletPhysicsServer::soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) { + print_line("TODO MUST BE IMPLEMENTED"); +} + +Variant BulletPhysicsServer::soft_body_get_state(RID p_body, BodyState p_state) const { + print_line("TODO MUST BE IMPLEMENTED"); + return Variant(); +} + +void BulletPhysicsServer::soft_body_set_transform(RID p_body, const Transform &p_transform) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->set_transform(p_transform); +} + +Transform BulletPhysicsServer::soft_body_get_transform(RID p_body) const { + const SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, Transform()); + + return body->get_transform(); +} + +void BulletPhysicsServer::soft_body_set_ray_pickable(RID p_body, bool p_enable) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_ray_pickable(p_enable); +} + +bool BulletPhysicsServer::soft_body_is_ray_pickable(RID p_body) const { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, false); + return body->is_ray_pickable(); +} + +PhysicsServer::JointType BulletPhysicsServer::joint_get_type(RID p_joint) const { + JointBullet *joint = joint_owner.get(p_joint); + ERR_FAIL_COND_V(!joint, JOINT_PIN); + return joint->get_type(); +} + +void BulletPhysicsServer::joint_set_solver_priority(RID p_joint, int p_priority) { + //WARN_PRINTS("Joint priority not supported by bullet"); +} + +int BulletPhysicsServer::joint_get_solver_priority(RID p_joint) const { + //WARN_PRINTS("Joint priority not supported by bullet"); + return 0; +} + +RID BulletPhysicsServer::joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) { + RigidBodyBullet *body_A = rigid_body_owner.get(p_body_A); + ERR_FAIL_COND_V(!body_A, RID()); + + JointAssertSpace(body_A, "A", RID()); + + RigidBodyBullet *body_B = NULL; + if (p_body_B.is_valid()) { + body_B = rigid_body_owner.get(p_body_B); + JointAssertSpace(body_B, "B", RID()); + JointAssertSameSpace(body_A, body_B, RID()); + } + + ERR_FAIL_COND_V(body_A == body_B, RID()); + + JointBullet *joint = bulletnew(PinJointBullet(body_A, p_local_A, body_B, p_local_B)); + AddJointToSpace(body_A, joint, true); + + CreateThenReturnRID(joint_owner, joint); +} + +void BulletPhysicsServer::pin_joint_set_param(RID p_joint, PinJointParam p_param, float p_value) { + JointBullet *joint = joint_owner.get(p_joint); + ERR_FAIL_COND(!joint); + ERR_FAIL_COND(joint->get_type() != JOINT_PIN); + PinJointBullet *pin_joint = static_cast<PinJointBullet *>(joint); + pin_joint->set_param(p_param, p_value); +} + +float BulletPhysicsServer::pin_joint_get_param(RID p_joint, PinJointParam p_param) const { + JointBullet *joint = joint_owner.get(p_joint); + ERR_FAIL_COND_V(!joint, 0); + ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, 0); + PinJointBullet *pin_joint = static_cast<PinJointBullet *>(joint); + return pin_joint->get_param(p_param); +} + +void BulletPhysicsServer::pin_joint_set_local_a(RID p_joint, const Vector3 &p_A) { + JointBullet *joint = joint_owner.get(p_joint); + ERR_FAIL_COND(!joint); + ERR_FAIL_COND(joint->get_type() != JOINT_PIN); + PinJointBullet *pin_joint = static_cast<PinJointBullet *>(joint); + pin_joint->setPivotInA(p_A); +} + +Vector3 BulletPhysicsServer::pin_joint_get_local_a(RID p_joint) const { + JointBullet *joint = joint_owner.get(p_joint); + ERR_FAIL_COND_V(!joint, Vector3()); + ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, Vector3()); + PinJointBullet *pin_joint = static_cast<PinJointBullet *>(joint); + return pin_joint->getPivotInA(); +} + +void BulletPhysicsServer::pin_joint_set_local_b(RID p_joint, const Vector3 &p_B) { + JointBullet *joint = joint_owner.get(p_joint); + ERR_FAIL_COND(!joint); + ERR_FAIL_COND(joint->get_type() != JOINT_PIN); + PinJointBullet *pin_joint = static_cast<PinJointBullet *>(joint); + pin_joint->setPivotInB(p_B); +} + +Vector3 BulletPhysicsServer::pin_joint_get_local_b(RID p_joint) const { + JointBullet *joint = joint_owner.get(p_joint); + ERR_FAIL_COND_V(!joint, Vector3()); + ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, Vector3()); + PinJointBullet *pin_joint = static_cast<PinJointBullet *>(joint); + return pin_joint->getPivotInB(); +} + +RID BulletPhysicsServer::joint_create_hinge(RID p_body_A, const Transform &p_hinge_A, RID p_body_B, const Transform &p_hinge_B) { + RigidBodyBullet *body_A = rigid_body_owner.get(p_body_A); + ERR_FAIL_COND_V(!body_A, RID()); + JointAssertSpace(body_A, "A", RID()); + + RigidBodyBullet *body_B = NULL; + if (p_body_B.is_valid()) { + body_B = rigid_body_owner.get(p_body_B); + JointAssertSpace(body_B, "B", RID()); + JointAssertSameSpace(body_A, body_B, RID()); + } + + ERR_FAIL_COND_V(body_A == body_B, RID()); + + JointBullet *joint = bulletnew(HingeJointBullet(body_A, body_B, p_hinge_A, p_hinge_B)); + AddJointToSpace(body_A, joint, true); + + CreateThenReturnRID(joint_owner, joint); +} + +RID BulletPhysicsServer::joint_create_hinge_simple(RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) { + RigidBodyBullet *body_A = rigid_body_owner.get(p_body_A); + ERR_FAIL_COND_V(!body_A, RID()); + JointAssertSpace(body_A, "A", RID()); + + RigidBodyBullet *body_B = NULL; + if (p_body_B.is_valid()) { + body_B = rigid_body_owner.get(p_body_B); + JointAssertSpace(body_B, "B", RID()); + JointAssertSameSpace(body_A, body_B, RID()); + } + + ERR_FAIL_COND_V(body_A == body_B, RID()); + + JointBullet *joint = bulletnew(HingeJointBullet(body_A, body_B, p_pivot_A, p_pivot_B, p_axis_A, p_axis_B)); + AddJointToSpace(body_A, joint, true); + + CreateThenReturnRID(joint_owner, joint); +} + +void BulletPhysicsServer::hinge_joint_set_param(RID p_joint, HingeJointParam p_param, float p_value) { + JointBullet *joint = joint_owner.get(p_joint); + ERR_FAIL_COND(!joint); + ERR_FAIL_COND(joint->get_type() != JOINT_HINGE); + HingeJointBullet *hinge_joint = static_cast<HingeJointBullet *>(joint); + hinge_joint->set_param(p_param, p_value); +} + +float BulletPhysicsServer::hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const { + JointBullet *joint = joint_owner.get(p_joint); + ERR_FAIL_COND_V(!joint, 0); + ERR_FAIL_COND_V(joint->get_type() != JOINT_HINGE, 0); + HingeJointBullet *hinge_joint = static_cast<HingeJointBullet *>(joint); + return hinge_joint->get_param(p_param); +} + +void BulletPhysicsServer::hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_value) { + JointBullet *joint = joint_owner.get(p_joint); + ERR_FAIL_COND(!joint); + ERR_FAIL_COND(joint->get_type() != JOINT_HINGE); + HingeJointBullet *hinge_joint = static_cast<HingeJointBullet *>(joint); + hinge_joint->set_flag(p_flag, p_value); +} + +bool BulletPhysicsServer::hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const { + JointBullet *joint = joint_owner.get(p_joint); + ERR_FAIL_COND_V(!joint, false); + ERR_FAIL_COND_V(joint->get_type() != JOINT_HINGE, false); + HingeJointBullet *hinge_joint = static_cast<HingeJointBullet *>(joint); + return hinge_joint->get_flag(p_flag); +} + +RID BulletPhysicsServer::joint_create_slider(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) { + RigidBodyBullet *body_A = rigid_body_owner.get(p_body_A); + ERR_FAIL_COND_V(!body_A, RID()); + JointAssertSpace(body_A, "A", RID()); + + RigidBodyBullet *body_B = NULL; + if (p_body_B.is_valid()) { + body_B = rigid_body_owner.get(p_body_B); + JointAssertSpace(body_B, "B", RID()); + JointAssertSameSpace(body_A, body_B, RID()); + } + + ERR_FAIL_COND_V(body_A == body_B, RID()); + + JointBullet *joint = bulletnew(SliderJointBullet(body_A, body_B, p_local_frame_A, p_local_frame_B)); + AddJointToSpace(body_A, joint, true); + + CreateThenReturnRID(joint_owner, joint); +} + +void BulletPhysicsServer::slider_joint_set_param(RID p_joint, SliderJointParam p_param, float p_value) { + JointBullet *joint = joint_owner.get(p_joint); + ERR_FAIL_COND(!joint); + ERR_FAIL_COND(joint->get_type() != JOINT_SLIDER); + SliderJointBullet *slider_joint = static_cast<SliderJointBullet *>(joint); + slider_joint->set_param(p_param, p_value); +} + +float BulletPhysicsServer::slider_joint_get_param(RID p_joint, SliderJointParam p_param) const { + JointBullet *joint = joint_owner.get(p_joint); + ERR_FAIL_COND_V(!joint, 0); + ERR_FAIL_COND_V(joint->get_type() != JOINT_SLIDER, 0); + SliderJointBullet *slider_joint = static_cast<SliderJointBullet *>(joint); + return slider_joint->get_param(p_param); +} + +RID BulletPhysicsServer::joint_create_cone_twist(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) { + RigidBodyBullet *body_A = rigid_body_owner.get(p_body_A); + ERR_FAIL_COND_V(!body_A, RID()); + JointAssertSpace(body_A, "A", RID()); + + RigidBodyBullet *body_B = NULL; + if (p_body_B.is_valid()) { + body_B = rigid_body_owner.get(p_body_B); + JointAssertSpace(body_B, "B", RID()); + JointAssertSameSpace(body_A, body_B, RID()); + } + + JointBullet *joint = bulletnew(ConeTwistJointBullet(body_A, body_B, p_local_frame_A, p_local_frame_B)); + AddJointToSpace(body_A, joint, true); + + CreateThenReturnRID(joint_owner, joint); +} + +void BulletPhysicsServer::cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, float p_value) { + JointBullet *joint = joint_owner.get(p_joint); + ERR_FAIL_COND(!joint); + ERR_FAIL_COND(joint->get_type() != JOINT_CONE_TWIST); + ConeTwistJointBullet *coneTwist_joint = static_cast<ConeTwistJointBullet *>(joint); + coneTwist_joint->set_param(p_param, p_value); +} + +float BulletPhysicsServer::cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const { + JointBullet *joint = joint_owner.get(p_joint); + ERR_FAIL_COND_V(!joint, 0.); + ERR_FAIL_COND_V(joint->get_type() != JOINT_CONE_TWIST, 0.); + ConeTwistJointBullet *coneTwist_joint = static_cast<ConeTwistJointBullet *>(joint); + return coneTwist_joint->get_param(p_param); +} + +RID BulletPhysicsServer::joint_create_generic_6dof(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) { + RigidBodyBullet *body_A = rigid_body_owner.get(p_body_A); + ERR_FAIL_COND_V(!body_A, RID()); + JointAssertSpace(body_A, "A", RID()); + + RigidBodyBullet *body_B = NULL; + if (p_body_B.is_valid()) { + body_B = rigid_body_owner.get(p_body_B); + JointAssertSpace(body_B, "B", RID()); + JointAssertSameSpace(body_A, body_B, RID()); + } + + ERR_FAIL_COND_V(body_A == body_B, RID()); + + JointBullet *joint = bulletnew(Generic6DOFJointBullet(body_A, body_B, p_local_frame_A, p_local_frame_B, true)); + AddJointToSpace(body_A, joint, true); + + CreateThenReturnRID(joint_owner, joint); +} + +void BulletPhysicsServer::generic_6dof_joint_set_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param, float p_value) { + JointBullet *joint = joint_owner.get(p_joint); + ERR_FAIL_COND(!joint); + ERR_FAIL_COND(joint->get_type() != JOINT_6DOF); + Generic6DOFJointBullet *generic_6dof_joint = static_cast<Generic6DOFJointBullet *>(joint); + generic_6dof_joint->set_param(p_axis, p_param, p_value); +} + +float BulletPhysicsServer::generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param) { + JointBullet *joint = joint_owner.get(p_joint); + ERR_FAIL_COND_V(!joint, 0); + ERR_FAIL_COND_V(joint->get_type() != JOINT_6DOF, 0); + Generic6DOFJointBullet *generic_6dof_joint = static_cast<Generic6DOFJointBullet *>(joint); + return generic_6dof_joint->get_param(p_axis, p_param); +} + +void BulletPhysicsServer::generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag, bool p_enable) { + JointBullet *joint = joint_owner.get(p_joint); + ERR_FAIL_COND(!joint); + ERR_FAIL_COND(joint->get_type() != JOINT_6DOF); + Generic6DOFJointBullet *generic_6dof_joint = static_cast<Generic6DOFJointBullet *>(joint); + generic_6dof_joint->set_flag(p_axis, p_flag, p_enable); +} + +bool BulletPhysicsServer::generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag) { + JointBullet *joint = joint_owner.get(p_joint); + ERR_FAIL_COND_V(!joint, false); + ERR_FAIL_COND_V(joint->get_type() != JOINT_6DOF, false); + Generic6DOFJointBullet *generic_6dof_joint = static_cast<Generic6DOFJointBullet *>(joint); + return generic_6dof_joint->get_flag(p_axis, p_flag); +} + +void BulletPhysicsServer::free(RID p_rid) { + if (shape_owner.owns(p_rid)) { + + ShapeBullet *shape = shape_owner.get(p_rid); + + // Notify the shape is configured + for (Map<ShapeOwnerBullet *, int>::Element *element = shape->get_owners().front(); element; element = element->next()) { + static_cast<ShapeOwnerBullet *>(element->key())->remove_shape(shape); + } + + shape_owner.free(p_rid); + bulletdelete(shape); + } else if (rigid_body_owner.owns(p_rid)) { + + RigidBodyBullet *body = rigid_body_owner.get(p_rid); + + body->set_space(NULL); + + body->remove_all_shapes(true); + + rigid_body_owner.free(p_rid); + bulletdelete(body); + + } else if (soft_body_owner.owns(p_rid)) { + + SoftBodyBullet *body = soft_body_owner.get(p_rid); + + body->set_space(NULL); + + soft_body_owner.free(p_rid); + bulletdelete(body); + + } else if (area_owner.owns(p_rid)) { + + AreaBullet *area = area_owner.get(p_rid); + + area->set_space(NULL); + + area->remove_all_shapes(true); + + area_owner.free(p_rid); + bulletdelete(area); + + } else if (joint_owner.owns(p_rid)) { + + JointBullet *joint = joint_owner.get(p_rid); + joint->destroy_internal_constraint(); + joint_owner.free(p_rid); + bulletdelete(joint); + + } else if (space_owner.owns(p_rid)) { + + SpaceBullet *space = space_owner.get(p_rid); + + space->remove_all_collision_objects(); + + space_set_active(p_rid, false); + space_owner.free(p_rid); + bulletdelete(space); + } else { + + ERR_EXPLAIN("Invalid ID"); + ERR_FAIL(); + } +} + +void BulletPhysicsServer::init() { + BulletPhysicsDirectBodyState::initSingleton(); +} + +void BulletPhysicsServer::step(float p_deltaTime) { + if (!active) + return; + + BulletPhysicsDirectBodyState::singleton_setDeltaTime(p_deltaTime); + if (activeSpace) { + activeSpace->step(p_deltaTime); + } +} + +void BulletPhysicsServer::sync() { +} + +void BulletPhysicsServer::flush_queries() { +} + +void BulletPhysicsServer::finish() { + BulletPhysicsDirectBodyState::destroySingleton(); +} + +int BulletPhysicsServer::get_process_info(ProcessInfo p_info) { + return 0; +} + +CollisionObjectBullet *BulletPhysicsServer::get_collisin_object(RID p_object) const { + if (rigid_body_owner.owns(p_object)) { + return rigid_body_owner.getornull(p_object); + } + if (area_owner.owns(p_object)) { + return area_owner.getornull(p_object); + } + if (soft_body_owner.owns(p_object)) { + return soft_body_owner.getornull(p_object); + } + return NULL; +} + +RigidCollisionObjectBullet *BulletPhysicsServer::get_rigid_collisin_object(RID p_object) const { + if (rigid_body_owner.owns(p_object)) { + return rigid_body_owner.getornull(p_object); + } + if (area_owner.owns(p_object)) { + return area_owner.getornull(p_object); + } + return NULL; +} diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h new file mode 100644 index 0000000000..e66e8a5ac1 --- /dev/null +++ b/modules/bullet/bullet_physics_server.h @@ -0,0 +1,358 @@ +/*************************************************************************/ +/* bullet_physics_server.h */ +/* 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. */ +/*************************************************************************/ + +#ifndef BULLET_PHYSICS_SERVER_H +#define BULLET_PHYSICS_SERVER_H + +#include "area_bullet.h" +#include "joint_bullet.h" +#include "rid.h" +#include "rigid_body_bullet.h" +#include "servers/physics_server.h" +#include "shape_bullet.h" +#include "soft_body_bullet.h" +#include "space_bullet.h" + +class BulletPhysicsServer : public PhysicsServer { + GDCLASS(BulletPhysicsServer, PhysicsServer) + + friend class BulletPhysicsDirectSpaceState; + + bool active; + SpaceBullet *activeSpace; + + mutable RID_Owner<SpaceBullet> space_owner; + mutable RID_Owner<ShapeBullet> shape_owner; + mutable RID_Owner<AreaBullet> area_owner; + mutable RID_Owner<RigidBodyBullet> rigid_body_owner; + mutable RID_Owner<SoftBodyBullet> soft_body_owner; + mutable RID_Owner<JointBullet> joint_owner; + +private: + /// This is used when a collision shape is not active, so the bullet compound shapes index are always sync with godot index + static btEmptyShape *emptyShape; + +public: + static btEmptyShape *get_empty_shape(); + +protected: + static void _bind_methods(); + +public: + BulletPhysicsServer(); + ~BulletPhysicsServer(); + + _FORCE_INLINE_ RID_Owner<SpaceBullet> *get_space_owner() { + return &space_owner; + } + _FORCE_INLINE_ RID_Owner<ShapeBullet> *get_shape_owner() { + return &shape_owner; + } + _FORCE_INLINE_ RID_Owner<AreaBullet> *get_area_owner() { + return &area_owner; + } + _FORCE_INLINE_ RID_Owner<RigidBodyBullet> *get_rigid_body_owner() { + return &rigid_body_owner; + } + _FORCE_INLINE_ RID_Owner<SoftBodyBullet> *get_soft_body_owner() { + return &soft_body_owner; + } + _FORCE_INLINE_ RID_Owner<JointBullet> *get_joint_owner() { + return &joint_owner; + } + + /* SHAPE API */ + virtual RID shape_create(ShapeType p_shape); + virtual void shape_set_data(RID p_shape, const Variant &p_data); + virtual ShapeType shape_get_type(RID p_shape) const; + virtual Variant shape_get_data(RID p_shape) const; + + /// Not supported + virtual void shape_set_custom_solver_bias(RID p_shape, real_t p_bias); + /// Not supported + virtual real_t shape_get_custom_solver_bias(RID p_shape) const; + + /* SPACE API */ + + virtual RID space_create(); + virtual void space_set_active(RID p_space, bool p_active); + virtual bool space_is_active(RID p_space) const; + + /// Not supported + virtual void space_set_param(RID p_space, SpaceParameter p_param, real_t p_value); + /// Not supported + virtual real_t space_get_param(RID p_space, SpaceParameter p_param) const; + + virtual PhysicsDirectSpaceState *space_get_direct_state(RID p_space); + + virtual void space_set_debug_contacts(RID p_space, int p_max_contacts); + virtual Vector<Vector3> space_get_contacts(RID p_space) const; + virtual int space_get_contact_count(RID p_space) const; + + /* AREA API */ + + /// Bullet Physics Engine not support "Area", this must be handled by the game developer in another way. + /// Since godot Physics use the concept of area even to define the main world, the API area_set_param is used to set initial physics world information. + /// The API area_set_param is a bit hacky, and allow Godot to set some parameters on Bullet's world, a different use print a warning to console. + /// All other APIs returns a warning message if used + + virtual RID area_create(); + + virtual void area_set_space(RID p_area, RID p_space); + + virtual RID area_get_space(RID p_area) const; + + virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode); + virtual AreaSpaceOverrideMode area_get_space_override_mode(RID p_area) const; + + virtual void area_add_shape(RID p_area, RID p_shape, const Transform &p_transform = Transform()); + virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape); + virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform); + virtual int area_get_shape_count(RID p_area) const; + virtual RID area_get_shape(RID p_area, int p_shape_idx) const; + virtual Transform area_get_shape_transform(RID p_area, int p_shape_idx) const; + virtual void area_remove_shape(RID p_area, int p_shape_idx); + virtual void area_clear_shapes(RID p_area); + virtual void area_set_shape_disabled(RID p_area, int p_shape_idx, bool p_disabled); + virtual void area_attach_object_instance_id(RID p_area, ObjectID p_ID); + virtual ObjectID area_get_object_instance_id(RID p_area) const; + + /// If you pass as p_area the SpaceBullet you can set some parameters as specified below + /// AREA_PARAM_GRAVITY + /// AREA_PARAM_GRAVITY_VECTOR + /// Otherwise you can set area parameters + virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value); + virtual Variant area_get_param(RID p_parea, AreaParameter p_param) const; + + virtual void area_set_transform(RID p_area, const Transform &p_transform); + virtual Transform area_get_transform(RID p_area) const; + + virtual void area_set_collision_mask(RID p_area, uint32_t p_mask); + virtual void area_set_collision_layer(RID p_area, uint32_t p_layer); + + virtual void area_set_monitorable(RID p_area, bool p_monitorable); + virtual void area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method); + virtual void area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method); + virtual void area_set_ray_pickable(RID p_area, bool p_enable); + virtual bool area_is_ray_pickable(RID p_area) const; + + /* RIGID BODY API */ + + virtual RID body_create(BodyMode p_mode = BODY_MODE_RIGID, bool p_init_sleeping = false); + + virtual void body_set_space(RID p_body, RID p_space); + virtual RID body_get_space(RID p_body) const; + + virtual void body_set_mode(RID p_body, BodyMode p_mode); + virtual BodyMode body_get_mode(RID p_body) const; + + virtual void body_add_shape(RID p_body, RID p_shape, const Transform &p_transform = Transform()); + // Not supported, Please remove and add new shape + virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape); + virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform); + + virtual int body_get_shape_count(RID p_body) const; + virtual RID body_get_shape(RID p_body, int p_shape_idx) const; + virtual Transform body_get_shape_transform(RID p_body, int p_shape_idx) const; + + virtual void body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled); + + virtual void body_remove_shape(RID p_body, int p_shape_idx); + virtual void body_clear_shapes(RID p_body); + + // Used for Rigid and Soft Bodies + virtual void body_attach_object_instance_id(RID p_body, uint32_t p_ID); + virtual uint32_t body_get_object_instance_id(RID p_body) const; + + virtual void body_set_enable_continuous_collision_detection(RID p_body, bool p_enable); + virtual bool body_is_continuous_collision_detection_enabled(RID p_body) const; + + virtual void body_set_collision_layer(RID p_body, uint32_t p_layer); + virtual uint32_t body_get_collision_layer(RID p_body) const; + + virtual void body_set_collision_mask(RID p_body, uint32_t p_mask); + virtual uint32_t body_get_collision_mask(RID p_body) const; + + /// This is not supported by physics server + virtual void body_set_user_flags(RID p_body, uint32_t p_flags); + /// This is not supported by physics server + virtual uint32_t body_get_user_flags(RID p_body) const; + + virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value); + virtual float body_get_param(RID p_body, BodyParameter p_param) const; + + virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant); + virtual Variant body_get_state(RID p_body, BodyState p_state) const; + + virtual void body_set_applied_force(RID p_body, const Vector3 &p_force); + virtual Vector3 body_get_applied_force(RID p_body) const; + + virtual void body_set_applied_torque(RID p_body, const Vector3 &p_torque); + virtual Vector3 body_get_applied_torque(RID p_body) const; + + virtual void body_apply_impulse(RID p_body, const Vector3 &p_pos, const Vector3 &p_impulse); + virtual void body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse); + virtual void body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity); + + virtual void body_set_axis_lock(RID p_body, BodyAxisLock p_lock); + virtual BodyAxisLock body_get_axis_lock(RID p_body) const; + + virtual void body_add_collision_exception(RID p_body, RID p_body_b); + virtual void body_remove_collision_exception(RID p_body, RID p_body_b); + virtual void body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions); + + virtual void body_set_max_contacts_reported(RID p_body, int p_contacts); + virtual int body_get_max_contacts_reported(RID p_body) const; + + virtual void body_set_contacts_reported_depth_threshold(RID p_body, float p_treshold); + virtual float body_get_contacts_reported_depth_threshold(RID p_body) const; + + virtual void body_set_omit_force_integration(RID p_body, bool p_omit); + virtual bool body_is_omitting_force_integration(RID p_body) const; + + virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant()); + + virtual void body_set_ray_pickable(RID p_body, bool p_enable); + virtual bool body_is_ray_pickable(RID p_body) const; + + // this function only works on physics process, errors and returns null otherwise + virtual PhysicsDirectBodyState *body_get_direct_state(RID p_body); + + virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, float p_margin = 0.001, MotionResult *r_result = NULL); + + /* SOFT BODY API */ + + virtual RID soft_body_create(bool p_init_sleeping = false); + + virtual void soft_body_set_space(RID p_body, RID p_space); + virtual RID soft_body_get_space(RID p_body) const; + + virtual void soft_body_set_trimesh_body_shape(RID p_body, PoolVector<int> p_indices, PoolVector<Vector3> p_vertices, int p_triangles_num); + + virtual void soft_body_set_collision_layer(RID p_body, uint32_t p_layer); + virtual uint32_t soft_body_get_collision_layer(RID p_body) const; + + virtual void soft_body_set_collision_mask(RID p_body, uint32_t p_mask); + virtual uint32_t soft_body_get_collision_mask(RID p_body) const; + + virtual void soft_body_add_collision_exception(RID p_body, RID p_body_b); + virtual void soft_body_remove_collision_exception(RID p_body, RID p_body_b); + virtual void soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions); + + virtual void soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant); + virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const; + + virtual void soft_body_set_transform(RID p_body, const Transform &p_transform); + virtual Transform soft_body_get_transform(RID p_body) const; + + virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable); + virtual bool soft_body_is_ray_pickable(RID p_body) const; + + /* JOINT API */ + + virtual JointType joint_get_type(RID p_joint) const; + + virtual void joint_set_solver_priority(RID p_joint, int p_priority); + virtual int joint_get_solver_priority(RID p_joint) const; + + virtual RID joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B); + + virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, float p_value); + virtual float pin_joint_get_param(RID p_joint, PinJointParam p_param) const; + + virtual void pin_joint_set_local_a(RID p_joint, const Vector3 &p_A); + virtual Vector3 pin_joint_get_local_a(RID p_joint) const; + + virtual void pin_joint_set_local_b(RID p_joint, const Vector3 &p_B); + virtual Vector3 pin_joint_get_local_b(RID p_joint) const; + + virtual RID joint_create_hinge(RID p_body_A, const Transform &p_frame_A, RID p_body_B, const Transform &p_frame_B); + virtual RID joint_create_hinge_simple(RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B); + + virtual void hinge_joint_set_param(RID p_joint, HingeJointParam p_param, float p_value); + virtual float hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const; + + virtual void hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_value); + virtual bool hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const; + + /// Reference frame is A + virtual RID joint_create_slider(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B); + + virtual void slider_joint_set_param(RID p_joint, SliderJointParam p_param, float p_value); + virtual float slider_joint_get_param(RID p_joint, SliderJointParam p_param) const; + + /// Reference frame is A + virtual RID joint_create_cone_twist(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B); + + virtual void cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, float p_value); + virtual float cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const; + + /// Reference frame is A + virtual RID joint_create_generic_6dof(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B); + + virtual void generic_6dof_joint_set_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param, float p_value); + virtual float generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param); + + virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag, bool p_enable); + virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag); + + /* MISC */ + + virtual void free(RID p_rid); + + virtual void set_active(bool p_active) { + active = p_active; + } + + static bool singleton_isActive() { + return static_cast<BulletPhysicsServer *>(get_singleton())->active; + } + + bool isActive() { + return active; + } + + virtual void init(); + virtual void step(float p_deltaTime); + virtual void sync(); + virtual void flush_queries(); + virtual void finish(); + + virtual int get_process_info(ProcessInfo p_info); + + CollisionObjectBullet *get_collisin_object(RID p_object) const; + RigidCollisionObjectBullet *get_rigid_collisin_object(RID p_object) const; + + /// Internal APIs +public: +}; + +#endif diff --git a/modules/bullet/bullet_types_converter.cpp b/modules/bullet/bullet_types_converter.cpp new file mode 100644 index 0000000000..5010197a78 --- /dev/null +++ b/modules/bullet/bullet_types_converter.cpp @@ -0,0 +1,94 @@ +/*************************************************************************/ +/* bullet_types_converter.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. */ +/*************************************************************************/ + +#pragma once + +#include "bullet_types_converter.h" + +// ++ BULLET to GODOT ++++++++++ +void B_TO_G(btVector3 const &inVal, Vector3 &outVal) { + outVal[0] = inVal[0]; + outVal[1] = inVal[1]; + outVal[2] = inVal[2]; +} + +void INVERT_B_TO_G(btVector3 const &inVal, Vector3 &outVal) { + outVal[0] = inVal[0] != 0. ? 1. / inVal[0] : 0.; + outVal[1] = inVal[1] != 0. ? 1. / inVal[1] : 0.; + outVal[2] = inVal[2] != 0. ? 1. / inVal[2] : 0.; +} + +void B_TO_G(btMatrix3x3 const &inVal, Basis &outVal) { + B_TO_G(inVal[0], outVal[0]); + B_TO_G(inVal[1], outVal[1]); + B_TO_G(inVal[2], outVal[2]); +} + +void INVERT_B_TO_G(btMatrix3x3 const &inVal, Basis &outVal) { + INVERT_B_TO_G(inVal[0], outVal[0]); + INVERT_B_TO_G(inVal[1], outVal[1]); + INVERT_B_TO_G(inVal[2], outVal[2]); +} + +void B_TO_G(btTransform const &inVal, Transform &outVal) { + B_TO_G(inVal.getBasis(), outVal.basis); + B_TO_G(inVal.getOrigin(), outVal.origin); +} + +// ++ GODOT to BULLET ++++++++++ +void G_TO_B(Vector3 const &inVal, btVector3 &outVal) { + outVal[0] = inVal[0]; + outVal[1] = inVal[1]; + outVal[2] = inVal[2]; +} + +void INVERT_G_TO_B(Vector3 const &inVal, btVector3 &outVal) { + outVal[0] = inVal[0] != 0. ? 1. / inVal[0] : 0.; + outVal[1] = inVal[1] != 0. ? 1. / inVal[1] : 0.; + outVal[2] = inVal[2] != 0. ? 1. / inVal[2] : 0.; +} + +void G_TO_B(Basis const &inVal, btMatrix3x3 &outVal) { + G_TO_B(inVal[0], outVal[0]); + G_TO_B(inVal[1], outVal[1]); + G_TO_B(inVal[2], outVal[2]); +} + +void INVERT_G_TO_B(Basis const &inVal, btMatrix3x3 &outVal) { + INVERT_G_TO_B(inVal[0], outVal[0]); + INVERT_G_TO_B(inVal[1], outVal[1]); + INVERT_G_TO_B(inVal[2], outVal[2]); +} + +void G_TO_B(Transform const &inVal, btTransform &outVal) { + G_TO_B(inVal.basis, outVal.getBasis()); + G_TO_B(inVal.origin, outVal.getOrigin()); +} diff --git a/modules/bullet/bullet_types_converter.h b/modules/bullet/bullet_types_converter.h new file mode 100644 index 0000000000..ed6a349382 --- /dev/null +++ b/modules/bullet/bullet_types_converter.h @@ -0,0 +1,57 @@ +/*************************************************************************/ +/* bullet_types_converter.h */ +/* 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. */ +/*************************************************************************/ + +#ifndef BULLET_TYPES_CONVERTER_H +#define BULLET_TYPES_CONVERTER_H + +#include "LinearMath/btMatrix3x3.h" +#include "LinearMath/btTransform.h" +#include "LinearMath/btVector3.h" +#include "core/math/matrix3.h" +#include "core/math/transform.h" +#include "core/math/vector3.h" +#include "core/typedefs.h" + +// Bullet to Godot +extern void B_TO_G(btVector3 const &inVal, Vector3 &outVal); +extern void INVERT_B_TO_G(btVector3 const &inVal, Vector3 &outVal); +extern void B_TO_G(btMatrix3x3 const &inVal, Basis &outVal); +extern void INVERT_B_TO_G(btMatrix3x3 const &inVal, Basis &outVal); +extern void B_TO_G(btTransform const &inVal, Transform &outVal); + +// Godot TO Bullet +extern void G_TO_B(Vector3 const &inVal, btVector3 &outVal); +extern void INVERT_G_TO_B(Vector3 const &inVal, btVector3 &outVal); +extern void G_TO_B(Basis const &inVal, btMatrix3x3 &outVal); +extern void INVERT_G_TO_B(Basis const &inVal, btMatrix3x3 &outVal); +extern void G_TO_B(Transform const &inVal, btTransform &outVal); + +#endif diff --git a/modules/bullet/bullet_utilities.h b/modules/bullet/bullet_utilities.h new file mode 100644 index 0000000000..45cde169b7 --- /dev/null +++ b/modules/bullet/bullet_utilities.h @@ -0,0 +1,44 @@ +/*************************************************************************/ +/* bullet_utilities.h */ +/* 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. */ +/*************************************************************************/ + +#ifndef BULLET_UTILITIES_H +#define BULLET_UTILITIES_H + +#pragma once + +#define bulletnew(cl) \ + new cl + +#define bulletdelete(cl) \ + delete cl; \ + cl = NULL; + +#endif diff --git a/modules/bullet/collision_object_bullet.cpp b/modules/bullet/collision_object_bullet.cpp new file mode 100644 index 0000000000..5739568d91 --- /dev/null +++ b/modules/bullet/collision_object_bullet.cpp @@ -0,0 +1,316 @@ +/*************************************************************************/ +/* collision_object_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 "collision_object_bullet.h" +#include "area_bullet.h" +#include "btBulletCollisionCommon.h" +#include "bullet_physics_server.h" +#include "bullet_types_converter.h" +#include "bullet_utilities.h" +#include "shape_bullet.h" +#include "space_bullet.h" + +#define enableDynamicAabbTree true +#define initialChildCapacity 1 + +CollisionObjectBullet::ShapeWrapper::~ShapeWrapper() {} + +void CollisionObjectBullet::ShapeWrapper::set_transform(const Transform &p_transform) { + G_TO_B(p_transform, transform); +} +void CollisionObjectBullet::ShapeWrapper::set_transform(const btTransform &p_transform) { + transform = p_transform; +} + +CollisionObjectBullet::CollisionObjectBullet(Type p_type) + : RIDBullet(), space(NULL), type(p_type), collisionsEnabled(true), m_isStatic(false), bt_collision_object(NULL), body_scale(1., 1., 1.) {} + +CollisionObjectBullet::~CollisionObjectBullet() { + // Remove all overlapping + for (int i = areasOverlapped.size() - 1; 0 <= i; --i) { + areasOverlapped[i]->remove_overlapping_instantly(this); + } + // not required + // areasOverlapped.clear(); + + destroyBulletCollisionObject(); +} + +bool equal(real_t first, real_t second) { + return Math::abs(first - second) <= 0.001f; +} + +void CollisionObjectBullet::set_body_scale(const Vector3 &p_new_scale) { + if (!equal(p_new_scale[0], body_scale[0]) || !equal(p_new_scale[1], body_scale[1]) || !equal(p_new_scale[2], body_scale[2])) { + G_TO_B(p_new_scale, body_scale); + on_body_scale_changed(); + } +} + +void CollisionObjectBullet::on_body_scale_changed() { +} + +void CollisionObjectBullet::destroyBulletCollisionObject() { + bulletdelete(bt_collision_object); +} + +void CollisionObjectBullet::setupBulletCollisionObject(btCollisionObject *p_collisionObject) { + bt_collision_object = p_collisionObject; + bt_collision_object->setUserPointer(this); + bt_collision_object->setUserIndex(type); + // Force the enabling of collision and avoid problems + set_collision_enabled(collisionsEnabled); +} + +void CollisionObjectBullet::add_collision_exception(const CollisionObjectBullet *p_ignoreCollisionObject) { + exceptions.insert(p_ignoreCollisionObject->get_self()); + bt_collision_object->setIgnoreCollisionCheck(p_ignoreCollisionObject->bt_collision_object, true); +} + +void CollisionObjectBullet::remove_collision_exception(const CollisionObjectBullet *p_ignoreCollisionObject) { + exceptions.erase(p_ignoreCollisionObject->get_self()); + bt_collision_object->setIgnoreCollisionCheck(p_ignoreCollisionObject->bt_collision_object, false); +} + +bool CollisionObjectBullet::has_collision_exception(const CollisionObjectBullet *p_otherCollisionObject) const { + return !bt_collision_object->checkCollideWithOverride(p_otherCollisionObject->bt_collision_object); +} + +void CollisionObjectBullet::set_collision_enabled(bool p_enabled) { + collisionsEnabled = p_enabled; + if (collisionsEnabled) { + bt_collision_object->setCollisionFlags(bt_collision_object->getCollisionFlags() & (~btCollisionObject::CF_NO_CONTACT_RESPONSE)); + } else { + bt_collision_object->setCollisionFlags(bt_collision_object->getCollisionFlags() | btCollisionObject::CF_NO_CONTACT_RESPONSE); + } +} + +bool CollisionObjectBullet::is_collisions_response_enabled() { + return collisionsEnabled; +} + +void CollisionObjectBullet::notify_new_overlap(AreaBullet *p_area) { + areasOverlapped.push_back(p_area); +} + +void CollisionObjectBullet::on_exit_area(AreaBullet *p_area) { + areasOverlapped.erase(p_area); +} + +void CollisionObjectBullet::set_godot_object_flags(int flags) { + bt_collision_object->setUserIndex2(flags); +} + +int CollisionObjectBullet::get_godot_object_flags() const { + return bt_collision_object->getUserIndex2(); +} + +void CollisionObjectBullet::set_transform(const Transform &p_global_transform) { + + btTransform btTrans; + Basis decomposed_basis; + + Vector3 decomposed_scale = p_global_transform.get_basis().rotref_posscale_decomposition(decomposed_basis); + + G_TO_B(p_global_transform.get_origin(), btTrans.getOrigin()); + G_TO_B(decomposed_basis, btTrans.getBasis()); + + set_body_scale(decomposed_scale); + set_transform__bullet(btTrans); +} + +Transform CollisionObjectBullet::get_transform() const { + Transform t; + B_TO_G(get_transform__bullet(), t); + return t; +} + +void CollisionObjectBullet::set_transform__bullet(const btTransform &p_global_transform) { + bt_collision_object->setWorldTransform(p_global_transform); +} + +const btTransform &CollisionObjectBullet::get_transform__bullet() const { + return bt_collision_object->getWorldTransform(); +} + +RigidCollisionObjectBullet::RigidCollisionObjectBullet(Type p_type) + : CollisionObjectBullet(p_type), compoundShape(bulletnew(btCompoundShape(enableDynamicAabbTree, initialChildCapacity))) { +} + +RigidCollisionObjectBullet::~RigidCollisionObjectBullet() { + remove_all_shapes(true); + bt_collision_object->setCollisionShape(NULL); + bulletdelete(compoundShape); +} + +/* Not used +void RigidCollisionObjectBullet::_internal_replaceShape(btCollisionShape *p_old_shape, btCollisionShape *p_new_shape) { + bool at_least_one_was_changed = false; + btTransform old_transf; + // Inverse because I need remove the shapes + // Fetch all shapes to be sure to remove all shapes + for (int i = compoundShape->getNumChildShapes() - 1; 0 <= i; --i) { + if (compoundShape->getChildShape(i) == p_old_shape) { + + old_transf = compoundShape->getChildTransform(i); + compoundShape->removeChildShapeByIndex(i); + compoundShape->addChildShape(old_transf, p_new_shape); + at_least_one_was_changed = true; + } + } + + if (at_least_one_was_changed) { + on_shapes_changed(); + } +}*/ + +void RigidCollisionObjectBullet::add_shape(ShapeBullet *p_shape, const Transform &p_transform) { + shapes.push_back(ShapeWrapper(p_shape, p_transform, true)); + p_shape->add_owner(this); + on_shapes_changed(); +} + +void RigidCollisionObjectBullet::set_shape(int p_index, ShapeBullet *p_shape) { + ShapeWrapper &shp = shapes[p_index]; + shp.shape->remove_owner(this); + p_shape->add_owner(this); + shp.shape = p_shape; + on_shapes_changed(); +} + +void RigidCollisionObjectBullet::set_shape_transform(int p_index, const Transform &p_transform) { + ERR_FAIL_INDEX(p_index, get_shape_count()); + + shapes[p_index].set_transform(p_transform); + on_shapes_changed(); +} + +void RigidCollisionObjectBullet::remove_shape(ShapeBullet *p_shape) { + // Remove the shape, all the times it appears + // Reverse order required for delete. + for (int i = shapes.size() - 1; 0 <= i; --i) { + if (p_shape == shapes[i].shape) { + internal_shape_destroy(i); + shapes.remove(i); + } + } + on_shapes_changed(); +} + +void RigidCollisionObjectBullet::remove_shape(int p_index) { + ERR_FAIL_INDEX(p_index, get_shape_count()); + internal_shape_destroy(p_index); + shapes.remove(p_index); + on_shapes_changed(); +} + +void RigidCollisionObjectBullet::remove_all_shapes(bool p_permanentlyFromThisBody) { + // Reverse order required for delete. + for (int i = shapes.size() - 1; 0 <= i; --i) { + internal_shape_destroy(i, p_permanentlyFromThisBody); + } + shapes.clear(); + on_shapes_changed(); +} + +int RigidCollisionObjectBullet::get_shape_count() const { + return shapes.size(); +} + +ShapeBullet *RigidCollisionObjectBullet::get_shape(int p_index) const { + return shapes[p_index].shape; +} + +btCollisionShape *RigidCollisionObjectBullet::get_bt_shape(int p_index) const { + return shapes[p_index].bt_shape; +} + +Transform RigidCollisionObjectBullet::get_shape_transform(int p_index) const { + Transform trs; + B_TO_G(shapes[p_index].transform, trs); + return trs; +} + +void RigidCollisionObjectBullet::on_shape_changed(const ShapeBullet *const p_shape) { + const int size = shapes.size(); + for (int i = 0; i < size; ++i) { + if (shapes[i].shape == p_shape) { + bulletdelete(shapes[i].bt_shape); + } + } + on_shapes_changed(); +} + +void RigidCollisionObjectBullet::on_shapes_changed() { + int i; + // Remove all shapes, reverse order for performance reason (Array resize) + for (i = compoundShape->getNumChildShapes() - 1; 0 <= i; --i) { + compoundShape->removeChildShapeByIndex(i); + } + + // Insert all shapes + ShapeWrapper *shpWrapper; + const int size = shapes.size(); + for (i = 0; i < size; ++i) { + shpWrapper = &shapes[i]; + if (!shpWrapper->bt_shape) { + shpWrapper->bt_shape = shpWrapper->shape->create_bt_shape(); + } + if (shpWrapper->active) { + compoundShape->addChildShape(shpWrapper->transform, shpWrapper->bt_shape); + } else { + compoundShape->addChildShape(shpWrapper->transform, BulletPhysicsServer::get_empty_shape()); + } + } + + compoundShape->setLocalScaling(body_scale); + compoundShape->recalculateLocalAabb(); +} + +void RigidCollisionObjectBullet::set_shape_disabled(int p_index, bool p_disabled) { + shapes[p_index].active = !p_disabled; + on_shapes_changed(); +} + +bool RigidCollisionObjectBullet::is_shape_disabled(int p_index) { + return !shapes[p_index].active; +} + +void RigidCollisionObjectBullet::on_body_scale_changed() { + CollisionObjectBullet::on_body_scale_changed(); + on_shapes_changed(); +} + +void RigidCollisionObjectBullet::internal_shape_destroy(int p_index, bool p_permanentlyFromThisBody) { + ShapeWrapper &shp = shapes[p_index]; + shp.shape->remove_owner(this, p_permanentlyFromThisBody); + bulletdelete(shp.bt_shape); +} diff --git a/modules/bullet/collision_object_bullet.h b/modules/bullet/collision_object_bullet.h new file mode 100644 index 0000000000..153b8ea5bc --- /dev/null +++ b/modules/bullet/collision_object_bullet.h @@ -0,0 +1,234 @@ +/*************************************************************************/ +/* collision_object_bullet.h */ +/* 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. */ +/*************************************************************************/ + +#ifndef COLLISION_OBJECT_BULLET_H +#define COLLISION_OBJECT_BULLET_H + +#include "LinearMath/btTransform.h" +#include "core/vset.h" +#include "object.h" +#include "shape_owner_bullet.h" +#include "transform.h" +#include "vector3.h" + +class AreaBullet; +class ShapeBullet; +class btCollisionObject; +class btCompoundShape; +class btCollisionShape; +class SpaceBullet; + +class CollisionObjectBullet : public RIDBullet { +public: + enum GodotObjectFlags { + GOF_IS_MONITORING_AREA = 1 << 0 + // FLAG2 = 1 << 1, + // FLAG3 = 1 << 2, + // FLAG4 = 1 << 3, + // FLAG5 = 1 << 4, + // FLAG6 = 1 << 5 + // etc.. + }; + enum Type { + TYPE_AREA = 0, + TYPE_RIGID_BODY, + TYPE_SOFT_BODY, + TYPE_KINEMATIC_GHOST_BODY + }; + + struct ShapeWrapper { + ShapeBullet *shape; + btCollisionShape *bt_shape; + btTransform transform; + bool active; + + ShapeWrapper() + : shape(NULL), bt_shape(NULL), active(true) {} + + ShapeWrapper(ShapeBullet *p_shape, const btTransform &p_transform, bool p_active) + : shape(p_shape), bt_shape(NULL), active(p_active) { + set_transform(p_transform); + } + + ShapeWrapper(ShapeBullet *p_shape, const Transform &p_transform, bool p_active) + : shape(p_shape), bt_shape(NULL), active(p_active) { + set_transform(p_transform); + } + ~ShapeWrapper(); + + ShapeWrapper(const ShapeWrapper &otherShape) { + operator=(otherShape); + } + + void operator=(const ShapeWrapper &otherShape) { + shape = otherShape.shape; + bt_shape = otherShape.bt_shape; + transform = otherShape.transform; + active = otherShape.active; + } + + void set_transform(const Transform &p_transform); + void set_transform(const btTransform &p_transform); + }; + +protected: + Type type; + ObjectID instance_id; + uint32_t collisionLayer; + uint32_t collisionMask; + bool collisionsEnabled; + bool m_isStatic; + bool ray_pickable; + btCollisionObject *bt_collision_object; + btVector3 body_scale; + SpaceBullet *space; + + VSet<RID> exceptions; + + /// This array is used to know all areas where this Object is overlapped in + /// New area is added when overlap with new area (AreaBullet::addOverlap), then is removed when it exit (CollisionObjectBullet::onExitArea) + /// This array is used mainly to know which area hold the pointer of this object + Vector<AreaBullet *> areasOverlapped; + +public: + CollisionObjectBullet(Type p_type); + virtual ~CollisionObjectBullet(); + + Type getType() { return type; } + +protected: + void destroyBulletCollisionObject(); + void setupBulletCollisionObject(btCollisionObject *p_collisionObject); + +public: + _FORCE_INLINE_ btCollisionObject *get_bt_collision_object() { return bt_collision_object; } + + _FORCE_INLINE_ void set_instance_id(const ObjectID &p_instance_id) { instance_id = p_instance_id; } + _FORCE_INLINE_ ObjectID get_instance_id() const { return instance_id; } + + _FORCE_INLINE_ bool is_static() const { return m_isStatic; } + + _FORCE_INLINE_ void set_ray_pickable(bool p_enable) { ray_pickable = p_enable; } + _FORCE_INLINE_ bool is_ray_pickable() const { return ray_pickable; } + + void set_body_scale(const Vector3 &p_new_scale); + virtual void on_body_scale_changed(); + + void add_collision_exception(const CollisionObjectBullet *p_ignoreCollisionObject); + void remove_collision_exception(const CollisionObjectBullet *p_ignoreCollisionObject); + bool has_collision_exception(const CollisionObjectBullet *p_otherCollisionObject) const; + _FORCE_INLINE_ const VSet<RID> &get_exceptions() const { return exceptions; } + + _FORCE_INLINE_ void set_collision_layer(uint32_t p_layer) { + collisionLayer = p_layer; + on_collision_filters_change(); + } + _FORCE_INLINE_ uint32_t get_collision_layer() const { return collisionLayer; } + + _FORCE_INLINE_ void set_collision_mask(uint32_t p_mask) { + collisionMask = p_mask; + on_collision_filters_change(); + } + _FORCE_INLINE_ uint32_t get_collision_mask() const { return collisionMask; } + + virtual void on_collision_filters_change() = 0; + + _FORCE_INLINE_ bool test_collision_mask(CollisionObjectBullet *p_other) const { + return collisionLayer & p_other->collisionMask || p_other->collisionLayer & collisionMask; + } + + virtual void reload_body() = 0; + virtual void set_space(SpaceBullet *p_space) = 0; + _FORCE_INLINE_ SpaceBullet *get_space() const { return space; } + /// This is an event that is called when a collision checker starts + virtual void on_collision_checker_start() = 0; + + virtual void dispatch_callbacks() = 0; + + void set_collision_enabled(bool p_enabled); + bool is_collisions_response_enabled(); + + void notify_new_overlap(AreaBullet *p_area); + virtual void on_enter_area(AreaBullet *p_area) = 0; + virtual void on_exit_area(AreaBullet *p_area); + + /// GodotObjectFlags + void set_godot_object_flags(int flags); + int get_godot_object_flags() const; + + void set_transform(const Transform &p_global_transform); + Transform get_transform() const; + virtual void set_transform__bullet(const btTransform &p_global_transform); + virtual const btTransform &get_transform__bullet() const; +}; + +class RigidCollisionObjectBullet : public CollisionObjectBullet, public ShapeOwnerBullet { +protected: + /// This is required to combine some shapes together. + /// Since Godot allow to have multiple shapes for each body with custom relative location, + /// each body will attach the shapes using this class even if there is only one shape. + btCompoundShape *compoundShape; + Vector<ShapeWrapper> shapes; + +public: + RigidCollisionObjectBullet(Type p_type); + ~RigidCollisionObjectBullet(); + + _FORCE_INLINE_ const Vector<ShapeWrapper> &get_shapes_wrappers() const { return shapes; } + + /// This is used to set new shape or replace existing + //virtual void _internal_replaceShape(btCollisionShape *p_old_shape, btCollisionShape *p_new_shape) = 0; + void add_shape(ShapeBullet *p_shape, const Transform &p_transform = Transform()); + void set_shape(int p_index, ShapeBullet *p_shape); + void set_shape_transform(int p_index, const Transform &p_transform); + virtual void remove_shape(ShapeBullet *p_shape); + void remove_shape(int p_index); + void remove_all_shapes(bool p_permanentlyFromThisBody = false); + + virtual void on_shape_changed(const ShapeBullet *const p_shape); + virtual void on_shapes_changed(); + + _FORCE_INLINE_ btCompoundShape *get_compound_shape() const { return compoundShape; } + int get_shape_count() const; + ShapeBullet *get_shape(int p_index) const; + btCollisionShape *get_bt_shape(int p_index) const; + Transform get_shape_transform(int p_index) const; + + void set_shape_disabled(int p_index, bool p_disabled); + bool is_shape_disabled(int p_index); + + virtual void on_body_scale_changed(); + +private: + void internal_shape_destroy(int p_index, bool p_permanentlyFromThisBody = false); +}; + +#endif diff --git a/modules/bullet/cone_twist_joint_bullet.cpp b/modules/bullet/cone_twist_joint_bullet.cpp new file mode 100644 index 0000000000..f6ac40e001 --- /dev/null +++ b/modules/bullet/cone_twist_joint_bullet.cpp @@ -0,0 +1,111 @@ +/*************************************************************************/ +/* cone_twist_joint_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 "cone_twist_joint_bullet.h" +#include "BulletDynamics/ConstraintSolver/btConeTwistConstraint.h" +#include "bullet_types_converter.h" +#include "bullet_utilities.h" +#include "rigid_body_bullet.h" + +ConeTwistJointBullet::ConeTwistJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &rbAFrame, const Transform &rbBFrame) + : JointBullet() { + btTransform btFrameA; + G_TO_B(rbAFrame, btFrameA); + if (rbB) { + btTransform btFrameB; + G_TO_B(rbBFrame, btFrameB); + coneConstraint = bulletnew(btConeTwistConstraint(*rbA->get_bt_rigid_body(), *rbB->get_bt_rigid_body(), btFrameA, btFrameB)); + } else { + coneConstraint = bulletnew(btConeTwistConstraint(*rbA->get_bt_rigid_body(), btFrameA)); + } + setup(coneConstraint); +} + +void ConeTwistJointBullet::set_angular_only(bool angularOnly) { + coneConstraint->setAngularOnly(angularOnly); +} + +void ConeTwistJointBullet::set_limit(real_t _swingSpan1, real_t _swingSpan2, real_t _twistSpan, real_t _softness, real_t _biasFactor, real_t _relaxationFactor) { + coneConstraint->setLimit(_swingSpan1, _swingSpan2, _twistSpan, _softness, _biasFactor, _relaxationFactor); +} + +int ConeTwistJointBullet::get_solve_twist_limit() { + return coneConstraint->getSolveTwistLimit(); +} + +int ConeTwistJointBullet::get_solve_swing_limit() { + return coneConstraint->getSolveSwingLimit(); +} + +real_t ConeTwistJointBullet::get_twist_limit_sign() { + return coneConstraint->getTwistLimitSign(); +} + +void ConeTwistJointBullet::set_param(PhysicsServer::ConeTwistJointParam p_param, real_t p_value) { + switch (p_param) { + case PhysicsServer::CONE_TWIST_JOINT_SWING_SPAN: + coneConstraint->setLimit(5, p_value); + coneConstraint->setLimit(4, p_value); + break; + case PhysicsServer::CONE_TWIST_JOINT_TWIST_SPAN: + coneConstraint->setLimit(3, p_value); + break; + case PhysicsServer::CONE_TWIST_JOINT_BIAS: + coneConstraint->setLimit(coneConstraint->getSwingSpan1(), coneConstraint->getSwingSpan2(), coneConstraint->getTwistSpan(), coneConstraint->getLimitSoftness(), p_value, coneConstraint->getRelaxationFactor()); + break; + case PhysicsServer::CONE_TWIST_JOINT_SOFTNESS: + coneConstraint->setLimit(coneConstraint->getSwingSpan1(), coneConstraint->getSwingSpan2(), coneConstraint->getTwistSpan(), p_value, coneConstraint->getBiasFactor(), coneConstraint->getRelaxationFactor()); + break; + case PhysicsServer::CONE_TWIST_JOINT_RELAXATION: + coneConstraint->setLimit(coneConstraint->getSwingSpan1(), coneConstraint->getSwingSpan2(), coneConstraint->getTwistSpan(), coneConstraint->getLimitSoftness(), coneConstraint->getBiasFactor(), p_value); + break; + default: + WARN_PRINT("This parameter is not supported by Bullet engine"); + } +} + +real_t ConeTwistJointBullet::get_param(PhysicsServer::ConeTwistJointParam p_param) const { + switch (p_param) { + case PhysicsServer::CONE_TWIST_JOINT_SWING_SPAN: + return coneConstraint->getSwingSpan1(); + case PhysicsServer::CONE_TWIST_JOINT_TWIST_SPAN: + return coneConstraint->getTwistSpan(); + case PhysicsServer::CONE_TWIST_JOINT_BIAS: + return coneConstraint->getBiasFactor(); + case PhysicsServer::CONE_TWIST_JOINT_SOFTNESS: + return coneConstraint->getLimitSoftness(); + case PhysicsServer::CONE_TWIST_JOINT_RELAXATION: + return coneConstraint->getRelaxationFactor(); + default: + WARN_PRINT("This parameter is not supported by Bullet engine"); + return 0; + } +} diff --git a/modules/bullet/cone_twist_joint_bullet.h b/modules/bullet/cone_twist_joint_bullet.h new file mode 100644 index 0000000000..1ce5ef9826 --- /dev/null +++ b/modules/bullet/cone_twist_joint_bullet.h @@ -0,0 +1,58 @@ +/*************************************************************************/ +/* cone_twist_joint_bullet.h */ +/* 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. */ +/*************************************************************************/ + +#ifndef CONE_TWIST_JOINT_BULLET_H +#define CONE_TWIST_JOINT_BULLET_H + +#include "joint_bullet.h" + +class RigidBodyBullet; + +class ConeTwistJointBullet : public JointBullet { + class btConeTwistConstraint *coneConstraint; + +public: + ConeTwistJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &rbAFrame, const Transform &rbBFrame); + + virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_CONE_TWIST; } + + void set_angular_only(bool angularOnly); + + void set_limit(real_t _swingSpan1, real_t _swingSpan2, real_t _twistSpan, real_t _softness = 0.8f, real_t _biasFactor = 0.3f, real_t _relaxationFactor = 1.0f); + int get_solve_twist_limit(); + + int get_solve_swing_limit(); + real_t get_twist_limit_sign(); + + void set_param(PhysicsServer::ConeTwistJointParam p_param, real_t p_value); + real_t get_param(PhysicsServer::ConeTwistJointParam p_param) const; +}; +#endif diff --git a/modules/bullet/config.py b/modules/bullet/config.py new file mode 100644 index 0000000000..b00ea18328 --- /dev/null +++ b/modules/bullet/config.py @@ -0,0 +1,6 @@ +def can_build(platform): + return True + +def configure(env): + pass + diff --git a/modules/bullet/constraint_bullet.cpp b/modules/bullet/constraint_bullet.cpp new file mode 100644 index 0000000000..08fc36f274 --- /dev/null +++ b/modules/bullet/constraint_bullet.cpp @@ -0,0 +1,50 @@ +/*************************************************************************/ +/* constraint_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 "constraint_bullet.h" +#include "collision_object_bullet.h" +#include "space_bullet.h" + +ConstraintBullet::ConstraintBullet() + : space(NULL), constraint(NULL) {} + +void ConstraintBullet::setup(btTypedConstraint *p_constraint) { + constraint = p_constraint; + constraint->setUserConstraintPtr(this); +} + +void ConstraintBullet::set_space(SpaceBullet *p_space) { + space = p_space; +} + +void ConstraintBullet::destroy_internal_constraint() { + space->remove_constraint(this); +} diff --git a/modules/bullet/constraint_bullet.h b/modules/bullet/constraint_bullet.h new file mode 100644 index 0000000000..b528ec6d7b --- /dev/null +++ b/modules/bullet/constraint_bullet.h @@ -0,0 +1,64 @@ +/*************************************************************************/ +/* constraint_bullet.h */ +/* 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. */ +/*************************************************************************/ + +#ifndef CONSTRAINT_BULLET_H +#define CONSTRAINT_BULLET_H + +#include "BulletDynamics/ConstraintSolver/btTypedConstraint.h" +#include "bullet_utilities.h" +#include "rid_bullet.h" + +class RigidBodyBullet; +class SpaceBullet; +class btTypedConstraint; + +class ConstraintBullet : public RIDBullet { + +protected: + SpaceBullet *space; + btTypedConstraint *constraint; + +public: + ConstraintBullet(); + + virtual void setup(btTypedConstraint *p_constraint); + virtual void set_space(SpaceBullet *p_space); + virtual void destroy_internal_constraint(); + +public: + virtual ~ConstraintBullet() { + bulletdelete(constraint); + constraint = NULL; + } + + _FORCE_INLINE_ btTypedConstraint *get_bt_constraint() { return constraint; } +}; +#endif diff --git a/modules/bullet/generic_6dof_joint_bullet.cpp b/modules/bullet/generic_6dof_joint_bullet.cpp new file mode 100644 index 0000000000..647396c24c --- /dev/null +++ b/modules/bullet/generic_6dof_joint_bullet.cpp @@ -0,0 +1,241 @@ +/*************************************************************************/ +/* generic_6dof_joint_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 "generic_6dof_joint_bullet.h" +#include "BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h" +#include "bullet_types_converter.h" +#include "bullet_utilities.h" +#include "rigid_body_bullet.h" + +Generic6DOFJointBullet::Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB, bool useLinearReferenceFrameA) + : JointBullet() { + + btTransform btFrameA; + G_TO_B(frameInA, btFrameA); + + if (rbB) { + btTransform btFrameB; + G_TO_B(frameInB, btFrameB); + + sixDOFConstraint = bulletnew(btGeneric6DofConstraint(*rbA->get_bt_rigid_body(), *rbB->get_bt_rigid_body(), btFrameA, btFrameB, useLinearReferenceFrameA)); + } else { + sixDOFConstraint = bulletnew(btGeneric6DofConstraint(*rbA->get_bt_rigid_body(), btFrameA, useLinearReferenceFrameA)); + } + + setup(sixDOFConstraint); +} + +Transform Generic6DOFJointBullet::getFrameOffsetA() const { + btTransform btTrs = sixDOFConstraint->getFrameOffsetA(); + Transform gTrs; + B_TO_G(btTrs, gTrs); + return gTrs; +} + +Transform Generic6DOFJointBullet::getFrameOffsetB() const { + btTransform btTrs = sixDOFConstraint->getFrameOffsetB(); + Transform gTrs; + B_TO_G(btTrs, gTrs); + return gTrs; +} + +Transform Generic6DOFJointBullet::getFrameOffsetA() { + btTransform btTrs = sixDOFConstraint->getFrameOffsetA(); + Transform gTrs; + B_TO_G(btTrs, gTrs); + return gTrs; +} + +Transform Generic6DOFJointBullet::getFrameOffsetB() { + btTransform btTrs = sixDOFConstraint->getFrameOffsetB(); + Transform gTrs; + B_TO_G(btTrs, gTrs); + return gTrs; +} + +void Generic6DOFJointBullet::set_linear_lower_limit(const Vector3 &linearLower) { + btVector3 btVec; + G_TO_B(linearLower, btVec); + sixDOFConstraint->setLinearLowerLimit(btVec); +} + +void Generic6DOFJointBullet::set_linear_upper_limit(const Vector3 &linearUpper) { + btVector3 btVec; + G_TO_B(linearUpper, btVec); + sixDOFConstraint->setLinearUpperLimit(btVec); +} + +void Generic6DOFJointBullet::set_angular_lower_limit(const Vector3 &angularLower) { + btVector3 btVec; + G_TO_B(angularLower, btVec); + sixDOFConstraint->setAngularLowerLimit(btVec); +} + +void Generic6DOFJointBullet::set_angular_upper_limit(const Vector3 &angularUpper) { + btVector3 btVec; + G_TO_B(angularUpper, btVec); + sixDOFConstraint->setAngularUpperLimit(btVec); +} + +void Generic6DOFJointBullet::set_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisParam p_param, real_t p_value) { + ERR_FAIL_INDEX(p_axis, 3); + switch (p_param) { + case PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT: + sixDOFConstraint->getTranslationalLimitMotor()->m_lowerLimit[p_axis] = p_value; + break; + case PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT: + sixDOFConstraint->getTranslationalLimitMotor()->m_upperLimit[p_axis] = p_value; + break; + case PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS: + sixDOFConstraint->getTranslationalLimitMotor()->m_limitSoftness = p_value; + break; + case PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION: + sixDOFConstraint->getTranslationalLimitMotor()->m_restitution = p_value; + break; + case PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING: + sixDOFConstraint->getTranslationalLimitMotor()->m_damping = p_value; + break; + case PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT: + sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_loLimit = p_value; + break; + case PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT: + sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_hiLimit = p_value; + break; + case PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS: + sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_limitSoftness = p_value; + break; + case PhysicsServer::G6DOF_JOINT_ANGULAR_DAMPING: + sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_damping = p_value; + break; + case PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION: + sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_bounce = p_value; + break; + case PhysicsServer::G6DOF_JOINT_ANGULAR_FORCE_LIMIT: + sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_maxLimitForce = p_value; + break; + case PhysicsServer::G6DOF_JOINT_ANGULAR_ERP: + sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_stopERP = p_value; + break; + case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY: + sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_targetVelocity = p_value; + break; + case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT: + sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_maxLimitForce = p_value; + break; + default: + WARN_PRINT("This parameter is not supported"); + } +} + +real_t Generic6DOFJointBullet::get_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisParam p_param) const { + ERR_FAIL_INDEX_V(p_axis, 3, 0.); + switch (p_param) { + case PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT: + return sixDOFConstraint->getTranslationalLimitMotor()->m_lowerLimit[p_axis]; + case PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT: + return sixDOFConstraint->getTranslationalLimitMotor()->m_upperLimit[p_axis]; + case PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS: + return sixDOFConstraint->getTranslationalLimitMotor()->m_limitSoftness; + case PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION: + return sixDOFConstraint->getTranslationalLimitMotor()->m_restitution; + case PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING: + return sixDOFConstraint->getTranslationalLimitMotor()->m_damping; + case PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT: + return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_loLimit; + case PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT: + return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_hiLimit; + case PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS: + return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_limitSoftness; + case PhysicsServer::G6DOF_JOINT_ANGULAR_DAMPING: + return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_damping; + case PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION: + return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_bounce; + case PhysicsServer::G6DOF_JOINT_ANGULAR_FORCE_LIMIT: + return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_maxLimitForce; + case PhysicsServer::G6DOF_JOINT_ANGULAR_ERP: + return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_stopERP; + case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY: + return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_targetVelocity; + case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT: + return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_maxLimitForce; + default: + WARN_PRINT("This parameter is not supported"); + return 0.; + } +} + +void Generic6DOFJointBullet::set_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag, bool p_value) { + ERR_FAIL_INDEX(p_axis, 3); + switch (p_flag) { + case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT: + if (p_value) { + if (!get_flag(p_axis, p_flag)) // avoid overwrite, if limited + sixDOFConstraint->setLimit(p_axis, 0, 0); // Limited + } else { + if (get_flag(p_axis, p_flag)) // avoid overwrite, if free + sixDOFConstraint->setLimit(p_axis, 0, -1); // Free + } + break; + case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT: { + int angularAxis = 3 + p_axis; + if (p_value) { + if (!get_flag(p_axis, p_flag)) // avoid overwrite, if Limited + sixDOFConstraint->setLimit(angularAxis, 0, 0); // Limited + } else { + if (get_flag(p_axis, p_flag)) // avoid overwrite, if free + sixDOFConstraint->setLimit(angularAxis, 0, -1); // Free + } + break; + } + case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_MOTOR: + //sixDOFConstraint->getTranslationalLimitMotor()->m_enableMotor[p_axis] = p_value; + sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_enableMotor = p_value; + break; + default: + WARN_PRINT("This flag is not supported by Bullet engine"); + } +} + +bool Generic6DOFJointBullet::get_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag) const { + ERR_FAIL_INDEX_V(p_axis, 3, false); + switch (p_flag) { + case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT: + return sixDOFConstraint->getTranslationalLimitMotor()->isLimited(p_axis); + case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT: + return sixDOFConstraint->getRotationalLimitMotor(p_axis)->isLimited(); + case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_MOTOR: + return //sixDOFConstraint->getTranslationalLimitMotor()->m_enableMotor[p_axis] && + sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_enableMotor; + default: + WARN_PRINT("This flag is not supported by Bullet engine"); + return false; + } +} diff --git a/modules/bullet/generic_6dof_joint_bullet.h b/modules/bullet/generic_6dof_joint_bullet.h new file mode 100644 index 0000000000..0d47b823de --- /dev/null +++ b/modules/bullet/generic_6dof_joint_bullet.h @@ -0,0 +1,65 @@ +/*************************************************************************/ +/* generic_6dof_joint_bullet.h */ +/* 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. */ +/*************************************************************************/ + +#ifndef GENERIC_6DOF_JOINT_BULLET_H +#define GENERIC_6DOF_JOINT_BULLET_H + +#include "joint_bullet.h" + +class RigidBodyBullet; + +class Generic6DOFJointBullet : public JointBullet { + class btGeneric6DofConstraint *sixDOFConstraint; + +public: + Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB, bool useLinearReferenceFrameA); + + virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_6DOF; } + + Transform getFrameOffsetA() const; + Transform getFrameOffsetB() const; + Transform getFrameOffsetA(); + Transform getFrameOffsetB(); + + void set_linear_lower_limit(const Vector3 &linearLower); + void set_linear_upper_limit(const Vector3 &linearUpper); + + void set_angular_lower_limit(const Vector3 &angularLower); + void set_angular_upper_limit(const Vector3 &angularUpper); + + void set_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisParam p_param, real_t p_value); + real_t get_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisParam p_param) const; + + void set_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag, bool p_value); + bool get_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag) const; +}; + +#endif diff --git a/modules/bullet/godot_collision_configuration.cpp b/modules/bullet/godot_collision_configuration.cpp new file mode 100644 index 0000000000..4e4228cc48 --- /dev/null +++ b/modules/bullet/godot_collision_configuration.cpp @@ -0,0 +1,91 @@ +/*************************************************************************/ +/* godot_collision_configuration.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 "godot_collision_configuration.h" +#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" +#include "BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h" +#include "godot_ray_world_algorithm.h" + +GodotCollisionConfiguration::GodotCollisionConfiguration(const btDiscreteDynamicsWorld *world, const btDefaultCollisionConstructionInfo &constructionInfo) + : btDefaultCollisionConfiguration(constructionInfo) { + + void *mem = NULL; + + mem = btAlignedAlloc(sizeof(GodotRayWorldAlgorithm::CreateFunc), 16); + m_rayWorldCF = new (mem) GodotRayWorldAlgorithm::CreateFunc(world); + + mem = btAlignedAlloc(sizeof(GodotRayWorldAlgorithm::SwappedCreateFunc), 16); + m_swappedRayWorldCF = new (mem) GodotRayWorldAlgorithm::SwappedCreateFunc(world); +} + +GodotCollisionConfiguration::~GodotCollisionConfiguration() { + m_rayWorldCF->~btCollisionAlgorithmCreateFunc(); + btAlignedFree(m_rayWorldCF); + + m_swappedRayWorldCF->~btCollisionAlgorithmCreateFunc(); + btAlignedFree(m_swappedRayWorldCF); +} + +btCollisionAlgorithmCreateFunc *GodotCollisionConfiguration::getCollisionAlgorithmCreateFunc(int proxyType0, int proxyType1) { + + if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType0 && CUSTOM_CONVEX_SHAPE_TYPE == proxyType1) { + + // This collision is not supported + return m_emptyCreateFunc; + } else if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType0) { + + return m_rayWorldCF; + } else if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType1) { + + return m_swappedRayWorldCF; + } else { + + return btDefaultCollisionConfiguration::getCollisionAlgorithmCreateFunc(proxyType0, proxyType1); + } +} + +btCollisionAlgorithmCreateFunc *GodotCollisionConfiguration::getClosestPointsAlgorithmCreateFunc(int proxyType0, int proxyType1) { + + if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType0 && CUSTOM_CONVEX_SHAPE_TYPE == proxyType1) { + + // This collision is not supported + return m_emptyCreateFunc; + } else if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType0) { + + return m_rayWorldCF; + } else if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType1) { + + return m_swappedRayWorldCF; + } else { + + return btDefaultCollisionConfiguration::getClosestPointsAlgorithmCreateFunc(proxyType0, proxyType1); + } +} diff --git a/modules/bullet/godot_collision_configuration.h b/modules/bullet/godot_collision_configuration.h new file mode 100644 index 0000000000..ed99065f8c --- /dev/null +++ b/modules/bullet/godot_collision_configuration.h @@ -0,0 +1,50 @@ +/*************************************************************************/ +/* godot_collision_configuration.h */ +/* 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. */ +/*************************************************************************/ + +#ifndef GODOT_COLLISION_CONFIGURATION_H +#define GODOT_COLLISION_CONFIGURATION_H + +#include "BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h" + +class btDiscreteDynamicsWorld; + +class GodotCollisionConfiguration : public btDefaultCollisionConfiguration { + btCollisionAlgorithmCreateFunc *m_rayWorldCF; + btCollisionAlgorithmCreateFunc *m_swappedRayWorldCF; + +public: + GodotCollisionConfiguration(const btDiscreteDynamicsWorld *world, const btDefaultCollisionConstructionInfo &constructionInfo = btDefaultCollisionConstructionInfo()); + virtual ~GodotCollisionConfiguration(); + + virtual btCollisionAlgorithmCreateFunc *getCollisionAlgorithmCreateFunc(int proxyType0, int proxyType1); + virtual btCollisionAlgorithmCreateFunc *getClosestPointsAlgorithmCreateFunc(int proxyType0, int proxyType1); +}; +#endif diff --git a/modules/bullet/godot_collision_dispatcher.cpp b/modules/bullet/godot_collision_dispatcher.cpp new file mode 100644 index 0000000000..ea75e4eef4 --- /dev/null +++ b/modules/bullet/godot_collision_dispatcher.cpp @@ -0,0 +1,54 @@ +/*************************************************************************/ +/* godot_collision_dispatcher.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 "godot_collision_dispatcher.h" +#include "collision_object_bullet.h" + +const int GodotCollisionDispatcher::CASTED_TYPE_AREA = static_cast<int>(CollisionObjectBullet::TYPE_AREA); + +GodotCollisionDispatcher::GodotCollisionDispatcher(btCollisionConfiguration *collisionConfiguration) + : btCollisionDispatcher(collisionConfiguration) {} + +bool GodotCollisionDispatcher::needsCollision(const btCollisionObject *body0, const btCollisionObject *body1) { + if (body0->getUserIndex() == CASTED_TYPE_AREA || body1->getUserIndex() == CASTED_TYPE_AREA) { + // Avoide area narrow phase + return false; + } + return btCollisionDispatcher::needsCollision(body0, body1); +} + +bool GodotCollisionDispatcher::needsResponse(const btCollisionObject *body0, const btCollisionObject *body1) { + if (body0->getUserIndex() == CASTED_TYPE_AREA || body1->getUserIndex() == CASTED_TYPE_AREA) { + // Avoide area narrow phase + return false; + } + return btCollisionDispatcher::needsResponse(body0, body1); +} diff --git a/modules/bullet/godot_collision_dispatcher.h b/modules/bullet/godot_collision_dispatcher.h new file mode 100644 index 0000000000..501b2078dd --- /dev/null +++ b/modules/bullet/godot_collision_dispatcher.h @@ -0,0 +1,48 @@ +/*************************************************************************/ +/* godot_collision_dispatcher.h */ +/* 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. */ +/*************************************************************************/ + +#ifndef GODOT_COLLISION_DISPATCHER_H +#define GODOT_COLLISION_DISPATCHER_H + +#include "int_types.h" +#include <btBulletDynamicsCommon.h> + +/// This class is required to implement custom collision behaviour in the narrowphase +class GodotCollisionDispatcher : public btCollisionDispatcher { +private: + static const int CASTED_TYPE_AREA; + +public: + GodotCollisionDispatcher(btCollisionConfiguration *collisionConfiguration); + virtual bool needsCollision(const btCollisionObject *body0, const btCollisionObject *body1); + virtual bool needsResponse(const btCollisionObject *body0, const btCollisionObject *body1); +}; +#endif diff --git a/modules/bullet/godot_motion_state.h b/modules/bullet/godot_motion_state.h new file mode 100644 index 0000000000..5111807394 --- /dev/null +++ b/modules/bullet/godot_motion_state.h @@ -0,0 +1,96 @@ +/*************************************************************************/ +/* godot_motion_state.h */ +/* 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. */ +/*************************************************************************/ + +#ifndef GODOT_MOTION_STATE_H +#define GODOT_MOTION_STATE_H + +#include "LinearMath/btMotionState.h" +#include "rigid_body_bullet.h" + +class RigidBodyBullet; + +// This clas is responsible to move kinematic actor +// and sincronize rendering engine with Bullet +/// DOC: +/// http://www.bulletphysics.org/mediawiki-1.5.8/index.php/MotionStates#What.27s_a_MotionState.3F +class GodotMotionState : public btMotionState { + + /// This data is used to store the new world position for kinematic body + btTransform bodyKinematicWorldTransf; + /// This data is used to store last world position + btTransform bodyCurrentWorldTransform; + + RigidBodyBullet *owner; + +public: + GodotMotionState(RigidBodyBullet *p_owner) + : bodyKinematicWorldTransf(btMatrix3x3(1., 0., 0., 0., 1., 0., 0., 0., 1.), btVector3(0., 0., 0.)), + bodyCurrentWorldTransform(btMatrix3x3(1., 0., 0., 0., 1., 0., 0., 0., 1.), btVector3(0., 0., 0.)), + owner(p_owner) {} + + /// IMPORTANT DON'T USE THIS FUNCTION TO KNOW THE CURRENT BODY TRANSFORM + /// This class is used internally by Bullet + /// Use GodotMotionState::getCurrentWorldTransform to know current position + /// + /// This function is used by Bullet to get the position of object in the world + /// if the body is kinematic Bullet will move the object to this location + /// if the body is static Bullet doesn't move at all + virtual void getWorldTransform(btTransform &worldTrans) const { + worldTrans = bodyKinematicWorldTransf; + } + + /// IMPORTANT: to move the body use: moveBody + /// IMPORTANT: DON'T CALL THIS FUNCTION, IT IS CALLED BY BULLET TO UPDATE RENDERING ENGINE + /// + /// This function is called each time by Bullet and set the current position of body + /// inside the physics world. + /// Don't allow Godot rendering scene takes world transform from this object because + /// the correct transform is set by Bullet only after the last step when there are sub steps + /// This function must update Godot transform rendering scene for this object. + virtual void setWorldTransform(const btTransform &worldTrans) { + bodyCurrentWorldTransform = worldTrans; + + owner->scratch(); + } + +public: + /// Use this function to move kinematic body + /// -- or set initial transfom before body creation. + void moveBody(const btTransform &newWorldTransform) { + bodyKinematicWorldTransf = newWorldTransform; + } + + /// It returns the current body transform from last Bullet update + const btTransform &getCurrentWorldTransform() const { + return bodyCurrentWorldTransform; + } +}; +#endif diff --git a/modules/bullet/godot_ray_world_algorithm.cpp b/modules/bullet/godot_ray_world_algorithm.cpp new file mode 100644 index 0000000000..98daf8398e --- /dev/null +++ b/modules/bullet/godot_ray_world_algorithm.cpp @@ -0,0 +1,104 @@ +/*************************************************************************/ +/* godot_ray_world_algorithm.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 "godot_ray_world_algorithm.h" +#include "BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h" +#include "btRayShape.h" +#include "collision_object_bullet.h" + +GodotRayWorldAlgorithm::CreateFunc::CreateFunc(const btDiscreteDynamicsWorld *world) + : m_world(world) {} + +GodotRayWorldAlgorithm::SwappedCreateFunc::SwappedCreateFunc(const btDiscreteDynamicsWorld *world) + : m_world(world) {} + +GodotRayWorldAlgorithm::GodotRayWorldAlgorithm(const btDiscreteDynamicsWorld *world, btPersistentManifold *mf, const btCollisionAlgorithmConstructionInfo &ci, const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap, bool isSwapped) + : btActivatingCollisionAlgorithm(ci, body0Wrap, body1Wrap), + m_manifoldPtr(mf), + m_ownManifold(false), + m_world(world), + m_isSwapped(isSwapped) {} + +GodotRayWorldAlgorithm::~GodotRayWorldAlgorithm() { + if (m_ownManifold && m_manifoldPtr) { + m_dispatcher->releaseManifold(m_manifoldPtr); + } +} + +void GodotRayWorldAlgorithm::processCollision(const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap, const btDispatcherInfo &dispatchInfo, btManifoldResult *resultOut) { + + if (!m_manifoldPtr) { + if (m_isSwapped) { + m_manifoldPtr = m_dispatcher->getNewManifold(body1Wrap->getCollisionObject(), body0Wrap->getCollisionObject()); + } else { + m_manifoldPtr = m_dispatcher->getNewManifold(body0Wrap->getCollisionObject(), body1Wrap->getCollisionObject()); + } + m_ownManifold = true; + } + m_manifoldPtr->clearManifold(); + resultOut->setPersistentManifold(m_manifoldPtr); + + const btRayShape *ray_shape; + btTransform ray_transform; + + const btCollisionObjectWrapper *other_co_wrapper; + + if (m_isSwapped) { + + ray_shape = static_cast<const btRayShape *>(body1Wrap->getCollisionShape()); + ray_transform = body1Wrap->getWorldTransform(); + + other_co_wrapper = body0Wrap; + } else { + + ray_shape = static_cast<const btRayShape *>(body0Wrap->getCollisionShape()); + ray_transform = body0Wrap->getWorldTransform(); + + other_co_wrapper = body1Wrap; + } + + btTransform to(ray_transform * ray_shape->getSupportPoint()); + + btCollisionWorld::ClosestRayResultCallback btResult(ray_transform.getOrigin(), to.getOrigin()); + + m_world->rayTestSingleInternal(ray_transform, to, other_co_wrapper, btResult); + + if (btResult.hasHit()) { + btVector3 ray_normal(to.getOrigin() - ray_transform.getOrigin()); + ray_normal.normalize(); + ray_normal *= -1; + resultOut->addContactPoint(ray_normal, btResult.m_hitPointWorld, ray_shape->getScaledLength() * (btResult.m_closestHitFraction - 1)); + } +} + +btScalar GodotRayWorldAlgorithm::calculateTimeOfImpact(btCollisionObject *body0, btCollisionObject *body1, const btDispatcherInfo &dispatchInfo, btManifoldResult *resultOut) { + return 1; +} diff --git a/modules/bullet/godot_ray_world_algorithm.h b/modules/bullet/godot_ray_world_algorithm.h new file mode 100644 index 0000000000..15c71b8d7d --- /dev/null +++ b/modules/bullet/godot_ray_world_algorithm.h @@ -0,0 +1,83 @@ +/*************************************************************************/ +/* godot_ray_world_algorithm.h */ +/* 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. */ +/*************************************************************************/ + +#ifndef GODOT_RAY_WORLD_ALGORITHM_H +#define GODOT_RAY_WORLD_ALGORITHM_H + +#include "BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.h" +#include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" +#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" + +class btDiscreteDynamicsWorld; + +class GodotRayWorldAlgorithm : public btActivatingCollisionAlgorithm { + + const btDiscreteDynamicsWorld *m_world; + btPersistentManifold *m_manifoldPtr; + bool m_ownManifold; + bool m_isSwapped; + +public: + GodotRayWorldAlgorithm(const btDiscreteDynamicsWorld *m_world, btPersistentManifold *mf, const btCollisionAlgorithmConstructionInfo &ci, const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap, bool isSwapped); + virtual ~GodotRayWorldAlgorithm(); + + virtual void processCollision(const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap, const btDispatcherInfo &dispatchInfo, btManifoldResult *resultOut); + virtual btScalar calculateTimeOfImpact(btCollisionObject *body0, btCollisionObject *body1, const btDispatcherInfo &dispatchInfo, btManifoldResult *resultOut); + + virtual void getAllContactManifolds(btManifoldArray &manifoldArray) { + ///should we use m_ownManifold to avoid adding duplicates? + if (m_manifoldPtr && m_ownManifold) + manifoldArray.push_back(m_manifoldPtr); + } + struct CreateFunc : public btCollisionAlgorithmCreateFunc { + + const btDiscreteDynamicsWorld *m_world; + CreateFunc(const btDiscreteDynamicsWorld *world); + + virtual btCollisionAlgorithm *CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo &ci, const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap) { + void *mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(GodotRayWorldAlgorithm)); + return new (mem) GodotRayWorldAlgorithm(m_world, ci.m_manifold, ci, body0Wrap, body1Wrap, false); + } + }; + + struct SwappedCreateFunc : public btCollisionAlgorithmCreateFunc { + + const btDiscreteDynamicsWorld *m_world; + SwappedCreateFunc(const btDiscreteDynamicsWorld *world); + + virtual btCollisionAlgorithm *CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo &ci, const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap) { + void *mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(GodotRayWorldAlgorithm)); + return new (mem) GodotRayWorldAlgorithm(m_world, ci.m_manifold, ci, body0Wrap, body1Wrap, true); + } + }; +}; + +#endif // GODOT_RAY_WORLD_ALGORITHM_H diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp new file mode 100644 index 0000000000..409d12f080 --- /dev/null +++ b/modules/bullet/godot_result_callbacks.cpp @@ -0,0 +1,291 @@ +/*************************************************************************/ +/* godot_result_callbacks.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 "godot_result_callbacks.h" +#include "bullet_types_converter.h" +#include "collision_object_bullet.h" +#include "rigid_body_bullet.h" + +bool GodotFilterCallback::test_collision_filters(uint32_t body0_collision_layer, uint32_t body0_collision_mask, uint32_t body1_collision_layer, uint32_t body1_collision_mask) { + return body0_collision_layer & body1_collision_mask || body1_collision_layer & body0_collision_mask; +} + +bool GodotFilterCallback::needBroadphaseCollision(btBroadphaseProxy *proxy0, btBroadphaseProxy *proxy1) const { + return GodotFilterCallback::test_collision_filters(proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask, proxy1->m_collisionFilterGroup, proxy1->m_collisionFilterMask); +} + +bool GodotClosestRayResultCallback::needsCollision(btBroadphaseProxy *proxy0) const { + const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask); + if (needs) { + btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); + CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); + if (m_pickRay && gObj->is_ray_pickable()) { + return true; + } else if (m_exclude->has(gObj->get_self())) { + return false; + } + return true; + } else { + return false; + } +} + +bool GodotAllConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) const { + const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask); + if (needs) { + btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); + CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); + if (m_exclude->has(gObj->get_self())) { + return false; + } + return true; + } else { + return false; + } +} + +btScalar GodotAllConvexResultCallback::addSingleResult(btCollisionWorld::LocalConvexResult &convexResult, bool normalInWorldSpace) { + CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(convexResult.m_hitCollisionObject->getUserPointer()); + + PhysicsDirectSpaceState::ShapeResult &result = m_results[count]; + + result.shape = convexResult.m_localShapeInfo->m_shapePart; + result.rid = gObj->get_self(); + result.collider_id = gObj->get_instance_id(); + result.collider = 0 == result.collider_id ? NULL : ObjectDB::get_instance(result.collider_id); + + ++count; + return count < m_resultMax; +} + +bool GodotKinClosestConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) const { + const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask); + if (needs) { + btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); + CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); + if (gObj == m_self_object) { + return false; + } else { + if (m_ignore_areas && gObj->getType() == CollisionObjectBullet::TYPE_AREA) { + return false; + } else if (m_self_object->has_collision_exception(gObj)) { + return false; + } + } + return true; + } else { + return false; + } +} + +bool GodotClosestConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) const { + const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask); + if (needs) { + btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); + CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); + if (m_exclude->has(gObj->get_self())) { + return false; + } + return true; + } else { + return false; + } +} + +btScalar GodotClosestConvexResultCallback::addSingleResult(btCollisionWorld::LocalConvexResult &convexResult, bool normalInWorldSpace) { + btScalar res = btCollisionWorld::ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace); + m_shapePart = convexResult.m_localShapeInfo->m_shapePart; + return res; +} + +bool GodotAllContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) const { + const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask); + if (needs) { + btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); + CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); + if (m_exclude->has(gObj->get_self())) { + return false; + } + return true; + } else { + return false; + } +} + +btScalar GodotAllContactResultCallback::addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1) { + + if (cp.getDistance() <= 0) { + + PhysicsDirectSpaceState::ShapeResult &result = m_results[m_count]; + // Penetrated + + CollisionObjectBullet *colObj; + if (m_self_object == colObj0Wrap->getCollisionObject()) { + colObj = static_cast<CollisionObjectBullet *>(colObj1Wrap->getCollisionObject()->getUserPointer()); + result.shape = cp.m_index1; + } else { + colObj = static_cast<CollisionObjectBullet *>(colObj0Wrap->getCollisionObject()->getUserPointer()); + result.shape = cp.m_index0; + } + + if (colObj) + result.collider_id = colObj->get_instance_id(); + else + result.collider_id = 0; + result.collider = 0 == result.collider_id ? NULL : ObjectDB::get_instance(result.collider_id); + result.rid = colObj->get_self(); + ++m_count; + } + + return m_count < m_resultMax; +} + +bool GodotContactPairContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) const { + const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask); + if (needs) { + btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); + CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); + if (m_exclude->has(gObj->get_self())) { + return false; + } + return true; + } else { + return false; + } +} + +btScalar GodotContactPairContactResultCallback::addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1) { + + if (m_self_object == colObj0Wrap->getCollisionObject()) { + B_TO_G(cp.m_localPointA, m_results[m_count * 2 + 0]); // Local contact + B_TO_G(cp.m_localPointB, m_results[m_count * 2 + 1]); + } else { + B_TO_G(cp.m_localPointB, m_results[m_count * 2 + 0]); // Local contact + B_TO_G(cp.m_localPointA, m_results[m_count * 2 + 1]); + } + + ++m_count; + + return m_count < m_resultMax; +} + +bool GodotRestInfoContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) const { + const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask); + if (needs) { + btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); + CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); + if (m_exclude->has(gObj->get_self())) { + return false; + } + return true; + } else { + return false; + } +} + +btScalar GodotRestInfoContactResultCallback::addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1) { + + if (cp.getDistance() <= m_min_distance) { + m_min_distance = cp.getDistance(); + + CollisionObjectBullet *colObj; + if (m_self_object == colObj0Wrap->getCollisionObject()) { + colObj = static_cast<CollisionObjectBullet *>(colObj1Wrap->getCollisionObject()->getUserPointer()); + m_result->shape = cp.m_index1; + B_TO_G(cp.getPositionWorldOnB(), m_result->point); + m_rest_info_bt_point = cp.getPositionWorldOnB(); + m_rest_info_collision_object = colObj1Wrap->getCollisionObject(); + } else { + colObj = static_cast<CollisionObjectBullet *>(colObj0Wrap->getCollisionObject()->getUserPointer()); + m_result->shape = cp.m_index0; + B_TO_G(cp.m_normalWorldOnB * -1, m_result->normal); + m_rest_info_bt_point = cp.getPositionWorldOnA(); + m_rest_info_collision_object = colObj0Wrap->getCollisionObject(); + } + + if (colObj) + m_result->collider_id = colObj->get_instance_id(); + else + m_result->collider_id = 0; + m_result->rid = colObj->get_self(); + + m_collided = true; + } + + return cp.getDistance(); +} + +bool GodotRecoverAndClosestContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) const { + const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask); + if (needs) { + btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); + CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); + if (gObj == m_self_object) { + return false; + } else { + if (m_ignore_areas && gObj->getType() == CollisionObjectBullet::TYPE_AREA) { + return false; + } else if (m_self_object->has_collision_exception(gObj)) { + return false; + } + } + return true; + } else { + return false; + } +} + +btScalar GodotRecoverAndClosestContactResultCallback::addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1) { + + if (cp.getDistance() < -MAX_PENETRATION_DEPTH) { + if (m_most_penetrated_distance > cp.getDistance()) { + m_most_penetrated_distance = cp.getDistance(); + + // take other object + btScalar sign(1); + if (m_self_object == colObj0Wrap->getCollisionObject()->getUserPointer()) { + m_pointCollisionObject = colObj1Wrap->getCollisionObject(); + m_other_compound_shape_index = cp.m_index1; + } else { + m_pointCollisionObject = colObj0Wrap->getCollisionObject(); + sign = -1; + m_other_compound_shape_index = cp.m_index0; + } + + m_pointNormalWorld = cp.m_normalWorldOnB * sign; + m_pointWorld = cp.getPositionWorldOnB(); + m_penetration_distance = cp.getDistance(); + + m_recover_penetration -= cp.m_normalWorldOnB * sign * (cp.getDistance() + MAX_PENETRATION_DEPTH); + } + } + return 1; +} diff --git a/modules/bullet/godot_result_callbacks.h b/modules/bullet/godot_result_callbacks.h new file mode 100644 index 0000000000..d505bd0de1 --- /dev/null +++ b/modules/bullet/godot_result_callbacks.h @@ -0,0 +1,189 @@ +/*************************************************************************/ +/* godot_result_callbacks.h */ +/* 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. */ +/*************************************************************************/ + +#ifndef GODOT_RESULT_CALLBACKS_H +#define GODOT_RESULT_CALLBACKS_H + +#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" +#include "btBulletDynamicsCommon.h" +#include "servers/physics_server.h" + +#define MAX_PENETRATION_DEPTH 0.005 + +class RigidBodyBullet; + +/// This class is required to implement custom collision behaviour in the broadphase +struct GodotFilterCallback : public btOverlapFilterCallback { + static bool test_collision_filters(uint32_t body0_collision_layer, uint32_t body0_collision_mask, uint32_t body1_collision_layer, uint32_t body1_collision_mask); + + // return true when pairs need collision + virtual bool needBroadphaseCollision(btBroadphaseProxy *proxy0, btBroadphaseProxy *proxy1) const; +}; + +/// It performs an additional check allow exclusions. +struct GodotClosestRayResultCallback : public btCollisionWorld::ClosestRayResultCallback { + const Set<RID> *m_exclude; + bool m_pickRay; + +public: + GodotClosestRayResultCallback(const btVector3 &rayFromWorld, const btVector3 &rayToWorld, const Set<RID> *p_exclude) + : btCollisionWorld::ClosestRayResultCallback(rayFromWorld, rayToWorld), m_exclude(p_exclude), m_pickRay(false) {} + + virtual bool needsCollision(btBroadphaseProxy *proxy0) const; +}; + +// store all colliding object +struct GodotAllConvexResultCallback : public btCollisionWorld::ConvexResultCallback { +public: + PhysicsDirectSpaceState::ShapeResult *m_results; + int m_resultMax; + int count; + const Set<RID> *m_exclude; + + GodotAllConvexResultCallback(PhysicsDirectSpaceState::ShapeResult *p_results, int p_resultMax, const Set<RID> *p_exclude) + : m_results(p_results), m_exclude(p_exclude), m_resultMax(p_resultMax), count(0) {} + + virtual bool needsCollision(btBroadphaseProxy *proxy0) const; + + virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult &convexResult, bool normalInWorldSpace); +}; + +struct GodotKinClosestConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback { +public: + const RigidBodyBullet *m_self_object; + const bool m_ignore_areas; + + GodotKinClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const RigidBodyBullet *p_self_object, bool p_ignore_areas) + : btCollisionWorld::ClosestConvexResultCallback(convexFromWorld, convexToWorld), m_self_object(p_self_object), m_ignore_areas(p_ignore_areas) {} + + virtual bool needsCollision(btBroadphaseProxy *proxy0) const; +}; + +struct GodotClosestConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback { +public: + const Set<RID> *m_exclude; + int m_shapePart; + + GodotClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const Set<RID> *p_exclude) + : btCollisionWorld::ClosestConvexResultCallback(convexFromWorld, convexToWorld), m_exclude(p_exclude) {} + + virtual bool needsCollision(btBroadphaseProxy *proxy0) const; + + virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult &convexResult, bool normalInWorldSpace); +}; + +struct GodotAllContactResultCallback : public btCollisionWorld::ContactResultCallback { +public: + const btCollisionObject *m_self_object; + PhysicsDirectSpaceState::ShapeResult *m_results; + int m_resultMax; + int m_count; + const Set<RID> *m_exclude; + + GodotAllContactResultCallback(btCollisionObject *p_self_object, PhysicsDirectSpaceState::ShapeResult *p_results, int p_resultMax, const Set<RID> *p_exclude) + : m_self_object(p_self_object), m_results(p_results), m_exclude(p_exclude), m_resultMax(p_resultMax), m_count(0) {} + + virtual bool needsCollision(btBroadphaseProxy *proxy0) const; + + virtual btScalar addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1); +}; + +/// Returns the list of contacts pairs in this order: Local contact, other body contact +struct GodotContactPairContactResultCallback : public btCollisionWorld::ContactResultCallback { +public: + const btCollisionObject *m_self_object; + Vector3 *m_results; + int m_resultMax; + int m_count; + const Set<RID> *m_exclude; + + GodotContactPairContactResultCallback(btCollisionObject *p_self_object, Vector3 *p_results, int p_resultMax, const Set<RID> *p_exclude) + : m_self_object(p_self_object), m_results(p_results), m_exclude(p_exclude), m_resultMax(p_resultMax), m_count(0) {} + + virtual bool needsCollision(btBroadphaseProxy *proxy0) const; + + virtual btScalar addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1); +}; + +struct GodotRestInfoContactResultCallback : public btCollisionWorld::ContactResultCallback { +public: + const btCollisionObject *m_self_object; + PhysicsDirectSpaceState::ShapeRestInfo *m_result; + bool m_collided; + real_t m_min_distance; + const btCollisionObject *m_rest_info_collision_object; + btVector3 m_rest_info_bt_point; + const Set<RID> *m_exclude; + + GodotRestInfoContactResultCallback(btCollisionObject *p_self_object, PhysicsDirectSpaceState::ShapeRestInfo *p_result, const Set<RID> *p_exclude) + : m_self_object(p_self_object), m_result(p_result), m_exclude(p_exclude), m_collided(false), m_min_distance(0) {} + + virtual bool needsCollision(btBroadphaseProxy *proxy0) const; + + virtual btScalar addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1); +}; + +struct GodotRecoverAndClosestContactResultCallback : public btCollisionWorld::ContactResultCallback { +public: + btVector3 m_pointNormalWorld; + btVector3 m_pointWorld; + btScalar m_penetration_distance; + int m_other_compound_shape_index; + const btCollisionObject *m_pointCollisionObject; + + const RigidBodyBullet *m_self_object; + bool m_ignore_areas; + + btScalar m_most_penetrated_distance; + btVector3 m_recover_penetration; + + GodotRecoverAndClosestContactResultCallback() + : m_pointCollisionObject(NULL), m_penetration_distance(0), m_other_compound_shape_index(0), m_self_object(NULL), m_ignore_areas(true), m_most_penetrated_distance(1e20), m_recover_penetration(0, 0, 0) {} + + GodotRecoverAndClosestContactResultCallback(const RigidBodyBullet *p_self_object, bool p_ignore_areas) + : m_pointCollisionObject(NULL), m_penetration_distance(0), m_other_compound_shape_index(0), m_self_object(p_self_object), m_ignore_areas(p_ignore_areas), m_most_penetrated_distance(9999999999), m_recover_penetration(0, 0, 0) {} + + void reset() { + m_pointCollisionObject = NULL; + m_most_penetrated_distance = 1e20; + m_recover_penetration.setZero(); + } + + bool hasHit() { + return m_pointCollisionObject; + } + + virtual bool needsCollision(btBroadphaseProxy *proxy0) const; + + virtual btScalar addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1); +}; + +#endif // GODOT_RESULT_CALLBACKS_H diff --git a/modules/bullet/hinge_joint_bullet.cpp b/modules/bullet/hinge_joint_bullet.cpp new file mode 100644 index 0000000000..bb70babd99 --- /dev/null +++ b/modules/bullet/hinge_joint_bullet.cpp @@ -0,0 +1,163 @@ +/*************************************************************************/ +/* hinge_joint_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 "hinge_joint_bullet.h" +#include "BulletDynamics/ConstraintSolver/btHingeConstraint.h" +#include "bullet_types_converter.h" +#include "bullet_utilities.h" +#include "rigid_body_bullet.h" + +HingeJointBullet::HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameA, const Transform &frameB) + : JointBullet() { + btTransform btFrameA; + G_TO_B(frameA, btFrameA); + + if (rbB) { + btTransform btFrameB; + G_TO_B(frameB, btFrameB); + + hingeConstraint = bulletnew(btHingeConstraint(*rbA->get_bt_rigid_body(), *rbB->get_bt_rigid_body(), btFrameA, btFrameB)); + } else { + + hingeConstraint = bulletnew(btHingeConstraint(*rbA->get_bt_rigid_body(), btFrameA)); + } + + setup(hingeConstraint); +} + +HingeJointBullet::HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Vector3 &pivotInA, const Vector3 &pivotInB, const Vector3 &axisInA, const Vector3 &axisInB) + : JointBullet() { + + btVector3 btPivotA; + btVector3 btAxisA; + G_TO_B(pivotInA, btPivotA); + G_TO_B(axisInA, btAxisA); + + if (rbB) { + btVector3 btPivotB; + btVector3 btAxisB; + G_TO_B(pivotInB, btPivotB); + G_TO_B(axisInB, btAxisB); + + hingeConstraint = bulletnew(btHingeConstraint(*rbA->get_bt_rigid_body(), *rbB->get_bt_rigid_body(), btPivotA, btPivotB, btAxisA, btAxisB)); + } else { + + hingeConstraint = bulletnew(btHingeConstraint(*rbA->get_bt_rigid_body(), btPivotA, btAxisA)); + } + + setup(hingeConstraint); +} + +real_t HingeJointBullet::get_hinge_angle() { + return hingeConstraint->getHingeAngle(); +} + +void HingeJointBullet::set_param(PhysicsServer::HingeJointParam p_param, real_t p_value) { + switch (p_param) { + case PhysicsServer::HINGE_JOINT_BIAS: + if (0 < p_value) { + print_line("The Bullet Hinge Joint doesn't support bias, So it's always 0"); + } + break; + case PhysicsServer::HINGE_JOINT_LIMIT_UPPER: + hingeConstraint->setLimit(hingeConstraint->getLowerLimit(), p_value, hingeConstraint->getLimitSoftness(), hingeConstraint->getLimitBiasFactor(), hingeConstraint->getLimitRelaxationFactor()); + break; + case PhysicsServer::HINGE_JOINT_LIMIT_LOWER: + hingeConstraint->setLimit(p_value, hingeConstraint->getUpperLimit(), hingeConstraint->getLimitSoftness(), hingeConstraint->getLimitBiasFactor(), hingeConstraint->getLimitRelaxationFactor()); + break; + case PhysicsServer::HINGE_JOINT_LIMIT_BIAS: + hingeConstraint->setLimit(hingeConstraint->getLowerLimit(), hingeConstraint->getUpperLimit(), hingeConstraint->getLimitSoftness(), p_value, hingeConstraint->getLimitRelaxationFactor()); + break; + case PhysicsServer::HINGE_JOINT_LIMIT_SOFTNESS: + hingeConstraint->setLimit(hingeConstraint->getLowerLimit(), hingeConstraint->getUpperLimit(), p_value, hingeConstraint->getLimitBiasFactor(), hingeConstraint->getLimitRelaxationFactor()); + break; + case PhysicsServer::HINGE_JOINT_LIMIT_RELAXATION: + hingeConstraint->setLimit(hingeConstraint->getLowerLimit(), hingeConstraint->getUpperLimit(), hingeConstraint->getLimitSoftness(), hingeConstraint->getLimitBiasFactor(), p_value); + break; + case PhysicsServer::HINGE_JOINT_MOTOR_TARGET_VELOCITY: + hingeConstraint->setMotorTargetVelocity(p_value); + break; + case PhysicsServer::HINGE_JOINT_MOTOR_MAX_IMPULSE: + hingeConstraint->setMaxMotorImpulse(p_value); + break; + default: + WARN_PRINTS("The Bullet Hinge Joint doesn't support this parameter: " + itos(p_param) + ", value: " + itos(p_value)); + } +} + +real_t HingeJointBullet::get_param(PhysicsServer::HingeJointParam p_param) const { + switch (p_param) { + case PhysicsServer::HINGE_JOINT_BIAS: + return 0; + break; + case PhysicsServer::HINGE_JOINT_LIMIT_UPPER: + return hingeConstraint->getUpperLimit(); + case PhysicsServer::HINGE_JOINT_LIMIT_LOWER: + return hingeConstraint->getLowerLimit(); + case PhysicsServer::HINGE_JOINT_LIMIT_BIAS: + return hingeConstraint->getLimitBiasFactor(); + case PhysicsServer::HINGE_JOINT_LIMIT_SOFTNESS: + return hingeConstraint->getLimitSoftness(); + case PhysicsServer::HINGE_JOINT_LIMIT_RELAXATION: + return hingeConstraint->getLimitRelaxationFactor(); + case PhysicsServer::HINGE_JOINT_MOTOR_TARGET_VELOCITY: + return hingeConstraint->getMotorTargetVelocity(); + case PhysicsServer::HINGE_JOINT_MOTOR_MAX_IMPULSE: + return hingeConstraint->getMaxMotorImpulse(); + default: + WARN_PRINTS("The Bullet Hinge Joint doesn't support this parameter: " + itos(p_param)); + return 0; + } +} + +void HingeJointBullet::set_flag(PhysicsServer::HingeJointFlag p_flag, bool p_value) { + switch (p_flag) { + case PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT: + if (!p_value) { + hingeConstraint->setLimit(-Math_PI, Math_PI); + } + break; + case PhysicsServer::HINGE_JOINT_FLAG_ENABLE_MOTOR: + hingeConstraint->enableMotor(p_value); + break; + } +} + +bool HingeJointBullet::get_flag(PhysicsServer::HingeJointFlag p_flag) const { + switch (p_flag) { + case PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT: + return true; + case PhysicsServer::HINGE_JOINT_FLAG_ENABLE_MOTOR: + return hingeConstraint->getEnableAngularMotor(); + default: + return false; + } +} diff --git a/modules/bullet/hinge_joint_bullet.h b/modules/bullet/hinge_joint_bullet.h new file mode 100644 index 0000000000..a78788a5e5 --- /dev/null +++ b/modules/bullet/hinge_joint_bullet.h @@ -0,0 +1,54 @@ +/*************************************************************************/ +/* hinge_joint_bullet.h */ +/* 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. */ +/*************************************************************************/ + +#ifndef HINGE_JOINT_BULLET_H +#define HINGE_JOINT_BULLET_H + +#include "joint_bullet.h" + +class HingeJointBullet : public JointBullet { + class btHingeConstraint *hingeConstraint; + +public: + HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameA, const Transform &frameB); + HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Vector3 &pivotInA, const Vector3 &pivotInB, const Vector3 &axisInA, const Vector3 &axisInB); + + virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_HINGE; } + + real_t get_hinge_angle(); + + void set_param(PhysicsServer::HingeJointParam p_param, real_t p_value); + real_t get_param(PhysicsServer::HingeJointParam p_param) const; + + void set_flag(PhysicsServer::HingeJointFlag p_flag, bool p_value); + bool get_flag(PhysicsServer::HingeJointFlag p_flag) const; +}; +#endif diff --git a/modules/bullet/joint_bullet.cpp b/modules/bullet/joint_bullet.cpp new file mode 100644 index 0000000000..be544f89bf --- /dev/null +++ b/modules/bullet/joint_bullet.cpp @@ -0,0 +1,38 @@ +/*************************************************************************/ +/* joint_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 "joint_bullet.h" +#include "space_bullet.h" + +JointBullet::JointBullet() + : ConstraintBullet() {} + +JointBullet::~JointBullet() {} diff --git a/modules/bullet/joint_bullet.h b/modules/bullet/joint_bullet.h new file mode 100644 index 0000000000..d47e677502 --- /dev/null +++ b/modules/bullet/joint_bullet.h @@ -0,0 +1,49 @@ +/*************************************************************************/ +/* joint_bullet.h */ +/* 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. */ +/*************************************************************************/ + +#ifndef JOINT_BULLET_H +#define JOINT_BULLET_H + +#include "constraint_bullet.h" +#include "servers/physics_server.h" + +class RigidBodyBullet; +class btTypedConstraint; + +class JointBullet : public ConstraintBullet { + +public: + JointBullet(); + virtual ~JointBullet(); + + virtual PhysicsServer::JointType get_type() const = 0; +}; +#endif diff --git a/modules/bullet/pin_joint_bullet.cpp b/modules/bullet/pin_joint_bullet.cpp new file mode 100644 index 0000000000..cd9e9a4557 --- /dev/null +++ b/modules/bullet/pin_joint_bullet.cpp @@ -0,0 +1,112 @@ +/*************************************************************************/ +/* pin_joint_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 "pin_joint_bullet.h" +#include "BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h" +#include "bullet_types_converter.h" +#include "rigid_body_bullet.h" + +PinJointBullet::PinJointBullet(RigidBodyBullet *p_body_a, const Vector3 &p_pos_a, RigidBodyBullet *p_body_b, const Vector3 &p_pos_b) + : JointBullet() { + if (p_body_b) { + + btVector3 btPivotA; + btVector3 btPivotB; + G_TO_B(p_pos_a, btPivotA); + G_TO_B(p_pos_b, btPivotB); + p2pConstraint = bulletnew(btPoint2PointConstraint(*p_body_a->get_bt_rigid_body(), + *p_body_b->get_bt_rigid_body(), + btPivotA, + btPivotB)); + } else { + btVector3 btPivotA; + G_TO_B(p_pos_a, btPivotA); + p2pConstraint = bulletnew(btPoint2PointConstraint(*p_body_a->get_bt_rigid_body(), btPivotA)); + } + + setup(p2pConstraint); +} + +PinJointBullet::~PinJointBullet() {} + +void PinJointBullet::set_param(PhysicsServer::PinJointParam p_param, real_t p_value) { + switch (p_param) { + case PhysicsServer::PIN_JOINT_BIAS: + p2pConstraint->m_setting.m_tau = p_value; + break; + case PhysicsServer::PIN_JOINT_DAMPING: + p2pConstraint->m_setting.m_damping = p_value; + break; + case PhysicsServer::PIN_JOINT_IMPULSE_CLAMP: + p2pConstraint->m_setting.m_impulseClamp = p_value; + break; + } +} + +real_t PinJointBullet::get_param(PhysicsServer::PinJointParam p_param) const { + switch (p_param) { + case PhysicsServer::PIN_JOINT_BIAS: + return p2pConstraint->m_setting.m_tau; + case PhysicsServer::PIN_JOINT_DAMPING: + return p2pConstraint->m_setting.m_damping; + case PhysicsServer::PIN_JOINT_IMPULSE_CLAMP: + return p2pConstraint->m_setting.m_impulseClamp; + default: + WARN_PRINTS("This get parameter is not supported"); + return 0; + } +} + +void PinJointBullet::setPivotInA(const Vector3 &p_pos) { + btVector3 btVec; + G_TO_B(p_pos, btVec); + p2pConstraint->setPivotA(btVec); +} + +void PinJointBullet::setPivotInB(const Vector3 &p_pos) { + btVector3 btVec; + G_TO_B(p_pos, btVec); + p2pConstraint->setPivotB(btVec); +} + +Vector3 PinJointBullet::getPivotInA() { + btVector3 vec = p2pConstraint->getPivotInA(); + Vector3 gVec; + B_TO_G(vec, gVec); + return gVec; +} + +Vector3 PinJointBullet::getPivotInB() { + btVector3 vec = p2pConstraint->getPivotInB(); + Vector3 gVec; + B_TO_G(vec, gVec); + return gVec; +} diff --git a/modules/bullet/pin_joint_bullet.h b/modules/bullet/pin_joint_bullet.h new file mode 100644 index 0000000000..3a0906bf83 --- /dev/null +++ b/modules/bullet/pin_joint_bullet.h @@ -0,0 +1,57 @@ +/*************************************************************************/ +/* pin_joint_bullet.h */ +/* 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. */ +/*************************************************************************/ + +#ifndef PIN_JOINT_BULLET_H +#define PIN_JOINT_BULLET_H + +#include "joint_bullet.h" + +class RigidBodyBullet; + +class PinJointBullet : public JointBullet { + class btPoint2PointConstraint *p2pConstraint; + +public: + PinJointBullet(RigidBodyBullet *p_body_a, const Vector3 &p_pos_a, RigidBodyBullet *p_body_b, const Vector3 &p_pos_b); + ~PinJointBullet(); + + virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_PIN; } + + void set_param(PhysicsServer::PinJointParam p_param, real_t p_value); + real_t get_param(PhysicsServer::PinJointParam p_param) const; + + void setPivotInA(const Vector3 &p_pos); + void setPivotInB(const Vector3 &p_pos); + + Vector3 getPivotInA(); + Vector3 getPivotInB(); +}; +#endif diff --git a/modules/bullet/register_types.cpp b/modules/bullet/register_types.cpp new file mode 100644 index 0000000000..1e697e7443 --- /dev/null +++ b/modules/bullet/register_types.cpp @@ -0,0 +1,47 @@ +/*************************************************************************/ +/* register_types.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 "register_types.h" +#include "bullet_physics_server.h" +#include "class_db.h" + +PhysicsServer *_createBulletPhysicsCallback() { + return memnew(BulletPhysicsServer); +} + +void register_bullet_types() { + + PhysicsServerManager::register_server("Bullet", &_createBulletPhysicsCallback); + PhysicsServerManager::set_default_server("Bullet", 1); +} + +void unregister_bullet_types() { +} diff --git a/modules/bullet/register_types.h b/modules/bullet/register_types.h new file mode 100644 index 0000000000..ca0683fa3b --- /dev/null +++ b/modules/bullet/register_types.h @@ -0,0 +1,37 @@ +/*************************************************************************/ +/* register_types.h */ +/* 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. */ +/*************************************************************************/ + +#ifndef REGISTER_BULLET_TYPES_H +#define REGISTER_BULLET_TYPES_H + +void register_bullet_types(); +void unregister_bullet_types(); +#endif diff --git a/modules/bullet/rid_bullet.h b/modules/bullet/rid_bullet.h new file mode 100644 index 0000000000..da7517f246 --- /dev/null +++ b/modules/bullet/rid_bullet.h @@ -0,0 +1,50 @@ +/*************************************************************************/ +/* rid_bullet.h */ +/* 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. */ +/*************************************************************************/ + +#ifndef RID_BULLET_H +#define RID_BULLET_H + +#include "core/rid.h" + +class BulletPhysicsServer; + +class RIDBullet : public RID_Data { + RID self; + BulletPhysicsServer *physicsServer; + +public: + _FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; } + _FORCE_INLINE_ RID get_self() const { return self; } + + _FORCE_INLINE_ void _set_physics_server(BulletPhysicsServer *p_physicsServer) { physicsServer = p_physicsServer; } + _FORCE_INLINE_ BulletPhysicsServer *get_physics_server() const { return physicsServer; } +}; +#endif diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp new file mode 100644 index 0000000000..5d0513db76 --- /dev/null +++ b/modules/bullet/rigid_body_bullet.cpp @@ -0,0 +1,1009 @@ +/*************************************************************************/ +/* body_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 "rigid_body_bullet.h" +#include "BulletCollision/CollisionDispatch/btGhostObject.h" +#include "BulletCollision/CollisionShapes/btConvexPointCloudShape.h" +#include "BulletDynamics/Dynamics/btRigidBody.h" +#include "btBulletCollisionCommon.h" +#include "btRayShape.h" +#include "bullet_physics_server.h" +#include "bullet_types_converter.h" +#include "bullet_utilities.h" +#include "godot_motion_state.h" +#include "joint_bullet.h" +#include <assert.h> + +BulletPhysicsDirectBodyState *BulletPhysicsDirectBodyState::singleton = NULL; + +Vector3 BulletPhysicsDirectBodyState::get_total_gravity() const { + Vector3 gVec; + B_TO_G(body->btBody->getGravity(), gVec); + return gVec; +} + +float BulletPhysicsDirectBodyState::get_total_angular_damp() const { + return body->btBody->getAngularDamping(); +} + +float BulletPhysicsDirectBodyState::get_total_linear_damp() const { + return body->btBody->getLinearDamping(); +} + +Vector3 BulletPhysicsDirectBodyState::get_center_of_mass() const { + Vector3 gVec; + B_TO_G(body->btBody->getCenterOfMassPosition(), gVec); + return gVec; +} + +Basis BulletPhysicsDirectBodyState::get_principal_inertia_axes() const { + return Basis(); +} + +float BulletPhysicsDirectBodyState::get_inverse_mass() const { + return body->btBody->getInvMass(); +} + +Vector3 BulletPhysicsDirectBodyState::get_inverse_inertia() const { + Vector3 gVec; + B_TO_G(body->btBody->getInvInertiaDiagLocal(), gVec); + return gVec; +} + +Basis BulletPhysicsDirectBodyState::get_inverse_inertia_tensor() const { + Basis gInertia; + B_TO_G(body->btBody->getInvInertiaTensorWorld(), gInertia); + return gInertia; +} + +void BulletPhysicsDirectBodyState::set_linear_velocity(const Vector3 &p_velocity) { + body->set_linear_velocity(p_velocity); +} + +Vector3 BulletPhysicsDirectBodyState::get_linear_velocity() const { + return body->get_linear_velocity(); +} + +void BulletPhysicsDirectBodyState::set_angular_velocity(const Vector3 &p_velocity) { + body->set_angular_velocity(p_velocity); +} + +Vector3 BulletPhysicsDirectBodyState::get_angular_velocity() const { + return body->get_angular_velocity(); +} + +void BulletPhysicsDirectBodyState::set_transform(const Transform &p_transform) { + body->set_transform(p_transform); +} + +Transform BulletPhysicsDirectBodyState::get_transform() const { + return body->get_transform(); +} + +void BulletPhysicsDirectBodyState::add_force(const Vector3 &p_force, const Vector3 &p_pos) { + body->apply_force(p_force, p_pos); +} + +void BulletPhysicsDirectBodyState::apply_impulse(const Vector3 &p_pos, const Vector3 &p_j) { + body->apply_impulse(p_pos, p_j); +} + +void BulletPhysicsDirectBodyState::apply_torque_impulse(const Vector3 &p_j) { + body->apply_torque_impulse(p_j); +} + +void BulletPhysicsDirectBodyState::set_sleep_state(bool p_enable) { + body->set_activation_state(p_enable); +} + +bool BulletPhysicsDirectBodyState::is_sleeping() const { + return !body->is_active(); +} + +int BulletPhysicsDirectBodyState::get_contact_count() const { + return body->collisionsCount; +} + +Vector3 BulletPhysicsDirectBodyState::get_contact_local_position(int p_contact_idx) const { + return body->collisions[p_contact_idx].hitLocalLocation; +} + +Vector3 BulletPhysicsDirectBodyState::get_contact_local_normal(int p_contact_idx) const { + return body->collisions[p_contact_idx].hitNormal; +} + +int BulletPhysicsDirectBodyState::get_contact_local_shape(int p_contact_idx) const { + return body->collisions[p_contact_idx].local_shape; +} + +RID BulletPhysicsDirectBodyState::get_contact_collider(int p_contact_idx) const { + return body->collisions[p_contact_idx].otherObject->get_self(); +} + +Vector3 BulletPhysicsDirectBodyState::get_contact_collider_position(int p_contact_idx) const { + return body->collisions[p_contact_idx].hitWorldLocation; +} + +ObjectID BulletPhysicsDirectBodyState::get_contact_collider_id(int p_contact_idx) const { + return body->collisions[p_contact_idx].otherObject->get_instance_id(); +} + +int BulletPhysicsDirectBodyState::get_contact_collider_shape(int p_contact_idx) const { + return body->collisions[p_contact_idx].other_object_shape; +} + +Vector3 BulletPhysicsDirectBodyState::get_contact_collider_velocity_at_position(int p_contact_idx) const { + RigidBodyBullet::CollisionData &colDat = body->collisions[p_contact_idx]; + + btVector3 hitLocation; + G_TO_B(colDat.hitLocalLocation, hitLocation); + + Vector3 velocityAtPoint; + B_TO_G(colDat.otherObject->get_bt_rigid_body()->getVelocityInLocalPoint(hitLocation), velocityAtPoint); + + return velocityAtPoint; +} + +PhysicsDirectSpaceState *BulletPhysicsDirectBodyState::get_space_state() { + return body->get_space()->get_direct_state(); +} + +RigidBodyBullet::KinematicUtilities::KinematicUtilities(RigidBodyBullet *p_owner) + : m_owner(p_owner), m_margin(0.01) // Godot default margin 0.001 +{ + m_ghostObject = bulletnew(btPairCachingGhostObject); + + int clearedCurrentFlags = m_ghostObject->getCollisionFlags(); + clearedCurrentFlags &= ~(btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT); + + m_ghostObject->setCollisionFlags(clearedCurrentFlags | btCollisionObject::CF_KINEMATIC_OBJECT); + m_ghostObject->setUserPointer(p_owner); + m_ghostObject->setUserIndex(TYPE_KINEMATIC_GHOST_BODY); + + resetDefShape(); +} + +RigidBodyBullet::KinematicUtilities::~KinematicUtilities() { + just_delete_shapes(m_shapes.size()); // don't need to resize + bulletdelete(m_ghostObject); +} + +void RigidBodyBullet::KinematicUtilities::resetDefShape() { + m_ghostObject->setCollisionShape(BulletPhysicsServer::get_empty_shape()); +} + +void RigidBodyBullet::KinematicUtilities::copyAllOwnerShapes() { + const Vector<CollisionObjectBullet::ShapeWrapper> &shapes_wrappers(m_owner->get_shapes_wrappers()); + const int shapes_count = shapes_wrappers.size(); + + just_delete_shapes(shapes_count); + + const CollisionObjectBullet::ShapeWrapper *shape_wrapper; + + for (int i = shapes_count - 1; 0 <= i; --i) { + shape_wrapper = &shapes_wrappers[i]; + if (!shape_wrapper->active) { + continue; + } + m_shapes[i].transform = shape_wrapper->transform; + + btConvexShape *&kin_shape_ref = m_shapes[i].shape; + + switch (shape_wrapper->shape->get_type()) { + case PhysicsServer::SHAPE_SPHERE: { + SphereShapeBullet *sphere = static_cast<SphereShapeBullet *>(shape_wrapper->shape); + kin_shape_ref = ShapeBullet::create_shape_sphere(sphere->get_radius() * m_owner->body_scale[0] + m_margin); + break; + } + case PhysicsServer::SHAPE_BOX: { + BoxShapeBullet *box = static_cast<BoxShapeBullet *>(shape_wrapper->shape); + kin_shape_ref = ShapeBullet::create_shape_box((box->get_half_extents() * m_owner->body_scale) + btVector3(m_margin, m_margin, m_margin)); + break; + } + case PhysicsServer::SHAPE_CAPSULE: { + CapsuleShapeBullet *capsule = static_cast<CapsuleShapeBullet *>(shape_wrapper->shape); + kin_shape_ref = ShapeBullet::create_shape_capsule(capsule->get_radius() * m_owner->body_scale[0] + m_margin, capsule->get_height() * m_owner->body_scale[1] + m_margin); + break; + } + case PhysicsServer::SHAPE_CONVEX_POLYGON: { + ConvexPolygonShapeBullet *godot_convex = static_cast<ConvexPolygonShapeBullet *>(shape_wrapper->shape); + kin_shape_ref = ShapeBullet::create_shape_convex(godot_convex->vertices); + kin_shape_ref->setLocalScaling(m_owner->body_scale + btVector3(m_margin, m_margin, m_margin)); + break; + } + case PhysicsServer::SHAPE_RAY: { + RayShapeBullet *godot_ray = static_cast<RayShapeBullet *>(shape_wrapper->shape); + kin_shape_ref = ShapeBullet::create_shape_ray(godot_ray->length * m_owner->body_scale[1] + m_margin); + break; + } + default: + WARN_PRINT("This shape is not supported to be kinematic!"); + kin_shape_ref = NULL; + } + } +} + +void RigidBodyBullet::KinematicUtilities::just_delete_shapes(int new_size) { + for (int i = m_shapes.size() - 1; 0 <= i; --i) { + if (m_shapes[i].shape) { + bulletdelete(m_shapes[i].shape); + } + } + m_shapes.resize(new_size); +} + +RigidBodyBullet::RigidBodyBullet() + : RigidCollisionObjectBullet(CollisionObjectBullet::TYPE_RIGID_BODY), + kinematic_utilities(NULL), + gravity_scale(1), + mass(1), + linearDamp(0), + angularDamp(0), + can_sleep(true), + force_integration_callback(NULL), + isTransformChanged(false), + maxCollisionsDetection(0), + collisionsCount(0), + maxAreasWhereIam(10), + areaWhereIamCount(0), + countGravityPointSpaces(0), + isScratchedSpaceOverrideModificator(false) { + + godotMotionState = bulletnew(GodotMotionState(this)); + + // Initial properties + const btVector3 localInertia(0, 0, 0); + btRigidBody::btRigidBodyConstructionInfo cInfo(mass, godotMotionState, compoundShape, localInertia); + + btBody = bulletnew(btRigidBody(cInfo)); + setupBulletCollisionObject(btBody); + + set_mode(PhysicsServer::BODY_MODE_RIGID); + set_axis_lock(PhysicsServer::BODY_AXIS_LOCK_DISABLED); + + areasWhereIam.resize(maxAreasWhereIam); + for (int i = areasWhereIam.size() - 1; 0 <= i; --i) { + areasWhereIam[i] = NULL; + } +} + +RigidBodyBullet::~RigidBodyBullet() { + bulletdelete(godotMotionState); + + if (force_integration_callback) + memdelete(force_integration_callback); + + destroy_kinematic_utilities(); +} + +void RigidBodyBullet::init_kinematic_utilities() { + kinematic_utilities = memnew(KinematicUtilities(this)); +} + +void RigidBodyBullet::destroy_kinematic_utilities() { + if (kinematic_utilities) { + memdelete(kinematic_utilities); + kinematic_utilities = NULL; + } +} + +void RigidBodyBullet::reload_body() { + if (space) { + space->remove_rigid_body(this); + space->add_rigid_body(this); + } +} + +void RigidBodyBullet::set_space(SpaceBullet *p_space) { + // Clear the old space if there is one + if (space) { + isTransformChanged = false; + + // Remove all eventual constraints + assert_no_constraints(); + + // Remove this object form the physics world + space->remove_rigid_body(this); + } + + space = p_space; + + if (space) { + space->add_rigid_body(this); + } +} + +void RigidBodyBullet::dispatch_callbacks() { + /// The check isTransformChanged is necessary in order to call integrated forces only when the first transform is sent + if (btBody->isActive() && force_integration_callback && isTransformChanged) { + + BulletPhysicsDirectBodyState *bodyDirect = BulletPhysicsDirectBodyState::get_singleton(this); + + Variant variantBodyDirect = bodyDirect; + + Object *obj = ObjectDB::get_instance(force_integration_callback->id); + if (!obj) { + // Remove integration callback + set_force_integration_callback(0, StringName()); + } else { + const Variant *vp[2] = { &variantBodyDirect, &force_integration_callback->udata }; + + Variant::CallError responseCallError; + int argc = (force_integration_callback->udata.get_type() == Variant::NIL) ? 1 : 2; + obj->call(force_integration_callback->method, vp, argc, responseCallError); + } + } + + if (isScratchedSpaceOverrideModificator || 0 < countGravityPointSpaces) { + isScratchedSpaceOverrideModificator = false; + reload_space_override_modificator(); + } + + /// Lock axis + btBody->setLinearVelocity(btBody->getLinearVelocity() * btBody->getLinearFactor()); + btBody->setAngularVelocity(btBody->getAngularVelocity() * btBody->getAngularFactor()); +} + +void RigidBodyBullet::set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata) { + + if (force_integration_callback) { + memdelete(force_integration_callback); + force_integration_callback = NULL; + } + + if (p_id != 0) { + force_integration_callback = memnew(ForceIntegrationCallback); + force_integration_callback->id = p_id; + force_integration_callback->method = p_method; + force_integration_callback->udata = p_udata; + } +} + +void RigidBodyBullet::scratch() { + isTransformChanged = true; +} + +void RigidBodyBullet::scratch_space_override_modificator() { + isScratchedSpaceOverrideModificator = true; +} + +void RigidBodyBullet::on_collision_filters_change() { + if (space) { + space->reload_collision_filters(this); + } +} + +void RigidBodyBullet::on_collision_checker_start() { + collisionsCount = 0; +} + +bool RigidBodyBullet::add_collision_object(RigidBodyBullet *p_otherObject, const Vector3 &p_hitWorldLocation, const Vector3 &p_hitLocalLocation, const Vector3 &p_hitNormal, int p_other_shape_index, int p_local_shape_index) { + + if (collisionsCount >= maxCollisionsDetection) { + return false; + } + + CollisionData &cd = collisions[collisionsCount]; + cd.hitLocalLocation = p_hitLocalLocation; + cd.otherObject = p_otherObject; + cd.hitWorldLocation = p_hitWorldLocation; + cd.hitNormal = p_hitNormal; + cd.other_object_shape = p_other_shape_index; + cd.local_shape = p_local_shape_index; + + ++collisionsCount; + return true; +} + +void RigidBodyBullet::assert_no_constraints() { + if (btBody->getNumConstraintRefs()) { + WARN_PRINT("A body with a joints is destroyed. Please check the implementation in order to destroy the joint before the body."); + } + /*for(int i = btBody->getNumConstraintRefs()-1; 0<=i; --i){ + btTypedConstraint* btConst = btBody->getConstraintRef(i); + JointBullet* joint = static_cast<JointBullet*>( btConst->getUserConstraintPtr() ); + space->removeConstraint(joint); + }*/ +} + +void RigidBodyBullet::set_activation_state(bool p_active) { + if (p_active) { + btBody->setActivationState(ACTIVE_TAG); + } else { + btBody->setActivationState(WANTS_DEACTIVATION); + } +} + +bool RigidBodyBullet::is_active() const { + return btBody->isActive(); +} + +void RigidBodyBullet::set_param(PhysicsServer::BodyParameter p_param, real_t p_value) { + switch (p_param) { + case PhysicsServer::BODY_PARAM_BOUNCE: + btBody->setRestitution(p_value); + break; + case PhysicsServer::BODY_PARAM_FRICTION: + btBody->setFriction(p_value); + break; + case PhysicsServer::BODY_PARAM_MASS: { + ERR_FAIL_COND(p_value < 0); + mass = p_value; + _internal_set_mass(p_value); + break; + } + case PhysicsServer::BODY_PARAM_LINEAR_DAMP: + linearDamp = p_value; + btBody->setDamping(linearDamp, angularDamp); + break; + case PhysicsServer::BODY_PARAM_ANGULAR_DAMP: + angularDamp = p_value; + btBody->setDamping(linearDamp, angularDamp); + break; + case PhysicsServer::BODY_PARAM_GRAVITY_SCALE: + gravity_scale = p_value; + /// The Bullet gravity will be is set by reload_space_override_modificator + scratch_space_override_modificator(); + break; + default: + WARN_PRINTS("Parameter " + itos(p_param) + " not supported by bullet. Value: " + itos(p_value)); + } +} + +real_t RigidBodyBullet::get_param(PhysicsServer::BodyParameter p_param) const { + switch (p_param) { + case PhysicsServer::BODY_PARAM_BOUNCE: + return btBody->getRestitution(); + case PhysicsServer::BODY_PARAM_FRICTION: + return btBody->getFriction(); + case PhysicsServer::BODY_PARAM_MASS: { + const btScalar invMass = btBody->getInvMass(); + return 0 == invMass ? 0 : 1 / invMass; + } + case PhysicsServer::BODY_PARAM_LINEAR_DAMP: + return linearDamp; + case PhysicsServer::BODY_PARAM_ANGULAR_DAMP: + return angularDamp; + case PhysicsServer::BODY_PARAM_GRAVITY_SCALE: + return gravity_scale; + default: + WARN_PRINTS("Parameter " + itos(p_param) + " not supported by bullet"); + return 0; + } +} + +void RigidBodyBullet::set_mode(PhysicsServer::BodyMode p_mode) { + // This is necessary to block force_integration untile next move + isTransformChanged = false; + destroy_kinematic_utilities(); + // The mode change is relevant to its mass + switch (p_mode) { + case PhysicsServer::BODY_MODE_KINEMATIC: + mode = PhysicsServer::BODY_MODE_KINEMATIC; + set_axis_lock(axis_lock); // Reload axis lock + _internal_set_mass(0); + init_kinematic_utilities(); + break; + case PhysicsServer::BODY_MODE_STATIC: + mode = PhysicsServer::BODY_MODE_STATIC; + set_axis_lock(axis_lock); // Reload axis lock + _internal_set_mass(0); + break; + case PhysicsServer::BODY_MODE_RIGID: { + mode = PhysicsServer::BODY_MODE_RIGID; + set_axis_lock(axis_lock); // Reload axis lock + _internal_set_mass(0 == mass ? 1 : mass); + break; + } + case PhysicsServer::BODY_MODE_CHARACTER: { + mode = PhysicsServer::BODY_MODE_CHARACTER; + set_axis_lock(axis_lock); // Reload axis lock + _internal_set_mass(0 == mass ? 1 : mass); + break; + } + } + + btBody->setAngularVelocity(btVector3(0, 0, 0)); + btBody->setLinearVelocity(btVector3(0, 0, 0)); +} +PhysicsServer::BodyMode RigidBodyBullet::get_mode() const { + return mode; +} + +void RigidBodyBullet::set_state(PhysicsServer::BodyState p_state, const Variant &p_variant) { + + switch (p_state) { + case PhysicsServer::BODY_STATE_TRANSFORM: + set_transform(p_variant); + break; + case PhysicsServer::BODY_STATE_LINEAR_VELOCITY: + set_linear_velocity(p_variant); + break; + case PhysicsServer::BODY_STATE_ANGULAR_VELOCITY: + set_angular_velocity(p_variant); + break; + case PhysicsServer::BODY_STATE_SLEEPING: + set_activation_state(!bool(p_variant)); + break; + case PhysicsServer::BODY_STATE_CAN_SLEEP: + can_sleep = bool(p_variant); + if (!can_sleep) { + // Can't sleep + btBody->forceActivationState(DISABLE_DEACTIVATION); + } + break; + } +} + +Variant RigidBodyBullet::get_state(PhysicsServer::BodyState p_state) const { + switch (p_state) { + case PhysicsServer::BODY_STATE_TRANSFORM: + return get_transform(); + case PhysicsServer::BODY_STATE_LINEAR_VELOCITY: + return get_linear_velocity(); + case PhysicsServer::BODY_STATE_ANGULAR_VELOCITY: + return get_angular_velocity(); + case PhysicsServer::BODY_STATE_SLEEPING: + return !is_active(); + case PhysicsServer::BODY_STATE_CAN_SLEEP: + return can_sleep; + default: + WARN_PRINTS("This state " + itos(p_state) + " is not supported by Bullet"); + return Variant(); + } +} + +void RigidBodyBullet::apply_central_impulse(const Vector3 &p_impulse) { + btVector3 btImpu; + G_TO_B(p_impulse, btImpu); + btBody->activate(); + btBody->applyCentralImpulse(btImpu); +} + +void RigidBodyBullet::apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse) { + btVector3 btImpu; + btVector3 btPos; + G_TO_B(p_impulse, btImpu); + G_TO_B(p_pos, btPos); + btBody->activate(); + btBody->applyImpulse(btImpu, btPos); +} + +void RigidBodyBullet::apply_torque_impulse(const Vector3 &p_impulse) { + btVector3 btImp; + G_TO_B(p_impulse, btImp); + btBody->activate(); + btBody->applyTorqueImpulse(btImp); +} + +void RigidBodyBullet::apply_force(const Vector3 &p_force, const Vector3 &p_pos) { + btVector3 btForce; + btVector3 btPos; + G_TO_B(p_force, btForce); + G_TO_B(p_pos, btPos); + btBody->activate(); + btBody->applyForce(btForce, btPos); +} + +void RigidBodyBullet::apply_central_force(const Vector3 &p_force) { + btVector3 btForce; + G_TO_B(p_force, btForce); + btBody->activate(); + btBody->applyCentralForce(btForce); +} + +void RigidBodyBullet::apply_torque(const Vector3 &p_torque) { + btVector3 btTorq; + G_TO_B(p_torque, btTorq); + btBody->activate(); + btBody->applyTorque(btTorq); +} + +void RigidBodyBullet::set_applied_force(const Vector3 &p_force) { + btVector3 btVec = btBody->getTotalTorque(); + + btBody->activate(); + + btBody->clearForces(); + btBody->applyTorque(btVec); + + G_TO_B(p_force, btVec); + btBody->applyCentralForce(btVec); +} + +Vector3 RigidBodyBullet::get_applied_force() const { + Vector3 gTotForc; + B_TO_G(btBody->getTotalForce(), gTotForc); + return gTotForc; +} + +void RigidBodyBullet::set_applied_torque(const Vector3 &p_torque) { + btVector3 btVec = btBody->getTotalForce(); + + btBody->activate(); + + btBody->clearForces(); + btBody->applyCentralForce(btVec); + + G_TO_B(p_torque, btVec); + btBody->applyTorque(btVec); +} + +Vector3 RigidBodyBullet::get_applied_torque() const { + Vector3 gTotTorq; + B_TO_G(btBody->getTotalTorque(), gTotTorq); + return gTotTorq; +} + +void RigidBodyBullet::set_axis_lock(PhysicsServer::BodyAxisLock p_lock) { + axis_lock = p_lock; + + if (PhysicsServer::BODY_AXIS_LOCK_DISABLED == axis_lock) { + btBody->setLinearFactor(btVector3(1., 1., 1.)); + btBody->setAngularFactor(btVector3(1., 1., 1.)); + } else if (PhysicsServer::BODY_AXIS_LOCK_X == axis_lock) { + btBody->setLinearFactor(btVector3(0., 1., 1.)); + btBody->setAngularFactor(btVector3(1., 0., 0.)); + } else if (PhysicsServer::BODY_AXIS_LOCK_Y == axis_lock) { + btBody->setLinearFactor(btVector3(1., 0., 1.)); + btBody->setAngularFactor(btVector3(0., 1., 0.)); + } else if (PhysicsServer::BODY_AXIS_LOCK_Z == axis_lock) { + btBody->setLinearFactor(btVector3(1., 1., 0.)); + btBody->setAngularFactor(btVector3(0., 0., 1.)); + } + + if (PhysicsServer::BODY_MODE_CHARACTER == mode) { + /// When character lock angular + btBody->setAngularFactor(btVector3(0., 0., 0.)); + } +} + +PhysicsServer::BodyAxisLock RigidBodyBullet::get_axis_lock() const { + btVector3 vec = btBody->getLinearFactor(); + if (0. == vec.x()) { + return PhysicsServer::BODY_AXIS_LOCK_X; + } else if (0. == vec.y()) { + return PhysicsServer::BODY_AXIS_LOCK_Y; + } else if (0. == vec.z()) { + return PhysicsServer::BODY_AXIS_LOCK_Z; + } else { + return PhysicsServer::BODY_AXIS_LOCK_DISABLED; + } +} + +void RigidBodyBullet::set_continuous_collision_detection(bool p_enable) { + if (p_enable) { + // This threshold enable CCD if the object moves more than + // 1 meter in one simulation frame + btBody->setCcdMotionThreshold(1); + + /// Calculate using the rule writte below the CCD swept sphere radius + /// CCD works on an embedded sphere of radius, make sure this radius + /// is embedded inside the convex objects, preferably smaller: + /// for an object of dimentions 1 meter, try 0.2 + btVector3 center; + btScalar radius; + btBody->getCollisionShape()->getBoundingSphere(center, radius); + btBody->setCcdSweptSphereRadius(radius * 0.2); + } else { + btBody->setCcdMotionThreshold(0.); + btBody->setCcdSweptSphereRadius(0.); + } +} + +bool RigidBodyBullet::is_continuous_collision_detection_enabled() const { + return 0. != btBody->getCcdMotionThreshold(); +} + +void RigidBodyBullet::set_linear_velocity(const Vector3 &p_velocity) { + btVector3 btVec; + G_TO_B(p_velocity, btVec); + btBody->activate(); + btBody->setLinearVelocity(btVec); +} + +Vector3 RigidBodyBullet::get_linear_velocity() const { + Vector3 gVec; + B_TO_G(btBody->getLinearVelocity(), gVec); + return gVec; +} + +void RigidBodyBullet::set_angular_velocity(const Vector3 &p_velocity) { + btVector3 btVec; + G_TO_B(p_velocity, btVec); + btBody->activate(); + btBody->setAngularVelocity(btVec); +} + +Vector3 RigidBodyBullet::get_angular_velocity() const { + Vector3 gVec; + B_TO_G(btBody->getAngularVelocity(), gVec); + return gVec; +} + +void RigidBodyBullet::set_transform__bullet(const btTransform &p_global_transform) { + if (mode == PhysicsServer::BODY_MODE_KINEMATIC) { + // The kinematic use MotionState class + godotMotionState->moveBody(p_global_transform); + } + btBody->setWorldTransform(p_global_transform); +} + +const btTransform &RigidBodyBullet::get_transform__bullet() const { + if (is_static()) { + + return RigidCollisionObjectBullet::get_transform__bullet(); + } else { + + return godotMotionState->getCurrentWorldTransform(); + } +} + +void RigidBodyBullet::on_shapes_changed() { + RigidCollisionObjectBullet::on_shapes_changed(); + + const btScalar invMass = btBody->getInvMass(); + const btScalar mass = invMass == 0 ? 0 : 1 / invMass; + + btVector3 inertia; + btBody->getCollisionShape()->calculateLocalInertia(mass, inertia); + btBody->setMassProps(mass, inertia); + btBody->updateInertiaTensor(); + + reload_kinematic_shapes(); + + reload_body(); +} + +void RigidBodyBullet::on_enter_area(AreaBullet *p_area) { + /// Add this area to the array in an ordered way + ++areaWhereIamCount; + if (areaWhereIamCount >= maxAreasWhereIam) { + --areaWhereIamCount; + return; + } + for (int i = 0; i < areaWhereIamCount; ++i) { + + if (NULL == areasWhereIam[i]) { + // This area has the highest priority + areasWhereIam[i] = p_area; + break; + } else { + if (areasWhereIam[i]->get_spOv_priority() > p_area->get_spOv_priority()) { + // The position was found, just shift all elements + for (int j = i; j < areaWhereIamCount; ++j) { + areasWhereIam[j + 1] = areasWhereIam[j]; + } + areasWhereIam[i] = p_area; + break; + } + } + } + if (PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED != p_area->get_spOv_mode()) { + scratch_space_override_modificator(); + } + + if (p_area->is_spOv_gravityPoint()) { + ++countGravityPointSpaces; + assert(0 < countGravityPointSpaces); + } +} + +void RigidBodyBullet::on_exit_area(AreaBullet *p_area) { + RigidCollisionObjectBullet::on_exit_area(p_area); + /// Remove this area and keep the order + /// N.B. Since I don't want resize the array I can't use the "erase" function + bool wasTheAreaFound = false; + for (int i = 0; i < areaWhereIamCount; ++i) { + if (p_area == areasWhereIam[i]) { + // The area was fount, just shift down all elements + for (int j = i; j < areaWhereIamCount; ++j) { + areasWhereIam[j] = areasWhereIam[j + 1]; + } + wasTheAreaFound = true; + break; + } + } + if (wasTheAreaFound) { + if (p_area->is_spOv_gravityPoint()) { + --countGravityPointSpaces; + assert(0 <= countGravityPointSpaces); + } + + --areaWhereIamCount; + areasWhereIam[areaWhereIamCount] = NULL; // Even if this is not required, I clear the last element to be safe + if (PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED != p_area->get_spOv_mode()) { + scratch_space_override_modificator(); + } + } +} + +void RigidBodyBullet::reload_space_override_modificator() { + + Vector3 newGravity(space->get_gravity_direction() * space->get_gravity_magnitude()); + real_t newLinearDamp(linearDamp); + real_t newAngularDamp(angularDamp); + + AreaBullet *currentArea; + // Variable used to calculate new gravity for gravity point areas, it is pointed by currentGravity pointer + Vector3 support_gravity(0, 0, 0); + + int countCombined(0); + for (int i = areaWhereIamCount - 1; 0 <= i; --i) { + + currentArea = areasWhereIam[i]; + + if (PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED == currentArea->get_spOv_mode()) { + continue; + } + + /// Here is calculated the gravity + if (currentArea->is_spOv_gravityPoint()) { + + /// It calculates the direction of new gravity + support_gravity = currentArea->get_transform().xform(currentArea->get_spOv_gravityVec()) - get_transform().get_origin(); + real_t distanceMag = support_gravity.length(); + // Normalized in this way to avoid the double call of function "length()" + if (distanceMag == 0) { + support_gravity.x = 0; + support_gravity.y = 0; + support_gravity.z = 0; + } else { + support_gravity.x /= distanceMag; + support_gravity.y /= distanceMag; + support_gravity.z /= distanceMag; + } + + /// Here is calculated the final gravity + if (currentArea->get_spOv_gravityPointDistanceScale() > 0) { + // Scaled gravity by distance + support_gravity *= currentArea->get_spOv_gravityMag() / Math::pow(distanceMag * currentArea->get_spOv_gravityPointDistanceScale() + 1, 2); + } else { + // Unscaled gravity + support_gravity *= currentArea->get_spOv_gravityMag(); + } + } else { + support_gravity = currentArea->get_spOv_gravityVec() * currentArea->get_spOv_gravityMag(); + } + + switch (currentArea->get_spOv_mode()) { + ///case PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED: + /// This area does not affect gravity/damp. These are generally areas + /// that exist only to detect collisions, and objects entering or exiting them. + /// break; + case PhysicsServer::AREA_SPACE_OVERRIDE_COMBINE: + /// This area adds its gravity/damp values to whatever has been + /// calculated so far. This way, many overlapping areas can combine + /// their physics to make interesting + newGravity += support_gravity; + newLinearDamp += currentArea->get_spOv_linearDamp(); + newAngularDamp += currentArea->get_spOv_angularDamp(); + ++countCombined; + break; + case PhysicsServer::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: + /// This area adds its gravity/damp values to whatever has been calculated + /// so far. Then stops taking into account the rest of the areas, even the + /// default one. + newGravity += support_gravity; + newLinearDamp += currentArea->get_spOv_linearDamp(); + newAngularDamp += currentArea->get_spOv_angularDamp(); + ++countCombined; + goto endAreasCycle; + case PhysicsServer::AREA_SPACE_OVERRIDE_REPLACE: + /// This area replaces any gravity/damp, even the default one, and + /// stops taking into account the rest of the areas. + newGravity = support_gravity; + newLinearDamp = currentArea->get_spOv_linearDamp(); + newAngularDamp = currentArea->get_spOv_angularDamp(); + countCombined = 1; + goto endAreasCycle; + case PhysicsServer::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: + /// This area replaces any gravity/damp calculated so far, but keeps + /// calculating the rest of the areas, down to the default one. + newGravity = support_gravity; + newLinearDamp = currentArea->get_spOv_linearDamp(); + newAngularDamp = currentArea->get_spOv_angularDamp(); + countCombined = 1; + break; + } + } +endAreasCycle: + + if (1 < countCombined) { + newGravity /= countCombined; + newLinearDamp /= countCombined; + newAngularDamp /= countCombined; + } + + btVector3 newBtGravity; + G_TO_B(newGravity * gravity_scale, newBtGravity); + + btBody->setGravity(newBtGravity); + btBody->setDamping(newLinearDamp, newAngularDamp); +} + +void RigidBodyBullet::reload_kinematic_shapes() { + if (!kinematic_utilities) { + return; + } + kinematic_utilities->copyAllOwnerShapes(); +} + +void RigidBodyBullet::_internal_set_mass(real_t p_mass) { + + btVector3 localInertia(0, 0, 0); + + int clearedCurrentFlags = btBody->getCollisionFlags(); + clearedCurrentFlags &= ~(btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_CHARACTER_OBJECT); + + // Rigidbody is dynamic if and only if mass is non Zero, otherwise static + const bool isDynamic = p_mass != 0.f; + if (isDynamic) { + + ERR_FAIL_COND(PhysicsServer::BODY_MODE_RIGID != mode && PhysicsServer::BODY_MODE_CHARACTER != mode); + + m_isStatic = false; + compoundShape->calculateLocalInertia(p_mass, localInertia); + + if (PhysicsServer::BODY_MODE_RIGID == mode) { + + btBody->setCollisionFlags(clearedCurrentFlags); // Just set the flags without Kin and Static + } else { + + btBody->setCollisionFlags(clearedCurrentFlags | btCollisionObject::CF_CHARACTER_OBJECT); + } + + if (can_sleep) { + btBody->forceActivationState(ACTIVE_TAG); // ACTIVE_TAG 1 + } else { + btBody->forceActivationState(DISABLE_DEACTIVATION); // DISABLE_DEACTIVATION 4 + } + } else { + + ERR_FAIL_COND(PhysicsServer::BODY_MODE_STATIC != mode && PhysicsServer::BODY_MODE_KINEMATIC != mode); + + m_isStatic = true; + if (PhysicsServer::BODY_MODE_STATIC == mode) { + + btBody->setCollisionFlags(clearedCurrentFlags | btCollisionObject::CF_STATIC_OBJECT); + } else { + + btBody->setCollisionFlags(clearedCurrentFlags | btCollisionObject::CF_KINEMATIC_OBJECT); + set_transform__bullet(btBody->getWorldTransform()); // Set current Transform using kinematic method + } + btBody->forceActivationState(DISABLE_SIMULATION); // DISABLE_SIMULATION 5 + } + + btBody->setMassProps(p_mass, localInertia); + btBody->updateInertiaTensor(); + + reload_body(); +} diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h new file mode 100644 index 0000000000..0cf3f9f605 --- /dev/null +++ b/modules/bullet/rigid_body_bullet.h @@ -0,0 +1,304 @@ +/*************************************************************************/ +/* body_bullet.h */ +/* 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. */ +/*************************************************************************/ + +#ifndef BODYBULLET_H +#define BODYBULLET_H + +#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" +#include "LinearMath/btTransform.h" +#include "collision_object_bullet.h" +#include "space_bullet.h" + +class AreaBullet; +class SpaceBullet; +class btRigidBody; +class GodotMotionState; +class BulletPhysicsDirectBodyState; + +/// This class could be used in multi thread with few changes but currently +/// is setted to be only in one single thread. +/// +/// In the system there is only one object at a time that manage all bodies and is +/// created by BulletPhysicsServer and is held by the "singleton" variable of this class +/// Each time something require it, the body must be setted again. +class BulletPhysicsDirectBodyState : public PhysicsDirectBodyState { + GDCLASS(BulletPhysicsDirectBodyState, PhysicsDirectBodyState) + + static BulletPhysicsDirectBodyState *singleton; + +public: + /// This class avoid the creation of more object of this class + static void initSingleton() { + if (!singleton) { + singleton = memnew(BulletPhysicsDirectBodyState); + } + } + + static void destroySingleton() { + memdelete(singleton); + singleton = NULL; + } + + static void singleton_setDeltaTime(real_t p_deltaTime) { + singleton->deltaTime = p_deltaTime; + } + + static BulletPhysicsDirectBodyState *get_singleton(RigidBodyBullet *p_body) { + singleton->body = p_body; + return singleton; + } + +public: + RigidBodyBullet *body; + real_t deltaTime; + +private: + BulletPhysicsDirectBodyState() {} + +public: + virtual Vector3 get_total_gravity() const; + virtual float get_total_angular_damp() const; + virtual float get_total_linear_damp() const; + + virtual Vector3 get_center_of_mass() const; + virtual Basis get_principal_inertia_axes() const; + // get the mass + virtual float get_inverse_mass() const; + // get density of this body space + virtual Vector3 get_inverse_inertia() const; + // get density of this body space + virtual Basis get_inverse_inertia_tensor() const; + + virtual void set_linear_velocity(const Vector3 &p_velocity); + virtual Vector3 get_linear_velocity() const; + + virtual void set_angular_velocity(const Vector3 &p_velocity); + virtual Vector3 get_angular_velocity() const; + + virtual void set_transform(const Transform &p_transform); + virtual Transform get_transform() const; + + virtual void add_force(const Vector3 &p_force, const Vector3 &p_pos); + virtual void apply_impulse(const Vector3 &p_pos, const Vector3 &p_j); + virtual void apply_torque_impulse(const Vector3 &p_j); + + virtual void set_sleep_state(bool p_enable); + virtual bool is_sleeping() const; + + virtual int get_contact_count() const; + + virtual Vector3 get_contact_local_position(int p_contact_idx) const; + virtual Vector3 get_contact_local_normal(int p_contact_idx) const; + virtual int get_contact_local_shape(int p_contact_idx) const; + + virtual RID get_contact_collider(int p_contact_idx) const; + virtual Vector3 get_contact_collider_position(int p_contact_idx) const; + virtual ObjectID get_contact_collider_id(int p_contact_idx) const; + virtual int get_contact_collider_shape(int p_contact_idx) const; + virtual Vector3 get_contact_collider_velocity_at_position(int p_contact_idx) const; + + virtual real_t get_step() const { return deltaTime; } + virtual void integrate_forces() { + // Skip the execution of this function + } + + virtual PhysicsDirectSpaceState *get_space_state(); +}; + +class RigidBodyBullet : public RigidCollisionObjectBullet { + +public: + struct CollisionData { + RigidBodyBullet *otherObject; + int other_object_shape; + int local_shape; + Vector3 hitLocalLocation; + Vector3 hitWorldLocation; + Vector3 hitNormal; + }; + + struct ForceIntegrationCallback { + ObjectID id; + StringName method; + Variant udata; + }; + + /// Used to hold shapes + struct KinematicShape { + class btConvexShape *shape; + btTransform transform; + + KinematicShape() + : shape(NULL) {} + const bool is_active() const { return shape; } + }; + + struct KinematicUtilities { + RigidBodyBullet *m_owner; + btScalar m_margin; + btManifoldArray m_manifoldArray; ///keep track of the contact manifolds + class btPairCachingGhostObject *m_ghostObject; + Vector<KinematicShape> m_shapes; + + KinematicUtilities(RigidBodyBullet *p_owner); + ~KinematicUtilities(); + + /// Used to set the default shape to ghost + void resetDefShape(); + void copyAllOwnerShapes(); + + private: + void just_delete_shapes(int new_size); + }; + +private: + friend class BulletPhysicsDirectBodyState; + + // This is required only for Kinematic movement + KinematicUtilities *kinematic_utilities; + + PhysicsServer::BodyMode mode; + PhysicsServer::BodyAxisLock axis_lock; + GodotMotionState *godotMotionState; + btRigidBody *btBody; + real_t mass; + real_t gravity_scale; + real_t linearDamp; + real_t angularDamp; + bool can_sleep; + + Vector<CollisionData> collisions; + // these parameters are used to avoid vector resize + int maxCollisionsDetection; + int collisionsCount; + + Vector<AreaBullet *> areasWhereIam; + // these parameters are used to avoid vector resize + int maxAreasWhereIam; + int areaWhereIamCount; + // Used to know if the area is used as gravity point + int countGravityPointSpaces; + bool isScratchedSpaceOverrideModificator; + + bool isTransformChanged; + + ForceIntegrationCallback *force_integration_callback; + +public: + RigidBodyBullet(); + ~RigidBodyBullet(); + + void init_kinematic_utilities(); + void destroy_kinematic_utilities(); + _FORCE_INLINE_ class KinematicUtilities *get_kinematic_utilities() const { return kinematic_utilities; } + + _FORCE_INLINE_ btRigidBody *get_bt_rigid_body() { return btBody; } + + virtual void reload_body(); + virtual void set_space(SpaceBullet *p_space); + + virtual void dispatch_callbacks(); + void set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata = Variant()); + void scratch(); + void scratch_space_override_modificator(); + + virtual void on_collision_filters_change(); + virtual void on_collision_checker_start(); + void set_max_collisions_detection(int p_maxCollisionsDetection) { + maxCollisionsDetection = p_maxCollisionsDetection; + collisions.resize(p_maxCollisionsDetection); + collisionsCount = 0; + } + int get_max_collisions_detection() { + return maxCollisionsDetection; + } + + bool can_add_collision() { return collisionsCount < maxCollisionsDetection; } + bool add_collision_object(RigidBodyBullet *p_otherObject, const Vector3 &p_hitWorldLocation, const Vector3 &p_hitLocalLocation, const Vector3 &p_hitNormal, int p_other_shape_index, int p_local_shape_index); + + void assert_no_constraints(); + + void set_activation_state(bool p_active); + bool is_active() const; + + void set_param(PhysicsServer::BodyParameter p_param, real_t); + real_t get_param(PhysicsServer::BodyParameter p_param) const; + + void set_mode(PhysicsServer::BodyMode p_mode); + PhysicsServer::BodyMode get_mode() const; + + void set_state(PhysicsServer::BodyState p_state, const Variant &p_variant); + Variant get_state(PhysicsServer::BodyState p_state) const; + + void apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse); + void apply_central_impulse(const Vector3 &p_force); + void apply_torque_impulse(const Vector3 &p_impulse); + + void apply_force(const Vector3 &p_force, const Vector3 &p_pos); + void apply_central_force(const Vector3 &p_force); + void apply_torque(const Vector3 &p_force); + + void set_applied_force(const Vector3 &p_force); + Vector3 get_applied_force() const; + void set_applied_torque(const Vector3 &p_torque); + Vector3 get_applied_torque() const; + + void set_axis_lock(PhysicsServer::BodyAxisLock p_lock); + PhysicsServer::BodyAxisLock get_axis_lock() const; + + /// Doc: + /// http://www.bulletphysics.org/mediawiki-1.5.8/index.php?title=Anti_tunneling_by_Motion_Clamping + void set_continuous_collision_detection(bool p_enable); + bool is_continuous_collision_detection_enabled() const; + + void set_linear_velocity(const Vector3 &p_velocity); + Vector3 get_linear_velocity() const; + + void set_angular_velocity(const Vector3 &p_velocity); + Vector3 get_angular_velocity() const; + + virtual void set_transform__bullet(const btTransform &p_global_transform); + virtual const btTransform &get_transform__bullet() const; + + virtual void on_shapes_changed(); + + virtual void on_enter_area(AreaBullet *p_area); + virtual void on_exit_area(AreaBullet *p_area); + void reload_space_override_modificator(); + + /// Kinematic + void reload_kinematic_shapes(); + +private: + void _internal_set_mass(real_t p_mass); +}; + +#endif 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)); +} diff --git a/modules/bullet/shape_bullet.h b/modules/bullet/shape_bullet.h new file mode 100644 index 0000000000..0a56fa1709 --- /dev/null +++ b/modules/bullet/shape_bullet.h @@ -0,0 +1,225 @@ +/*************************************************************************/ +/* shape_bullet.h */ +/* 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. */ +/*************************************************************************/ + +#ifndef SHAPE_BULLET_H +#define SHAPE_BULLET_H + +#include "LinearMath/btAlignedObjectArray.h" +#include "LinearMath/btScalar.h" +#include "LinearMath/btVector3.h" +#include "core/variant.h" +#include "geometry.h" +#include "rid_bullet.h" +#include "servers/physics_server.h" + +class ShapeBullet; +class btCollisionShape; +class ShapeOwnerBullet; +class btBvhTriangleMeshShape; + +class ShapeBullet : public RIDBullet { + + Map<ShapeOwnerBullet *, int> owners; + +protected: + /// return self + btCollisionShape *prepare(btCollisionShape *p_btShape) const; + void notifyShapeChanged(); + +public: + ShapeBullet(); + virtual ~ShapeBullet(); + + virtual btCollisionShape *create_bt_shape() = 0; + + void add_owner(ShapeOwnerBullet *p_owner); + void remove_owner(ShapeOwnerBullet *p_owner, bool p_permanentlyFromThisBody = false); + bool is_owner(ShapeOwnerBullet *p_owner) const; + const Map<ShapeOwnerBullet *, int> &get_owners() const; + + /// Setup the shape + virtual void set_data(const Variant &p_data) = 0; + virtual Variant get_data() const = 0; + + virtual PhysicsServer::ShapeType get_type() const = 0; + +public: + static class btEmptyShape *create_shape_empty(); + static class btStaticPlaneShape *create_shape_plane(const btVector3 &planeNormal, btScalar planeConstant); + static class btSphereShape *create_shape_sphere(btScalar radius); + static class btBoxShape *create_shape_box(const btVector3 &boxHalfExtents); + static class btCapsuleShapeZ *create_shape_capsule(btScalar radius, btScalar height); + /// IMPORTANT: Remember to delete the shape interface by calling: delete my_shape->getMeshInterface(); + static class btConvexPointCloudShape *create_shape_convex(btAlignedObjectArray<btVector3> &p_vertices, const btVector3 &p_local_scaling = btVector3(1, 1, 1)); + static class btScaledBvhTriangleMeshShape *create_shape_concave(btBvhTriangleMeshShape *p_mesh_shape, const btVector3 &p_local_scaling = btVector3(1, 1, 1)); + static class btHeightfieldTerrainShape *create_shape_height_field(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_cell_size); + static class btRayShape *create_shape_ray(real_t p_length); +}; + +class PlaneShapeBullet : public ShapeBullet { + + Plane plane; + +public: + PlaneShapeBullet(); + + virtual void set_data(const Variant &p_data); + virtual Variant get_data() const; + virtual PhysicsServer::ShapeType get_type() const; + virtual btCollisionShape *create_bt_shape(); + +private: + void setup(const Plane &p_plane); +}; + +class SphereShapeBullet : public ShapeBullet { + + real_t radius; + +public: + SphereShapeBullet(); + + _FORCE_INLINE_ real_t get_radius() { return radius; } + virtual void set_data(const Variant &p_data); + virtual Variant get_data() const; + virtual PhysicsServer::ShapeType get_type() const; + virtual btCollisionShape *create_bt_shape(); + +private: + void setup(real_t p_radius); +}; + +class BoxShapeBullet : public ShapeBullet { + + btVector3 half_extents; + +public: + BoxShapeBullet(); + + _FORCE_INLINE_ const btVector3 &get_half_extents() { return half_extents; } + virtual void set_data(const Variant &p_data); + virtual Variant get_data() const; + virtual PhysicsServer::ShapeType get_type() const; + virtual btCollisionShape *create_bt_shape(); + +private: + void setup(const Vector3 &p_half_extents); +}; + +class CapsuleShapeBullet : public ShapeBullet { + + real_t height; + real_t radius; + +public: + CapsuleShapeBullet(); + + _FORCE_INLINE_ real_t get_height() { return height; } + _FORCE_INLINE_ real_t get_radius() { return radius; } + virtual void set_data(const Variant &p_data); + virtual Variant get_data() const; + virtual PhysicsServer::ShapeType get_type() const; + virtual btCollisionShape *create_bt_shape(); + +private: + void setup(real_t p_height, real_t p_radius); +}; + +class ConvexPolygonShapeBullet : public ShapeBullet { + +public: + btAlignedObjectArray<btVector3> vertices; + + ConvexPolygonShapeBullet(); + + virtual void set_data(const Variant &p_data); + void get_vertices(Vector<Vector3> &out_vertices); + virtual Variant get_data() const; + virtual PhysicsServer::ShapeType get_type() const; + virtual btCollisionShape *create_bt_shape(); + +private: + void setup(const Vector<Vector3> &p_vertices); +}; + +class ConcavePolygonShapeBullet : public ShapeBullet { + class btBvhTriangleMeshShape *meshShape; + +public: + PoolVector<Vector3> faces; + + ConcavePolygonShapeBullet(); + virtual ~ConcavePolygonShapeBullet(); + + virtual void set_data(const Variant &p_data); + virtual Variant get_data() const; + virtual PhysicsServer::ShapeType get_type() const; + virtual btCollisionShape *create_bt_shape(); + +private: + void setup(PoolVector<Vector3> p_faces); +}; + +class HeightMapShapeBullet : public ShapeBullet { + +public: + PoolVector<real_t> heights; + int width; + int depth; + real_t cell_size; + + HeightMapShapeBullet(); + + virtual void set_data(const Variant &p_data); + virtual Variant get_data() const; + virtual PhysicsServer::ShapeType get_type() const; + virtual btCollisionShape *create_bt_shape(); + +private: + void setup(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_cell_size); +}; + +class RayShapeBullet : public ShapeBullet { + +public: + real_t length; + + RayShapeBullet(); + + virtual void set_data(const Variant &p_data); + virtual Variant get_data() const; + virtual PhysicsServer::ShapeType get_type() const; + virtual btCollisionShape *create_bt_shape(); + +private: + void setup(real_t p_length); +}; +#endif diff --git a/modules/bullet/shape_owner_bullet.cpp b/modules/bullet/shape_owner_bullet.cpp new file mode 100644 index 0000000000..04b2b01675 --- /dev/null +++ b/modules/bullet/shape_owner_bullet.cpp @@ -0,0 +1,32 @@ +/*************************************************************************/ +/* shape_owner_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_owner_bullet.h" diff --git a/modules/bullet/shape_owner_bullet.h b/modules/bullet/shape_owner_bullet.h new file mode 100644 index 0000000000..d2f3d321c7 --- /dev/null +++ b/modules/bullet/shape_owner_bullet.h @@ -0,0 +1,52 @@ +/*************************************************************************/ +/* shape_owner_bullet.h */ +/* 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. */ +/*************************************************************************/ + +#ifndef SHAPE_OWNER_BULLET_H +#define SHAPE_OWNER_BULLET_H + +#include "rid_bullet.h" + +class ShapeBullet; +class btCollisionShape; +class CollisionObjectBullet; + +/// Each clas that want to use Shapes must inherit this class +/// E.G. BodyShape is a child of this +class ShapeOwnerBullet { +public: + /// This is used to set new shape or replace existing + //virtual void _internal_replaceShape(btCollisionShape *p_old_shape, btCollisionShape *p_new_shape) = 0; + virtual void on_shape_changed(const ShapeBullet *const p_shape) = 0; + virtual void on_shapes_changed() = 0; + virtual void remove_shape(class ShapeBullet *p_shape) = 0; + virtual ~ShapeOwnerBullet() {} +}; +#endif diff --git a/modules/bullet/slider_joint_bullet.cpp b/modules/bullet/slider_joint_bullet.cpp new file mode 100644 index 0000000000..2da65677f5 --- /dev/null +++ b/modules/bullet/slider_joint_bullet.cpp @@ -0,0 +1,385 @@ +/*************************************************************************/ +/* slider_joint_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 "slider_joint_bullet.h" +#include "BulletDynamics/ConstraintSolver/btSliderConstraint.h" +#include "bullet_types_converter.h" +#include "bullet_utilities.h" +#include "rigid_body_bullet.h" + +SliderJointBullet::SliderJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB) + : JointBullet() { + btTransform btFrameA; + G_TO_B(frameInA, btFrameA); + if (rbB) { + btTransform btFrameB; + G_TO_B(frameInB, btFrameB); + sliderConstraint = bulletnew(btSliderConstraint(*rbA->get_bt_rigid_body(), *rbB->get_bt_rigid_body(), btFrameA, btFrameB, true)); + + } else { + sliderConstraint = bulletnew(btSliderConstraint(*rbA->get_bt_rigid_body(), btFrameA, true)); + } + setup(sliderConstraint); +} + +const RigidBodyBullet *SliderJointBullet::getRigidBodyA() const { + return static_cast<RigidBodyBullet *>(sliderConstraint->getRigidBodyA().getUserPointer()); +} + +const RigidBodyBullet *SliderJointBullet::getRigidBodyB() const { + return static_cast<RigidBodyBullet *>(sliderConstraint->getRigidBodyB().getUserPointer()); +} + +const Transform SliderJointBullet::getCalculatedTransformA() const { + btTransform btTransform = sliderConstraint->getCalculatedTransformA(); + Transform gTrans; + B_TO_G(btTransform, gTrans); + return gTrans; +} + +const Transform SliderJointBullet::getCalculatedTransformB() const { + btTransform btTransform = sliderConstraint->getCalculatedTransformB(); + Transform gTrans; + B_TO_G(btTransform, gTrans); + return gTrans; +} + +const Transform SliderJointBullet::getFrameOffsetA() const { + btTransform btTransform = sliderConstraint->getFrameOffsetA(); + Transform gTrans; + B_TO_G(btTransform, gTrans); + return gTrans; +} + +const Transform SliderJointBullet::getFrameOffsetB() const { + btTransform btTransform = sliderConstraint->getFrameOffsetB(); + Transform gTrans; + B_TO_G(btTransform, gTrans); + return gTrans; +} + +Transform SliderJointBullet::getFrameOffsetA() { + btTransform btTransform = sliderConstraint->getFrameOffsetA(); + Transform gTrans; + B_TO_G(btTransform, gTrans); + return gTrans; +} + +Transform SliderJointBullet::getFrameOffsetB() { + btTransform btTransform = sliderConstraint->getFrameOffsetB(); + Transform gTrans; + B_TO_G(btTransform, gTrans); + return gTrans; +} + +real_t SliderJointBullet::getLowerLinLimit() const { + return sliderConstraint->getLowerLinLimit(); +} + +void SliderJointBullet::setLowerLinLimit(real_t lowerLimit) { + sliderConstraint->setLowerLinLimit(lowerLimit); +} +real_t SliderJointBullet::getUpperLinLimit() const { + return sliderConstraint->getUpperLinLimit(); +} + +void SliderJointBullet::setUpperLinLimit(real_t upperLimit) { + sliderConstraint->setUpperLinLimit(upperLimit); +} + +real_t SliderJointBullet::getLowerAngLimit() const { + return sliderConstraint->getLowerAngLimit(); +} + +void SliderJointBullet::setLowerAngLimit(real_t lowerLimit) { + sliderConstraint->setLowerAngLimit(lowerLimit); +} + +real_t SliderJointBullet::getUpperAngLimit() const { + return sliderConstraint->getUpperAngLimit(); +} + +void SliderJointBullet::setUpperAngLimit(real_t upperLimit) { + sliderConstraint->setUpperAngLimit(upperLimit); +} + +real_t SliderJointBullet::getSoftnessDirLin() const { + return sliderConstraint->getSoftnessDirLin(); +} + +real_t SliderJointBullet::getRestitutionDirLin() const { + return sliderConstraint->getRestitutionDirLin(); +} + +real_t SliderJointBullet::getDampingDirLin() const { + return sliderConstraint->getDampingDirLin(); +} + +real_t SliderJointBullet::getSoftnessDirAng() const { + return sliderConstraint->getSoftnessDirAng(); +} + +real_t SliderJointBullet::getRestitutionDirAng() const { + return sliderConstraint->getRestitutionDirAng(); +} + +real_t SliderJointBullet::getDampingDirAng() const { + return sliderConstraint->getDampingDirAng(); +} + +real_t SliderJointBullet::getSoftnessLimLin() const { + return sliderConstraint->getSoftnessLimLin(); +} + +real_t SliderJointBullet::getRestitutionLimLin() const { + return sliderConstraint->getRestitutionLimLin(); +} + +real_t SliderJointBullet::getDampingLimLin() const { + return sliderConstraint->getDampingLimLin(); +} + +real_t SliderJointBullet::getSoftnessLimAng() const { + return sliderConstraint->getSoftnessLimAng(); +} + +real_t SliderJointBullet::getRestitutionLimAng() const { + return sliderConstraint->getRestitutionLimAng(); +} + +real_t SliderJointBullet::getDampingLimAng() const { + return sliderConstraint->getDampingLimAng(); +} + +real_t SliderJointBullet::getSoftnessOrthoLin() const { + return sliderConstraint->getSoftnessOrthoLin(); +} + +real_t SliderJointBullet::getRestitutionOrthoLin() const { + return sliderConstraint->getRestitutionOrthoLin(); +} + +real_t SliderJointBullet::getDampingOrthoLin() const { + return sliderConstraint->getDampingOrthoLin(); +} + +real_t SliderJointBullet::getSoftnessOrthoAng() const { + return sliderConstraint->getSoftnessOrthoAng(); +} + +real_t SliderJointBullet::getRestitutionOrthoAng() const { + return sliderConstraint->getRestitutionOrthoAng(); +} + +real_t SliderJointBullet::getDampingOrthoAng() const { + return sliderConstraint->getDampingOrthoAng(); +} + +void SliderJointBullet::setSoftnessDirLin(real_t softnessDirLin) { + sliderConstraint->setSoftnessDirLin(softnessDirLin); +} + +void SliderJointBullet::setRestitutionDirLin(real_t restitutionDirLin) { + sliderConstraint->setRestitutionDirLin(restitutionDirLin); +} + +void SliderJointBullet::setDampingDirLin(real_t dampingDirLin) { + sliderConstraint->setDampingDirLin(dampingDirLin); +} + +void SliderJointBullet::setSoftnessDirAng(real_t softnessDirAng) { + sliderConstraint->setSoftnessDirAng(softnessDirAng); +} + +void SliderJointBullet::setRestitutionDirAng(real_t restitutionDirAng) { + sliderConstraint->setRestitutionDirAng(restitutionDirAng); +} + +void SliderJointBullet::setDampingDirAng(real_t dampingDirAng) { + sliderConstraint->setDampingDirAng(dampingDirAng); +} + +void SliderJointBullet::setSoftnessLimLin(real_t softnessLimLin) { + sliderConstraint->setSoftnessLimLin(softnessLimLin); +} + +void SliderJointBullet::setRestitutionLimLin(real_t restitutionLimLin) { + sliderConstraint->setRestitutionLimLin(restitutionLimLin); +} + +void SliderJointBullet::setDampingLimLin(real_t dampingLimLin) { + sliderConstraint->setDampingLimLin(dampingLimLin); +} + +void SliderJointBullet::setSoftnessLimAng(real_t softnessLimAng) { + sliderConstraint->setSoftnessLimAng(softnessLimAng); +} + +void SliderJointBullet::setRestitutionLimAng(real_t restitutionLimAng) { + sliderConstraint->setRestitutionLimAng(restitutionLimAng); +} + +void SliderJointBullet::setDampingLimAng(real_t dampingLimAng) { + sliderConstraint->setDampingLimAng(dampingLimAng); +} + +void SliderJointBullet::setSoftnessOrthoLin(real_t softnessOrthoLin) { + sliderConstraint->setSoftnessOrthoLin(softnessOrthoLin); +} + +void SliderJointBullet::setRestitutionOrthoLin(real_t restitutionOrthoLin) { + sliderConstraint->setRestitutionOrthoLin(restitutionOrthoLin); +} + +void SliderJointBullet::setDampingOrthoLin(real_t dampingOrthoLin) { + sliderConstraint->setDampingOrthoLin(dampingOrthoLin); +} + +void SliderJointBullet::setSoftnessOrthoAng(real_t softnessOrthoAng) { + sliderConstraint->setSoftnessOrthoAng(softnessOrthoAng); +} + +void SliderJointBullet::setRestitutionOrthoAng(real_t restitutionOrthoAng) { + sliderConstraint->setRestitutionOrthoAng(restitutionOrthoAng); +} + +void SliderJointBullet::setDampingOrthoAng(real_t dampingOrthoAng) { + sliderConstraint->setDampingOrthoAng(dampingOrthoAng); +} + +void SliderJointBullet::setPoweredLinMotor(bool onOff) { + sliderConstraint->setPoweredLinMotor(onOff); +} + +bool SliderJointBullet::getPoweredLinMotor() { + return sliderConstraint->getPoweredLinMotor(); +} + +void SliderJointBullet::setTargetLinMotorVelocity(real_t targetLinMotorVelocity) { + sliderConstraint->setTargetLinMotorVelocity(targetLinMotorVelocity); +} + +real_t SliderJointBullet::getTargetLinMotorVelocity() { + return sliderConstraint->getTargetLinMotorVelocity(); +} + +void SliderJointBullet::setMaxLinMotorForce(real_t maxLinMotorForce) { + sliderConstraint->setMaxLinMotorForce(maxLinMotorForce); +} + +real_t SliderJointBullet::getMaxLinMotorForce() { + return sliderConstraint->getMaxLinMotorForce(); +} + +void SliderJointBullet::setPoweredAngMotor(bool onOff) { + sliderConstraint->setPoweredAngMotor(onOff); +} + +bool SliderJointBullet::getPoweredAngMotor() { + return sliderConstraint->getPoweredAngMotor(); +} + +void SliderJointBullet::setTargetAngMotorVelocity(real_t targetAngMotorVelocity) { + sliderConstraint->setTargetAngMotorVelocity(targetAngMotorVelocity); +} + +real_t SliderJointBullet::getTargetAngMotorVelocity() { + return sliderConstraint->getTargetAngMotorVelocity(); +} + +void SliderJointBullet::setMaxAngMotorForce(real_t maxAngMotorForce) { + sliderConstraint->setMaxAngMotorForce(maxAngMotorForce); +} + +real_t SliderJointBullet::getMaxAngMotorForce() { + return sliderConstraint->getMaxAngMotorForce(); +} + +real_t SliderJointBullet::getLinearPos() { + return sliderConstraint->getLinearPos(); + ; +} + +void SliderJointBullet::set_param(PhysicsServer::SliderJointParam p_param, real_t p_value) { + switch (p_param) { + case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_UPPER: setUpperLinLimit(p_value); break; + case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_LOWER: setLowerLinLimit(p_value); break; + case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS: setSoftnessLimLin(p_value); break; + case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION: setRestitutionLimLin(p_value); break; + case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_DAMPING: setDampingLimLin(p_value); break; + case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS: setSoftnessDirLin(p_value); break; + case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION: setRestitutionDirLin(p_value); break; + case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_DAMPING: setDampingDirLin(p_value); break; + case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS: setSoftnessOrthoLin(p_value); break; + case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION: setRestitutionOrthoLin(p_value); break; + case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING: setDampingOrthoLin(p_value); break; + case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_UPPER: setUpperAngLimit(p_value); break; + case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_LOWER: setLowerAngLimit(p_value); break; + case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS: setSoftnessLimAng(p_value); break; + case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION: setRestitutionLimAng(p_value); break; + case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING: setDampingLimAng(p_value); break; + case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS: setSoftnessDirAng(p_value); break; + case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION: setRestitutionDirAng(p_value); break; + case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_DAMPING: setDampingDirAng(p_value); break; + case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS: setSoftnessOrthoAng(p_value); break; + case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION: setRestitutionOrthoAng(p_value); break; + case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING: setDampingOrthoAng(p_value); break; + } +} + +real_t SliderJointBullet::get_param(PhysicsServer::SliderJointParam p_param) const { + switch (p_param) { + case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_UPPER: return getUpperLinLimit(); + case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_LOWER: return getLowerLinLimit(); + case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS: return getSoftnessLimLin(); + case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION: return getRestitutionLimLin(); + case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_DAMPING: return getDampingLimLin(); + case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS: return getSoftnessDirLin(); + case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION: return getRestitutionDirLin(); + case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_DAMPING: return getDampingDirLin(); + case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS: return getSoftnessOrthoLin(); + case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION: return getRestitutionOrthoLin(); + case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING: return getDampingOrthoLin(); + case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_UPPER: return getUpperAngLimit(); + case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_LOWER: return getLowerAngLimit(); + case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS: return getSoftnessLimAng(); + case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION: return getRestitutionLimAng(); + case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING: return getDampingLimAng(); + case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS: return getSoftnessDirAng(); + case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION: return getRestitutionDirAng(); + case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_DAMPING: return getDampingDirAng(); + case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS: return getSoftnessOrthoAng(); + case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION: return getRestitutionOrthoAng(); + case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING: return getDampingOrthoAng(); + default: + return 0; + } +} diff --git a/modules/bullet/slider_joint_bullet.h b/modules/bullet/slider_joint_bullet.h new file mode 100644 index 0000000000..d50c376ea6 --- /dev/null +++ b/modules/bullet/slider_joint_bullet.h @@ -0,0 +1,118 @@ +/*************************************************************************/ +/* slider_joint_bullet.h */ +/* 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. */ +/*************************************************************************/ + +#ifndef SLIDER_JOINT_BULLET_H +#define SLIDER_JOINT_BULLET_H + +#include "joint_bullet.h" + +class RigidBodyBullet; + +class SliderJointBullet : public JointBullet { + class btSliderConstraint *sliderConstraint; + +public: + /// Reference frame is A + SliderJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB); + + virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_SLIDER; } + + const RigidBodyBullet *getRigidBodyA() const; + const RigidBodyBullet *getRigidBodyB() const; + const Transform getCalculatedTransformA() const; + const Transform getCalculatedTransformB() const; + const Transform getFrameOffsetA() const; + const Transform getFrameOffsetB() const; + Transform getFrameOffsetA(); + Transform getFrameOffsetB(); + real_t getLowerLinLimit() const; + void setLowerLinLimit(real_t lowerLimit); + real_t getUpperLinLimit() const; + void setUpperLinLimit(real_t upperLimit); + real_t getLowerAngLimit() const; + void setLowerAngLimit(real_t lowerLimit); + real_t getUpperAngLimit() const; + void setUpperAngLimit(real_t upperLimit); + + real_t getSoftnessDirLin() const; + real_t getRestitutionDirLin() const; + real_t getDampingDirLin() const; + real_t getSoftnessDirAng() const; + real_t getRestitutionDirAng() const; + real_t getDampingDirAng() const; + real_t getSoftnessLimLin() const; + real_t getRestitutionLimLin() const; + real_t getDampingLimLin() const; + real_t getSoftnessLimAng() const; + real_t getRestitutionLimAng() const; + real_t getDampingLimAng() const; + real_t getSoftnessOrthoLin() const; + real_t getRestitutionOrthoLin() const; + real_t getDampingOrthoLin() const; + real_t getSoftnessOrthoAng() const; + real_t getRestitutionOrthoAng() const; + real_t getDampingOrthoAng() const; + void setSoftnessDirLin(real_t softnessDirLin); + void setRestitutionDirLin(real_t restitutionDirLin); + void setDampingDirLin(real_t dampingDirLin); + void setSoftnessDirAng(real_t softnessDirAng); + void setRestitutionDirAng(real_t restitutionDirAng); + void setDampingDirAng(real_t dampingDirAng); + void setSoftnessLimLin(real_t softnessLimLin); + void setRestitutionLimLin(real_t restitutionLimLin); + void setDampingLimLin(real_t dampingLimLin); + void setSoftnessLimAng(real_t softnessLimAng); + void setRestitutionLimAng(real_t restitutionLimAng); + void setDampingLimAng(real_t dampingLimAng); + void setSoftnessOrthoLin(real_t softnessOrthoLin); + void setRestitutionOrthoLin(real_t restitutionOrthoLin); + void setDampingOrthoLin(real_t dampingOrthoLin); + void setSoftnessOrthoAng(real_t softnessOrthoAng); + void setRestitutionOrthoAng(real_t restitutionOrthoAng); + void setDampingOrthoAng(real_t dampingOrthoAng); + void setPoweredLinMotor(bool onOff); + bool getPoweredLinMotor(); + void setTargetLinMotorVelocity(real_t targetLinMotorVelocity); + real_t getTargetLinMotorVelocity(); + void setMaxLinMotorForce(real_t maxLinMotorForce); + real_t getMaxLinMotorForce(); + void setPoweredAngMotor(bool onOff); + bool getPoweredAngMotor(); + void setTargetAngMotorVelocity(real_t targetAngMotorVelocity); + real_t getTargetAngMotorVelocity(); + void setMaxAngMotorForce(real_t maxAngMotorForce); + real_t getMaxAngMotorForce(); + real_t getLinearPos(); + + void set_param(PhysicsServer::SliderJointParam p_param, real_t p_value); + real_t get_param(PhysicsServer::SliderJointParam p_param) const; +}; +#endif diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp new file mode 100644 index 0000000000..64ef7bfad2 --- /dev/null +++ b/modules/bullet/soft_body_bullet.cpp @@ -0,0 +1,303 @@ +/*************************************************************************/ +/* soft_body_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 "soft_body_bullet.h" +#include "bullet_types_converter.h" +#include "bullet_utilities.h" +#include "space_bullet.h" + +#include "scene/3d/immediate_geometry.h" + +SoftBodyBullet::SoftBodyBullet() + : CollisionObjectBullet(CollisionObjectBullet::TYPE_SOFT_BODY), mass(1), simulation_precision(5), stiffness(0.5f), pressure_coefficient(50), damping_coefficient(0.005), drag_coefficient(0.005), bt_soft_body(NULL), soft_shape_type(SOFT_SHAPETYPE_NONE), isScratched(false), soft_body_shape_data(NULL) { + + test_geometry = memnew(ImmediateGeometry); + + red_mat = Ref<SpatialMaterial>(memnew(SpatialMaterial)); + red_mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + red_mat->set_line_width(20.0); + red_mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); + red_mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + red_mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); + red_mat->set_albedo(Color(1, 0, 0, 1)); + test_geometry->set_material_override(red_mat); + + test_is_in_scene = false; +} + +SoftBodyBullet::~SoftBodyBullet() { + bulletdelete(soft_body_shape_data); +} + +void SoftBodyBullet::reload_body() { + if (space) { + space->remove_soft_body(this); + space->add_soft_body(this); + } +} + +void SoftBodyBullet::set_space(SpaceBullet *p_space) { + if (space) { + isScratched = false; + + // Remove this object from the physics world + space->remove_soft_body(this); + } + + space = p_space; + + if (space) { + space->add_soft_body(this); + } + + reload_soft_body(); +} + +void SoftBodyBullet::dispatch_callbacks() { + if (!bt_soft_body) { + return; + } + + if (!test_is_in_scene) { + test_is_in_scene = true; + SceneTree::get_singleton()->get_current_scene()->add_child(test_geometry); + } + + test_geometry->clear(); + test_geometry->begin(Mesh::PRIMITIVE_LINES, NULL); + bool first = true; + Vector3 pos; + for (int i = 0; i < bt_soft_body->m_nodes.size(); ++i) { + const btSoftBody::Node &n = bt_soft_body->m_nodes[i]; + B_TO_G(n.m_x, pos); + test_geometry->add_vertex(pos); + if (!first) { + test_geometry->add_vertex(pos); + } else { + first = false; + } + } + test_geometry->end(); +} + +void SoftBodyBullet::on_collision_filters_change() { +} + +void SoftBodyBullet::on_collision_checker_start() { +} + +void SoftBodyBullet::on_enter_area(AreaBullet *p_area) { +} + +void SoftBodyBullet::on_exit_area(AreaBullet *p_area) { +} + +void SoftBodyBullet::set_trimesh_body_shape(PoolVector<int> p_indices, PoolVector<Vector3> p_vertices, int p_triangles_num) { + + TrimeshSoftShapeData *shape_data = bulletnew(TrimeshSoftShapeData); + shape_data->m_triangles_indices = p_indices; + shape_data->m_vertices = p_vertices; + shape_data->m_triangles_num = p_triangles_num; + + set_body_shape_data(shape_data, SOFT_SHAPE_TYPE_TRIMESH); + reload_soft_body(); +} + +void SoftBodyBullet::set_body_shape_data(SoftShapeData *p_soft_shape_data, SoftShapeType p_type) { + bulletdelete(soft_body_shape_data); + soft_body_shape_data = p_soft_shape_data; + soft_shape_type = p_type; +} + +void SoftBodyBullet::set_transform(const Transform &p_transform) { + transform = p_transform; + if (bt_soft_body) { + // TODO the softbody set new transform considering the current transform as center of world + // like if it's local transform, so I must fix this by setting nwe transform considering the old + btTransform bt_trans; + G_TO_B(transform, bt_trans); + //bt_soft_body->transform(bt_trans); + } +} + +const Transform &SoftBodyBullet::get_transform() const { + return transform; +} + +void SoftBodyBullet::get_first_node_origin(btVector3 &p_out_origin) const { + if (bt_soft_body && bt_soft_body->m_nodes.size()) { + p_out_origin = bt_soft_body->m_nodes[0].m_x; + } else { + p_out_origin.setZero(); + } +} + +void SoftBodyBullet::set_activation_state(bool p_active) { + if (p_active) { + bt_soft_body->setActivationState(ACTIVE_TAG); + } else { + bt_soft_body->setActivationState(WANTS_DEACTIVATION); + } +} + +void SoftBodyBullet::set_mass(real_t p_val) { + if (0 >= p_val) { + p_val = 1; + } + mass = p_val; + if (bt_soft_body) { + bt_soft_body->setTotalMass(mass); + } +} + +void SoftBodyBullet::set_stiffness(real_t p_val) { + stiffness = p_val; + if (bt_soft_body) { + mat0->m_kAST = stiffness; + mat0->m_kLST = stiffness; + mat0->m_kVST = stiffness; + } +} + +void SoftBodyBullet::set_simulation_precision(int p_val) { + simulation_precision = p_val; + if (bt_soft_body) { + bt_soft_body->m_cfg.piterations = simulation_precision; + } +} + +void SoftBodyBullet::set_pressure_coefficient(real_t p_val) { + pressure_coefficient = p_val; + if (bt_soft_body) { + bt_soft_body->m_cfg.kPR = pressure_coefficient; + } +} + +void SoftBodyBullet::set_damping_coefficient(real_t p_val) { + damping_coefficient = p_val; + if (bt_soft_body) { + bt_soft_body->m_cfg.kDP = damping_coefficient; + } +} + +void SoftBodyBullet::set_drag_coefficient(real_t p_val) { + drag_coefficient = p_val; + if (bt_soft_body) { + bt_soft_body->m_cfg.kDG = drag_coefficient; + } +} + +void SoftBodyBullet::reload_soft_body() { + + destroy_soft_body(); + create_soft_body(); + + if (bt_soft_body) { + + // TODO the softbody set new transform considering the current transform as center of world + // like if it's local transform, so I must fix this by setting nwe transform considering the old + btTransform bt_trans; + G_TO_B(transform, bt_trans); + bt_soft_body->transform(bt_trans); + + bt_soft_body->generateBendingConstraints(2, mat0); + mat0->m_kAST = stiffness; + mat0->m_kLST = stiffness; + mat0->m_kVST = stiffness; + + bt_soft_body->m_cfg.piterations = simulation_precision; + bt_soft_body->m_cfg.kDP = damping_coefficient; + bt_soft_body->m_cfg.kDG = drag_coefficient; + bt_soft_body->m_cfg.kPR = pressure_coefficient; + bt_soft_body->setTotalMass(mass); + } + if (space) { + // TODO remove this please + space->add_soft_body(this); + } +} + +void SoftBodyBullet::create_soft_body() { + if (!space || !soft_body_shape_data) { + return; + } + ERR_FAIL_COND(!space->is_using_soft_world()); + switch (soft_shape_type) { + case SOFT_SHAPE_TYPE_TRIMESH: { + TrimeshSoftShapeData *trimesh_data = static_cast<TrimeshSoftShapeData *>(soft_body_shape_data); + + Vector<int> indices; + Vector<btScalar> vertices; + + int i; + const int indices_size = trimesh_data->m_triangles_indices.size(); + const int vertices_size = trimesh_data->m_vertices.size(); + indices.resize(indices_size); + vertices.resize(vertices_size * 3); + + PoolVector<int>::Read i_r = trimesh_data->m_triangles_indices.read(); + for (i = 0; i < indices_size; ++i) { + indices[i] = i_r[i]; + } + i_r = PoolVector<int>::Read(); + + PoolVector<Vector3>::Read f_r = trimesh_data->m_vertices.read(); + for (int j = i = 0; i < vertices_size; ++i, j += 3) { + vertices[j + 0] = f_r[i][0]; + vertices[j + 1] = f_r[i][1]; + vertices[j + 2] = f_r[i][2]; + } + f_r = PoolVector<Vector3>::Read(); + + bt_soft_body = btSoftBodyHelpers::CreateFromTriMesh(*space->get_soft_body_world_info(), vertices.ptr(), indices.ptr(), trimesh_data->m_triangles_num); + } break; + default: + ERR_PRINT("Shape type not supported"); + return; + } + + setupBulletCollisionObject(bt_soft_body); + bt_soft_body->getCollisionShape()->setMargin(0.001f); + bt_soft_body->setCollisionFlags(bt_soft_body->getCollisionFlags() & (~(btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT))); + mat0 = bt_soft_body->appendMaterial(); +} + +void SoftBodyBullet::destroy_soft_body() { + if (space) { + /// This step is required to assert that the body is not into the world during deletion + /// This step is required since to change the body shape the body must be re-created. + /// Here is handled the case when the body is assigned into a world and the body + /// shape is changed. + space->remove_soft_body(this); + } + destroyBulletCollisionObject(); + bt_soft_body = NULL; +} diff --git a/modules/bullet/soft_body_bullet.h b/modules/bullet/soft_body_bullet.h new file mode 100644 index 0000000000..9ee7cd76d3 --- /dev/null +++ b/modules/bullet/soft_body_bullet.h @@ -0,0 +1,136 @@ +/*************************************************************************/ +/* soft_body_bullet.h */ +/* 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. */ +/*************************************************************************/ + +#ifndef SOFT_BODY_BULLET_H +#define SOFT_BODY_BULLET_H + +#ifdef None +/// This is required to remove the macro None defined by x11 compiler because this word "None" is used internally by Bullet +#undef None +#define x11_None 0L +#endif + +#include "BulletSoftBody/btSoftBodyHelpers.h" +#include "collision_object_bullet.h" + +#ifdef x11_None +/// This is required to re add the macro None defined by x11 compiler +#undef x11_None +#define None 0L +#endif + +#include "scene/resources/material.h" // TODO remove thsi please + +struct SoftShapeData {}; +struct TrimeshSoftShapeData : public SoftShapeData { + PoolVector<int> m_triangles_indices; + PoolVector<Vector3> m_vertices; + int m_triangles_num; +}; + +class SoftBodyBullet : public CollisionObjectBullet { +public: + enum SoftShapeType { + SOFT_SHAPETYPE_NONE = 0, + SOFT_SHAPE_TYPE_TRIMESH + }; + +private: + btSoftBody *bt_soft_body; + btSoftBody::Material *mat0; // This is just a copy of pointer managed by btSoftBody + SoftShapeType soft_shape_type; + bool isScratched; + + SoftShapeData *soft_body_shape_data; + + Transform transform; + int simulation_precision; + real_t mass; + real_t stiffness; // [0,1] + real_t pressure_coefficient; // [-inf,+inf] + real_t damping_coefficient; // [0,1] + real_t drag_coefficient; // [0,1] + + class ImmediateGeometry *test_geometry; // TODO remove this please + Ref<SpatialMaterial> red_mat; // TODO remove this please + bool test_is_in_scene; // TODO remove this please + +public: + SoftBodyBullet(); + ~SoftBodyBullet(); + + virtual void reload_body(); + virtual void set_space(SpaceBullet *p_space); + + virtual void dispatch_callbacks(); + virtual void on_collision_filters_change(); + virtual void on_collision_checker_start(); + virtual void on_enter_area(AreaBullet *p_area); + virtual void on_exit_area(AreaBullet *p_area); + + _FORCE_INLINE_ btSoftBody *get_bt_soft_body() const { return bt_soft_body; } + + void set_trimesh_body_shape(PoolVector<int> p_indices, PoolVector<Vector3> p_vertices, int p_triangles_num); + void set_body_shape_data(SoftShapeData *p_soft_shape_data, SoftShapeType p_type); + + void set_transform(const Transform &p_transform); + /// This function doesn't return the exact COM transform. + /// It returns the origin only of first node (vertice) of current soft body + /// --- + /// The soft body doesn't have a fixed center of mass, but is a group of nodes (vertices) + /// that each has its own position in the world. + /// For this reason return the correct COM is not so simple and must be calculate + /// Check this to improve this function http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=8803 + const Transform &get_transform() const; + void get_first_node_origin(btVector3 &p_out_origin) const; + + void set_activation_state(bool p_active); + + void set_mass(real_t p_val); + _FORCE_INLINE_ real_t get_mass() const { return mass; } + void set_stiffness(real_t p_val); + _FORCE_INLINE_ real_t get_stiffness() const { return stiffness; } + void set_simulation_precision(int p_val); + _FORCE_INLINE_ int get_simulation_precision() const { return simulation_precision; } + void set_pressure_coefficient(real_t p_val); + _FORCE_INLINE_ real_t get_pressure_coefficient() const { return pressure_coefficient; } + void set_damping_coefficient(real_t p_val); + _FORCE_INLINE_ real_t get_damping_coefficient() const { return damping_coefficient; } + void set_drag_coefficient(real_t p_val); + _FORCE_INLINE_ real_t get_drag_coefficient() const { return drag_coefficient; } + +private: + void reload_soft_body(); + void create_soft_body(); + void destroy_soft_body(); +}; + +#endif // SOFT_BODY_BULLET_H diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp new file mode 100644 index 0000000000..af7f511fab --- /dev/null +++ b/modules/bullet/space_bullet.cpp @@ -0,0 +1,1163 @@ +/*************************************************************************/ +/* space_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 "space_bullet.h" +#include "BulletCollision/CollisionDispatch/btCollisionObject.h" +#include "BulletCollision/CollisionDispatch/btGhostObject.h" +#include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h" +#include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h" +#include "BulletCollision/NarrowPhaseCollision/btPointCollector.h" +#include "BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h" +#include "BulletSoftBody/btSoftRigidDynamicsWorld.h" +#include "btBulletDynamicsCommon.h" +#include "bullet_physics_server.h" +#include "bullet_types_converter.h" +#include "bullet_utilities.h" +#include "constraint_bullet.h" +#include "godot_collision_configuration.h" +#include "godot_collision_dispatcher.h" +#include "rigid_body_bullet.h" +#include "servers/physics_server.h" +#include "soft_body_bullet.h" +#include "ustring.h" +#include <assert.h> + +// test only +//#include "scene/3d/immediate_geometry.h" + +BulletPhysicsDirectSpaceState::BulletPhysicsDirectSpaceState(SpaceBullet *p_space) + : PhysicsDirectSpaceState(), space(p_space) {} + +int BulletPhysicsDirectSpaceState::intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_layer, uint32_t p_object_type_mask) { + + if (p_result_max <= 0) + return 0; + + btVector3 bt_point; + G_TO_B(p_point, bt_point); + + btSphereShape sphere_point(0.f); + btCollisionObject collision_object_point; + collision_object_point.setCollisionShape(&sphere_point); + collision_object_point.setWorldTransform(btTransform(btQuaternion::getIdentity(), bt_point)); + + // Setup query + GodotAllContactResultCallback btResult(&collision_object_point, r_results, p_result_max, &p_exclude); + btResult.m_collisionFilterGroup = p_collision_layer; + btResult.m_collisionFilterMask = p_object_type_mask; + space->dynamicsWorld->contactTest(&collision_object_point, btResult); + + // The results is already populated by GodotAllConvexResultCallback + return btResult.m_count; +} + +bool BulletPhysicsDirectSpaceState::intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude, uint32_t p_collision_layer, uint32_t p_object_type_mask, bool p_pick_ray) { + + btVector3 btVec_from; + btVector3 btVec_to; + + G_TO_B(p_from, btVec_from); + G_TO_B(p_to, btVec_to); + + // setup query + GodotClosestRayResultCallback btResult(btVec_from, btVec_to, &p_exclude); + btResult.m_collisionFilterGroup = p_collision_layer; + btResult.m_collisionFilterMask = p_object_type_mask; + btResult.m_pickRay = p_pick_ray; + + space->dynamicsWorld->rayTest(btVec_from, btVec_to, btResult); + if (btResult.hasHit()) { + B_TO_G(btResult.m_hitPointWorld, r_result.position); + B_TO_G(btResult.m_hitNormalWorld.normalize(), r_result.normal); + CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btResult.m_collisionObject->getUserPointer()); + if (gObj) { + r_result.shape = 0; + r_result.rid = gObj->get_self(); + r_result.collider_id = gObj->get_instance_id(); + r_result.collider = 0 == r_result.collider_id ? NULL : ObjectDB::get_instance(r_result.collider_id); + } else { + WARN_PRINTS("The raycast performed has hit a collision object that is not part of Godot scene, please check it."); + } + return true; + } else { + return false; + } +} + +int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Transform &p_xform, float p_margin, ShapeResult *p_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_layer, uint32_t p_object_type_mask) { + if (p_result_max <= 0) + return 0; + + ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->get(p_shape); + + btConvexShape *btConvex = dynamic_cast<btConvexShape *>(shape->create_bt_shape()); + if (!btConvex) { + bulletdelete(btConvex); + ERR_PRINTS("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type())); + return 0; + } + + btVector3 scale_with_margin; + G_TO_B(p_xform.basis.get_scale(), scale_with_margin); + btConvex->setLocalScaling(scale_with_margin); + + btTransform bt_xform; + G_TO_B(p_xform, bt_xform); + + btCollisionObject collision_object; + collision_object.setCollisionShape(btConvex); + collision_object.setWorldTransform(bt_xform); + + GodotAllContactResultCallback btQuery(&collision_object, p_results, p_result_max, &p_exclude); + btQuery.m_collisionFilterGroup = p_collision_layer; + btQuery.m_collisionFilterMask = p_object_type_mask; + btQuery.m_closestDistanceThreshold = p_margin; + space->dynamicsWorld->contactTest(&collision_object, btQuery); + + bulletdelete(btConvex); + + return btQuery.m_count; +} + +bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, float p_margin, float &p_closest_safe, float &p_closest_unsafe, const Set<RID> &p_exclude, uint32_t p_collision_layer, uint32_t p_object_type_mask, ShapeRestInfo *r_info) { + ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->get(p_shape); + + btConvexShape *bt_convex_shape = dynamic_cast<btConvexShape *>(shape->create_bt_shape()); + if (!bt_convex_shape) { + bulletdelete(bt_convex_shape); + ERR_PRINTS("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type())); + return 0; + } + + btVector3 bt_motion; + G_TO_B(p_motion, bt_motion); + + btVector3 scale_with_margin; + G_TO_B(p_xform.basis.get_scale() + Vector3(p_margin, p_margin, p_margin), scale_with_margin); + bt_convex_shape->setLocalScaling(scale_with_margin); + + btTransform bt_xform_from; + G_TO_B(p_xform, bt_xform_from); + + btTransform bt_xform_to(bt_xform_from); + bt_xform_to.getOrigin() += bt_motion; + + GodotClosestConvexResultCallback btResult(bt_xform_from.getOrigin(), bt_xform_to.getOrigin(), &p_exclude); + btResult.m_collisionFilterGroup = p_collision_layer; + btResult.m_collisionFilterMask = p_object_type_mask; + + space->dynamicsWorld->convexSweepTest(bt_convex_shape, bt_xform_from, bt_xform_to, btResult); + + if (btResult.hasHit()) { + if (btCollisionObject::CO_RIGID_BODY == btResult.m_hitCollisionObject->getInternalType()) { + B_TO_G(static_cast<const btRigidBody *>(btResult.m_hitCollisionObject)->getVelocityInLocalPoint(btResult.m_hitPointWorld), r_info->linear_velocity); + } + CollisionObjectBullet *collision_object = static_cast<CollisionObjectBullet *>(btResult.m_hitCollisionObject->getUserPointer()); + p_closest_safe = p_closest_unsafe = btResult.m_closestHitFraction; + B_TO_G(btResult.m_hitPointWorld, r_info->point); + B_TO_G(btResult.m_hitNormalWorld, r_info->normal); + r_info->rid = collision_object->get_self(); + r_info->collider_id = collision_object->get_instance_id(); + r_info->shape = btResult.m_shapePart; + } + + bulletdelete(bt_convex_shape); + return btResult.hasHit(); +} + +/// Returns the list of contacts pairs in this order: Local contact, other body contact +bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform &p_shape_xform, float p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_collision_layer, uint32_t p_object_type_mask) { + if (p_result_max <= 0) + return 0; + + ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->get(p_shape); + + btConvexShape *btConvex = dynamic_cast<btConvexShape *>(shape->create_bt_shape()); + if (!btConvex) { + bulletdelete(btConvex); + ERR_PRINTS("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type())); + return 0; + } + + btVector3 scale_with_margin; + G_TO_B(p_shape_xform.basis.get_scale(), scale_with_margin); + btConvex->setLocalScaling(scale_with_margin); + + btTransform bt_xform; + G_TO_B(p_shape_xform, bt_xform); + + btCollisionObject collision_object; + collision_object.setCollisionShape(btConvex); + collision_object.setWorldTransform(bt_xform); + + GodotContactPairContactResultCallback btQuery(&collision_object, r_results, p_result_max, &p_exclude); + btQuery.m_collisionFilterGroup = p_collision_layer; + btQuery.m_collisionFilterMask = p_object_type_mask; + btQuery.m_closestDistanceThreshold = p_margin; + space->dynamicsWorld->contactTest(&collision_object, btQuery); + + r_result_count = btQuery.m_count; + bulletdelete(btConvex); + + return btQuery.m_count; +} + +bool BulletPhysicsDirectSpaceState::rest_info(RID p_shape, const Transform &p_shape_xform, float p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_layer, uint32_t p_object_type_mask) { + + ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->get(p_shape); + + btConvexShape *btConvex = dynamic_cast<btConvexShape *>(shape->create_bt_shape()); + if (!btConvex) { + bulletdelete(btConvex); + ERR_PRINTS("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type())); + return 0; + } + + btVector3 scale_with_margin; + G_TO_B(p_shape_xform.basis.get_scale() + Vector3(p_margin, p_margin, p_margin), scale_with_margin); + btConvex->setLocalScaling(scale_with_margin); + + btTransform bt_xform; + G_TO_B(p_shape_xform, bt_xform); + + btCollisionObject collision_object; + collision_object.setCollisionShape(btConvex); + collision_object.setWorldTransform(bt_xform); + + GodotRestInfoContactResultCallback btQuery(&collision_object, r_info, &p_exclude); + btQuery.m_collisionFilterGroup = p_collision_layer; + btQuery.m_collisionFilterMask = p_object_type_mask; + btQuery.m_closestDistanceThreshold = p_margin; + space->dynamicsWorld->contactTest(&collision_object, btQuery); + + bulletdelete(btConvex); + + if (btQuery.m_collided) { + if (btCollisionObject::CO_RIGID_BODY == btQuery.m_rest_info_collision_object->getInternalType()) { + B_TO_G(static_cast<const btRigidBody *>(btQuery.m_rest_info_collision_object)->getVelocityInLocalPoint(btQuery.m_rest_info_bt_point), r_info->linear_velocity); + } + B_TO_G(btQuery.m_rest_info_bt_point, r_info->point); + } + + return btQuery.m_collided; +} + +Vector3 BulletPhysicsDirectSpaceState::get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const { + + RigidCollisionObjectBullet *rigid_object = space->get_physics_server()->get_rigid_collisin_object(p_object); + ERR_FAIL_COND_V(!rigid_object, Vector3()); + + btVector3 out_closest_point(0, 0, 0); + btScalar out_distance = 1e20; + + btVector3 bt_point; + G_TO_B(p_point, bt_point); + + btGjkEpaPenetrationDepthSolver gjk_epa_pen_solver; + btVoronoiSimplexSolver gjk_simplex_solver; + gjk_simplex_solver.setEqualVertexThreshold(0.); + + btSphereShape point_shape(0.); + + btCollisionShape *shape; + btConvexShape *convex_shape; + btTransform child_transform; + btTransform body_transform(rigid_object->get_bt_collision_object()->getWorldTransform()); + + btGjkPairDetector::ClosestPointInput input; + input.m_transformA.getBasis().setIdentity(); + input.m_transformA.setOrigin(bt_point); + + bool shapes_found = false; + + btCompoundShape *compound = rigid_object->get_compound_shape(); + for (int i = compound->getNumChildShapes() - 1; 0 <= i; --i) { + shape = compound->getChildShape(i); + if (shape->isConvex()) { + child_transform = compound->getChildTransform(i); + convex_shape = static_cast<btConvexShape *>(shape); + + input.m_transformB = body_transform * child_transform; + + btPointCollector result; + btGjkPairDetector gjk_pair_detector(&point_shape, convex_shape, &gjk_simplex_solver, &gjk_epa_pen_solver); + gjk_pair_detector.getClosestPoints(input, result, 0); + + if (out_distance > result.m_distance) { + out_distance = result.m_distance; + out_closest_point = result.m_pointInWorld; + } + } + shapes_found = true; + } + + if (shapes_found) { + + Vector3 out; + B_TO_G(out_closest_point, out); + return out; + } else { + + // no shapes found, use distance to origin. + return rigid_object->get_transform().get_origin(); + } +} + +SpaceBullet::SpaceBullet(bool p_create_soft_world) + : broadphase(NULL), + dispatcher(NULL), + solver(NULL), + collisionConfiguration(NULL), + dynamicsWorld(NULL), + soft_body_world_info(NULL), + ghostPairCallback(NULL), + godotFilterCallback(NULL), + gravityDirection(0, -1, 0), + gravityMagnitude(10), + contactDebugCount(0) { + + create_empty_world(p_create_soft_world); + direct_access = memnew(BulletPhysicsDirectSpaceState(this)); +} + +SpaceBullet::~SpaceBullet() { + memdelete(direct_access); + destroy_world(); +} + +void SpaceBullet::flush_queries() { + const btCollisionObjectArray &colObjArray = dynamicsWorld->getCollisionObjectArray(); + for (int i = colObjArray.size() - 1; 0 <= i; --i) { + static_cast<CollisionObjectBullet *>(colObjArray[i]->getUserPointer())->dispatch_callbacks(); + } +} + +void SpaceBullet::step(real_t p_delta_time) { + dynamicsWorld->stepSimulation(p_delta_time, 0, 0); +} + +void SpaceBullet::set_param(PhysicsServer::AreaParameter p_param, const Variant &p_value) { + assert(dynamicsWorld); + + switch (p_param) { + case PhysicsServer::AREA_PARAM_GRAVITY: + gravityMagnitude = p_value; + update_gravity(); + break; + case PhysicsServer::AREA_PARAM_GRAVITY_VECTOR: + gravityDirection = p_value; + update_gravity(); + break; + case PhysicsServer::AREA_PARAM_LINEAR_DAMP: + case PhysicsServer::AREA_PARAM_ANGULAR_DAMP: + break; // No damp + case PhysicsServer::AREA_PARAM_PRIORITY: + // Priority is always 0, the lower + break; + case PhysicsServer::AREA_PARAM_GRAVITY_IS_POINT: + case PhysicsServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE: + case PhysicsServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION: + break; + default: + WARN_PRINTS("This set parameter (" + itos(p_param) + ") is ignored, the SpaceBullet doesn't support it."); + break; + } +} + +Variant SpaceBullet::get_param(PhysicsServer::AreaParameter p_param) { + switch (p_param) { + case PhysicsServer::AREA_PARAM_GRAVITY: + return gravityMagnitude; + case PhysicsServer::AREA_PARAM_GRAVITY_VECTOR: + return gravityDirection; + case PhysicsServer::AREA_PARAM_LINEAR_DAMP: + case PhysicsServer::AREA_PARAM_ANGULAR_DAMP: + return 0; // No damp + case PhysicsServer::AREA_PARAM_PRIORITY: + return 0; // Priority is always 0, the lower + case PhysicsServer::AREA_PARAM_GRAVITY_IS_POINT: + return false; + case PhysicsServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE: + return 0; + case PhysicsServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION: + return 0; + default: + WARN_PRINTS("This get parameter (" + itos(p_param) + ") is ignored, the SpaceBullet doesn't support it."); + return Variant(); + } +} + +void SpaceBullet::set_param(PhysicsServer::SpaceParameter p_param, real_t p_value) { + switch (p_param) { + case PhysicsServer::SPACE_PARAM_CONTACT_RECYCLE_RADIUS: + case PhysicsServer::SPACE_PARAM_CONTACT_MAX_SEPARATION: + case PhysicsServer::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION: + case PhysicsServer::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD: + case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD: + case PhysicsServer::SPACE_PARAM_BODY_TIME_TO_SLEEP: + case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO: + case PhysicsServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: + default: + WARN_PRINTS("This set parameter (" + itos(p_param) + ") is ignored, the SpaceBullet doesn't support it."); + break; + } +} + +real_t SpaceBullet::get_param(PhysicsServer::SpaceParameter p_param) { + switch (p_param) { + case PhysicsServer::SPACE_PARAM_CONTACT_RECYCLE_RADIUS: + case PhysicsServer::SPACE_PARAM_CONTACT_MAX_SEPARATION: + case PhysicsServer::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION: + case PhysicsServer::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD: + case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD: + case PhysicsServer::SPACE_PARAM_BODY_TIME_TO_SLEEP: + case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO: + case PhysicsServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: + default: + WARN_PRINTS("The SpaceBullet doesn't support this get parameter (" + itos(p_param) + "), 0 is returned."); + return 0.f; + } +} + +void SpaceBullet::add_area(AreaBullet *p_area) { + areas.push_back(p_area); + dynamicsWorld->addCollisionObject(p_area->get_bt_ghost(), p_area->get_collision_layer(), p_area->get_collision_mask()); +} + +void SpaceBullet::remove_area(AreaBullet *p_area) { + areas.erase(p_area); + dynamicsWorld->removeCollisionObject(p_area->get_bt_ghost()); +} + +void SpaceBullet::reload_collision_filters(AreaBullet *p_area) { + // This is necessary to change collision filter + dynamicsWorld->removeCollisionObject(p_area->get_bt_ghost()); + dynamicsWorld->addCollisionObject(p_area->get_bt_ghost(), p_area->get_collision_layer(), p_area->get_collision_mask()); +} + +void SpaceBullet::add_rigid_body(RigidBodyBullet *p_body) { + if (p_body->is_static()) { + dynamicsWorld->addCollisionObject(p_body->get_bt_rigid_body(), p_body->get_collision_layer(), p_body->get_collision_mask()); + } else { + dynamicsWorld->addRigidBody(p_body->get_bt_rigid_body(), p_body->get_collision_layer(), p_body->get_collision_mask()); + } +} + +void SpaceBullet::remove_rigid_body(RigidBodyBullet *p_body) { + if (p_body->is_static()) { + dynamicsWorld->removeCollisionObject(p_body->get_bt_rigid_body()); + } else { + dynamicsWorld->removeRigidBody(p_body->get_bt_rigid_body()); + } +} + +void SpaceBullet::reload_collision_filters(RigidBodyBullet *p_body) { + // This is necessary to change collision filter + remove_rigid_body(p_body); + add_rigid_body(p_body); +} + +void SpaceBullet::add_soft_body(SoftBodyBullet *p_body) { + if (is_using_soft_world()) { + if (p_body->get_bt_soft_body()) { + static_cast<btSoftRigidDynamicsWorld *>(dynamicsWorld)->addSoftBody(p_body->get_bt_soft_body(), p_body->get_collision_layer(), p_body->get_collision_mask()); + } + } else { + ERR_PRINT("This soft body can't be added to non soft world"); + } +} + +void SpaceBullet::remove_soft_body(SoftBodyBullet *p_body) { + if (is_using_soft_world()) { + if (p_body->get_bt_soft_body()) { + static_cast<btSoftRigidDynamicsWorld *>(dynamicsWorld)->removeSoftBody(p_body->get_bt_soft_body()); + } + } +} + +void SpaceBullet::reload_collision_filters(SoftBodyBullet *p_body) { + // This is necessary to change collision filter + remove_soft_body(p_body); + add_soft_body(p_body); +} + +void SpaceBullet::add_constraint(ConstraintBullet *p_constraint, bool disableCollisionsBetweenLinkedBodies) { + p_constraint->set_space(this); + dynamicsWorld->addConstraint(p_constraint->get_bt_constraint(), disableCollisionsBetweenLinkedBodies); +} + +void SpaceBullet::remove_constraint(ConstraintBullet *p_constraint) { + dynamicsWorld->removeConstraint(p_constraint->get_bt_constraint()); +} + +int SpaceBullet::get_num_collision_objects() const { + return dynamicsWorld->getNumCollisionObjects(); +} + +void SpaceBullet::remove_all_collision_objects() { + for (int i = dynamicsWorld->getNumCollisionObjects() - 1; 0 <= i; --i) { + btCollisionObject *btObj = dynamicsWorld->getCollisionObjectArray()[i]; + CollisionObjectBullet *colObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); + colObj->set_space(NULL); + } +} + +void onBulletPreTickCallback(btDynamicsWorld *p_dynamicsWorld, btScalar timeStep) { + static_cast<SpaceBullet *>(p_dynamicsWorld->getWorldUserInfo())->flush_queries(); +} + +void onBulletTickCallback(btDynamicsWorld *p_dynamicsWorld, btScalar timeStep) { + + // Notify all Collision objects the collision checker is started + const btCollisionObjectArray &colObjArray = p_dynamicsWorld->getCollisionObjectArray(); + for (int i = colObjArray.size() - 1; 0 <= i; --i) { + CollisionObjectBullet *colObj = static_cast<CollisionObjectBullet *>(colObjArray[i]->getUserPointer()); + assert(NULL != colObj); + colObj->on_collision_checker_start(); + } + + SpaceBullet *sb = static_cast<SpaceBullet *>(p_dynamicsWorld->getWorldUserInfo()); + sb->check_ghost_overlaps(); + sb->check_body_collision(); +} + +BulletPhysicsDirectSpaceState *SpaceBullet::get_direct_state() { + return direct_access; +} + +btScalar calculateGodotCombinedRestitution(const btCollisionObject *body0, const btCollisionObject *body1) { + return MAX(body0->getRestitution(), body1->getRestitution()); +} + +void SpaceBullet::create_empty_world(bool p_create_soft_world) { + assert(NULL == broadphase); + assert(NULL == dispatcher); + assert(NULL == solver); + assert(NULL == collisionConfiguration); + assert(NULL == dynamicsWorld); + assert(NULL == ghostPairCallback); + assert(NULL == godotFilterCallback); + + void *world_mem; + if (p_create_soft_world) { + world_mem = malloc(sizeof(btSoftRigidDynamicsWorld)); + } else { + world_mem = malloc(sizeof(btDiscreteDynamicsWorld)); + } + + if (p_create_soft_world) { + collisionConfiguration = bulletnew(btSoftBodyRigidBodyCollisionConfiguration); + } else { + collisionConfiguration = bulletnew(GodotCollisionConfiguration(static_cast<btDiscreteDynamicsWorld *>(world_mem))); + } + + dispatcher = bulletnew(GodotCollisionDispatcher(collisionConfiguration)); + broadphase = bulletnew(btDbvtBroadphase); + solver = bulletnew(btSequentialImpulseConstraintSolver); + + if (p_create_soft_world) { + dynamicsWorld = new (world_mem) btSoftRigidDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration); + soft_body_world_info = bulletnew(btSoftBodyWorldInfo); + } else { + dynamicsWorld = new (world_mem) btDiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration); + } + + ghostPairCallback = bulletnew(btGhostPairCallback); + godotFilterCallback = bulletnew(GodotFilterCallback); + gCalculateCombinedRestitutionCallback = &calculateGodotCombinedRestitution; + + dynamicsWorld->setWorldUserInfo(this); + + dynamicsWorld->setInternalTickCallback(onBulletPreTickCallback, this, true); + dynamicsWorld->setInternalTickCallback(onBulletTickCallback, this, false); + dynamicsWorld->getBroadphase()->getOverlappingPairCache()->setInternalGhostPairCallback(ghostPairCallback); // Setup ghost check + dynamicsWorld->getPairCache()->setOverlapFilterCallback(godotFilterCallback); + + if (soft_body_world_info) { + soft_body_world_info->m_broadphase = broadphase; + soft_body_world_info->m_dispatcher = dispatcher; + soft_body_world_info->m_sparsesdf.Initialize(); + } + + update_gravity(); +} + +void SpaceBullet::destroy_world() { + assert(NULL != broadphase); + assert(NULL != dispatcher); + assert(NULL != solver); + assert(NULL != collisionConfiguration); + assert(NULL != dynamicsWorld); + assert(NULL != ghostPairCallback); + assert(NULL != godotFilterCallback); + + /// The world elements (like: Collision Objects, Constraints, Shapes) are managed by godot + + dynamicsWorld->getBroadphase()->getOverlappingPairCache()->setInternalGhostPairCallback(NULL); + dynamicsWorld->getPairCache()->setOverlapFilterCallback(NULL); + + bulletdelete(ghostPairCallback); + bulletdelete(godotFilterCallback); + + // Deallocate world + dynamicsWorld->~btDiscreteDynamicsWorld(); + free(dynamicsWorld); + dynamicsWorld = NULL; + + bulletdelete(solver); + bulletdelete(broadphase); + bulletdelete(dispatcher); + bulletdelete(collisionConfiguration); + bulletdelete(soft_body_world_info); +} + +void SpaceBullet::check_ghost_overlaps() { + + /// Algorith support variables + btGjkEpaPenetrationDepthSolver gjk_epa_pen_solver; + btVoronoiSimplexSolver gjk_simplex_solver; + gjk_simplex_solver.setEqualVertexThreshold(0.f); + btConvexShape *other_body_shape; + btConvexShape *area_shape; + btGjkPairDetector::ClosestPointInput gjk_input; + AreaBullet *area; + RigidCollisionObjectBullet *otherObject; + int x(-1), i(-1), y(-1), z(-1), indexOverlap(-1); + + /// For each areas + for (x = areas.size() - 1; 0 <= x; --x) { + area = areas[x]; + + if (!area->is_monitoring()) + continue; + + /// 1. Reset all states + for (i = area->overlappingObjects.size() - 1; 0 <= i; --i) { + AreaBullet::OverlappingObjectData &otherObj = area->overlappingObjects[i]; + // This check prevent the overwrite of ENTER state + // if this function is called more times before dispatchCallbacks + if (otherObj.state != AreaBullet::OVERLAP_STATE_ENTER) { + otherObj.state = AreaBullet::OVERLAP_STATE_DIRTY; + } + } + + /// 2. Check all overlapping objects using GJK + + const btAlignedObjectArray<btCollisionObject *> ghostOverlaps = area->get_bt_ghost()->getOverlappingPairs(); + + // For each overlapping + for (i = ghostOverlaps.size() - 1; 0 <= i; --i) { + + if (!(ghostOverlaps[i]->getUserIndex() == CollisionObjectBullet::TYPE_RIGID_BODY || ghostOverlaps[i]->getUserIndex() == CollisionObjectBullet::TYPE_AREA)) + continue; + + otherObject = static_cast<RigidCollisionObjectBullet *>(ghostOverlaps[i]->getUserPointer()); + + bool hasOverlap = false; + + // For each area shape + for (y = area->get_compound_shape()->getNumChildShapes() - 1; 0 <= y; --y) { + if (!area->get_compound_shape()->getChildShape(y)->isConvex()) + continue; + + gjk_input.m_transformA = area->get_transform__bullet() * area->get_compound_shape()->getChildTransform(y); + area_shape = static_cast<btConvexShape *>(area->get_compound_shape()->getChildShape(y)); + + // For each other object shape + for (z = otherObject->get_compound_shape()->getNumChildShapes() - 1; 0 <= z; --z) { + + if (!otherObject->get_compound_shape()->getChildShape(z)->isConvex()) + continue; + + other_body_shape = static_cast<btConvexShape *>(otherObject->get_compound_shape()->getChildShape(z)); + gjk_input.m_transformB = otherObject->get_transform__bullet() * otherObject->get_compound_shape()->getChildTransform(z); + + btPointCollector result; + btGjkPairDetector gjk_pair_detector(area_shape, other_body_shape, &gjk_simplex_solver, &gjk_epa_pen_solver); + gjk_pair_detector.getClosestPoints(gjk_input, result, 0); + + if (0 >= result.m_distance) { + hasOverlap = true; + goto collision_found; + } + } // ~For each other object shape + } // ~For each area shape + + collision_found: + if (!hasOverlap) + continue; + + indexOverlap = area->find_overlapping_object(otherObject); + if (-1 == indexOverlap) { + // Not found + area->add_overlap(otherObject); + } else { + // Found + area->put_overlap_as_inside(indexOverlap); + } + } + + /// 3. Remove not overlapping + for (i = area->overlappingObjects.size() - 1; 0 <= i; --i) { + // If the overlap has DIRTY state it means that it's no more overlapping + if (area->overlappingObjects[i].state == AreaBullet::OVERLAP_STATE_DIRTY) { + area->put_overlap_as_exit(i); + } + } + } +} + +void SpaceBullet::check_body_collision() { +#ifdef DEBUG_ENABLED + reset_debug_contact_count(); +#endif + + const int numManifolds = dynamicsWorld->getDispatcher()->getNumManifolds(); + for (int i = 0; i < numManifolds; ++i) { + btPersistentManifold *contactManifold = dynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i); + const btCollisionObject *obA = contactManifold->getBody0(); + const btCollisionObject *obB = contactManifold->getBody1(); + + if (btCollisionObject::CO_RIGID_BODY != obA->getInternalType() || btCollisionObject::CO_RIGID_BODY != obB->getInternalType()) { + // This checks is required to be sure the ghost object is skipped + // The ghost object "getUserPointer" return the BodyBullet owner so this check is required + continue; + } + + // Asserts all Godot objects are assigned + assert(NULL != obA->getUserPointer()); + assert(NULL != obB->getUserPointer()); + + // I know this static cast is a bit risky. But I'm checking its type just after it. + // This allow me to avoid a lot of other cast and checks + RigidBodyBullet *bodyA = static_cast<RigidBodyBullet *>(obA->getUserPointer()); + RigidBodyBullet *bodyB = static_cast<RigidBodyBullet *>(obB->getUserPointer()); + + if (CollisionObjectBullet::TYPE_RIGID_BODY == bodyA->getType() && CollisionObjectBullet::TYPE_RIGID_BODY == bodyB->getType()) { + if (!bodyA->can_add_collision() && !bodyB->can_add_collision()) { + continue; + } + + const int numContacts = contactManifold->getNumContacts(); +#define REPORT_ALL_CONTACTS 0 +#if REPORT_ALL_CONTACTS + for (int j = 0; j < numContacts; j++) { + btManifoldPoint &pt = contactManifold->getContactPoint(j); +#else + // Since I don't need report all contacts for these objects, I'll report only the first + if (numContacts) { + btManifoldPoint &pt = contactManifold->getContactPoint(0); +#endif + Vector3 collisionWorldPosition; + Vector3 collisionLocalPosition; + Vector3 normalOnB; + B_TO_G(pt.m_normalWorldOnB, normalOnB); + + if (bodyA->can_add_collision()) { + B_TO_G(pt.getPositionWorldOnB(), collisionWorldPosition); + /// pt.m_localPointB Doesn't report the exact point in local space + B_TO_G(pt.getPositionWorldOnB() - obB->getWorldTransform().getOrigin(), collisionLocalPosition); + bodyA->add_collision_object(bodyB, collisionWorldPosition, collisionLocalPosition, normalOnB, pt.m_index1, pt.m_index0); + } + if (bodyB->can_add_collision()) { + B_TO_G(pt.getPositionWorldOnA(), collisionWorldPosition); + /// pt.m_localPointA Doesn't report the exact point in local space + B_TO_G(pt.getPositionWorldOnA() - obA->getWorldTransform().getOrigin(), collisionLocalPosition); + bodyB->add_collision_object(bodyA, collisionWorldPosition, collisionLocalPosition, normalOnB * -1, pt.m_index0, pt.m_index1); + } + +#ifdef DEBUG_ENABLED + if (is_debugging_contacts()) { + add_debug_contact(collisionWorldPosition); + } +#endif + } + } + } +} + +void SpaceBullet::update_gravity() { + btVector3 btGravity; + G_TO_B(gravityDirection * gravityMagnitude, btGravity); + dynamicsWorld->setGravity(btGravity); + if (soft_body_world_info) { + soft_body_world_info->m_gravity = btGravity; + } +} + +/// IMPORTANT: Please don't turn it ON this is not managed correctly!! +/// I'm leaving this here just for future tests. +/// Debug motion and normal vector drawing +#define debug_test_motion 0 +#if debug_test_motion +static ImmediateGeometry *motionVec(NULL); +static ImmediateGeometry *normalLine(NULL); +static Ref<SpatialMaterial> red_mat; +static Ref<SpatialMaterial> blue_mat; +#endif + +#define IGNORE_AREAS_TRUE true +bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, real_t p_margin, PhysicsServer::MotionResult *r_result) { + +#if debug_test_motion + /// Yes I know this is not good, but I've used it as fast debugging. + /// I'm leaving it here just for speedup the other eventual debugs + if (!normalLine) { + motionVec = memnew(ImmediateGeometry); + normalLine = memnew(ImmediateGeometry); + SceneTree::get_singleton()->get_current_scene()->add_child(motionVec); + SceneTree::get_singleton()->get_current_scene()->add_child(normalLine); + + red_mat = Ref<SpatialMaterial>(memnew(SpatialMaterial)); + red_mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + red_mat->set_line_width(20.0); + red_mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); + red_mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + red_mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); + red_mat->set_albedo(Color(1, 0, 0, 1)); + motionVec->set_material_override(red_mat); + + blue_mat = Ref<SpatialMaterial>(memnew(SpatialMaterial)); + blue_mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + blue_mat->set_line_width(20.0); + blue_mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); + blue_mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + blue_mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); + blue_mat->set_albedo(Color(0, 0, 1, 1)); + normalLine->set_material_override(blue_mat); + } +#endif + + ///// Release all generated manifolds + //{ + // if(p_body->get_kinematic_utilities()){ + // for(int i= p_body->get_kinematic_utilities()->m_generatedManifold.size()-1; 0<=i; --i){ + // dispatcher->releaseManifold( p_body->get_kinematic_utilities()->m_generatedManifold[i] ); + // } + // p_body->get_kinematic_utilities()->m_generatedManifold.clear(); + // } + //} + + btVector3 recover_initial_position; + recover_initial_position.setZero(); + +/// I'm performing the unstack at the end of movement so I'm sure the player is unstacked even after the movement. +/// I've removed the initial unstack because this is useful just for the first tick since after the first +/// the real unstack is performed at the end of process. +/// However I'm leaving here the old code. +/// Note: It has a bug when two shapes touches something simultaneously the body is moved too much away (I'm not fixing it for the reason written above). +#define INITIAL_UNSTACK 0 +#if !INITIAL_UNSTACK + btTransform body_safe_position; + G_TO_B(p_from, body_safe_position); +//btTransform body_unsafe_positino; +//G_TO_B(p_from, body_unsafe_positino); +#else + btTransform body_safe_position; + btTransform body_unsafe_positino; + { /// Phase one - multi shapes depenetration using margin + G_TO_B(p_from, body_safe_position); + G_TO_B(p_from, body_unsafe_positino); + + // MAX_PENETRATION_DEPTH Is useful have the ghost a bit penetrated so I can detect the floor easily + recover_from_penetration(p_body, body_safe_position, MAX_PENETRATION_DEPTH, /* p_depenetration_speed */ 1, recover_initial_position); + + /// Not required if I put p_depenetration_speed = 1 + //for(int t = 0; t<4; ++t){ + // if(!recover_from_penetration(p_body, body_safe_position, MAX_PENETRATION_DEPTH, /* p_depenetration_speed */0.2, recover_initial_position)){ + // break; + // } + //} + + // Add recover position to "From" and "To" transforms + body_safe_position.getOrigin() += recover_initial_position; + } +#endif + + int shape_most_recovered(-1); + btVector3 recovered_motion; + G_TO_B(p_motion, recovered_motion); + const int shape_count(p_body->get_shape_count()); + + { /// phase two - sweep test, from a secure position without margin + +#if debug_test_motion + Vector3 sup_line; + B_TO_G(body_safe_position.getOrigin(), sup_line); + motionVec->clear(); + motionVec->begin(Mesh::PRIMITIVE_LINES, NULL); + motionVec->add_vertex(sup_line); + motionVec->add_vertex(sup_line + p_motion * 10); + motionVec->end(); +#endif + + for (int shIndex = 0; shIndex < shape_count; ++shIndex) { + if (p_body->is_shape_disabled(shIndex)) { + continue; + } + + btConvexShape *convex_shape_test(dynamic_cast<btConvexShape *>(p_body->get_bt_shape(shIndex))); + if (!convex_shape_test) { + // Skip no convex shape + continue; + } + + btTransform shape_xform_from; + G_TO_B(p_body->get_shape_transform(shIndex), shape_xform_from); + //btTransform shape_xform_to(shape_xform_from); + + // Add local shape transform + shape_xform_from.getOrigin() += body_safe_position.getOrigin(); + shape_xform_from.getBasis() *= body_safe_position.getBasis(); + + btTransform shape_xform_to(shape_xform_from); + //shape_xform_to.getOrigin() += body_unsafe_positino.getOrigin(); + //shape_xform_to.getBasis() *= body_unsafe_positino.getBasis(); + shape_xform_to.getOrigin() += recovered_motion; + + GodotKinClosestConvexResultCallback btResult(shape_xform_from.getOrigin(), shape_xform_to.getOrigin(), p_body, IGNORE_AREAS_TRUE); + btResult.m_collisionFilterGroup = p_body->get_collision_layer(); + btResult.m_collisionFilterMask = p_body->get_collision_mask(); + + dynamicsWorld->convexSweepTest(convex_shape_test, shape_xform_from, shape_xform_to, btResult); + + if (btResult.hasHit()) { + //recovered_motion *= btResult.m_closestHitFraction; + /// Since for each sweep test I fix the motion of new shapes in base the recover result, + /// if another shape will hit something it means that has a deepest recovering respect the previous shape + shape_most_recovered = shIndex; + } + } + } + + bool hasHit = false; + + { /// Phase three - contact test with margin + + btGhostObject *ghost = p_body->get_kinematic_utilities()->m_ghostObject; + + GodotRecoverAndClosestContactResultCallback result_callabck; + + if (false && 0 <= shape_most_recovered) { + result_callabck.m_self_object = p_body; + result_callabck.m_ignore_areas = IGNORE_AREAS_TRUE; + result_callabck.m_collisionFilterGroup = p_body->get_collision_layer(); + result_callabck.m_collisionFilterMask = p_body->get_collision_mask(); + + const RigidBodyBullet::KinematicShape &kin(p_body->get_kinematic_utilities()->m_shapes[shape_most_recovered]); + ghost->setCollisionShape(kin.shape); + ghost->setWorldTransform(body_safe_position); + + ghost->getWorldTransform().getOrigin() += recovered_motion; + ghost->getWorldTransform().getOrigin() += kin.transform.getOrigin(); + ghost->getWorldTransform().getBasis() *= kin.transform.getBasis(); + + dynamicsWorld->contactTest(ghost, result_callabck); + + recovered_motion += result_callabck.m_recover_penetration; // Required to avoid all kind of penetration + + } else { + // The sweep result does not return a penetrated shape, so I've to check all shapes + // Then return the most penetrated shape + + GodotRecoverAndClosestContactResultCallback iter_result_callabck(p_body, IGNORE_AREAS_TRUE); + iter_result_callabck.m_collisionFilterGroup = p_body->get_collision_layer(); + iter_result_callabck.m_collisionFilterMask = p_body->get_collision_mask(); + + btScalar max_penetration(99999999999); + for (int i = 0; i < shape_count; ++i) { + + const RigidBodyBullet::KinematicShape &kin(p_body->get_kinematic_utilities()->m_shapes[i]); + if (!kin.is_active()) { + continue; + } + + // reset callback each function + iter_result_callabck.reset(); + + ghost->setCollisionShape(kin.shape); + ghost->setWorldTransform(body_safe_position); + ghost->getWorldTransform().getOrigin() += recovered_motion; + ghost->getWorldTransform().getOrigin() += kin.transform.getOrigin(); + ghost->getWorldTransform().getBasis() *= kin.transform.getBasis(); + + dynamicsWorld->contactTest(ghost, iter_result_callabck); + + if (iter_result_callabck.hasHit()) { + if (max_penetration > iter_result_callabck.m_penetration_distance) { + max_penetration = iter_result_callabck.m_penetration_distance; + shape_most_recovered = i; + // This is more penetrated + result_callabck.m_pointCollisionObject = iter_result_callabck.m_pointCollisionObject; + result_callabck.m_pointNormalWorld = iter_result_callabck.m_pointNormalWorld; + result_callabck.m_pointWorld = iter_result_callabck.m_pointWorld; + result_callabck.m_penetration_distance = iter_result_callabck.m_penetration_distance; + result_callabck.m_other_compound_shape_index = iter_result_callabck.m_other_compound_shape_index; + + recovered_motion += iter_result_callabck.m_recover_penetration; // Required to avoid all kind of penetration + } + } + } + } + + hasHit = result_callabck.hasHit(); + + if (r_result) { + + B_TO_G(recovered_motion + recover_initial_position, r_result->motion); + + if (hasHit) { + + if (btCollisionObject::CO_RIGID_BODY != result_callabck.m_pointCollisionObject->getInternalType()) { + ERR_PRINT("The collision is not against a rigid body. Please check what's going on."); + goto EndExecution; + } + const btRigidBody *btRigid = static_cast<const btRigidBody *>(result_callabck.m_pointCollisionObject); + CollisionObjectBullet *collisionObject = static_cast<CollisionObjectBullet *>(btRigid->getUserPointer()); + + r_result->remainder = p_motion - r_result->motion; // is the remaining movements + B_TO_G(result_callabck.m_pointWorld, r_result->collision_point); + B_TO_G(result_callabck.m_pointNormalWorld, r_result->collision_normal); + B_TO_G(btRigid->getVelocityInLocalPoint(result_callabck.m_pointWorld - btRigid->getWorldTransform().getOrigin()), r_result->collider_velocity); // It calculates velocity at point and assign it using special function Bullet_to_Godot + r_result->collider = collisionObject->get_self(); + r_result->collider_id = collisionObject->get_instance_id(); + r_result->collider_shape = result_callabck.m_other_compound_shape_index; + r_result->collision_local_shape = shape_most_recovered; + +//{ /// Add manifold point to manage collisions +// btPersistentManifold* manifold = dynamicsWorld->getDispatcher()->getNewManifold(p_body->getBtBody(), btRigid); +// btManifoldPoint manifoldPoint(result_callabck.m_pointWorld, result_callabck.m_pointWorld, result_callabck.m_pointNormalWorld, result_callabck.m_penetration_distance); +// manifoldPoint.m_index0 = r_result->collision_local_shape; +// manifoldPoint.m_index1 = r_result->collider_shape; +// manifold->addManifoldPoint(manifoldPoint); +// p_body->get_kinematic_utilities()->m_generatedManifold.push_back(manifold); +//} + +#if debug_test_motion + Vector3 sup_line2; + B_TO_G(recovered_motion, sup_line2); + //Vector3 sup_pos; + //B_TO_G( pt.getPositionWorldOnB(), sup_pos); + normalLine->clear(); + normalLine->begin(Mesh::PRIMITIVE_LINES, NULL); + normalLine->add_vertex(r_result->collision_point); + normalLine->add_vertex(r_result->collision_point + r_result->collision_normal * 10); + normalLine->end(); +#endif + + } else { + r_result->remainder = Vector3(); + } + } + } + +EndExecution: + p_body->get_kinematic_utilities()->resetDefShape(); + return hasHit; +} + +/// Note: It has a bug when two shapes touches something simultaneously the body is moved too much away +/// (I'm not fixing it because I don't use it). +bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_from, btScalar p_maxPenetrationDepth, btScalar p_depenetration_speed, btVector3 &out_recover_position) { + + bool penetration = false; + btPairCachingGhostObject *ghost = p_body->get_kinematic_utilities()->m_ghostObject; + + for (int kinIndex = p_body->get_kinematic_utilities()->m_shapes.size() - 1; 0 <= kinIndex; --kinIndex) { + const RigidBodyBullet::KinematicShape &kin_shape(p_body->get_kinematic_utilities()->m_shapes[kinIndex]); + if (!kin_shape.is_active()) { + continue; + } + + btConvexShape *convexShape = kin_shape.shape; + btTransform shape_xform(kin_shape.transform); + + // from local to world + shape_xform.getOrigin() += p_from.getOrigin(); + shape_xform.getBasis() *= p_from.getBasis(); + + // Apply last recovery to avoid doubling the recovering + shape_xform.getOrigin() += out_recover_position; + + ghost->setCollisionShape(convexShape); + ghost->setWorldTransform(shape_xform); + + btVector3 minAabb, maxAabb; + convexShape->getAabb(shape_xform, minAabb, maxAabb); + dynamicsWorld->getBroadphase()->setAabb(ghost->getBroadphaseHandle(), + minAabb, + maxAabb, + dynamicsWorld->getDispatcher()); + + dynamicsWorld->getDispatcher()->dispatchAllCollisionPairs(ghost->getOverlappingPairCache(), dynamicsWorld->getDispatchInfo(), dynamicsWorld->getDispatcher()); + + for (int i = 0; i < ghost->getOverlappingPairCache()->getNumOverlappingPairs(); ++i) { + p_body->get_kinematic_utilities()->m_manifoldArray.resize(0); + + btBroadphasePair *collisionPair = &ghost->getOverlappingPairCache()->getOverlappingPairArray()[i]; + + btCollisionObject *obj0 = static_cast<btCollisionObject *>(collisionPair->m_pProxy0->m_clientObject); + btCollisionObject *obj1 = static_cast<btCollisionObject *>(collisionPair->m_pProxy1->m_clientObject); + + if ((obj0 && !obj0->hasContactResponse()) || (obj1 && !obj1->hasContactResponse())) + continue; + + // This is not required since the dispatched does all the job + //if (!needsCollision(obj0, obj1)) + // continue; + + if (collisionPair->m_algorithm) + collisionPair->m_algorithm->getAllContactManifolds(p_body->get_kinematic_utilities()->m_manifoldArray); + + for (int j = 0; j < p_body->get_kinematic_utilities()->m_manifoldArray.size(); ++j) { + + btPersistentManifold *manifold = p_body->get_kinematic_utilities()->m_manifoldArray[j]; + btScalar directionSign = manifold->getBody0() == ghost ? btScalar(-1.0) : btScalar(1.0); + for (int p = 0; p < manifold->getNumContacts(); ++p) { + const btManifoldPoint &pt = manifold->getContactPoint(p); + + btScalar dist = pt.getDistance(); + if (dist < -p_maxPenetrationDepth) { + penetration = true; + out_recover_position += pt.m_normalWorldOnB * directionSign * (dist + p_maxPenetrationDepth) * p_depenetration_speed; + //print_line("penetrate distance: " + rtos(dist)); + } + //else { + // print_line("touching distance: " + rtos(dist)); + //} + } + } + } + } + + p_body->get_kinematic_utilities()->resetDefShape(); + return penetration; +} diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h new file mode 100644 index 0000000000..cbbfdac1d7 --- /dev/null +++ b/modules/bullet/space_bullet.h @@ -0,0 +1,176 @@ +/*************************************************************************/ +/* space_bullet.h */ +/* 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. */ +/*************************************************************************/ + +#ifndef SPACE_BULLET_H +#define SPACE_BULLET_H + +#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" +#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h" +#include "LinearMath/btScalar.h" +#include "LinearMath/btTransform.h" +#include "LinearMath/btVector3.h" +#include "core/variant.h" +#include "core/vector.h" +#include "godot_result_callbacks.h" +#include "rid_bullet.h" +#include "servers/physics_server.h" + +class AreaBullet; +class btBroadphaseInterface; +class btCollisionDispatcher; +class btConstraintSolver; +class btDefaultCollisionConfiguration; +class btDynamicsWorld; +class btDiscreteDynamicsWorld; +class btEmptyShape; +class btGhostPairCallback; +class btSoftRigidDynamicsWorld; +class btSoftBodyWorldInfo; +class ConstraintBullet; +class CollisionObjectBullet; +class RigidBodyBullet; +class SpaceBullet; +class SoftBodyBullet; + +class BulletPhysicsDirectSpaceState : public PhysicsDirectSpaceState { + GDCLASS(BulletPhysicsDirectSpaceState, PhysicsDirectSpaceState) +private: + SpaceBullet *space; + +public: + BulletPhysicsDirectSpaceState(SpaceBullet *p_space); + + virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION); + virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION, bool p_pick_ray = false); + virtual int intersect_shape(const RID &p_shape, const Transform &p_xform, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION); + virtual bool cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, float p_margin, float &p_closest_safe, float &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION, ShapeRestInfo *r_info = NULL); + /// Returns the list of contacts pairs in this order: Local contact, other body contact + virtual bool collide_shape(RID p_shape, const Transform &p_shape_xform, float p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION); + virtual bool rest_info(RID p_shape, const Transform &p_shape_xform, float p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION); + virtual Vector3 get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const; +}; + +class SpaceBullet : public RIDBullet { +private: + friend class AreaBullet; + friend void onBulletTickCallback(btDynamicsWorld *world, btScalar timeStep); + friend class BulletPhysicsDirectSpaceState; + + btBroadphaseInterface *broadphase; + btDefaultCollisionConfiguration *collisionConfiguration; + btCollisionDispatcher *dispatcher; + btConstraintSolver *solver; + btDiscreteDynamicsWorld *dynamicsWorld; + btGhostPairCallback *ghostPairCallback; + GodotFilterCallback *godotFilterCallback; + btSoftBodyWorldInfo *soft_body_world_info; + + BulletPhysicsDirectSpaceState *direct_access; + Vector3 gravityDirection; + real_t gravityMagnitude; + + Vector<AreaBullet *> areas; + + Vector<Vector3> contactDebug; + int contactDebugCount; + +public: + SpaceBullet(bool p_create_soft_world); + virtual ~SpaceBullet(); + + void flush_queries(); + void step(real_t p_delta_time); + + _FORCE_INLINE_ btCollisionDispatcher *get_dispatcher() { return dispatcher; } + _FORCE_INLINE_ btSoftBodyWorldInfo *get_soft_body_world_info() { return soft_body_world_info; } + _FORCE_INLINE_ bool is_using_soft_world() { return soft_body_world_info; } + + /// Used to set some parameters to Bullet world + /// @param p_param: + /// AREA_PARAM_GRAVITY to set the gravity magnitude of entire world + /// AREA_PARAM_GRAVITY_VECTOR to set the gravity direction of entire world + void set_param(PhysicsServer::AreaParameter p_param, const Variant &p_value); + /// Used to get some parameters to Bullet world + /// @param p_param: + /// AREA_PARAM_GRAVITY to get the gravity magnitude of entire world + /// AREA_PARAM_GRAVITY_VECTOR to get the gravity direction of entire world + Variant get_param(PhysicsServer::AreaParameter p_param); + + void set_param(PhysicsServer::SpaceParameter p_param, real_t p_value); + real_t get_param(PhysicsServer::SpaceParameter p_param); + + void add_area(AreaBullet *p_area); + void remove_area(AreaBullet *p_area); + void reload_collision_filters(AreaBullet *p_area); + + void add_rigid_body(RigidBodyBullet *p_body); + void remove_rigid_body(RigidBodyBullet *p_body); + void reload_collision_filters(RigidBodyBullet *p_body); + + void add_soft_body(SoftBodyBullet *p_body); + void remove_soft_body(SoftBodyBullet *p_body); + void reload_collision_filters(SoftBodyBullet *p_body); + + void add_constraint(ConstraintBullet *p_constraint, bool disableCollisionsBetweenLinkedBodies = false); + void remove_constraint(ConstraintBullet *p_constraint); + + int get_num_collision_objects() const; + void remove_all_collision_objects(); + + BulletPhysicsDirectSpaceState *get_direct_state(); + + void set_debug_contacts(int p_amount) { contactDebug.resize(p_amount); } + _FORCE_INLINE_ bool is_debugging_contacts() const { return !contactDebug.empty(); } + _FORCE_INLINE_ void reset_debug_contact_count() { + contactDebugCount = 0; + } + _FORCE_INLINE_ void add_debug_contact(const Vector3 &p_contact) { + if (contactDebugCount < contactDebug.size()) contactDebug[contactDebugCount++] = p_contact; + } + _FORCE_INLINE_ Vector<Vector3> get_debug_contacts() { return contactDebug; } + _FORCE_INLINE_ int get_debug_contact_count() { return contactDebugCount; } + + const Vector3 &get_gravity_direction() const { return gravityDirection; } + real_t get_gravity_magnitude() const { return gravityMagnitude; } + + void update_gravity(); + + bool test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, real_t p_margin, PhysicsServer::MotionResult *r_result); + +private: + void create_empty_world(bool p_create_soft_world); + void destroy_world(); + void check_ghost_overlaps(); + void check_body_collision(); + + bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_from, btScalar p_maxPenetrationDepth, btScalar p_depenetration_speed, btVector3 &out_recover_position); +}; +#endif diff --git a/servers/physics_server.h b/servers/physics_server.h index 09990cd02a..7cccd9b4cb 100644 --- a/servers/physics_server.h +++ b/servers/physics_server.h @@ -357,7 +357,7 @@ public: BODY_MODE_STATIC, BODY_MODE_KINEMATIC, BODY_MODE_RIGID, - //BODY_MODE_SOFT + BODY_MODE_SOFT, BODY_MODE_CHARACTER }; |