diff options
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 }; |