From c9450bba02dbc0ecf0acb1cbf85e4331e9537729 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 28 Oct 2014 17:32:34 -0700 Subject: [PATCH 001/105] Adding Bullet as non-required dependency --- libraries/physics/CMakeLists.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/physics/CMakeLists.txt b/libraries/physics/CMakeLists.txt index 5270f08730..8b6025aa1d 100644 --- a/libraries/physics/CMakeLists.txt +++ b/libraries/physics/CMakeLists.txt @@ -7,13 +7,13 @@ include_glm() link_hifi_libraries(shared) -## find BULLET -#find_package(BULLET REQUIRED) -# -#include_directories(SYSTEM "${BULLET_INCLUDE_DIRS}") -# -## append BULLET to our list of libraries to link -#list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${BULLET_LIBRARIES}") +# Note: we rely on the default FindBullet.cmake moduld that comes with cmake +find_package(Bullet) +if (BULLET_FOUND) + include_directories(SYSTEM "${BULLET_INCLUDE_DIRS}") + list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${BULLET_LIBRARIES}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_BULLET_PHYSICS}") +endif (BULLET_FOUND) # call macro to link our dependencies and bubble them up via a property on our target link_shared_dependencies() From c18121756c25d469fabb8153fef8c5f072ecb00b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 29 Oct 2014 14:33:11 -0700 Subject: [PATCH 002/105] fixed path to file in comments --- libraries/physics/src/AACubeShape.cpp | 2 +- libraries/physics/src/AACubeShape.h | 2 +- libraries/physics/src/CapsuleShape.cpp | 2 +- libraries/physics/src/CapsuleShape.h | 2 +- libraries/physics/src/CollisionInfo.cpp | 2 +- libraries/physics/src/CollisionInfo.h | 2 +- libraries/physics/src/Constraint.h | 2 +- libraries/physics/src/ContactConstraint.cpp | 2 +- libraries/physics/src/ContactConstraint.h | 2 +- libraries/physics/src/ContactPoint.cpp | 2 +- libraries/physics/src/ContactPoint.h | 2 +- libraries/physics/src/DistanceConstraint.cpp | 2 +- libraries/physics/src/DistanceConstraint.h | 2 +- libraries/physics/src/FixedConstraint.cpp | 2 +- libraries/physics/src/FixedConstraint.h | 2 +- libraries/physics/src/ListShape.cpp | 2 +- libraries/physics/src/ListShape.h | 2 +- libraries/physics/src/PhysicsEntity.cpp | 2 +- libraries/physics/src/PhysicsEntity.h | 2 +- libraries/physics/src/PhysicsSimulation.cpp | 2 +- libraries/physics/src/PhysicsSimulation.h | 2 +- libraries/physics/src/PlaneShape.cpp | 2 +- libraries/physics/src/PlaneShape.h | 2 +- libraries/physics/src/Ragdoll.cpp | 2 +- libraries/physics/src/Ragdoll.h | 2 +- libraries/physics/src/RayIntersectionInfo.h | 2 +- libraries/physics/src/Shape.h | 2 +- libraries/physics/src/ShapeCollider.cpp | 2 +- libraries/physics/src/ShapeCollider.h | 2 +- libraries/physics/src/SphereShape.cpp | 2 +- libraries/physics/src/SphereShape.h | 2 +- libraries/physics/src/VerletCapsuleShape.cpp | 2 +- libraries/physics/src/VerletCapsuleShape.h | 2 +- libraries/physics/src/VerletPoint.cpp | 2 +- libraries/physics/src/VerletPoint.h | 2 +- libraries/physics/src/VerletSphereShape.cpp | 2 +- libraries/physics/src/VerletSphereShape.h | 2 +- 37 files changed, 37 insertions(+), 37 deletions(-) diff --git a/libraries/physics/src/AACubeShape.cpp b/libraries/physics/src/AACubeShape.cpp index fa1a45b809..7ec024bf08 100644 --- a/libraries/physics/src/AACubeShape.cpp +++ b/libraries/physics/src/AACubeShape.cpp @@ -1,6 +1,6 @@ // // AACubeShape.cpp -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows on 2014.08.22 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/AACubeShape.h b/libraries/physics/src/AACubeShape.h index da7ba9d53f..914ec88812 100644 --- a/libraries/physics/src/AACubeShape.h +++ b/libraries/physics/src/AACubeShape.h @@ -1,6 +1,6 @@ // // AACubeShape.h -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows on 2014.08.22 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/CapsuleShape.cpp b/libraries/physics/src/CapsuleShape.cpp index 778798c15b..153f1991d4 100644 --- a/libraries/physics/src/CapsuleShape.cpp +++ b/libraries/physics/src/CapsuleShape.cpp @@ -1,6 +1,6 @@ // // CapsuleShape.cpp -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows on 02/20/2014. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/CapsuleShape.h b/libraries/physics/src/CapsuleShape.h index ede6993b40..b79af60582 100644 --- a/libraries/physics/src/CapsuleShape.h +++ b/libraries/physics/src/CapsuleShape.h @@ -1,6 +1,6 @@ // // CapsuleShape.h -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows on 02/20/2014. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/CollisionInfo.cpp b/libraries/physics/src/CollisionInfo.cpp index a652f3ce41..20ca543d90 100644 --- a/libraries/physics/src/CollisionInfo.cpp +++ b/libraries/physics/src/CollisionInfo.cpp @@ -1,6 +1,6 @@ // // CollisionInfo.cpp -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows on 02/14/2014. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/CollisionInfo.h b/libraries/physics/src/CollisionInfo.h index e6daf949b3..191e4e90d4 100644 --- a/libraries/physics/src/CollisionInfo.h +++ b/libraries/physics/src/CollisionInfo.h @@ -1,6 +1,6 @@ // // CollisionInfo.h -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows on 02/14/2014. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/Constraint.h b/libraries/physics/src/Constraint.h index 9bbdc185e1..ed97d6cc73 100644 --- a/libraries/physics/src/Constraint.h +++ b/libraries/physics/src/Constraint.h @@ -1,6 +1,6 @@ // // Constraint.h -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows 2014.07.24 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/ContactConstraint.cpp b/libraries/physics/src/ContactConstraint.cpp index 9d1a92bb21..9734922a52 100644 --- a/libraries/physics/src/ContactConstraint.cpp +++ b/libraries/physics/src/ContactConstraint.cpp @@ -1,6 +1,6 @@ // // ContactConstraint.cpp -// interface/src/avatar +// libraries/physcis/src // // Created by Andrew Meadows 2014.07.24 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/ContactConstraint.h b/libraries/physics/src/ContactConstraint.h index 41be2f769d..44c9c1b879 100644 --- a/libraries/physics/src/ContactConstraint.h +++ b/libraries/physics/src/ContactConstraint.h @@ -1,6 +1,6 @@ // // ContactConstraint.h -// interface/src/avatar +// libraries/physcis/src // // Created by Andrew Meadows 2014.07.24 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/ContactPoint.cpp b/libraries/physics/src/ContactPoint.cpp index b9ad87aa8f..b949f12582 100644 --- a/libraries/physics/src/ContactPoint.cpp +++ b/libraries/physics/src/ContactPoint.cpp @@ -1,6 +1,6 @@ // // ContactPoint.cpp -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows 2014.07.30 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/ContactPoint.h b/libraries/physics/src/ContactPoint.h index d584945970..dde8aa38e1 100644 --- a/libraries/physics/src/ContactPoint.h +++ b/libraries/physics/src/ContactPoint.h @@ -1,6 +1,6 @@ // // ContactPoint.h -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows 2014.07.30 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/DistanceConstraint.cpp b/libraries/physics/src/DistanceConstraint.cpp index 94dbfeba24..d513c4785b 100644 --- a/libraries/physics/src/DistanceConstraint.cpp +++ b/libraries/physics/src/DistanceConstraint.cpp @@ -1,6 +1,6 @@ // // DistanceConstraint.cpp -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows 2014.07.24 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/DistanceConstraint.h b/libraries/physics/src/DistanceConstraint.h index c588807178..8c2dd38102 100644 --- a/libraries/physics/src/DistanceConstraint.h +++ b/libraries/physics/src/DistanceConstraint.h @@ -1,6 +1,6 @@ // // DistanceConstraint.h -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows 2014.07.24 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/FixedConstraint.cpp b/libraries/physics/src/FixedConstraint.cpp index 8f1edc1fb5..23f1749fa9 100644 --- a/libraries/physics/src/FixedConstraint.cpp +++ b/libraries/physics/src/FixedConstraint.cpp @@ -1,6 +1,6 @@ // // FixedConstraint.cpp -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows 2014.07.24 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/FixedConstraint.h b/libraries/physics/src/FixedConstraint.h index 66a27369ce..067b9988cd 100644 --- a/libraries/physics/src/FixedConstraint.h +++ b/libraries/physics/src/FixedConstraint.h @@ -1,6 +1,6 @@ // // FixedConstraint.h -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows 2014.07.24 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/ListShape.cpp b/libraries/physics/src/ListShape.cpp index 67ec32d4b1..cf548d3430 100644 --- a/libraries/physics/src/ListShape.cpp +++ b/libraries/physics/src/ListShape.cpp @@ -1,6 +1,6 @@ // // ListShape.cpp -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows on 02/20/2014. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/ListShape.h b/libraries/physics/src/ListShape.h index 6352ef3f07..0c1d2ddbb0 100644 --- a/libraries/physics/src/ListShape.h +++ b/libraries/physics/src/ListShape.h @@ -1,6 +1,6 @@ // // ListShape.h -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows on 02/20/2014. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/PhysicsEntity.cpp b/libraries/physics/src/PhysicsEntity.cpp index a01706f539..80176edb76 100644 --- a/libraries/physics/src/PhysicsEntity.cpp +++ b/libraries/physics/src/PhysicsEntity.cpp @@ -1,6 +1,6 @@ // // PhysicsEntity.cpp -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows 2014.06.11 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/PhysicsEntity.h b/libraries/physics/src/PhysicsEntity.h index a96754b75c..fc39dcb7fc 100644 --- a/libraries/physics/src/PhysicsEntity.h +++ b/libraries/physics/src/PhysicsEntity.h @@ -1,6 +1,6 @@ // // PhysicsEntity.h -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows 2014.05.30 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/PhysicsSimulation.cpp b/libraries/physics/src/PhysicsSimulation.cpp index 72a1eeebfd..b92d9bec8f 100644 --- a/libraries/physics/src/PhysicsSimulation.cpp +++ b/libraries/physics/src/PhysicsSimulation.cpp @@ -1,6 +1,6 @@ // // PhysicsSimulation.cpp -// interface/src/avatar +// libraries/physcis/src // // Created by Andrew Meadows 2014.06.06 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/PhysicsSimulation.h b/libraries/physics/src/PhysicsSimulation.h index 12506e23d0..90d6e38187 100644 --- a/libraries/physics/src/PhysicsSimulation.h +++ b/libraries/physics/src/PhysicsSimulation.h @@ -1,6 +1,6 @@ // // PhysicsSimulation.h -// interface/src/avatar +// libraries/physcis/src // // Created by Andrew Meadows 2014.06.06 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/PlaneShape.cpp b/libraries/physics/src/PlaneShape.cpp index 1a4122f3aa..2e71c2f330 100644 --- a/libraries/physics/src/PlaneShape.cpp +++ b/libraries/physics/src/PlaneShape.cpp @@ -1,6 +1,6 @@ // // PlaneShape.cpp -// libraries/shared/src +// libraries/physics/src // // Created by Andrzej Kapolka on 4/10/2014. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/PlaneShape.h b/libraries/physics/src/PlaneShape.h index 8d6de326af..bb2c0ba408 100644 --- a/libraries/physics/src/PlaneShape.h +++ b/libraries/physics/src/PlaneShape.h @@ -1,6 +1,6 @@ // // PlaneShape.h -// libraries/shared/src +// libraries/physics/src // // Created by Andrzej Kapolka on 4/9/2014. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/Ragdoll.cpp b/libraries/physics/src/Ragdoll.cpp index 3eecef2333..7936828025 100644 --- a/libraries/physics/src/Ragdoll.cpp +++ b/libraries/physics/src/Ragdoll.cpp @@ -1,6 +1,6 @@ // // Ragdoll.cpp -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows 2014.05.30 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/Ragdoll.h b/libraries/physics/src/Ragdoll.h index 5447b6769e..ab81f165bd 100644 --- a/libraries/physics/src/Ragdoll.h +++ b/libraries/physics/src/Ragdoll.h @@ -1,6 +1,6 @@ // // Ragdoll.h -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows 2014.05.30 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/RayIntersectionInfo.h b/libraries/physics/src/RayIntersectionInfo.h index 6c4eb3f8dd..06ec0aceaa 100644 --- a/libraries/physics/src/RayIntersectionInfo.h +++ b/libraries/physics/src/RayIntersectionInfo.h @@ -1,6 +1,6 @@ // // RayIntersectionInfo.h -// interface/src/avatar +// libraries/physcis/src // // Created by Andrew Meadows 2014.09.09 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/Shape.h b/libraries/physics/src/Shape.h index cdf3ba72e5..139f7719de 100644 --- a/libraries/physics/src/Shape.h +++ b/libraries/physics/src/Shape.h @@ -1,6 +1,6 @@ // // Shape.h -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows on 2014. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/ShapeCollider.cpp b/libraries/physics/src/ShapeCollider.cpp index 2f8ea88553..f94e06bf26 100644 --- a/libraries/physics/src/ShapeCollider.cpp +++ b/libraries/physics/src/ShapeCollider.cpp @@ -1,6 +1,6 @@ // // ShapeCollider.cpp -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows on 02/20/2014. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/ShapeCollider.h b/libraries/physics/src/ShapeCollider.h index 7414665ca7..f2c0de470d 100644 --- a/libraries/physics/src/ShapeCollider.h +++ b/libraries/physics/src/ShapeCollider.h @@ -1,6 +1,6 @@ // // ShapeCollider.h -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows on 02/20/2014. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/SphereShape.cpp b/libraries/physics/src/SphereShape.cpp index 4c47ae91c0..d63ff412df 100644 --- a/libraries/physics/src/SphereShape.cpp +++ b/libraries/physics/src/SphereShape.cpp @@ -1,6 +1,6 @@ // // SphereShape.cpp -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows on 2014.06.17 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/SphereShape.h b/libraries/physics/src/SphereShape.h index 72f46c1168..9cb83f92e1 100644 --- a/libraries/physics/src/SphereShape.h +++ b/libraries/physics/src/SphereShape.h @@ -1,6 +1,6 @@ // // SphereShape.h -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows on 2014. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/VerletCapsuleShape.cpp b/libraries/physics/src/VerletCapsuleShape.cpp index 78e3f6763b..a04c36d56d 100644 --- a/libraries/physics/src/VerletCapsuleShape.cpp +++ b/libraries/physics/src/VerletCapsuleShape.cpp @@ -1,6 +1,6 @@ // // VerletCapsuleShape.cpp -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows on 2014.06.16 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/VerletCapsuleShape.h b/libraries/physics/src/VerletCapsuleShape.h index 828e5def6c..19afab2b61 100644 --- a/libraries/physics/src/VerletCapsuleShape.h +++ b/libraries/physics/src/VerletCapsuleShape.h @@ -1,6 +1,6 @@ // // VerletCapsuleShape.h -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows on 2014.06.16 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/VerletPoint.cpp b/libraries/physics/src/VerletPoint.cpp index cf9aeca149..895f3be8b2 100644 --- a/libraries/physics/src/VerletPoint.cpp +++ b/libraries/physics/src/VerletPoint.cpp @@ -1,6 +1,6 @@ // // VerletPoint.cpp -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows 2014.07.24 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/VerletPoint.h b/libraries/physics/src/VerletPoint.h index 3c73e5eb01..d80698c9e2 100644 --- a/libraries/physics/src/VerletPoint.h +++ b/libraries/physics/src/VerletPoint.h @@ -1,6 +1,6 @@ // // VerletPoint.h -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows 2014.07.24 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/VerletSphereShape.cpp b/libraries/physics/src/VerletSphereShape.cpp index da8242f26a..83dcbd9a58 100644 --- a/libraries/physics/src/VerletSphereShape.cpp +++ b/libraries/physics/src/VerletSphereShape.cpp @@ -1,6 +1,6 @@ // // VerletSphereShape.cpp -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows on 2014.06.16 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/physics/src/VerletSphereShape.h b/libraries/physics/src/VerletSphereShape.h index c9a23faef2..596f4a517b 100644 --- a/libraries/physics/src/VerletSphereShape.h +++ b/libraries/physics/src/VerletSphereShape.h @@ -1,6 +1,6 @@ // // VerletSphereShape.h -// libraries/shared/src +// libraries/physics/src // // Created by Andrew Meadows on 2014.06.16 // Copyright 2014 High Fidelity, Inc. From 29fd35938587cc4b9b45dc60b279ad2c929f24ff Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 29 Oct 2014 14:39:23 -0700 Subject: [PATCH 003/105] fix typo in libraries/physics/CMakeLists.txt --- libraries/physics/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/CMakeLists.txt b/libraries/physics/CMakeLists.txt index 8b6025aa1d..ec289cd096 100644 --- a/libraries/physics/CMakeLists.txt +++ b/libraries/physics/CMakeLists.txt @@ -12,7 +12,7 @@ find_package(Bullet) if (BULLET_FOUND) include_directories(SYSTEM "${BULLET_INCLUDE_DIRS}") list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${BULLET_LIBRARIES}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_BULLET_PHYSICS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_BULLET_PHYSICS") endif (BULLET_FOUND) # call macro to link our dependencies and bubble them up via a property on our target From 50a97849bbe67421bdbf8a889c8962f3a2e111fb Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 30 Oct 2014 10:42:44 -0700 Subject: [PATCH 004/105] Add PhysicsWorld and ShapeManager classes --- libraries/physics/src/PhysicsWorld.cpp | 23 +++++++ libraries/physics/src/PhysicsWorld.h | 41 +++++++++++ libraries/physics/src/ShapeManager.cpp | 94 ++++++++++++++++++++++++++ libraries/physics/src/ShapeManager.h | 88 ++++++++++++++++++++++++ 4 files changed, 246 insertions(+) create mode 100644 libraries/physics/src/PhysicsWorld.cpp create mode 100644 libraries/physics/src/PhysicsWorld.h create mode 100644 libraries/physics/src/ShapeManager.cpp create mode 100644 libraries/physics/src/ShapeManager.h diff --git a/libraries/physics/src/PhysicsWorld.cpp b/libraries/physics/src/PhysicsWorld.cpp new file mode 100644 index 0000000000..9364b77e65 --- /dev/null +++ b/libraries/physics/src/PhysicsWorld.cpp @@ -0,0 +1,23 @@ +// +// PhysicsWorld.cpp +// libraries/physcis/src +// +// Created by Andrew Meadows 2014.10.29 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "PhysicsWorld.h" + +PhysicsWorld::~PhysicsWorld() { +} + +void PhysicsWorld::init() { + _collisionConfig = new btDefaultCollisionConfiguration(); + _collisionDispatcher = new btCollisionDispatcher(_collisionConfig); + _broadphaseFilter = new btDbvtBroadphase(); + _constraintSolver = new btSequentialImpulseConstraintSolver; + _dynamicsWorld = new btDiscreteDynamicsWorld(_collisionDispatcher, _broadphaseFilter, _constraintSolver, _collisionConfig); +} diff --git a/libraries/physics/src/PhysicsWorld.h b/libraries/physics/src/PhysicsWorld.h new file mode 100644 index 0000000000..778e5280d8 --- /dev/null +++ b/libraries/physics/src/PhysicsWorld.h @@ -0,0 +1,41 @@ +// +// PhysicsWorld.h +// libraries/physcis/src +// +// Created by Andrew Meadows 2014.10.29 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_PhysicsWorld_h +#define hifi_PhysicsWorld_h + +#ifdef USE_BULLET_PHYSICS + +#include + +class PhysicsWorld { +public: + + PhysicsWorld() : _collisionConfig(NULL), _collisionDispatcher(NULL), + _broadphaseFilter(NULL), _constraintSolver(NULL), _dynamicsWorld(NULL) { } + + ~PhysicsWorld(); + + void init(); + +protected: + btDefaultCollisionConfiguration* _collisionConfig; + btCollisionDispatcher* _collisionDispatcher; + btBroadphaseInterface* _broadphaseFilter; + btSequentialImpulseConstraintSolver* _constraintSolver; + btDiscreteDynamicsWorld* _dynamicsWorld; + +private: +}; + + +#endif // USE_BULLET_PHYSICS +#endif // hifi_PhysicsWorld_h diff --git a/libraries/physics/src/ShapeManager.cpp b/libraries/physics/src/ShapeManager.cpp new file mode 100644 index 0000000000..99c1d8b2ef --- /dev/null +++ b/libraries/physics/src/ShapeManager.cpp @@ -0,0 +1,94 @@ +// +// ShapeManager.cpp +// libraries/physcis/src +// +// Created by Andrew Meadows 2014.10.29 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifdef USE_BULLET_PHYSICS +#include "ShapeManager.h" + +ShapeManager::ShapeManager() { +} + +ShapeManager::~ShapeManager() { + int numShapes = _shapeMap.size(); + for (int i = 0; i < numShapes; ++i) { + ShapeReference* shapeRef = _shapeMap.getAtIndex(i); + delete shapeRef->_shape; + } +} + + +btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { + int key = info.getHash(); + ShapeReference* shapeRef = _shapeMap.find(key); + if (shapeRef) { + shapeRef->_refCount++; + return shapeRef->_shape; + } else { + btCollisionShape* shape = info.createShape(); + if (shape) { + ShapeReference newRef; + newRef._refCount = 1; + newRef._shape = shape; + _shapeMap.insert(key, newRef); + } + return shape; + } +} + +bool ShapeManager::releaseShape(const ShapeInfo& info) { + int key = info.getHash(); + ShapeReference* shapeRef = _shapeMap.find(key); + if (shapeRef) { + if (shapeRef->_refCount > 0) { + shapeRef->_refCount--; + if (shapeRef->_refCount == 0) { + _pendingGarbage.push_back(key); + const int MAX_GARBAGE_CAPACITY = 127; + if (_pendingGarbage.size() > MAX_GARBAGE_CAPACITY) { + collectGarbage(); + } + } + return true; + } else { + // attempt to remove shape that has no refs + assert(false); + } + } else { + // attempt to remove unmanaged shape + assert(false); + } + return false; +} + +void ShapeManager::collectGarbage() { + int numShapes = _pendingGarbage.size(); + for (int i = 0; i < numShapes; ++i) { + int key = _pendingGarbage[i]; + ShapeReference* shapeRef = _shapeMap.find(key); + assert(shapeRef != NULL); + if (shapeRef->_refCount == 0) { + delete shapeRef->_shape; + _shapeMap.remove(key); + } + } + _pendingGarbage.clear(); +} + +int ShapeManager::getNumReferences(const ShapeInfo& info) const { + int key = info.getHash(); + const ShapeReference* shapeRef = _shapeMap.find(key); + if (shapeRef) { + return shapeRef->_refCount; + } + return -1; +} + + +#endif // USE_BULLET_PHYSICS diff --git a/libraries/physics/src/ShapeManager.h b/libraries/physics/src/ShapeManager.h new file mode 100644 index 0000000000..0a1f75c7c8 --- /dev/null +++ b/libraries/physics/src/ShapeManager.h @@ -0,0 +1,88 @@ +// +// ShapeManager.h +// libraries/physcis/src +// +// Created by Andrew Meadows 2014.10.29 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ShapeManager_h +#define hifi_ShapeManager_h + +#ifdef USE_BULLET_PHYSICS + +#include +#include + +struct ShapeInfo { + int _type; + btVector3 _size; + + ShapeInfo() : _type(BOX_SHAPE_PROXYTYPE), _size(1.0f, 1.0f, 1.0f) {} + + virtual int getHash() const { + // successfully multiply components of size by primes near 256 and convert to U32 + unsigned int key = (unsigned int)(241.0f * _size.getX()) + + 241 * (unsigned int)(251.0f * _size.getY()) + + (241 * 251) * (unsigned int)(257.0f * _size.getZ()); + // then scramble the results + key += ~(key << 15); + key ^= (key >> 10); + key += (key << 3); + key ^= (key >> 6); + key += ~(key << 11); + key ^= (key >> 16); + // finally XOR with type + key ^= _type; + return key; + } + + virtual btCollisionShape* createShape() const { + const float MAX_SHAPE_DIMENSION = 100.0f; + const float MIN_SHAPE_DIMENSION = 0.01f; + for (int i = 0; i < 3; ++i) { + float side = _size[i]; + if (side > MAX_SHAPE_DIMENSION || side < MIN_SHAPE_DIMENSION) { + return NULL; + } + } + // default behavior is to create a btBoxShape + return new btBoxShape(0.5f * _size); + } +}; + +struct ShapeReference { + int _refCount; + btCollisionShape* _shape; + ShapeReference() : _refCount(0), _shape(NULL) {} +}; + +class ShapeManager { +public: + + ShapeManager(); + ~ShapeManager(); + + /// \return pointer to shape + btCollisionShape* getShape(const ShapeInfo& info); + + /// \return true if shape was found and released + bool releaseShape(const ShapeInfo& info); + + /// delete shapes that have zero references + void collectGarbage(); + + // validation methods + int getNumShapes() const { return _shapeMap.size(); } + int getNumReferences(const ShapeInfo& info) const; + +private: + btHashMap _shapeMap; + btAlignedObjectArray _pendingGarbage; +}; + +#endif // USE_BULLET_PHYSICS +#endif // hifi_ShapeManager_h From d26540b029b8ab6da29287c4761582558aef89a6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 31 Oct 2014 17:13:17 -0700 Subject: [PATCH 005/105] ShapeManager now under unit test --- libraries/physics/CMakeLists.txt | 9 +- libraries/physics/src/PhysicsEntity.h | 4 + libraries/physics/src/ShapeInfo.cpp | 159 +++++++++++++++++++++ libraries/physics/src/ShapeInfo.h | 187 +++++++++++++++++++++++++ libraries/physics/src/ShapeManager.cpp | 35 ++++- libraries/physics/src/ShapeManager.h | 187 +++++++++++++++++++++---- tests/physics/CMakeLists.txt | 2 +- tests/physics/src/main.cpp | 6 +- 8 files changed, 544 insertions(+), 45 deletions(-) create mode 100644 libraries/physics/src/ShapeInfo.cpp create mode 100644 libraries/physics/src/ShapeInfo.h diff --git a/libraries/physics/CMakeLists.txt b/libraries/physics/CMakeLists.txt index ec289cd096..4799deea3d 100644 --- a/libraries/physics/CMakeLists.txt +++ b/libraries/physics/CMakeLists.txt @@ -4,16 +4,9 @@ set(TARGET_NAME physics) setup_hifi_library() include_glm() +include_bullet() link_hifi_libraries(shared) -# Note: we rely on the default FindBullet.cmake moduld that comes with cmake -find_package(Bullet) -if (BULLET_FOUND) - include_directories(SYSTEM "${BULLET_INCLUDE_DIRS}") - list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${BULLET_LIBRARIES}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_BULLET_PHYSICS") -endif (BULLET_FOUND) - # call macro to link our dependencies and bubble them up via a property on our target link_shared_dependencies() diff --git a/libraries/physics/src/PhysicsEntity.h b/libraries/physics/src/PhysicsEntity.h index fc39dcb7fc..0487b9b078 100644 --- a/libraries/physics/src/PhysicsEntity.h +++ b/libraries/physics/src/PhysicsEntity.h @@ -18,6 +18,10 @@ #include #include +#ifdef USE_BULLET_PHYSICS +#include "PhysicsWorld.h" +#endif // USE_BULLET_PHYSICS + #include "CollisionInfo.h" #include "RayIntersectionInfo.h" diff --git a/libraries/physics/src/ShapeInfo.cpp b/libraries/physics/src/ShapeInfo.cpp new file mode 100644 index 0000000000..03dc162f6b --- /dev/null +++ b/libraries/physics/src/ShapeInfo.cpp @@ -0,0 +1,159 @@ +// +// ShapeInfo.cpp +// libraries/physcis/src +// +// Created by Andrew Meadows 2014.10.29 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifdef USE_BULLET_PHYSICS + +#include + +#include "ShapeInfo.h" + +void ShapeInfo::getInfo(const btCollisionShape* shape) { + _data.clear(); + if (shape) { + _type = (unsigned int)(shape->getShapeType()); + switch(_type) { + case BOX_SHAPE_PROXYTYPE: + { + const btBoxShape* boxShape = static_cast(shape); + _data.push_back(boxShape->getHalfExtentsWithMargin()); + } + break; + case SPHERE_SHAPE_PROXYTYPE: + { + const btSphereShape* sphereShape = static_cast(shape); + _data.push_back(btVector3(0.0f, 0.0f, sphereShape->getRadius())); + } + break; + case CYLINDER_SHAPE_PROXYTYPE: + { + const btCylinderShape* cylinderShape = static_cast(shape); + _data.push_back(cylinderShape->getHalfExtentsWithMargin()); + } + break; + case CAPSULE_SHAPE_PROXYTYPE: + { + const btCapsuleShape* capsuleShape = static_cast(shape); + _data.push_back(btVector3(capsuleShape->getRadius(), capsuleShape->getHalfHeight(), 0.0f)); + // NOTE: we only support capsules with axis along yAxis + } + break; + default: + _type = INVALID_SHAPE_PROXYTYPE; + break; + } + } else { + _type = INVALID_SHAPE_PROXYTYPE; + } +} + +void ShapeInfo::setBox(const btVector3& halfExtents) { + _type = BOX_SHAPE_PROXYTYPE; + _data.clear(); + _data.push_back(halfExtents); +} + +void ShapeInfo::setSphere(float radius) { + _type = SPHERE_SHAPE_PROXYTYPE; + _data.clear(); + _data.push_back(btVector3(0.0f, 0.0f, radius)); +} + +void ShapeInfo::setCylinder(float radius, float height) { + _type = CYLINDER_SHAPE_PROXYTYPE; + _data.clear(); + // NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X + // halfExtents = btVector3(radius, halfHeight, unused) + _data.push_back(btVector3(radius, 0.5f * height, radius)); +} + +void ShapeInfo::setCapsule(float radius, float height) { + _type = CAPSULE_SHAPE_PROXYTYPE; + _data.clear(); + _data.push_back(btVector3(radius, 0.5f * height, 0.0f)); +} + +int ShapeInfo::computeHash() const { + // This hash algorithm works well for shapes that have dimensions less than about 256m. + // At larger values the likelihood of hash collision goes up because of the most + // significant bits are pushed off the top and the result could be the same as for smaller + // dimensions (truncation). + // + // The algorithm may produce collisions for shapes whose dimensions differ by less than + // ~1/256 m, however this is by design -- we don't expect collision differences smaller + // than 1 mm to be noticable. + unsigned int key = 0; + btVector3 tempData; + int numData = _data.size(); + for (int i = 0; i < numData; ++i) { + // Successively multiply components of each vec3 by primes near 512 and convert to U32 + // to spread the data across more bits. Note that all dimensions are at half-value + // (half extents, radius, etc) which is why we multiply by primes near 512 rather + // than 256. + tempData = _data[i]; + key += (unsigned int)(509.0f * (tempData.getZ() + 0.01f)) + + 509 * (unsigned int)(521.0f * (tempData.getY() + 0.01f)) + + (509 * 521) * (unsigned int)(523.0f * (tempData.getX() + 0.01f)); + // avalanch the bits + key += ~(key << 15); + key ^= (key >> 10); + key += (key << 3); + key ^= (key >> 6); + key += ~(key << 11); + key ^= (key >> 16); + } + // finally XOR with type + return (int)(key ^ _type); +} + +btCollisionShape* ShapeInfo::createShape() const { + btCollisionShape* shape = NULL; + int numData = _data.size(); + switch(_type) { + case BOX_SHAPE_PROXYTYPE: + { + if (numData > 0) { + btVector3 halfExtents = _data[0]; + shape = new btBoxShape(halfExtents); + } + } + break; + case SPHERE_SHAPE_PROXYTYPE: + { + if (numData > 0) { + float radius = _data[0].getZ(); + shape = new btSphereShape(radius); + } + } + break; + case CYLINDER_SHAPE_PROXYTYPE: + { + if (numData > 0) { + btVector3 halfExtents = _data[0]; + // NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X + // halfExtents = btVector3(radius, halfHeight, unused) + shape = new btCylinderShape(halfExtents); + } + } + break; + case CAPSULE_SHAPE_PROXYTYPE: + { + if (numData > 0) { + float radius = _data[0].getX(); + float height = 2.0f * _data[0].getY(); + shape = new btCapsuleShape(radius, height); + } + } + break; + } + return shape; +} + +#endif // USE_BULLET_PHYSICS diff --git a/libraries/physics/src/ShapeInfo.h b/libraries/physics/src/ShapeInfo.h new file mode 100644 index 0000000000..86063694ca --- /dev/null +++ b/libraries/physics/src/ShapeInfo.h @@ -0,0 +1,187 @@ +// +// ShapeInfo.h +// libraries/physcis/src +// +// Created by Andrew Meadows 2014.10.29 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ShapeInfo_h +#define hifi_ShapeInfo_h + +#ifdef USE_BULLET_PHYSICS + +#include +#include + +const float DEFAULT_MARGIN = 0.04f; + +class ShapeInfo { +public: + ShapeInfo() : _type(INVALID_SHAPE_PROXYTYPE) {} + + ShapeInfo(const btCollisionShape* shape) : _type(INVALID_SHAPE_PROXYTYPE) { + getInfo(shape); + } + + // BOOKMARK -- move ShapeInfo to its own files + void getInfo(const btCollisionShape* shape); + /*{ + _data.clear(); + if (shape) { + _type = (unsigned int)(shape->getShapeType()); + switch(_type) { + case BOX_SHAPE_PROXYTYPE: + { + const btBoxShape* boxShape = static_cast(shape); + _data.push_back(boxShape->getHalfExtentsWithMargin()); + } + break; + case SPHERE_SHAPE_PROXYTYPE: + { + const btSphereShape* sphereShape = static_cast(shape); + _data.push_back(btVector3(0.0f, 0.0f, sphereShape->getRadius())); + } + break; + case CYLINDER_SHAPE_PROXYTYPE: + { + const btCylinderShape* cylinderShape = static_cast(shape); + _data.push_back(cylinderShape->getHalfExtentsWithMargin()); + } + break; + case CAPSULE_SHAPE_PROXYTYPE: + { + const btCapsuleShape* capsuleShape = static_cast(shape); + _data.push_back(btVector3(capsuleShape->getRadius(), capsuleShape->getHalfHeight(), 0.0f)); + // NOTE: we only support capsules with axis along yAxis + } + break; + default: + _type = INVALID_SHAPE_PROXYTYPE; + break; + } + } else { + _type = INVALID_SHAPE_PROXYTYPE; + } + }*/ + + void setBox(const btVector3& halfExtents); + /*{ + _type = BOX_SHAPE_PROXYTYPE; + _data.clear(); + _data.push_back(halfExtents); + }*/ + + void setSphere(float radius); + /* { + _type = SPHERE_SHAPE_PROXYTYPE; + _data.clear(); + _data.push_back(btVector3(0.0f, 0.0f, radius)); + }*/ + + void setCylinder(float radius, float height); + /*{ + _type = CYLINDER_SHAPE_PROXYTYPE; + _data.clear(); + // NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X + // halfExtents = btVector3(radius, halfHeight, unused) + _data.push_back(btVector3(radius, 0.5f * height, radius)); + }*/ + + void setCapsule(float radius, float height); + /*{ + _type = CAPSULE_SHAPE_PROXYTYPE; + _data.clear(); + _data.push_back(btVector3(radius, 0.5f * height, 0.0f)); + }*/ + + int computeHash() const; + /*{ + // This hash algorithm works well for shapes that have dimensions less than about 256m. + // At larger values the likelihood of hash collision goes up because of the most + // significant bits are pushed off the top and the result could be the same as for smaller + // dimensions (truncation). + // + // The algorithm may produce collisions for shapes whose dimensions differ by less than + // ~1/256 m, however this is by design -- we don't expect collision differences smaller + // than 1 mm to be noticable. + unsigned int key = 0; + btVector3 tempData; + int numData = _data.size(); + for (int i = 0; i < numData; ++i) { + // Successively multiply components of each vec3 by primes near 512 and convert to U32 + // to spread the data across more bits. Note that all dimensions are at half-value + // (half extents, radius, etc) which is why we multiply by primes near 512 rather + // than 256. + tempData = _data[i]; + key += (unsigned int)(509.0f * (tempData.getZ() + 0.01f)) + + 509 * (unsigned int)(521.0f * (tempData.getY() + 0.01f)) + + (509 * 521) * (unsigned int)(523.0f * (tempData.getX() + 0.01f)); + // avalanch the bits + key += ~(key << 15); + key ^= (key >> 10); + key += (key << 3); + key ^= (key >> 6); + key += ~(key << 11); + key ^= (key >> 16); + } + // finally XOR with type + return (int)(key ^ _type); + }*/ + +private: + friend class ShapeManager; + + btCollisionShape* createShape() const; + /*{ + btCollisionShape* shape = NULL; + int numData = _data.size(); + switch(_type) { + case BOX_SHAPE_PROXYTYPE: + { + if (numData > 0) { + btVector3 halfExtents = _data[0]; + shape = new btBoxShape(halfExtents); + } + } + break; + case SPHERE_SHAPE_PROXYTYPE: + { + if (numData > 0) { + float radius = _data[0].getZ(); + shape = new btSphereShape(radius); + } + } + break; + case CYLINDER_SHAPE_PROXYTYPE: + { + if (numData > 0) { + btVector3 halfExtents = _data[0]; + // NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X + // halfExtents = btVector3(radius, halfHeight, unused) + shape = new btCylinderShape(halfExtents); + } + } + break; + case CAPSULE_SHAPE_PROXYTYPE: + { + if (numData > 0) { + float radius = _data[0].getX(); + float height = 2.0f * _data[0].getY(); + shape = new btCapsuleShape(radius, height); + } + } + break; + } + return shape; + }*/ + + int _type; + btAlignedObjectArray _data; +}; + +#endif // USE_BULLET_PHYSICS +#endif // hifi_ShapeInfo_h diff --git a/libraries/physics/src/ShapeManager.cpp b/libraries/physics/src/ShapeManager.cpp index 99c1d8b2ef..9874f24859 100644 --- a/libraries/physics/src/ShapeManager.cpp +++ b/libraries/physics/src/ShapeManager.cpp @@ -25,7 +25,7 @@ ShapeManager::~ShapeManager() { btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { - int key = info.getHash(); + int key = info.computeHash(); ShapeReference* shapeRef = _shapeMap.find(key); if (shapeRef) { shapeRef->_refCount++; @@ -43,7 +43,7 @@ btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { } bool ShapeManager::releaseShape(const ShapeInfo& info) { - int key = info.getHash(); + int key = info.computeHash(); ShapeReference* shapeRef = _shapeMap.find(key); if (shapeRef) { if (shapeRef->_refCount > 0) { @@ -67,6 +67,35 @@ bool ShapeManager::releaseShape(const ShapeInfo& info) { return false; } +/* +bool ShapeManager::releaseShape(const btCollisionShape* shape) { + // when the number of shapes is high it's probably cheaper to try to construct a ShapeInfo + // and then compute the hash rather than walking the list in search of the pointer. + int key = info.computeHash(); + ShapeReference* shapeRef = _shapeMap.find(key); + if (shapeRef) { + if (shapeRef->_refCount > 0) { + shapeRef->_refCount--; + if (shapeRef->_refCount == 0) { + _pendingGarbage.push_back(key); + const int MAX_GARBAGE_CAPACITY = 127; + if (_pendingGarbage.size() > MAX_GARBAGE_CAPACITY) { + collectGarbage(); + } + } + return true; + } else { + // attempt to remove shape that has no refs + assert(false); + } + } else { + // attempt to remove unmanaged shape + assert(false); + } + return false; +} +*/ + void ShapeManager::collectGarbage() { int numShapes = _pendingGarbage.size(); for (int i = 0; i < numShapes; ++i) { @@ -82,7 +111,7 @@ void ShapeManager::collectGarbage() { } int ShapeManager::getNumReferences(const ShapeInfo& info) const { - int key = info.getHash(); + int key = info.computeHash(); const ShapeReference* shapeRef = _shapeMap.find(key); if (shapeRef) { return shapeRef->_refCount; diff --git a/libraries/physics/src/ShapeManager.h b/libraries/physics/src/ShapeManager.h index 0a1f75c7c8..c683a041a3 100644 --- a/libraries/physics/src/ShapeManager.h +++ b/libraries/physics/src/ShapeManager.h @@ -17,48 +17,166 @@ #include #include +#include "ShapeInfo.h" + +/* struct ShapeInfo { int _type; - btVector3 _size; + btAlignedObjectArray _data; + //btVector3 _scale; - ShapeInfo() : _type(BOX_SHAPE_PROXYTYPE), _size(1.0f, 1.0f, 1.0f) {} + ShapeInfo() : _type(INVALID_SHAPE_PROXYTYPE) {} - virtual int getHash() const { - // successfully multiply components of size by primes near 256 and convert to U32 - unsigned int key = (unsigned int)(241.0f * _size.getX()) - + 241 * (unsigned int)(251.0f * _size.getY()) - + (241 * 251) * (unsigned int)(257.0f * _size.getZ()); - // then scramble the results - key += ~(key << 15); - key ^= (key >> 10); - key += (key << 3); - key ^= (key >> 6); - key += ~(key << 11); - key ^= (key >> 16); - // finally XOR with type - key ^= _type; - return key; + ShapeInfo(const btCollisionShape* shape) : _type(INVALID_SHAPE_PROXYTYPE) { + getInfo(shape); } + // BOOKMARK -- move ShapeInfo to its own files + void getInfo(const btCollisionShape* shape) { + _data.clear(); + if (shape) { + _type = (unsigned int)(shape->getShapeType()); + switch(_type) { + case BOX_SHAPE_PROXYTYPE: + { + const btBoxShape* boxShape = static_cast(shape); + _data.push_back(boxShape->getHalfExtentsWithMargin()); + } + break; + case SPHERE_SHAPE_PROXYTYPE: + { + const btSphereShape* sphereShape = static_cast(shape); + _data.push_back(btVector3(0.0f, 0.0f, sphereShape->getRadius())); + } + break; + case CYLINDER_SHAPE_PROXYTYPE: + { + const btCylinderShape* cylinderShape = static_cast(shape); + _data.push_back(cylinderShape->getHalfExtentsWithMargin()); + } + break; + case CAPSULE_SHAPE_PROXYTYPE: + { + const btCapsuleShape* capsuleShape = static_cast(shape); + _data.push_back(btVector3(capsuleShape->getRadius(), capsuleShape->getHalfHeight(), 0.0f)); + // NOTE: we only support capsules with axis along yAxis + } + break; + default: + _type = INVALID_SHAPE_PROXYTYPE; + break; + } + } else { + _type = INVALID_SHAPE_PROXYTYPE; + } + } + + void setBox(const btVector3& halfExtents) { + _type = BOX_SHAPE_PROXYTYPE; + _data.clear(); + _data.push_back(halfExtents); + } + + void setSphere(float radius) { + _type = SPHERE_SHAPE_PROXYTYPE; + _data.clear(); + _data.push_back(btVector3(0.0f, 0.0f, radius)); + } + + void setCylinder(float radius, float height) { + _type = CYLINDER_SHAPE_PROXYTYPE; + _data.clear(); + // NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X + // halfExtents = btVector3(radius, halfHeight, unused) + _data.push_back(btVector3(radius, 0.5f * height, radius)); + } + + void setCapsule(float radius, float height) { + _type = CAPSULE_SHAPE_PROXYTYPE; + _data.clear(); + _data.push_back(btVector3(radius, 0.5f * height, 0.0f)); + } + + virtual int computeHash() const { + // This hash algorithm works well for shapes that have dimensions less than about 256m. + // At larger values the likelihood of hash collision goes up because of the most + // significant bits are pushed off the top and the result could be the same as for smaller + // dimensions (truncation). + // + // The algorithm may produce collisions for shapes whose dimensions differ by less than + // ~1/256 m, however this is by design -- we don't expect collision differences smaller + // than 1 mm to be noticable. + unsigned int key = 0; + btVector3 tempData; + int numData = _data.size(); + for (int i = 0; i < numData; ++i) { + // Successively multiply components of each vec3 by primes near 512 and convert to U32 + // to spread the data across more bits. Note that all dimensions are at half-value + // (half extents, radius, etc) which is why we multiply by primes near 512 rather + // than 256. + tempData = _data[i]; + key += (unsigned int)(509.0f * (tempData.getZ() + 0.01f)) + + 509 * (unsigned int)(521.0f * (tempData.getY() + 0.01f)) + + (509 * 521) * (unsigned int)(523.0f * (tempData.getX() + 0.01f)); + // avalanch the bits + key += ~(key << 15); + key ^= (key >> 10); + key += (key << 3); + key ^= (key >> 6); + key += ~(key << 11); + key ^= (key >> 16); + } + // finally XOR with type + return (int)(key ^ _type); + } + +private: + friend class ShapeManager; + virtual btCollisionShape* createShape() const { - const float MAX_SHAPE_DIMENSION = 100.0f; - const float MIN_SHAPE_DIMENSION = 0.01f; - for (int i = 0; i < 3; ++i) { - float side = _size[i]; - if (side > MAX_SHAPE_DIMENSION || side < MIN_SHAPE_DIMENSION) { - return NULL; + btCollisionShape* shape = NULL; + int numData = _data.size(); + switch(_type) { + case BOX_SHAPE_PROXYTYPE: + { + if (numData > 0) { + btVector3 halfExtents = _data[0]; + shape = new btBoxShape(halfExtents); + } } + break; + case SPHERE_SHAPE_PROXYTYPE: + { + if (numData > 0) { + float radius = _data[0].getZ(); + shape = new btSphereShape(radius); + } + } + break; + case CYLINDER_SHAPE_PROXYTYPE: + { + if (numData > 0) { + btVector3 halfExtents = _data[0]; + // NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X + // halfExtents = btVector3(radius, halfHeight, unused) + shape = new btCylinderShape(halfExtents); + } + } + break; + case CAPSULE_SHAPE_PROXYTYPE: + { + if (numData > 0) { + float radius = _data[0].getX(); + float height = 2.0f * _data[0].getY(); + shape = new btCapsuleShape(radius, height); + } + } + break; } - // default behavior is to create a btBoxShape - return new btBoxShape(0.5f * _size); + return shape; } }; - -struct ShapeReference { - int _refCount; - btCollisionShape* _shape; - ShapeReference() : _refCount(0), _shape(NULL) {} -}; +*/ class ShapeManager { public: @@ -71,6 +189,7 @@ public: /// \return true if shape was found and released bool releaseShape(const ShapeInfo& info); +// bool removeReference(const btCollisionShape*); /// delete shapes that have zero references void collectGarbage(); @@ -80,6 +199,12 @@ public: int getNumReferences(const ShapeInfo& info) const; private: + struct ShapeReference { + int _refCount; + btCollisionShape* _shape; + ShapeReference() : _refCount(0), _shape(NULL) {} + }; + btHashMap _shapeMap; btAlignedObjectArray _pendingGarbage; }; diff --git a/tests/physics/CMakeLists.txt b/tests/physics/CMakeLists.txt index d47b979459..a7f54eab93 100644 --- a/tests/physics/CMakeLists.txt +++ b/tests/physics/CMakeLists.txt @@ -3,8 +3,8 @@ set(TARGET_NAME physics-tests) setup_hifi_project() include_glm() +include_bullet() -# link in the shared libraries link_hifi_libraries(shared physics) link_shared_dependencies() diff --git a/tests/physics/src/main.cpp b/tests/physics/src/main.cpp index 086bff4dcd..0e25f0f48c 100644 --- a/tests/physics/src/main.cpp +++ b/tests/physics/src/main.cpp @@ -10,9 +10,11 @@ #include "ShapeColliderTests.h" #include "VerletShapeTests.h" +#include "ShapeManagerTests.h" int main(int argc, char** argv) { - ShapeColliderTests::runAllTests(); - VerletShapeTests::runAllTests(); + //ShapeColliderTests::runAllTests(); + //VerletShapeTests::runAllTests(); + ShapeManagerTests::runAllTests(); return 0; } From b1b6188bb8edb65e9fc7c0b78cbdd50e54d3c07e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 3 Nov 2014 14:01:19 -0800 Subject: [PATCH 006/105] ShapeManager has improved HashMap --- libraries/physics/src/ShapeInfo.cpp | 110 ++++++++++------ libraries/physics/src/ShapeInfo.h | 148 +--------------------- libraries/physics/src/ShapeManager.cpp | 14 +-- libraries/physics/src/ShapeManager.h | 167 +++---------------------- 4 files changed, 101 insertions(+), 338 deletions(-) diff --git a/libraries/physics/src/ShapeInfo.cpp b/libraries/physics/src/ShapeInfo.cpp index 03dc162f6b..3d2b8c0f81 100644 --- a/libraries/physics/src/ShapeInfo.cpp +++ b/libraries/physics/src/ShapeInfo.cpp @@ -15,7 +15,20 @@ #include "ShapeInfo.h" -void ShapeInfo::getInfo(const btCollisionShape* shape) { +// prime numbers larger than 1e6 +const int NUM_PRIMES = 64; +const unsigned int PRIMES[] = { + 4194301U, 4194287U, 4194277U, 4194271U, 4194247U, 4194217U, 4194199U, 4194191U, + 4194187U, 4194181U, 4194173U, 4194167U, 4194143U, 4194137U, 4194131U, 4194107U, + 4194103U, 4194023U, 4194011U, 4194007U, 4193977U, 4193971U, 4193963U, 4193957U, + 4193939U, 4193929U, 4193909U, 4193869U, 4193807U, 4193803U, 4193801U, 4193789U, + 4193759U, 4193753U, 4193743U, 4193701U, 4193663U, 4193633U, 4193573U, 4193569U, + 4193551U, 4193549U, 4193531U, 4193513U, 4193507U, 4193459U, 4193447U, 4193443U, + 4193417U, 4193411U, 4193393U, 4193389U, 4193381U, 4193377U, 4193369U, 4193359U, + 4193353U, 4193327U, 4193309U, 4193303U, 4193297U, 4193279U, 4193269U, 4193263U +}; + +void ShapeInfo::collectInfo(const btCollisionShape* shape) { _data.clear(); if (shape) { _type = (unsigned int)(shape->getShapeType()); @@ -80,61 +93,87 @@ void ShapeInfo::setCapsule(float radius, float height) { _data.push_back(btVector3(radius, 0.5f * height, 0.0f)); } +unsigned int ShapeInfo::hashFunction(unsigned int value, int primeIndex) { + unsigned int hash = PRIMES[primeIndex % NUM_PRIMES] * (value + 1U); + hash += ~(hash << 15); + hash ^= (hash >> 10); + hash += (hash << 3); + hash ^= (hash >> 6); + hash += ~(hash << 11); + return hash ^ (hash >> 16); +} + +unsigned int ShapeInfo::hashFunction2(unsigned int value) { + unsigned hash = 0x811c9dc5U; + for (int i = 0; i < 4; i++ ) { + unsigned int byte = (value << (i * 8)) >> (24 - i * 8); + hash = ( hash ^ byte ) * 0x01000193U; + } + return hash; +} + +const float MILLIMETERS_PER_METER = 1000.0f; + int ShapeInfo::computeHash() const { - // This hash algorithm works well for shapes that have dimensions less than about 256m. - // At larger values the likelihood of hash collision goes up because of the most - // significant bits are pushed off the top and the result could be the same as for smaller - // dimensions (truncation). - // - // The algorithm may produce collisions for shapes whose dimensions differ by less than - // ~1/256 m, however this is by design -- we don't expect collision differences smaller - // than 1 mm to be noticable. - unsigned int key = 0; - btVector3 tempData; + // scramble the bits of the type + // TODO?: provide lookup table for hash of _type? + int primeIndex = 0; + unsigned int hash = ShapeInfo::hashFunction((unsigned int)_type, primeIndex++); + + btVector3 tmpData; int numData = _data.size(); for (int i = 0; i < numData; ++i) { - // Successively multiply components of each vec3 by primes near 512 and convert to U32 - // to spread the data across more bits. Note that all dimensions are at half-value - // (half extents, radius, etc) which is why we multiply by primes near 512 rather - // than 256. - tempData = _data[i]; - key += (unsigned int)(509.0f * (tempData.getZ() + 0.01f)) - + 509 * (unsigned int)(521.0f * (tempData.getY() + 0.01f)) - + (509 * 521) * (unsigned int)(523.0f * (tempData.getX() + 0.01f)); - // avalanch the bits - key += ~(key << 15); - key ^= (key >> 10); - key += (key << 3); - key ^= (key >> 6); - key += ~(key << 11); - key ^= (key >> 16); + tmpData = _data[i]; + for (int j = 0; j < 3; ++j) { + // multiply these mm by a new prime + unsigned int floatHash = ShapeInfo::hashFunction((unsigned int)(tmpData[j] * MILLIMETERS_PER_METER + 0.49f), primeIndex++); + hash ^= floatHash; + } } - // finally XOR with type - return (int)(key ^ _type); + return hash; +} + +int ShapeInfo::computeHash2() const { + // scramble the bits of the type + // TODO?: provide lookup table for hash of _type? + unsigned int hash = ShapeInfo::hashFunction2((unsigned int)_type); + + btVector3 tmpData; + int numData = _data.size(); + for (int i = 0; i < numData; ++i) { + tmpData = _data[i]; + for (int j = 0; j < 3; ++j) { + unsigned int floatHash = ShapeInfo::hashFunction2((unsigned int)(tmpData[j] * MILLIMETERS_PER_METER + 0.49f)); + hash += ~(floatHash << 17); + hash ^= (floatHash >> 11); + hash += (floatHash << 4); + hash ^= (floatHash >> 7); + hash += ~(floatHash << 10); + hash = (hash << 16) | (hash >> 16); + } + } + return hash; } btCollisionShape* ShapeInfo::createShape() const { btCollisionShape* shape = NULL; int numData = _data.size(); switch(_type) { - case BOX_SHAPE_PROXYTYPE: - { + case BOX_SHAPE_PROXYTYPE: { if (numData > 0) { btVector3 halfExtents = _data[0]; shape = new btBoxShape(halfExtents); } } break; - case SPHERE_SHAPE_PROXYTYPE: - { + case SPHERE_SHAPE_PROXYTYPE: { if (numData > 0) { float radius = _data[0].getZ(); shape = new btSphereShape(radius); } } break; - case CYLINDER_SHAPE_PROXYTYPE: - { + case CYLINDER_SHAPE_PROXYTYPE: { if (numData > 0) { btVector3 halfExtents = _data[0]; // NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X @@ -143,8 +182,7 @@ btCollisionShape* ShapeInfo::createShape() const { } } break; - case CAPSULE_SHAPE_PROXYTYPE: - { + case CAPSULE_SHAPE_PROXYTYPE: { if (numData > 0) { float radius = _data[0].getX(); float height = 2.0f * _data[0].getY(); diff --git a/libraries/physics/src/ShapeInfo.h b/libraries/physics/src/ShapeInfo.h index 86063694ca..50f7be7275 100644 --- a/libraries/physics/src/ShapeInfo.h +++ b/libraries/physics/src/ShapeInfo.h @@ -17,167 +17,31 @@ #include #include -const float DEFAULT_MARGIN = 0.04f; - class ShapeInfo { public: ShapeInfo() : _type(INVALID_SHAPE_PROXYTYPE) {} ShapeInfo(const btCollisionShape* shape) : _type(INVALID_SHAPE_PROXYTYPE) { - getInfo(shape); + collectInfo(shape); } - // BOOKMARK -- move ShapeInfo to its own files - void getInfo(const btCollisionShape* shape); - /*{ - _data.clear(); - if (shape) { - _type = (unsigned int)(shape->getShapeType()); - switch(_type) { - case BOX_SHAPE_PROXYTYPE: - { - const btBoxShape* boxShape = static_cast(shape); - _data.push_back(boxShape->getHalfExtentsWithMargin()); - } - break; - case SPHERE_SHAPE_PROXYTYPE: - { - const btSphereShape* sphereShape = static_cast(shape); - _data.push_back(btVector3(0.0f, 0.0f, sphereShape->getRadius())); - } - break; - case CYLINDER_SHAPE_PROXYTYPE: - { - const btCylinderShape* cylinderShape = static_cast(shape); - _data.push_back(cylinderShape->getHalfExtentsWithMargin()); - } - break; - case CAPSULE_SHAPE_PROXYTYPE: - { - const btCapsuleShape* capsuleShape = static_cast(shape); - _data.push_back(btVector3(capsuleShape->getRadius(), capsuleShape->getHalfHeight(), 0.0f)); - // NOTE: we only support capsules with axis along yAxis - } - break; - default: - _type = INVALID_SHAPE_PROXYTYPE; - break; - } - } else { - _type = INVALID_SHAPE_PROXYTYPE; - } - }*/ + void collectInfo(const btCollisionShape* shape); void setBox(const btVector3& halfExtents); - /*{ - _type = BOX_SHAPE_PROXYTYPE; - _data.clear(); - _data.push_back(halfExtents); - }*/ - void setSphere(float radius); - /* { - _type = SPHERE_SHAPE_PROXYTYPE; - _data.clear(); - _data.push_back(btVector3(0.0f, 0.0f, radius)); - }*/ - void setCylinder(float radius, float height); - /*{ - _type = CYLINDER_SHAPE_PROXYTYPE; - _data.clear(); - // NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X - // halfExtents = btVector3(radius, halfHeight, unused) - _data.push_back(btVector3(radius, 0.5f * height, radius)); - }*/ - void setCapsule(float radius, float height); - /*{ - _type = CAPSULE_SHAPE_PROXYTYPE; - _data.clear(); - _data.push_back(btVector3(radius, 0.5f * height, 0.0f)); - }*/ int computeHash() const; - /*{ - // This hash algorithm works well for shapes that have dimensions less than about 256m. - // At larger values the likelihood of hash collision goes up because of the most - // significant bits are pushed off the top and the result could be the same as for smaller - // dimensions (truncation). - // - // The algorithm may produce collisions for shapes whose dimensions differ by less than - // ~1/256 m, however this is by design -- we don't expect collision differences smaller - // than 1 mm to be noticable. - unsigned int key = 0; - btVector3 tempData; - int numData = _data.size(); - for (int i = 0; i < numData; ++i) { - // Successively multiply components of each vec3 by primes near 512 and convert to U32 - // to spread the data across more bits. Note that all dimensions are at half-value - // (half extents, radius, etc) which is why we multiply by primes near 512 rather - // than 256. - tempData = _data[i]; - key += (unsigned int)(509.0f * (tempData.getZ() + 0.01f)) - + 509 * (unsigned int)(521.0f * (tempData.getY() + 0.01f)) - + (509 * 521) * (unsigned int)(523.0f * (tempData.getX() + 0.01f)); - // avalanch the bits - key += ~(key << 15); - key ^= (key >> 10); - key += (key << 3); - key ^= (key >> 6); - key += ~(key << 11); - key ^= (key >> 16); - } - // finally XOR with type - return (int)(key ^ _type); - }*/ + int computeHash2() const; + + static unsigned int hashFunction(unsigned int value, int primeIndex); + static unsigned int hashFunction2(unsigned int value); private: friend class ShapeManager; btCollisionShape* createShape() const; - /*{ - btCollisionShape* shape = NULL; - int numData = _data.size(); - switch(_type) { - case BOX_SHAPE_PROXYTYPE: - { - if (numData > 0) { - btVector3 halfExtents = _data[0]; - shape = new btBoxShape(halfExtents); - } - } - break; - case SPHERE_SHAPE_PROXYTYPE: - { - if (numData > 0) { - float radius = _data[0].getZ(); - shape = new btSphereShape(radius); - } - } - break; - case CYLINDER_SHAPE_PROXYTYPE: - { - if (numData > 0) { - btVector3 halfExtents = _data[0]; - // NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X - // halfExtents = btVector3(radius, halfHeight, unused) - shape = new btCylinderShape(halfExtents); - } - } - break; - case CAPSULE_SHAPE_PROXYTYPE: - { - if (numData > 0) { - float radius = _data[0].getX(); - float height = 2.0f * _data[0].getY(); - shape = new btCapsuleShape(radius, height); - } - } - break; - } - return shape; - }*/ int _type; btAlignedObjectArray _data; diff --git a/libraries/physics/src/ShapeManager.cpp b/libraries/physics/src/ShapeManager.cpp index 9874f24859..61f0ceabad 100644 --- a/libraries/physics/src/ShapeManager.cpp +++ b/libraries/physics/src/ShapeManager.cpp @@ -21,11 +21,12 @@ ShapeManager::~ShapeManager() { ShapeReference* shapeRef = _shapeMap.getAtIndex(i); delete shapeRef->_shape; } + _shapeMap.clear(); } btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { - int key = info.computeHash(); + ShapeKey key(info); ShapeReference* shapeRef = _shapeMap.find(key); if (shapeRef) { shapeRef->_refCount++; @@ -43,7 +44,7 @@ btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { } bool ShapeManager::releaseShape(const ShapeInfo& info) { - int key = info.computeHash(); + ShapeKey key(info); ShapeReference* shapeRef = _shapeMap.find(key); if (shapeRef) { if (shapeRef->_refCount > 0) { @@ -71,7 +72,7 @@ bool ShapeManager::releaseShape(const ShapeInfo& info) { bool ShapeManager::releaseShape(const btCollisionShape* shape) { // when the number of shapes is high it's probably cheaper to try to construct a ShapeInfo // and then compute the hash rather than walking the list in search of the pointer. - int key = info.computeHash(); + ShapeKey key(info); ShapeReference* shapeRef = _shapeMap.find(key); if (shapeRef) { if (shapeRef->_refCount > 0) { @@ -99,10 +100,9 @@ bool ShapeManager::releaseShape(const btCollisionShape* shape) { void ShapeManager::collectGarbage() { int numShapes = _pendingGarbage.size(); for (int i = 0; i < numShapes; ++i) { - int key = _pendingGarbage[i]; + ShapeKey& key = _pendingGarbage[i]; ShapeReference* shapeRef = _shapeMap.find(key); - assert(shapeRef != NULL); - if (shapeRef->_refCount == 0) { + if (shapeRef && shapeRef->_refCount == 0) { delete shapeRef->_shape; _shapeMap.remove(key); } @@ -111,7 +111,7 @@ void ShapeManager::collectGarbage() { } int ShapeManager::getNumReferences(const ShapeInfo& info) const { - int key = info.computeHash(); + ShapeKey key(info); const ShapeReference* shapeRef = _shapeMap.find(key); if (shapeRef) { return shapeRef->_refCount; diff --git a/libraries/physics/src/ShapeManager.h b/libraries/physics/src/ShapeManager.h index c683a041a3..6c497dd981 100644 --- a/libraries/physics/src/ShapeManager.h +++ b/libraries/physics/src/ShapeManager.h @@ -19,164 +19,25 @@ #include "ShapeInfo.h" -/* -struct ShapeInfo { - int _type; - btAlignedObjectArray _data; - //btVector3 _scale; - - ShapeInfo() : _type(INVALID_SHAPE_PROXYTYPE) {} - - ShapeInfo(const btCollisionShape* shape) : _type(INVALID_SHAPE_PROXYTYPE) { - getInfo(shape); +class ShapeKey +{ +public: + ShapeKey(const ShapeInfo& info) : _hash(0), _hash2(0) { + _hash = info.computeHash(); + _hash2 = info.computeHash2(); } - // BOOKMARK -- move ShapeInfo to its own files - void getInfo(const btCollisionShape* shape) { - _data.clear(); - if (shape) { - _type = (unsigned int)(shape->getShapeType()); - switch(_type) { - case BOX_SHAPE_PROXYTYPE: - { - const btBoxShape* boxShape = static_cast(shape); - _data.push_back(boxShape->getHalfExtentsWithMargin()); - } - break; - case SPHERE_SHAPE_PROXYTYPE: - { - const btSphereShape* sphereShape = static_cast(shape); - _data.push_back(btVector3(0.0f, 0.0f, sphereShape->getRadius())); - } - break; - case CYLINDER_SHAPE_PROXYTYPE: - { - const btCylinderShape* cylinderShape = static_cast(shape); - _data.push_back(cylinderShape->getHalfExtentsWithMargin()); - } - break; - case CAPSULE_SHAPE_PROXYTYPE: - { - const btCapsuleShape* capsuleShape = static_cast(shape); - _data.push_back(btVector3(capsuleShape->getRadius(), capsuleShape->getHalfHeight(), 0.0f)); - // NOTE: we only support capsules with axis along yAxis - } - break; - default: - _type = INVALID_SHAPE_PROXYTYPE; - break; - } - } else { - _type = INVALID_SHAPE_PROXYTYPE; - } + bool equals(const ShapeKey& other) const { + return _hash == other._hash && _hash2 == other._hash2; } - void setBox(const btVector3& halfExtents) { - _type = BOX_SHAPE_PROXYTYPE; - _data.clear(); - _data.push_back(halfExtents); - } - - void setSphere(float radius) { - _type = SPHERE_SHAPE_PROXYTYPE; - _data.clear(); - _data.push_back(btVector3(0.0f, 0.0f, radius)); - } - - void setCylinder(float radius, float height) { - _type = CYLINDER_SHAPE_PROXYTYPE; - _data.clear(); - // NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X - // halfExtents = btVector3(radius, halfHeight, unused) - _data.push_back(btVector3(radius, 0.5f * height, radius)); - } - - void setCapsule(float radius, float height) { - _type = CAPSULE_SHAPE_PROXYTYPE; - _data.clear(); - _data.push_back(btVector3(radius, 0.5f * height, 0.0f)); - } - - virtual int computeHash() const { - // This hash algorithm works well for shapes that have dimensions less than about 256m. - // At larger values the likelihood of hash collision goes up because of the most - // significant bits are pushed off the top and the result could be the same as for smaller - // dimensions (truncation). - // - // The algorithm may produce collisions for shapes whose dimensions differ by less than - // ~1/256 m, however this is by design -- we don't expect collision differences smaller - // than 1 mm to be noticable. - unsigned int key = 0; - btVector3 tempData; - int numData = _data.size(); - for (int i = 0; i < numData; ++i) { - // Successively multiply components of each vec3 by primes near 512 and convert to U32 - // to spread the data across more bits. Note that all dimensions are at half-value - // (half extents, radius, etc) which is why we multiply by primes near 512 rather - // than 256. - tempData = _data[i]; - key += (unsigned int)(509.0f * (tempData.getZ() + 0.01f)) - + 509 * (unsigned int)(521.0f * (tempData.getY() + 0.01f)) - + (509 * 521) * (unsigned int)(523.0f * (tempData.getX() + 0.01f)); - // avalanch the bits - key += ~(key << 15); - key ^= (key >> 10); - key += (key << 3); - key ^= (key >> 6); - key += ~(key << 11); - key ^= (key >> 16); - } - // finally XOR with type - return (int)(key ^ _type); - } + unsigned int getHash() const { return (unsigned int)_hash; } private: - friend class ShapeManager; - - virtual btCollisionShape* createShape() const { - btCollisionShape* shape = NULL; - int numData = _data.size(); - switch(_type) { - case BOX_SHAPE_PROXYTYPE: - { - if (numData > 0) { - btVector3 halfExtents = _data[0]; - shape = new btBoxShape(halfExtents); - } - } - break; - case SPHERE_SHAPE_PROXYTYPE: - { - if (numData > 0) { - float radius = _data[0].getZ(); - shape = new btSphereShape(radius); - } - } - break; - case CYLINDER_SHAPE_PROXYTYPE: - { - if (numData > 0) { - btVector3 halfExtents = _data[0]; - // NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X - // halfExtents = btVector3(radius, halfHeight, unused) - shape = new btCylinderShape(halfExtents); - } - } - break; - case CAPSULE_SHAPE_PROXYTYPE: - { - if (numData > 0) { - float radius = _data[0].getX(); - float height = 2.0f * _data[0].getY(); - shape = new btCapsuleShape(radius, height); - } - } - break; - } - return shape; - } + int _hash; + int _hash2; }; -*/ + class ShapeManager { public: @@ -205,8 +66,8 @@ private: ShapeReference() : _refCount(0), _shape(NULL) {} }; - btHashMap _shapeMap; - btAlignedObjectArray _pendingGarbage; + btHashMap _shapeMap; + btAlignedObjectArray _pendingGarbage; }; #endif // USE_BULLET_PHYSICS From aa0172cf8b3c02fe6ef02fbbd9504f76fcc1c20e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 3 Nov 2014 14:03:05 -0800 Subject: [PATCH 007/105] Unit tests for ShapeManager --- tests/physics/src/ShapeManagerTests.cpp | 395 ++++++++++++++++++++++++ tests/physics/src/ShapeManagerTests.h | 26 ++ 2 files changed, 421 insertions(+) create mode 100644 tests/physics/src/ShapeManagerTests.cpp create mode 100644 tests/physics/src/ShapeManagerTests.h diff --git a/tests/physics/src/ShapeManagerTests.cpp b/tests/physics/src/ShapeManagerTests.cpp new file mode 100644 index 0000000000..9dab84dd08 --- /dev/null +++ b/tests/physics/src/ShapeManagerTests.cpp @@ -0,0 +1,395 @@ +// +// ShapeManagerTests.cpp +// tests/physics/src +// +// Created by Andrew Meadows on 2014.10.30 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include +#include + +#include "ShapeManagerTests.h" + +void ShapeManagerTests::testHashFunctions() { +#ifdef USE_BULLET_PHYSICS + int maxTests = 10000000; + ShapeInfo info; + btHashMap hashes; + + int bits[32]; + unsigned int masks[32]; + for (int i = 0; i < 32; ++i) { + bits[i] = 0; + masks[i] = 1U << i; + } + + float deltaLength = 0.002f; + float endLength = 100.0f; + int numSteps = (int)(endLength / deltaLength); + + int testCount = 0; + int numCollisions = 0; + btClock timer; + for (int x = 1; x < numSteps && testCount < maxTests; ++x) { + float radiusX = (float)x * deltaLength; + // test sphere + info.setSphere(radiusX); + ++testCount; + int hash = info.computeHash(); + int hash2 = info.computeHash2(); + int* hashPtr = hashes.find(hash); + if (hashPtr && *hashPtr == hash2) { + std::cout << testCount << " hash collision radiusX = " << radiusX + << " h1 = 0x" << std::hex << (unsigned int)(hash) + << " h2 = 0x" << std::hex << (unsigned int)(hash2) + << std::endl; + ++numCollisions; + assert(false); + } else { + hashes.insert(hash, hash2); + } + for (int k = 0; k < 32; ++k) { + if (masks[k] & hash2) { + ++bits[k]; + } + } + + for (int y = 1; y < numSteps && testCount < maxTests; ++y) { + float radiusY = (float)y * deltaLength; + // test cylinder and capsule + int types[] = { CYLINDER_SHAPE_PROXYTYPE, CAPSULE_SHAPE_PROXYTYPE }; + for (int i = 0; i < 2; ++i) { + switch(types[i]) { + case CYLINDER_SHAPE_PROXYTYPE: { + info.setCylinder(radiusX, radiusY); + break; + } + case CAPSULE_SHAPE_PROXYTYPE: { + info.setCapsule(radiusX, radiusY); + break; + } + } + + ++testCount; + hash = info.computeHash(); + hash2 = info.computeHash2(); + hashPtr = hashes.find(hash); + if (hashPtr && *hashPtr == hash2) { + std::cout << testCount << " hash collision radiusX = " << radiusX << " radiusY = " << radiusY + << " h1 = 0x" << std::hex << (unsigned int)(hash) + << " h2 = 0x" << std::hex << (unsigned int)(hash2) + << std::endl; + ++numCollisions; + assert(false); + } else { + hashes.insert(hash, hash2); + } + for (int k = 0; k < 32; ++k) { + if (masks[k] & hash2) { + ++bits[k]; + } + } + } + + for (int z = 1; z < numSteps && testCount < maxTests; ++z) { + float radiusZ = (float)z * deltaLength; + // test box + info.setBox(btVector3(radiusX, radiusY, radiusZ)); + ++testCount; + hash = info.computeHash(); + hash2 = info.computeHash2(); + hashPtr = hashes.find(hash); + if (hashPtr && *hashPtr == hash2) { + std::cout << testCount << " hash collision radiusX = " << radiusX + << " radiusY = " << radiusY << " radiusZ = " << radiusZ + << " h1 = 0x" << std::hex << (unsigned int)(hash) + << " h2 = 0x" << std::hex << (unsigned int)(hash2) + << std::endl; + ++numCollisions; + assert(false); + } else { + hashes.insert(hash, hash2); + } + for (int k = 0; k < 32; ++k) { + if (masks[k] & hash2) { + ++bits[k]; + } + } + } + } + } + unsigned long int msec = timer.getTimeMilliseconds(); + std::cout << msec << " msec with " << numCollisions << " collisions out of " << testCount << " hashes" << std::endl; + + // print out distribution of bits + for (int i = 0; i < 32; ++i) { + std::cout << "bit 0x" << std::hex << masks[i] << std::dec << " = " << bits[i] << std::endl; + } +#endif // USE_BULLET_PHYSICS +} + +void ShapeManagerTests::testShapeAccounting() { +#ifdef USE_BULLET_PHYSICS + ShapeManager shapeManager; + ShapeInfo info; + info.setBox(btVector3(1.0f, 1.0f, 1.0f)); + + // NOTE: ShapeManager returns -1 as refcount when the shape is unknown, + // which is distinct from "known but with zero references" + int numReferences = shapeManager.getNumReferences(info); + if (numReferences != -1) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: expected ignorant ShapeManager after initialization" << std::endl; + } + + // create one shape and verify we get a valid pointer + btCollisionShape* shape = shapeManager.getShape(info); + if (!shape) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: expected shape creation for default parameters" << std::endl; + } + + // verify number of shapes + if (shapeManager.getNumShapes() != 1) { + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: expected one shape" << std::endl; + } + + // reference the shape again and verify that we get the same pointer + btCollisionShape* otherShape = shapeManager.getShape(info); + if (otherShape != shape) { + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: expected shape* " << (void*)(shape) + << " but found shape* " << (void*)(otherShape) << std::endl; + } + + // verify number of references + numReferences = shapeManager.getNumReferences(info); + int expectedNumReferences = 2; + if (numReferences != expectedNumReferences) { + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: expected " << expectedNumReferences + << " references but found " << numReferences << std::endl; + } + + // release all references + bool released = shapeManager.releaseShape(info); + numReferences--; + while (numReferences > 0) { + released = shapeManager.releaseShape(info) && released; + numReferences--; + } + if (!released) { + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: expected shape released" << std::endl; + } + + // verify shape still exists (not yet garbage collected) + if (shapeManager.getNumShapes() != 1) { + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: expected one shape after release but before garbage collection" << std::endl; + } + + // verify shape's refcount is zero + numReferences = shapeManager.getNumReferences(info); + if (numReferences != 0) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: expected refcount = 0 for shape but found refcount = " << numReferences << std::endl; + } + + // reference the shape again and verify refcount is updated + otherShape = shapeManager.getShape(info); + numReferences = shapeManager.getNumReferences(info); + if (numReferences != 1) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: expected refcount = 1 for shape but found refcount = " << numReferences << std::endl; + } + + // verify that shape is not collected as garbage + shapeManager.collectGarbage(); + if (shapeManager.getNumShapes() != 1) { + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: expected one shape after release" << std::endl; + } + numReferences = shapeManager.getNumReferences(info); + if (numReferences != 1) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: expected refcount = 1 for shape but found refcount = " << numReferences << std::endl; + } + + // release reference and verify that it is collected as garbage + released = shapeManager.releaseShape(info); + shapeManager.collectGarbage(); + if (shapeManager.getNumShapes() != 0) { + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: expected zero shapes after release" << std::endl; + } + numReferences = shapeManager.getNumReferences(info); + if (numReferences != -1) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: expected ignorant ShapeManager after garbage collection" << std::endl; + } + + // add the shape again and verify that it gets added again + otherShape = shapeManager.getShape(info); + numReferences = shapeManager.getNumReferences(info); + if (numReferences != 1) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: expected refcount = 1 for shape but found refcount = " << numReferences << std::endl; + } +#endif // USE_BULLET_PHYSICS +} + +void ShapeManagerTests::addManyShapes() { +#ifdef USE_BULLET_PHYSICS + ShapeManager shapeManager; + + int numSizes = 100; + float startSize = 1.0f; + float endSize = 99.0f; + float deltaSize = (endSize - startSize) / (float)numSizes; + ShapeInfo info; + for (int i = 0; i < numSizes; ++i) { + float s = startSize + (float)i * deltaSize; + btVector3 scale(s, 1.23f + s, s - 0.573f); + info.setBox(0.5f * scale); + btCollisionShape* shape = shapeManager.getShape(info); + if (!shape) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: i = " << i << " null box shape for scale = " << scale << std::endl; + } + info.setSphere(s); + shape = shapeManager.getShape(info); + if (!shape) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: i = " << i << " null sphere shape for radius = " << s << std::endl; + } + } + int numShapes = shapeManager.getNumShapes(); + if (numShapes != 2 * numSizes) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: expected numShapes = " << numSizes << " but found numShapes = " << numShapes << std::endl; + } +#endif // USE_BULLET_PHYSICS +} + +void ShapeManagerTests::testBoxShape() { +#ifdef USE_BULLET_PHYSICS + ShapeInfo info; + btVector3 halfExtents(1.23f, 4.56f, 7.89f); + info.setBox(halfExtents); + int hash = info.computeHash(); + + ShapeManager shapeManager; + btCollisionShape* shape = shapeManager.getShape(info); + + ShapeInfo otherInfo; + otherInfo.collectInfo(shape); + int otherHash = otherInfo.computeHash(); + + if (hash != otherHash) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: expected Box shape hash = " << hash << " but found hash = " << otherHash << std::endl; + } + + btCollisionShape* otherShape = shapeManager.getShape(info); + if (shape != otherShape) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: Box ShapeInfo --> shape --> ShapeInfo --> shape did not work" << std::endl; + } +#endif // USE_BULLET_PHYSICS +} + +void ShapeManagerTests::testSphereShape() { +#ifdef USE_BULLET_PHYSICS + ShapeInfo info; + float radius = 1.23f; + info.setSphere(radius); + int hash = info.computeHash(); + + ShapeManager shapeManager; + btCollisionShape* shape = shapeManager.getShape(info); + + ShapeInfo otherInfo; + otherInfo.collectInfo(shape); + int otherHash = otherInfo.computeHash(); + + if (hash != otherHash) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: expected Sphere shape hash = " << hash << " but found hash = " << otherHash << std::endl; + } + + btCollisionShape* otherShape = shapeManager.getShape(info); + if (shape != otherShape) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: Sphere ShapeInfo --> shape --> ShapeInfo --> shape did not work" << std::endl; + } +#endif // USE_BULLET_PHYSICS +} + +void ShapeManagerTests::testCylinderShape() { +#ifdef USE_BULLET_PHYSICS + ShapeInfo info; + float radius = 1.23f; + float height = 4.56f; + info.setCylinder(radius, height); + int hash = info.computeHash(); + + ShapeManager shapeManager; + btCollisionShape* shape = shapeManager.getShape(info); + + ShapeInfo otherInfo; + otherInfo.collectInfo(shape); + int otherHash = otherInfo.computeHash(); + + if (hash != otherHash) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: expected Cylinder shape hash = " << hash << " but found hash = " << otherHash << std::endl; + } + + btCollisionShape* otherShape = shapeManager.getShape(info); + if (shape != otherShape) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: Cylinder ShapeInfo --> shape --> ShapeInfo --> shape did not work" << std::endl; + } +#endif // USE_BULLET_PHYSICS +} + +void ShapeManagerTests::testCapsuleShape() { +#ifdef USE_BULLET_PHYSICS + ShapeInfo info; + float radius = 1.23f; + float height = 4.56f; + info.setCapsule(radius, height); + int hash = info.computeHash(); + + ShapeManager shapeManager; + btCollisionShape* shape = shapeManager.getShape(info); + + ShapeInfo otherInfo; + otherInfo.collectInfo(shape); + int otherHash = otherInfo.computeHash(); + + if (hash != otherHash) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: expected Capsule shape hash = " << hash << " but found hash = " << otherHash << std::endl; + } + + btCollisionShape* otherShape = shapeManager.getShape(info); + if (shape != otherShape) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: Capsule ShapeInfo --> shape --> ShapeInfo --> shape did not work" << std::endl; + } +#endif // USE_BULLET_PHYSICS +} + +void ShapeManagerTests::runAllTests() { +//#define MANUAL_TEST +#ifdef MANUAL_TEST + testHashFunctions(); +#endif // MANUAL_TEST + testShapeAccounting(); + addManyShapes(); + testBoxShape(); + testSphereShape(); + testCylinderShape(); + testCapsuleShape(); +} diff --git a/tests/physics/src/ShapeManagerTests.h b/tests/physics/src/ShapeManagerTests.h new file mode 100644 index 0000000000..3cbae8cffb --- /dev/null +++ b/tests/physics/src/ShapeManagerTests.h @@ -0,0 +1,26 @@ +// +// ShapeManagerTests.h +// tests/physics/src +// +// Created by Andrew Meadows on 2014.10.30 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ShapeManagerTests_h +#define hifi_ShapeManagerTests_h + +namespace ShapeManagerTests { + void testHashFunctions(); + void testShapeAccounting(); + void addManyShapes(); + void testBoxShape(); + void testSphereShape(); + void testCylinderShape(); + void testCapsuleShape(); + void runAllTests(); +} + +#endif // hifi_VerletShapeTests_h From 4a1133fbc2484663e72e5da72a659ce67bafd977 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 3 Nov 2014 15:25:04 -0800 Subject: [PATCH 008/105] moved ShapeInfo tests to their own file --- libraries/physics/src/ShapeInfo.h | 4 +- tests/physics/src/ShapeInfoTests.cpp | 266 ++++++++++++++++++++++++ tests/physics/src/ShapeInfoTests.h | 24 +++ tests/physics/src/ShapeManagerTests.cpp | 174 ++-------------- tests/physics/src/ShapeManagerTests.h | 11 +- tests/physics/src/main.cpp | 6 +- 6 files changed, 312 insertions(+), 173 deletions(-) create mode 100644 tests/physics/src/ShapeInfoTests.cpp create mode 100644 tests/physics/src/ShapeInfoTests.h diff --git a/libraries/physics/src/ShapeInfo.h b/libraries/physics/src/ShapeInfo.h index 50f7be7275..d5d70d7b56 100644 --- a/libraries/physics/src/ShapeInfo.h +++ b/libraries/physics/src/ShapeInfo.h @@ -38,11 +38,9 @@ public: static unsigned int hashFunction(unsigned int value, int primeIndex); static unsigned int hashFunction2(unsigned int value); -private: - friend class ShapeManager; - btCollisionShape* createShape() const; +private: int _type; btAlignedObjectArray _data; }; diff --git a/tests/physics/src/ShapeInfoTests.cpp b/tests/physics/src/ShapeInfoTests.cpp new file mode 100644 index 0000000000..5ce74888fc --- /dev/null +++ b/tests/physics/src/ShapeInfoTests.cpp @@ -0,0 +1,266 @@ +// +// ShapeInfoTests.cpp +// tests/physics/src +// +// Created by Andrew Meadows on 2014.11.02 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include +#include + +#include "ShapeInfoTests.h" + +void ShapeInfoTests::testHashFunctions() { +#ifdef USE_BULLET_PHYSICS + int maxTests = 10000000; + ShapeInfo info; + btHashMap hashes; + + int bits[32]; + unsigned int masks[32]; + for (int i = 0; i < 32; ++i) { + bits[i] = 0; + masks[i] = 1U << i; + } + + float deltaLength = 0.002f; + float endLength = 100.0f; + int numSteps = (int)(endLength / deltaLength); + + int testCount = 0; + int numCollisions = 0; + btClock timer; + for (int x = 1; x < numSteps && testCount < maxTests; ++x) { + float radiusX = (float)x * deltaLength; + // test sphere + info.setSphere(radiusX); + ++testCount; + int hash = info.computeHash(); + int hash2 = info.computeHash2(); + int* hashPtr = hashes.find(hash); + if (hashPtr && *hashPtr == hash2) { + std::cout << testCount << " hash collision radiusX = " << radiusX + << " h1 = 0x" << std::hex << (unsigned int)(hash) + << " h2 = 0x" << std::hex << (unsigned int)(hash2) + << std::endl; + ++numCollisions; + assert(false); + } else { + hashes.insert(hash, hash2); + } + for (int k = 0; k < 32; ++k) { + if (masks[k] & hash2) { + ++bits[k]; + } + } + + for (int y = 1; y < numSteps && testCount < maxTests; ++y) { + float radiusY = (float)y * deltaLength; + // test cylinder and capsule + int types[] = { CYLINDER_SHAPE_PROXYTYPE, CAPSULE_SHAPE_PROXYTYPE }; + for (int i = 0; i < 2; ++i) { + switch(types[i]) { + case CYLINDER_SHAPE_PROXYTYPE: { + info.setCylinder(radiusX, radiusY); + break; + } + case CAPSULE_SHAPE_PROXYTYPE: { + info.setCapsule(radiusX, radiusY); + break; + } + } + + ++testCount; + hash = info.computeHash(); + hash2 = info.computeHash2(); + hashPtr = hashes.find(hash); + if (hashPtr && *hashPtr == hash2) { + std::cout << testCount << " hash collision radiusX = " << radiusX << " radiusY = " << radiusY + << " h1 = 0x" << std::hex << (unsigned int)(hash) + << " h2 = 0x" << std::hex << (unsigned int)(hash2) + << std::endl; + ++numCollisions; + assert(false); + } else { + hashes.insert(hash, hash2); + } + for (int k = 0; k < 32; ++k) { + if (masks[k] & hash2) { + ++bits[k]; + } + } + } + + for (int z = 1; z < numSteps && testCount < maxTests; ++z) { + float radiusZ = (float)z * deltaLength; + // test box + info.setBox(btVector3(radiusX, radiusY, radiusZ)); + ++testCount; + hash = info.computeHash(); + hash2 = info.computeHash2(); + hashPtr = hashes.find(hash); + if (hashPtr && *hashPtr == hash2) { + std::cout << testCount << " hash collision radiusX = " << radiusX + << " radiusY = " << radiusY << " radiusZ = " << radiusZ + << " h1 = 0x" << std::hex << (unsigned int)(hash) + << " h2 = 0x" << std::hex << (unsigned int)(hash2) + << std::endl; + ++numCollisions; + assert(false); + } else { + hashes.insert(hash, hash2); + } + for (int k = 0; k < 32; ++k) { + if (masks[k] & hash2) { + ++bits[k]; + } + } + } + } + } + unsigned long int msec = timer.getTimeMilliseconds(); + std::cout << msec << " msec with " << numCollisions << " collisions out of " << testCount << " hashes" << std::endl; + + // print out distribution of bits + for (int i = 0; i < 32; ++i) { + std::cout << "bit 0x" << std::hex << masks[i] << std::dec << " = " << bits[i] << std::endl; + } +#endif // USE_BULLET_PHYSICS +} + +void ShapeInfoTests::testBoxShape() { +#ifdef USE_BULLET_PHYSICS + ShapeInfo info; + btVector3 halfExtents(1.23f, 4.56f, 7.89f); + info.setBox(halfExtents); + int hash = info.computeHash(); + int hash2 = info.computeHash2(); + + btCollisionShape* shape = info.createShape(); + if (!shape) { + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: NULL Box shape" << std::endl; + } + + ShapeInfo otherInfo; + otherInfo.collectInfo(shape); + + int otherHash = otherInfo.computeHash(); + if (hash != otherHash) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: expected Box shape hash = " << hash << " but found hash = " << otherHash << std::endl; + } + + int otherHash2= otherInfo.computeHash2(); + if (hash2 != otherHash2) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: expected Box shape hash2 = " << hash2 << " but found hash2 = " << otherHash2 << std::endl; + } + + delete shape; +#endif // USE_BULLET_PHYSICS +} + +void ShapeInfoTests::testSphereShape() { +#ifdef USE_BULLET_PHYSICS + ShapeInfo info; + float radius = 1.23f; + info.setSphere(radius); + int hash = info.computeHash(); + int hash2 = info.computeHash2(); + + btCollisionShape* shape = info.createShape(); + + ShapeInfo otherInfo; + otherInfo.collectInfo(shape); + + int otherHash = otherInfo.computeHash(); + if (hash != otherHash) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: expected Sphere shape hash = " << hash << " but found hash = " << otherHash << std::endl; + } + + int otherHash2 = otherInfo.computeHash2(); + if (hash2 != otherHash2) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: expected Sphere shape hash2 = " << hash2 << " but found hash2 = " << otherHash2 << std::endl; + } + + delete shape; +#endif // USE_BULLET_PHYSICS +} + +void ShapeInfoTests::testCylinderShape() { +#ifdef USE_BULLET_PHYSICS + ShapeInfo info; + float radius = 1.23f; + float height = 4.56f; + info.setCylinder(radius, height); + int hash = info.computeHash(); + int hash2 = info.computeHash2(); + + btCollisionShape* shape = info.createShape(); + + ShapeInfo otherInfo; + otherInfo.collectInfo(shape); + + int otherHash = otherInfo.computeHash(); + if (hash != otherHash) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: expected Cylinder shape hash = " << hash << " but found hash = " << otherHash << std::endl; + } + + int otherHash2 = otherInfo.computeHash2(); + if (hash2 != otherHash2) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: expected Cylinder shape hash2 = " << hash2 << " but found hash2 = " << otherHash2 << std::endl; + } + + delete shape; +#endif // USE_BULLET_PHYSICS +} + +void ShapeInfoTests::testCapsuleShape() { +#ifdef USE_BULLET_PHYSICS + ShapeInfo info; + float radius = 1.23f; + float height = 4.56f; + info.setCapsule(radius, height); + int hash = info.computeHash(); + int hash2 = info.computeHash2(); + + btCollisionShape* shape = info.createShape(); + + ShapeInfo otherInfo; + otherInfo.collectInfo(shape); + + int otherHash = otherInfo.computeHash(); + if (hash != otherHash) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: expected Capsule shape hash = " << hash << " but found hash = " << otherHash << std::endl; + } + + int otherHash2 = otherInfo.computeHash2(); + if (hash2 != otherHash2) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: expected Capsule shape hash2 = " << hash2 << " but found hash2 = " << otherHash2 << std::endl; + } + + delete shape; +#endif // USE_BULLET_PHYSICS +} + +void ShapeInfoTests::runAllTests() { +//#define MANUAL_TEST +#ifdef MANUAL_TEST + testHashFunctions(); +#endif // MANUAL_TEST + testBoxShape(); + testSphereShape(); + testCylinderShape(); + testCapsuleShape(); +} diff --git a/tests/physics/src/ShapeInfoTests.h b/tests/physics/src/ShapeInfoTests.h new file mode 100644 index 0000000000..b786ca92d5 --- /dev/null +++ b/tests/physics/src/ShapeInfoTests.h @@ -0,0 +1,24 @@ +// +// ShapeInfoTests.h +// tests/physics/src +// +// Created by Andrew Meadows on 2014.11.02 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ShapeInfoTests_h +#define hifi_ShapeInfoTests_h + +namespace ShapeInfoTests { + void testHashFunctions(); + void testBoxShape(); + void testSphereShape(); + void testCylinderShape(); + void testCapsuleShape(); + void runAllTests(); +} + +#endif // hifi_ShapeInfoTests_h diff --git a/tests/physics/src/ShapeManagerTests.cpp b/tests/physics/src/ShapeManagerTests.cpp index 9dab84dd08..78ef45f107 100644 --- a/tests/physics/src/ShapeManagerTests.cpp +++ b/tests/physics/src/ShapeManagerTests.cpp @@ -15,124 +15,6 @@ #include "ShapeManagerTests.h" -void ShapeManagerTests::testHashFunctions() { -#ifdef USE_BULLET_PHYSICS - int maxTests = 10000000; - ShapeInfo info; - btHashMap hashes; - - int bits[32]; - unsigned int masks[32]; - for (int i = 0; i < 32; ++i) { - bits[i] = 0; - masks[i] = 1U << i; - } - - float deltaLength = 0.002f; - float endLength = 100.0f; - int numSteps = (int)(endLength / deltaLength); - - int testCount = 0; - int numCollisions = 0; - btClock timer; - for (int x = 1; x < numSteps && testCount < maxTests; ++x) { - float radiusX = (float)x * deltaLength; - // test sphere - info.setSphere(radiusX); - ++testCount; - int hash = info.computeHash(); - int hash2 = info.computeHash2(); - int* hashPtr = hashes.find(hash); - if (hashPtr && *hashPtr == hash2) { - std::cout << testCount << " hash collision radiusX = " << radiusX - << " h1 = 0x" << std::hex << (unsigned int)(hash) - << " h2 = 0x" << std::hex << (unsigned int)(hash2) - << std::endl; - ++numCollisions; - assert(false); - } else { - hashes.insert(hash, hash2); - } - for (int k = 0; k < 32; ++k) { - if (masks[k] & hash2) { - ++bits[k]; - } - } - - for (int y = 1; y < numSteps && testCount < maxTests; ++y) { - float radiusY = (float)y * deltaLength; - // test cylinder and capsule - int types[] = { CYLINDER_SHAPE_PROXYTYPE, CAPSULE_SHAPE_PROXYTYPE }; - for (int i = 0; i < 2; ++i) { - switch(types[i]) { - case CYLINDER_SHAPE_PROXYTYPE: { - info.setCylinder(radiusX, radiusY); - break; - } - case CAPSULE_SHAPE_PROXYTYPE: { - info.setCapsule(radiusX, radiusY); - break; - } - } - - ++testCount; - hash = info.computeHash(); - hash2 = info.computeHash2(); - hashPtr = hashes.find(hash); - if (hashPtr && *hashPtr == hash2) { - std::cout << testCount << " hash collision radiusX = " << radiusX << " radiusY = " << radiusY - << " h1 = 0x" << std::hex << (unsigned int)(hash) - << " h2 = 0x" << std::hex << (unsigned int)(hash2) - << std::endl; - ++numCollisions; - assert(false); - } else { - hashes.insert(hash, hash2); - } - for (int k = 0; k < 32; ++k) { - if (masks[k] & hash2) { - ++bits[k]; - } - } - } - - for (int z = 1; z < numSteps && testCount < maxTests; ++z) { - float radiusZ = (float)z * deltaLength; - // test box - info.setBox(btVector3(radiusX, radiusY, radiusZ)); - ++testCount; - hash = info.computeHash(); - hash2 = info.computeHash2(); - hashPtr = hashes.find(hash); - if (hashPtr && *hashPtr == hash2) { - std::cout << testCount << " hash collision radiusX = " << radiusX - << " radiusY = " << radiusY << " radiusZ = " << radiusZ - << " h1 = 0x" << std::hex << (unsigned int)(hash) - << " h2 = 0x" << std::hex << (unsigned int)(hash2) - << std::endl; - ++numCollisions; - assert(false); - } else { - hashes.insert(hash, hash2); - } - for (int k = 0; k < 32; ++k) { - if (masks[k] & hash2) { - ++bits[k]; - } - } - } - } - } - unsigned long int msec = timer.getTimeMilliseconds(); - std::cout << msec << " msec with " << numCollisions << " collisions out of " << testCount << " hashes" << std::endl; - - // print out distribution of bits - for (int i = 0; i < 32; ++i) { - std::cout << "bit 0x" << std::hex << masks[i] << std::dec << " = " << bits[i] << std::endl; - } -#endif // USE_BULLET_PHYSICS -} - void ShapeManagerTests::testShapeAccounting() { #ifdef USE_BULLET_PHYSICS ShapeManager shapeManager; @@ -271,26 +153,19 @@ void ShapeManagerTests::addManyShapes() { #endif // USE_BULLET_PHYSICS } -void ShapeManagerTests::testBoxShape() { +void ShapeManagerTests::addBoxShape() { #ifdef USE_BULLET_PHYSICS ShapeInfo info; btVector3 halfExtents(1.23f, 4.56f, 7.89f); info.setBox(halfExtents); - int hash = info.computeHash(); ShapeManager shapeManager; btCollisionShape* shape = shapeManager.getShape(info); ShapeInfo otherInfo; otherInfo.collectInfo(shape); - int otherHash = otherInfo.computeHash(); - if (hash != otherHash) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: expected Box shape hash = " << hash << " but found hash = " << otherHash << std::endl; - } - - btCollisionShape* otherShape = shapeManager.getShape(info); + btCollisionShape* otherShape = shapeManager.getShape(otherInfo); if (shape != otherShape) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: Box ShapeInfo --> shape --> ShapeInfo --> shape did not work" << std::endl; @@ -298,26 +173,19 @@ void ShapeManagerTests::testBoxShape() { #endif // USE_BULLET_PHYSICS } -void ShapeManagerTests::testSphereShape() { +void ShapeManagerTests::addSphereShape() { #ifdef USE_BULLET_PHYSICS ShapeInfo info; float radius = 1.23f; info.setSphere(radius); - int hash = info.computeHash(); ShapeManager shapeManager; btCollisionShape* shape = shapeManager.getShape(info); ShapeInfo otherInfo; otherInfo.collectInfo(shape); - int otherHash = otherInfo.computeHash(); - if (hash != otherHash) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: expected Sphere shape hash = " << hash << " but found hash = " << otherHash << std::endl; - } - - btCollisionShape* otherShape = shapeManager.getShape(info); + btCollisionShape* otherShape = shapeManager.getShape(otherInfo); if (shape != otherShape) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: Sphere ShapeInfo --> shape --> ShapeInfo --> shape did not work" << std::endl; @@ -325,27 +193,20 @@ void ShapeManagerTests::testSphereShape() { #endif // USE_BULLET_PHYSICS } -void ShapeManagerTests::testCylinderShape() { +void ShapeManagerTests::addCylinderShape() { #ifdef USE_BULLET_PHYSICS ShapeInfo info; float radius = 1.23f; float height = 4.56f; info.setCylinder(radius, height); - int hash = info.computeHash(); ShapeManager shapeManager; btCollisionShape* shape = shapeManager.getShape(info); ShapeInfo otherInfo; otherInfo.collectInfo(shape); - int otherHash = otherInfo.computeHash(); - if (hash != otherHash) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: expected Cylinder shape hash = " << hash << " but found hash = " << otherHash << std::endl; - } - - btCollisionShape* otherShape = shapeManager.getShape(info); + btCollisionShape* otherShape = shapeManager.getShape(otherInfo); if (shape != otherShape) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: Cylinder ShapeInfo --> shape --> ShapeInfo --> shape did not work" << std::endl; @@ -353,27 +214,20 @@ void ShapeManagerTests::testCylinderShape() { #endif // USE_BULLET_PHYSICS } -void ShapeManagerTests::testCapsuleShape() { +void ShapeManagerTests::addCapsuleShape() { #ifdef USE_BULLET_PHYSICS ShapeInfo info; float radius = 1.23f; float height = 4.56f; info.setCapsule(radius, height); - int hash = info.computeHash(); ShapeManager shapeManager; btCollisionShape* shape = shapeManager.getShape(info); ShapeInfo otherInfo; otherInfo.collectInfo(shape); - int otherHash = otherInfo.computeHash(); - if (hash != otherHash) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: expected Capsule shape hash = " << hash << " but found hash = " << otherHash << std::endl; - } - - btCollisionShape* otherShape = shapeManager.getShape(info); + btCollisionShape* otherShape = shapeManager.getShape(otherInfo); if (shape != otherShape) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: Capsule ShapeInfo --> shape --> ShapeInfo --> shape did not work" << std::endl; @@ -382,14 +236,10 @@ void ShapeManagerTests::testCapsuleShape() { } void ShapeManagerTests::runAllTests() { -//#define MANUAL_TEST -#ifdef MANUAL_TEST - testHashFunctions(); -#endif // MANUAL_TEST testShapeAccounting(); addManyShapes(); - testBoxShape(); - testSphereShape(); - testCylinderShape(); - testCapsuleShape(); + addBoxShape(); + addSphereShape(); + addCylinderShape(); + addCapsuleShape(); } diff --git a/tests/physics/src/ShapeManagerTests.h b/tests/physics/src/ShapeManagerTests.h index 3cbae8cffb..98703fda1e 100644 --- a/tests/physics/src/ShapeManagerTests.h +++ b/tests/physics/src/ShapeManagerTests.h @@ -13,14 +13,13 @@ #define hifi_ShapeManagerTests_h namespace ShapeManagerTests { - void testHashFunctions(); void testShapeAccounting(); void addManyShapes(); - void testBoxShape(); - void testSphereShape(); - void testCylinderShape(); - void testCapsuleShape(); + void addBoxShape(); + void addSphereShape(); + void addCylinderShape(); + void addCapsuleShape(); void runAllTests(); } -#endif // hifi_VerletShapeTests_h +#endif // hifi_ShapeManagerTests_h diff --git a/tests/physics/src/main.cpp b/tests/physics/src/main.cpp index 0e25f0f48c..dfc3698eb5 100644 --- a/tests/physics/src/main.cpp +++ b/tests/physics/src/main.cpp @@ -8,13 +8,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "ShapeColliderTests.h" -#include "VerletShapeTests.h" +//#include "ShapeColliderTests.h" +//#include "VerletShapeTests.h" +#include "ShapeInfoTests.h" #include "ShapeManagerTests.h" int main(int argc, char** argv) { //ShapeColliderTests::runAllTests(); //VerletShapeTests::runAllTests(); + ShapeInfoTests::runAllTests(); ShapeManagerTests::runAllTests(); return 0; } From f1bdd2ef7b3e88f1f12499fd1cf090d363f72a3a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 3 Nov 2014 16:02:16 -0800 Subject: [PATCH 009/105] PhysicsWorld has a ShapeManager --- libraries/physics/src/PhysicsWorld.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/physics/src/PhysicsWorld.h b/libraries/physics/src/PhysicsWorld.h index 778e5280d8..523b1282f7 100644 --- a/libraries/physics/src/PhysicsWorld.h +++ b/libraries/physics/src/PhysicsWorld.h @@ -16,6 +16,8 @@ #include +#include "ShapeManager.h" + class PhysicsWorld { public: @@ -32,6 +34,8 @@ protected: btBroadphaseInterface* _broadphaseFilter; btSequentialImpulseConstraintSolver* _constraintSolver; btDiscreteDynamicsWorld* _dynamicsWorld; + + ShapeManager _shapeManager; private: }; From 57e972d87665d588a5a66b99565503f2eb71dadc Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 4 Nov 2014 14:54:35 -0800 Subject: [PATCH 010/105] ShapeKey now derives from DoubleHashKey --- libraries/physics/src/DoubleHashKey.cpp | 43 +++++++++++++++++++++++++ libraries/physics/src/DoubleHashKey.h | 36 +++++++++++++++++++++ libraries/physics/src/ShapeInfo.cpp | 40 +++-------------------- libraries/physics/src/ShapeInfo.h | 5 ++- libraries/physics/src/ShapeManager.cpp | 28 ++-------------- libraries/physics/src/ShapeManager.h | 18 +++-------- 6 files changed, 91 insertions(+), 79 deletions(-) create mode 100644 libraries/physics/src/DoubleHashKey.cpp create mode 100644 libraries/physics/src/DoubleHashKey.h diff --git a/libraries/physics/src/DoubleHashKey.cpp b/libraries/physics/src/DoubleHashKey.cpp new file mode 100644 index 0000000000..fae1d715fb --- /dev/null +++ b/libraries/physics/src/DoubleHashKey.cpp @@ -0,0 +1,43 @@ +// +// DoubleHashKey.cpp +// libraries/physcis/src +// +// Created by Andrew Meadows 2014.11.02 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "DoubleHashKey.h" + +const int NUM_PRIMES = 64; +const unsigned int PRIMES[] = { + 4194301U, 4194287U, 4194277U, 4194271U, 4194247U, 4194217U, 4194199U, 4194191U, + 4194187U, 4194181U, 4194173U, 4194167U, 4194143U, 4194137U, 4194131U, 4194107U, + 4194103U, 4194023U, 4194011U, 4194007U, 4193977U, 4193971U, 4193963U, 4193957U, + 4193939U, 4193929U, 4193909U, 4193869U, 4193807U, 4193803U, 4193801U, 4193789U, + 4193759U, 4193753U, 4193743U, 4193701U, 4193663U, 4193633U, 4193573U, 4193569U, + 4193551U, 4193549U, 4193531U, 4193513U, 4193507U, 4193459U, 4193447U, 4193443U, + 4193417U, 4193411U, 4193393U, 4193389U, 4193381U, 4193377U, 4193369U, 4193359U, + 4193353U, 4193327U, 4193309U, 4193303U, 4193297U, 4193279U, 4193269U, 4193263U +}; + +unsigned int DoubleHashKey::hashFunction(unsigned int value, int primeIndex) { + unsigned int hash = PRIMES[primeIndex % NUM_PRIMES] * (value + 1U); + hash += ~(hash << 15); + hash ^= (hash >> 10); + hash += (hash << 3); + hash ^= (hash >> 6); + hash += ~(hash << 11); + return hash ^ (hash >> 16); +} + +unsigned int DoubleHashKey::hashFunction2(unsigned int value) { + unsigned hash = 0x811c9dc5U; + for (int i = 0; i < 4; i++ ) { + unsigned int byte = (value << (i * 8)) >> (24 - i * 8); + hash = ( hash ^ byte ) * 0x01000193U; + } + return hash; +} diff --git a/libraries/physics/src/DoubleHashKey.h b/libraries/physics/src/DoubleHashKey.h new file mode 100644 index 0000000000..090eab38a6 --- /dev/null +++ b/libraries/physics/src/DoubleHashKey.h @@ -0,0 +1,36 @@ +// +// DoubleHashKey.h +// libraries/physcis/src +// +// Created by Andrew Meadows 2014.11.02 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_DoubleHashKey_h +#define hifi_DoubleHashKey_h + +// DoubleHashKey for use with btHashMap +class DoubleHashKey { +public: + static unsigned int hashFunction(unsigned int value, int primeIndex); + static unsigned int hashFunction2(unsigned int value); + + DoubleHashKey(unsigned int value, int primIndex = 0) : _hash(hashFunction(value, primIndex)), _hash2(hashFunction2(value)) { } + + bool equals(const DoubleHashKey& other) const { + return _hash == other._hash && _hash2 == other._hash2; + } + + unsigned int getHash() const { return (unsigned int)_hash; } + +protected: + DoubleHashKey() : _hash(0), _hash2(0) { } + + int _hash; + int _hash2; +}; + +#endif // hifi_DoubleHashKey_h diff --git a/libraries/physics/src/ShapeInfo.cpp b/libraries/physics/src/ShapeInfo.cpp index 3d2b8c0f81..85a01f6bda 100644 --- a/libraries/physics/src/ShapeInfo.cpp +++ b/libraries/physics/src/ShapeInfo.cpp @@ -15,19 +15,6 @@ #include "ShapeInfo.h" -// prime numbers larger than 1e6 -const int NUM_PRIMES = 64; -const unsigned int PRIMES[] = { - 4194301U, 4194287U, 4194277U, 4194271U, 4194247U, 4194217U, 4194199U, 4194191U, - 4194187U, 4194181U, 4194173U, 4194167U, 4194143U, 4194137U, 4194131U, 4194107U, - 4194103U, 4194023U, 4194011U, 4194007U, 4193977U, 4193971U, 4193963U, 4193957U, - 4193939U, 4193929U, 4193909U, 4193869U, 4193807U, 4193803U, 4193801U, 4193789U, - 4193759U, 4193753U, 4193743U, 4193701U, 4193663U, 4193633U, 4193573U, 4193569U, - 4193551U, 4193549U, 4193531U, 4193513U, 4193507U, 4193459U, 4193447U, 4193443U, - 4193417U, 4193411U, 4193393U, 4193389U, 4193381U, 4193377U, 4193369U, 4193359U, - 4193353U, 4193327U, 4193309U, 4193303U, 4193297U, 4193279U, 4193269U, 4193263U -}; - void ShapeInfo::collectInfo(const btCollisionShape* shape) { _data.clear(); if (shape) { @@ -93,32 +80,13 @@ void ShapeInfo::setCapsule(float radius, float height) { _data.push_back(btVector3(radius, 0.5f * height, 0.0f)); } -unsigned int ShapeInfo::hashFunction(unsigned int value, int primeIndex) { - unsigned int hash = PRIMES[primeIndex % NUM_PRIMES] * (value + 1U); - hash += ~(hash << 15); - hash ^= (hash >> 10); - hash += (hash << 3); - hash ^= (hash >> 6); - hash += ~(hash << 11); - return hash ^ (hash >> 16); -} - -unsigned int ShapeInfo::hashFunction2(unsigned int value) { - unsigned hash = 0x811c9dc5U; - for (int i = 0; i < 4; i++ ) { - unsigned int byte = (value << (i * 8)) >> (24 - i * 8); - hash = ( hash ^ byte ) * 0x01000193U; - } - return hash; -} - const float MILLIMETERS_PER_METER = 1000.0f; int ShapeInfo::computeHash() const { // scramble the bits of the type // TODO?: provide lookup table for hash of _type? int primeIndex = 0; - unsigned int hash = ShapeInfo::hashFunction((unsigned int)_type, primeIndex++); + unsigned int hash = DoubleHashKey::hashFunction((unsigned int)_type, primeIndex++); btVector3 tmpData; int numData = _data.size(); @@ -126,7 +94,7 @@ int ShapeInfo::computeHash() const { tmpData = _data[i]; for (int j = 0; j < 3; ++j) { // multiply these mm by a new prime - unsigned int floatHash = ShapeInfo::hashFunction((unsigned int)(tmpData[j] * MILLIMETERS_PER_METER + 0.49f), primeIndex++); + unsigned int floatHash = DoubleHashKey::hashFunction((unsigned int)(tmpData[j] * MILLIMETERS_PER_METER + 0.49f), primeIndex++); hash ^= floatHash; } } @@ -136,14 +104,14 @@ int ShapeInfo::computeHash() const { int ShapeInfo::computeHash2() const { // scramble the bits of the type // TODO?: provide lookup table for hash of _type? - unsigned int hash = ShapeInfo::hashFunction2((unsigned int)_type); + unsigned int hash = DoubleHashKey::hashFunction2((unsigned int)_type); btVector3 tmpData; int numData = _data.size(); for (int i = 0; i < numData; ++i) { tmpData = _data[i]; for (int j = 0; j < 3; ++j) { - unsigned int floatHash = ShapeInfo::hashFunction2((unsigned int)(tmpData[j] * MILLIMETERS_PER_METER + 0.49f)); + unsigned int floatHash = DoubleHashKey::hashFunction2((unsigned int)(tmpData[j] * MILLIMETERS_PER_METER + 0.49f)); hash += ~(floatHash << 17); hash ^= (floatHash >> 11); hash += (floatHash << 4); diff --git a/libraries/physics/src/ShapeInfo.h b/libraries/physics/src/ShapeInfo.h index d5d70d7b56..f2a39b5320 100644 --- a/libraries/physics/src/ShapeInfo.h +++ b/libraries/physics/src/ShapeInfo.h @@ -17,6 +17,8 @@ #include #include +#include "DoubleHashKey.h" + class ShapeInfo { public: ShapeInfo() : _type(INVALID_SHAPE_PROXYTYPE) {} @@ -35,9 +37,6 @@ public: int computeHash() const; int computeHash2() const; - static unsigned int hashFunction(unsigned int value, int primeIndex); - static unsigned int hashFunction2(unsigned int value); - btCollisionShape* createShape() const; private: diff --git a/libraries/physics/src/ShapeManager.cpp b/libraries/physics/src/ShapeManager.cpp index 61f0ceabad..c75bfd67ea 100644 --- a/libraries/physics/src/ShapeManager.cpp +++ b/libraries/physics/src/ShapeManager.cpp @@ -68,34 +68,10 @@ bool ShapeManager::releaseShape(const ShapeInfo& info) { return false; } -/* bool ShapeManager::releaseShape(const btCollisionShape* shape) { - // when the number of shapes is high it's probably cheaper to try to construct a ShapeInfo - // and then compute the hash rather than walking the list in search of the pointer. - ShapeKey key(info); - ShapeReference* shapeRef = _shapeMap.find(key); - if (shapeRef) { - if (shapeRef->_refCount > 0) { - shapeRef->_refCount--; - if (shapeRef->_refCount == 0) { - _pendingGarbage.push_back(key); - const int MAX_GARBAGE_CAPACITY = 127; - if (_pendingGarbage.size() > MAX_GARBAGE_CAPACITY) { - collectGarbage(); - } - } - return true; - } else { - // attempt to remove shape that has no refs - assert(false); - } - } else { - // attempt to remove unmanaged shape - assert(false); - } - return false; + ShapeInfo info(shape); + return releaseShape(info); } -*/ void ShapeManager::collectGarbage() { int numShapes = _pendingGarbage.size(); diff --git a/libraries/physics/src/ShapeManager.h b/libraries/physics/src/ShapeManager.h index 6c497dd981..b205103f19 100644 --- a/libraries/physics/src/ShapeManager.h +++ b/libraries/physics/src/ShapeManager.h @@ -17,28 +17,18 @@ #include #include +#include "DoubleHashKey.h" #include "ShapeInfo.h" -class ShapeKey +class ShapeKey : public DoubleHashKey { public: - ShapeKey(const ShapeInfo& info) : _hash(0), _hash2(0) { + ShapeKey(const ShapeInfo& info) : DoubleHashKey() { _hash = info.computeHash(); _hash2 = info.computeHash2(); } - - bool equals(const ShapeKey& other) const { - return _hash == other._hash && _hash2 == other._hash2; - } - - unsigned int getHash() const { return (unsigned int)_hash; } - -private: - int _hash; - int _hash2; }; - class ShapeManager { public: @@ -50,7 +40,7 @@ public: /// \return true if shape was found and released bool releaseShape(const ShapeInfo& info); -// bool removeReference(const btCollisionShape*); + bool releaseShape(const btCollisionShape* shape); /// delete shapes that have zero references void collectGarbage(); From 2734afcf9a20945ee8d4fa57e4bd02c2c8f8a89c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 4 Nov 2014 16:43:50 -0800 Subject: [PATCH 011/105] Adding BulletUtil.h with tests. --- libraries/physics/src/BulletUtil.h | 40 ++++++++++ tests/physics/src/BulletUtilTests.cpp | 107 ++++++++++++++++++++++++++ tests/physics/src/BulletUtilTests.h | 21 +++++ tests/physics/src/main.cpp | 2 + 4 files changed, 170 insertions(+) create mode 100644 libraries/physics/src/BulletUtil.h create mode 100644 tests/physics/src/BulletUtilTests.cpp create mode 100644 tests/physics/src/BulletUtilTests.h diff --git a/libraries/physics/src/BulletUtil.h b/libraries/physics/src/BulletUtil.h new file mode 100644 index 0000000000..36b3960521 --- /dev/null +++ b/libraries/physics/src/BulletUtil.h @@ -0,0 +1,40 @@ +// +// BulletUtil.h +// libraries/physcis/src +// +// Created by Andrew Meadows 2014.11.02 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_BulletUtil_h +#define hifi_BulletUtil_h + +#include +#include +#include + +inline void bulletToGLM(const btVector3& b, glm::vec3& g) { + g = glm::vec3(b.getX(), b.getY(), b.getZ()); +} + +inline void bulletToGLM(const btQuaternion& b, glm::quat& g) { + g.x = b.getX(); + g.y = b.getY(); + g.z = b.getZ(); + g.w = b.getW(); +} + +inline void glmToBullet(const glm::vec3& g, btVector3& b) { + b.setX(g.x); + b.setY(g.y); + b.setZ(g.z); +} + +inline void glmToBullet(const glm::quat& g, btQuaternion& b) { + b = btQuaternion(g.x, g.y, g.z, g.w); +} + +#endif // hifi_BulletUtil_h diff --git a/tests/physics/src/BulletUtilTests.cpp b/tests/physics/src/BulletUtilTests.cpp new file mode 100644 index 0000000000..5486870196 --- /dev/null +++ b/tests/physics/src/BulletUtilTests.cpp @@ -0,0 +1,107 @@ +// +// BulletUtilTests.cpp +// tests/physics/src +// +// Created by Andrew Meadows on 2014.11.02 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include + +#include +#include + +#include "BulletUtilTests.h" + +void BulletUtilTests::fromBulletToGLM() { + btVector3 bV(1.23f, 4.56f, 7.89f); + glm::vec3 gV; + bulletToGLM(bV, gV); + if (gV.x != bV.getX()) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: x mismatch bullet.x = " << bV.getX() << " != glm.x = " << gV.x << std::endl; + } + if (gV.y != bV.getY()) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: x mismatch bullet.y = " << bV.getY() << " != glm.y = " << gV.y << std::endl; + } + if (gV.z != bV.getZ()) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: x mismatch bullet.z = " << bV.getZ() << " != glm.z = " << gV.z << std::endl; + } + + float angle = 0.317f * PI; + btVector3 axis(1.23f, 2.34f, 3.45f); + axis.normalize(); + btQuaternion bQ(axis, angle); + + glm::quat gQ; + bulletToGLM(bQ, gQ); + if (gQ.x != bQ.getX()) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: x mismatch bullet.x = " << bQ.getX() << " != glm.x = " << gQ.x << std::endl; + } + if (gQ.y != bQ.getY()) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: x mismatch bullet.y = " << bQ.getY() << " != glm.y = " << gQ.y << std::endl; + } + if (gQ.z != bQ.getZ()) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: x mismatch bullet.z = " << bQ.getZ() << " != glm.z = " << gQ.z << std::endl; + } + if (gQ.w != bQ.getW()) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: x mismatch bullet.w = " << bQ.getW() << " != glm.w = " << gQ.w << std::endl; + } +} + +void BulletUtilTests::fromGLMToBullet() { + glm::vec3 gV(1.23f, 4.56f, 7.89f); + btVector3 bV; + glmToBullet(gV, bV); + if (gV.x != bV.getX()) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: x mismatch glm.x = " << gV.x << " != bullet.x = " << bV.getX() << std::endl; + } + if (gV.y != bV.getY()) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: x mismatch glm.y = " << gV.y << " != bullet.y = " << bV.getY() << std::endl; + } + if (gV.z != bV.getZ()) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: x mismatch glm.z = " << gV.z << " != bullet.z = " << bV.getZ() << std::endl; + } + + float angle = 0.317f * PI; + btVector3 axis(1.23f, 2.34f, 3.45f); + axis.normalize(); + btQuaternion bQ(axis, angle); + + glm::quat gQ; + bulletToGLM(bQ, gQ); + if (gQ.x != bQ.getX()) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: x mismatch glm.x = " << gQ.x << " != bullet.x = " << bQ.getX() << std::endl; + } + if (gQ.y != bQ.getY()) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: x mismatch glm.y = " << gQ.y << " != bullet.y = " << bQ.getY() << std::endl; + } + if (gQ.z != bQ.getZ()) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: x mismatch glm.z = " << gQ.z << " != bullet.z = " << bQ.getZ() << std::endl; + } + if (gQ.w != bQ.getW()) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: x mismatch glm.w = " << gQ.w << " != bullet.w = " << bQ.getW() << std::endl; + } +} + +void BulletUtilTests::runAllTests() { + fromBulletToGLM(); + fromGLMToBullet(); +} + diff --git a/tests/physics/src/BulletUtilTests.h b/tests/physics/src/BulletUtilTests.h new file mode 100644 index 0000000000..b885777bdd --- /dev/null +++ b/tests/physics/src/BulletUtilTests.h @@ -0,0 +1,21 @@ +// +// BulletUtilTests.h +// tests/physics/src +// +// Created by Andrew Meadows on 2014.11.02 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_BulletUtilTests_h +#define hifi_BulletUtilTests_h + +namespace BulletUtilTests { + void fromBulletToGLM(); + void fromGLMToBullet(); + void runAllTests(); +} + +#endif // hifi_BulletUtilTests_h diff --git a/tests/physics/src/main.cpp b/tests/physics/src/main.cpp index dfc3698eb5..2318ee2dca 100644 --- a/tests/physics/src/main.cpp +++ b/tests/physics/src/main.cpp @@ -12,11 +12,13 @@ //#include "VerletShapeTests.h" #include "ShapeInfoTests.h" #include "ShapeManagerTests.h" +#include "BulletUtilTests.h" int main(int argc, char** argv) { //ShapeColliderTests::runAllTests(); //VerletShapeTests::runAllTests(); ShapeInfoTests::runAllTests(); ShapeManagerTests::runAllTests(); + BulletUtilTests::runAllTests(); return 0; } From 92ceb521835530a27efb9ae31d970907886577bd Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 4 Nov 2014 16:46:45 -0800 Subject: [PATCH 012/105] adding macro to find bullet --- cmake/macros/IncludeBullet.cmake | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 cmake/macros/IncludeBullet.cmake diff --git a/cmake/macros/IncludeBullet.cmake b/cmake/macros/IncludeBullet.cmake new file mode 100644 index 0000000000..53b7224bb8 --- /dev/null +++ b/cmake/macros/IncludeBullet.cmake @@ -0,0 +1,17 @@ +# +# IncludeBullet.cmake +# +# Copyright 2014 High Fidelity, Inc. +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# + +macro(INCLUDE_BULLET) + find_package(Bullet) + if (BULLET_FOUND) + include_directories(SYSTEM "${BULLET_INCLUDE_DIRS}") + list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${BULLET_LIBRARIES}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_BULLET_PHYSICS") + endif (BULLET_FOUND) +endmacro(INCLUDE_BULLET) From 8e90cca2901667e6e1ed49b452f9be4de1c7ff06 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 5 Nov 2014 13:05:43 -0800 Subject: [PATCH 013/105] PhysicsWorld can add and remove voxels --- libraries/physics/src/DoubleHashKey.h | 6 ++- libraries/physics/src/PhysicsWorld.cpp | 60 +++++++++++++++++++++++ libraries/physics/src/PhysicsWorld.h | 42 +++++++++++++++- libraries/physics/src/PositionHashKey.cpp | 37 ++++++++++++++ libraries/physics/src/PositionHashKey.h | 28 +++++++++++ libraries/physics/src/ShapeInfo.cpp | 25 ++++++++-- libraries/physics/src/ShapeInfo.h | 2 + libraries/physics/src/VoxelObject.h | 31 ++++++++++++ 8 files changed, 224 insertions(+), 7 deletions(-) create mode 100644 libraries/physics/src/PositionHashKey.cpp create mode 100644 libraries/physics/src/PositionHashKey.h create mode 100644 libraries/physics/src/VoxelObject.h diff --git a/libraries/physics/src/DoubleHashKey.h b/libraries/physics/src/DoubleHashKey.h index 090eab38a6..0dbf2430e2 100644 --- a/libraries/physics/src/DoubleHashKey.h +++ b/libraries/physics/src/DoubleHashKey.h @@ -18,7 +18,10 @@ public: static unsigned int hashFunction(unsigned int value, int primeIndex); static unsigned int hashFunction2(unsigned int value); - DoubleHashKey(unsigned int value, int primIndex = 0) : _hash(hashFunction(value, primIndex)), _hash2(hashFunction2(value)) { } + DoubleHashKey(unsigned int value, int primeIndex = 0) : + _hash(hashFunction(value, primeIndex)), + _hash2(hashFunction2(value)) { + } bool equals(const DoubleHashKey& other) const { return _hash == other._hash && _hash2 == other._hash2; @@ -27,6 +30,7 @@ public: unsigned int getHash() const { return (unsigned int)_hash; } protected: + // the default ctor is protected so that only derived classes can use it DoubleHashKey() : _hash(0), _hash2(0) { } int _hash; diff --git a/libraries/physics/src/PhysicsWorld.cpp b/libraries/physics/src/PhysicsWorld.cpp index 9364b77e65..faa5757e4a 100644 --- a/libraries/physics/src/PhysicsWorld.cpp +++ b/libraries/physics/src/PhysicsWorld.cpp @@ -21,3 +21,63 @@ void PhysicsWorld::init() { _constraintSolver = new btSequentialImpulseConstraintSolver; _dynamicsWorld = new btDiscreteDynamicsWorld(_collisionDispatcher, _broadphaseFilter, _constraintSolver, _collisionConfig); } + +/// \return true if Voxel added +/// \param position the minimum corner of the voxel +/// \param scale the length of the voxel side +bool PhysicsWorld::addVoxel(const glm::vec3& position, float scale) { + glm::vec3 halfExtents = glm::vec3(0.5f * scale); + glm::vec3 center = position + halfExtents; + PositionHashKey key(center); + VoxelObject* proxy = _voxels.find(key); + if (!proxy) { + // create a shape + ShapeInfo info; + info.setBox(halfExtents); + btCollisionShape* shape = _shapeManager.getShape(info); + + // NOTE: the shape creation will fail when the size of the voxel is out of range + if (shape) { + // create a collisionObject + btCollisionObject* object = new btCollisionObject(); + object->setCollisionShape(shape); + btTransform transform; + transform.setIdentity(); + transform.setOrigin(btVector3(center.x, center.y, center.z)); + object->setWorldTransform(transform); + + // add to map and world + _voxels.insert(key, VoxelObject(center, object)); + _dynamicsWorld->addCollisionObject(object); + return true; + } + } + return false; +} + +/// \return true if Voxel removed +/// \param position the minimum corner of the voxel +/// \param scale the length of voxel side +bool PhysicsWorld::removeVoxel(const glm::vec3& position, float scale) { + glm::vec3 halfExtents = glm::vec3(0.5f * scale); + glm::vec3 center = position + halfExtents; + PositionHashKey key(center); + VoxelObject* proxy = _voxels.find(key); + if (proxy) { + // remove from world + assert(proxy->_object); + _dynamicsWorld->removeCollisionObject(proxy->_object); + + // release shape + ShapeInfo info; + info.setBox(halfExtents); + bool released = _shapeManager.releaseShape(info); + assert(released); + + // delete object and remove from voxel map + delete proxy->_object; + _voxels.remove(key); + return true; + } + return false; +} diff --git a/libraries/physics/src/PhysicsWorld.h b/libraries/physics/src/PhysicsWorld.h index 523b1282f7..ca42113a65 100644 --- a/libraries/physics/src/PhysicsWorld.h +++ b/libraries/physics/src/PhysicsWorld.h @@ -17,6 +17,35 @@ #include #include "ShapeManager.h" +#include "BulletUtil.h" +#include "PositionHashKey.h" +#include "VoxelObject.h" + +#ifdef COLLIDABLE +enum MotionType { + MOTION_TYPE_STATIC, + MOTION_TYPE_DYNAMIC, + MOTION_TYPE_KINEMATIC +}; + +class EntityObject { +public: + EntityObject(); + + bool makeStatic(); + bool makeDynamic(); + bool makeKinematic(); + + MotionType getMotionType() const { return _motionType; } + +private: + btCollisionObject* _object; + btMotionState* _motionState; + MotionType _motionType; + btVector3 _inertiaDiagLocal; + float _mass; +}; +#endif // COLLIDABLE class PhysicsWorld { public: @@ -27,7 +56,17 @@ public: ~PhysicsWorld(); void init(); - + + /// \return true if Voxel added + /// \param position the minimum corner of the voxel + /// \param scale the length of the voxel side + bool addVoxel(const glm::vec3& position, float scale); + + /// \return true if Voxel removed + /// \param position the minimum corner of the voxel + /// \param scale the length of the voxel side + bool removeVoxel(const glm::vec3& position, float scale); + protected: btDefaultCollisionConfiguration* _collisionConfig; btCollisionDispatcher* _collisionDispatcher; @@ -38,6 +77,7 @@ protected: ShapeManager _shapeManager; private: + btHashMap _voxels; }; diff --git a/libraries/physics/src/PositionHashKey.cpp b/libraries/physics/src/PositionHashKey.cpp new file mode 100644 index 0000000000..e03391c72c --- /dev/null +++ b/libraries/physics/src/PositionHashKey.cpp @@ -0,0 +1,37 @@ +// +// PositionHashKey.cpp +// libraries/physcis/src +// +// Created by Andrew Meadows 2014.11.05 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include + +#include "PositionHashKey.h" + +// static +int PositionHashKey::computeHash(const glm::vec3& center) { + // NOTE: 0.49f is used to bump the float up almost half a millimeter + // so the cast to int produces a round() effect rather than a floor() + int hash = DoubleHashKey::hashFunction((int)(center.x * MILLIMETERS_PER_METER + copysignf(1.0f, center.x) * 0.49f), 0); + hash ^= DoubleHashKey::hashFunction((int)(center.y * MILLIMETERS_PER_METER + copysignf(1.0f, center.y) * 0.49f), 1); + return hash ^ DoubleHashKey::hashFunction((int)(center.z * MILLIMETERS_PER_METER + copysignf(1.0f, center.z) * 0.49f), 2); +} + +// static +int PositionHashKey::computeHash2(const glm::vec3& center) { + // NOTE: 0.49f is used to bump the float up almost half a millimeter + // so the cast to int produces a round() effect rather than a floor() + int hash = DoubleHashKey::hashFunction2((int)(center.x * MILLIMETERS_PER_METER + copysignf(1.0f, center.x) * 0.49f)); + hash ^= DoubleHashKey::hashFunction2((int)(center.y * MILLIMETERS_PER_METER + copysignf(1.0f, center.y) * 0.49f)); + return hash ^ DoubleHashKey::hashFunction2((int)(center.z * MILLIMETERS_PER_METER + copysignf(1.0f, center.z) * 0.49f)); +} + +PositionHashKey::PositionHashKey(glm::vec3 center) : DoubleHashKey() { + _hash = PositionHashKey::computeHash(center); + _hash2 = PositionHashKey::computeHash2(center); +} diff --git a/libraries/physics/src/PositionHashKey.h b/libraries/physics/src/PositionHashKey.h new file mode 100644 index 0000000000..bb2f277051 --- /dev/null +++ b/libraries/physics/src/PositionHashKey.h @@ -0,0 +1,28 @@ +// +// PositionHashKey.h +// libraries/physcis/src +// +// Created by Andrew Meadows 2014.11.05 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_PositionHashKey_h +#define hifi_PositionHashKey_h + +#include + +#include + +#include "DoubleHashKey.h" + +class PositionHashKey : public DoubleHashKey { +public: + static int computeHash(const glm::vec3& center); + static int computeHash2(const glm::vec3& center); + PositionHashKey(glm::vec3 center); +}; + +#endif // hifi_PositionHashKey_h diff --git a/libraries/physics/src/ShapeInfo.cpp b/libraries/physics/src/ShapeInfo.cpp index 85a01f6bda..cf848793a9 100644 --- a/libraries/physics/src/ShapeInfo.cpp +++ b/libraries/physics/src/ShapeInfo.cpp @@ -11,8 +11,12 @@ #ifdef USE_BULLET_PHYSICS +#include #include +#include // for MILLIMETERS_PER_METER + +#include "BulletUtil.h" #include "ShapeInfo.h" void ShapeInfo::collectInfo(const btCollisionShape* shape) { @@ -60,6 +64,14 @@ void ShapeInfo::setBox(const btVector3& halfExtents) { _data.push_back(halfExtents); } +void ShapeInfo::setBox(const glm::vec3& halfExtents) { + _type = BOX_SHAPE_PROXYTYPE; + _data.clear(); + btVector3 bulletHalfExtents; + glmToBullet(halfExtents, bulletHalfExtents); + _data.push_back(bulletHalfExtents); +} + void ShapeInfo::setSphere(float radius) { _type = SPHERE_SHAPE_PROXYTYPE; _data.clear(); @@ -80,8 +92,6 @@ void ShapeInfo::setCapsule(float radius, float height) { _data.push_back(btVector3(radius, 0.5f * height, 0.0f)); } -const float MILLIMETERS_PER_METER = 1000.0f; - int ShapeInfo::computeHash() const { // scramble the bits of the type // TODO?: provide lookup table for hash of _type? @@ -93,8 +103,10 @@ int ShapeInfo::computeHash() const { for (int i = 0; i < numData; ++i) { tmpData = _data[i]; for (int j = 0; j < 3; ++j) { - // multiply these mm by a new prime - unsigned int floatHash = DoubleHashKey::hashFunction((unsigned int)(tmpData[j] * MILLIMETERS_PER_METER + 0.49f), primeIndex++); + // NOTE: 0.49f is used to bump the float up almost half a millimeter + // so the cast to int produces a round() effect rather than a floor() + unsigned int floatHash = + DoubleHashKey::hashFunction((int)(tmpData[j] * MILLIMETERS_PER_METER + copysignf(1.0f, tmpData[j]) * 0.49f), primeIndex++); hash ^= floatHash; } } @@ -111,7 +123,10 @@ int ShapeInfo::computeHash2() const { for (int i = 0; i < numData; ++i) { tmpData = _data[i]; for (int j = 0; j < 3; ++j) { - unsigned int floatHash = DoubleHashKey::hashFunction2((unsigned int)(tmpData[j] * MILLIMETERS_PER_METER + 0.49f)); + // NOTE: 0.49f is used to bump the float up almost half a millimeter + // so the cast to int produces a round() effect rather than a floor() + unsigned int floatHash = + DoubleHashKey::hashFunction2((int)(tmpData[j] * MILLIMETERS_PER_METER + copysignf(1.0f, tmpData[j]) * 0.49f)); hash += ~(floatHash << 17); hash ^= (floatHash >> 11); hash += (floatHash << 4); diff --git a/libraries/physics/src/ShapeInfo.h b/libraries/physics/src/ShapeInfo.h index f2a39b5320..40dedfef1e 100644 --- a/libraries/physics/src/ShapeInfo.h +++ b/libraries/physics/src/ShapeInfo.h @@ -16,6 +16,7 @@ #include #include +#include #include "DoubleHashKey.h" @@ -30,6 +31,7 @@ public: void collectInfo(const btCollisionShape* shape); void setBox(const btVector3& halfExtents); + void setBox(const glm::vec3& halfExtents); void setSphere(float radius); void setCylinder(float radius, float height); void setCapsule(float radius, float height); diff --git a/libraries/physics/src/VoxelObject.h b/libraries/physics/src/VoxelObject.h new file mode 100644 index 0000000000..49866e0bce --- /dev/null +++ b/libraries/physics/src/VoxelObject.h @@ -0,0 +1,31 @@ +// +// VoxelObject.h +// libraries/physcis/src +// +// Created by Andrew Meadows 2014.11.05 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_VoxelObject_h +#define hifi_VoxelObject_h + +#ifdef USE_BULLET_PHYSICS + +#include +#include + +// VoxelObject is a simple wrapper for tracking a Voxel in a PhysicsWorld +class VoxelObject { +public: + VoxelObject(const glm::vec3& center, btCollisionObject* object) : _object(object), _center(center) { + assert(object != NULL); + } + btCollisionObject* _object; + glm::vec3 _center; +}; + +#endif // USE_BULLET_PHYSICS +#endif // hifi_VoxelObject_h From 1097e7f1f2b85a220b2d300a220eedc34c61edd2 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 5 Nov 2014 16:35:06 -0800 Subject: [PATCH 014/105] stubbery for EntityMotionState --- libraries/physics/src/EntityMotionState.cpp | 68 +++++++++++++++++++++ libraries/physics/src/EntityMotionState.h | 57 +++++++++++++++++ libraries/physics/src/PhysicsWorld.cpp | 27 ++++++-- libraries/physics/src/PhysicsWorld.h | 39 ++++-------- libraries/physics/src/UUIDHashKey.h | 31 ++++++++++ 5 files changed, 189 insertions(+), 33 deletions(-) create mode 100644 libraries/physics/src/EntityMotionState.cpp create mode 100644 libraries/physics/src/EntityMotionState.h create mode 100644 libraries/physics/src/UUIDHashKey.h diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp new file mode 100644 index 0000000000..2eaab25a46 --- /dev/null +++ b/libraries/physics/src/EntityMotionState.cpp @@ -0,0 +1,68 @@ +// +// EntityMotionState.cpp +// libraries/physcis/src +// +// Created by Andrew Meadows 2014.11.05 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifdef USE_BULLET_PHYSICS + +#include "EntityMotionState.h" + +EntityMotionState::EntityMotionState() : _motionType(MOTION_TYPE_STATIC), + _inertiaDiagLocal(1.0f, 1.0f, 1.0f), _mass(1.0f), + _shape(NULL), _object(NULL) { +} + +/* +void EntityMotionState::getWorldTransform (btTransform &worldTrans) const { +} + +void EntityMotionState::setWorldTransform (const btTransform &worldTrans) { +} + +void EntityMotionState::computeMassProperties() { +} + +void EntityMotionState::getShapeInfo(ShapeInfo& info) { +} +*/ + +bool EntityMotionState::makeStatic() { + if (_motionType == MOTION_TYPE_STATIC) { + return true; + } + if (!_object) { + _motionType = MOTION_TYPE_STATIC; + return true; + } + return false; +} + +bool EntityMotionState::makeDynamic() { + if (_motionType == MOTION_TYPE_DYNAMIC) { + return true; + } + if (!_object) { + _motionType = MOTION_TYPE_DYNAMIC; + return true; + } + return false; +} + +bool EntityMotionState::makeKinematic() { + if (_motionType == MOTION_TYPE_KINEMATIC) { + return true; + } + if (!_object) { + _motionType = MOTION_TYPE_KINEMATIC; + return true; + } + return false; +} + +#endif // USE_BULLET_PHYSICS diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h new file mode 100644 index 0000000000..b891f93ae3 --- /dev/null +++ b/libraries/physics/src/EntityMotionState.h @@ -0,0 +1,57 @@ +// +// EntityMotionState.h +// libraries/physcis/src +// +// Created by Andrew Meadows 2014.11.05 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_EntityMotionState_h +#define hifi_EntityMotionState_h + +#ifdef USE_BULLET_PHYSICS + +#include + +#include "ShapeInfo.h" +#include "UUIDHashKey.h" + +enum MotionType { + MOTION_TYPE_STATIC, // no motion + MOTION_TYPE_DYNAMIC, // motion according to physical laws + MOTION_TYPE_KINEMATIC // keyframed motion +}; + +class EntityMotionState : public btMotionState { +public: + EntityMotionState(); + + //// these override methods of the btMotionState base class + //virtual void getWorldTransform (btTransform &worldTrans) const; + //virtual void setWorldTransform (const btTransform &worldTrans); + + virtual void computeMassProperties() = 0; + virtual void getShapeInfo(ShapeInfo& info) = 0; + + bool makeStatic(); + bool makeDynamic(); + bool makeKinematic(); + + MotionType getMotionType() const { return _motionType; } + +private: + friend class PhysicsWorld; + + //EntityItem* _entity; + MotionType _motionType; + btVector3 _inertiaDiagLocal; + float _mass; + btCollisionShape* _shape; + btCollisionObject* _object; +}; + +#endif // USE_BULLET_PHYSICS +#endif // hifi_EntityMotionState_h diff --git a/libraries/physics/src/PhysicsWorld.cpp b/libraries/physics/src/PhysicsWorld.cpp index faa5757e4a..0d475f0a84 100644 --- a/libraries/physics/src/PhysicsWorld.cpp +++ b/libraries/physics/src/PhysicsWorld.cpp @@ -22,9 +22,6 @@ void PhysicsWorld::init() { _dynamicsWorld = new btDiscreteDynamicsWorld(_collisionDispatcher, _broadphaseFilter, _constraintSolver, _collisionConfig); } -/// \return true if Voxel added -/// \param position the minimum corner of the voxel -/// \param scale the length of the voxel side bool PhysicsWorld::addVoxel(const glm::vec3& position, float scale) { glm::vec3 halfExtents = glm::vec3(0.5f * scale); glm::vec3 center = position + halfExtents; @@ -55,9 +52,6 @@ bool PhysicsWorld::addVoxel(const glm::vec3& position, float scale) { return false; } -/// \return true if Voxel removed -/// \param position the minimum corner of the voxel -/// \param scale the length of voxel side bool PhysicsWorld::removeVoxel(const glm::vec3& position, float scale) { glm::vec3 halfExtents = glm::vec3(0.5f * scale); glm::vec3 center = position + halfExtents; @@ -81,3 +75,24 @@ bool PhysicsWorld::removeVoxel(const glm::vec3& position, float scale) { } return false; } + +bool PhysicsWorld::addEntity(const QUuid& id, EntityMotionState* motionState) { + assert(motionState); + UUIDHashKey key(id); + EntityMotionState** statePtr = _entities.find(key); + if (!statePtr) { + // BOOKMARK: Andrew to implement this + } else { + assert(*statePtr == motionState); + } + return false; +} + +bool PhysicsWorld::removeEntity(const QUuid& id) { + UUIDHashKey key(id); + EntityMotionState** statePtr = _entities.find(key); + if (statePtr) { + // BOOKMARK: Andrew to implement this + } + return false; +} diff --git a/libraries/physics/src/PhysicsWorld.h b/libraries/physics/src/PhysicsWorld.h index ca42113a65..f6728bbd8b 100644 --- a/libraries/physics/src/PhysicsWorld.h +++ b/libraries/physics/src/PhysicsWorld.h @@ -16,37 +16,13 @@ #include -#include "ShapeManager.h" #include "BulletUtil.h" +#include "EntityMotionState.h" #include "PositionHashKey.h" +#include "ShapeManager.h" +#include "UUIDHashKey.h" #include "VoxelObject.h" -#ifdef COLLIDABLE -enum MotionType { - MOTION_TYPE_STATIC, - MOTION_TYPE_DYNAMIC, - MOTION_TYPE_KINEMATIC -}; - -class EntityObject { -public: - EntityObject(); - - bool makeStatic(); - bool makeDynamic(); - bool makeKinematic(); - - MotionType getMotionType() const { return _motionType; } - -private: - btCollisionObject* _object; - btMotionState* _motionState; - MotionType _motionType; - btVector3 _inertiaDiagLocal; - float _mass; -}; -#endif // COLLIDABLE - class PhysicsWorld { public: @@ -67,6 +43,14 @@ public: /// \param scale the length of the voxel side bool removeVoxel(const glm::vec3& position, float scale); + /// \return true if Entity added + /// \param info information about collision shapes to create + bool addEntity(const QUuid& id, EntityMotionState* motionState); + + /// \return true if Entity removed + /// \param id UUID of the entity + bool removeEntity(const QUuid& id); + protected: btDefaultCollisionConfiguration* _collisionConfig; btCollisionDispatcher* _collisionDispatcher; @@ -78,6 +62,7 @@ protected: private: btHashMap _voxels; + btHashMap _entities; }; diff --git a/libraries/physics/src/UUIDHashKey.h b/libraries/physics/src/UUIDHashKey.h new file mode 100644 index 0000000000..fcc6209d5a --- /dev/null +++ b/libraries/physics/src/UUIDHashKey.h @@ -0,0 +1,31 @@ +// +// UUIDHashKey.h +// libraries/physcis/src +// +// Created by Andrew Meadows 2014.11.05 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_UUIDHashKey_h +#define hifi_UUIDHashKey_h + +#include + +class UUIDHashKey { +public: + UUIDHashKey(const QUuid& id) : _hash(0), _id(id) { _hash = (int)(qHash(id)); } + + bool equals(const UUIDHashKey& other) const { + return _hash == other._hash && _id == other._id; + } + + unsigned int getHash() const { return (unsigned int)_hash; } +protected: + int _hash; + QUuid _id; +}; + +#endif // hifi_UUIDHashKey_h From bcac1b9b31a691b7ca399371ffa4113cf372affb Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 5 Nov 2014 16:35:24 -0800 Subject: [PATCH 015/105] minor comment typos --- libraries/entities/src/EntityItem.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index d41bd4a179..c32ab18299 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -59,10 +59,10 @@ public: // methods for getting/setting all properties of an entity virtual EntityItemProperties getProperties() const; - /// returns true is something changed + /// returns true if something changed virtual bool setProperties(const EntityItemProperties& properties, bool forceCopy = false); - /// override this in your derived class if you'd like to be informed when something about the state of the entity + /// Override this in your derived class if you'd like to be informed when something about the state of the entity /// has changed. This will be called with properties change or when new data is loaded from a stream virtual void somethingChangedNotification() { } From 57f13f3a7cfc507a90942de886f289937cdd0354 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 5 Nov 2014 17:05:26 -0800 Subject: [PATCH 016/105] entities lib now depends on bullet (if exists) --- libraries/entities/CMakeLists.txt | 1 + libraries/entities/src/EntityItem.h | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/libraries/entities/CMakeLists.txt b/libraries/entities/CMakeLists.txt index e48baa7615..5e3ab70f76 100644 --- a/libraries/entities/CMakeLists.txt +++ b/libraries/entities/CMakeLists.txt @@ -4,6 +4,7 @@ set(TARGET_NAME entities) setup_hifi_library(Network Script) include_glm() +include_bullet() link_hifi_libraries(shared octree fbx networking animation physics) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index dba1a04bf0..f1d4e42b81 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -34,6 +34,10 @@ class EntityTreeElementExtraEncodeData; #define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0; #define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() { }; +#ifdef USE_BULLET_PHYSICS +class EntityMotionState; +#endif // USE_BULLET_PHYSICS + /// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available /// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate @@ -254,6 +258,11 @@ public: void applyHardCollision(const CollisionInfo& collisionInfo); virtual const Shape& getCollisionShapeInMeters() const { return _collisionShape; } virtual bool contains(const glm::vec3& point) const { return getAABox().contains(point); } + +#ifdef USE_BULLET_PHYSICS + //EntityMotionState* createMotionState() = 0; + EntityMotionState* createMotionState() { return NULL; } +#endif // USE_BULLET_PHYSICS protected: virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init From 01b76af9d02d96725698517bce3e0a1bf79db8a1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 6 Nov 2014 10:58:04 -0800 Subject: [PATCH 017/105] moved EntityMotionState.* to CustomMotionState.* --- .../src/{EntityMotionState.cpp => CustomMotionState.cpp} | 0 .../physics/src/{EntityMotionState.h => CustomMotionState.h} | 0 libraries/physics/src/PhysicsWorld.h | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename libraries/physics/src/{EntityMotionState.cpp => CustomMotionState.cpp} (100%) rename libraries/physics/src/{EntityMotionState.h => CustomMotionState.h} (100%) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/CustomMotionState.cpp similarity index 100% rename from libraries/physics/src/EntityMotionState.cpp rename to libraries/physics/src/CustomMotionState.cpp diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/CustomMotionState.h similarity index 100% rename from libraries/physics/src/EntityMotionState.h rename to libraries/physics/src/CustomMotionState.h diff --git a/libraries/physics/src/PhysicsWorld.h b/libraries/physics/src/PhysicsWorld.h index f6728bbd8b..cfb2d08613 100644 --- a/libraries/physics/src/PhysicsWorld.h +++ b/libraries/physics/src/PhysicsWorld.h @@ -17,7 +17,7 @@ #include #include "BulletUtil.h" -#include "EntityMotionState.h" +#include "CustomMotionState.h" #include "PositionHashKey.h" #include "ShapeManager.h" #include "UUIDHashKey.h" From 94b6d89b4ebf8cd084227daf8b143c3725f4246b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 6 Nov 2014 10:59:04 -0800 Subject: [PATCH 018/105] namechange EntityMotionState to CustomMotionState --- libraries/physics/src/CustomMotionState.cpp | 20 ++++++++++---------- libraries/physics/src/CustomMotionState.h | 12 ++++++------ libraries/physics/src/PhysicsWorld.cpp | 6 +++--- libraries/physics/src/PhysicsWorld.h | 4 ++-- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/libraries/physics/src/CustomMotionState.cpp b/libraries/physics/src/CustomMotionState.cpp index 2eaab25a46..bd9d41011c 100644 --- a/libraries/physics/src/CustomMotionState.cpp +++ b/libraries/physics/src/CustomMotionState.cpp @@ -1,5 +1,5 @@ // -// EntityMotionState.cpp +// CustomMotionState.cpp // libraries/physcis/src // // Created by Andrew Meadows 2014.11.05 @@ -11,28 +11,28 @@ #ifdef USE_BULLET_PHYSICS -#include "EntityMotionState.h" +#include "CustomMotionState.h" -EntityMotionState::EntityMotionState() : _motionType(MOTION_TYPE_STATIC), +CustomMotionState::CustomMotionState() : _motionType(MOTION_TYPE_STATIC), _inertiaDiagLocal(1.0f, 1.0f, 1.0f), _mass(1.0f), _shape(NULL), _object(NULL) { } /* -void EntityMotionState::getWorldTransform (btTransform &worldTrans) const { +void CustomMotionState::getWorldTransform (btTransform &worldTrans) const { } -void EntityMotionState::setWorldTransform (const btTransform &worldTrans) { +void CustomMotionState::setWorldTransform (const btTransform &worldTrans) { } -void EntityMotionState::computeMassProperties() { +void CustomMotionState::computeMassProperties() { } -void EntityMotionState::getShapeInfo(ShapeInfo& info) { +void CustomMotionState::getShapeInfo(ShapeInfo& info) { } */ -bool EntityMotionState::makeStatic() { +bool CustomMotionState::makeStatic() { if (_motionType == MOTION_TYPE_STATIC) { return true; } @@ -43,7 +43,7 @@ bool EntityMotionState::makeStatic() { return false; } -bool EntityMotionState::makeDynamic() { +bool CustomMotionState::makeDynamic() { if (_motionType == MOTION_TYPE_DYNAMIC) { return true; } @@ -54,7 +54,7 @@ bool EntityMotionState::makeDynamic() { return false; } -bool EntityMotionState::makeKinematic() { +bool CustomMotionState::makeKinematic() { if (_motionType == MOTION_TYPE_KINEMATIC) { return true; } diff --git a/libraries/physics/src/CustomMotionState.h b/libraries/physics/src/CustomMotionState.h index b891f93ae3..282c4eaae0 100644 --- a/libraries/physics/src/CustomMotionState.h +++ b/libraries/physics/src/CustomMotionState.h @@ -1,5 +1,5 @@ // -// EntityMotionState.h +// CustomMotionState.h // libraries/physcis/src // // Created by Andrew Meadows 2014.11.05 @@ -9,8 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_EntityMotionState_h -#define hifi_EntityMotionState_h +#ifndef hifi_CustomMotionState_h +#define hifi_CustomMotionState_h #ifdef USE_BULLET_PHYSICS @@ -25,9 +25,9 @@ enum MotionType { MOTION_TYPE_KINEMATIC // keyframed motion }; -class EntityMotionState : public btMotionState { +class CustomMotionState : public btMotionState { public: - EntityMotionState(); + CustomMotionState(); //// these override methods of the btMotionState base class //virtual void getWorldTransform (btTransform &worldTrans) const; @@ -54,4 +54,4 @@ private: }; #endif // USE_BULLET_PHYSICS -#endif // hifi_EntityMotionState_h +#endif // hifi_CustomMotionState_h diff --git a/libraries/physics/src/PhysicsWorld.cpp b/libraries/physics/src/PhysicsWorld.cpp index 0d475f0a84..14387fba32 100644 --- a/libraries/physics/src/PhysicsWorld.cpp +++ b/libraries/physics/src/PhysicsWorld.cpp @@ -76,10 +76,10 @@ bool PhysicsWorld::removeVoxel(const glm::vec3& position, float scale) { return false; } -bool PhysicsWorld::addEntity(const QUuid& id, EntityMotionState* motionState) { +bool PhysicsWorld::addEntity(const QUuid& id, CustomMotionState* motionState) { assert(motionState); UUIDHashKey key(id); - EntityMotionState** statePtr = _entities.find(key); + CustomMotionState** statePtr = _entities.find(key); if (!statePtr) { // BOOKMARK: Andrew to implement this } else { @@ -90,7 +90,7 @@ bool PhysicsWorld::addEntity(const QUuid& id, EntityMotionState* motionState) { bool PhysicsWorld::removeEntity(const QUuid& id) { UUIDHashKey key(id); - EntityMotionState** statePtr = _entities.find(key); + CustomMotionState** statePtr = _entities.find(key); if (statePtr) { // BOOKMARK: Andrew to implement this } diff --git a/libraries/physics/src/PhysicsWorld.h b/libraries/physics/src/PhysicsWorld.h index cfb2d08613..d7ea0436ad 100644 --- a/libraries/physics/src/PhysicsWorld.h +++ b/libraries/physics/src/PhysicsWorld.h @@ -45,7 +45,7 @@ public: /// \return true if Entity added /// \param info information about collision shapes to create - bool addEntity(const QUuid& id, EntityMotionState* motionState); + bool addEntity(const QUuid& id, CustomMotionState* motionState); /// \return true if Entity removed /// \param id UUID of the entity @@ -62,7 +62,7 @@ protected: private: btHashMap _voxels; - btHashMap _entities; + btHashMap _entities; }; From 053b16783cdddfa7213c2d5fe6693cfb32acb38d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 6 Nov 2014 16:42:07 -0800 Subject: [PATCH 019/105] initial impl of PhysicsWorld::addEntity() --- libraries/entities/src/EntityItem.cpp | 15 ++++ libraries/entities/src/EntityItem.h | 8 ++- libraries/entities/src/EntityMotionState.cpp | 56 +++++++++++++++ libraries/entities/src/EntityMotionState.h | 34 +++++++++ libraries/physics/src/CustomMotionState.cpp | 72 +++++++++----------- libraries/physics/src/CustomMotionState.h | 32 +++++---- libraries/physics/src/PhysicsWorld.cpp | 45 ++++++++---- libraries/physics/src/PhysicsWorld.h | 11 +-- 8 files changed, 199 insertions(+), 74 deletions(-) create mode 100644 libraries/entities/src/EntityMotionState.cpp create mode 100644 libraries/entities/src/EntityMotionState.h diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 346070c567..9d32b17dfb 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -21,6 +21,7 @@ #include "EntityScriptingInterface.h" #include "EntityItem.h" +#include "EntityMotionState.h" #include "EntityTree.h" const float EntityItem::IMMORTAL = -1.0f; /// special lifetime which means the entity lives for ever. default lifetime @@ -87,6 +88,9 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) { _lastEditedFromRemoteInRemoteTime = 0; _lastUpdated = 0; _created = 0; +#ifdef USE_BULLET_PHYSICS + _motionState = NULL; +#endif // USE_BULLET_PHYSICS initFromEntityItemID(entityItemID); } @@ -97,10 +101,21 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert _lastEditedFromRemoteInRemoteTime = 0; _lastUpdated = 0; _created = properties.getCreated(); +#ifdef USE_BULLET_PHYSICS + _motionState = NULL; +#endif // USE_BULLET_PHYSICS initFromEntityItemID(entityItemID); setProperties(properties, true); // force copy } +EntityItem::~EntityItem() { +#ifdef USE_BULLET_PHYSICS + // make sure the _motionState is already deleted (e.g. the entity has been removed + // from the physics simulation) BEFORE you get here + assert(_motionState == NULL); +#endif // USE_BULLET_PHYSICS +} + EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index f1d4e42b81..205dc2f165 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -49,7 +49,7 @@ public: EntityItem(const EntityItemID& entityItemID); EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); - virtual ~EntityItem() { } + virtual ~EntityItem(); // ID and EntityItemID related methods QUuid getID() const { return _id; } @@ -260,8 +260,7 @@ public: virtual bool contains(const glm::vec3& point) const { return getAABox().contains(point); } #ifdef USE_BULLET_PHYSICS - //EntityMotionState* createMotionState() = 0; - EntityMotionState* createMotionState() { return NULL; } + virtual EntityMotionState* createMotionState() { return NULL; } #endif // USE_BULLET_PHYSICS protected: @@ -304,6 +303,9 @@ protected: void setRadius(float value); AACubeShape _collisionShape; +#ifdef USE_BULLET_PHYSICS + EntityMotionState* _motionState; +#endif // USE_BULLET_PHYSICS }; diff --git a/libraries/entities/src/EntityMotionState.cpp b/libraries/entities/src/EntityMotionState.cpp new file mode 100644 index 0000000000..1c3266a68e --- /dev/null +++ b/libraries/entities/src/EntityMotionState.cpp @@ -0,0 +1,56 @@ +// +// EntityMotionState.cpp +// libraries/entities/src +// +// Created by Andrew Meadows on 2014.11.06 +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include + +#include "EntityItem.h" +#include "EntityMotionState.h" + +EntityMotionState::EntityMotionState(EntityItem* entity) : _entity(entity) { + assert(entity != NULL); +} + +EntityMotionState::~EntityMotionState() { +} + +// This callback is invoked by the physics simulation in two cases: +// (1) when the RigidBody is first added to the world +// (irregardless of MotionType: STATIC, DYNAMIC, or KINEMATIC) +// (2) at the beginning of each simulation frame for KINEMATIC RigidBody's -- +// it is an opportunity for outside code to update the position of the object +void EntityMotionState::getWorldTransform (btTransform &worldTrans) const { + btVector3 pos; + glmToBullet(_entity->getPosition(), pos); + btQuaternion rot; + glmToBullet(_entity->getRotation(), rot); + worldTrans.setOrigin(pos); + worldTrans.setRotation(rot); +} + +// This callback is invoked by the physics simulation at the end of each simulation frame... +// iff the corresponding RigidBody is DYNAMIC and has moved. +void EntityMotionState::setWorldTransform (const btTransform &worldTrans) { + glm::vec3 pos; + bulletToGLM(worldTrans.getOrigin(), pos); + _entity->setPositionInMeters(pos); + glm::quat rot; + bulletToGLM(worldTrans.getRotation(), rot); + _entity->setRotation(rot); +} + +void EntityMotionState::computeShapeInfo(ShapeInfo& info) { + // HACK: for now we make everything a box. + glm::vec3 halfExtents = _entity->getDimensionsInMeters(); + btVector3 bulletHalfExtents; + glmToBullet(halfExtents, bulletHalfExtents); + info.setBox(bulletHalfExtents); +} + diff --git a/libraries/entities/src/EntityMotionState.h b/libraries/entities/src/EntityMotionState.h new file mode 100644 index 0000000000..8dbb0720e4 --- /dev/null +++ b/libraries/entities/src/EntityMotionState.h @@ -0,0 +1,34 @@ +// +// EntityMotionState.h +// libraries/entities/src +// +// Created by Andrew Meadows on 2014.11.06 +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_EntityMotionState_h +#define hifi_EntityMotionState_h + +#ifdef USE_BULLET_PHYSICS + +#include + +class EntityMotionState : public CustomMotionState { +public: + EntityMotionState(EntityItem* item); + virtual ~EntityMotionState(); + + virtual void getWorldTransform (btTransform &worldTrans) const; + virtual void setWorldTransform (const btTransform &worldTrans); + + virtual void computeShapeInfo(ShapeInfo& info); + +protected: + EntityItem* _entity; +}; + +#endif // USE_BULLET_PHYSICS +#endif // hifi_EntityMotionState_h diff --git a/libraries/physics/src/CustomMotionState.cpp b/libraries/physics/src/CustomMotionState.cpp index bd9d41011c..40175d1366 100644 --- a/libraries/physics/src/CustomMotionState.cpp +++ b/libraries/physics/src/CustomMotionState.cpp @@ -11,58 +11,50 @@ #ifdef USE_BULLET_PHYSICS +#include + #include "CustomMotionState.h" -CustomMotionState::CustomMotionState() : _motionType(MOTION_TYPE_STATIC), - _inertiaDiagLocal(1.0f, 1.0f, 1.0f), _mass(1.0f), - _shape(NULL), _object(NULL) { +const float MIN_DENSITY = 200.0f; +const float DEFAULT_DENSITY = 1000.0f; +const float MAX_DENSITY = 20000.0f; + +const float MIN_VOLUME = 0.001f; +const float DEFAULT_VOLUME = 1.0f; +const float MAX_VOLUME = 1000000.0f; + +const float DEFAULT_FRICTION = 0.5f; +const float MAX_FRICTION = 10.0f; + +const float DEFAULT_RESTITUTION = 0.0f; + +CustomMotionState::CustomMotionState() : + _density(DEFAULT_DENSITY), + _volume(DEFAULT_VOLUME), + _friction(DEFAULT_FRICTION), + _restitution(DEFAULT_RESTITUTION), + _motionType(MOTION_TYPE_STATIC), + _body(NULL) { } -/* -void CustomMotionState::getWorldTransform (btTransform &worldTrans) const { +CustomMotionState::~CustomMotionState() { + assert(_body == NULL); } -void CustomMotionState::setWorldTransform (const btTransform &worldTrans) { +void CustomMotionState::setDensity(float density) { + _density = btMax(btMin(fabsf(density), MAX_DENSITY), MIN_DENSITY); } -void CustomMotionState::computeMassProperties() { +void CustomMotionState::setFriction(float friction) { + _friction = btMax(btMin(fabsf(friction), MAX_FRICTION), 0.0f); } -void CustomMotionState::getShapeInfo(ShapeInfo& info) { -} -*/ - -bool CustomMotionState::makeStatic() { - if (_motionType == MOTION_TYPE_STATIC) { - return true; - } - if (!_object) { - _motionType = MOTION_TYPE_STATIC; - return true; - } - return false; +void CustomMotionState::setRestitution(float restitution) { + _restitution = btMax(btMin(fabsf(restitution), 1.0f), 0.0f); } -bool CustomMotionState::makeDynamic() { - if (_motionType == MOTION_TYPE_DYNAMIC) { - return true; - } - if (!_object) { - _motionType = MOTION_TYPE_DYNAMIC; - return true; - } - return false; -} - -bool CustomMotionState::makeKinematic() { - if (_motionType == MOTION_TYPE_KINEMATIC) { - return true; - } - if (!_object) { - _motionType = MOTION_TYPE_KINEMATIC; - return true; - } - return false; +void CustomMotionState::setVolume(float volume) { + _volume = btMax(btMin(fabsf(volume), MAX_VOLUME), MIN_VOLUME); } #endif // USE_BULLET_PHYSICS diff --git a/libraries/physics/src/CustomMotionState.h b/libraries/physics/src/CustomMotionState.h index 282c4eaae0..88991a4855 100644 --- a/libraries/physics/src/CustomMotionState.h +++ b/libraries/physics/src/CustomMotionState.h @@ -17,7 +17,6 @@ #include #include "ShapeInfo.h" -#include "UUIDHashKey.h" enum MotionType { MOTION_TYPE_STATIC, // no motion @@ -28,29 +27,34 @@ enum MotionType { class CustomMotionState : public btMotionState { public: CustomMotionState(); + ~CustomMotionState(); //// these override methods of the btMotionState base class //virtual void getWorldTransform (btTransform &worldTrans) const; //virtual void setWorldTransform (const btTransform &worldTrans); - virtual void computeMassProperties() = 0; - virtual void getShapeInfo(ShapeInfo& info) = 0; - - bool makeStatic(); - bool makeDynamic(); - bool makeKinematic(); + virtual void computeShapeInfo(ShapeInfo& info) = 0; MotionType getMotionType() const { return _motionType; } -private: - friend class PhysicsWorld; + void setDensity(float density); + void setFriction(float friction); + void setRestitution(float restitution); + void setVolume(float volume); - //EntityItem* _entity; + float getMass() const { return _volume * _density; } + + friend class PhysicsWorld; +protected: + + float _density; + float _volume; + float _friction; + float _restitution; + + // The data members below have NO setters. They are only changed by a PhysicsWorld instance. MotionType _motionType; - btVector3 _inertiaDiagLocal; - float _mass; - btCollisionShape* _shape; - btCollisionObject* _object; + btRigidBody* _body; }; #endif // USE_BULLET_PHYSICS diff --git a/libraries/physics/src/PhysicsWorld.cpp b/libraries/physics/src/PhysicsWorld.cpp index 14387fba32..8c1492360a 100644 --- a/libraries/physics/src/PhysicsWorld.cpp +++ b/libraries/physics/src/PhysicsWorld.cpp @@ -76,23 +76,44 @@ bool PhysicsWorld::removeVoxel(const glm::vec3& position, float scale) { return false; } -bool PhysicsWorld::addEntity(const QUuid& id, CustomMotionState* motionState) { +bool PhysicsWorld::addEntity(CustomMotionState* motionState, float mass) { assert(motionState); - UUIDHashKey key(id); - CustomMotionState** statePtr = _entities.find(key); - if (!statePtr) { - // BOOKMARK: Andrew to implement this - } else { - assert(*statePtr == motionState); + ShapeInfo info; + motionState->computeShapeInfo(info); + btCollisionShape* shape = _shapeManager.getShape(info); + if (shape) { + btVector3 inertia; + shape->calculateLocalInertia(mass, inertia); + btRigidBody* body = new btRigidBody(mass, motionState, shape, inertia); + _dynamicsWorld->addRigidBody(body); + motionState->_body = body; } return false; } -bool PhysicsWorld::removeEntity(const QUuid& id) { - UUIDHashKey key(id); - CustomMotionState** statePtr = _entities.find(key); - if (statePtr) { - // BOOKMARK: Andrew to implement this +bool PhysicsWorld::removeEntity(CustomMotionState* motionState) { + assert(motionState); + btRigidBody* body = motionState->_body; + if (body) { + const btCollisionShape* shape = body->getCollisionShape(); + ShapeInfo info; + info.collectInfo(shape); + _dynamicsWorld->removeRigidBody(body); + _shapeManager.releaseShape(info); + delete body; + motionState->_body = NULL; } return false; } + +bool PhysicsWorld::updateEntityMotionType(CustomMotionState* motionState, MotionType type) { + // TODO: implement this + assert(motionState); + return false; +} + +bool PhysicsWorld::updateEntityMassProperties(CustomMotionState* motionState, float mass, const glm::vec3& inertiaEigenValues) { + // TODO: implement this + assert(motionState); + return false; +} diff --git a/libraries/physics/src/PhysicsWorld.h b/libraries/physics/src/PhysicsWorld.h index d7ea0436ad..0714c72011 100644 --- a/libraries/physics/src/PhysicsWorld.h +++ b/libraries/physics/src/PhysicsWorld.h @@ -20,7 +20,6 @@ #include "CustomMotionState.h" #include "PositionHashKey.h" #include "ShapeManager.h" -#include "UUIDHashKey.h" #include "VoxelObject.h" class PhysicsWorld { @@ -45,11 +44,15 @@ public: /// \return true if Entity added /// \param info information about collision shapes to create - bool addEntity(const QUuid& id, CustomMotionState* motionState); + bool addEntity(CustomMotionState* motionState, float mass); /// \return true if Entity removed /// \param id UUID of the entity - bool removeEntity(const QUuid& id); + bool removeEntity(CustomMotionState* motionState); + + bool updateEntityMotionType(CustomMotionState* motionState, MotionType type); + + bool updateEntityMassProperties(CustomMotionState* motionState, float mass, const glm::vec3& inertiaEigenValues); protected: btDefaultCollisionConfiguration* _collisionConfig; @@ -57,12 +60,10 @@ protected: btBroadphaseInterface* _broadphaseFilter; btSequentialImpulseConstraintSolver* _constraintSolver; btDiscreteDynamicsWorld* _dynamicsWorld; - ShapeManager _shapeManager; private: btHashMap _voxels; - btHashMap _entities; }; From ed90bf00b96387e0ce40b866563688f24bbdeaeb Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 7 Nov 2014 08:51:57 -0800 Subject: [PATCH 020/105] add offset to physics simulation we anticipate floating point error problems at distances far from origin and we don't want the simulation to span a big space anyway so world-frame objects are simulated in a local frame and positions are translated back and forth as necessary --- libraries/entities/src/EntityMotionState.cpp | 22 +++++++++++++++++--- libraries/entities/src/EntityMotionState.h | 3 +++ libraries/physics/src/PhysicsWorld.cpp | 17 ++++++++------- libraries/physics/src/PhysicsWorld.h | 14 +++++++++++-- 4 files changed, 44 insertions(+), 12 deletions(-) diff --git a/libraries/entities/src/EntityMotionState.cpp b/libraries/entities/src/EntityMotionState.cpp index 1c3266a68e..f2bfd5f333 100644 --- a/libraries/entities/src/EntityMotionState.cpp +++ b/libraries/entities/src/EntityMotionState.cpp @@ -14,6 +14,20 @@ #include "EntityItem.h" #include "EntityMotionState.h" +// TODO: store _cachedWorldOffset in a more central location -- VoxelTree and others also need to know about it +// origin of physics simulation in world frame +glm::vec3 _cachedWorldOffset(0.0f); + +// static +void EntityMotionState::setWorldOffset(const glm::vec3& offset) { + _cachedWorldOffset = offset; +} + +// static +const glm::vec3& getWorldOffset() { + return _cachedWorldOffset; +} + EntityMotionState::EntityMotionState(EntityItem* entity) : _entity(entity) { assert(entity != NULL); } @@ -28,10 +42,11 @@ EntityMotionState::~EntityMotionState() { // it is an opportunity for outside code to update the position of the object void EntityMotionState::getWorldTransform (btTransform &worldTrans) const { btVector3 pos; - glmToBullet(_entity->getPosition(), pos); + glmToBullet(_entity->getPosition() - _cachedWorldOffset, pos); + worldTrans.setOrigin(pos); + btQuaternion rot; glmToBullet(_entity->getRotation(), rot); - worldTrans.setOrigin(pos); worldTrans.setRotation(rot); } @@ -40,7 +55,8 @@ void EntityMotionState::getWorldTransform (btTransform &worldTrans) const { void EntityMotionState::setWorldTransform (const btTransform &worldTrans) { glm::vec3 pos; bulletToGLM(worldTrans.getOrigin(), pos); - _entity->setPositionInMeters(pos); + _entity->setPositionInMeters(pos + _cachedWorldOffset); + glm::quat rot; bulletToGLM(worldTrans.getRotation(), rot); _entity->setRotation(rot); diff --git a/libraries/entities/src/EntityMotionState.h b/libraries/entities/src/EntityMotionState.h index 8dbb0720e4..750a5c4b7a 100644 --- a/libraries/entities/src/EntityMotionState.h +++ b/libraries/entities/src/EntityMotionState.h @@ -18,6 +18,9 @@ class EntityMotionState : public CustomMotionState { public: + static void setWorldOffset(const glm::vec3& offset); + static const glm::vec3& getWorldOffset(); + EntityMotionState(EntityItem* item); virtual ~EntityMotionState(); diff --git a/libraries/physics/src/PhysicsWorld.cpp b/libraries/physics/src/PhysicsWorld.cpp index 8c1492360a..22f7b6c0f0 100644 --- a/libraries/physics/src/PhysicsWorld.cpp +++ b/libraries/physics/src/PhysicsWorld.cpp @@ -24,8 +24,8 @@ void PhysicsWorld::init() { bool PhysicsWorld::addVoxel(const glm::vec3& position, float scale) { glm::vec3 halfExtents = glm::vec3(0.5f * scale); - glm::vec3 center = position + halfExtents; - PositionHashKey key(center); + glm::vec3 trueCenter = position + halfExtents; + PositionHashKey key(trueCenter); VoxelObject* proxy = _voxels.find(key); if (!proxy) { // create a shape @@ -40,11 +40,13 @@ bool PhysicsWorld::addVoxel(const glm::vec3& position, float scale) { object->setCollisionShape(shape); btTransform transform; transform.setIdentity(); - transform.setOrigin(btVector3(center.x, center.y, center.z)); + // we shift the center into the simulation's frame + glm::vec3 shiftedCenter = (position - _originOffset) + halfExtents; + transform.setOrigin(btVector3(shiftedCenter.x, shiftedCenter.y, shiftedCenter.z)); object->setWorldTransform(transform); // add to map and world - _voxels.insert(key, VoxelObject(center, object)); + _voxels.insert(key, VoxelObject(trueCenter, object)); _dynamicsWorld->addCollisionObject(object); return true; } @@ -54,8 +56,8 @@ bool PhysicsWorld::addVoxel(const glm::vec3& position, float scale) { bool PhysicsWorld::removeVoxel(const glm::vec3& position, float scale) { glm::vec3 halfExtents = glm::vec3(0.5f * scale); - glm::vec3 center = position + halfExtents; - PositionHashKey key(center); + glm::vec3 trueCenter = position + halfExtents; + PositionHashKey key(trueCenter); VoxelObject* proxy = _voxels.find(key); if (proxy) { // remove from world @@ -85,8 +87,9 @@ bool PhysicsWorld::addEntity(CustomMotionState* motionState, float mass) { btVector3 inertia; shape->calculateLocalInertia(mass, inertia); btRigidBody* body = new btRigidBody(mass, motionState, shape, inertia); - _dynamicsWorld->addRigidBody(body); motionState->_body = body; + // TODO: set dynamic/kinematic/static property from data stored in motionState + _dynamicsWorld->addRigidBody(body); } return false; } diff --git a/libraries/physics/src/PhysicsWorld.h b/libraries/physics/src/PhysicsWorld.h index 0714c72011..0e9fe50791 100644 --- a/libraries/physics/src/PhysicsWorld.h +++ b/libraries/physics/src/PhysicsWorld.h @@ -25,13 +25,22 @@ class PhysicsWorld { public: - PhysicsWorld() : _collisionConfig(NULL), _collisionDispatcher(NULL), - _broadphaseFilter(NULL), _constraintSolver(NULL), _dynamicsWorld(NULL) { } + PhysicsWorld(const glm::vec3& offset) + : _collisionConfig(NULL), + _collisionDispatcher(NULL), + _broadphaseFilter(NULL), + _constraintSolver(NULL), + _dynamicsWorld(NULL), + _originOffset(offset), + _voxels() { + } ~PhysicsWorld(); void init(); + const glm::vec3& getOriginOffset() const { return _originOffset; } + /// \return true if Voxel added /// \param position the minimum corner of the voxel /// \param scale the length of the voxel side @@ -63,6 +72,7 @@ protected: ShapeManager _shapeManager; private: + glm::vec3 _originOffset; btHashMap _voxels; }; From 82d7b70ec979ee9003f3eb2b1e837f755e5f1d33 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 11 Nov 2014 10:56:31 -0800 Subject: [PATCH 021/105] add offset to physics simulation --- interface/CMakeLists.txt | 1 + interface/src/Application.cpp | 25 ++++++++++++++++++++++++- interface/src/Application.h | 6 ++++++ libraries/physics/src/PhysicsWorld.h | 14 ++++++++++---- 4 files changed, 41 insertions(+), 5 deletions(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index eb788ac49a..f9b6fedfe1 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -38,6 +38,7 @@ endif () # set up the external glm library include_glm() +include_bullet() # create the InterfaceConfig.h file based on GL_HEADERS above configure_file(InterfaceConfig.h.in "${PROJECT_BINARY_DIR}/includes/InterfaceConfig.h") diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ff4a23ceaf..df13e26eae 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -153,6 +153,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _entityClipboardRenderer(false), _entityClipboard(), _wantToKillLocalVoxels(false), +#ifdef USE_BULLET_PHYSICS + _physicsWorld(glm::vec3(0.0f)), +#endif // USE_BULLET_PHYSICS _viewFrustum(), _lastQueriedViewFrustum(), _lastQueriedTime(usecTimestampNow()), @@ -1987,7 +1990,7 @@ void Application::init() { &AudioDeviceScriptingInterface::muteToggled, Qt::DirectConnection); // save settings when avatar changes - connect(_myAvatar, &MyAvatar::transformChanged, this, &Application::bumpSettings); + connect(_myAvatar, &MyAvatar::transformChanged, this, &Application::updateMyAvatarTransform); } void Application::closeMirrorView() { @@ -4059,6 +4062,26 @@ void Application::openUrl(const QUrl& url) { } } +void Application::updateMyAvatarTransform() { + bumpSettings(); +#ifdef USE_BULLET_PHYSICS + const float SIMULATION_OFFSET_QUANTIZATION = 8.0f; // meters + glm::vec3 avatarPosition = _myAvatar->getPosition(); + glm::vec3 physicsWorldOffset = _physicsWorld.getOriginOffset(); + if (glm::distance(avatarPosition, physicsWorldOffset) > HALF_SIMULATION_EXTENT) { + //_entityCollisionSystem.forgetAllPhysics(); + glm::vec3 newOriginOffset = avatarPosition; + int halfExtent = (int)HALF_SIMULATION_EXENT; + for (int i = 0; i < 3; ++i) { + newOriginOffset[i] = (float)(glm::max(halfExtent, + ((int)(avatarPosition[i] / SIMULATION_OFFSET_QUANTIZATION)) * (int)SIMULATION_OFFSET_QUANTIZATION)); + } + _physicsWorld.setOriginOffset(newOrigin); + //_entityCollisionSystem.rememberAllPhysics(); + } +#endif // USE_BULLET_PHYSICS +} + void Application::domainSettingsReceived(const QJsonObject& domainSettingsObject) { // from the domain-handler, figure out the satoshi cost per voxel and per meter cubed diff --git a/interface/src/Application.h b/interface/src/Application.h index d92333058f..e9361a577a 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -368,6 +369,7 @@ public slots: void openUrl(const QUrl& url); + void updateMyAvatarTransform(); void bumpSettings() { ++_numChangedSettings; } void domainSettingsReceived(const QJsonObject& domainSettingsObject); @@ -498,6 +500,10 @@ private: MetavoxelSystem _metavoxels; +#ifdef USE_BULLET_PHYSICS + PhysicsWorld _physicsWorld; +#endif // USE_BULLET_PHYSICS + ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc. ViewFrustum _lastQueriedViewFrustum; /// last view frustum used to query octree servers (voxels) ViewFrustum _displayViewFrustum; diff --git a/libraries/physics/src/PhysicsWorld.h b/libraries/physics/src/PhysicsWorld.h index 0e9fe50791..e599b4f8a8 100644 --- a/libraries/physics/src/PhysicsWorld.h +++ b/libraries/physics/src/PhysicsWorld.h @@ -22,6 +22,8 @@ #include "ShapeManager.h" #include "VoxelObject.h" +const float HALF_SIMULATION_EXTENT = 512.0f; // meters + class PhysicsWorld { public: @@ -39,24 +41,28 @@ public: void init(); + /// \param offset position of simulation origin in domain-frame + void setOriginOffset(const glm::vec3& offset) { _originOffset = offset; } + + /// \return position of simulation origin in domain-frame const glm::vec3& getOriginOffset() const { return _originOffset; } - /// \return true if Voxel added /// \param position the minimum corner of the voxel /// \param scale the length of the voxel side + /// \return true if Voxel added bool addVoxel(const glm::vec3& position, float scale); - /// \return true if Voxel removed /// \param position the minimum corner of the voxel /// \param scale the length of the voxel side + /// \return true if Voxel removed bool removeVoxel(const glm::vec3& position, float scale); - /// \return true if Entity added /// \param info information about collision shapes to create + /// \return true if Entity added bool addEntity(CustomMotionState* motionState, float mass); - /// \return true if Entity removed /// \param id UUID of the entity + /// \return true if Entity removed bool removeEntity(CustomMotionState* motionState); bool updateEntityMotionType(CustomMotionState* motionState, MotionType type); From 1ffb22e2de1cd0b4a28384c7e5393531469e7829 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 11 Nov 2014 10:56:52 -0800 Subject: [PATCH 022/105] stubbery for BoxEntityImtem::createMotionState() --- libraries/entities/src/BoxEntityItem.cpp | 17 +++++++++++++++-- libraries/entities/src/BoxEntityItem.h | 10 +++++++--- libraries/entities/src/EntityMotionState.cpp | 2 +- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/BoxEntityItem.cpp b/libraries/entities/src/BoxEntityItem.cpp index 83d6d7eff9..1aaa440481 100644 --- a/libraries/entities/src/BoxEntityItem.cpp +++ b/libraries/entities/src/BoxEntityItem.cpp @@ -14,9 +14,10 @@ #include +#include "BoxEntityItem.h" +#include "EntityMotionState.h" #include "EntityTree.h" #include "EntityTreeElement.h" -#include "BoxEntityItem.h" EntityItem* BoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { @@ -94,4 +95,16 @@ void BoxEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitst bool successPropertyFits = true; APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor()); -} \ No newline at end of file +} + +#ifdef USE_BULLET_PHYSICS +// BOOKMARK: move EntityMotionState implementation to Entities +// also define interface for it (dunno what to call it) +EntityMotionState* BoxEntityItem::createMotionState() { + if (!_motionState) { + _motionState = new EntityMotionState(this); + } + return _motionState; +} +#endif // USE_BULLET_PHYSICS + diff --git a/libraries/entities/src/BoxEntityItem.h b/libraries/entities/src/BoxEntityItem.h index b5f4521f96..faae308b43 100644 --- a/libraries/entities/src/BoxEntityItem.h +++ b/libraries/entities/src/BoxEntityItem.h @@ -46,11 +46,15 @@ public: void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); } void setColor(const xColor& value) { - _color[RED_INDEX] = value.red; - _color[GREEN_INDEX] = value.green; - _color[BLUE_INDEX] = value.blue; + _color[RED_INDEX] = value.red; + _color[GREEN_INDEX] = value.green; + _color[BLUE_INDEX] = value.blue; } +#ifdef USE_BULLET_PHYSICS + EntityMotionState* createMotionState(); +#endif // USE_BULLET_PHYSICS + protected: rgbColor _color; }; diff --git a/libraries/entities/src/EntityMotionState.cpp b/libraries/entities/src/EntityMotionState.cpp index f2bfd5f333..f9ff7291d9 100644 --- a/libraries/entities/src/EntityMotionState.cpp +++ b/libraries/entities/src/EntityMotionState.cpp @@ -39,7 +39,7 @@ EntityMotionState::~EntityMotionState() { // (1) when the RigidBody is first added to the world // (irregardless of MotionType: STATIC, DYNAMIC, or KINEMATIC) // (2) at the beginning of each simulation frame for KINEMATIC RigidBody's -- -// it is an opportunity for outside code to update the position of the object +// it is an opportunity for outside code to update the object's simulation position void EntityMotionState::getWorldTransform (btTransform &worldTrans) const { btVector3 pos; glmToBullet(_entity->getPosition() - _cachedWorldOffset, pos); From 0d0f98f669f428508951a32de252e19389d32a44 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 11 Nov 2014 12:09:59 -0800 Subject: [PATCH 023/105] init and step physics simulation --- interface/src/Application.cpp | 11 +++++++++++ libraries/physics/src/PhysicsWorld.cpp | 11 +++++++++++ libraries/physics/src/PhysicsWorld.h | 3 +++ 3 files changed, 25 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5abb826f45..f0b4afe90a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2009,6 +2009,10 @@ void Application::init() { // save settings when avatar changes connect(_myAvatar, &MyAvatar::transformChanged, this, &Application::updateMyAvatarTransform); + +#ifdef USE_BULLET_PHYSICS + _physicsWorld.init(); +#endif // USE_BULLET_PHYSICS } void Application::closeMirrorView() { @@ -2314,6 +2318,13 @@ void Application::update(float deltaTime) { updateDialogs(deltaTime); // update various stats dialogs if present updateCursor(deltaTime); // Handle cursor updates +#ifdef USE_BULLET_PHYSICS + { + PerformanceTimer perfTimer("physics"); + _physicsWorld.stepSimulation(); + } +#endif // USE_BULLET_PHYSICS + { PerformanceTimer perfTimer("entities"); _entities.update(); // update the models... diff --git a/libraries/physics/src/PhysicsWorld.cpp b/libraries/physics/src/PhysicsWorld.cpp index 22f7b6c0f0..72d2786350 100644 --- a/libraries/physics/src/PhysicsWorld.cpp +++ b/libraries/physics/src/PhysicsWorld.cpp @@ -22,6 +22,17 @@ void PhysicsWorld::init() { _dynamicsWorld = new btDiscreteDynamicsWorld(_collisionDispatcher, _broadphaseFilter, _constraintSolver, _collisionConfig); } +void PhysicsWorld::stepSimulation() { + const float MAX_TIMESTEP = 1.0f / 30.0f; + const int MAX_NUM_SUBSTEPS = 2; + const float FIXED_SUBSTEP = 1.0f / 60.0f; + + float dt = 1.0e-6f * (float)(_clock.getTimeMicroseconds()); + _clock.reset(); + float timeStep = btMin(dt, MAX_TIMESTEP); + _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, FIXED_SUBSTEP); +} + bool PhysicsWorld::addVoxel(const glm::vec3& position, float scale) { glm::vec3 halfExtents = glm::vec3(0.5f * scale); glm::vec3 trueCenter = position + halfExtents; diff --git a/libraries/physics/src/PhysicsWorld.h b/libraries/physics/src/PhysicsWorld.h index e599b4f8a8..e18b87c91c 100644 --- a/libraries/physics/src/PhysicsWorld.h +++ b/libraries/physics/src/PhysicsWorld.h @@ -41,6 +41,8 @@ public: void init(); + void stepSimulation(); + /// \param offset position of simulation origin in domain-frame void setOriginOffset(const glm::vec3& offset) { _originOffset = offset; } @@ -70,6 +72,7 @@ public: bool updateEntityMassProperties(CustomMotionState* motionState, float mass, const glm::vec3& inertiaEigenValues); protected: + btClock _clock; btDefaultCollisionConfiguration* _collisionConfig; btCollisionDispatcher* _collisionDispatcher; btBroadphaseInterface* _broadphaseFilter; From 7c53c7a4959e0d73f78d0a08c3fe3590639ae31f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 11 Nov 2014 12:24:29 -0800 Subject: [PATCH 024/105] fix build to work when cmake does not fiind Bullet --- libraries/entities/src/EntityMotionState.cpp | 2 ++ libraries/physics/src/BulletUtil.h | 3 +++ libraries/physics/src/PhysicsWorld.cpp | 3 +++ tests/physics/src/BulletUtilTests.cpp | 11 +++++++++++ 4 files changed, 19 insertions(+) diff --git a/libraries/entities/src/EntityMotionState.cpp b/libraries/entities/src/EntityMotionState.cpp index f9ff7291d9..067583209e 100644 --- a/libraries/entities/src/EntityMotionState.cpp +++ b/libraries/entities/src/EntityMotionState.cpp @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#ifdef USE_BULLET_PHYSICS #include #include "EntityItem.h" @@ -70,3 +71,4 @@ void EntityMotionState::computeShapeInfo(ShapeInfo& info) { info.setBox(bulletHalfExtents); } +#endif // USE_BULLET_PHYSICS diff --git a/libraries/physics/src/BulletUtil.h b/libraries/physics/src/BulletUtil.h index 36b3960521..41d78dd97e 100644 --- a/libraries/physics/src/BulletUtil.h +++ b/libraries/physics/src/BulletUtil.h @@ -12,6 +12,8 @@ #ifndef hifi_BulletUtil_h #define hifi_BulletUtil_h +#ifdef USE_BULLET_PHYSICS + #include #include #include @@ -37,4 +39,5 @@ inline void glmToBullet(const glm::quat& g, btQuaternion& b) { b = btQuaternion(g.x, g.y, g.z, g.w); } +#endif // USE_BULLET_PHYSICS #endif // hifi_BulletUtil_h diff --git a/libraries/physics/src/PhysicsWorld.cpp b/libraries/physics/src/PhysicsWorld.cpp index 72d2786350..230e510729 100644 --- a/libraries/physics/src/PhysicsWorld.cpp +++ b/libraries/physics/src/PhysicsWorld.cpp @@ -10,6 +10,7 @@ // #include "PhysicsWorld.h" +#ifdef USE_BULLET_PHYSICS PhysicsWorld::~PhysicsWorld() { } @@ -131,3 +132,5 @@ bool PhysicsWorld::updateEntityMassProperties(CustomMotionState* motionState, fl assert(motionState); return false; } + +#endif // USE_BULLET_PHYSICS diff --git a/tests/physics/src/BulletUtilTests.cpp b/tests/physics/src/BulletUtilTests.cpp index 5486870196..823d0d01b2 100644 --- a/tests/physics/src/BulletUtilTests.cpp +++ b/tests/physics/src/BulletUtilTests.cpp @@ -16,6 +16,7 @@ #include "BulletUtilTests.h" +#ifdef USE_BULLET_PHYSICS void BulletUtilTests::fromBulletToGLM() { btVector3 bV(1.23f, 4.56f, 7.89f); glm::vec3 gV; @@ -105,3 +106,13 @@ void BulletUtilTests::runAllTests() { fromGLMToBullet(); } +#else // USE_BULLET_PHYSICS +void BulletUtilTests::fromBulletToGLM() { +} + +void BulletUtilTests::fromGLMToBullet() { +} + +void BulletUtilTests::runAllTests() { +} +#endif // USE_BULLET_PHYSICS From ccc315658704eb578fc739796e5ed7822d5ce256 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 11 Nov 2014 17:28:42 -0800 Subject: [PATCH 025/105] PhysicsWorld::addEntity() doesn't need mass arg --- libraries/physics/src/PhysicsWorld.cpp | 3 ++- libraries/physics/src/PhysicsWorld.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/PhysicsWorld.cpp b/libraries/physics/src/PhysicsWorld.cpp index 230e510729..5541622a66 100644 --- a/libraries/physics/src/PhysicsWorld.cpp +++ b/libraries/physics/src/PhysicsWorld.cpp @@ -90,13 +90,14 @@ bool PhysicsWorld::removeVoxel(const glm::vec3& position, float scale) { return false; } -bool PhysicsWorld::addEntity(CustomMotionState* motionState, float mass) { +bool PhysicsWorld::addEntity(CustomMotionState* motionState) { assert(motionState); ShapeInfo info; motionState->computeShapeInfo(info); btCollisionShape* shape = _shapeManager.getShape(info); if (shape) { btVector3 inertia; + float mass = motionState->getMass(); shape->calculateLocalInertia(mass, inertia); btRigidBody* body = new btRigidBody(mass, motionState, shape, inertia); motionState->_body = body; diff --git a/libraries/physics/src/PhysicsWorld.h b/libraries/physics/src/PhysicsWorld.h index e18b87c91c..0c508af2da 100644 --- a/libraries/physics/src/PhysicsWorld.h +++ b/libraries/physics/src/PhysicsWorld.h @@ -61,7 +61,7 @@ public: /// \param info information about collision shapes to create /// \return true if Entity added - bool addEntity(CustomMotionState* motionState, float mass); + bool addEntity(CustomMotionState* motionState); /// \param id UUID of the entity /// \return true if Entity removed From 9e5007a0a339de86bc08dcf47b17e57a6b8e15ce Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 11 Nov 2014 17:31:27 -0800 Subject: [PATCH 026/105] added a comment --- libraries/physics/src/CustomMotionState.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/physics/src/CustomMotionState.cpp b/libraries/physics/src/CustomMotionState.cpp index 40175d1366..07f1895a30 100644 --- a/libraries/physics/src/CustomMotionState.cpp +++ b/libraries/physics/src/CustomMotionState.cpp @@ -38,6 +38,7 @@ CustomMotionState::CustomMotionState() : } CustomMotionState::~CustomMotionState() { + // NOTE: you MUST remove this MotionState from the world before you call the dtor. assert(_body == NULL); } From 66857b823f070785be1704e10aca13f397944632 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 11 Nov 2014 17:34:00 -0800 Subject: [PATCH 027/105] EntityTree has a PhysicsWorld --- libraries/entities/src/BoxEntityItem.cpp | 2 + .../entities/src/DeleteEntityOperator.cpp | 1 + libraries/entities/src/EntityItem.cpp | 193 +++++++++--------- libraries/entities/src/EntityItem.h | 2 + libraries/entities/src/EntityMotionState.cpp | 7 + libraries/entities/src/EntityMotionState.h | 3 + libraries/entities/src/EntityTree.cpp | 43 +++- libraries/entities/src/EntityTree.h | 8 + 8 files changed, 164 insertions(+), 95 deletions(-) diff --git a/libraries/entities/src/BoxEntityItem.cpp b/libraries/entities/src/BoxEntityItem.cpp index 1aaa440481..f7d53ad499 100644 --- a/libraries/entities/src/BoxEntityItem.cpp +++ b/libraries/entities/src/BoxEntityItem.cpp @@ -103,6 +103,8 @@ void BoxEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitst EntityMotionState* BoxEntityItem::createMotionState() { if (!_motionState) { _motionState = new EntityMotionState(this); + glm::vec3 extents = getDimensionsInMeters(); + _motionState->setVolume(extents.x * extents.y * extents.z); } return _motionState; } diff --git a/libraries/entities/src/DeleteEntityOperator.cpp b/libraries/entities/src/DeleteEntityOperator.cpp index 5b0ada4ec1..18dd8ed629 100644 --- a/libraries/entities/src/DeleteEntityOperator.cpp +++ b/libraries/entities/src/DeleteEntityOperator.cpp @@ -102,6 +102,7 @@ bool DeleteEntityOperator::preRecursion(OctreeElement* element) { EntityItem* theEntity = entityTreeElement->getEntityWithEntityItemID(entityItemID); // find the actual entity entityTreeElement->removeEntityItem(theEntity); // remove it from the element _tree->setContainingElement(entityItemID, NULL); // update or id to element lookup + _tree->removeEntityFromPhysicsWorld(theEntity); delete theEntity; // now actually delete the entity! _foundCount++; } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index a65d7519a5..7e9b1de05c 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -623,104 +623,106 @@ void EntityItem::update(const quint64& updateTime) { qDebug() << " ********** EntityItem::update() .... SETTING _lastUpdated=" << _lastUpdated; } - if (hasAngularVelocity()) { - glm::quat rotation = getRotation(); - glm::vec3 angularVelocity = glm::radians(getAngularVelocity()); - float angularSpeed = glm::length(angularVelocity); - - if (angularSpeed < EPSILON_VELOCITY_LENGTH) { - setAngularVelocity(NO_ANGULAR_VELOCITY); - } else { - float angle = timeElapsed * angularSpeed; - glm::quat dQ = glm::angleAxis(angle, glm::normalize(angularVelocity)); - rotation = dQ * rotation; - setRotation(rotation); - - // handle damping for angular velocity - if (getAngularDamping() > 0.0f) { - glm::vec3 dampingResistance = getAngularVelocity() * getAngularDamping(); - glm::vec3 newAngularVelocity = getAngularVelocity() - (dampingResistance * timeElapsed); - setAngularVelocity(newAngularVelocity); - if (wantDebug) { - qDebug() << " getDamping():" << getDamping(); - qDebug() << " dampingResistance:" << dampingResistance; - qDebug() << " newAngularVelocity:" << newAngularVelocity; + if (!_motionState) { + if (hasAngularVelocity()) { + glm::quat rotation = getRotation(); + glm::vec3 angularVelocity = glm::radians(getAngularVelocity()); + float angularSpeed = glm::length(angularVelocity); + + if (angularSpeed < EPSILON_VELOCITY_LENGTH) { + setAngularVelocity(NO_ANGULAR_VELOCITY); + } else { + float angle = timeElapsed * angularSpeed; + glm::quat dQ = glm::angleAxis(angle, glm::normalize(angularVelocity)); + rotation = dQ * rotation; + setRotation(rotation); + + // handle damping for angular velocity + if (getAngularDamping() > 0.0f) { + glm::vec3 dampingResistance = getAngularVelocity() * getAngularDamping(); + glm::vec3 newAngularVelocity = getAngularVelocity() - (dampingResistance * timeElapsed); + setAngularVelocity(newAngularVelocity); + if (wantDebug) { + qDebug() << " getDamping():" << getDamping(); + qDebug() << " dampingResistance:" << dampingResistance; + qDebug() << " newAngularVelocity:" << newAngularVelocity; + } } } } - } - - if (hasVelocity() || hasGravity()) { - glm::vec3 position = getPosition(); - glm::vec3 velocity = getVelocity(); - glm::vec3 newPosition = position + (velocity * timeElapsed); - - if (wantDebug) { - qDebug() << " EntityItem::update()...."; - qDebug() << " timeElapsed:" << timeElapsed; - qDebug() << " old AACube:" << getMaximumAACube(); - qDebug() << " old position:" << position; - qDebug() << " old velocity:" << velocity; - qDebug() << " old getAABox:" << getAABox(); - qDebug() << " getDistanceToBottomOfEntity():" << getDistanceToBottomOfEntity() * (float)TREE_SCALE << " in meters"; - qDebug() << " newPosition:" << newPosition; - qDebug() << " glm::distance(newPosition, position):" << glm::distance(newPosition, position); - } - - position = newPosition; - - // handle bounces off the ground... We bounce at the distance to the bottom of our entity - if (position.y <= getDistanceToBottomOfEntity()) { - velocity = velocity * glm::vec3(1,-1,1); - - // if we've slowed considerably, then just stop moving + + if (hasVelocity() || hasGravity()) { + glm::vec3 position = getPosition(); + glm::vec3 velocity = getVelocity(); + glm::vec3 newPosition = position + (velocity * timeElapsed); + + if (wantDebug) { + qDebug() << " EntityItem::update()...."; + qDebug() << " timeElapsed:" << timeElapsed; + qDebug() << " old AACube:" << getMaximumAACube(); + qDebug() << " old position:" << position; + qDebug() << " old velocity:" << velocity; + qDebug() << " old getAABox:" << getAABox(); + qDebug() << " getDistanceToBottomOfEntity():" << getDistanceToBottomOfEntity() * (float)TREE_SCALE << " in meters"; + qDebug() << " newPosition:" << newPosition; + qDebug() << " glm::distance(newPosition, position):" << glm::distance(newPosition, position); + } + + position = newPosition; + + // handle bounces off the ground... We bounce at the distance to the bottom of our entity + if (position.y <= getDistanceToBottomOfEntity()) { + velocity = velocity * glm::vec3(1,-1,1); + + // if we've slowed considerably, then just stop moving + if (glm::length(velocity) <= EPSILON_VELOCITY_LENGTH) { + velocity = NO_VELOCITY; + } + + position.y = getDistanceToBottomOfEntity(); + } + + // handle gravity.... + if (hasGravity() && !isRestingOnSurface()) { + velocity += getGravity() * timeElapsed; + } + + // handle resting on surface case, this is definitely a bit of a hack, and it only works on the + // "ground" plane of the domain, but for now it + if (hasGravity() && isRestingOnSurface()) { + velocity.y = 0.0f; + position.y = getDistanceToBottomOfEntity(); + } + + // handle damping for velocity + glm::vec3 dampingResistance = velocity * getDamping(); + if (wantDebug) { + qDebug() << " getDamping():" << getDamping(); + qDebug() << " dampingResistance:" << dampingResistance; + qDebug() << " dampingResistance * timeElapsed:" << dampingResistance * timeElapsed; + } + velocity -= dampingResistance * timeElapsed; + + if (wantDebug) { + qDebug() << " velocity AFTER dampingResistance:" << velocity; + qDebug() << " glm::length(velocity):" << glm::length(velocity); + qDebug() << " EPSILON_VELOCITY_LENGTH:" << EPSILON_VELOCITY_LENGTH; + } + + // round velocity to zero if it's close enough... if (glm::length(velocity) <= EPSILON_VELOCITY_LENGTH) { velocity = NO_VELOCITY; } + + setPosition(position); // this will automatically recalculate our collision shape + setVelocity(velocity); - position.y = getDistanceToBottomOfEntity(); - } - - // handle gravity.... - if (hasGravity() && !isRestingOnSurface()) { - velocity += getGravity() * timeElapsed; - } - - // handle resting on surface case, this is definitely a bit of a hack, and it only works on the - // "ground" plane of the domain, but for now it - if (hasGravity() && isRestingOnSurface()) { - velocity.y = 0.0f; - position.y = getDistanceToBottomOfEntity(); - } - - // handle damping for velocity - glm::vec3 dampingResistance = velocity * getDamping(); - if (wantDebug) { - qDebug() << " getDamping():" << getDamping(); - qDebug() << " dampingResistance:" << dampingResistance; - qDebug() << " dampingResistance * timeElapsed:" << dampingResistance * timeElapsed; - } - velocity -= dampingResistance * timeElapsed; - - if (wantDebug) { - qDebug() << " velocity AFTER dampingResistance:" << velocity; - qDebug() << " glm::length(velocity):" << glm::length(velocity); - qDebug() << " EPSILON_VELOCITY_LENGTH:" << EPSILON_VELOCITY_LENGTH; - } - - // round velocity to zero if it's close enough... - if (glm::length(velocity) <= EPSILON_VELOCITY_LENGTH) { - velocity = NO_VELOCITY; - } - - setPosition(position); // this will automatically recalculate our collision shape - setVelocity(velocity); - - if (wantDebug) { - qDebug() << " new position:" << position; - qDebug() << " new velocity:" << velocity; - qDebug() << " new AACube:" << getMaximumAACube(); - qDebug() << " old getAABox:" << getAABox(); + if (wantDebug) { + qDebug() << " new position:" << position; + qDebug() << " new velocity:" << velocity; + qDebug() << " new AACube:" << getMaximumAACube(); + qDebug() << " old getAABox:" << getAABox(); + } } } } @@ -954,6 +956,15 @@ void EntityItem::recalculateCollisionShape() { entityAACube.scale(TREE_SCALE); // scale to meters _collisionShape.setTranslation(entityAACube.calcCenter()); _collisionShape.setScale(entityAACube.getScale()); + // TODO: use motionState to update physics object } +#ifdef USE_BULLET_PHYSICS +void EntityItem::destroyMotionState() { + if (_motionState) { + delete _motionState; + _motionState = NULL; + } +} +#endif // USE_BULLET_PHYSICS diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index d24e12434b..6514fb032a 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -264,7 +264,9 @@ public: virtual bool contains(const glm::vec3& point) const { return getAABox().contains(point); } #ifdef USE_BULLET_PHYSICS + EntityMotionState* getMotionState() const { return _motionState; } virtual EntityMotionState* createMotionState() { return NULL; } + void destroyMotionState(); #endif // USE_BULLET_PHYSICS protected: diff --git a/libraries/entities/src/EntityMotionState.cpp b/libraries/entities/src/EntityMotionState.cpp index 067583209e..ea788500ef 100644 --- a/libraries/entities/src/EntityMotionState.cpp +++ b/libraries/entities/src/EntityMotionState.cpp @@ -31,6 +31,7 @@ const glm::vec3& getWorldOffset() { EntityMotionState::EntityMotionState(EntityItem* entity) : _entity(entity) { assert(entity != NULL); + _oldBoundingCube = _entity->getMaximumAACube(); } EntityMotionState::~EntityMotionState() { @@ -71,4 +72,10 @@ void EntityMotionState::computeShapeInfo(ShapeInfo& info) { info.setBox(bulletHalfExtents); } +void EntityMotionState::getBoundingCubes(AACube& oldCube, AACube& newCube) { + oldCube = _oldBoundingCube; + newCube = _entity->getMaximumAACube(); + _oldBoundingCube = newCube; +} + #endif // USE_BULLET_PHYSICS diff --git a/libraries/entities/src/EntityMotionState.h b/libraries/entities/src/EntityMotionState.h index 750a5c4b7a..a6cfa86887 100644 --- a/libraries/entities/src/EntityMotionState.h +++ b/libraries/entities/src/EntityMotionState.h @@ -29,8 +29,11 @@ public: virtual void computeShapeInfo(ShapeInfo& info); + void getBoundingCubes(AACube& oldCube, AACube& newCube); + protected: EntityItem* _entity; + AACube _oldBoundingCube; }; #endif // USE_BULLET_PHYSICS diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 199bd92030..44e5446924 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -10,15 +10,17 @@ // #include +#include #include "EntityTree.h" #include "AddEntityOperator.h" #include "DeleteEntityOperator.h" +#include "EntityMotionState.h" #include "MovingEntitiesOperator.h" #include "UpdateEntityOperator.h" -EntityTree::EntityTree(bool shouldReaverage) : Octree(shouldReaverage) { +EntityTree::EntityTree(bool shouldReaverage) : Octree(shouldReaverage), _physicsWorld(NULL) { _rootElement = createNewElement(); } @@ -184,6 +186,13 @@ void EntityTree::trackDeletedEntity(const EntityItemID& entityID) { } } +void EntityTree::setPhysicsWorld(PhysicsWorld* world) { + if (_physicsWorld) { + // TODO: remove all entities before we clear the world + } + _physicsWorld = world; +} + void EntityTree::deleteEntity(const EntityItemID& entityID) { emit deletingEntity(entityID); @@ -588,6 +597,9 @@ void EntityTree::changeEntityState(EntityItem* const entity, case EntityItem::Moving: _movingEntities.push_back(entity); + if (_physicsWorld && !entity->getMotionState()) { + addEntityToPhysicsWorld(entity); + } break; case EntityItem::Mortal: @@ -599,6 +611,23 @@ void EntityTree::changeEntityState(EntityItem* const entity, } } +void EntityTree::addEntityToPhysicsWorld(EntityItem* entity) { + EntityMotionState* motionState = entity->createMotionState(); + if (!_physicsWorld->addEntity(static_cast(motionState))) { + // failed to add to world: probably because of bad shape, + // probably because entity is too big or too small + entity->destroyMotionState(); + } +} + +void EntityTree::removeEntityFromPhysicsWorld(EntityItem* entity) { + EntityMotionState* motionState = entity->getMotionState(); + if (motionState) { + _physicsWorld->removeEntity(static_cast(motionState)); + entity->destroyMotionState(); + } +} + void EntityTree::update() { // our new strategy should be to segregate entities into three classes: // 1) stationary things that are not changing - most models @@ -684,9 +713,15 @@ void EntityTree::updateMovingEntities(quint64 now, QSet& entitiesT entitiesToDelete << thisEntity->getEntityItemID(); entitiesBecomingStatic << thisEntity; } else { - AACube oldCube = thisEntity->getMaximumAACube(); - thisEntity->update(now); - AACube newCube = thisEntity->getMaximumAACube(); + AACube oldCube, newCube; + EntityMotionState* motionState = thisEntity->getMotionState(); + if (motionState) { + motionState->getBoundingCubes(oldCube, newCube); + } else { + oldCube = thisEntity->getMaximumAACube(); + thisEntity->update(now); + newCube = thisEntity->getMaximumAACube(); + } // check to see if this movement has sent the entity outside of the domain. AACube domainBounds(glm::vec3(0.0f,0.0f,0.0f), 1.0f); diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 8d1acc0d01..2aebe520c8 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -17,6 +17,7 @@ class Model; +class PhysicsWorld; class NewlyCreatedEntityHook { public: @@ -138,9 +139,14 @@ public: void changeEntityState(EntityItem* const entity, EntityItem::SimulationState oldState, EntityItem::SimulationState newState); + void addEntityToPhysicsWorld(EntityItem* entity); + void removeEntityFromPhysicsWorld(EntityItem* entity); + void trackDeletedEntity(const EntityItemID& entityID); QList& getMovingEntities() { return _movingEntities; } + + void setPhysicsWorld(PhysicsWorld* world); signals: void deletingEntity(const EntityItemID& entityID); @@ -170,6 +176,8 @@ private: QList _movingEntities; // entities that are moving as part of update QList _changingEntities; // entities that are changing (like animating), but not moving QList _mortalEntities; // entities that are mortal (have lifetime), but not moving or changing + + PhysicsWorld* _physicsWorld; }; #endif // hifi_EntityTree_h From 0117233ed4482d2b6592a9a7319319844be985c6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 12 Nov 2014 15:19:33 -0800 Subject: [PATCH 028/105] add ThreadSafeDynamicsWorld pure virtual interface --- .../physics/src/ThreadSafeDynamicsWorld.cpp | 83 +++++++++++++++++++ .../physics/src/ThreadSafeDynamicsWorld.h | 44 ++++++++++ 2 files changed, 127 insertions(+) create mode 100644 libraries/physics/src/ThreadSafeDynamicsWorld.cpp create mode 100644 libraries/physics/src/ThreadSafeDynamicsWorld.h diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp new file mode 100644 index 0000000000..54bea0fff5 --- /dev/null +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp @@ -0,0 +1,83 @@ +/* + * Bullet Continuous Collision Detection and Physics Library + * Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it freely, + * subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * Copied and modified from btDiscreteDynamicsWorld.cpp by AndrewMeadows on 2014.11.12. + * */ + +#include "ThreadSafeDynamicsWorld.h" + +ThreadSafeDynamicsWorld::ThreadSafeDynamicsWorld( + btDispatcher* dispatcher, + btBroadphaseInterface* pairCache, + btConstraintSolver* constraintSolver, + btCollisionConfiguration* collisionConfiguration) + : btDiscreteDynamicsWorld(dispatcher, pairCache, constraintSolver, collisionConfiguration) { +} + +void ThreadSafeDynamicsWorld::synchronizeMotionStates() { + if (tryLock()) { + btDiscreteDynamicsWorld::synchronizeMotionStates(); + unlock(); + } +} + +int ThreadSafeDynamicsWorld::stepSimulation( btScalar timeStep, int maxSubSteps, btScalar fixedTimeStep) { + int subSteps = 0; + if (maxSubSteps) { + //fixed timestep with interpolation + m_fixedTimeStep = fixedTimeStep; + m_localTime += timeStep; + if (m_localTime >= fixedTimeStep) + { + subSteps = int( m_localTime / fixedTimeStep); + m_localTime -= subSteps * fixedTimeStep; + } + } else { + //variable timestep + fixedTimeStep = timeStep; + m_localTime = m_latencyMotionStateInterpolation ? 0 : timeStep; + m_fixedTimeStep = 0; + if (btFuzzyZero(timeStep)) + { + subSteps = 0; + maxSubSteps = 0; + } else + { + subSteps = 1; + maxSubSteps = 1; + } + } + + /*//process some debugging flags + if (getDebugDrawer()) { + btIDebugDraw* debugDrawer = getDebugDrawer (); + gDisableDeactivation = (debugDrawer->getDebugMode() & btIDebugDraw::DBG_NoDeactivation) != 0; + }*/ + if (subSteps) { + //clamp the number of substeps, to prevent simulation grinding spiralling down to a halt + int clampedSimulationSteps = (subSteps > maxSubSteps)? maxSubSteps : subSteps; + + saveKinematicState(fixedTimeStep*clampedSimulationSteps); + + applyGravity(); + + for (int i=0;i + +ATTRIBUTE_ALIGNED16(class) ThreadSafeDynamicsWorld : public btDiscreteDynamicsWorld +{ +public: + BT_DECLARE_ALIGNED_ALLOCATOR(); + + ThreadSafeDynamicsWorld( + btDispatcher* dispatcher, + btBroadphaseInterface* pairCache, + btConstraintSolver* constraintSolver, + btCollisionConfiguration* collisionConfiguration); + + // virtual overrides of btDiscreteDynamicsWorld + int stepSimulation( btScalar timeStep, int maxSubSteps=1, btScalar fixedTimeStep=btScalar(1.)/btScalar(60.)); + void synchronizeMotionStates(); + + /// \return true if lock succeeds + virtual bool tryLock() = 0; + + virtual void unlock() = 0; +}; + +#endif // hifi_ThreadSafeDynamicsWorld_h From 14f49df44d3ded809fba81bd2b2cbf1b6618b616 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 13 Nov 2014 10:02:36 -0800 Subject: [PATCH 029/105] Application gets a ThreadSafePhysicsWorld --- interface/src/Application.cpp | 2 +- interface/src/Application.h | 5 +-- interface/src/Physics.cpp | 45 +++++++++++++++++++++++++- interface/src/Physics.h | 14 ++++++++ libraries/physics/src/PhysicsWorld.cpp | 13 +++++--- libraries/physics/src/PhysicsWorld.h | 2 +- 6 files changed, 71 insertions(+), 10 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f0b4afe90a..50de20bbed 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2011,7 +2011,7 @@ void Application::init() { connect(_myAvatar, &MyAvatar::transformChanged, this, &Application::updateMyAvatarTransform); #ifdef USE_BULLET_PHYSICS - _physicsWorld.init(); + _physicsWorld.initSafe(_entities.getTree()); #endif // USE_BULLET_PHYSICS } diff --git a/interface/src/Application.h b/interface/src/Application.h index fb8518b794..49773ee96e 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -35,7 +35,7 @@ #include #include #include -#include +//#include #include #include #include @@ -53,6 +53,7 @@ #include "Menu.h" #include "MetavoxelSystem.h" #include "PacketHeaders.h" +#include "Physics.h" #include "Stars.h" #include "avatar/Avatar.h" #include "avatar/AvatarManager.h" @@ -504,7 +505,7 @@ private: MetavoxelSystem _metavoxels; #ifdef USE_BULLET_PHYSICS - PhysicsWorld _physicsWorld; + ThreadSafePhysicsWorld _physicsWorld; #endif // USE_BULLET_PHYSICS ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc. diff --git a/interface/src/Physics.cpp b/interface/src/Physics.cpp index 30ea829c4e..63100ef504 100644 --- a/interface/src/Physics.cpp +++ b/interface/src/Physics.cpp @@ -9,12 +9,55 @@ // #include + +#include #include +#include #include "Util.h" #include "world.h" #include "Physics.h" +// DynamicsImpl is an implementation of ThreadSafeDynamicsWorld that knows how to lock an EntityTree +class DynamicsImpl : public ThreadSafeDynamicsWorld { +public: + DynamicsImpl( + btDispatcher* dispatcher, + btBroadphaseInterface* pairCache, + btConstraintSolver* constraintSolver, + btCollisionConfiguration* collisionConfiguration, + EntityTree* entities) + : ThreadSafeDynamicsWorld(dispatcher, pairCache, constraintSolver, collisionConfiguration), _entities(entities) { + assert(entities); + } + + bool tryLock() { + // wait for lock + _entities->lockForRead(); + return true; + } + + void unlock() { + _entities->unlock(); + } +private: + EntityTree* _entities; +}; + +ThreadSafePhysicsWorld::ThreadSafePhysicsWorld(const glm::vec3& offset) : PhysicsWorld(offset) { +} + +void ThreadSafePhysicsWorld::initSafe(EntityTree* entities) { + assert(!_dynamicsWorld); // only call this once + assert(entities); + _collisionConfig = new btDefaultCollisionConfiguration(); + _collisionDispatcher = new btCollisionDispatcher(_collisionConfig); + _broadphaseFilter = new btDbvtBroadphase(); + _constraintSolver = new btSequentialImpulseConstraintSolver; + // ThreadSafePhysicsWorld gets a DynamicsImpl, which derives from ThreadSafeDynamicsWorld + _dynamicsWorld = new DynamicsImpl(_collisionDispatcher, _broadphaseFilter, _constraintSolver, _collisionConfig, entities); +} + // // Applies static friction: maxVelocity is the largest velocity for which there // there is friction, and strength is the amount of friction force applied to reduce @@ -41,4 +84,4 @@ void applyDamping(float deltaTime, glm::vec3& velocity, float linearStrength, fl void applyDampedSpring(float deltaTime, glm::vec3& velocity, glm::vec3& position, glm::vec3& targetPosition, float k, float damping) { -} \ No newline at end of file +} diff --git a/interface/src/Physics.h b/interface/src/Physics.h index 97e873d920..36bf46a180 100644 --- a/interface/src/Physics.h +++ b/interface/src/Physics.h @@ -12,6 +12,20 @@ #ifndef hifi_Physics_h #define hifi_Physics_h +#include + +class EntityTree; + +class ThreadSafePhysicsWorld : public PhysicsWorld { +public: + ThreadSafePhysicsWorld(const glm::vec3& offset); + + // virtual override from PhysicsWorld + void init() { assert(false); } // call initSafe() instead + + void initSafe(EntityTree* entities); +}; + void applyStaticFriction(float deltaTime, glm::vec3& velocity, float maxVelocity, float strength); void applyDamping(float deltaTime, glm::vec3& velocity, float linearStrength, float squaredStrength); diff --git a/libraries/physics/src/PhysicsWorld.cpp b/libraries/physics/src/PhysicsWorld.cpp index 5541622a66..b112110da8 100644 --- a/libraries/physics/src/PhysicsWorld.cpp +++ b/libraries/physics/src/PhysicsWorld.cpp @@ -15,12 +15,15 @@ PhysicsWorld::~PhysicsWorld() { } +// virtual void PhysicsWorld::init() { - _collisionConfig = new btDefaultCollisionConfiguration(); - _collisionDispatcher = new btCollisionDispatcher(_collisionConfig); - _broadphaseFilter = new btDbvtBroadphase(); - _constraintSolver = new btSequentialImpulseConstraintSolver; - _dynamicsWorld = new btDiscreteDynamicsWorld(_collisionDispatcher, _broadphaseFilter, _constraintSolver, _collisionConfig); + if (!_dynamicsWorld) { + _collisionConfig = new btDefaultCollisionConfiguration(); + _collisionDispatcher = new btCollisionDispatcher(_collisionConfig); + _broadphaseFilter = new btDbvtBroadphase(); + _constraintSolver = new btSequentialImpulseConstraintSolver; + _dynamicsWorld = new btDiscreteDynamicsWorld(_collisionDispatcher, _broadphaseFilter, _constraintSolver, _collisionConfig); + } } void PhysicsWorld::stepSimulation() { diff --git a/libraries/physics/src/PhysicsWorld.h b/libraries/physics/src/PhysicsWorld.h index 0c508af2da..04d0563f84 100644 --- a/libraries/physics/src/PhysicsWorld.h +++ b/libraries/physics/src/PhysicsWorld.h @@ -39,7 +39,7 @@ public: ~PhysicsWorld(); - void init(); + virtual void init(); void stepSimulation(); From ebe24b5c4c15d83847e51ec5a4272d6fe5b1ce77 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 13 Nov 2014 10:04:55 -0800 Subject: [PATCH 030/105] give the EntityTree a pointer to its PhysicsWorld --- interface/src/Application.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 50de20bbed..c084af9696 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2012,6 +2012,7 @@ void Application::init() { #ifdef USE_BULLET_PHYSICS _physicsWorld.initSafe(_entities.getTree()); + _entities.setPhysicsWorld(*_physicsWorld); #endif // USE_BULLET_PHYSICS } From 7f46ac0935fe237308b8a6400b1a1fa02e452e2e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 13 Nov 2014 10:12:52 -0800 Subject: [PATCH 031/105] EntityTree gtts PhysicsWorld*, with less error --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c084af9696..ddcb2b3d1c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2012,7 +2012,7 @@ void Application::init() { #ifdef USE_BULLET_PHYSICS _physicsWorld.initSafe(_entities.getTree()); - _entities.setPhysicsWorld(*_physicsWorld); + _entities.getTree()->setPhysicsWorld(&_physicsWorld); #endif // USE_BULLET_PHYSICS } From 7fb7256a92e6d61be62d5fcd8c4d1038260dc0d4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 14 Nov 2014 09:02:22 -0800 Subject: [PATCH 032/105] MotionState also ferries velocity --- libraries/entities/src/EntityMotionState.cpp | 17 +++++++++++++++- libraries/entities/src/EntityMotionState.h | 10 +++++++--- libraries/physics/src/CustomMotionState.cpp | 21 ++++++++++++++++++++ libraries/physics/src/CustomMotionState.h | 9 +++++++++ libraries/physics/src/PhysicsWorld.cpp | 3 +++ 5 files changed, 56 insertions(+), 4 deletions(-) diff --git a/libraries/entities/src/EntityMotionState.cpp b/libraries/entities/src/EntityMotionState.cpp index ea788500ef..26349290ea 100644 --- a/libraries/entities/src/EntityMotionState.cpp +++ b/libraries/entities/src/EntityMotionState.cpp @@ -44,12 +44,14 @@ EntityMotionState::~EntityMotionState() { // it is an opportunity for outside code to update the object's simulation position void EntityMotionState::getWorldTransform (btTransform &worldTrans) const { btVector3 pos; - glmToBullet(_entity->getPosition() - _cachedWorldOffset, pos); + glmToBullet(_entity->getPositionInMeters() - _cachedWorldOffset, pos); worldTrans.setOrigin(pos); btQuaternion rot; glmToBullet(_entity->getRotation(), rot); worldTrans.setRotation(rot); + + applyVelocities(); } // This callback is invoked by the physics simulation at the end of each simulation frame... @@ -62,6 +64,19 @@ void EntityMotionState::setWorldTransform (const btTransform &worldTrans) { glm::quat rot; bulletToGLM(worldTrans.getRotation(), rot); _entity->setRotation(rot); + + glm::vec3 v; + getVelocity(v); + _entity->setVelocityInMeters(v); + getAngularVelocity(v); + _entity->setAngularVelocity(v); +} + +void EntityMotionState::applyVelocities() const { + if (_body) { + setVelocity(_entity->getVelocityInMeters()); + setAngularVelocity(_entity->getAngularVelocity()); + } } void EntityMotionState::computeShapeInfo(ShapeInfo& info) { diff --git a/libraries/entities/src/EntityMotionState.h b/libraries/entities/src/EntityMotionState.h index a6cfa86887..c80df13f7e 100644 --- a/libraries/entities/src/EntityMotionState.h +++ b/libraries/entities/src/EntityMotionState.h @@ -14,8 +14,11 @@ #ifdef USE_BULLET_PHYSICS +#include #include +class EntityItem; + class EntityMotionState : public CustomMotionState { public: static void setWorldOffset(const glm::vec3& offset); @@ -24,10 +27,11 @@ public: EntityMotionState(EntityItem* item); virtual ~EntityMotionState(); - virtual void getWorldTransform (btTransform &worldTrans) const; - virtual void setWorldTransform (const btTransform &worldTrans); + void getWorldTransform (btTransform &worldTrans) const; + void setWorldTransform (const btTransform &worldTrans); + void applyVelocities() const; - virtual void computeShapeInfo(ShapeInfo& info); + void computeShapeInfo(ShapeInfo& info); void getBoundingCubes(AACube& oldCube, AACube& newCube); diff --git a/libraries/physics/src/CustomMotionState.cpp b/libraries/physics/src/CustomMotionState.cpp index 07f1895a30..5ccca75ab4 100644 --- a/libraries/physics/src/CustomMotionState.cpp +++ b/libraries/physics/src/CustomMotionState.cpp @@ -13,6 +13,7 @@ #include +#include "BulletUtil.h" #include "CustomMotionState.h" const float MIN_DENSITY = 200.0f; @@ -58,4 +59,24 @@ void CustomMotionState::setVolume(float volume) { _volume = btMax(btMin(fabsf(volume), MAX_VOLUME), MIN_VOLUME); } +void CustomMotionState::setVelocity(const glm::vec3& velocity) const { + btVector3 v; + glmToBullet(velocity, v); + _body->setLinearVelocity(v); +} + +void CustomMotionState::setAngularVelocity(const glm::vec3& velocity) const { + btVector3 v; + glmToBullet(velocity, v); + _body->setAngularVelocity(v); +} + +void CustomMotionState::getVelocity(glm::vec3& velocityOut) const { + bulletToGLM(_body->getLinearVelocity(), velocityOut); +} + +void CustomMotionState::getAngularVelocity(glm::vec3& angularVelocityOut) const { + bulletToGLM(_body->getAngularVelocity(), angularVelocityOut); +} + #endif // USE_BULLET_PHYSICS diff --git a/libraries/physics/src/CustomMotionState.h b/libraries/physics/src/CustomMotionState.h index 88991a4855..87e911f879 100644 --- a/libraries/physics/src/CustomMotionState.h +++ b/libraries/physics/src/CustomMotionState.h @@ -15,6 +15,7 @@ #ifdef USE_BULLET_PHYSICS #include +#include #include "ShapeInfo.h" @@ -33,6 +34,8 @@ public: //virtual void getWorldTransform (btTransform &worldTrans) const; //virtual void setWorldTransform (const btTransform &worldTrans); + virtual void applyVelocities() const = 0; + virtual void computeShapeInfo(ShapeInfo& info) = 0; MotionType getMotionType() const { return _motionType; } @@ -44,6 +47,12 @@ public: float getMass() const { return _volume * _density; } + void setVelocity(const glm::vec3& velocity) const; + void setAngularVelocity(const glm::vec3& velocity) const; + + void getVelocity(glm::vec3& velocityOut) const; + void getAngularVelocity(glm::vec3& angularVelocityOut) const; + friend class PhysicsWorld; protected: diff --git a/libraries/physics/src/PhysicsWorld.cpp b/libraries/physics/src/PhysicsWorld.cpp index b112110da8..b49fd8d802 100644 --- a/libraries/physics/src/PhysicsWorld.cpp +++ b/libraries/physics/src/PhysicsWorld.cpp @@ -104,8 +104,10 @@ bool PhysicsWorld::addEntity(CustomMotionState* motionState) { shape->calculateLocalInertia(mass, inertia); btRigidBody* body = new btRigidBody(mass, motionState, shape, inertia); motionState->_body = body; + motionState->applyVelocities(); // TODO: set dynamic/kinematic/static property from data stored in motionState _dynamicsWorld->addRigidBody(body); + return true; } return false; } @@ -121,6 +123,7 @@ bool PhysicsWorld::removeEntity(CustomMotionState* motionState) { _shapeManager.releaseShape(info); delete body; motionState->_body = NULL; + return true; } return false; } From 1a094f2b514c47b16c01dd5c33060f84486706db Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 14 Nov 2014 09:03:41 -0800 Subject: [PATCH 033/105] reorder PhysicsWorld and EntityTree in Application --- interface/src/Application.cpp | 6 +++--- interface/src/Application.h | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5bfdd90c22..13582be5a7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -152,14 +152,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _voxelImporter(), _importSucceded(false), _sharedVoxelSystem(TREE_SCALE, DEFAULT_MAX_VOXELS_PER_SYSTEM, &_clipboard), +#ifdef USE_BULLET_PHYSICS + _physicsWorld(glm::vec3(0.0f)), +#endif // USE_BULLET_PHYSICS _entities(true), _entityCollisionSystem(), _entityClipboardRenderer(false), _entityClipboard(), _wantToKillLocalVoxels(false), -#ifdef USE_BULLET_PHYSICS - _physicsWorld(glm::vec3(0.0f)), -#endif // USE_BULLET_PHYSICS _viewFrustum(), _lastQueriedViewFrustum(), _lastQueriedTime(usecTimestampNow()), diff --git a/interface/src/Application.h b/interface/src/Application.h index 1d537503a9..7172003435 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -494,6 +494,10 @@ private: VoxelSystem _sharedVoxelSystem; ViewFrustum _sharedVoxelSystemViewFrustum; +#ifdef USE_BULLET_PHYSICS + ThreadSafePhysicsWorld _physicsWorld; +#endif // USE_BULLET_PHYSICS + EntityTreeRenderer _entities; EntityCollisionSystem _entityCollisionSystem; EntityTreeRenderer _entityClipboardRenderer; @@ -504,10 +508,6 @@ private: MetavoxelSystem _metavoxels; -#ifdef USE_BULLET_PHYSICS - ThreadSafePhysicsWorld _physicsWorld; -#endif // USE_BULLET_PHYSICS - ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc. ViewFrustum _lastQueriedViewFrustum; /// last view frustum used to query octree servers (voxels) ViewFrustum _displayViewFrustum; From 40b9416810c9cbc0432b326bdf02c64e72c63f21 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 14 Nov 2014 09:04:09 -0800 Subject: [PATCH 034/105] cleanup motionstate on EntityItem delete --- libraries/entities/src/EntityTree.cpp | 7 +++++-- libraries/entities/src/EntityTreeElement.cpp | 10 +++++++++- libraries/entities/src/EntityTreeElement.h | 3 ++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index e77134413c..97647501ea 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -37,7 +37,7 @@ EntityTreeElement* EntityTree::createNewElement(unsigned char * octalCode) { void EntityTree::eraseAllOctreeElements(bool createNewRoot) { // this would be a good place to clean up our entities... foreach (EntityTreeElement* element, _entityToElementMap) { - element->cleanupEntities(); + element->cleanupEntities(_physicsWorld); } _entityToElementMap.clear(); Octree::eraseAllOctreeElements(createNewRoot); @@ -91,6 +91,7 @@ void EntityTree::addEntityItem(EntityItem* entityItem) { recurseTreeWithOperator(&theOperator); // check to see if we need to simulate this entity.. + // BOOKMARK -- add entity to physics engine here changeEntityState(entityItem, EntityItem::Static, entityItem->getSimulationState()); _isDirty = true; @@ -133,7 +134,9 @@ bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProp _isDirty = true; EntityItem::SimulationState newState = existingEntity->getSimulationState(); - changeEntityState(existingEntity, oldState, newState); + if (newState != oldState) { + changeEntityState(existingEntity, oldState, newState); + } QString entityScriptAfter = existingEntity->getScript(); if (entityScriptBefore != entityScriptAfter) { diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 1dea2bcd85..b26db16f89 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -16,7 +16,9 @@ #include #include +#include +#include "EntityMotionState.h" #include "EntityTree.h" #include "EntityTreeElement.h" @@ -653,10 +655,16 @@ EntityItem* EntityTreeElement::getEntityWithEntityItemID(const EntityItemID& id) return foundEntity; } -void EntityTreeElement::cleanupEntities() { +void EntityTreeElement::cleanupEntities(PhysicsWorld* physicsWorld) { uint16_t numberOfEntities = _entityItems->size(); for (uint16_t i = 0; i < numberOfEntities; i++) { EntityItem* entity = (*_entityItems)[i]; + EntityMotionState* motionState = entity->getMotionState(); + if (motionState) { + assert(physicsWorld); + physicsWorld->removeEntity(static_cast(motionState)); + entity->destroyMotionState(); + } delete entity; } _entityItems->clear(); diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index ab3754749b..7e26aacf1c 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -21,6 +21,7 @@ class EntityTree; class EntityTreeElement; +class PhysicsWorld; class EntityTreeUpdateArgs { public: @@ -175,7 +176,7 @@ public: EntityItem* getEntityWithEntityItemID(const EntityItemID& id); - void cleanupEntities(); /// called by EntityTree on cleanup this will free all entities + void cleanupEntities(PhysicsWorld* physicsWorld); bool removeEntityWithEntityItemID(const EntityItemID& id); bool removeEntityItem(EntityItem* entity); From 2f9a35412f91ec7826900d525f9bd9c89291353b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 14 Nov 2014 15:56:52 -0800 Subject: [PATCH 035/105] initial support for STATIC and KINEMATIC motion --- libraries/entities/src/EntityMotionState.cpp | 7 ++ libraries/entities/src/EntityMotionState.h | 2 + libraries/entities/src/EntityTree.cpp | 24 ++-- libraries/physics/src/CustomMotionState.cpp | 3 +- libraries/physics/src/CustomMotionState.h | 9 +- libraries/physics/src/PhysicsWorld.cpp | 118 +++++++++++++++++-- libraries/physics/src/PhysicsWorld.h | 8 +- 7 files changed, 147 insertions(+), 24 deletions(-) diff --git a/libraries/entities/src/EntityMotionState.cpp b/libraries/entities/src/EntityMotionState.cpp index 26349290ea..be15f1cfe9 100644 --- a/libraries/entities/src/EntityMotionState.cpp +++ b/libraries/entities/src/EntityMotionState.cpp @@ -37,6 +37,13 @@ EntityMotionState::EntityMotionState(EntityItem* entity) : _entity(entity) { EntityMotionState::~EntityMotionState() { } +MotionType EntityMotionState::getMotionType() const { + // HACK: According to EntityTree the meaning of "static" is "not moving" whereas + // to Bullet it means "can't move". For demo purposes we temporarily interpret + // Entity::weightless to mean Bullet::static. + return _entity->hasGravity() ? MOTION_TYPE_DYNAMIC : MOTION_TYPE_STATIC; +} + // This callback is invoked by the physics simulation in two cases: // (1) when the RigidBody is first added to the world // (irregardless of MotionType: STATIC, DYNAMIC, or KINEMATIC) diff --git a/libraries/entities/src/EntityMotionState.h b/libraries/entities/src/EntityMotionState.h index c80df13f7e..3b69abcd9d 100644 --- a/libraries/entities/src/EntityMotionState.h +++ b/libraries/entities/src/EntityMotionState.h @@ -27,6 +27,8 @@ public: EntityMotionState(EntityItem* item); virtual ~EntityMotionState(); + MotionType getMotionType() const; + void getWorldTransform (btTransform &worldTrans) const; void setWorldTransform (const btTransform &worldTrans); void applyVelocities() const; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 97647501ea..967d45b5af 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -77,9 +77,9 @@ EntityItem* EntityTree::getOrCreateEntityItem(const EntityItemID& entityID, cons } /// Adds a new entity item to the tree -void EntityTree::addEntityItem(EntityItem* entityItem) { +void EntityTree::addEntityItem(EntityItem* entity) { // You should not call this on existing entities that are already part of the tree! Call updateEntity() - EntityItemID entityID = entityItem->getEntityItemID(); + EntityItemID entityID = entity->getEntityItemID(); EntityTreeElement* containingElement = getContainingElement(entityID); if (containingElement) { qDebug() << "UNEXPECTED!!!! don't call addEntityItem() on existing entity items. entityID=" << entityID; @@ -87,12 +87,15 @@ void EntityTree::addEntityItem(EntityItem* entityItem) { } // Recurse the tree and store the entity in the correct tree element - AddEntityOperator theOperator(this, entityItem); + AddEntityOperator theOperator(this, entity); recurseTreeWithOperator(&theOperator); // check to see if we need to simulate this entity.. - // BOOKMARK -- add entity to physics engine here - changeEntityState(entityItem, EntityItem::Static, entityItem->getSimulationState()); + changeEntityState(entity, EntityItem::Static, entity->getSimulationState()); + + if (_physicsWorld && !entity->getMotionState()) { + addEntityToPhysicsWorld(entity); + } _isDirty = true; } @@ -530,7 +533,7 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char // search for the entity by EntityItemID EntityItem* existingEntity = findEntityByEntityItemID(entityItemID); - // if the entityItem exists, then update it + // if the EntityItem exists, then update it if (existingEntity) { updateEntity(entityItemID, properties); existingEntity->markAsChangedOnServer(); @@ -621,9 +624,6 @@ void EntityTree::changeEntityState(EntityItem* const entity, case EntityItem::Moving: _movingEntities.push_back(entity); - if (_physicsWorld && !entity->getMotionState()) { - addEntityToPhysicsWorld(entity); - } break; case EntityItem::Mortal: @@ -683,7 +683,11 @@ void EntityTree::updateChangingEntities(quint64 now, QSet& entitie // TODO: switch these to iterators so we can remove items that get deleted for (int i = 0; i < _changingEntities.size(); i++) { EntityItem* thisEntity = _changingEntities[i]; - thisEntity->update(now); + EntityMotionState* motionState = thisEntity->getMotionState(); + if (!motionState) { + thisEntity->update(now); + } + // always check to see if the lifetime has expired, for immortal entities this is always false if (thisEntity->lifetimeHasExpired()) { qDebug() << "Lifetime has expired for entity:" << thisEntity->getEntityItemID(); diff --git a/libraries/physics/src/CustomMotionState.cpp b/libraries/physics/src/CustomMotionState.cpp index 5ccca75ab4..743ed26614 100644 --- a/libraries/physics/src/CustomMotionState.cpp +++ b/libraries/physics/src/CustomMotionState.cpp @@ -34,7 +34,8 @@ CustomMotionState::CustomMotionState() : _volume(DEFAULT_VOLUME), _friction(DEFAULT_FRICTION), _restitution(DEFAULT_RESTITUTION), - _motionType(MOTION_TYPE_STATIC), + _wasInWorld(false), + _motionType(MOTION_TYPE_STATIC), _body(NULL) { } diff --git a/libraries/physics/src/CustomMotionState.h b/libraries/physics/src/CustomMotionState.h index 87e911f879..7db25d3899 100644 --- a/libraries/physics/src/CustomMotionState.h +++ b/libraries/physics/src/CustomMotionState.h @@ -38,7 +38,7 @@ public: virtual void computeShapeInfo(ShapeInfo& info) = 0; - MotionType getMotionType() const { return _motionType; } + virtual MotionType getMotionType() const { return _motionType; } void setDensity(float density); void setFriction(float friction); @@ -54,15 +54,16 @@ public: void getAngularVelocity(glm::vec3& angularVelocityOut) const; friend class PhysicsWorld; -protected: +protected: float _density; float _volume; float _friction; float _restitution; - - // The data members below have NO setters. They are only changed by a PhysicsWorld instance. + bool _wasInWorld; MotionType _motionType; + + // _body has NO setters -- it is only changed by PhysicsWorld btRigidBody* _body; }; diff --git a/libraries/physics/src/PhysicsWorld.cpp b/libraries/physics/src/PhysicsWorld.cpp index b49fd8d802..518989c81f 100644 --- a/libraries/physics/src/PhysicsWorld.cpp +++ b/libraries/physics/src/PhysicsWorld.cpp @@ -23,6 +23,26 @@ void PhysicsWorld::init() { _broadphaseFilter = new btDbvtBroadphase(); _constraintSolver = new btSequentialImpulseConstraintSolver; _dynamicsWorld = new btDiscreteDynamicsWorld(_collisionDispatcher, _broadphaseFilter, _constraintSolver, _collisionConfig); + + // TODO: once the initial physics system is working we will set gravity of the world to be zero + // and each object will have to specify its own local gravity, or we'll set up gravity zones. + //_dynamicsWorld->setGravity(btVector3(0.0f, 0.0f, 0.0f)); + // + // GROUND HACK: In the meantime we add a big planar floor to catch falling objects + // NOTE: we don't care about memory leaking groundShape and groundObject --> + // they'll exist until the executable exits. + const float halfSide = 200.0f; + const float halfHeight = 10.0f; + + btCollisionShape* groundShape = new btBoxShape(btVector3(halfSide, halfHeight, halfSide)); + btTransform groundTransform; + groundTransform.setIdentity(); + groundTransform.setOrigin(btVector3(halfSide, -halfHeight, halfSide)); + + btCollisionObject* groundObject = new btCollisionObject(); + groundObject->setCollisionShape(groundShape); + groundObject->setWorldTransform(groundTransform); + _dynamicsWorld->addCollisionObject(groundObject); } } @@ -93,19 +113,103 @@ bool PhysicsWorld::removeVoxel(const glm::vec3& position, float scale) { return false; } +// Bullet collision flags are as follows: +// CF_STATIC_OBJECT= 1, +// CF_KINEMATIC_OBJECT= 2, +// CF_NO_CONTACT_RESPONSE = 4, +// CF_CUSTOM_MATERIAL_CALLBACK = 8,//this allows per-triangle material (friction/restitution) +// CF_CHARACTER_OBJECT = 16, +// CF_DISABLE_VISUALIZE_OBJECT = 32, //disable debug drawing +// CF_DISABLE_SPU_COLLISION_PROCESSING = 64//disable parallel/SPU processing + bool PhysicsWorld::addEntity(CustomMotionState* motionState) { assert(motionState); ShapeInfo info; motionState->computeShapeInfo(info); btCollisionShape* shape = _shapeManager.getShape(info); if (shape) { - btVector3 inertia; - float mass = motionState->getMass(); - shape->calculateLocalInertia(mass, inertia); - btRigidBody* body = new btRigidBody(mass, motionState, shape, inertia); - motionState->_body = body; - motionState->applyVelocities(); - // TODO: set dynamic/kinematic/static property from data stored in motionState + btVector3 inertia(0.0f, 0.0f, 0.0f); + float mass = 0.0f; + btRigidBody* body = NULL; + switch(motionState->_motionType) { + case MOTION_TYPE_KINEMATIC: { + body = new btRigidBody(mass, motionState, shape, inertia); + body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); + body->setActivationState(DISABLE_DEACTIVATION); + body->updateInertiaTensor(); + motionState->_body = body; + break; + } + case MOTION_TYPE_DYNAMIC: { + mass = motionState->getMass(); + shape->calculateLocalInertia(mass, inertia); + body = new btRigidBody(mass, motionState, shape, inertia); + body->updateInertiaTensor(); + motionState->_body = body; + motionState->applyVelocities(); + break; + } + default: { + // MOTION_TYPE_STATIC + body = new btRigidBody(mass, motionState, shape, inertia); + body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT); + body->updateInertiaTensor(); + motionState->_body = body; + break; + } + } + body->setRestitution(motionState->_restitution); + body->setFriction(motionState->_friction); + _dynamicsWorld->addRigidBody(body); + return true; + } + return false; +} + +bool PhysicsWorld::updateEntityMotionType(CustomMotionState* motionState) { + btRigidBody* body = motionState->_body; + if (!body) { + return false; + } + + MotionType oldType = MOTION_TYPE_DYNAMIC; + if (body->isStaticObject()) { + oldType = MOTION_TYPE_STATIC; + } else if (body->isKinematicObject()) { + oldType = MOTION_TYPE_KINEMATIC; + } + MotionType newType = motionState->getMotionType(); + if (oldType != newType) { + // pull body out of physics engine + _dynamicsWorld->removeRigidBody(body); + + // update various properties and flags + switch (newType) { + case MOTION_TYPE_KINEMATIC: { + body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); + body->setActivationState(DISABLE_DEACTIVATION); + body->updateInertiaTensor(); + break; + } + case MOTION_TYPE_DYNAMIC: { + btVector3 inertia(0.0f, 0.0f, 0.0f); + float mass = motionState->getMass(); + body->getCollisionShape()->calculateLocalInertia(mass, inertia); + body->updateInertiaTensor(); + motionState->applyVelocities(); + break; + } + default: { + // MOTION_TYPE_STATIC + body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT); + body->updateInertiaTensor(); + break; + } + } + + // reinsert body into physics engine + body->setRestitution(motionState->_restitution); + body->setFriction(motionState->_friction); _dynamicsWorld->addRigidBody(body); return true; } diff --git a/libraries/physics/src/PhysicsWorld.h b/libraries/physics/src/PhysicsWorld.h index 04d0563f84..1ff06c9c5d 100644 --- a/libraries/physics/src/PhysicsWorld.h +++ b/libraries/physics/src/PhysicsWorld.h @@ -59,11 +59,15 @@ public: /// \return true if Voxel removed bool removeVoxel(const glm::vec3& position, float scale); - /// \param info information about collision shapes to create + /// \param motionState pointer to Entity's MotionState /// \return true if Entity added bool addEntity(CustomMotionState* motionState); - /// \param id UUID of the entity + /// \param motionState pointer to Entity's MotionState + /// \return true if entity updated + bool updateEntityMotionType(CustomMotionState* motionState); + + /// \param motionState pointer to Entity's MotionState /// \return true if Entity removed bool removeEntity(CustomMotionState* motionState); From dd0bdabfe118dc5a1920963c67dc8f6343ea3cb8 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 17 Nov 2014 15:50:35 -0800 Subject: [PATCH 036/105] setSimulationState() --> computeSimulationState() --- interface/src/entities/RenderableModelEntityItem.cpp | 2 +- libraries/entities/src/EntityItem.cpp | 6 ++++-- libraries/entities/src/EntityItem.h | 2 +- libraries/entities/src/ModelEntityItem.cpp | 6 +++--- libraries/entities/src/ModelEntityItem.h | 2 +- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/interface/src/entities/RenderableModelEntityItem.cpp b/interface/src/entities/RenderableModelEntityItem.cpp index 8d932b121d..ec3fa7a269 100644 --- a/interface/src/entities/RenderableModelEntityItem.cpp +++ b/interface/src/entities/RenderableModelEntityItem.cpp @@ -246,7 +246,7 @@ Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) { } bool RenderableModelEntityItem::needsSimulation() const { - SimulationState simulationState = getSimulationState(); + SimulationState simulationState = computeSimulationState(); return _needsInitialSimulation || simulationState == Moving || simulationState == Changing; } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index d9eb33cba3..3e42e8bff8 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -395,6 +395,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef quint64 lastEditedFromBuffer = 0; quint64 lastEditedFromBufferAdjusted = 0; + // BOOKMARK: TODO: figure out if we can catch remote updates to EntityItems and build a list in the Tree + // that is then relayed to the physics engine (and other data structures that cache EntityItem data) // TODO: we could make this encoded as a delta from _created // _lastEdited memcpy(&lastEditedFromBuffer, dataAt, sizeof(lastEditedFromBuffer)); @@ -419,7 +421,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef qDebug() << " fromSameServerEdit=" << fromSameServerEdit; } - bool ignoreServerPacket = false; // assume we're use this server packet + bool ignoreServerPacket = false; // assume we'll use this server packet // If this packet is from the same server edit as the last packet we accepted from the server // we probably want to use it. @@ -732,7 +734,7 @@ void EntityItem::update(const quint64& updateTime) { } } -EntityItem::SimulationState EntityItem::getSimulationState() const { +EntityItem::SimulationState EntityItem::computeSimulationState() const { if (hasVelocity() || (hasGravity() && !isRestingOnSurface())) { return EntityItem::Moving; } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index ba8bfddaec..b8865a8380 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -123,7 +123,7 @@ public: Moving } SimulationState; - virtual SimulationState getSimulationState() const; + virtual SimulationState computeSimulationState() const; virtual void debugDump() const; // similar to assignment/copy, but it handles keeping lifetime accurate diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index f50fe7866b..31a0c57f5b 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -371,15 +371,15 @@ bool ModelEntityItem::isAnimatingSomething() const { !getAnimationURL().isEmpty(); } -EntityItem::SimulationState ModelEntityItem::getSimulationState() const { - EntityItem::SimulationState baseClassState = EntityItem::getSimulationState(); +EntityItem::SimulationState ModelEntityItem::computeSimulationState() const { + EntityItem::SimulationState baseClassState = EntityItem::computeSimulationState(); // if the base class is static, then consider our animation state, and upgrade to changing if // we are animating. If the base class has a higher simulation state than static, then // use the base class state. if (baseClassState == EntityItem::Static) { if (isAnimatingSomething()) { - return EntityItem::Changing; + return EntityItem::Moving; } } return baseClassState; diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 97ffed4076..0b2508ec80 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -46,7 +46,7 @@ public: EntityPropertyFlags& propertyFlags, bool overwriteLocalData); virtual void update(const quint64& now); - virtual SimulationState getSimulationState() const; + virtual SimulationState computeSimulationState() const; virtual void debugDump() const; From 2cf93697cb153fb62ee3b0165b26074cc44ceb84 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 17 Nov 2014 15:51:29 -0800 Subject: [PATCH 037/105] removed some crufty comments --- libraries/entities/src/BoxEntityItem.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/entities/src/BoxEntityItem.cpp b/libraries/entities/src/BoxEntityItem.cpp index f7d53ad499..d1a58722b0 100644 --- a/libraries/entities/src/BoxEntityItem.cpp +++ b/libraries/entities/src/BoxEntityItem.cpp @@ -98,8 +98,6 @@ void BoxEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitst } #ifdef USE_BULLET_PHYSICS -// BOOKMARK: move EntityMotionState implementation to Entities -// also define interface for it (dunno what to call it) EntityMotionState* BoxEntityItem::createMotionState() { if (!_motionState) { _motionState = new EntityMotionState(this); From ac87c90d621051ca935f0034b8bbdfa2e6bf3112 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 17 Nov 2014 15:53:03 -0800 Subject: [PATCH 038/105] Remove Changing state, now keep QSet of changes --- libraries/entities/src/EntityTree.cpp | 64 ++++++-------------- libraries/entities/src/EntityTree.h | 12 ++-- libraries/entities/src/EntityTreeElement.cpp | 10 +-- 3 files changed, 31 insertions(+), 55 deletions(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 967d45b5af..d19dda8e6c 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -42,8 +42,8 @@ void EntityTree::eraseAllOctreeElements(bool createNewRoot) { _entityToElementMap.clear(); Octree::eraseAllOctreeElements(createNewRoot); _movingEntities.clear(); - _changingEntities.clear(); _mortalEntities.clear(); + _changedEntities.clear(); } bool EntityTree::handlesEditPacketType(PacketType packetType) const { @@ -91,7 +91,7 @@ void EntityTree::addEntityItem(EntityItem* entity) { recurseTreeWithOperator(&theOperator); // check to see if we need to simulate this entity.. - changeEntityState(entity, EntityItem::Static, entity->getSimulationState()); + changeEntityState(entity, EntityItem::Static, entity->computeSimulationState()); if (_physicsWorld && !entity->getMotionState()) { addEntityToPhysicsWorld(entity); @@ -129,14 +129,14 @@ bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProp } } else { // check to see if we need to simulate this entity... - EntityItem::SimulationState oldState = existingEntity->getSimulationState(); + EntityItem::SimulationState oldState = existingEntity->computeSimulationState(); QString entityScriptBefore = existingEntity->getScript(); UpdateEntityOperator theOperator(this, containingElement, existingEntity, properties); recurseTreeWithOperator(&theOperator); _isDirty = true; - EntityItem::SimulationState newState = existingEntity->getSimulationState(); + EntityItem::SimulationState newState = existingEntity->computeSimulationState(); if (newState != oldState) { changeEntityState(existingEntity, oldState, newState); } @@ -242,12 +242,8 @@ void EntityTree::removeEntityFromSimulationLists(const EntityItemID& entityID) { if (theEntity) { // make sure to remove it from any of our simulation lists - EntityItem::SimulationState theState = theEntity->getSimulationState(); + EntityItem::SimulationState theState = theEntity->computeSimulationState(); switch (theState) { - case EntityItem::Changing: - _changingEntities.removeAll(theEntity); - break; - case EntityItem::Moving: _movingEntities.removeAll(theEntity); break; @@ -259,6 +255,7 @@ void EntityTree::removeEntityFromSimulationLists(const EntityItemID& entityID) { default: break; } + _changedEntities.remove(theEntity); } } @@ -600,10 +597,6 @@ void EntityTree::changeEntityState(EntityItem* const entity, // TODO: can we short circuit this if the state isn't changing? switch (oldState) { - case EntityItem::Changing: - _changingEntities.removeAll(entity); - break; - case EntityItem::Moving: _movingEntities.removeAll(entity); break; @@ -618,10 +611,6 @@ void EntityTree::changeEntityState(EntityItem* const entity, switch (newState) { - case EntityItem::Changing: - _changingEntities.push_back(entity); - break; - case EntityItem::Moving: _movingEntities.push_back(entity); break; @@ -635,6 +624,10 @@ void EntityTree::changeEntityState(EntityItem* const entity, } } +void EntityTree::entityChanged(EntityItem* entity) { + _changedEntities.insert(entity); +} + void EntityTree::addEntityToPhysicsWorld(EntityItem* entity) { EntityMotionState* motionState = entity->createMotionState(); if (!_physicsWorld->addEntity(static_cast(motionState))) { @@ -665,7 +658,7 @@ void EntityTree::update() { lockForWrite(); quint64 now = usecTimestampNow(); QSet entitiesToDelete; - updateChangingEntities(now, entitiesToDelete); + updateChangedEntities(now, entitiesToDelete); updateMovingEntities(now, entitiesToDelete); updateMortalEntities(now, entitiesToDelete); @@ -675,27 +668,21 @@ void EntityTree::update() { unlock(); } -void EntityTree::updateChangingEntities(quint64 now, QSet& entitiesToDelete) { +void EntityTree::updateChangedEntities(quint64 now, QSet& entitiesToDelete) { QSet entitiesBecomingStatic; QSet entitiesBecomingMortal; QSet entitiesBecomingMoving; // TODO: switch these to iterators so we can remove items that get deleted - for (int i = 0; i < _changingEntities.size(); i++) { - EntityItem* thisEntity = _changingEntities[i]; - EntityMotionState* motionState = thisEntity->getMotionState(); - if (!motionState) { - thisEntity->update(now); - } - - // always check to see if the lifetime has expired, for immortal entities this is always false + foreach (EntityItem* thisEntity, _changedEntities) { + // check to see if the lifetime has expired, for immortal entities this is always false if (thisEntity->lifetimeHasExpired()) { qDebug() << "Lifetime has expired for entity:" << thisEntity->getEntityItemID(); entitiesToDelete << thisEntity->getEntityItemID(); entitiesBecomingStatic << thisEntity; } else { - // check to see if this entity is no longer moving - EntityItem::SimulationState newState = thisEntity->getSimulationState(); + // TODO: Andrew to push changes to physics engine (when we know how to sort the changes) + EntityItem::SimulationState newState = thisEntity->computeSimulationState(); if (newState == EntityItem::Static) { entitiesBecomingStatic << thisEntity; @@ -706,6 +693,7 @@ void EntityTree::updateChangingEntities(quint64 now, QSet& entitie } } } + _changedEntities.clear(); // change state for any entities that were changing but are now either static, mortal, or moving foreach(EntityItem* entity, entitiesBecomingStatic) { @@ -726,7 +714,6 @@ void EntityTree::updateMovingEntities(quint64 now, QSet& entitiesT QSet entitiesBecomingStatic; QSet entitiesBecomingMortal; - QSet entitiesBecomingChanging; { PerformanceTimer perfTimer("_movingEntities"); @@ -761,10 +748,8 @@ void EntityTree::updateMovingEntities(quint64 now, QSet& entitiesT moveOperator.addEntityToMoveList(thisEntity, oldCube, newCube); // check to see if this entity is no longer moving - EntityItem::SimulationState newState = thisEntity->getSimulationState(); - if (newState == EntityItem::Changing) { - entitiesBecomingChanging << thisEntity; - } else if (newState == EntityItem::Mortal) { + EntityItem::SimulationState newState = thisEntity->computeSimulationState(); + if (newState == EntityItem::Mortal) { entitiesBecomingMortal << thisEntity; } else if (newState == EntityItem::Static) { entitiesBecomingStatic << thisEntity; @@ -785,15 +770,11 @@ void EntityTree::updateMovingEntities(quint64 now, QSet& entitiesT foreach(EntityItem* entity, entitiesBecomingMortal) { changeEntityState(entity, EntityItem::Moving, EntityItem::Mortal); } - foreach(EntityItem* entity, entitiesBecomingChanging) { - changeEntityState(entity, EntityItem::Moving, EntityItem::Changing); - } } } void EntityTree::updateMortalEntities(quint64 now, QSet& entitiesToDelete) { QSet entitiesBecomingStatic; - QSet entitiesBecomingChanging; QSet entitiesBecomingMoving; // TODO: switch these to iterators so we can remove items that get deleted @@ -807,12 +788,10 @@ void EntityTree::updateMortalEntities(quint64 now, QSet& entitiesT entitiesBecomingStatic << thisEntity; } else { // check to see if this entity is no longer moving - EntityItem::SimulationState newState = thisEntity->getSimulationState(); + EntityItem::SimulationState newState = thisEntity->computeSimulationState(); if (newState == EntityItem::Static) { entitiesBecomingStatic << thisEntity; - } else if (newState == EntityItem::Changing) { - entitiesBecomingChanging << thisEntity; } else if (newState == EntityItem::Moving) { entitiesBecomingMoving << thisEntity; } @@ -823,9 +802,6 @@ void EntityTree::updateMortalEntities(quint64 now, QSet& entitiesT foreach(EntityItem* entity, entitiesBecomingStatic) { changeEntityState(entity, EntityItem::Mortal, EntityItem::Static); } - foreach(EntityItem* entity, entitiesBecomingChanging) { - changeEntityState(entity, EntityItem::Mortal, EntityItem::Changing); - } foreach(EntityItem* entity, entitiesBecomingMoving) { changeEntityState(entity, EntityItem::Mortal, EntityItem::Moving); } diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index e32f9a9f47..9ce1e6b94a 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -12,6 +12,8 @@ #ifndef hifi_EntityTree_h #define hifi_EntityTree_h +#include + #include #include "EntityTreeElement.h" @@ -139,6 +141,7 @@ public: void changeEntityState(EntityItem* const entity, EntityItem::SimulationState oldState, EntityItem::SimulationState newState); + void entityChanged(EntityItem* entity); void addEntityToPhysicsWorld(EntityItem* entity); void removeEntityFromPhysicsWorld(EntityItem* entity); @@ -159,7 +162,7 @@ signals: private: - void updateChangingEntities(quint64 now, QSet& entitiesToDelete); + void updateChangedEntities(quint64 now, QSet& entitiesToDelete); void updateMovingEntities(quint64 now, QSet& entitiesToDelete); void updateMortalEntities(quint64 now, QSet& entitiesToDelete); @@ -179,9 +182,10 @@ private: QHash _entityToElementMap; - QList _movingEntities; // entities that are moving as part of update - QList _changingEntities; // entities that are changing (like animating), but not moving - QList _mortalEntities; // entities that are mortal (have lifetime), but not moving or changing + QList _movingEntities; // entities that need to be updated + QList _mortalEntities; // entities that need to be checked for expiry + + QSet _changedEntities; // entities that have changed in the last frame PhysicsWorld* _physicsWorld; }; diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index b26db16f89..f3fd8fc494 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -745,14 +745,10 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int QString entityScriptBefore = entityItem->getScript(); bool bestFitBefore = bestFitEntityBounds(entityItem); EntityTreeElement* currentContainingElement = _myTree->getContainingElement(entityItemID); - EntityItem::SimulationState oldState = entityItem->getSimulationState(); bytesForThisEntity = entityItem->readEntityDataFromBuffer(dataAt, bytesLeftToRead, args); - - EntityItem::SimulationState newState = entityItem->getSimulationState(); - if (oldState != newState) { - _myTree->changeEntityState(entityItem, oldState, newState); - } + // TODO: Andrew to only set changed if something has actually changed + _myTree->entityChanged(entityItem); bool bestFitAfter = bestFitEntityBounds(entityItem); if (bestFitBefore != bestFitAfter) { @@ -780,7 +776,7 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int entityItemID = entityItem->getEntityItemID(); _myTree->setContainingElement(entityItemID, this); _myTree->emitAddingEntity(entityItemID); // we just added an entity - EntityItem::SimulationState newState = entityItem->getSimulationState(); + EntityItem::SimulationState newState = entityItem->computeSimulationState(); _myTree->changeEntityState(entityItem, EntityItem::Static, newState); } } From 2d400e6ae0b55b37365817218b5e3f7d6d619ae1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 18 Nov 2014 09:55:25 -0800 Subject: [PATCH 039/105] rename PhysicsWorld to PhysicsEngine --- interface/src/Application.cpp | 14 +++++----- interface/src/Application.h | 3 +- interface/src/Physics.cpp | 6 ++-- interface/src/Physics.h | 8 +++--- .../entities/src/DeleteEntityOperator.cpp | 2 +- libraries/entities/src/EntityTree.cpp | 28 +++++++++---------- libraries/entities/src/EntityTree.h | 10 +++---- libraries/entities/src/EntityTreeElement.cpp | 8 +++--- libraries/entities/src/EntityTreeElement.h | 4 +-- libraries/physics/src/CustomMotionState.h | 4 +-- .../{PhysicsWorld.cpp => PhysicsEngine.cpp} | 24 ++++++++-------- .../src/{PhysicsWorld.h => PhysicsEngine.h} | 14 +++++----- libraries/physics/src/PhysicsEntity.h | 2 +- libraries/physics/src/VoxelObject.h | 2 +- 14 files changed, 64 insertions(+), 65 deletions(-) rename libraries/physics/src/{PhysicsWorld.cpp => PhysicsEngine.cpp} (91%) rename libraries/physics/src/{PhysicsWorld.h => PhysicsEngine.h} (93%) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bd75c3c6d8..58aa06e105 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -64,7 +64,7 @@ #include #include #include -#include +#include #include #include #include @@ -154,7 +154,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _importSucceded(false), _sharedVoxelSystem(TREE_SCALE, DEFAULT_MAX_VOXELS_PER_SYSTEM, &_clipboard), #ifdef USE_BULLET_PHYSICS - _physicsWorld(glm::vec3(0.0f)), + _physicsEngine(glm::vec3(0.0f)), #endif // USE_BULLET_PHYSICS _entities(true), _entityCollisionSystem(), @@ -2009,8 +2009,8 @@ void Application::init() { connect(_myAvatar, &MyAvatar::transformChanged, this, &Application::updateMyAvatarTransform); #ifdef USE_BULLET_PHYSICS - _physicsWorld.initSafe(_entities.getTree()); - _entities.getTree()->setPhysicsWorld(&_physicsWorld); + _physicsEngine.initSafe(_entities.getTree()); + _entities.getTree()->setPhysicsEngine(&_physicsEngine); #endif // USE_BULLET_PHYSICS } @@ -2320,7 +2320,7 @@ void Application::update(float deltaTime) { #ifdef USE_BULLET_PHYSICS { PerformanceTimer perfTimer("physics"); - _physicsWorld.stepSimulation(); + _physicsEngine.stepSimulation(); } #endif // USE_BULLET_PHYSICS @@ -4117,7 +4117,7 @@ void Application::updateMyAvatarTransform() { #ifdef USE_BULLET_PHYSICS const float SIMULATION_OFFSET_QUANTIZATION = 16.0f; // meters glm::vec3 avatarPosition = _myAvatar->getPosition(); - glm::vec3 physicsWorldOffset = _physicsWorld.getOriginOffset(); + glm::vec3 physicsWorldOffset = _physicsEngine.getOriginOffset(); if (glm::distance(avatarPosition, physicsWorldOffset) > SIMULATION_OFFSET_QUANTIZATION) { //_entityCollisionSystem.forgetAllPhysics(); glm::vec3 newOriginOffset = avatarPosition; @@ -4126,7 +4126,7 @@ void Application::updateMyAvatarTransform() { newOriginOffset[i] = (float)(glm::max(halfExtent, ((int)(avatarPosition[i] / SIMULATION_OFFSET_QUANTIZATION)) * (int)SIMULATION_OFFSET_QUANTIZATION)); } - _physicsWorld.setOriginOffset(newOriginOffset); + _physicsEngine.setOriginOffset(newOriginOffset); //_entityCollisionSystem.rememberAllPhysics(); } #endif // USE_BULLET_PHYSICS diff --git a/interface/src/Application.h b/interface/src/Application.h index 2420e68592..0ca777117d 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -35,7 +35,6 @@ #include #include #include -//#include #include #include #include @@ -495,7 +494,7 @@ private: ViewFrustum _sharedVoxelSystemViewFrustum; #ifdef USE_BULLET_PHYSICS - ThreadSafePhysicsWorld _physicsWorld; + ThreadSafePhysicsEngine _physicsEngine; #endif // USE_BULLET_PHYSICS EntityTreeRenderer _entities; diff --git a/interface/src/Physics.cpp b/interface/src/Physics.cpp index 63100ef504..35751371da 100644 --- a/interface/src/Physics.cpp +++ b/interface/src/Physics.cpp @@ -44,17 +44,17 @@ private: EntityTree* _entities; }; -ThreadSafePhysicsWorld::ThreadSafePhysicsWorld(const glm::vec3& offset) : PhysicsWorld(offset) { +ThreadSafePhysicsEngine::ThreadSafePhysicsEngine(const glm::vec3& offset) : PhysicsEngine(offset) { } -void ThreadSafePhysicsWorld::initSafe(EntityTree* entities) { +void ThreadSafePhysicsEngine::initSafe(EntityTree* entities) { assert(!_dynamicsWorld); // only call this once assert(entities); _collisionConfig = new btDefaultCollisionConfiguration(); _collisionDispatcher = new btCollisionDispatcher(_collisionConfig); _broadphaseFilter = new btDbvtBroadphase(); _constraintSolver = new btSequentialImpulseConstraintSolver; - // ThreadSafePhysicsWorld gets a DynamicsImpl, which derives from ThreadSafeDynamicsWorld + // ThreadSafePhysicsEngine gets a DynamicsImpl, which derives from ThreadSafeDynamicsWorld _dynamicsWorld = new DynamicsImpl(_collisionDispatcher, _broadphaseFilter, _constraintSolver, _collisionConfig, entities); } diff --git a/interface/src/Physics.h b/interface/src/Physics.h index 36bf46a180..fd2881184a 100644 --- a/interface/src/Physics.h +++ b/interface/src/Physics.h @@ -12,15 +12,15 @@ #ifndef hifi_Physics_h #define hifi_Physics_h -#include +#include class EntityTree; -class ThreadSafePhysicsWorld : public PhysicsWorld { +class ThreadSafePhysicsEngine : public PhysicsEngine { public: - ThreadSafePhysicsWorld(const glm::vec3& offset); + ThreadSafePhysicsEngine(const glm::vec3& offset); - // virtual override from PhysicsWorld + // virtual override from PhysicsEngine void init() { assert(false); } // call initSafe() instead void initSafe(EntityTree* entities); diff --git a/libraries/entities/src/DeleteEntityOperator.cpp b/libraries/entities/src/DeleteEntityOperator.cpp index 18dd8ed629..06927468f4 100644 --- a/libraries/entities/src/DeleteEntityOperator.cpp +++ b/libraries/entities/src/DeleteEntityOperator.cpp @@ -102,7 +102,7 @@ bool DeleteEntityOperator::preRecursion(OctreeElement* element) { EntityItem* theEntity = entityTreeElement->getEntityWithEntityItemID(entityItemID); // find the actual entity entityTreeElement->removeEntityItem(theEntity); // remove it from the element _tree->setContainingElement(entityItemID, NULL); // update or id to element lookup - _tree->removeEntityFromPhysicsWorld(theEntity); + _tree->removeEntityFromPhysicsEngine(theEntity); delete theEntity; // now actually delete the entity! _foundCount++; } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index d19dda8e6c..2364d347db 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -10,7 +10,7 @@ // #include -#include +#include #include "EntityTree.h" @@ -20,7 +20,7 @@ #include "MovingEntitiesOperator.h" #include "UpdateEntityOperator.h" -EntityTree::EntityTree(bool shouldReaverage) : Octree(shouldReaverage), _physicsWorld(NULL) { +EntityTree::EntityTree(bool shouldReaverage) : Octree(shouldReaverage), _physicsEngine(NULL) { _rootElement = createNewElement(); } @@ -37,7 +37,7 @@ EntityTreeElement* EntityTree::createNewElement(unsigned char * octalCode) { void EntityTree::eraseAllOctreeElements(bool createNewRoot) { // this would be a good place to clean up our entities... foreach (EntityTreeElement* element, _entityToElementMap) { - element->cleanupEntities(_physicsWorld); + element->cleanupEntities(_physicsEngine); } _entityToElementMap.clear(); Octree::eraseAllOctreeElements(createNewRoot); @@ -93,8 +93,8 @@ void EntityTree::addEntityItem(EntityItem* entity) { // check to see if we need to simulate this entity.. changeEntityState(entity, EntityItem::Static, entity->computeSimulationState()); - if (_physicsWorld && !entity->getMotionState()) { - addEntityToPhysicsWorld(entity); + if (_physicsEngine && !entity->getMotionState()) { + addEntityToPhysicsEngine(entity); } _isDirty = true; @@ -200,11 +200,11 @@ void EntityTree::trackDeletedEntity(const EntityItemID& entityID) { } } -void EntityTree::setPhysicsWorld(PhysicsWorld* world) { - if (_physicsWorld) { - // TODO: remove all entities before we clear the world +void EntityTree::setPhysicsEngine(PhysicsEngine* engine) { + if (_physicsEngine) { + // TODO: remove all entities before we clear the engine } - _physicsWorld = world; + _physicsEngine = engine; } void EntityTree::emitAddingEntity(const EntityItemID& entityItemID) { @@ -628,19 +628,19 @@ void EntityTree::entityChanged(EntityItem* entity) { _changedEntities.insert(entity); } -void EntityTree::addEntityToPhysicsWorld(EntityItem* entity) { +void EntityTree::addEntityToPhysicsEngine(EntityItem* entity) { EntityMotionState* motionState = entity->createMotionState(); - if (!_physicsWorld->addEntity(static_cast(motionState))) { - // failed to add to world: probably because of bad shape, + if (!_physicsEngine->addEntity(static_cast(motionState))) { + // failed to add to engine: probably because of bad shape, // probably because entity is too big or too small entity->destroyMotionState(); } } -void EntityTree::removeEntityFromPhysicsWorld(EntityItem* entity) { +void EntityTree::removeEntityFromPhysicsEngine(EntityItem* entity) { EntityMotionState* motionState = entity->getMotionState(); if (motionState) { - _physicsWorld->removeEntity(static_cast(motionState)); + _physicsEngine->removeEntity(static_cast(motionState)); entity->destroyMotionState(); } } diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 9ce1e6b94a..25b12a8c18 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -19,7 +19,7 @@ class Model; -class PhysicsWorld; +class PhysicsEngine; class NewlyCreatedEntityHook { public: @@ -142,8 +142,8 @@ public: EntityItem::SimulationState oldState, EntityItem::SimulationState newState); void entityChanged(EntityItem* entity); - void addEntityToPhysicsWorld(EntityItem* entity); - void removeEntityFromPhysicsWorld(EntityItem* entity); + void addEntityToPhysicsEngine(EntityItem* entity); + void removeEntityFromPhysicsEngine(EntityItem* entity); void trackDeletedEntity(const EntityItemID& entityID); @@ -152,7 +152,7 @@ public: QList& getMovingEntities() { return _movingEntities; } - void setPhysicsWorld(PhysicsWorld* world); + void setPhysicsEngine(PhysicsEngine* engine); signals: void deletingEntity(const EntityItemID& entityID); @@ -187,7 +187,7 @@ private: QSet _changedEntities; // entities that have changed in the last frame - PhysicsWorld* _physicsWorld; + PhysicsEngine* _physicsEngine; }; #endif // hifi_EntityTree_h diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index f3fd8fc494..c48377e252 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -16,7 +16,7 @@ #include #include -#include +#include #include "EntityMotionState.h" #include "EntityTree.h" @@ -655,14 +655,14 @@ EntityItem* EntityTreeElement::getEntityWithEntityItemID(const EntityItemID& id) return foundEntity; } -void EntityTreeElement::cleanupEntities(PhysicsWorld* physicsWorld) { +void EntityTreeElement::cleanupEntities(PhysicsEngine* physicsEngine) { uint16_t numberOfEntities = _entityItems->size(); for (uint16_t i = 0; i < numberOfEntities; i++) { EntityItem* entity = (*_entityItems)[i]; EntityMotionState* motionState = entity->getMotionState(); if (motionState) { - assert(physicsWorld); - physicsWorld->removeEntity(static_cast(motionState)); + assert(physicsEngine); + physicsEngine->removeEntity(static_cast(motionState)); entity->destroyMotionState(); } delete entity; diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index 7e26aacf1c..df6342fd97 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -21,7 +21,7 @@ class EntityTree; class EntityTreeElement; -class PhysicsWorld; +class PhysicsEngine; class EntityTreeUpdateArgs { public: @@ -176,7 +176,7 @@ public: EntityItem* getEntityWithEntityItemID(const EntityItemID& id); - void cleanupEntities(PhysicsWorld* physicsWorld); + void cleanupEntities(PhysicsEngine* physicsEngine); bool removeEntityWithEntityItemID(const EntityItemID& id); bool removeEntityItem(EntityItem* entity); diff --git a/libraries/physics/src/CustomMotionState.h b/libraries/physics/src/CustomMotionState.h index 7db25d3899..7801625e09 100644 --- a/libraries/physics/src/CustomMotionState.h +++ b/libraries/physics/src/CustomMotionState.h @@ -53,7 +53,7 @@ public: void getVelocity(glm::vec3& velocityOut) const; void getAngularVelocity(glm::vec3& angularVelocityOut) const; - friend class PhysicsWorld; + friend class PhysicsEngine; protected: float _density; @@ -63,7 +63,7 @@ protected: bool _wasInWorld; MotionType _motionType; - // _body has NO setters -- it is only changed by PhysicsWorld + // _body has NO setters -- it is only changed by PhysicsEngine btRigidBody* _body; }; diff --git a/libraries/physics/src/PhysicsWorld.cpp b/libraries/physics/src/PhysicsEngine.cpp similarity index 91% rename from libraries/physics/src/PhysicsWorld.cpp rename to libraries/physics/src/PhysicsEngine.cpp index 518989c81f..515ce6b8e1 100644 --- a/libraries/physics/src/PhysicsWorld.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -1,5 +1,5 @@ // -// PhysicsWorld.cpp +// PhysicsEngine.cpp // libraries/physcis/src // // Created by Andrew Meadows 2014.10.29 @@ -9,14 +9,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "PhysicsWorld.h" +#include "PhysicsEngine.h" #ifdef USE_BULLET_PHYSICS -PhysicsWorld::~PhysicsWorld() { +PhysicsEngine::~PhysicsEngine() { } // virtual -void PhysicsWorld::init() { +void PhysicsEngine::init() { if (!_dynamicsWorld) { _collisionConfig = new btDefaultCollisionConfiguration(); _collisionDispatcher = new btCollisionDispatcher(_collisionConfig); @@ -46,7 +46,7 @@ void PhysicsWorld::init() { } } -void PhysicsWorld::stepSimulation() { +void PhysicsEngine::stepSimulation() { const float MAX_TIMESTEP = 1.0f / 30.0f; const int MAX_NUM_SUBSTEPS = 2; const float FIXED_SUBSTEP = 1.0f / 60.0f; @@ -57,7 +57,7 @@ void PhysicsWorld::stepSimulation() { _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, FIXED_SUBSTEP); } -bool PhysicsWorld::addVoxel(const glm::vec3& position, float scale) { +bool PhysicsEngine::addVoxel(const glm::vec3& position, float scale) { glm::vec3 halfExtents = glm::vec3(0.5f * scale); glm::vec3 trueCenter = position + halfExtents; PositionHashKey key(trueCenter); @@ -89,7 +89,7 @@ bool PhysicsWorld::addVoxel(const glm::vec3& position, float scale) { return false; } -bool PhysicsWorld::removeVoxel(const glm::vec3& position, float scale) { +bool PhysicsEngine::removeVoxel(const glm::vec3& position, float scale) { glm::vec3 halfExtents = glm::vec3(0.5f * scale); glm::vec3 trueCenter = position + halfExtents; PositionHashKey key(trueCenter); @@ -122,7 +122,7 @@ bool PhysicsWorld::removeVoxel(const glm::vec3& position, float scale) { // CF_DISABLE_VISUALIZE_OBJECT = 32, //disable debug drawing // CF_DISABLE_SPU_COLLISION_PROCESSING = 64//disable parallel/SPU processing -bool PhysicsWorld::addEntity(CustomMotionState* motionState) { +bool PhysicsEngine::addEntity(CustomMotionState* motionState) { assert(motionState); ShapeInfo info; motionState->computeShapeInfo(info); @@ -166,7 +166,7 @@ bool PhysicsWorld::addEntity(CustomMotionState* motionState) { return false; } -bool PhysicsWorld::updateEntityMotionType(CustomMotionState* motionState) { +bool PhysicsEngine::updateEntityMotionType(CustomMotionState* motionState) { btRigidBody* body = motionState->_body; if (!body) { return false; @@ -216,7 +216,7 @@ bool PhysicsWorld::updateEntityMotionType(CustomMotionState* motionState) { return false; } -bool PhysicsWorld::removeEntity(CustomMotionState* motionState) { +bool PhysicsEngine::removeEntity(CustomMotionState* motionState) { assert(motionState); btRigidBody* body = motionState->_body; if (body) { @@ -232,13 +232,13 @@ bool PhysicsWorld::removeEntity(CustomMotionState* motionState) { return false; } -bool PhysicsWorld::updateEntityMotionType(CustomMotionState* motionState, MotionType type) { +bool PhysicsEngine::updateEntityMotionType(CustomMotionState* motionState, MotionType type) { // TODO: implement this assert(motionState); return false; } -bool PhysicsWorld::updateEntityMassProperties(CustomMotionState* motionState, float mass, const glm::vec3& inertiaEigenValues) { +bool PhysicsEngine::updateEntityMassProperties(CustomMotionState* motionState, float mass, const glm::vec3& inertiaEigenValues) { // TODO: implement this assert(motionState); return false; diff --git a/libraries/physics/src/PhysicsWorld.h b/libraries/physics/src/PhysicsEngine.h similarity index 93% rename from libraries/physics/src/PhysicsWorld.h rename to libraries/physics/src/PhysicsEngine.h index 1ff06c9c5d..b9475e43d1 100644 --- a/libraries/physics/src/PhysicsWorld.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -1,5 +1,5 @@ // -// PhysicsWorld.h +// PhysicsEngine.h // libraries/physcis/src // // Created by Andrew Meadows 2014.10.29 @@ -9,8 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_PhysicsWorld_h -#define hifi_PhysicsWorld_h +#ifndef hifi_PhysicsEngine_h +#define hifi_PhysicsEngine_h #ifdef USE_BULLET_PHYSICS @@ -24,10 +24,10 @@ const float HALF_SIMULATION_EXTENT = 512.0f; // meters -class PhysicsWorld { +class PhysicsEngine { public: - PhysicsWorld(const glm::vec3& offset) + PhysicsEngine(const glm::vec3& offset) : _collisionConfig(NULL), _collisionDispatcher(NULL), _broadphaseFilter(NULL), @@ -37,7 +37,7 @@ public: _voxels() { } - ~PhysicsWorld(); + ~PhysicsEngine(); virtual void init(); @@ -91,4 +91,4 @@ private: #endif // USE_BULLET_PHYSICS -#endif // hifi_PhysicsWorld_h +#endif // hifi_PhysicsEngine_h diff --git a/libraries/physics/src/PhysicsEntity.h b/libraries/physics/src/PhysicsEntity.h index 0487b9b078..bf401d9339 100644 --- a/libraries/physics/src/PhysicsEntity.h +++ b/libraries/physics/src/PhysicsEntity.h @@ -19,7 +19,7 @@ #include #ifdef USE_BULLET_PHYSICS -#include "PhysicsWorld.h" +#include "PhysicsEngine.h" #endif // USE_BULLET_PHYSICS #include "CollisionInfo.h" diff --git a/libraries/physics/src/VoxelObject.h b/libraries/physics/src/VoxelObject.h index 49866e0bce..1372f761c7 100644 --- a/libraries/physics/src/VoxelObject.h +++ b/libraries/physics/src/VoxelObject.h @@ -17,7 +17,7 @@ #include #include -// VoxelObject is a simple wrapper for tracking a Voxel in a PhysicsWorld +// VoxelObject is a simple wrapper for tracking a Voxel in a PhysicsEngine class VoxelObject { public: VoxelObject(const glm::vec3& center, btCollisionObject* object) : _object(object), _center(center) { From 3b85805048911ff2dd2a8dcd6e5418938f72f14f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 19 Nov 2014 14:01:55 -0800 Subject: [PATCH 040/105] add EntityItem::updateFoo() methods that set flags when properties are actually changed --- libraries/entities/src/EntityItem.cpp | 109 ++++++++++++++++++++++++-- libraries/entities/src/EntityItem.h | 34 +++++++- 2 files changed, 134 insertions(+), 9 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index bd0834109c..8bdf4aba6d 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -94,6 +94,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) { #ifdef USE_BULLET_PHYSICS _motionState = NULL; #endif // USE_BULLET_PHYSICS + _updateFlags = 0; _changedOnServer = 0; initFromEntityItemID(entityItemID); _simulationState = EntityItem::Static; @@ -109,6 +110,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert #ifdef USE_BULLET_PHYSICS _motionState = NULL; #endif // USE_BULLET_PHYSICS + _updateFlags = 0; _changedOnServer = 0; initFromEntityItemID(entityItemID); setProperties(properties, true); // force copy @@ -523,7 +525,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, _angularDamping); READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, _visible); READ_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, bool, _ignoreForCollisions); - READ_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, bool, _collisionsWillMove); + READ_ENTITY_PROPERTY_SETTER(PROP_COLLISIONS_WILL_MOVE, bool, setCollisionsWillMove); READ_ENTITY_PROPERTY(PROP_LOCKED, bool, _locked); READ_ENTITY_PROPERTY_STRING(PROP_USER_DATA,setUserData); @@ -750,11 +752,6 @@ bool EntityItem::lifetimeHasExpired() const { return isMortal() && (getAge() > getLifetime()); } - -void EntityItem::copyChangedProperties(const EntityItem& other) { - *this = other; -} - EntityItemProperties EntityItem::getProperties() const { EntityItemProperties properties; properties._id = getID(); @@ -967,6 +964,106 @@ void EntityItem::recalculateCollisionShape() { // TODO: use motionState to update physics object } +void EntityItem::updatePosition(const glm::vec3& value) { + if (_position != value) { + _position = value; + recalculateCollisionShape(); + _updateFlags |= UPDATE_POSITION; + } +} + +void EntityItem::updatePositionInMeters(const glm::vec3& value) { + glm::vec3 position = glm::clamp(value / (float) TREE_SCALE, 0.0f, 1.0f); + if (_position != position) { + _position = position; + recalculateCollisionShape(); + _updateFlags |= UPDATE_POSITION; + } +} + +void EntityItem::updateDimensions(const glm::vec3& value) { + if (_dimensions != value) { + _dimensions = value; + recalculateCollisionShape(); + _updateFlags |= UPDATE_SHAPE; + } +} + +void EntityItem::updateDimensionsInMeters(const glm::vec3& value) { + glm::vec3 dimensions = value / (float) TREE_SCALE; + if (_dimensions != dimensions) { + _dimensions = dimensions; + recalculateCollisionShape(); + _updateFlags |= UPDATE_SHAPE; + } +} + +void EntityItem::updateRotation(const glm::quat& rotation) { + if (_rotation != rotation) { + _rotation = rotation; + recalculateCollisionShape(); + _updateFlags |= UPDATE_POSITION; + } +} + +void EntityItem::updateMass(float value) { + if (_mass != value) { + _mass = value; + _updateFlags |= UPDATE_MASS; + } +} + +void EntityItem::updateVelocity(const glm::vec3& value) { + if (_velocity != value) { + _velocity = value; + _updateFlags |= UPDATE_VELOCITY; + } +} + +void EntityItem::updateVelocityInMeters(const glm::vec3& value) { + glm::vec3 velocity = value / (float) TREE_SCALE; + if (_velocity != velocity) { + _velocity = velocity; + _updateFlags |= UPDATE_VELOCITY; + } +} + +void EntityItem::updateGravity(const glm::vec3& value) { + if (_gravity != value) { + _gravity = value; + _updateFlags |= UPDATE_VELOCITY; + } +} + +void EntityItem::updateGravityInMeters(const glm::vec3& value) { + glm::vec3 gravity = value / (float) TREE_SCALE; + if (_gravity != gravity) { + _gravity = gravity; + _updateFlags |= UPDATE_VELOCITY; + } +} + +void EntityItem::updateAngularVelocity(const glm::vec3& value) { + if (_angularVelocity != value) { + _angularVelocity = value; + _updateFlags |= UPDATE_VELOCITY; + } +} + +void EntityItem::updateIgnoreForCollisions(bool value) { + if (_ignoreForCollisions != value) { + _ignoreForCollisions = value; + _updateFlags |= UPDATE_COLLISION; + } +} + +void EntityItem::updateCollisionsWillMove(bool value) { + if (_collisionsWillMove != value) { + _collisionsWillMove = value; + _updateFlags |= UPDATE_COLLISION; + } +} + #ifdef USE_BULLET_PHYSICS void EntityItem::destroyMotionState() { if (_motionState) { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 3b569a8830..5e71e4a89e 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -39,6 +39,15 @@ class EntityTreeElementExtraEncodeData; class EntityMotionState; #endif // USE_BULLET_PHYSICS +enum EntityUpdateFlags { + UPDATE_POSITION = 0x0001, + UPDATE_VELOCITY = 0x0002, + UPDATE_MASS = 0x0004, + UPDATE_COLLISION = 0x0008, + UPDATE_SHAPE = 0x0010, + //UPDATE_APPEARANCE = 0x8000, +}; + /// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available /// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate @@ -129,9 +138,6 @@ public: virtual void debugDump() const; - // similar to assignment/copy, but it handles keeping lifetime accurate - void copyChangedProperties(const EntityItem& other); - // attributes applicable to all entity types EntityTypes::EntityType getType() const { return _type; } const glm::vec3& getPosition() const { return _position; } /// get position in domain scale units (0.0 - 1.0) @@ -270,6 +276,24 @@ public: virtual const Shape& getCollisionShapeInMeters() const { return _collisionShape; } virtual bool contains(const glm::vec3& point) const { return getAABox().contains(point); } + // updateFoo() methods to be used when changes need to be accumulated in the _updateFlags + void updatePosition(const glm::vec3& value); + void updatePositionInMeters(const glm::vec3& value); + void updateDimensions(const glm::vec3& value); + void updateDimensionsInMeters(const glm::vec3& value); + void updateRotation(const glm::quat& rotation); + void updateMass(float value); + void updateVelocity(const glm::vec3& value); + void updateVelocityInMeters(const glm::vec3& value); + void updateGravity(const glm::vec3& value); + void updateGravityInMeters(const glm::vec3& value); + void updateAngularVelocity(const glm::vec3& value); + void updateIgnoreForCollisions(bool value); + void updateCollisionsWillMove(bool value); + + void setUpdateFlags(uint32_t mask) { _updateFlags |= mask; } + void clearUpdateFlags(uint32_t mask) { _updateFlags &= ~mask; } + #ifdef USE_BULLET_PHYSICS EntityMotionState* getMotionState() const { return _motionState; } virtual EntityMotionState* createMotionState() { return NULL; } @@ -326,6 +350,10 @@ protected: EntityMotionState* _motionState; #endif // USE_BULLET_PHYSICS SimulationState _simulationState; // only set by EntityTree + + // UpdateFlags are set whenever a property changes that requires the change to be communicated to other + // data structures. It is the responsibility of the EntityTree to relay changes entity and clear flags. + uint32_t _updateFlags; }; From 48164c9399fda7eeffd96ef6c5e517b714a4bd84 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 19 Nov 2014 15:31:17 -0800 Subject: [PATCH 041/105] cleanup and moving things around --- libraries/entities/src/EntityTree.cpp | 3 +- libraries/physics/src/PhysicsEngine.cpp | 40 +++++++++++-------------- libraries/physics/src/PhysicsEngine.h | 8 ++--- 3 files changed, 21 insertions(+), 30 deletions(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 97a992cb48..7d37962696 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -669,8 +669,7 @@ void EntityTree::update() { // 1) stationary things that are not changing - most models // 2) mortal things - these are stationary but have a lifetime - then need to be checked, // can be touched linearly, and won't change the tree - // 2) changing things - like things animating they can be touched linearly and they don't change the tree - // 3) moving things - these need to scan the tree and update accordingly + // 2) moving/changing things - like things animating they can be touched linearly and they don't change the tree // finally - all things that need to be deleted, can be handled on a single delete pass. // // TODO: theoretically we could combine the move and delete tree passes... diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 515ce6b8e1..94d92f19f8 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -149,8 +149,8 @@ bool PhysicsEngine::addEntity(CustomMotionState* motionState) { motionState->applyVelocities(); break; } + case MOTION_TYPE_STATIC: default: { - // MOTION_TYPE_STATIC body = new btRigidBody(mass, motionState, shape, inertia); body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT); body->updateInertiaTensor(); @@ -166,6 +166,22 @@ bool PhysicsEngine::addEntity(CustomMotionState* motionState) { return false; } +bool PhysicsEngine::removeEntity(CustomMotionState* motionState) { + assert(motionState); + btRigidBody* body = motionState->_body; + if (body) { + const btCollisionShape* shape = body->getCollisionShape(); + ShapeInfo info; + info.collectInfo(shape); + _dynamicsWorld->removeRigidBody(body); + _shapeManager.releaseShape(info); + delete body; + motionState->_body = NULL; + return true; + } + return false; +} + bool PhysicsEngine::updateEntityMotionType(CustomMotionState* motionState) { btRigidBody* body = motionState->_body; if (!body) { @@ -216,28 +232,6 @@ bool PhysicsEngine::updateEntityMotionType(CustomMotionState* motionState) { return false; } -bool PhysicsEngine::removeEntity(CustomMotionState* motionState) { - assert(motionState); - btRigidBody* body = motionState->_body; - if (body) { - const btCollisionShape* shape = body->getCollisionShape(); - ShapeInfo info; - info.collectInfo(shape); - _dynamicsWorld->removeRigidBody(body); - _shapeManager.releaseShape(info); - delete body; - motionState->_body = NULL; - return true; - } - return false; -} - -bool PhysicsEngine::updateEntityMotionType(CustomMotionState* motionState, MotionType type) { - // TODO: implement this - assert(motionState); - return false; -} - bool PhysicsEngine::updateEntityMassProperties(CustomMotionState* motionState, float mass, const glm::vec3& inertiaEigenValues) { // TODO: implement this assert(motionState); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index a29769ccb5..222860e575 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -63,15 +63,13 @@ public: /// \return true if Entity added bool addEntity(CustomMotionState* motionState); - /// \param motionState pointer to Entity's MotionState - /// \return true if entity updated - bool updateEntityMotionType(CustomMotionState* motionState); - /// \param motionState pointer to Entity's MotionState /// \return true if Entity removed bool removeEntity(CustomMotionState* motionState); - bool updateEntityMotionType(CustomMotionState* motionState, MotionType type); + /// \param motionState pointer to Entity's MotionState + /// \return true if entity updated + bool updateEntityMotionType(CustomMotionState* motionState); bool updateEntityMassProperties(CustomMotionState* motionState, float mass, const glm::vec3& inertiaEigenValues); From 51da6786759f5558ee003bde6d577c5d536e2a04 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 19 Nov 2014 17:05:31 -0800 Subject: [PATCH 042/105] update entity MotionType when it changes --- libraries/entities/src/DeleteEntityOperator.cpp | 1 + libraries/entities/src/EntityItem.cpp | 4 ++-- libraries/entities/src/EntityTree.cpp | 8 +++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/DeleteEntityOperator.cpp b/libraries/entities/src/DeleteEntityOperator.cpp index 06927468f4..c0fe51a75e 100644 --- a/libraries/entities/src/DeleteEntityOperator.cpp +++ b/libraries/entities/src/DeleteEntityOperator.cpp @@ -103,6 +103,7 @@ bool DeleteEntityOperator::preRecursion(OctreeElement* element) { entityTreeElement->removeEntityItem(theEntity); // remove it from the element _tree->setContainingElement(entityItemID, NULL); // update or id to element lookup _tree->removeEntityFromPhysicsEngine(theEntity); + theEntity->destroyMotionState(); delete theEntity; // now actually delete the entity! _foundCount++; } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index d8750ab297..e610ed4c2f 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -119,8 +119,8 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert EntityItem::~EntityItem() { #ifdef USE_BULLET_PHYSICS - // make sure the _motionState is already deleted (e.g. the entity has been removed - // from the physics simulation) BEFORE you get here + // Make sure the EntityItem has been removed from the physics engine AND + // that its _motionState has been destroyed BEFORE you get here. assert(_motionState == NULL); #endif // USE_BULLET_PHYSICS } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 28968b051e..2e697eebbb 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -619,6 +619,13 @@ void EntityTree::updateEntityState(EntityItem* entity) { break; } entity->setSimulationState(newState); + + if (_physicsEngine) { + EntityMotionState* motionState = entity->getMotionState(); + if (motionState) { + _physicsEngine->updateEntityMotionType(motionState); + } + } } } @@ -659,7 +666,6 @@ void EntityTree::removeEntityFromPhysicsEngine(EntityItem* entity) { EntityMotionState* motionState = entity->getMotionState(); if (motionState) { _physicsEngine->removeEntity(static_cast(motionState)); - entity->destroyMotionState(); } #endif // USE_BULLET_PHYSICS } From eda779b434fd071a504e98b28654da8bc6d9f84e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 24 Nov 2014 11:04:27 -0800 Subject: [PATCH 043/105] add != operator for AACube --- libraries/shared/src/AACube.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/shared/src/AACube.h b/libraries/shared/src/AACube.h index 7067175f3a..6de27ad433 100644 --- a/libraries/shared/src/AACube.h +++ b/libraries/shared/src/AACube.h @@ -78,6 +78,10 @@ inline bool operator==(const AACube& a, const AACube& b) { return a.getCorner() == b.getCorner() && a.getScale() == b.getScale(); } +inline bool operator!=(const AACube& a, const AACube& b) { + return a.getCorner() != b.getCorner() || a.getScale() == b.getScale(); +} + inline QDebug operator<<(QDebug debug, const AACube& cube) { debug << "AACube[ (" << cube.getCorner().x << "," << cube.getCorner().y << "," << cube.getCorner().z << " ) to (" From ec1f11c1a896d47d74f9514c7df34d3c471d9e59 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 24 Nov 2014 11:21:40 -0800 Subject: [PATCH 044/105] route more entity updates into physics engine --- .../entities/src/EntityCollisionSystem.cpp | 4 +- libraries/entities/src/EntityItem.cpp | 47 +++--- libraries/entities/src/EntityItem.h | 33 ++-- libraries/entities/src/EntityMotionState.cpp | 51 ++++-- libraries/entities/src/EntityMotionState.h | 14 +- libraries/entities/src/EntityTree.cpp | 71 +++++---- libraries/entities/src/EntityTree.h | 6 +- libraries/entities/src/EntityTreeElement.cpp | 14 +- .../entities/src/UpdateEntityOperator.cpp | 15 +- libraries/physics/src/CustomMotionState.cpp | 6 + libraries/physics/src/CustomMotionState.h | 2 + libraries/physics/src/PhysicsEngine.cpp | 148 +++++++++++++----- libraries/physics/src/PhysicsEngine.h | 26 ++- 13 files changed, 290 insertions(+), 147 deletions(-) diff --git a/libraries/entities/src/EntityCollisionSystem.cpp b/libraries/entities/src/EntityCollisionSystem.cpp index 903cd430de..448a39de78 100644 --- a/libraries/entities/src/EntityCollisionSystem.cpp +++ b/libraries/entities/src/EntityCollisionSystem.cpp @@ -50,7 +50,9 @@ void EntityCollisionSystem::update() { if (_entities->tryLockForRead()) { QList& movingEntities = _entities->getMovingEntities(); foreach (EntityItem* entity, movingEntities) { - checkEntity(entity); + if (!entity->getMotionState()) { + checkEntity(entity); + } } _entities->unlock(); } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index e610ed4c2f..f07ce3ca16 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -91,9 +91,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) { _lastEditedFromRemoteInRemoteTime = 0; _lastUpdated = 0; _created = 0; -#ifdef USE_BULLET_PHYSICS _motionState = NULL; -#endif // USE_BULLET_PHYSICS _updateFlags = 0; _changedOnServer = 0; initFromEntityItemID(entityItemID); @@ -107,9 +105,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert _lastEditedFromRemoteInRemoteTime = 0; _lastUpdated = 0; _created = properties.getCreated(); -#ifdef USE_BULLET_PHYSICS _motionState = NULL; -#endif // USE_BULLET_PHYSICS _updateFlags = 0; _changedOnServer = 0; initFromEntityItemID(entityItemID); @@ -118,11 +114,9 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert } EntityItem::~EntityItem() { -#ifdef USE_BULLET_PHYSICS // Make sure the EntityItem has been removed from the physics engine AND // that its _motionState has been destroyed BEFORE you get here. assert(_motionState == NULL); -#endif // USE_BULLET_PHYSICS } EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& params) const { @@ -519,7 +513,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY_SETTER(PROP_GRAVITY, glm::vec3, updateGravity); READ_ENTITY_PROPERTY(PROP_DAMPING, float, _damping); READ_ENTITY_PROPERTY_SETTER(PROP_LIFETIME, float, updateLifetime); - READ_ENTITY_PROPERTY_STRING(PROP_SCRIPT,setScript); + READ_ENTITY_PROPERTY_STRING(PROP_SCRIPT, updateScript); READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, _registrationPoint); READ_ENTITY_PROPERTY_SETTER(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity); READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, _angularDamping); @@ -797,23 +791,23 @@ bool EntityItem::setProperties(const EntityItemProperties& properties, bool forc } } - SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, setPositionInMeters); // this will call recalculate collision shape if needed - SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, setDimensionsInMeters); // NOTE: radius is obsolete - SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, setRotation); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(mass, setMass); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocity, setVelocityInMeters); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(gravity, setGravityInMeters); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, updatePositionInMeters); // this will call recalculate collision shape if needed + SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, updateDimensionsInMeters); // NOTE: radius is obsolete + SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, updateRotation); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(mass, updateMass); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocity, updateVelocityInMeters); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(gravity, updateGravityInMeters); SET_ENTITY_PROPERTY_FROM_PROPERTIES(damping, setDamping); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, setLifetime); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, setScript); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, updateLifetime); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, updateScript); SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, setRegistrationPoint); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularVelocity, setAngularVelocity); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularVelocity, updateAngularVelocity); SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularDamping, setAngularDamping); SET_ENTITY_PROPERTY_FROM_PROPERTIES(glowLevel, setGlowLevel); SET_ENTITY_PROPERTY_FROM_PROPERTIES(localRenderAlpha, setLocalRenderAlpha); SET_ENTITY_PROPERTY_FROM_PROPERTIES(visible, setVisible); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignoreForCollisions, setIgnoreForCollisions); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, setCollisionsWillMove); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignoreForCollisions, updateIgnoreForCollisions); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, updateCollisionsWillMove); SET_ENTITY_PROPERTY_FROM_PROPERTIES(locked, setLocked); SET_ENTITY_PROPERTY_FROM_PROPERTIES(userData, setUserData); @@ -985,7 +979,7 @@ void EntityItem::updateDimensions(const glm::vec3& value) { if (_dimensions != value) { _dimensions = value; recalculateCollisionShape(); - _updateFlags |= EntityItem::UPDATE_SHAPE; + _updateFlags |= (EntityItem::UPDATE_SHAPE | EntityItem::UPDATE_MASS); } } @@ -994,7 +988,7 @@ void EntityItem::updateDimensionsInMeters(const glm::vec3& value) { if (_dimensions != dimensions) { _dimensions = dimensions; recalculateCollisionShape(); - _updateFlags |= EntityItem::UPDATE_SHAPE; + _updateFlags |= (EntityItem::UPDATE_SHAPE | EntityItem::UPDATE_MASS); } } @@ -1031,7 +1025,7 @@ void EntityItem::updateVelocityInMeters(const glm::vec3& value) { void EntityItem::updateGravity(const glm::vec3& value) { if (_gravity != value) { _gravity = value; - _updateFlags |= EntityItem::UPDATE_VELOCITY; + _updateFlags |= EntityItem::UPDATE_GRAVITY; } } @@ -1039,7 +1033,7 @@ void EntityItem::updateGravityInMeters(const glm::vec3& value) { glm::vec3 gravity = value / (float) TREE_SCALE; if (_gravity != gravity) { _gravity = gravity; - _updateFlags |= EntityItem::UPDATE_VELOCITY; + _updateFlags |= EntityItem::UPDATE_GRAVITY; } } @@ -1071,12 +1065,17 @@ void EntityItem::updateLifetime(float value) { } } -#ifdef USE_BULLET_PHYSICS +void EntityItem::updateScript(const QString& value) { + if (_script != value) { + _script = value; + _updateFlags |= EntityItem::UPDATE_SCRIPT; + } +} + void EntityItem::destroyMotionState() { if (_motionState) { delete _motionState; _motionState = NULL; } } -#endif // USE_BULLET_PHYSICS diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 3c84fd193d..a32bd111d0 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -22,6 +22,7 @@ #include // for EncodeBitstreamParams class #include // for OctreeElement::AppendState #include +#include #include #include "EntityItemID.h" @@ -35,9 +36,7 @@ class EntityTreeElementExtraEncodeData; #define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0; #define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() { }; -#ifdef USE_BULLET_PHYSICS class EntityMotionState; -#endif // USE_BULLET_PHYSICS /// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available /// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate @@ -46,14 +45,21 @@ class EntityItem { public: enum EntityUpdateFlags { - UPDATE_POSITION = 0x0001, - UPDATE_VELOCITY = 0x0002, - UPDATE_MASS = 0x0004, - UPDATE_COLLISION_GROUP = 0x0008, - UPDATE_MOTION_TYPE = 0x0010, - UPDATE_SHAPE = 0x0020, - UPDATE_LIFETIME = 0x0040 - //UPDATE_APPEARANCE = 0x8000, + // flags for things that need to be relayed to physics engine + UPDATE_POSITION = PHYSICS_UPDATE_POSITION, //0x0001, + UPDATE_VELOCITY = PHYSICS_UPDATE_VELOCITY, //0x0002, + UPDATE_GRAVITY = PHYSICS_UPDATE_GRAVITY, //0x0004, + UPDATE_MASS = PHYSICS_UPDATE_MASS, //0x0008, + UPDATE_COLLISION_GROUP = PHYSICS_UPDATE_COLLISION_GROUP, //0x0010, + UPDATE_MOTION_TYPE = PHYSICS_UPDATE_MOTION_TYPE, //0x0020, + UPDATE_SHAPE = PHYSICS_UPDATE_SHAPE, //0x0040, + //... + // add new flags here in the middle + //... + // non-physics stuff + UPDATE_SCRIPT = 0x2000, + UPDATE_LIFETIME = 0x4000, + UPDATE_APPEARANCE = 0x8000 }; DONT_ALLOW_INSTANTIATION // This class can not be instantiated directly @@ -292,19 +298,18 @@ public: void updateIgnoreForCollisions(bool value); void updateCollisionsWillMove(bool value); void updateLifetime(float value); + void updateScript(const QString& value); uint32_t getUpdateFlags() const { return _updateFlags; } - void clearUpdateFlags() { _updateFlags = 0; } -#ifdef USE_BULLET_PHYSICS EntityMotionState* getMotionState() const { return _motionState; } virtual EntityMotionState* createMotionState() { return NULL; } void destroyMotionState(); -#endif // USE_BULLET_PHYSICS SimulationState getSimulationState() const { return _simulationState; } protected: friend class EntityTree; + void clearUpdateFlags() { _updateFlags = 0; } void setSimulationState(SimulationState state) { _simulationState = state; } virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init @@ -348,9 +353,7 @@ protected: void setRadius(float value); AACubeShape _collisionShape; -#ifdef USE_BULLET_PHYSICS EntityMotionState* _motionState; -#endif // USE_BULLET_PHYSICS SimulationState _simulationState; // only set by EntityTree // UpdateFlags are set whenever a property changes that requires the change to be communicated to other diff --git a/libraries/entities/src/EntityMotionState.cpp b/libraries/entities/src/EntityMotionState.cpp index be15f1cfe9..b27e372902 100644 --- a/libraries/entities/src/EntityMotionState.cpp +++ b/libraries/entities/src/EntityMotionState.cpp @@ -11,6 +11,7 @@ #ifdef USE_BULLET_PHYSICS #include +#endif // USE_BULLET_PHYSICS #include "EntityItem.h" #include "EntityMotionState.h" @@ -41,9 +42,10 @@ MotionType EntityMotionState::getMotionType() const { // HACK: According to EntityTree the meaning of "static" is "not moving" whereas // to Bullet it means "can't move". For demo purposes we temporarily interpret // Entity::weightless to mean Bullet::static. - return _entity->hasGravity() ? MOTION_TYPE_DYNAMIC : MOTION_TYPE_STATIC; + return _entity->getCollisionsWillMove() ? MOTION_TYPE_DYNAMIC : MOTION_TYPE_STATIC; } +#ifdef USE_BULLET_PHYSICS // This callback is invoked by the physics simulation in two cases: // (1) when the RigidBody is first added to the world // (irregardless of MotionType: STATIC, DYNAMIC, or KINEMATIC) @@ -64,34 +66,54 @@ void EntityMotionState::getWorldTransform (btTransform &worldTrans) const { // This callback is invoked by the physics simulation at the end of each simulation frame... // iff the corresponding RigidBody is DYNAMIC and has moved. void EntityMotionState::setWorldTransform (const btTransform &worldTrans) { - glm::vec3 pos; - bulletToGLM(worldTrans.getOrigin(), pos); - _entity->setPositionInMeters(pos + _cachedWorldOffset); + uint32_t updateFlags = _entity->getUpdateFlags(); + if (! (updateFlags & PHYSICS_UPDATE_POSITION)) { + glm::vec3 pos; + bulletToGLM(worldTrans.getOrigin(), pos); + _entity->setPositionInMeters(pos + _cachedWorldOffset); + + glm::quat rot; + bulletToGLM(worldTrans.getRotation(), rot); + _entity->setRotation(rot); + } - glm::quat rot; - bulletToGLM(worldTrans.getRotation(), rot); - _entity->setRotation(rot); - - glm::vec3 v; - getVelocity(v); - _entity->setVelocityInMeters(v); - getAngularVelocity(v); - _entity->setAngularVelocity(v); + if (! (updateFlags & PHYSICS_UPDATE_VELOCITY)) { + glm::vec3 v; + getVelocity(v); + _entity->setVelocityInMeters(v); + getAngularVelocity(v); + _entity->setAngularVelocity(v); + } } +#endif // USE_BULLET_PHYSICS void EntityMotionState::applyVelocities() const { +#ifdef USE_BULLET_PHYSICS if (_body) { setVelocity(_entity->getVelocityInMeters()); setAngularVelocity(_entity->getAngularVelocity()); + _body->setActivationState(ACTIVE_TAG); } +#endif // USE_BULLET_PHYSICS +} + +void EntityMotionState::applyGravity() const { +#ifdef USE_BULLET_PHYSICS + if (_body) { + setGravity(_entity->getGravityInMeters()); + _body->setActivationState(ACTIVE_TAG); + } +#endif // USE_BULLET_PHYSICS } void EntityMotionState::computeShapeInfo(ShapeInfo& info) { +#ifdef USE_BULLET_PHYSICS // HACK: for now we make everything a box. - glm::vec3 halfExtents = _entity->getDimensionsInMeters(); + glm::vec3 halfExtents = 0.5f * _entity->getDimensionsInMeters(); btVector3 bulletHalfExtents; glmToBullet(halfExtents, bulletHalfExtents); info.setBox(bulletHalfExtents); +#endif // USE_BULLET_PHYSICS } void EntityMotionState::getBoundingCubes(AACube& oldCube, AACube& newCube) { @@ -100,4 +122,3 @@ void EntityMotionState::getBoundingCubes(AACube& oldCube, AACube& newCube) { _oldBoundingCube = newCube; } -#endif // USE_BULLET_PHYSICS diff --git a/libraries/entities/src/EntityMotionState.h b/libraries/entities/src/EntityMotionState.h index 3b69abcd9d..ace42613dd 100644 --- a/libraries/entities/src/EntityMotionState.h +++ b/libraries/entities/src/EntityMotionState.h @@ -12,10 +12,16 @@ #ifndef hifi_EntityMotionState_h #define hifi_EntityMotionState_h -#ifdef USE_BULLET_PHYSICS - #include +#ifdef USE_BULLET_PHYSICS #include +#else // USE_BULLET_PHYSICS +// CustomMotionState stubbery +class CustomMotionState { +public: + bool _foo; +}; +#endif // USE_BULLET_PHYSICS class EntityItem; @@ -29,9 +35,12 @@ public: MotionType getMotionType() const; +#ifdef USE_BULLET_PHYSICS void getWorldTransform (btTransform &worldTrans) const; void setWorldTransform (const btTransform &worldTrans); +#endif // USE_BULLET_PHYSICS void applyVelocities() const; + void applyGravity() const; void computeShapeInfo(ShapeInfo& info); @@ -42,5 +51,4 @@ protected: AACube _oldBoundingCube; }; -#endif // USE_BULLET_PHYSICS #endif // hifi_EntityMotionState_h diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 2e697eebbb..9dbedf331f 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -77,12 +77,13 @@ EntityItem* EntityTree::getOrCreateEntityItem(const EntityItemID& entityID, cons } /// Adds a new entity item to the tree -void EntityTree::addEntityItem(EntityItem* entity) { +void EntityTree::addEntityInternal(EntityItem* entity) { // You should not call this on existing entities that are already part of the tree! Call updateEntity() EntityItemID entityID = entity->getEntityItemID(); EntityTreeElement* containingElement = getContainingElement(entityID); if (containingElement) { - qDebug() << "UNEXPECTED!!!! don't call addEntityItem() on existing EntityItems. entityID=" << entityID; + // should probably assert here + qDebug() << "UNEXPECTED!!!! don't call addEntityInternal() on existing EntityItems. entityID=" << entityID; return; } @@ -90,17 +91,39 @@ void EntityTree::addEntityItem(EntityItem* entity) { AddEntityOperator theOperator(this, entity); recurseTreeWithOperator(&theOperator); - updateEntityState(entity); + emitAddingEntity(entity); +} +void EntityTree::emitAddingEntity(EntityItem* entity) { + // add entity to proper internal lists + EntityItem::SimulationState newState = entity->computeSimulationState(); + switch (newState) { + case EntityItem::Moving: + _movingEntities.push_back(entity); + break; + + case EntityItem::Mortal: + _mortalEntities.push_back(entity); + break; + + default: + break; + } + entity->setSimulationState(newState); + entity->clearUpdateFlags(); + + // add entity to physics engine if (_physicsEngine && !entity->getMotionState()) { addEntityToPhysicsEngine(entity); } _isDirty = true; + + // finally emit the signal + emit addingEntity(entity->getEntityItemID()); } bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties) { - // You should not call this on existing entities that are already part of the tree! Call updateEntity() EntityTreeElement* containingElement = getContainingElement(entityID); if (!containingElement) { qDebug() << "UNEXPECTED!!!! EntityTree::updateEntity() entityID doesn't exist!!! entityID=" << entityID; @@ -127,20 +150,9 @@ bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProp } } } else { - // check to see if we need to simulate this entity... - QString entityScriptBefore = existingEntity->getScript(); - UpdateEntityOperator theOperator(this, containingElement, existingEntity, properties); recurseTreeWithOperator(&theOperator); _isDirty = true; - - updateEntityState(existingEntity); - - QString entityScriptAfter = existingEntity->getScript(); - if (entityScriptBefore != entityScriptAfter) { - emitEntityScriptChanging(entityID); // the entity script has changed - } - } containingElement = getContainingElement(entityID); @@ -177,8 +189,7 @@ EntityItem* EntityTree::addEntity(const EntityItemID& entityID, const EntityItem if (result) { // this does the actual adding of the entity - addEntityItem(result); - emitAddingEntity(entityID); + addEntityInternal(result); } return result; } @@ -204,14 +215,6 @@ void EntityTree::setPhysicsEngine(PhysicsEngine* engine) { _physicsEngine = engine; } -void EntityTree::emitAddingEntity(const EntityItemID& entityItemID) { - emit addingEntity(entityItemID); -} - -void EntityTree::emitEntityScriptChanging(const EntityItemID& entityItemID) { - emit entityScriptChanging(entityItemID); -} - void EntityTree::deleteEntity(const EntityItemID& entityID) { emit deletingEntity(entityID); @@ -619,13 +622,6 @@ void EntityTree::updateEntityState(EntityItem* entity) { break; } entity->setSimulationState(newState); - - if (_physicsEngine) { - EntityMotionState* motionState = entity->getMotionState(); - if (motionState) { - _physicsEngine->updateEntityMotionType(motionState); - } - } } } @@ -701,8 +697,15 @@ void EntityTree::updateChangedEntities(quint64 now, QSet& entities entitiesToDelete << thisEntity->getEntityItemID(); clearEntityState(thisEntity); } else { - // TODO: Andrew to push changes to physics engine (when we know how to sort the changes) + uint32_t flags = thisEntity->getUpdateFlags(); + if (flags & EntityItem::UPDATE_SCRIPT) { + emit entityScriptChanging(thisEntity->getEntityItemID()); + } + updateEntityState(thisEntity); + if (_physicsEngine && thisEntity->getMotionState()) { + _physicsEngine->updateEntity(thisEntity->getMotionState(), flags); + } } thisEntity->clearUpdateFlags(); } @@ -742,7 +745,7 @@ void EntityTree::updateMovingEntities(quint64 now, QSet& entitiesT qDebug() << "Entity " << thisEntity->getEntityItemID() << " moved out of domain bounds."; entitiesToDelete << thisEntity->getEntityItemID(); clearEntityState(thisEntity); - } else { + } else if (newCube != oldCube) { moveOperator.addEntityToMoveList(thisEntity, oldCube, newCube); updateEntityState(thisEntity); } diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 2323a1b612..1ef9b7e144 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -79,7 +79,8 @@ public: // The newer API... EntityItem* getOrCreateEntityItem(const EntityItemID& entityID, const EntityItemProperties& properties); - void addEntityItem(EntityItem* entityItem); + void addEntityInternal(EntityItem* entityItem); + void emitAddingEntity(EntityItem* entityItem); EntityItem* addEntity(const EntityItemID& entityID, const EntityItemProperties& properties); bool updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties); @@ -147,9 +148,6 @@ public: void trackDeletedEntity(const EntityItemID& entityID); - void emitAddingEntity(const EntityItemID& entityItemID); - void emitEntityScriptChanging(const EntityItemID& entityItemID); - QList& getMovingEntities() { return _movingEntities; } void setPhysicsEngine(PhysicsEngine* engine); diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index e94fb1718f..9d3e46400c 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -742,12 +742,13 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int // TODO: Do we need to also do this? // 3) remember the old cube for the entity so we can mark it as dirty if (entityItem) { - QString entityScriptBefore = entityItem->getScript(); + uint32_t oldFlags = entityItem->getUpdateFlags(); bool bestFitBefore = bestFitEntityBounds(entityItem); EntityTreeElement* currentContainingElement = _myTree->getContainingElement(entityItemID); bytesForThisEntity = entityItem->readEntityDataFromBuffer(dataAt, bytesLeftToRead, args); - if (entityItem->getUpdateFlags()) { + if (!oldFlags && entityItem->getUpdateFlags()) { + // this entity is not yet on the changed list and needs to be added _myTree->entityChanged(entityItem); } bool bestFitAfter = bestFitEntityBounds(entityItem); @@ -763,21 +764,14 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int } } } - - QString entityScriptAfter = entityItem->getScript(); - if (entityScriptBefore != entityScriptAfter) { - _myTree->emitEntityScriptChanging(entityItemID); // the entity script has changed - } - } else { entityItem = EntityTypes::constructEntityItem(dataAt, bytesLeftToRead, args); if (entityItem) { bytesForThisEntity = entityItem->readEntityDataFromBuffer(dataAt, bytesLeftToRead, args); addEntityItem(entityItem); // add this new entity to this elements entities + _myTree->emitAddingEntity(entityItem); entityItemID = entityItem->getEntityItemID(); _myTree->setContainingElement(entityItemID, this); - _myTree->updateEntityState(entityItem); - _myTree->emitAddingEntity(entityItemID); // we just added an entity } } // Move the buffer forward to read more entities diff --git a/libraries/entities/src/UpdateEntityOperator.cpp b/libraries/entities/src/UpdateEntityOperator.cpp index 9cee11d73c..0f51d76162 100644 --- a/libraries/entities/src/UpdateEntityOperator.cpp +++ b/libraries/entities/src/UpdateEntityOperator.cpp @@ -299,14 +299,25 @@ bool UpdateEntityOperator::preRecursion(OctreeElement* element) { } // set the entity properties and mark our element as changed. - _existingEntity->setProperties(_properties); + uint32_t oldUpdateFlags = _existingEntity->getUpdateFlags(); + bool somethingChanged = _existingEntity->setProperties(_properties); + uint32_t newUpdateFlags = _existingEntity->getUpdateFlags(); + if (somethingChanged && !oldUpdateFlags && _existingEntity->getUpdateFlags()) { + // this entity hasn't yet been added to changed list + _tree->entityChanged(_existingEntity); + } if (_wantDebug) { qDebug() << " *** set properties ***"; } } else { // otherwise, this is an add case. entityTreeElement->addEntityItem(_existingEntity); - _existingEntity->setProperties(_properties); // still need to update the properties! + uint32_t oldUpdateFlags = _existingEntity->getUpdateFlags(); + bool somethingChanged = _existingEntity->setProperties(_properties); // still need to update the properties! + if (somethingChanged && !oldUpdateFlags && _existingEntity->getUpdateFlags()) { + // this entity hasn't yet been added to changed list + _tree->entityChanged(_existingEntity); + } _tree->setContainingElement(_entityItemID, entityTreeElement); if (_wantDebug) { qDebug() << " *** ADDING ENTITY to ELEMENT and MAP and SETTING PROPERTIES ***"; diff --git a/libraries/physics/src/CustomMotionState.cpp b/libraries/physics/src/CustomMotionState.cpp index 743ed26614..20bd1aac69 100644 --- a/libraries/physics/src/CustomMotionState.cpp +++ b/libraries/physics/src/CustomMotionState.cpp @@ -72,6 +72,12 @@ void CustomMotionState::setAngularVelocity(const glm::vec3& velocity) const { _body->setAngularVelocity(v); } +void CustomMotionState::setGravity(const glm::vec3& gravity) const { + btVector3 g; + glmToBullet(gravity, g); + _body->setGravity(g); +} + void CustomMotionState::getVelocity(glm::vec3& velocityOut) const { bulletToGLM(_body->getLinearVelocity(), velocityOut); } diff --git a/libraries/physics/src/CustomMotionState.h b/libraries/physics/src/CustomMotionState.h index 7801625e09..d78aa66dfd 100644 --- a/libraries/physics/src/CustomMotionState.h +++ b/libraries/physics/src/CustomMotionState.h @@ -35,6 +35,7 @@ public: //virtual void setWorldTransform (const btTransform &worldTrans); virtual void applyVelocities() const = 0; + virtual void applyGravity() const = 0; virtual void computeShapeInfo(ShapeInfo& info) = 0; @@ -49,6 +50,7 @@ public: void setVelocity(const glm::vec3& velocity) const; void setAngularVelocity(const glm::vec3& velocity) const; + void setGravity(const glm::vec3& gravity) const; void getVelocity(glm::vec3& velocityOut) const; void getAngularVelocity(glm::vec3& angularVelocityOut) const; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 94d92f19f8..2e44d27f13 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -32,7 +32,7 @@ void PhysicsEngine::init() { // NOTE: we don't care about memory leaking groundShape and groundObject --> // they'll exist until the executable exits. const float halfSide = 200.0f; - const float halfHeight = 10.0f; + const float halfHeight = 1.0f; btCollisionShape* groundShape = new btBoxShape(btVector3(halfSide, halfHeight, halfSide)); btTransform groundTransform; @@ -40,6 +40,7 @@ void PhysicsEngine::init() { groundTransform.setOrigin(btVector3(halfSide, -halfHeight, halfSide)); btCollisionObject* groundObject = new btCollisionObject(); + groundObject->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT); groundObject->setCollisionShape(groundShape); groundObject->setWorldTransform(groundTransform); _dynamicsWorld->addCollisionObject(groundObject); @@ -131,7 +132,7 @@ bool PhysicsEngine::addEntity(CustomMotionState* motionState) { btVector3 inertia(0.0f, 0.0f, 0.0f); float mass = 0.0f; btRigidBody* body = NULL; - switch(motionState->_motionType) { + switch(motionState->getMotionType()) { case MOTION_TYPE_KINEMATIC: { body = new btRigidBody(mass, motionState, shape, inertia); body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); @@ -147,6 +148,7 @@ bool PhysicsEngine::addEntity(CustomMotionState* motionState) { body->updateInertiaTensor(); motionState->_body = body; motionState->applyVelocities(); + motionState->applyGravity(); break; } case MOTION_TYPE_STATIC: @@ -158,6 +160,8 @@ bool PhysicsEngine::addEntity(CustomMotionState* motionState) { break; } } + // wtf? + body->setFlags(BT_DISABLE_WORLD_GRAVITY); body->setRestitution(motionState->_restitution); body->setFriction(motionState->_friction); _dynamicsWorld->addRigidBody(body); @@ -182,60 +186,132 @@ bool PhysicsEngine::removeEntity(CustomMotionState* motionState) { return false; } -bool PhysicsEngine::updateEntityMotionType(CustomMotionState* motionState) { +bool PhysicsEngine::updateEntity(CustomMotionState* motionState, uint32_t flags) { btRigidBody* body = motionState->_body; if (!body) { return false; } - + + if (flags & PHYSICS_UPDATE_HARD) { + // a hard update requires the body be pulled out of physics engine, changed, then reinserted + updateEntityHard(body, motionState, flags); + } else if (flags & PHYSICS_UPDATE_EASY) { + // an easy update does not require that the body be pulled out of physics engine + updateEntityEasy(body, motionState, flags); + } + return true; +} + +// private +void PhysicsEngine::updateEntityHard(btRigidBody* body, CustomMotionState* motionState, uint32_t flags) { + MotionType newType = motionState->getMotionType(); MotionType oldType = MOTION_TYPE_DYNAMIC; if (body->isStaticObject()) { oldType = MOTION_TYPE_STATIC; } else if (body->isKinematicObject()) { oldType = MOTION_TYPE_KINEMATIC; } - MotionType newType = motionState->getMotionType(); - if (oldType != newType) { - // pull body out of physics engine - _dynamicsWorld->removeRigidBody(body); - // update various properties and flags - switch (newType) { - case MOTION_TYPE_KINEMATIC: { - body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); - body->setActivationState(DISABLE_DEACTIVATION); - body->updateInertiaTensor(); - break; - } - case MOTION_TYPE_DYNAMIC: { + // pull body out of physics engine + _dynamicsWorld->removeRigidBody(body); + + if (flags & PHYSICS_UPDATE_SHAPE) { + btCollisionShape* oldShape = body->getCollisionShape(); + ShapeInfo info; + motionState->computeShapeInfo(info); + btCollisionShape* newShape = _shapeManager.getShape(info); + if (newShape != oldShape) { + body->setCollisionShape(newShape); + _shapeManager.releaseShape(oldShape); + } else { + // whoops, shape hasn't changed after all so we must release the reference + // that was created when looking it up + _shapeManager.releaseShape(newShape); + } + // MASS bit should be set whenever SHAPE is set + assert(flags & PHYSICS_UPDATE_MASS); + } + bool easyUpdate = flags & PHYSICS_UPDATE_EASY; + if (easyUpdate) { + updateEntityEasy(body, motionState, flags); + } + + // update the motion parameters + switch (newType) { + case MOTION_TYPE_KINEMATIC: { + int collisionFlags = body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT; + collisionFlags &= ~(btCollisionObject::CF_STATIC_OBJECT); + body->setCollisionFlags(collisionFlags); + body->forceActivationState(DISABLE_DEACTIVATION); + + body->setMassProps(0.0f, btVector3(0.0f, 0.0f, 0.0f)); + body->updateInertiaTensor(); + break; + } + case MOTION_TYPE_DYNAMIC: { + int collisionFlags = body->getCollisionFlags() & ~(btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT); + body->setCollisionFlags(collisionFlags); + if (! (flags & PHYSICS_UPDATE_MASS)) { + // always update mass properties when going dynamic (unless it's already been done) btVector3 inertia(0.0f, 0.0f, 0.0f); float mass = motionState->getMass(); body->getCollisionShape()->calculateLocalInertia(mass, inertia); + body->setMassProps(mass, inertia); body->updateInertiaTensor(); - motionState->applyVelocities(); - break; - } - default: { - // MOTION_TYPE_STATIC - body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT); - body->updateInertiaTensor(); - break; } + bool forceActivation = true; + body->activate(forceActivation); + break; } + default: { + // MOTION_TYPE_STATIC + int collisionFlags = body->getCollisionFlags() | btCollisionObject::CF_STATIC_OBJECT; + collisionFlags &= ~(btCollisionObject::CF_KINEMATIC_OBJECT); + body->setCollisionFlags(collisionFlags); + body->forceActivationState(DISABLE_SIMULATION); - // reinsert body into physics engine - body->setRestitution(motionState->_restitution); - body->setFriction(motionState->_friction); - _dynamicsWorld->addRigidBody(body); - return true; + body->setMassProps(0.0f, btVector3(0.0f, 0.0f, 0.0f)); + body->updateInertiaTensor(); + + body->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f)); + body->setAngularVelocity(btVector3(0.0f, 0.0f, 0.0f)); + break; + } } - return false; + + // reinsert body into physics engine + _dynamicsWorld->addRigidBody(body); + + body->activate(); } -bool PhysicsEngine::updateEntityMassProperties(CustomMotionState* motionState, float mass, const glm::vec3& inertiaEigenValues) { - // TODO: implement this - assert(motionState); - return false; -} +// private +void PhysicsEngine::updateEntityEasy(btRigidBody* body, CustomMotionState* motionState, uint32_t flags) { + if (flags & PHYSICS_UPDATE_POSITION) { + btTransform transform; + motionState->getWorldTransform(transform); + body->setWorldTransform(transform); + } + if (flags & PHYSICS_UPDATE_VELOCITY) { + motionState->applyVelocities(); + motionState->applyGravity(); + } + body->setRestitution(motionState->_restitution); + body->setFriction(motionState->_friction); + + if (flags & PHYSICS_UPDATE_MASS) { + float mass = motionState->getMass(); + btVector3 inertia(0.0f, 0.0f, 0.0f); + body->getCollisionShape()->calculateLocalInertia(mass, inertia); + body->setMassProps(mass, inertia); + body->updateInertiaTensor(); + } + body->activate(); + + btVector3 v = body->getLinearVelocity(); + btVector3 g = body->getGravity(); + + // TODO: support collision groups +}; #endif // USE_BULLET_PHYSICS diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 222860e575..4daca423ad 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -12,6 +12,24 @@ #ifndef hifi_PhysicsEngine_h #define hifi_PhysicsEngine_h +enum PhysicsUpdateFlag { + PHYSICS_UPDATE_POSITION = 0x0001, + PHYSICS_UPDATE_VELOCITY = 0x0002, + PHYSICS_UPDATE_GRAVITY = 0x0004, + PHYSICS_UPDATE_MASS = 0x0008, + PHYSICS_UPDATE_COLLISION_GROUP = 0x0010, + PHYSICS_UPDATE_MOTION_TYPE = 0x0020, + PHYSICS_UPDATE_SHAPE = 0x0040 +}; + +typedef unsigned int uint32_t; + +// The update flags trigger two varieties of updates: "hard" which require the body to be pulled +// and re-added to the physics engine and "easy" which just updates the body properties. +const uint32_t PHYSICS_UPDATE_HARD = PHYSICS_UPDATE_MOTION_TYPE | PHYSICS_UPDATE_SHAPE; +const uint32_t PHYSICS_UPDATE_EASY = PHYSICS_UPDATE_POSITION | PHYSICS_UPDATE_VELOCITY | + PHYSICS_UPDATE_GRAVITY PHYSICS_UPDATE_MASS | PHYSICS_UPDATE_COLLISION_GROUP; + #ifdef USE_BULLET_PHYSICS #include @@ -68,12 +86,14 @@ public: bool removeEntity(CustomMotionState* motionState); /// \param motionState pointer to Entity's MotionState + /// \param flags set of bits indicating what categories of properties need to be updated /// \return true if entity updated - bool updateEntityMotionType(CustomMotionState* motionState); - - bool updateEntityMassProperties(CustomMotionState* motionState, float mass, const glm::vec3& inertiaEigenValues); + bool updateEntity(CustomMotionState* motionState, uint32_t flags); protected: + void updateEntityHard(btRigidBody* body, CustomMotionState* motionState, uint32_t flags); + void updateEntityEasy(btRigidBody* body, CustomMotionState* motionState, uint32_t flags); + btClock _clock; btDefaultCollisionConfiguration* _collisionConfig; btCollisionDispatcher* _collisionDispatcher; From 0e0eaea849cc590594c66704a600945d67453fac Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 24 Nov 2014 11:36:17 -0800 Subject: [PATCH 045/105] fix typo that broke the build --- libraries/physics/src/PhysicsEngine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 4daca423ad..b9a44dc579 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -28,7 +28,7 @@ typedef unsigned int uint32_t; // and re-added to the physics engine and "easy" which just updates the body properties. const uint32_t PHYSICS_UPDATE_HARD = PHYSICS_UPDATE_MOTION_TYPE | PHYSICS_UPDATE_SHAPE; const uint32_t PHYSICS_UPDATE_EASY = PHYSICS_UPDATE_POSITION | PHYSICS_UPDATE_VELOCITY | - PHYSICS_UPDATE_GRAVITY PHYSICS_UPDATE_MASS | PHYSICS_UPDATE_COLLISION_GROUP; + PHYSICS_UPDATE_GRAVITY | PHYSICS_UPDATE_MASS | PHYSICS_UPDATE_COLLISION_GROUP; #ifdef USE_BULLET_PHYSICS From 1c569dcf3343a34c7a7bf3ba147c35e9764c4cc6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 24 Nov 2014 15:05:09 -0800 Subject: [PATCH 046/105] remove some cruft --- libraries/physics/src/PhysicsEngine.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 2e44d27f13..0dfa451b99 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -205,12 +205,6 @@ bool PhysicsEngine::updateEntity(CustomMotionState* motionState, uint32_t flags) // private void PhysicsEngine::updateEntityHard(btRigidBody* body, CustomMotionState* motionState, uint32_t flags) { MotionType newType = motionState->getMotionType(); - MotionType oldType = MOTION_TYPE_DYNAMIC; - if (body->isStaticObject()) { - oldType = MOTION_TYPE_STATIC; - } else if (body->isKinematicObject()) { - oldType = MOTION_TYPE_KINEMATIC; - } // pull body out of physics engine _dynamicsWorld->removeRigidBody(body); @@ -308,9 +302,6 @@ void PhysicsEngine::updateEntityEasy(btRigidBody* body, CustomMotionState* motio } body->activate(); - btVector3 v = body->getLinearVelocity(); - btVector3 g = body->getGravity(); - // TODO: support collision groups }; From 0b56169c6e993cf61ec8e61c9e20e5ed6f857ecf Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 26 Nov 2014 17:18:19 -0800 Subject: [PATCH 047/105] fix build after merge --- libraries/entities/src/DeleteEntityOperator.cpp | 2 -- libraries/entities/src/EntityItem.h | 3 +-- libraries/entities/src/EntityTree.cpp | 16 +++------------- libraries/entities/src/EntityTree.h | 4 ---- libraries/entities/src/UpdateEntityOperator.cpp | 1 - 5 files changed, 4 insertions(+), 22 deletions(-) diff --git a/libraries/entities/src/DeleteEntityOperator.cpp b/libraries/entities/src/DeleteEntityOperator.cpp index c8f27e379e..12441e5427 100644 --- a/libraries/entities/src/DeleteEntityOperator.cpp +++ b/libraries/entities/src/DeleteEntityOperator.cpp @@ -97,8 +97,6 @@ bool DeleteEntityOperator::preRecursion(OctreeElement* element) { _tree->trackDeletedEntity(theEntity); entityTreeElement->removeEntityItem(theEntity); // remove it from the element _tree->setContainingElement(entityItemID, NULL); // update or id to element lookup - _tree->removeEntityFromPhysicsEngine(theEntity); - theEntity->destroyMotionState(); delete theEntity; // now actually delete the entity! _foundCount++; } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 18f0788b4c..7c43194152 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -301,14 +301,13 @@ public: void updateScript(const QString& value); uint32_t getUpdateFlags() const { return _updateFlags; } + void clearUpdateFlags() { _updateFlags = 0; } EntityMotionState* getMotionState() const { return _motionState; } virtual EntityMotionState* createMotionState() { return NULL; } void destroyMotionState(); SimulationState getSimulationState() const { return _simulationState; } - SimulationState getSimulationState() const { return _simulationState; } - void setSimulationState(SimulationState state) { _simulationState = state; } protected: diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 8913f2eb22..2cc735fafc 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -10,7 +10,6 @@ // #include -#include #include "EntityTree.h" #include "EntitySimulation.h" @@ -138,9 +137,9 @@ bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProp _simulation->entityChanged(existingEntity); } - QString entityScriptAfter = existingEntity->getScript(); - if (entityScriptBefore != entityScriptAfter) { - emitEntityScriptChanging(entityID); // the entity script has changed + uint32_t flags = existingEntity->getUpdateFlags(); + if (flags & EntityItem::UPDATE_SCRIPT) { + emit entityScriptChanging(existingEntity->getEntityItemID()); } } @@ -198,15 +197,6 @@ void EntityTree::trackDeletedEntity(EntityItem* entity) { } } -void EntityTree::setPhysicsEngine(PhysicsEngine* engine) { - if (_physicsEngine) { -#ifdef USE_BULLET_PHYSICS - // TODO: remove all entities before we clear the engine -#endif // USE_BULLET_PHYSICS - } - _physicsEngine = engine; -} - void EntityTree::setSimulation(EntitySimulation* simulation) { if (simulation) { // assert that the simulation's backpointer has already been properly connected diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 5b9f5f50af..337c7f7523 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -80,7 +80,6 @@ public: // The newer API... EntityItem* getOrCreateEntityItem(const EntityItemID& entityID, const EntityItemProperties& properties); void addEntityInternal(EntityItem* entityItem); - void emitAddingEntity(EntityItem* entityItem); EntityItem* addEntity(const EntityItemID& entityID, const EntityItemProperties& properties); bool updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties); @@ -140,12 +139,9 @@ public: void sendEntities(EntityEditPacketSender* packetSender, EntityTree* localTree, float x, float y, float z); void entityChanged(EntityItem* entity); - void addEntityToPhysicsEngine(EntityItem* entity); - void removeEntityFromPhysicsEngine(EntityItem* entity); void trackDeletedEntity(EntityItem* entity); - void emitAddingEntity(const EntityItemID& entityItemID); void emitEntityScriptChanging(const EntityItemID& entityItemID); void setSimulation(EntitySimulation* simulation); diff --git a/libraries/entities/src/UpdateEntityOperator.cpp b/libraries/entities/src/UpdateEntityOperator.cpp index 0f51d76162..4da24fb28a 100644 --- a/libraries/entities/src/UpdateEntityOperator.cpp +++ b/libraries/entities/src/UpdateEntityOperator.cpp @@ -301,7 +301,6 @@ bool UpdateEntityOperator::preRecursion(OctreeElement* element) { // set the entity properties and mark our element as changed. uint32_t oldUpdateFlags = _existingEntity->getUpdateFlags(); bool somethingChanged = _existingEntity->setProperties(_properties); - uint32_t newUpdateFlags = _existingEntity->getUpdateFlags(); if (somethingChanged && !oldUpdateFlags && _existingEntity->getUpdateFlags()) { // this entity hasn't yet been added to changed list _tree->entityChanged(_existingEntity); From 1df6c32a4e8cf287baf3e6191dda0c3e609b2484 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 1 Dec 2014 16:03:14 -0800 Subject: [PATCH 048/105] moving Shape* back into shared lib removing dependency of entities lib on physics lib physics lib now depends on entities lib --- interface/src/Application.cpp | 7 +++--- libraries/avatars/CMakeLists.txt | 2 +- libraries/entities/CMakeLists.txt | 3 +-- libraries/entities/src/BoxEntityItem.cpp | 3 ++- libraries/entities/src/BoxEntityItem.h | 4 ---- libraries/entities/src/EntityItem.cpp | 17 +++---------- libraries/entities/src/EntityItem.h | 21 +++++++--------- libraries/entities/src/EntitySimulation.h | 2 +- libraries/entities/src/EntityTree.cpp | 3 +-- libraries/entities/src/EntityTreeElement.cpp | 6 ++--- libraries/entities/src/EntityTreeElement.h | 4 ++-- .../entities/src/SimpleEntitySimulation.cpp | 2 +- .../entities/src/SimpleEntitySimulation.h | 2 +- libraries/octree/CMakeLists.txt | 2 +- libraries/physics/CMakeLists.txt | 3 ++- libraries/physics/src/ContactPoint.h | 3 ++- .../src/EntityMotionState.cpp | 12 +++++----- .../src/EntityMotionState.h | 4 +++- libraries/physics/src/PhysicsEngine.cpp | 24 +++++++++---------- libraries/physics/src/PhysicsEngine.h | 20 ++++++++-------- libraries/physics/src/PhysicsEntity.h | 6 ++--- libraries/physics/src/ShapeInfo.cpp | 1 + libraries/physics/src/ShapeInfo.h | 2 -- .../{physics => shared}/src/AACubeShape.cpp | 2 +- .../{physics => shared}/src/AACubeShape.h | 0 .../{physics => shared}/src/CapsuleShape.cpp | 6 ++--- .../{physics => shared}/src/CapsuleShape.h | 3 +-- .../{physics => shared}/src/CollisionInfo.cpp | 2 +- .../{physics => shared}/src/CollisionInfo.h | 0 .../{physics => shared}/src/ListShape.cpp | 0 libraries/{physics => shared}/src/ListShape.h | 0 .../{physics => shared}/src/PlaneShape.cpp | 5 ++-- .../{physics => shared}/src/PlaneShape.h | 0 .../src/RayIntersectionInfo.h | 0 libraries/{physics => shared}/src/Shape.h | 0 .../{physics => shared}/src/ShapeCollider.cpp | 8 +++---- .../{physics => shared}/src/ShapeCollider.h | 4 ++-- .../{physics => shared}/src/SphereShape.cpp | 0 .../{physics => shared}/src/SphereShape.h | 3 +-- 39 files changed, 81 insertions(+), 105 deletions(-) rename libraries/{entities => physics}/src/EntityMotionState.cpp (95%) rename libraries/{entities => physics}/src/EntityMotionState.h (97%) rename libraries/{physics => shared}/src/AACubeShape.cpp (98%) rename libraries/{physics => shared}/src/AACubeShape.h (100%) rename libraries/{physics => shared}/src/CapsuleShape.cpp (99%) rename libraries/{physics => shared}/src/CapsuleShape.h (98%) rename libraries/{physics => shared}/src/CollisionInfo.cpp (99%) rename libraries/{physics => shared}/src/CollisionInfo.h (100%) rename libraries/{physics => shared}/src/ListShape.cpp (100%) rename libraries/{physics => shared}/src/ListShape.h (100%) rename libraries/{physics => shared}/src/PlaneShape.cpp (98%) rename libraries/{physics => shared}/src/PlaneShape.h (100%) rename libraries/{physics => shared}/src/RayIntersectionInfo.h (100%) rename libraries/{physics => shared}/src/Shape.h (100%) rename libraries/{physics => shared}/src/ShapeCollider.cpp (99%) rename libraries/{physics => shared}/src/ShapeCollider.h (99%) rename libraries/{physics => shared}/src/SphereShape.cpp (100%) rename libraries/{physics => shared}/src/SphereShape.h (98%) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6f94925858..8abbf6314f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2021,8 +2021,8 @@ void Application::init() { connect(_myAvatar, &MyAvatar::transformChanged, this, &Application::updateMyAvatarTransform); #ifdef USE_BULLET_PHYSICS - _physicsEngine.initSafe(_entities.getTree()); - _entities.getTree()->setPhysicsEngine(&_physicsEngine); +// _physicsEngine.initSafe(_entities.getTree()); +// _entities.getTree()->setSimulation(&_physicsEngine); #endif // USE_BULLET_PHYSICS } @@ -4159,15 +4159,14 @@ void Application::updateMyAvatarTransform() { glm::vec3 avatarPosition = _myAvatar->getPosition(); glm::vec3 physicsWorldOffset = _physicsEngine.getOriginOffset(); if (glm::distance(avatarPosition, physicsWorldOffset) > SIMULATION_OFFSET_QUANTIZATION) { - //_entityCollisionSystem.forgetAllPhysics(); glm::vec3 newOriginOffset = avatarPosition; int halfExtent = (int)HALF_SIMULATION_EXTENT; for (int i = 0; i < 3; ++i) { newOriginOffset[i] = (float)(glm::max(halfExtent, ((int)(avatarPosition[i] / SIMULATION_OFFSET_QUANTIZATION)) * (int)SIMULATION_OFFSET_QUANTIZATION)); } + // TODO: Andrew to replace this with method that actually moves existing object positions in PhysicsEngine _physicsEngine.setOriginOffset(newOriginOffset); - //_entityCollisionSystem.rememberAllPhysics(); } #endif // USE_BULLET_PHYSICS } diff --git a/libraries/avatars/CMakeLists.txt b/libraries/avatars/CMakeLists.txt index 42b3cf7d3c..8cbbf7d1ae 100644 --- a/libraries/avatars/CMakeLists.txt +++ b/libraries/avatars/CMakeLists.txt @@ -5,7 +5,7 @@ setup_hifi_library(Network Script) include_glm() -link_hifi_libraries(shared octree voxels networking physics) +link_hifi_libraries(shared octree voxels networking) include_hifi_library_headers(fbx) # call macro to link our dependencies and bubble them up via a property on our target diff --git a/libraries/entities/CMakeLists.txt b/libraries/entities/CMakeLists.txt index 5e3ab70f76..40d71a032d 100644 --- a/libraries/entities/CMakeLists.txt +++ b/libraries/entities/CMakeLists.txt @@ -4,9 +4,8 @@ set(TARGET_NAME entities) setup_hifi_library(Network Script) include_glm() -include_bullet() -link_hifi_libraries(shared octree fbx networking animation physics) +link_hifi_libraries(shared octree fbx networking animation) # call macro to link our dependencies and bubble them up via a property on our target link_shared_dependencies() diff --git a/libraries/entities/src/BoxEntityItem.cpp b/libraries/entities/src/BoxEntityItem.cpp index d1a58722b0..ecd1306297 100644 --- a/libraries/entities/src/BoxEntityItem.cpp +++ b/libraries/entities/src/BoxEntityItem.cpp @@ -15,7 +15,6 @@ #include #include "BoxEntityItem.h" -#include "EntityMotionState.h" #include "EntityTree.h" #include "EntityTreeElement.h" @@ -97,6 +96,7 @@ void BoxEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitst APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor()); } +/* #ifdef USE_BULLET_PHYSICS EntityMotionState* BoxEntityItem::createMotionState() { if (!_motionState) { @@ -107,4 +107,5 @@ EntityMotionState* BoxEntityItem::createMotionState() { return _motionState; } #endif // USE_BULLET_PHYSICS +*/ diff --git a/libraries/entities/src/BoxEntityItem.h b/libraries/entities/src/BoxEntityItem.h index faae308b43..bea4f0c32a 100644 --- a/libraries/entities/src/BoxEntityItem.h +++ b/libraries/entities/src/BoxEntityItem.h @@ -50,10 +50,6 @@ public: _color[GREEN_INDEX] = value.green; _color[BLUE_INDEX] = value.blue; } - -#ifdef USE_BULLET_PHYSICS - EntityMotionState* createMotionState(); -#endif // USE_BULLET_PHYSICS protected: rgbColor _color; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index f07ce3ca16..928645b349 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -21,7 +21,6 @@ #include "EntityScriptingInterface.h" #include "EntityItem.h" -#include "EntityMotionState.h" #include "EntityTree.h" const float EntityItem::IMMORTAL = -1.0f; /// special lifetime which means the entity lives for ever. default lifetime @@ -91,7 +90,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) { _lastEditedFromRemoteInRemoteTime = 0; _lastUpdated = 0; _created = 0; - _motionState = NULL; + _physicsInfo = NULL; _updateFlags = 0; _changedOnServer = 0; initFromEntityItemID(entityItemID); @@ -105,7 +104,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert _lastEditedFromRemoteInRemoteTime = 0; _lastUpdated = 0; _created = properties.getCreated(); - _motionState = NULL; + _physicsInfo = NULL; _updateFlags = 0; _changedOnServer = 0; initFromEntityItemID(entityItemID); @@ -114,9 +113,6 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert } EntityItem::~EntityItem() { - // Make sure the EntityItem has been removed from the physics engine AND - // that its _motionState has been destroyed BEFORE you get here. - assert(_motionState == NULL); } EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& params) const { @@ -628,7 +624,7 @@ void EntityItem::update(const quint64& updateTime) { qDebug() << " ********** EntityItem::update() .... SETTING _lastUpdated=" << _lastUpdated; } - if (!_motionState) { + if (!_physicsInfo) { if (hasAngularVelocity()) { glm::quat rotation = getRotation(); glm::vec3 angularVelocity = glm::radians(getAngularVelocity()); @@ -1072,10 +1068,3 @@ void EntityItem::updateScript(const QString& value) { } } -void EntityItem::destroyMotionState() { - if (_motionState) { - delete _motionState; - _motionState = NULL; - } -} - diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 7c43194152..d3225daa64 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -22,7 +22,6 @@ #include // for EncodeBitstreamParams class #include // for OctreeElement::AppendState #include -#include #include #include "EntityItemID.h" @@ -46,13 +45,13 @@ class EntityItem { public: enum EntityUpdateFlags { // flags for things that need to be relayed to physics engine - UPDATE_POSITION = PHYSICS_UPDATE_POSITION, //0x0001, - UPDATE_VELOCITY = PHYSICS_UPDATE_VELOCITY, //0x0002, - UPDATE_GRAVITY = PHYSICS_UPDATE_GRAVITY, //0x0004, - UPDATE_MASS = PHYSICS_UPDATE_MASS, //0x0008, - UPDATE_COLLISION_GROUP = PHYSICS_UPDATE_COLLISION_GROUP, //0x0010, - UPDATE_MOTION_TYPE = PHYSICS_UPDATE_MOTION_TYPE, //0x0020, - UPDATE_SHAPE = PHYSICS_UPDATE_SHAPE, //0x0040, + UPDATE_POSITION = 0x0001, + UPDATE_VELOCITY = 0x0002, + UPDATE_GRAVITY = 0x0004, + UPDATE_MASS = 0x0008, + UPDATE_COLLISION_GROUP = 0x0010, + UPDATE_MOTION_TYPE = 0x0020, + UPDATE_SHAPE = 0x0040, //... // add new flags here in the middle //... @@ -303,9 +302,7 @@ public: uint32_t getUpdateFlags() const { return _updateFlags; } void clearUpdateFlags() { _updateFlags = 0; } - EntityMotionState* getMotionState() const { return _motionState; } - virtual EntityMotionState* createMotionState() { return NULL; } - void destroyMotionState(); + void* getPhysicsInfo() const { return _physicsInfo; } SimulationState getSimulationState() const { return _simulationState; } void setSimulationState(SimulationState state) { _simulationState = state; } @@ -352,7 +349,7 @@ protected: void setRadius(float value); AACubeShape _collisionShape; - EntityMotionState* _motionState; + void* _physicsInfo; SimulationState _simulationState; // only set by EntityTree // UpdateFlags are set whenever a property changes that requires the change to be communicated to other diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index 770d6ebdb0..edbae91c0a 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -25,7 +25,7 @@ public: virtual void setEntityTree(EntityTree* tree); /// \param[out] entitiesToDelete list of entities removed from simulation and should be deleted. - virtual void update(QSet& entitiesToDelete) = 0; + virtual void updateEntities(QSet& entitiesToDelete) = 0; /// \param entity pointer to EntityItem to add to the simulation /// \sideeffect the EntityItem::_simulationState member may be updated to indicate membership to internal list diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 9f78a350ff..f5e6260270 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -16,7 +16,6 @@ #include "AddEntityOperator.h" #include "DeleteEntityOperator.h" -#include "EntityMotionState.h" #include "MovingEntitiesOperator.h" #include "UpdateEntityOperator.h" @@ -653,7 +652,7 @@ void EntityTree::update() { if (_simulation) { lockForWrite(); QSet entitiesToDelete; - _simulation->update(entitiesToDelete); + _simulation->updateEntities(entitiesToDelete); if (entitiesToDelete.size() > 0) { // translate into list of ID's QSet idsToDelete; diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index f36b648703..0b5dfee1d1 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -16,9 +16,7 @@ #include #include -#include -#include "EntityMotionState.h" #include "EntityTree.h" #include "EntityTreeElement.h" @@ -655,6 +653,7 @@ EntityItem* EntityTreeElement::getEntityWithEntityItemID(const EntityItemID& id) return foundEntity; } +/* TODO: probably move the cleanupEntities() stuff into EntityTree void EntityTreeElement::cleanupEntities(PhysicsEngine* physicsEngine) { uint16_t numberOfEntities = _entityItems->size(); for (uint16_t i = 0; i < numberOfEntities; i++) { @@ -662,13 +661,14 @@ void EntityTreeElement::cleanupEntities(PhysicsEngine* physicsEngine) { EntityMotionState* motionState = entity->getMotionState(); if (motionState) { assert(physicsEngine); - physicsEngine->removeEntity(static_cast(motionState)); + physicsEngine->removeObject(static_cast(motionState)); entity->destroyMotionState(); } delete entity; } _entityItems->clear(); } +*/ bool EntityTreeElement::removeEntityWithEntityItemID(const EntityItemID& id) { bool foundEntity = false; diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index df6342fd97..102d3b9068 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -21,7 +21,6 @@ class EntityTree; class EntityTreeElement; -class PhysicsEngine; class EntityTreeUpdateArgs { public: @@ -176,7 +175,8 @@ public: EntityItem* getEntityWithEntityItemID(const EntityItemID& id); - void cleanupEntities(PhysicsEngine* physicsEngine); + // TODO: probably move the cleanupEntities() stuff into EntityTree + //void cleanupEntities(PhysicsEngine* physicsEngine); bool removeEntityWithEntityItemID(const EntityItemID& id); bool removeEntityItem(EntityItem* entity); diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index b3316978a9..f91c80d67b 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -16,7 +16,7 @@ #include "MovingEntitiesOperator.h" #include "SimpleEntitySimulation.h" -void SimpleEntitySimulation::update(QSet& entitiesToDelete) { +void SimpleEntitySimulation::updateEntities(QSet& entitiesToDelete) { quint64 now = usecTimestampNow(); updateChangedEntities(now, entitiesToDelete); updateMovingEntities(now, entitiesToDelete); diff --git a/libraries/entities/src/SimpleEntitySimulation.h b/libraries/entities/src/SimpleEntitySimulation.h index 7d0e8f0113..deff531fa4 100644 --- a/libraries/entities/src/SimpleEntitySimulation.h +++ b/libraries/entities/src/SimpleEntitySimulation.h @@ -21,7 +21,7 @@ public: SimpleEntitySimulation() : EntitySimulation() { } virtual ~SimpleEntitySimulation() { setEntityTree(NULL); } - virtual void update(QSet& entitiesToDelete); + virtual void updateEntities(QSet& entitiesToDelete); virtual void addEntity(EntityItem* entity); virtual void removeEntity(EntityItem* entity); diff --git a/libraries/octree/CMakeLists.txt b/libraries/octree/CMakeLists.txt index 9aea2fdea1..cfac2dcfa4 100644 --- a/libraries/octree/CMakeLists.txt +++ b/libraries/octree/CMakeLists.txt @@ -5,7 +5,7 @@ setup_hifi_library() include_glm() -link_hifi_libraries(shared networking physics) +link_hifi_libraries(shared networking) # find ZLIB find_package(ZLIB REQUIRED) diff --git a/libraries/physics/CMakeLists.txt b/libraries/physics/CMakeLists.txt index 4799deea3d..15e1ab238c 100644 --- a/libraries/physics/CMakeLists.txt +++ b/libraries/physics/CMakeLists.txt @@ -6,7 +6,8 @@ setup_hifi_library() include_glm() include_bullet() -link_hifi_libraries(shared) +link_hifi_libraries(shared fbx entities) +include_hifi_library_headers(fbx) # call macro to link our dependencies and bubble them up via a property on our target link_shared_dependencies() diff --git a/libraries/physics/src/ContactPoint.h b/libraries/physics/src/ContactPoint.h index dde8aa38e1..c2443f361f 100644 --- a/libraries/physics/src/ContactPoint.h +++ b/libraries/physics/src/ContactPoint.h @@ -15,7 +15,8 @@ #include #include -#include "CollisionInfo.h" +#include + #include "VerletPoint.h" class Shape; diff --git a/libraries/entities/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp similarity index 95% rename from libraries/entities/src/EntityMotionState.cpp rename to libraries/physics/src/EntityMotionState.cpp index b27e372902..c9fbc79169 100644 --- a/libraries/entities/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -9,11 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifdef USE_BULLET_PHYSICS -#include -#endif // USE_BULLET_PHYSICS +#include -#include "EntityItem.h" +#ifdef USE_BULLET_PHYSICS +#include "BulletUtil.h" +#endif // USE_BULLET_PHYSICS #include "EntityMotionState.h" // TODO: store _cachedWorldOffset in a more central location -- VoxelTree and others also need to know about it @@ -67,7 +67,7 @@ void EntityMotionState::getWorldTransform (btTransform &worldTrans) const { // iff the corresponding RigidBody is DYNAMIC and has moved. void EntityMotionState::setWorldTransform (const btTransform &worldTrans) { uint32_t updateFlags = _entity->getUpdateFlags(); - if (! (updateFlags & PHYSICS_UPDATE_POSITION)) { + if (! (updateFlags & EntityItem::UPDATE_POSITION)) { glm::vec3 pos; bulletToGLM(worldTrans.getOrigin(), pos); _entity->setPositionInMeters(pos + _cachedWorldOffset); @@ -77,7 +77,7 @@ void EntityMotionState::setWorldTransform (const btTransform &worldTrans) { _entity->setRotation(rot); } - if (! (updateFlags & PHYSICS_UPDATE_VELOCITY)) { + if (! (updateFlags & EntityItem::UPDATE_VELOCITY)) { glm::vec3 v; getVelocity(v); _entity->setVelocityInMeters(v); diff --git a/libraries/entities/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h similarity index 97% rename from libraries/entities/src/EntityMotionState.h rename to libraries/physics/src/EntityMotionState.h index ace42613dd..793633e783 100644 --- a/libraries/entities/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -13,9 +13,11 @@ #define hifi_EntityMotionState_h #include + #ifdef USE_BULLET_PHYSICS -#include +#include "CustomMotionState.h" #else // USE_BULLET_PHYSICS + // CustomMotionState stubbery class CustomMotionState { public: diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 0dfa451b99..b0e62beac4 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -24,10 +24,10 @@ void PhysicsEngine::init() { _constraintSolver = new btSequentialImpulseConstraintSolver; _dynamicsWorld = new btDiscreteDynamicsWorld(_collisionDispatcher, _broadphaseFilter, _constraintSolver, _collisionConfig); - // TODO: once the initial physics system is working we will set gravity of the world to be zero - // and each object will have to specify its own local gravity, or we'll set up gravity zones. - //_dynamicsWorld->setGravity(btVector3(0.0f, 0.0f, 0.0f)); - // + // default gravity of the world is zero, so each object must specify its own gravity + // TODO: set up gravity zones + _dynamicsWorld->setGravity(btVector3(0.0f, 0.0f, 0.0f)); + // GROUND HACK: In the meantime we add a big planar floor to catch falling objects // NOTE: we don't care about memory leaking groundShape and groundObject --> // they'll exist until the executable exits. @@ -123,7 +123,7 @@ bool PhysicsEngine::removeVoxel(const glm::vec3& position, float scale) { // CF_DISABLE_VISUALIZE_OBJECT = 32, //disable debug drawing // CF_DISABLE_SPU_COLLISION_PROCESSING = 64//disable parallel/SPU processing -bool PhysicsEngine::addEntity(CustomMotionState* motionState) { +bool PhysicsEngine::addObject(CustomMotionState* motionState) { assert(motionState); ShapeInfo info; motionState->computeShapeInfo(info); @@ -170,7 +170,7 @@ bool PhysicsEngine::addEntity(CustomMotionState* motionState) { return false; } -bool PhysicsEngine::removeEntity(CustomMotionState* motionState) { +bool PhysicsEngine::removeObject(CustomMotionState* motionState) { assert(motionState); btRigidBody* body = motionState->_body; if (body) { @@ -186,7 +186,7 @@ bool PhysicsEngine::removeEntity(CustomMotionState* motionState) { return false; } -bool PhysicsEngine::updateEntity(CustomMotionState* motionState, uint32_t flags) { +bool PhysicsEngine::updateObject(CustomMotionState* motionState, uint32_t flags) { btRigidBody* body = motionState->_body; if (!body) { return false; @@ -194,16 +194,16 @@ bool PhysicsEngine::updateEntity(CustomMotionState* motionState, uint32_t flags) if (flags & PHYSICS_UPDATE_HARD) { // a hard update requires the body be pulled out of physics engine, changed, then reinserted - updateEntityHard(body, motionState, flags); + updateObjectHard(body, motionState, flags); } else if (flags & PHYSICS_UPDATE_EASY) { // an easy update does not require that the body be pulled out of physics engine - updateEntityEasy(body, motionState, flags); + updateObjectEasy(body, motionState, flags); } return true; } // private -void PhysicsEngine::updateEntityHard(btRigidBody* body, CustomMotionState* motionState, uint32_t flags) { +void PhysicsEngine::updateObjectHard(btRigidBody* body, CustomMotionState* motionState, uint32_t flags) { MotionType newType = motionState->getMotionType(); // pull body out of physics engine @@ -227,7 +227,7 @@ void PhysicsEngine::updateEntityHard(btRigidBody* body, CustomMotionState* motio } bool easyUpdate = flags & PHYSICS_UPDATE_EASY; if (easyUpdate) { - updateEntityEasy(body, motionState, flags); + updateObjectEasy(body, motionState, flags); } // update the motion parameters @@ -280,7 +280,7 @@ void PhysicsEngine::updateEntityHard(btRigidBody* body, CustomMotionState* motio } // private -void PhysicsEngine::updateEntityEasy(btRigidBody* body, CustomMotionState* motionState, uint32_t flags) { +void PhysicsEngine::updateObjectEasy(btRigidBody* body, CustomMotionState* motionState, uint32_t flags) { if (flags & PHYSICS_UPDATE_POSITION) { btTransform transform; motionState->getWorldTransform(transform); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index b9a44dc579..dfac1b17e8 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -77,22 +77,22 @@ public: /// \return true if Voxel removed bool removeVoxel(const glm::vec3& position, float scale); - /// \param motionState pointer to Entity's MotionState - /// \return true if Entity added - bool addEntity(CustomMotionState* motionState); + /// \param motionState pointer to Object's MotionState + /// \return true if Object added + bool addObject(CustomMotionState* motionState); - /// \param motionState pointer to Entity's MotionState - /// \return true if Entity removed - bool removeEntity(CustomMotionState* motionState); + /// \param motionState pointer to Object's MotionState + /// \return true if Object removed + bool removeObject(CustomMotionState* motionState); - /// \param motionState pointer to Entity's MotionState + /// \param motionState pointer to Object's MotionState /// \param flags set of bits indicating what categories of properties need to be updated /// \return true if entity updated - bool updateEntity(CustomMotionState* motionState, uint32_t flags); + bool updateObject(CustomMotionState* motionState, uint32_t flags); protected: - void updateEntityHard(btRigidBody* body, CustomMotionState* motionState, uint32_t flags); - void updateEntityEasy(btRigidBody* body, CustomMotionState* motionState, uint32_t flags); + void updateObjectHard(btRigidBody* body, CustomMotionState* motionState, uint32_t flags); + void updateObjectEasy(btRigidBody* body, CustomMotionState* motionState, uint32_t flags); btClock _clock; btDefaultCollisionConfiguration* _collisionConfig; diff --git a/libraries/physics/src/PhysicsEntity.h b/libraries/physics/src/PhysicsEntity.h index bf401d9339..92b302debb 100644 --- a/libraries/physics/src/PhysicsEntity.h +++ b/libraries/physics/src/PhysicsEntity.h @@ -18,13 +18,13 @@ #include #include +#include +#include + #ifdef USE_BULLET_PHYSICS #include "PhysicsEngine.h" #endif // USE_BULLET_PHYSICS -#include "CollisionInfo.h" -#include "RayIntersectionInfo.h" - class Shape; class PhysicsSimulation; diff --git a/libraries/physics/src/ShapeInfo.cpp b/libraries/physics/src/ShapeInfo.cpp index cf848793a9..5587a6b528 100644 --- a/libraries/physics/src/ShapeInfo.cpp +++ b/libraries/physics/src/ShapeInfo.cpp @@ -17,6 +17,7 @@ #include // for MILLIMETERS_PER_METER #include "BulletUtil.h" +#include "DoubleHashKey.h" #include "ShapeInfo.h" void ShapeInfo::collectInfo(const btCollisionShape* shape) { diff --git a/libraries/physics/src/ShapeInfo.h b/libraries/physics/src/ShapeInfo.h index 40dedfef1e..1be59c9472 100644 --- a/libraries/physics/src/ShapeInfo.h +++ b/libraries/physics/src/ShapeInfo.h @@ -18,8 +18,6 @@ #include #include -#include "DoubleHashKey.h" - class ShapeInfo { public: ShapeInfo() : _type(INVALID_SHAPE_PROXYTYPE) {} diff --git a/libraries/physics/src/AACubeShape.cpp b/libraries/shared/src/AACubeShape.cpp similarity index 98% rename from libraries/physics/src/AACubeShape.cpp rename to libraries/shared/src/AACubeShape.cpp index 7ec024bf08..d713485c65 100644 --- a/libraries/physics/src/AACubeShape.cpp +++ b/libraries/shared/src/AACubeShape.cpp @@ -13,7 +13,7 @@ #include #include "AACubeShape.h" -#include // for SQUARE_ROOT_OF_3 +#include "SharedUtil.h" // for SQUARE_ROOT_OF_3 glm::vec3 faceNormals[3] = { glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f) }; diff --git a/libraries/physics/src/AACubeShape.h b/libraries/shared/src/AACubeShape.h similarity index 100% rename from libraries/physics/src/AACubeShape.h rename to libraries/shared/src/AACubeShape.h diff --git a/libraries/physics/src/CapsuleShape.cpp b/libraries/shared/src/CapsuleShape.cpp similarity index 99% rename from libraries/physics/src/CapsuleShape.cpp rename to libraries/shared/src/CapsuleShape.cpp index 153f1991d4..242f3160ce 100644 --- a/libraries/physics/src/CapsuleShape.cpp +++ b/libraries/shared/src/CapsuleShape.cpp @@ -12,11 +12,9 @@ #include #include -#include -#include - #include "CapsuleShape.h" - +#include "GeometryUtil.h" +#include "SharedUtil.h" CapsuleShape::CapsuleShape() : Shape(CAPSULE_SHAPE), _radius(0.0f), _halfHeight(0.0f) {} diff --git a/libraries/physics/src/CapsuleShape.h b/libraries/shared/src/CapsuleShape.h similarity index 98% rename from libraries/physics/src/CapsuleShape.h rename to libraries/shared/src/CapsuleShape.h index b79af60582..b91bf9f1ec 100644 --- a/libraries/physics/src/CapsuleShape.h +++ b/libraries/shared/src/CapsuleShape.h @@ -12,9 +12,8 @@ #ifndef hifi_CapsuleShape_h #define hifi_CapsuleShape_h -#include - #include "Shape.h" +#include "SharedUtil.h" // default axis of CapsuleShape is Y-axis const glm::vec3 DEFAULT_CAPSULE_AXIS(0.0f, 1.0f, 0.0f); diff --git a/libraries/physics/src/CollisionInfo.cpp b/libraries/shared/src/CollisionInfo.cpp similarity index 99% rename from libraries/physics/src/CollisionInfo.cpp rename to libraries/shared/src/CollisionInfo.cpp index 9add847980..b168b038f6 100644 --- a/libraries/physics/src/CollisionInfo.cpp +++ b/libraries/shared/src/CollisionInfo.cpp @@ -10,10 +10,10 @@ // -#include #include "CollisionInfo.h" #include "Shape.h" +#include "SharedUtil.h" CollisionInfo::CollisionInfo() : _data(NULL), diff --git a/libraries/physics/src/CollisionInfo.h b/libraries/shared/src/CollisionInfo.h similarity index 100% rename from libraries/physics/src/CollisionInfo.h rename to libraries/shared/src/CollisionInfo.h diff --git a/libraries/physics/src/ListShape.cpp b/libraries/shared/src/ListShape.cpp similarity index 100% rename from libraries/physics/src/ListShape.cpp rename to libraries/shared/src/ListShape.cpp diff --git a/libraries/physics/src/ListShape.h b/libraries/shared/src/ListShape.h similarity index 100% rename from libraries/physics/src/ListShape.h rename to libraries/shared/src/ListShape.h diff --git a/libraries/physics/src/PlaneShape.cpp b/libraries/shared/src/PlaneShape.cpp similarity index 98% rename from libraries/physics/src/PlaneShape.cpp rename to libraries/shared/src/PlaneShape.cpp index 2e71c2f330..012c418580 100644 --- a/libraries/physics/src/PlaneShape.cpp +++ b/libraries/shared/src/PlaneShape.cpp @@ -9,10 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include -#include - +#include "GLMHelpers.h" #include "PlaneShape.h" +#include "SharedUtil.h" const glm::vec3 UNROTATED_NORMAL(0.0f, 1.0f, 0.0f); diff --git a/libraries/physics/src/PlaneShape.h b/libraries/shared/src/PlaneShape.h similarity index 100% rename from libraries/physics/src/PlaneShape.h rename to libraries/shared/src/PlaneShape.h diff --git a/libraries/physics/src/RayIntersectionInfo.h b/libraries/shared/src/RayIntersectionInfo.h similarity index 100% rename from libraries/physics/src/RayIntersectionInfo.h rename to libraries/shared/src/RayIntersectionInfo.h diff --git a/libraries/physics/src/Shape.h b/libraries/shared/src/Shape.h similarity index 100% rename from libraries/physics/src/Shape.h rename to libraries/shared/src/Shape.h diff --git a/libraries/physics/src/ShapeCollider.cpp b/libraries/shared/src/ShapeCollider.cpp similarity index 99% rename from libraries/physics/src/ShapeCollider.cpp rename to libraries/shared/src/ShapeCollider.cpp index a7a4e34518..32d785b46a 100644 --- a/libraries/physics/src/ShapeCollider.cpp +++ b/libraries/shared/src/ShapeCollider.cpp @@ -11,16 +11,14 @@ #include -#include -#include - -#include "ShapeCollider.h" - #include "AACubeShape.h" #include "CapsuleShape.h" +#include "GeometryUtil.h" #include "ListShape.h" #include "PlaneShape.h" +#include "ShapeCollider.h" #include "SphereShape.h" +#include "StreamUtils.h" // NOTE: diff --git a/libraries/physics/src/ShapeCollider.h b/libraries/shared/src/ShapeCollider.h similarity index 99% rename from libraries/physics/src/ShapeCollider.h rename to libraries/shared/src/ShapeCollider.h index f2c0de470d..16023ac6a5 100644 --- a/libraries/physics/src/ShapeCollider.h +++ b/libraries/shared/src/ShapeCollider.h @@ -14,10 +14,10 @@ #include -#include - #include "CollisionInfo.h" #include "RayIntersectionInfo.h" +#include "SharedUtil.h" + class Shape; class SphereShape; diff --git a/libraries/physics/src/SphereShape.cpp b/libraries/shared/src/SphereShape.cpp similarity index 100% rename from libraries/physics/src/SphereShape.cpp rename to libraries/shared/src/SphereShape.cpp diff --git a/libraries/physics/src/SphereShape.h b/libraries/shared/src/SphereShape.h similarity index 98% rename from libraries/physics/src/SphereShape.h rename to libraries/shared/src/SphereShape.h index 9cb83f92e1..c8562a99da 100644 --- a/libraries/physics/src/SphereShape.h +++ b/libraries/shared/src/SphereShape.h @@ -12,9 +12,8 @@ #ifndef hifi_SphereShape_h #define hifi_SphereShape_h -#include - #include "Shape.h" +#include "SharedUtil.h" class SphereShape : public Shape { From 8aba2a06e010f78079b8c74ca3897bbd9a6497e4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 1 Dec 2014 16:47:33 -0800 Subject: [PATCH 049/105] Splitting Bullet stuff out of ShapeInfo --- libraries/physics/src/PhysicsEngine.cpp | 4 +- libraries/physics/src/ShapeInfo.cpp | 94 ++----------------------- libraries/physics/src/ShapeInfo.h | 15 ++-- libraries/physics/src/ShapeInfoUtil.cpp | 94 +++++++++++++++++++++++++ libraries/physics/src/ShapeInfoUtil.h | 31 ++++++++ libraries/physics/src/ShapeManager.cpp | 3 +- tests/physics/src/ShapeManagerTests.cpp | 9 +-- 7 files changed, 145 insertions(+), 105 deletions(-) create mode 100644 libraries/physics/src/ShapeInfoUtil.cpp create mode 100644 libraries/physics/src/ShapeInfoUtil.h diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index b0e62beac4..6962355d5d 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -12,6 +12,8 @@ #include "PhysicsEngine.h" #ifdef USE_BULLET_PHYSICS +#include "ShapeInfoUtil.h" + PhysicsEngine::~PhysicsEngine() { } @@ -176,7 +178,7 @@ bool PhysicsEngine::removeObject(CustomMotionState* motionState) { if (body) { const btCollisionShape* shape = body->getCollisionShape(); ShapeInfo info; - info.collectInfo(shape); + ShapeInfoUtil::collectInfoFromShape(shape, info); _dynamicsWorld->removeRigidBody(body); _shapeManager.releaseShape(info); delete body; diff --git a/libraries/physics/src/ShapeInfo.cpp b/libraries/physics/src/ShapeInfo.cpp index 5587a6b528..dc53b1eaf3 100644 --- a/libraries/physics/src/ShapeInfo.cpp +++ b/libraries/physics/src/ShapeInfo.cpp @@ -12,7 +12,6 @@ #ifdef USE_BULLET_PHYSICS #include -#include #include // for MILLIMETERS_PER_METER @@ -20,46 +19,7 @@ #include "DoubleHashKey.h" #include "ShapeInfo.h" -void ShapeInfo::collectInfo(const btCollisionShape* shape) { - _data.clear(); - if (shape) { - _type = (unsigned int)(shape->getShapeType()); - switch(_type) { - case BOX_SHAPE_PROXYTYPE: - { - const btBoxShape* boxShape = static_cast(shape); - _data.push_back(boxShape->getHalfExtentsWithMargin()); - } - break; - case SPHERE_SHAPE_PROXYTYPE: - { - const btSphereShape* sphereShape = static_cast(shape); - _data.push_back(btVector3(0.0f, 0.0f, sphereShape->getRadius())); - } - break; - case CYLINDER_SHAPE_PROXYTYPE: - { - const btCylinderShape* cylinderShape = static_cast(shape); - _data.push_back(cylinderShape->getHalfExtentsWithMargin()); - } - break; - case CAPSULE_SHAPE_PROXYTYPE: - { - const btCapsuleShape* capsuleShape = static_cast(shape); - _data.push_back(btVector3(capsuleShape->getRadius(), capsuleShape->getHalfHeight(), 0.0f)); - // NOTE: we only support capsules with axis along yAxis - } - break; - default: - _type = INVALID_SHAPE_PROXYTYPE; - break; - } - } else { - _type = INVALID_SHAPE_PROXYTYPE; - } -} - -void ShapeInfo::setBox(const btVector3& halfExtents) { +void ShapeInfo::setBox(const glm::vec3& halfExtents) { _type = BOX_SHAPE_PROXYTYPE; _data.clear(); _data.push_back(halfExtents); @@ -68,29 +28,26 @@ void ShapeInfo::setBox(const btVector3& halfExtents) { void ShapeInfo::setBox(const glm::vec3& halfExtents) { _type = BOX_SHAPE_PROXYTYPE; _data.clear(); - btVector3 bulletHalfExtents; - glmToBullet(halfExtents, bulletHalfExtents); _data.push_back(bulletHalfExtents); } void ShapeInfo::setSphere(float radius) { _type = SPHERE_SHAPE_PROXYTYPE; _data.clear(); - _data.push_back(btVector3(0.0f, 0.0f, radius)); + _data.push_back(glm::vec3(0.0f, 0.0f, radius)); } void ShapeInfo::setCylinder(float radius, float height) { _type = CYLINDER_SHAPE_PROXYTYPE; _data.clear(); // NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X - // halfExtents = btVector3(radius, halfHeight, unused) - _data.push_back(btVector3(radius, 0.5f * height, radius)); + _data.push_back(glm::vec3btVector3(radius, 0.5f * height, radius)); } void ShapeInfo::setCapsule(float radius, float height) { _type = CAPSULE_SHAPE_PROXYTYPE; _data.clear(); - _data.push_back(btVector3(radius, 0.5f * height, 0.0f)); + _data.push_back(glm::vec3(radius, 0.5f * height, 0.0f)); } int ShapeInfo::computeHash() const { @@ -99,7 +56,7 @@ int ShapeInfo::computeHash() const { int primeIndex = 0; unsigned int hash = DoubleHashKey::hashFunction((unsigned int)_type, primeIndex++); - btVector3 tmpData; + glm::vec3 tmpData; int numData = _data.size(); for (int i = 0; i < numData; ++i) { tmpData = _data[i]; @@ -119,7 +76,7 @@ int ShapeInfo::computeHash2() const { // TODO?: provide lookup table for hash of _type? unsigned int hash = DoubleHashKey::hashFunction2((unsigned int)_type); - btVector3 tmpData; + glm::vec3 tmpData; int numData = _data.size(); for (int i = 0; i < numData; ++i) { tmpData = _data[i]; @@ -139,43 +96,4 @@ int ShapeInfo::computeHash2() const { return hash; } -btCollisionShape* ShapeInfo::createShape() const { - btCollisionShape* shape = NULL; - int numData = _data.size(); - switch(_type) { - case BOX_SHAPE_PROXYTYPE: { - if (numData > 0) { - btVector3 halfExtents = _data[0]; - shape = new btBoxShape(halfExtents); - } - } - break; - case SPHERE_SHAPE_PROXYTYPE: { - if (numData > 0) { - float radius = _data[0].getZ(); - shape = new btSphereShape(radius); - } - } - break; - case CYLINDER_SHAPE_PROXYTYPE: { - if (numData > 0) { - btVector3 halfExtents = _data[0]; - // NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X - // halfExtents = btVector3(radius, halfHeight, unused) - shape = new btCylinderShape(halfExtents); - } - } - break; - case CAPSULE_SHAPE_PROXYTYPE: { - if (numData > 0) { - float radius = _data[0].getX(); - float height = 2.0f * _data[0].getY(); - shape = new btCapsuleShape(radius, height); - } - } - break; - } - return shape; -} - #endif // USE_BULLET_PHYSICS diff --git a/libraries/physics/src/ShapeInfo.h b/libraries/physics/src/ShapeInfo.h index 1be59c9472..0b60a4672e 100644 --- a/libraries/physics/src/ShapeInfo.h +++ b/libraries/physics/src/ShapeInfo.h @@ -14,19 +14,14 @@ #ifdef USE_BULLET_PHYSICS -#include -#include +//#include +#include #include class ShapeInfo { public: ShapeInfo() : _type(INVALID_SHAPE_PROXYTYPE) {} - ShapeInfo(const btCollisionShape* shape) : _type(INVALID_SHAPE_PROXYTYPE) { - collectInfo(shape); - } - - void collectInfo(const btCollisionShape* shape); void setBox(const btVector3& halfExtents); void setBox(const glm::vec3& halfExtents); @@ -37,12 +32,10 @@ public: int computeHash() const; int computeHash2() const; - btCollisionShape* createShape() const; - -private: int _type; - btAlignedObjectArray _data; + QVector _data; }; #endif // USE_BULLET_PHYSICS #endif // hifi_ShapeInfo_h + diff --git a/libraries/physics/src/ShapeInfoUtil.cpp b/libraries/physics/src/ShapeInfoUtil.cpp new file mode 100644 index 0000000000..95e2efb2c2 --- /dev/null +++ b/libraries/physics/src/ShapeInfoUtil.cpp @@ -0,0 +1,94 @@ +// +// ShapeInfoUtil.cpp +// libraries/physcis/src +// +// Created by Andrew Meadows 2014.12.01 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ShapeInfoUtil.h" + +#ifdef USE_BULLET_PHYSICS + +void ShapeInfoUtil::collectInfoFromShape(const btCollisionShape* shape, ShapeInfo& info) { + info._data.clear(); + if (shape) { + info._type = (unsigned int)(shape->getShapeType()); + switch(_type) { + case BOX_SHAPE_PROXYTYPE: + { + const btBoxShape* boxShape = static_cast(shape); + info._data.push_back(boxShape->getHalfExtentsWithMargin()); + } + break; + case SPHERE_SHAPE_PROXYTYPE: + { + const btSphereShape* sphereShape = static_cast(shape); + info._data.push_back(btVector3(0.0f, 0.0f, sphereShape->getRadius())); + } + break; + case CYLINDER_SHAPE_PROXYTYPE: + { + const btCylinderShape* cylinderShape = static_cast(shape); + info._data.push_back(cylinderShape->getHalfExtentsWithMargin()); + } + break; + case CAPSULE_SHAPE_PROXYTYPE: + { + const btCapsuleShape* capsuleShape = static_cast(shape); + info._data.push_back(btVector3(capsuleShape->getRadius(), capsuleShape->getHalfHeight(), 0.0f)); + // NOTE: we only support capsules with axis along yAxis + } + break; + default: + info._type = INVALID_SHAPE_PROXYTYPE; + break; + } + } else { + info._type = INVALID_SHAPE_PROXYTYPE; + } +} + +btCollisionShape* ShapeInfoUtil::createShape(const ShapeInfo& info) { + btCollisionShape* shape = NULL; + int numData = info._data.size(); + switch(info._type) { + case BOX_SHAPE_PROXYTYPE: { + if (numData > 0) { + btVector3 halfExtents = info._data[0]; + shape = new btBoxShape(halfExtents); + } + } + break; + case SPHERE_SHAPE_PROXYTYPE: { + if (numData > 0) { + float radius = info._data[0].getZ(); + shape = new btSphereShape(radius); + } + } + break; + case CYLINDER_SHAPE_PROXYTYPE: { + if (numData > 0) { + btVector3 halfExtents = info._data[0]; + // NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X + // halfExtents = btVector3(radius, halfHeight, unused) + shape = new btCylinderShape(halfExtents); + } + } + break; + case CAPSULE_SHAPE_PROXYTYPE: { + if (numData > 0) { + float radius = info._data[0].getX(); + float height = 2.0f * info._data[0].getY(); + shape = new btCapsuleShape(radius, height); + } + } + break; + } + return shape; +} + +#endif // USE_BULLET_PHYSICS diff --git a/libraries/physics/src/ShapeInfoUtil.h b/libraries/physics/src/ShapeInfoUtil.h new file mode 100644 index 0000000000..cff9c08a81 --- /dev/null +++ b/libraries/physics/src/ShapeInfoUtil.h @@ -0,0 +1,31 @@ +// +// ShapeInfoUtil.h +// libraries/physcis/src +// +// Created by Andrew Meadows 2014.12.01 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ShapeInfoUtil_h +#define hifi_ShapeInfoUtil_h + +#ifdef USE_BULLET_PHYSICS + +#include +#include + +#include + +// translates between ShapeInfo and btShape + +namespace ShapeInfoUtil { + void collectInfoFromShape(const btCollisionShape* shape, ShapeInfo& info); + + btCollisionShape* createShapeFromInfo(const ShapeInfo& info); +}; + +#endif // USE_BULLET_PHYSICS +#endif // hifi_ShapeInfoUtil_h diff --git a/libraries/physics/src/ShapeManager.cpp b/libraries/physics/src/ShapeManager.cpp index c75bfd67ea..73fa15211e 100644 --- a/libraries/physics/src/ShapeManager.cpp +++ b/libraries/physics/src/ShapeManager.cpp @@ -10,6 +10,7 @@ // #ifdef USE_BULLET_PHYSICS +#include "ShapeInfoUtil.h" #include "ShapeManager.h" ShapeManager::ShapeManager() { @@ -32,7 +33,7 @@ btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { shapeRef->_refCount++; return shapeRef->_shape; } else { - btCollisionShape* shape = info.createShape(); + btCollisionShape* shape = ShapeInfoUtil::createShapeFromInfo(info); if (shape) { ShapeReference newRef; newRef._refCount = 1; diff --git a/tests/physics/src/ShapeManagerTests.cpp b/tests/physics/src/ShapeManagerTests.cpp index 78ef45f107..3bfc8b1829 100644 --- a/tests/physics/src/ShapeManagerTests.cpp +++ b/tests/physics/src/ShapeManagerTests.cpp @@ -10,6 +10,7 @@ // #include +#include #include #include @@ -163,7 +164,7 @@ void ShapeManagerTests::addBoxShape() { btCollisionShape* shape = shapeManager.getShape(info); ShapeInfo otherInfo; - otherInfo.collectInfo(shape); + collectInfoFromShape(shape, otherInfo); btCollisionShape* otherShape = shapeManager.getShape(otherInfo); if (shape != otherShape) { @@ -183,7 +184,7 @@ void ShapeManagerTests::addSphereShape() { btCollisionShape* shape = shapeManager.getShape(info); ShapeInfo otherInfo; - otherInfo.collectInfo(shape); + collectInfoFromShape(shape, otherInfo); btCollisionShape* otherShape = shapeManager.getShape(otherInfo); if (shape != otherShape) { @@ -204,7 +205,7 @@ void ShapeManagerTests::addCylinderShape() { btCollisionShape* shape = shapeManager.getShape(info); ShapeInfo otherInfo; - otherInfo.collectInfo(shape); + collectInfoFromShape(shape, otherInfo); btCollisionShape* otherShape = shapeManager.getShape(otherInfo); if (shape != otherShape) { @@ -225,7 +226,7 @@ void ShapeManagerTests::addCapsuleShape() { btCollisionShape* shape = shapeManager.getShape(info); ShapeInfo otherInfo; - otherInfo.collectInfo(shape); + collectInfoFromShape(shape, otherInfo); btCollisionShape* otherShape = shapeManager.getShape(otherInfo); if (shape != otherShape) { From e6a9081184482bef5c1bd774c1c82cf201c76294 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 1 Dec 2014 16:47:55 -0800 Subject: [PATCH 050/105] Moving ShapeInfo to shared lib --- libraries/{physics => shared}/src/ShapeInfo.cpp | 0 libraries/{physics => shared}/src/ShapeInfo.h | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename libraries/{physics => shared}/src/ShapeInfo.cpp (100%) rename libraries/{physics => shared}/src/ShapeInfo.h (100%) diff --git a/libraries/physics/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp similarity index 100% rename from libraries/physics/src/ShapeInfo.cpp rename to libraries/shared/src/ShapeInfo.cpp diff --git a/libraries/physics/src/ShapeInfo.h b/libraries/shared/src/ShapeInfo.h similarity index 100% rename from libraries/physics/src/ShapeInfo.h rename to libraries/shared/src/ShapeInfo.h From 919214b7cb4c8aec6c64865c9f33986339329c31 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 2 Dec 2014 10:44:40 -0800 Subject: [PATCH 051/105] split ShapeInfo into shared and physics parts --- libraries/physics/src/DoubleHashKey.h | 6 +- libraries/physics/src/EntityMotionState.cpp | 6 +- libraries/physics/src/ShapeInfoUtil.cpp | 143 +++++++++++++++++--- libraries/physics/src/ShapeInfoUtil.h | 8 ++ libraries/physics/src/ShapeManager.cpp | 11 +- libraries/physics/src/ShapeManager.h | 16 +-- libraries/shared/src/Shape.h | 15 +- libraries/shared/src/ShapeInfo.cpp | 71 ++-------- libraries/shared/src/ShapeInfo.h | 13 +- tests/physics/src/ShapeInfoTests.cpp | 130 +++++++++--------- tests/physics/src/ShapeManagerTests.cpp | 14 +- 11 files changed, 230 insertions(+), 203 deletions(-) diff --git a/libraries/physics/src/DoubleHashKey.h b/libraries/physics/src/DoubleHashKey.h index 0dbf2430e2..ebacf6c96a 100644 --- a/libraries/physics/src/DoubleHashKey.h +++ b/libraries/physics/src/DoubleHashKey.h @@ -18,6 +18,8 @@ public: static unsigned int hashFunction(unsigned int value, int primeIndex); static unsigned int hashFunction2(unsigned int value); + DoubleHashKey() : _hash(0), _hash2(0) { } + DoubleHashKey(unsigned int value, int primeIndex = 0) : _hash(hashFunction(value, primeIndex)), _hash2(hashFunction2(value)) { @@ -29,10 +31,6 @@ public: unsigned int getHash() const { return (unsigned int)_hash; } -protected: - // the default ctor is protected so that only derived classes can use it - DoubleHashKey() : _hash(0), _hash2(0) { } - int _hash; int _hash2; }; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index c9fbc79169..f08b32afb2 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -107,13 +107,9 @@ void EntityMotionState::applyGravity() const { } void EntityMotionState::computeShapeInfo(ShapeInfo& info) { -#ifdef USE_BULLET_PHYSICS // HACK: for now we make everything a box. glm::vec3 halfExtents = 0.5f * _entity->getDimensionsInMeters(); - btVector3 bulletHalfExtents; - glmToBullet(halfExtents, bulletHalfExtents); - info.setBox(bulletHalfExtents); -#endif // USE_BULLET_PHYSICS + info.setBox(halfExtents); } void EntityMotionState::getBoundingCubes(AACube& oldCube, AACube& newCube) { diff --git a/libraries/physics/src/ShapeInfoUtil.cpp b/libraries/physics/src/ShapeInfoUtil.cpp index 95e2efb2c2..e4ea118a0b 100644 --- a/libraries/physics/src/ShapeInfoUtil.cpp +++ b/libraries/physics/src/ShapeInfoUtil.cpp @@ -9,80 +9,133 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include // for FOO_SHAPE types +#include // for MILLIMETERS_PER_METER + #include "ShapeInfoUtil.h" +#include "BulletUtil.h" #ifdef USE_BULLET_PHYSICS + +int ShapeInfoUtil::toBulletShapeType(int shapeInfoType) { + int bulletShapeType = INVALID_SHAPE_PROXYTYPE; + switch(shapeInfoType) { + case BOX_SHAPE: + bulletShapeType = BOX_SHAPE_PROXYTYPE; + break; + case SPHERE_SHAPE: + bulletShapeType = SPHERE_SHAPE_PROXYTYPE; + break; + case CAPSULE_SHAPE: + bulletShapeType = CAPSULE_SHAPE_PROXYTYPE; + break; + case CYLINDER_SHAPE: + bulletShapeType = CYLINDER_SHAPE_PROXYTYPE; + break; + } + return bulletShapeType; +} + +int ShapeInfoUtil::fromBulletShapeType(int bulletShapeType) { + int shapeInfoType = INVALID_SHAPE; + switch(bulletShapeType) { + case BOX_SHAPE_PROXYTYPE: + shapeInfoType = BOX_SHAPE; + break; + case SPHERE_SHAPE_PROXYTYPE: + shapeInfoType = SPHERE_SHAPE; + break; + case CAPSULE_SHAPE_PROXYTYPE: + shapeInfoType = CAPSULE_SHAPE; + break; + case CYLINDER_SHAPE_PROXYTYPE: + shapeInfoType = CYLINDER_SHAPE; + break; + } + return shapeInfoType; +} + void ShapeInfoUtil::collectInfoFromShape(const btCollisionShape* shape, ShapeInfo& info) { info._data.clear(); if (shape) { - info._type = (unsigned int)(shape->getShapeType()); - switch(_type) { - case BOX_SHAPE_PROXYTYPE: + info._type = ShapeInfoUtil::fromBulletShapeType(shape->getShapeType()); + switch(info._type) { + case BOX_SHAPE: { const btBoxShape* boxShape = static_cast(shape); - info._data.push_back(boxShape->getHalfExtentsWithMargin()); + glm::vec3 halfExtents; + bulletToGLM(boxShape->getHalfExtentsWithMargin(), halfExtents); + info._data.push_back(halfExtents); } break; - case SPHERE_SHAPE_PROXYTYPE: + case SPHERE_SHAPE: { const btSphereShape* sphereShape = static_cast(shape); - info._data.push_back(btVector3(0.0f, 0.0f, sphereShape->getRadius())); + glm::vec3 data; + bulletToGLM(btVector3(0.0f, 0.0f, sphereShape->getRadius()), data); + info._data.push_back(data); } break; - case CYLINDER_SHAPE_PROXYTYPE: + case CYLINDER_SHAPE: { const btCylinderShape* cylinderShape = static_cast(shape); - info._data.push_back(cylinderShape->getHalfExtentsWithMargin()); + glm::vec3 halfExtents; + bulletToGLM(cylinderShape->getHalfExtentsWithMargin(), halfExtents); + info._data.push_back(halfExtents); } break; - case CAPSULE_SHAPE_PROXYTYPE: + case CAPSULE_SHAPE: { const btCapsuleShape* capsuleShape = static_cast(shape); - info._data.push_back(btVector3(capsuleShape->getRadius(), capsuleShape->getHalfHeight(), 0.0f)); + glm::vec3 data; + bulletToGLM(btVector3(capsuleShape->getRadius(), capsuleShape->getHalfHeight(), 0.0f), data); + info._data.push_back(data); // NOTE: we only support capsules with axis along yAxis } break; default: - info._type = INVALID_SHAPE_PROXYTYPE; + info._type = INVALID_SHAPE; break; } } else { - info._type = INVALID_SHAPE_PROXYTYPE; + info._type = INVALID_SHAPE; } } -btCollisionShape* ShapeInfoUtil::createShape(const ShapeInfo& info) { +btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) { btCollisionShape* shape = NULL; int numData = info._data.size(); switch(info._type) { - case BOX_SHAPE_PROXYTYPE: { + case BOX_SHAPE: { if (numData > 0) { - btVector3 halfExtents = info._data[0]; + btVector3 halfExtents; + glmToBullet(info._data[0], halfExtents); shape = new btBoxShape(halfExtents); } } break; - case SPHERE_SHAPE_PROXYTYPE: { + case SPHERE_SHAPE: { if (numData > 0) { - float radius = info._data[0].getZ(); + float radius = info._data[0].z; shape = new btSphereShape(radius); } } break; - case CYLINDER_SHAPE_PROXYTYPE: { + case CYLINDER_SHAPE: { if (numData > 0) { - btVector3 halfExtents = info._data[0]; + btVector3 halfExtents; + glmToBullet(info._data[0], halfExtents); // NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X // halfExtents = btVector3(radius, halfHeight, unused) shape = new btCylinderShape(halfExtents); } } break; - case CAPSULE_SHAPE_PROXYTYPE: { + case CAPSULE_SHAPE: { if (numData > 0) { - float radius = info._data[0].getX(); - float height = 2.0f * info._data[0].getY(); + float radius = info._data[0].x; + float height = 2.0f * info._data[0].y; shape = new btCapsuleShape(radius, height); } } @@ -91,4 +144,50 @@ btCollisionShape* ShapeInfoUtil::createShape(const ShapeInfo& info) { return shape; } +DoubleHashKey ShapeInfoUtil::computeHash(const ShapeInfo& info) { + DoubleHashKey key; + // compute hash + // scramble the bits of the type + // TODO?: provide lookup table for hash of info._type rather than recompute? + int primeIndex = 0; + unsigned int hash = DoubleHashKey::hashFunction((unsigned int)info._type, primeIndex++); + + glm::vec3 tmpData; + int numData = info._data.size(); + for (int i = 0; i < numData; ++i) { + tmpData = info._data[i]; + for (int j = 0; j < 3; ++j) { + // NOTE: 0.49f is used to bump the float up almost half a millimeter + // so the cast to int produces a round() effect rather than a floor() + unsigned int floatHash = + DoubleHashKey::hashFunction((int)(tmpData[j] * MILLIMETERS_PER_METER + copysignf(1.0f, tmpData[j]) * 0.49f), primeIndex++); + hash ^= floatHash; + } + } + key._hash = (int)hash; + + // compute hash2 + // scramble the bits of the type + // TODO?: provide lookup table for hash2 of info._type rather than recompute? + hash = DoubleHashKey::hashFunction2((unsigned int)info._type); + + for (int i = 0; i < numData; ++i) { + tmpData = info._data[i]; + for (int j = 0; j < 3; ++j) { + // NOTE: 0.49f is used to bump the float up almost half a millimeter + // so the cast to int produces a round() effect rather than a floor() + unsigned int floatHash = + DoubleHashKey::hashFunction2((int)(tmpData[j] * MILLIMETERS_PER_METER + copysignf(1.0f, tmpData[j]) * 0.49f)); + hash += ~(floatHash << 17); + hash ^= (floatHash >> 11); + hash += (floatHash << 4); + hash ^= (floatHash >> 7); + hash += ~(floatHash << 10); + hash = (hash << 16) | (hash >> 16); + } + } + key._hash2 = (int)hash; + return key; +} + #endif // USE_BULLET_PHYSICS diff --git a/libraries/physics/src/ShapeInfoUtil.h b/libraries/physics/src/ShapeInfoUtil.h index cff9c08a81..7363cf483b 100644 --- a/libraries/physics/src/ShapeInfoUtil.h +++ b/libraries/physics/src/ShapeInfoUtil.h @@ -19,12 +19,20 @@ #include +#include "DoubleHashKey.h" + // translates between ShapeInfo and btShape namespace ShapeInfoUtil { void collectInfoFromShape(const btCollisionShape* shape, ShapeInfo& info); btCollisionShape* createShapeFromInfo(const ShapeInfo& info); + + DoubleHashKey computeHash(const ShapeInfo& info); + + // TODO? just use bullet shape types everywhere? + int toBulletShapeType(int shapeInfoType); + int fromBulletShapeType(int bulletShapeType); }; #endif // USE_BULLET_PHYSICS diff --git a/libraries/physics/src/ShapeManager.cpp b/libraries/physics/src/ShapeManager.cpp index 73fa15211e..670fcf54ae 100644 --- a/libraries/physics/src/ShapeManager.cpp +++ b/libraries/physics/src/ShapeManager.cpp @@ -27,7 +27,7 @@ ShapeManager::~ShapeManager() { btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { - ShapeKey key(info); + DoubleHashKey key = ShapeInfoUtil::computeHash(info); ShapeReference* shapeRef = _shapeMap.find(key); if (shapeRef) { shapeRef->_refCount++; @@ -45,7 +45,7 @@ btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { } bool ShapeManager::releaseShape(const ShapeInfo& info) { - ShapeKey key(info); + DoubleHashKey key = ShapeInfoUtil::computeHash(info); ShapeReference* shapeRef = _shapeMap.find(key); if (shapeRef) { if (shapeRef->_refCount > 0) { @@ -70,14 +70,15 @@ bool ShapeManager::releaseShape(const ShapeInfo& info) { } bool ShapeManager::releaseShape(const btCollisionShape* shape) { - ShapeInfo info(shape); + ShapeInfo info; + ShapeInfoUtil::collectInfoFromShape(shape, info); return releaseShape(info); } void ShapeManager::collectGarbage() { int numShapes = _pendingGarbage.size(); for (int i = 0; i < numShapes; ++i) { - ShapeKey& key = _pendingGarbage[i]; + DoubleHashKey& key = _pendingGarbage[i]; ShapeReference* shapeRef = _shapeMap.find(key); if (shapeRef && shapeRef->_refCount == 0) { delete shapeRef->_shape; @@ -88,7 +89,7 @@ void ShapeManager::collectGarbage() { } int ShapeManager::getNumReferences(const ShapeInfo& info) const { - ShapeKey key(info); + DoubleHashKey key = ShapeInfoUtil::computeHash(info); const ShapeReference* shapeRef = _shapeMap.find(key); if (shapeRef) { return shapeRef->_refCount; diff --git a/libraries/physics/src/ShapeManager.h b/libraries/physics/src/ShapeManager.h index b205103f19..6eb4f363ff 100644 --- a/libraries/physics/src/ShapeManager.h +++ b/libraries/physics/src/ShapeManager.h @@ -17,17 +17,9 @@ #include #include -#include "DoubleHashKey.h" -#include "ShapeInfo.h" +#include -class ShapeKey : public DoubleHashKey -{ -public: - ShapeKey(const ShapeInfo& info) : DoubleHashKey() { - _hash = info.computeHash(); - _hash2 = info.computeHash2(); - } -}; +#include "DoubleHashKey.h" class ShapeManager { public: @@ -56,8 +48,8 @@ private: ShapeReference() : _refCount(0), _shape(NULL) {} }; - btHashMap _shapeMap; - btAlignedObjectArray _pendingGarbage; + btHashMap _shapeMap; + btAlignedObjectArray _pendingGarbage; }; #endif // USE_BULLET_PHYSICS diff --git a/libraries/shared/src/Shape.h b/libraries/shared/src/Shape.h index d029dddd87..6e7fe88347 100644 --- a/libraries/shared/src/Shape.h +++ b/libraries/shared/src/Shape.h @@ -25,12 +25,15 @@ class VerletPoint; const float MAX_SHAPE_MASS = 1.0e18f; // something less than sqrt(FLT_MAX) -const quint8 SPHERE_SHAPE = 0; -const quint8 CAPSULE_SHAPE = 1; -const quint8 PLANE_SHAPE = 2; -const quint8 AACUBE_SHAPE = 3; -const quint8 LIST_SHAPE = 4; -const quint8 UNKNOWN_SHAPE = 5; +const quint8 UNKNOWN_SHAPE = 0; +const quint8 INVALID_SHAPE = 0; +const quint8 SPHERE_SHAPE = 1; +const quint8 CAPSULE_SHAPE = 2; +const quint8 PLANE_SHAPE = 3; +const quint8 BOX_SHAPE = 4; +const quint8 AACUBE_SHAPE = 5; +const quint8 CYLINDER_SHAPE = 6; +const quint8 LIST_SHAPE = 7; class Shape { public: diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index dc53b1eaf3..38ff2301ad 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -9,91 +9,36 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifdef USE_BULLET_PHYSICS - #include -#include // for MILLIMETERS_PER_METER +#include "SharedUtil.h" // for MILLIMETERS_PER_METER +#include "StreamUtils.h" // adebug -#include "BulletUtil.h" -#include "DoubleHashKey.h" +//#include "DoubleHashKey.h" #include "ShapeInfo.h" void ShapeInfo::setBox(const glm::vec3& halfExtents) { - _type = BOX_SHAPE_PROXYTYPE; + _type = BOX_SHAPE; _data.clear(); _data.push_back(halfExtents); } -void ShapeInfo::setBox(const glm::vec3& halfExtents) { - _type = BOX_SHAPE_PROXYTYPE; - _data.clear(); - _data.push_back(bulletHalfExtents); -} - void ShapeInfo::setSphere(float radius) { - _type = SPHERE_SHAPE_PROXYTYPE; + _type = SPHERE_SHAPE; _data.clear(); _data.push_back(glm::vec3(0.0f, 0.0f, radius)); } void ShapeInfo::setCylinder(float radius, float height) { - _type = CYLINDER_SHAPE_PROXYTYPE; + _type = CYLINDER_SHAPE; _data.clear(); // NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X - _data.push_back(glm::vec3btVector3(radius, 0.5f * height, radius)); + _data.push_back(glm::vec3(radius, 0.5f * height, radius)); } void ShapeInfo::setCapsule(float radius, float height) { - _type = CAPSULE_SHAPE_PROXYTYPE; + _type = CAPSULE_SHAPE; _data.clear(); _data.push_back(glm::vec3(radius, 0.5f * height, 0.0f)); } -int ShapeInfo::computeHash() const { - // scramble the bits of the type - // TODO?: provide lookup table for hash of _type? - int primeIndex = 0; - unsigned int hash = DoubleHashKey::hashFunction((unsigned int)_type, primeIndex++); - - glm::vec3 tmpData; - int numData = _data.size(); - for (int i = 0; i < numData; ++i) { - tmpData = _data[i]; - for (int j = 0; j < 3; ++j) { - // NOTE: 0.49f is used to bump the float up almost half a millimeter - // so the cast to int produces a round() effect rather than a floor() - unsigned int floatHash = - DoubleHashKey::hashFunction((int)(tmpData[j] * MILLIMETERS_PER_METER + copysignf(1.0f, tmpData[j]) * 0.49f), primeIndex++); - hash ^= floatHash; - } - } - return hash; -} - -int ShapeInfo::computeHash2() const { - // scramble the bits of the type - // TODO?: provide lookup table for hash of _type? - unsigned int hash = DoubleHashKey::hashFunction2((unsigned int)_type); - - glm::vec3 tmpData; - int numData = _data.size(); - for (int i = 0; i < numData; ++i) { - tmpData = _data[i]; - for (int j = 0; j < 3; ++j) { - // NOTE: 0.49f is used to bump the float up almost half a millimeter - // so the cast to int produces a round() effect rather than a floor() - unsigned int floatHash = - DoubleHashKey::hashFunction2((int)(tmpData[j] * MILLIMETERS_PER_METER + copysignf(1.0f, tmpData[j]) * 0.49f)); - hash += ~(floatHash << 17); - hash ^= (floatHash >> 11); - hash += (floatHash << 4); - hash ^= (floatHash >> 7); - hash += ~(floatHash << 10); - hash = (hash << 16) | (hash >> 16); - } - } - return hash; -} - -#endif // USE_BULLET_PHYSICS diff --git a/libraries/shared/src/ShapeInfo.h b/libraries/shared/src/ShapeInfo.h index 0b60a4672e..ec5352e3da 100644 --- a/libraries/shared/src/ShapeInfo.h +++ b/libraries/shared/src/ShapeInfo.h @@ -12,30 +12,23 @@ #ifndef hifi_ShapeInfo_h #define hifi_ShapeInfo_h -#ifdef USE_BULLET_PHYSICS - -//#include #include #include +#include "Shape.h" + class ShapeInfo { public: - ShapeInfo() : _type(INVALID_SHAPE_PROXYTYPE) {} + ShapeInfo() : _type(INVALID_SHAPE) {} - - void setBox(const btVector3& halfExtents); void setBox(const glm::vec3& halfExtents); void setSphere(float radius); void setCylinder(float radius, float height); void setCapsule(float radius, float height); - int computeHash() const; - int computeHash2() const; - int _type; QVector _data; }; -#endif // USE_BULLET_PHYSICS #endif // hifi_ShapeInfo_h diff --git a/tests/physics/src/ShapeInfoTests.cpp b/tests/physics/src/ShapeInfoTests.cpp index 5ce74888fc..8784ce1266 100644 --- a/tests/physics/src/ShapeInfoTests.cpp +++ b/tests/physics/src/ShapeInfoTests.cpp @@ -10,7 +10,13 @@ // #include + +#include +#include + +#include #include +#include #include #include "ShapeInfoTests.h" @@ -40,21 +46,20 @@ void ShapeInfoTests::testHashFunctions() { // test sphere info.setSphere(radiusX); ++testCount; - int hash = info.computeHash(); - int hash2 = info.computeHash2(); - int* hashPtr = hashes.find(hash); - if (hashPtr && *hashPtr == hash2) { + DoubleHashKey key = ShapeInfoUtil::computeHash(info); + int* hashPtr = hashes.find(key._hash); + if (hashPtr && *hashPtr == key._hash2) { std::cout << testCount << " hash collision radiusX = " << radiusX - << " h1 = 0x" << std::hex << (unsigned int)(hash) - << " h2 = 0x" << std::hex << (unsigned int)(hash2) + << " h1 = 0x" << std::hex << (unsigned int)(key._hash) + << " h2 = 0x" << std::hex << (unsigned int)(key._hash2) << std::endl; ++numCollisions; assert(false); } else { - hashes.insert(hash, hash2); + hashes.insert(key._hash, key._hash2); } for (int k = 0; k < 32; ++k) { - if (masks[k] & hash2) { + if (masks[k] & key._hash2) { ++bits[k]; } } @@ -76,21 +81,20 @@ void ShapeInfoTests::testHashFunctions() { } ++testCount; - hash = info.computeHash(); - hash2 = info.computeHash2(); - hashPtr = hashes.find(hash); - if (hashPtr && *hashPtr == hash2) { + key = ShapeInfoUtil::computeHash(info); + hashPtr = hashes.find(key._hash); + if (hashPtr && *hashPtr == key._hash2) { std::cout << testCount << " hash collision radiusX = " << radiusX << " radiusY = " << radiusY - << " h1 = 0x" << std::hex << (unsigned int)(hash) - << " h2 = 0x" << std::hex << (unsigned int)(hash2) + << " h1 = 0x" << std::hex << (unsigned int)(key._hash) + << " h2 = 0x" << std::hex << (unsigned int)(key._hash2) << std::endl; ++numCollisions; assert(false); } else { - hashes.insert(hash, hash2); + hashes.insert(key._hash, key._hash2); } for (int k = 0; k < 32; ++k) { - if (masks[k] & hash2) { + if (masks[k] & key._hash2) { ++bits[k]; } } @@ -99,24 +103,23 @@ void ShapeInfoTests::testHashFunctions() { for (int z = 1; z < numSteps && testCount < maxTests; ++z) { float radiusZ = (float)z * deltaLength; // test box - info.setBox(btVector3(radiusX, radiusY, radiusZ)); + info.setBox(glm::vec3(radiusX, radiusY, radiusZ)); ++testCount; - hash = info.computeHash(); - hash2 = info.computeHash2(); - hashPtr = hashes.find(hash); - if (hashPtr && *hashPtr == hash2) { + DoubleHashKey key = ShapeInfoUtil::computeHash(info); + hashPtr = hashes.find(key._hash); + if (hashPtr && *hashPtr == key._hash2) { std::cout << testCount << " hash collision radiusX = " << radiusX << " radiusY = " << radiusY << " radiusZ = " << radiusZ - << " h1 = 0x" << std::hex << (unsigned int)(hash) - << " h2 = 0x" << std::hex << (unsigned int)(hash2) + << " h1 = 0x" << std::hex << (unsigned int)(key._hash) + << " h2 = 0x" << std::hex << (unsigned int)(key._hash2) << std::endl; ++numCollisions; assert(false); } else { - hashes.insert(hash, hash2); + hashes.insert(key._hash, key._hash2); } for (int k = 0; k < 32; ++k) { - if (masks[k] & hash2) { + if (masks[k] & key._hash2) { ++bits[k]; } } @@ -136,29 +139,27 @@ void ShapeInfoTests::testHashFunctions() { void ShapeInfoTests::testBoxShape() { #ifdef USE_BULLET_PHYSICS ShapeInfo info; - btVector3 halfExtents(1.23f, 4.56f, 7.89f); + glm::vec3 halfExtents(1.23f, 4.56f, 7.89f); info.setBox(halfExtents); - int hash = info.computeHash(); - int hash2 = info.computeHash2(); + DoubleHashKey key = ShapeInfoUtil::computeHash(info); - btCollisionShape* shape = info.createShape(); + btCollisionShape* shape = ShapeInfoUtil::createShapeFromInfo(info); if (!shape) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: NULL Box shape" << std::endl; } ShapeInfo otherInfo; - otherInfo.collectInfo(shape); + ShapeInfoUtil::collectInfoFromShape(shape, otherInfo); - int otherHash = otherInfo.computeHash(); - if (hash != otherHash) { + DoubleHashKey otherKey = ShapeInfoUtil::computeHash(otherInfo); + if (key._hash != otherKey._hash) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: expected Box shape hash = " << hash << " but found hash = " << otherHash << std::endl; + << " ERROR: expected Box shape hash = " << key._hash << " but found hash = " << otherKey._hash << std::endl; } - int otherHash2= otherInfo.computeHash2(); - if (hash2 != otherHash2) { + if (key._hash2 != otherKey._hash2) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: expected Box shape hash2 = " << hash2 << " but found hash2 = " << otherHash2 << std::endl; + << " ERROR: expected Box shape hash2 = " << key._hash2 << " but found hash2 = " << otherKey._hash2 << std::endl; } delete shape; @@ -170,24 +171,21 @@ void ShapeInfoTests::testSphereShape() { ShapeInfo info; float radius = 1.23f; info.setSphere(radius); - int hash = info.computeHash(); - int hash2 = info.computeHash2(); + DoubleHashKey key = ShapeInfoUtil::computeHash(info); - btCollisionShape* shape = info.createShape(); + btCollisionShape* shape = ShapeInfoUtil::createShapeFromInfo(info); ShapeInfo otherInfo; - otherInfo.collectInfo(shape); + ShapeInfoUtil::collectInfoFromShape(shape, otherInfo); - int otherHash = otherInfo.computeHash(); - if (hash != otherHash) { + DoubleHashKey otherKey = ShapeInfoUtil::computeHash(otherInfo); + if (key._hash != otherKey._hash) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: expected Sphere shape hash = " << hash << " but found hash = " << otherHash << std::endl; + << " ERROR: expected Sphere shape hash = " << key._hash << " but found hash = " << otherKey._hash << std::endl; } - - int otherHash2 = otherInfo.computeHash2(); - if (hash2 != otherHash2) { + if (key._hash2 != otherKey._hash2) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: expected Sphere shape hash2 = " << hash2 << " but found hash2 = " << otherHash2 << std::endl; + << " ERROR: expected Sphere shape hash2 = " << key._hash2 << " but found hash2 = " << otherKey._hash2 << std::endl; } delete shape; @@ -200,24 +198,21 @@ void ShapeInfoTests::testCylinderShape() { float radius = 1.23f; float height = 4.56f; info.setCylinder(radius, height); - int hash = info.computeHash(); - int hash2 = info.computeHash2(); + DoubleHashKey key = ShapeInfoUtil::computeHash(info); - btCollisionShape* shape = info.createShape(); + btCollisionShape* shape = ShapeInfoUtil::createShapeFromInfo(info); ShapeInfo otherInfo; - otherInfo.collectInfo(shape); + ShapeInfoUtil::collectInfoFromShape(shape, otherInfo); - int otherHash = otherInfo.computeHash(); - if (hash != otherHash) { + DoubleHashKey otherKey = ShapeInfoUtil::computeHash(otherInfo); + if (key._hash != otherKey._hash) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: expected Cylinder shape hash = " << hash << " but found hash = " << otherHash << std::endl; + << " ERROR: expected Cylinder shape hash = " << key._hash << " but found hash = " << otherKey._hash << std::endl; } - - int otherHash2 = otherInfo.computeHash2(); - if (hash2 != otherHash2) { + if (key._hash2 != otherKey._hash2) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: expected Cylinder shape hash2 = " << hash2 << " but found hash2 = " << otherHash2 << std::endl; + << " ERROR: expected Cylinder shape hash2 = " << key._hash2 << " but found hash2 = " << otherKey._hash2 << std::endl; } delete shape; @@ -230,24 +225,21 @@ void ShapeInfoTests::testCapsuleShape() { float radius = 1.23f; float height = 4.56f; info.setCapsule(radius, height); - int hash = info.computeHash(); - int hash2 = info.computeHash2(); + DoubleHashKey key = ShapeInfoUtil::computeHash(info); - btCollisionShape* shape = info.createShape(); + btCollisionShape* shape = ShapeInfoUtil::createShapeFromInfo(info); ShapeInfo otherInfo; - otherInfo.collectInfo(shape); + ShapeInfoUtil::collectInfoFromShape(shape, otherInfo); - int otherHash = otherInfo.computeHash(); - if (hash != otherHash) { + DoubleHashKey otherKey = ShapeInfoUtil::computeHash(otherInfo); + if (key._hash != otherKey._hash) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: expected Capsule shape hash = " << hash << " but found hash = " << otherHash << std::endl; + << " ERROR: expected Capsule shape hash = " << key._hash << " but found hash = " << otherKey._hash << std::endl; } - - int otherHash2 = otherInfo.computeHash2(); - if (hash2 != otherHash2) { + if (key._hash2 != otherKey._hash2) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: expected Capsule shape hash2 = " << hash2 << " but found hash2 = " << otherHash2 << std::endl; + << " ERROR: expected Capsule shape hash2 = " << key._hash2 << " but found hash2 = " << otherKey._hash2 << std::endl; } delete shape; diff --git a/tests/physics/src/ShapeManagerTests.cpp b/tests/physics/src/ShapeManagerTests.cpp index 3bfc8b1829..ba1b6ff388 100644 --- a/tests/physics/src/ShapeManagerTests.cpp +++ b/tests/physics/src/ShapeManagerTests.cpp @@ -20,7 +20,7 @@ void ShapeManagerTests::testShapeAccounting() { #ifdef USE_BULLET_PHYSICS ShapeManager shapeManager; ShapeInfo info; - info.setBox(btVector3(1.0f, 1.0f, 1.0f)); + info.setBox(glm::vec3(1.0f, 1.0f, 1.0f)); // NOTE: ShapeManager returns -1 as refcount when the shape is unknown, // which is distinct from "known but with zero references" @@ -132,7 +132,7 @@ void ShapeManagerTests::addManyShapes() { ShapeInfo info; for (int i = 0; i < numSizes; ++i) { float s = startSize + (float)i * deltaSize; - btVector3 scale(s, 1.23f + s, s - 0.573f); + glm::vec3 scale(s, 1.23f + s, s - 0.573f); info.setBox(0.5f * scale); btCollisionShape* shape = shapeManager.getShape(info); if (!shape) { @@ -157,14 +157,14 @@ void ShapeManagerTests::addManyShapes() { void ShapeManagerTests::addBoxShape() { #ifdef USE_BULLET_PHYSICS ShapeInfo info; - btVector3 halfExtents(1.23f, 4.56f, 7.89f); + glm::vec3 halfExtents(1.23f, 4.56f, 7.89f); info.setBox(halfExtents); ShapeManager shapeManager; btCollisionShape* shape = shapeManager.getShape(info); ShapeInfo otherInfo; - collectInfoFromShape(shape, otherInfo); + ShapeInfoUtil::collectInfoFromShape(shape, otherInfo); btCollisionShape* otherShape = shapeManager.getShape(otherInfo); if (shape != otherShape) { @@ -184,7 +184,7 @@ void ShapeManagerTests::addSphereShape() { btCollisionShape* shape = shapeManager.getShape(info); ShapeInfo otherInfo; - collectInfoFromShape(shape, otherInfo); + ShapeInfoUtil::collectInfoFromShape(shape, otherInfo); btCollisionShape* otherShape = shapeManager.getShape(otherInfo); if (shape != otherShape) { @@ -205,7 +205,7 @@ void ShapeManagerTests::addCylinderShape() { btCollisionShape* shape = shapeManager.getShape(info); ShapeInfo otherInfo; - collectInfoFromShape(shape, otherInfo); + ShapeInfoUtil::collectInfoFromShape(shape, otherInfo); btCollisionShape* otherShape = shapeManager.getShape(otherInfo); if (shape != otherShape) { @@ -226,7 +226,7 @@ void ShapeManagerTests::addCapsuleShape() { btCollisionShape* shape = shapeManager.getShape(info); ShapeInfo otherInfo; - collectInfoFromShape(shape, otherInfo); + ShapeInfoUtil::collectInfoFromShape(shape, otherInfo); btCollisionShape* otherShape = shapeManager.getShape(otherInfo); if (shape != otherShape) { From c9ea6885c12d4bd6bcd08722b83d65fa05810745 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 2 Dec 2014 15:29:41 -0800 Subject: [PATCH 052/105] PhysicsEngine is now an EntitySimulation --- interface/src/Application.cpp | 6 +- interface/src/Application.h | 2 +- interface/src/Physics.cpp | 43 -------- interface/src/Physics.h | 14 --- libraries/entities/src/EntityItem.h | 9 +- .../entities/src/SimpleEntitySimulation.cpp | 2 +- libraries/physics/src/EntityMotionState.h | 1 - libraries/physics/src/PhysicsEngine.cpp | 99 ++++++++++++++++++- libraries/physics/src/PhysicsEngine.h | 48 ++++++--- .../physics/src/ThreadSafeDynamicsWorld.cpp | 16 ++- .../physics/src/ThreadSafeDynamicsWorld.h | 13 +-- 11 files changed, 163 insertions(+), 90 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8abbf6314f..c7c5dcb3cd 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2021,8 +2021,10 @@ void Application::init() { connect(_myAvatar, &MyAvatar::transformChanged, this, &Application::updateMyAvatarTransform); #ifdef USE_BULLET_PHYSICS -// _physicsEngine.initSafe(_entities.getTree()); -// _entities.getTree()->setSimulation(&_physicsEngine); + EntityTree* tree = _entities.getTree(); + _physicsEngine.setEntityTree(tree); + tree->setSimulation(&_physicsEngine); + _physicsEngine.init(); #endif // USE_BULLET_PHYSICS } diff --git a/interface/src/Application.h b/interface/src/Application.h index ccc7059ef5..7ee82da725 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -504,7 +504,7 @@ private: ViewFrustum _sharedVoxelSystemViewFrustum; #ifdef USE_BULLET_PHYSICS - ThreadSafePhysicsEngine _physicsEngine; + PhysicsEngine _physicsEngine; #endif // USE_BULLET_PHYSICS EntityTreeRenderer _entities; diff --git a/interface/src/Physics.cpp b/interface/src/Physics.cpp index 1f8215f9dd..7efa520571 100644 --- a/interface/src/Physics.cpp +++ b/interface/src/Physics.cpp @@ -9,55 +9,12 @@ // #include - -#include #include -#include #include "Util.h" #include "world.h" #include "Physics.h" -// DynamicsImpl is an implementation of ThreadSafeDynamicsWorld that knows how to lock an EntityTree -class DynamicsImpl : public ThreadSafeDynamicsWorld { -public: - DynamicsImpl( - btDispatcher* dispatcher, - btBroadphaseInterface* pairCache, - btConstraintSolver* constraintSolver, - btCollisionConfiguration* collisionConfiguration, - EntityTree* entities) - : ThreadSafeDynamicsWorld(dispatcher, pairCache, constraintSolver, collisionConfiguration), _entities(entities) { - assert(entities); - } - - bool tryLock() { - // wait for lock - _entities->lockForRead(); - return true; - } - - void unlock() { - _entities->unlock(); - } -private: - EntityTree* _entities; -}; - -ThreadSafePhysicsEngine::ThreadSafePhysicsEngine(const glm::vec3& offset) : PhysicsEngine(offset) { -} - -void ThreadSafePhysicsEngine::initSafe(EntityTree* entities) { - assert(!_dynamicsWorld); // only call this once - assert(entities); - _collisionConfig = new btDefaultCollisionConfiguration(); - _collisionDispatcher = new btCollisionDispatcher(_collisionConfig); - _broadphaseFilter = new btDbvtBroadphase(); - _constraintSolver = new btSequentialImpulseConstraintSolver; - // ThreadSafePhysicsEngine gets a DynamicsImpl, which derives from ThreadSafeDynamicsWorld - _dynamicsWorld = new DynamicsImpl(_collisionDispatcher, _broadphaseFilter, _constraintSolver, _collisionConfig, entities); -} - // // Applies static friction: maxVelocity is the largest velocity for which there // there is friction, and strength is the amount of friction force applied to reduce diff --git a/interface/src/Physics.h b/interface/src/Physics.h index fd2881184a..97e873d920 100644 --- a/interface/src/Physics.h +++ b/interface/src/Physics.h @@ -12,20 +12,6 @@ #ifndef hifi_Physics_h #define hifi_Physics_h -#include - -class EntityTree; - -class ThreadSafePhysicsEngine : public PhysicsEngine { -public: - ThreadSafePhysicsEngine(const glm::vec3& offset); - - // virtual override from PhysicsEngine - void init() { assert(false); } // call initSafe() instead - - void initSafe(EntityTree* entities); -}; - void applyStaticFriction(float deltaTime, glm::vec3& velocity, float maxVelocity, float strength); void applyDamping(float deltaTime, glm::vec3& velocity, float linearStrength, float squaredStrength); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index d3225daa64..e865b4a3f5 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -35,8 +35,6 @@ class EntityTreeElementExtraEncodeData; #define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0; #define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() { }; -class EntityMotionState; - /// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available /// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate /// one directly, instead you must only construct one of it's derived classes with additional features. @@ -303,9 +301,10 @@ public: void clearUpdateFlags() { _updateFlags = 0; } void* getPhysicsInfo() const { return _physicsInfo; } + void setPhysicsInfo(void* data) { _physicsInfo = data; } SimulationState getSimulationState() const { return _simulationState; } - void setSimulationState(SimulationState state) { _simulationState = state; } + protected: virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init @@ -349,8 +348,8 @@ protected: void setRadius(float value); AACubeShape _collisionShape; - void* _physicsInfo; - SimulationState _simulationState; // only set by EntityTree + void* _physicsInfo; // only set by EntitySimulation + SimulationState _simulationState; // only set by EntitySimulation // UpdateFlags are set whenever a property changes that requires the change to be communicated to other // data structures. It is the responsibility of the EntityTree to relay changes entity and clear flags. diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index f91c80d67b..68093eb0de 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -154,9 +154,9 @@ void SimpleEntitySimulation::updateMortalEntities(quint64 now, QSet item_itr = _mortalEntities.erase(item_itr); entity->setSimulationState(EntityItem::Static); } else { - // check to see if this entity is no longer moving EntityItem::SimulationState newState = entity->computeSimulationState(); if (newState != EntityItem::Mortal) { + // check to see if this entity is moving if (newState == EntityItem::Moving) { entity->update(now); _movingEntities.push_back(entity); diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 793633e783..534ef1c135 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -17,7 +17,6 @@ #ifdef USE_BULLET_PHYSICS #include "CustomMotionState.h" #else // USE_BULLET_PHYSICS - // CustomMotionState stubbery class CustomMotionState { public: diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 6962355d5d..8e192e4279 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -12,19 +12,116 @@ #include "PhysicsEngine.h" #ifdef USE_BULLET_PHYSICS +#include "EntityMotionState.h" #include "ShapeInfoUtil.h" +#include "ThreadSafeDynamicsWorld.h" + +class EntityTree; + +PhysicsEngine::PhysicsEngine(const glm::vec3& offset) + : _collisionConfig(NULL), + _collisionDispatcher(NULL), + _broadphaseFilter(NULL), + _constraintSolver(NULL), + _dynamicsWorld(NULL), + _originOffset(offset), + _voxels() { +} PhysicsEngine::~PhysicsEngine() { } +/// \param tree pointer to EntityTree which is stored internally +void PhysicsEngine::setEntityTree(EntityTree* tree) { + assert(_entityTree == NULL); + assert(tree); + _entityTree = tree; +} + +/// \param[out] entitiesToDelete list of entities removed from simulation and should be deleted. +void PhysicsEngine::updateEntities(QSet& entitiesToDelete) { + // relay changes + QSet::iterator item_itr = _changedEntities.begin(); + while (item_itr != _changedEntities.end()) { + EntityItem* entity = *item_itr; + void* physicsInfo = entity->getPhysicsInfo(); + if (physicsInfo) { + CustomMotionState* motionState = static_cast(physicsInfo); + updateObject(motionState, entity->getUpdateFlags()); + } + entity->clearUpdateFlags(); + // TODO: implement this + ++item_itr; + } + + // hunt for entities who have expired + // TODO: make EntityItems use an expiry to make this work faster. + item_itr = _mortalEntities.begin(); + while (item_itr != _mortalEntities.end()) { + EntityItem* entity = *item_itr; + // always check to see if the lifetime has expired, for immortal entities this is always false + if (entity->lifetimeHasExpired()) { + qDebug() << "Lifetime has expired for entity:" << entity->getEntityItemID(); + entitiesToDelete.insert(entity); + // remove entity from the list + item_itr = _mortalEntities.erase(item_itr); + } else if (entity->isImmortal()) { + // remove entity from the list + item_itr = _mortalEntities.erase(item_itr); + } else { + ++item_itr; + } + } + // TODO: check for entities that have exited the world boundaries +} + +/// \param entity pointer to EntityItem to add to the simulation +/// \sideeffect the EntityItem::_simulationState member may be updated to indicate membership to internal list +void PhysicsEngine::addEntity(EntityItem* entity) { + assert(entity); + void* physicsInfo = entity->getPhysicsInfo(); + if (!physicsInfo) { + EntityMotionState* motionState = new EntityMotionState(entity); + entity->setPhysicsInfo(static_cast(motionState)); + if (entity->isMortal()) { + _mortalEntities.insert(entity); + } + } +} + +/// \param entity pointer to EntityItem to removed from the simulation +/// \sideeffect the EntityItem::_simulationState member may be updated to indicate non-membership to internal list +void PhysicsEngine::removeEntity(EntityItem* entity) { + assert(entity); + void* physicsInfo = entity->getPhysicsInfo(); + if (physicsInfo) { + CustomMotionState* motionState = static_cast(physicsInfo); + removeObject(motionState); + entity->setPhysicsInfo(NULL); + } + _mortalEntities.remove(entity); +} + +/// \param entity pointer to EntityItem to that may have changed in a way that would affect its simulation +void PhysicsEngine::entityChanged(EntityItem* entity) { + _changedEntities.insert(entity); +} + +void PhysicsEngine::clearEntities() { + // For now we assume this would only be called on shutdown in which case we can just let the memory get lost. +} + // virtual void PhysicsEngine::init() { + // _entityTree should be set prior to the init() call + assert(_entityTree); + if (!_dynamicsWorld) { _collisionConfig = new btDefaultCollisionConfiguration(); _collisionDispatcher = new btCollisionDispatcher(_collisionConfig); _broadphaseFilter = new btDbvtBroadphase(); _constraintSolver = new btSequentialImpulseConstraintSolver; - _dynamicsWorld = new btDiscreteDynamicsWorld(_collisionDispatcher, _broadphaseFilter, _constraintSolver, _collisionConfig); + _dynamicsWorld = new ThreadSafeDynamicsWorld(_collisionDispatcher, _broadphaseFilter, _constraintSolver, _collisionConfig, _entityTree); // default gravity of the world is zero, so each object must specify its own gravity // TODO: set up gravity zones diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index dfac1b17e8..4915475c83 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -32,31 +32,53 @@ const uint32_t PHYSICS_UPDATE_EASY = PHYSICS_UPDATE_POSITION | PHYSICS_UPDATE_VE #ifdef USE_BULLET_PHYSICS +#include #include +#include +#include + #include "BulletUtil.h" #include "CustomMotionState.h" #include "PositionHashKey.h" #include "ShapeManager.h" +#include "ThreadSafeDynamicsWorld.h" #include "VoxelObject.h" const float HALF_SIMULATION_EXTENT = 512.0f; // meters -class PhysicsEngine { +class PhysicsEngine : public EntitySimulation { public: - PhysicsEngine(const glm::vec3& offset) - : _collisionConfig(NULL), - _collisionDispatcher(NULL), - _broadphaseFilter(NULL), - _constraintSolver(NULL), - _dynamicsWorld(NULL), - _originOffset(offset), - _voxels() { - } + PhysicsEngine(const glm::vec3& offset); ~PhysicsEngine(); + // override from EntitySimulation + /// \param tree pointer to EntityTree which is stored internally + void setEntityTree(EntityTree* tree); + + // override from EntitySimulation + /// \param[out] entitiesToDelete list of entities removed from simulation and should be deleted. + void updateEntities(QSet& entitiesToDelete); + + // override from EntitySimulation + /// \param entity pointer to EntityItem to add to the simulation + /// \sideeffect the EntityItem::_simulationState member may be updated to indicate membership to internal list + void addEntity(EntityItem* entity); + + // override from EntitySimulation + /// \param entity pointer to EntityItem to removed from the simulation + /// \sideeffect the EntityItem::_simulationState member may be updated to indicate non-membership to internal list + void removeEntity(EntityItem* entity); + + // override from EntitySimulation + /// \param entity pointer to EntityItem to that may have changed in a way that would affect its simulation + void entityChanged(EntityItem* entity); + + // override from EntitySimulation + void clearEntities(); + virtual void init(); void stepSimulation(); @@ -99,12 +121,16 @@ protected: btCollisionDispatcher* _collisionDispatcher; btBroadphaseInterface* _broadphaseFilter; btSequentialImpulseConstraintSolver* _constraintSolver; - btDiscreteDynamicsWorld* _dynamicsWorld; + ThreadSafeDynamicsWorld* _dynamicsWorld; ShapeManager _shapeManager; private: glm::vec3 _originOffset; btHashMap _voxels; + + // EntitySimulation stuff + QSet _changedEntities; + QSet _mortalEntities; }; #else // USE_BULLET_PHYSICS diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp index 54bea0fff5..4660e02c2f 100644 --- a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp @@ -15,21 +15,25 @@ * Copied and modified from btDiscreteDynamicsWorld.cpp by AndrewMeadows on 2014.11.12. * */ +#include + #include "ThreadSafeDynamicsWorld.h" ThreadSafeDynamicsWorld::ThreadSafeDynamicsWorld( btDispatcher* dispatcher, btBroadphaseInterface* pairCache, btConstraintSolver* constraintSolver, - btCollisionConfiguration* collisionConfiguration) + btCollisionConfiguration* collisionConfiguration, + EntityTree* entities) : btDiscreteDynamicsWorld(dispatcher, pairCache, constraintSolver, collisionConfiguration) { + assert(entities); + _entities = entities; } void ThreadSafeDynamicsWorld::synchronizeMotionStates() { - if (tryLock()) { - btDiscreteDynamicsWorld::synchronizeMotionStates(); - unlock(); - } + _entities->lockForWrite(); + btDiscreteDynamicsWorld::synchronizeMotionStates(); + _entities->unlock(); } int ThreadSafeDynamicsWorld::stepSimulation( btScalar timeStep, int maxSubSteps, btScalar fixedTimeStep) { @@ -77,6 +81,8 @@ int ThreadSafeDynamicsWorld::stepSimulation( btScalar timeStep, int maxSubSteps, } } + // We only sync motion states once at the end of all substeps. + // This is to avoid placing multiple, repeated thread locks on _entities. synchronizeMotionStates(); clearForces(); return subSteps; diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.h b/libraries/physics/src/ThreadSafeDynamicsWorld.h index 0f7961044e..980ba7ae88 100644 --- a/libraries/physics/src/ThreadSafeDynamicsWorld.h +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.h @@ -20,6 +20,8 @@ #include +class EntityTree; + ATTRIBUTE_ALIGNED16(class) ThreadSafeDynamicsWorld : public btDiscreteDynamicsWorld { public: @@ -29,16 +31,15 @@ public: btDispatcher* dispatcher, btBroadphaseInterface* pairCache, btConstraintSolver* constraintSolver, - btCollisionConfiguration* collisionConfiguration); + btCollisionConfiguration* collisionConfiguration, + EntityTree* entities); - // virtual overrides of btDiscreteDynamicsWorld + // virtual overrides from btDiscreteDynamicsWorld int stepSimulation( btScalar timeStep, int maxSubSteps=1, btScalar fixedTimeStep=btScalar(1.)/btScalar(60.)); void synchronizeMotionStates(); - /// \return true if lock succeeds - virtual bool tryLock() = 0; - - virtual void unlock() = 0; +private: + EntityTree* _entities; }; #endif // hifi_ThreadSafeDynamicsWorld_h From 9f11121df2d8832608773157521b1fd2e141172d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 2 Dec 2014 15:44:07 -0800 Subject: [PATCH 053/105] oops, forgot to add entities to Bullet simulation --- libraries/physics/src/PhysicsEngine.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 8e192e4279..80eb43a0cf 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -50,7 +50,6 @@ void PhysicsEngine::updateEntities(QSet& entitiesToDelete) { updateObject(motionState, entity->getUpdateFlags()); } entity->clearUpdateFlags(); - // TODO: implement this ++item_itr; } @@ -81,11 +80,16 @@ void PhysicsEngine::addEntity(EntityItem* entity) { assert(entity); void* physicsInfo = entity->getPhysicsInfo(); if (!physicsInfo) { - EntityMotionState* motionState = new EntityMotionState(entity); - entity->setPhysicsInfo(static_cast(motionState)); if (entity->isMortal()) { _mortalEntities.insert(entity); } + EntityMotionState* motionState = new EntityMotionState(entity); + if (addObject(motionState)) { + entity->setPhysicsInfo(static_cast(motionState)); + } else { + // We failed to add the object to the simulation. Probably because we couldn't create a shape for it. + delete motionState; + } } } From 182cebbe40820ed4dbcf3b8fc2c0c4595a2599a9 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 2 Dec 2014 17:47:00 -0800 Subject: [PATCH 054/105] Fix order of shape types for ShapeCollider --- libraries/shared/src/Shape.h | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/libraries/shared/src/Shape.h b/libraries/shared/src/Shape.h index 6e7fe88347..2cc309e1fa 100644 --- a/libraries/shared/src/Shape.h +++ b/libraries/shared/src/Shape.h @@ -25,15 +25,19 @@ class VerletPoint; const float MAX_SHAPE_MASS = 1.0e18f; // something less than sqrt(FLT_MAX) -const quint8 UNKNOWN_SHAPE = 0; -const quint8 INVALID_SHAPE = 0; -const quint8 SPHERE_SHAPE = 1; -const quint8 CAPSULE_SHAPE = 2; -const quint8 PLANE_SHAPE = 3; -const quint8 BOX_SHAPE = 4; -const quint8 AACUBE_SHAPE = 5; -const quint8 CYLINDER_SHAPE = 6; -const quint8 LIST_SHAPE = 7; +// DANGER: until ShapeCollider goes away the order of these values matter. Specifically, +// UNKNOWN_SHAPE must be equal to the number of shapes that ShapeCollider actually supports. +const quint8 SPHERE_SHAPE = 0; +const quint8 CAPSULE_SHAPE = 1; +const quint8 PLANE_SHAPE = 2; +const quint8 AACUBE_SHAPE = 3; +const quint8 LIST_SHAPE = 4; +const quint8 UNKNOWN_SHAPE = 5; +const quint8 INVALID_SHAPE = 5; + +// new shapes to be supported by Bullet +const quint8 BOX_SHAPE = 7; +const quint8 CYLINDER_SHAPE = 8; class Shape { public: From 6e88ab15f9ea01ac99f3bcb6e8c362dc8333f9b4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 2 Dec 2014 17:47:33 -0800 Subject: [PATCH 055/105] remove debug #include --- libraries/shared/src/ShapeInfo.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index 38ff2301ad..9e733e7b6e 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -12,7 +12,6 @@ #include #include "SharedUtil.h" // for MILLIMETERS_PER_METER -#include "StreamUtils.h" // adebug //#include "DoubleHashKey.h" #include "ShapeInfo.h" From 29d0d1010329bd80cd90c5294e94cda38ee5d9cc Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 2 Dec 2014 17:47:48 -0800 Subject: [PATCH 056/105] track entities added to PhysicsEngine also fix for RigidBody's not going dynamic and a fix for changed entities staying on changed list --- libraries/physics/src/PhysicsEngine.cpp | 19 +++++++++++++++++-- libraries/physics/src/PhysicsEngine.h | 1 + 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 80eb43a0cf..56740b5e57 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -52,6 +52,7 @@ void PhysicsEngine::updateEntities(QSet& entitiesToDelete) { entity->clearUpdateFlags(); ++item_itr; } + _changedEntities.clear(); // hunt for entities who have expired // TODO: make EntityItems use an expiry to make this work faster. @@ -64,6 +65,7 @@ void PhysicsEngine::updateEntities(QSet& entitiesToDelete) { entitiesToDelete.insert(entity); // remove entity from the list item_itr = _mortalEntities.erase(item_itr); + _entities.remove(entity); } else if (entity->isImmortal()) { // remove entity from the list item_itr = _mortalEntities.erase(item_itr); @@ -80,6 +82,8 @@ void PhysicsEngine::addEntity(EntityItem* entity) { assert(entity); void* physicsInfo = entity->getPhysicsInfo(); if (!physicsInfo) { + assert(!_entities.contains(entity)); + _entities.insert(entity); if (entity->isMortal()) { _mortalEntities.insert(entity); } @@ -103,6 +107,7 @@ void PhysicsEngine::removeEntity(EntityItem* entity) { removeObject(motionState); entity->setPhysicsInfo(NULL); } + _entities.remove(entity); _mortalEntities.remove(entity); } @@ -113,6 +118,17 @@ void PhysicsEngine::entityChanged(EntityItem* entity) { void PhysicsEngine::clearEntities() { // For now we assume this would only be called on shutdown in which case we can just let the memory get lost. + QSet::const_iterator entityItr = _entities.begin(); + for (entityItr = _entities.begin(); entityItr != _entities.end(); ++entityItr) { + void* physicsInfo = (*entityItr)->getPhysicsInfo(); + if (physicsInfo) { + CustomMotionState* motionState = static_cast(physicsInfo); + removeObject(motionState); + } + } + _entities.clear(); + _changedEntities.clear(); + _mortalEntities.clear(); } // virtual @@ -356,8 +372,7 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, CustomMotionState* motio body->setMassProps(mass, inertia); body->updateInertiaTensor(); } - bool forceActivation = true; - body->activate(forceActivation); + body->forceActivationState(ACTIVE_TAG); break; } default: { diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 4915475c83..fdf42f5209 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -129,6 +129,7 @@ private: btHashMap _voxels; // EntitySimulation stuff + QSet _entities; QSet _changedEntities; QSet _mortalEntities; }; From 64cdef42fe3f41998411c8314fbec44bee4c5806 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 3 Dec 2014 07:23:14 -0800 Subject: [PATCH 057/105] simplified API of PositionHashKey --- libraries/physics/src/PositionHashKey.cpp | 8 ++++---- libraries/physics/src/PositionHashKey.h | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/libraries/physics/src/PositionHashKey.cpp b/libraries/physics/src/PositionHashKey.cpp index e03391c72c..91f8261fba 100644 --- a/libraries/physics/src/PositionHashKey.cpp +++ b/libraries/physics/src/PositionHashKey.cpp @@ -14,7 +14,7 @@ #include "PositionHashKey.h" // static -int PositionHashKey::computeHash(const glm::vec3& center) { +int computeHash(const glm::vec3& center) { // NOTE: 0.49f is used to bump the float up almost half a millimeter // so the cast to int produces a round() effect rather than a floor() int hash = DoubleHashKey::hashFunction((int)(center.x * MILLIMETERS_PER_METER + copysignf(1.0f, center.x) * 0.49f), 0); @@ -23,7 +23,7 @@ int PositionHashKey::computeHash(const glm::vec3& center) { } // static -int PositionHashKey::computeHash2(const glm::vec3& center) { +int computeHash2(const glm::vec3& center) { // NOTE: 0.49f is used to bump the float up almost half a millimeter // so the cast to int produces a round() effect rather than a floor() int hash = DoubleHashKey::hashFunction2((int)(center.x * MILLIMETERS_PER_METER + copysignf(1.0f, center.x) * 0.49f)); @@ -32,6 +32,6 @@ int PositionHashKey::computeHash2(const glm::vec3& center) { } PositionHashKey::PositionHashKey(glm::vec3 center) : DoubleHashKey() { - _hash = PositionHashKey::computeHash(center); - _hash2 = PositionHashKey::computeHash2(center); + _hash = computeHash(center); + _hash2 = computeHash2(center); } diff --git a/libraries/physics/src/PositionHashKey.h b/libraries/physics/src/PositionHashKey.h index bb2f277051..1065034fa8 100644 --- a/libraries/physics/src/PositionHashKey.h +++ b/libraries/physics/src/PositionHashKey.h @@ -20,8 +20,6 @@ class PositionHashKey : public DoubleHashKey { public: - static int computeHash(const glm::vec3& center); - static int computeHash2(const glm::vec3& center); PositionHashKey(glm::vec3 center); }; From 8d49b694cc146e2e8fb4e5e300825486dc1a2b20 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 3 Dec 2014 10:08:26 -0800 Subject: [PATCH 058/105] ShapeManager doesn't support tiny and giant shapes --- libraries/physics/src/ShapeInfoUtil.cpp | 88 ++++++++++--------------- libraries/physics/src/ShapeManager.cpp | 28 +++++--- libraries/shared/src/ShapeInfo.cpp | 27 ++++++-- libraries/shared/src/ShapeInfo.h | 12 +++- 4 files changed, 86 insertions(+), 69 deletions(-) diff --git a/libraries/physics/src/ShapeInfoUtil.cpp b/libraries/physics/src/ShapeInfoUtil.cpp index e4ea118a0b..3d8e0b77a8 100644 --- a/libraries/physics/src/ShapeInfoUtil.cpp +++ b/libraries/physics/src/ShapeInfoUtil.cpp @@ -57,87 +57,70 @@ int ShapeInfoUtil::fromBulletShapeType(int bulletShapeType) { } void ShapeInfoUtil::collectInfoFromShape(const btCollisionShape* shape, ShapeInfo& info) { - info._data.clear(); if (shape) { - info._type = ShapeInfoUtil::fromBulletShapeType(shape->getShapeType()); - switch(info._type) { - case BOX_SHAPE: - { + int type = ShapeInfoUtil::fromBulletShapeType(shape->getShapeType()); + switch(type) { + case BOX_SHAPE: { const btBoxShape* boxShape = static_cast(shape); glm::vec3 halfExtents; bulletToGLM(boxShape->getHalfExtentsWithMargin(), halfExtents); - info._data.push_back(halfExtents); + info.setBox(halfExtents); } break; - case SPHERE_SHAPE: - { + case SPHERE_SHAPE: { const btSphereShape* sphereShape = static_cast(shape); - glm::vec3 data; - bulletToGLM(btVector3(0.0f, 0.0f, sphereShape->getRadius()), data); - info._data.push_back(data); + info.setSphere(sphereShape->getRadius()); } break; - case CYLINDER_SHAPE: - { + case CYLINDER_SHAPE: { + // NOTE: we only support cylinders along yAxis const btCylinderShape* cylinderShape = static_cast(shape); - glm::vec3 halfExtents; - bulletToGLM(cylinderShape->getHalfExtentsWithMargin(), halfExtents); - info._data.push_back(halfExtents); + btVector3 halfExtents = cylinderShape->getHalfExtentsWithMargin(); + info.setCylinder(halfExtents.getX(), halfExtents.getY()); } break; - case CAPSULE_SHAPE: - { + case CAPSULE_SHAPE: { + // NOTE: we only support capsules along yAxis const btCapsuleShape* capsuleShape = static_cast(shape); - glm::vec3 data; - bulletToGLM(btVector3(capsuleShape->getRadius(), capsuleShape->getHalfHeight(), 0.0f), data); - info._data.push_back(data); - // NOTE: we only support capsules with axis along yAxis + info.setCapsule(capsuleShape->getRadius(), capsuleShape->getHalfHeight()); } break; default: - info._type = INVALID_SHAPE; + info.clear(); break; } } else { - info._type = INVALID_SHAPE; + info.clear(); } } btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) { btCollisionShape* shape = NULL; - int numData = info._data.size(); - switch(info._type) { + const QVector& data = info.getData(); + switch(info.getType()) { case BOX_SHAPE: { - if (numData > 0) { - btVector3 halfExtents; - glmToBullet(info._data[0], halfExtents); - shape = new btBoxShape(halfExtents); - } + btVector3 halfExtents; + glmToBullet(data[0], halfExtents); + shape = new btBoxShape(halfExtents); } break; case SPHERE_SHAPE: { - if (numData > 0) { - float radius = info._data[0].z; - shape = new btSphereShape(radius); - } + float radius = data[0].z; + shape = new btSphereShape(radius); } break; case CYLINDER_SHAPE: { - if (numData > 0) { - btVector3 halfExtents; - glmToBullet(info._data[0], halfExtents); - // NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X - // halfExtents = btVector3(radius, halfHeight, unused) - shape = new btCylinderShape(halfExtents); - } + btVector3 halfExtents; + glmToBullet(data[0], halfExtents); + // NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X + // halfExtents = btVector3(radius, halfHeight, unused) + shape = new btCylinderShape(halfExtents); } break; case CAPSULE_SHAPE: { - if (numData > 0) { - float radius = info._data[0].x; - float height = 2.0f * info._data[0].y; - shape = new btCapsuleShape(radius, height); - } + float radius = data[0].x; + float height = 2.0f * data[0].y; + shape = new btCapsuleShape(radius, height); } break; } @@ -150,12 +133,13 @@ DoubleHashKey ShapeInfoUtil::computeHash(const ShapeInfo& info) { // scramble the bits of the type // TODO?: provide lookup table for hash of info._type rather than recompute? int primeIndex = 0; - unsigned int hash = DoubleHashKey::hashFunction((unsigned int)info._type, primeIndex++); + unsigned int hash = DoubleHashKey::hashFunction((unsigned int)info.getType(), primeIndex++); + const QVector& data = info.getData(); glm::vec3 tmpData; - int numData = info._data.size(); + int numData = data.size(); for (int i = 0; i < numData; ++i) { - tmpData = info._data[i]; + tmpData = data[i]; for (int j = 0; j < 3; ++j) { // NOTE: 0.49f is used to bump the float up almost half a millimeter // so the cast to int produces a round() effect rather than a floor() @@ -169,10 +153,10 @@ DoubleHashKey ShapeInfoUtil::computeHash(const ShapeInfo& info) { // compute hash2 // scramble the bits of the type // TODO?: provide lookup table for hash2 of info._type rather than recompute? - hash = DoubleHashKey::hashFunction2((unsigned int)info._type); + hash = DoubleHashKey::hashFunction2((unsigned int)info.getType()); for (int i = 0; i < numData; ++i) { - tmpData = info._data[i]; + tmpData = data[i]; for (int j = 0; j < 3; ++j) { // NOTE: 0.49f is used to bump the float up almost half a millimeter // so the cast to int produces a round() effect rather than a floor() diff --git a/libraries/physics/src/ShapeManager.cpp b/libraries/physics/src/ShapeManager.cpp index 670fcf54ae..1da705a5ff 100644 --- a/libraries/physics/src/ShapeManager.cpp +++ b/libraries/physics/src/ShapeManager.cpp @@ -10,6 +10,9 @@ // #ifdef USE_BULLET_PHYSICS + +#include + #include "ShapeInfoUtil.h" #include "ShapeManager.h" @@ -25,23 +28,28 @@ ShapeManager::~ShapeManager() { _shapeMap.clear(); } - btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { + // Very small or large objects are not supported. + float diagonal = glm::length2(info.getBoundingBoxDiagonal()); + const float MIN_SHAPE_DIAGONAL_SQUARED = 3.0e-4f; // 1 cm cube + const float MAX_SHAPE_DIAGONAL_SQUARED = 3.0e4f; // 100 m cube + if (diagonal < MIN_SHAPE_DIAGONAL_SQUARED || diagonal > MAX_SHAPE_DIAGONAL_SQUARED) { + return NULL; + } DoubleHashKey key = ShapeInfoUtil::computeHash(info); ShapeReference* shapeRef = _shapeMap.find(key); if (shapeRef) { shapeRef->_refCount++; return shapeRef->_shape; - } else { - btCollisionShape* shape = ShapeInfoUtil::createShapeFromInfo(info); - if (shape) { - ShapeReference newRef; - newRef._refCount = 1; - newRef._shape = shape; - _shapeMap.insert(key, newRef); - } - return shape; } + btCollisionShape* shape = ShapeInfoUtil::createShapeFromInfo(info); + if (shape) { + ShapeReference newRef; + newRef._refCount = 1; + newRef._shape = shape; + _shapeMap.insert(key, newRef); + } + return shape; } bool ShapeManager::releaseShape(const ShapeInfo& info) { diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index 9e733e7b6e..d402a048a0 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -16,6 +16,11 @@ //#include "DoubleHashKey.h" #include "ShapeInfo.h" +void ShapeInfo::clear() { + _type = INVALID_SHAPE; + _data.clear(); +} + void ShapeInfo::setBox(const glm::vec3& halfExtents) { _type = BOX_SHAPE; _data.clear(); @@ -25,19 +30,31 @@ void ShapeInfo::setBox(const glm::vec3& halfExtents) { void ShapeInfo::setSphere(float radius) { _type = SPHERE_SHAPE; _data.clear(); - _data.push_back(glm::vec3(0.0f, 0.0f, radius)); + _data.push_back(glm::vec3(radius)); } -void ShapeInfo::setCylinder(float radius, float height) { +void ShapeInfo::setCylinder(float radius, float halfHeight) { _type = CYLINDER_SHAPE; _data.clear(); // NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X - _data.push_back(glm::vec3(radius, 0.5f * height, radius)); + _data.push_back(glm::vec3(radius, halfHeight, radius)); } -void ShapeInfo::setCapsule(float radius, float height) { +void ShapeInfo::setCapsule(float radius, float halfHeight) { _type = CAPSULE_SHAPE; _data.clear(); - _data.push_back(glm::vec3(radius, 0.5f * height, 0.0f)); + _data.push_back(glm::vec3(radius, halfHeight, radius)); } +glm::vec3 ShapeInfo::getBoundingBoxDiagonal() const { + switch(_type) { + case BOX_SHAPE: + case SPHERE_SHAPE: + case CYLINDER_SHAPE: + case CAPSULE_SHAPE: + return 2.0f * _data[0]; + default: + break; + } + return glm::vec3(0.0f); +} diff --git a/libraries/shared/src/ShapeInfo.h b/libraries/shared/src/ShapeInfo.h index ec5352e3da..7ba290122c 100644 --- a/libraries/shared/src/ShapeInfo.h +++ b/libraries/shared/src/ShapeInfo.h @@ -21,11 +21,19 @@ class ShapeInfo { public: ShapeInfo() : _type(INVALID_SHAPE) {} + void clear(); + void setBox(const glm::vec3& halfExtents); void setSphere(float radius); - void setCylinder(float radius, float height); - void setCapsule(float radius, float height); + void setCylinder(float radius, float halfHeight); + void setCapsule(float radius, float halfHeight); + const int getType() const { return _type; } + const QVector& getData() const { return _data; } + + glm::vec3 getBoundingBoxDiagonal() const; + +protected: int _type; QVector _data; }; From 3c67400e13d9d399604257c7678b422155248c55 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 3 Dec 2014 11:12:04 -0800 Subject: [PATCH 059/105] namechange CustomMotionState to ObjectMotionState --- libraries/physics/src/EntityMotionState.h | 8 +++--- ...mMotionState.cpp => ObjectMotionState.cpp} | 26 +++++++++---------- ...ustomMotionState.h => ObjectMotionState.h} | 14 +++++----- libraries/physics/src/PhysicsEngine.cpp | 16 ++++++------ libraries/physics/src/PhysicsEngine.h | 12 ++++----- 5 files changed, 38 insertions(+), 38 deletions(-) rename libraries/physics/src/{CustomMotionState.cpp => ObjectMotionState.cpp} (72%) rename libraries/physics/src/{CustomMotionState.h => ObjectMotionState.h} (88%) diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 534ef1c135..91186c823c 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -15,10 +15,10 @@ #include #ifdef USE_BULLET_PHYSICS -#include "CustomMotionState.h" +#include "ObjectMotionState.h" #else // USE_BULLET_PHYSICS -// CustomMotionState stubbery -class CustomMotionState { +// ObjectMotionState stubbery +class ObjectMotionState { public: bool _foo; }; @@ -26,7 +26,7 @@ public: class EntityItem; -class EntityMotionState : public CustomMotionState { +class EntityMotionState : public ObjectMotionState { public: static void setWorldOffset(const glm::vec3& offset); static const glm::vec3& getWorldOffset(); diff --git a/libraries/physics/src/CustomMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp similarity index 72% rename from libraries/physics/src/CustomMotionState.cpp rename to libraries/physics/src/ObjectMotionState.cpp index 20bd1aac69..9a57db3dae 100644 --- a/libraries/physics/src/CustomMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -1,5 +1,5 @@ // -// CustomMotionState.cpp +// ObjectMotionState.cpp // libraries/physcis/src // // Created by Andrew Meadows 2014.11.05 @@ -14,7 +14,7 @@ #include #include "BulletUtil.h" -#include "CustomMotionState.h" +#include "ObjectMotionState.h" const float MIN_DENSITY = 200.0f; const float DEFAULT_DENSITY = 1000.0f; @@ -29,7 +29,7 @@ const float MAX_FRICTION = 10.0f; const float DEFAULT_RESTITUTION = 0.0f; -CustomMotionState::CustomMotionState() : +ObjectMotionState::ObjectMotionState() : _density(DEFAULT_DENSITY), _volume(DEFAULT_VOLUME), _friction(DEFAULT_FRICTION), @@ -39,50 +39,50 @@ CustomMotionState::CustomMotionState() : _body(NULL) { } -CustomMotionState::~CustomMotionState() { +ObjectMotionState::~ObjectMotionState() { // NOTE: you MUST remove this MotionState from the world before you call the dtor. assert(_body == NULL); } -void CustomMotionState::setDensity(float density) { +void ObjectMotionState::setDensity(float density) { _density = btMax(btMin(fabsf(density), MAX_DENSITY), MIN_DENSITY); } -void CustomMotionState::setFriction(float friction) { +void ObjectMotionState::setFriction(float friction) { _friction = btMax(btMin(fabsf(friction), MAX_FRICTION), 0.0f); } -void CustomMotionState::setRestitution(float restitution) { +void ObjectMotionState::setRestitution(float restitution) { _restitution = btMax(btMin(fabsf(restitution), 1.0f), 0.0f); } -void CustomMotionState::setVolume(float volume) { +void ObjectMotionState::setVolume(float volume) { _volume = btMax(btMin(fabsf(volume), MAX_VOLUME), MIN_VOLUME); } -void CustomMotionState::setVelocity(const glm::vec3& velocity) const { +void ObjectMotionState::setVelocity(const glm::vec3& velocity) const { btVector3 v; glmToBullet(velocity, v); _body->setLinearVelocity(v); } -void CustomMotionState::setAngularVelocity(const glm::vec3& velocity) const { +void ObjectMotionState::setAngularVelocity(const glm::vec3& velocity) const { btVector3 v; glmToBullet(velocity, v); _body->setAngularVelocity(v); } -void CustomMotionState::setGravity(const glm::vec3& gravity) const { +void ObjectMotionState::setGravity(const glm::vec3& gravity) const { btVector3 g; glmToBullet(gravity, g); _body->setGravity(g); } -void CustomMotionState::getVelocity(glm::vec3& velocityOut) const { +void ObjectMotionState::getVelocity(glm::vec3& velocityOut) const { bulletToGLM(_body->getLinearVelocity(), velocityOut); } -void CustomMotionState::getAngularVelocity(glm::vec3& angularVelocityOut) const { +void ObjectMotionState::getAngularVelocity(glm::vec3& angularVelocityOut) const { bulletToGLM(_body->getAngularVelocity(), angularVelocityOut); } diff --git a/libraries/physics/src/CustomMotionState.h b/libraries/physics/src/ObjectMotionState.h similarity index 88% rename from libraries/physics/src/CustomMotionState.h rename to libraries/physics/src/ObjectMotionState.h index d78aa66dfd..10e001f7c4 100644 --- a/libraries/physics/src/CustomMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -1,5 +1,5 @@ // -// CustomMotionState.h +// ObjectMotionState.h // libraries/physcis/src // // Created by Andrew Meadows 2014.11.05 @@ -9,8 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_CustomMotionState_h -#define hifi_CustomMotionState_h +#ifndef hifi_ObjectMotionState_h +#define hifi_ObjectMotionState_h #ifdef USE_BULLET_PHYSICS @@ -25,10 +25,10 @@ enum MotionType { MOTION_TYPE_KINEMATIC // keyframed motion }; -class CustomMotionState : public btMotionState { +class ObjectMotionState : public btMotionState { public: - CustomMotionState(); - ~CustomMotionState(); + ObjectMotionState(); + ~ObjectMotionState(); //// these override methods of the btMotionState base class //virtual void getWorldTransform (btTransform &worldTrans) const; @@ -70,4 +70,4 @@ protected: }; #endif // USE_BULLET_PHYSICS -#endif // hifi_CustomMotionState_h +#endif // hifi_ObjectMotionState_h diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 56740b5e57..a6013111b8 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -46,7 +46,7 @@ void PhysicsEngine::updateEntities(QSet& entitiesToDelete) { EntityItem* entity = *item_itr; void* physicsInfo = entity->getPhysicsInfo(); if (physicsInfo) { - CustomMotionState* motionState = static_cast(physicsInfo); + ObjectMotionState* motionState = static_cast(physicsInfo); updateObject(motionState, entity->getUpdateFlags()); } entity->clearUpdateFlags(); @@ -103,7 +103,7 @@ void PhysicsEngine::removeEntity(EntityItem* entity) { assert(entity); void* physicsInfo = entity->getPhysicsInfo(); if (physicsInfo) { - CustomMotionState* motionState = static_cast(physicsInfo); + ObjectMotionState* motionState = static_cast(physicsInfo); removeObject(motionState); entity->setPhysicsInfo(NULL); } @@ -122,7 +122,7 @@ void PhysicsEngine::clearEntities() { for (entityItr = _entities.begin(); entityItr != _entities.end(); ++entityItr) { void* physicsInfo = (*entityItr)->getPhysicsInfo(); if (physicsInfo) { - CustomMotionState* motionState = static_cast(physicsInfo); + ObjectMotionState* motionState = static_cast(physicsInfo); removeObject(motionState); } } @@ -242,7 +242,7 @@ bool PhysicsEngine::removeVoxel(const glm::vec3& position, float scale) { // CF_DISABLE_VISUALIZE_OBJECT = 32, //disable debug drawing // CF_DISABLE_SPU_COLLISION_PROCESSING = 64//disable parallel/SPU processing -bool PhysicsEngine::addObject(CustomMotionState* motionState) { +bool PhysicsEngine::addObject(ObjectMotionState* motionState) { assert(motionState); ShapeInfo info; motionState->computeShapeInfo(info); @@ -289,7 +289,7 @@ bool PhysicsEngine::addObject(CustomMotionState* motionState) { return false; } -bool PhysicsEngine::removeObject(CustomMotionState* motionState) { +bool PhysicsEngine::removeObject(ObjectMotionState* motionState) { assert(motionState); btRigidBody* body = motionState->_body; if (body) { @@ -305,7 +305,7 @@ bool PhysicsEngine::removeObject(CustomMotionState* motionState) { return false; } -bool PhysicsEngine::updateObject(CustomMotionState* motionState, uint32_t flags) { +bool PhysicsEngine::updateObject(ObjectMotionState* motionState, uint32_t flags) { btRigidBody* body = motionState->_body; if (!body) { return false; @@ -322,7 +322,7 @@ bool PhysicsEngine::updateObject(CustomMotionState* motionState, uint32_t flags) } // private -void PhysicsEngine::updateObjectHard(btRigidBody* body, CustomMotionState* motionState, uint32_t flags) { +void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags) { MotionType newType = motionState->getMotionType(); // pull body out of physics engine @@ -398,7 +398,7 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, CustomMotionState* motio } // private -void PhysicsEngine::updateObjectEasy(btRigidBody* body, CustomMotionState* motionState, uint32_t flags) { +void PhysicsEngine::updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags) { if (flags & PHYSICS_UPDATE_POSITION) { btTransform transform; motionState->getWorldTransform(transform); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index fdf42f5209..2656a3f8cf 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -39,7 +39,7 @@ const uint32_t PHYSICS_UPDATE_EASY = PHYSICS_UPDATE_POSITION | PHYSICS_UPDATE_VE #include #include "BulletUtil.h" -#include "CustomMotionState.h" +#include "ObjectMotionState.h" #include "PositionHashKey.h" #include "ShapeManager.h" #include "ThreadSafeDynamicsWorld.h" @@ -101,20 +101,20 @@ public: /// \param motionState pointer to Object's MotionState /// \return true if Object added - bool addObject(CustomMotionState* motionState); + bool addObject(ObjectMotionState* motionState); /// \param motionState pointer to Object's MotionState /// \return true if Object removed - bool removeObject(CustomMotionState* motionState); + bool removeObject(ObjectMotionState* motionState); /// \param motionState pointer to Object's MotionState /// \param flags set of bits indicating what categories of properties need to be updated /// \return true if entity updated - bool updateObject(CustomMotionState* motionState, uint32_t flags); + bool updateObject(ObjectMotionState* motionState, uint32_t flags); protected: - void updateObjectHard(btRigidBody* body, CustomMotionState* motionState, uint32_t flags); - void updateObjectEasy(btRigidBody* body, CustomMotionState* motionState, uint32_t flags); + void updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); + void updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); btClock _clock; btDefaultCollisionConfiguration* _collisionConfig; From fb7a5e64cf480f0b25effbc5eaf2d2f2cc11ec61 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 3 Dec 2014 11:15:44 -0800 Subject: [PATCH 060/105] fix file path in header text: physcis --> shared --- libraries/shared/src/AACubeShape.cpp | 2 +- libraries/shared/src/AACubeShape.h | 2 +- libraries/shared/src/CapsuleShape.cpp | 2 +- libraries/shared/src/CapsuleShape.h | 2 +- libraries/shared/src/CollisionInfo.cpp | 2 +- libraries/shared/src/CollisionInfo.h | 2 +- libraries/shared/src/ListShape.cpp | 2 +- libraries/shared/src/ListShape.h | 2 +- libraries/shared/src/PlaneShape.cpp | 2 +- libraries/shared/src/PlaneShape.h | 2 +- libraries/shared/src/Shape.h | 2 +- libraries/shared/src/ShapeCollider.cpp | 2 +- libraries/shared/src/ShapeCollider.h | 2 +- libraries/shared/src/SphereShape.cpp | 2 +- libraries/shared/src/SphereShape.h | 2 +- 15 files changed, 15 insertions(+), 15 deletions(-) diff --git a/libraries/shared/src/AACubeShape.cpp b/libraries/shared/src/AACubeShape.cpp index d713485c65..30197d6bfd 100644 --- a/libraries/shared/src/AACubeShape.cpp +++ b/libraries/shared/src/AACubeShape.cpp @@ -1,6 +1,6 @@ // // AACubeShape.cpp -// libraries/physics/src +// libraries/shared/src // // Created by Andrew Meadows on 2014.08.22 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/shared/src/AACubeShape.h b/libraries/shared/src/AACubeShape.h index 914ec88812..da7ba9d53f 100644 --- a/libraries/shared/src/AACubeShape.h +++ b/libraries/shared/src/AACubeShape.h @@ -1,6 +1,6 @@ // // AACubeShape.h -// libraries/physics/src +// libraries/shared/src // // Created by Andrew Meadows on 2014.08.22 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/shared/src/CapsuleShape.cpp b/libraries/shared/src/CapsuleShape.cpp index 242f3160ce..24ac6634ea 100644 --- a/libraries/shared/src/CapsuleShape.cpp +++ b/libraries/shared/src/CapsuleShape.cpp @@ -1,6 +1,6 @@ // // CapsuleShape.cpp -// libraries/physics/src +// libraries/shared/src // // Created by Andrew Meadows on 02/20/2014. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/shared/src/CapsuleShape.h b/libraries/shared/src/CapsuleShape.h index b91bf9f1ec..ad3066bab7 100644 --- a/libraries/shared/src/CapsuleShape.h +++ b/libraries/shared/src/CapsuleShape.h @@ -1,6 +1,6 @@ // // CapsuleShape.h -// libraries/physics/src +// libraries/shared/src // // Created by Andrew Meadows on 02/20/2014. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/shared/src/CollisionInfo.cpp b/libraries/shared/src/CollisionInfo.cpp index b168b038f6..1403e444cf 100644 --- a/libraries/shared/src/CollisionInfo.cpp +++ b/libraries/shared/src/CollisionInfo.cpp @@ -1,6 +1,6 @@ // // CollisionInfo.cpp -// libraries/physics/src +// libraries/shared/src // // Created by Andrew Meadows on 02/14/2014. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/shared/src/CollisionInfo.h b/libraries/shared/src/CollisionInfo.h index 191e4e90d4..e6daf949b3 100644 --- a/libraries/shared/src/CollisionInfo.h +++ b/libraries/shared/src/CollisionInfo.h @@ -1,6 +1,6 @@ // // CollisionInfo.h -// libraries/physics/src +// libraries/shared/src // // Created by Andrew Meadows on 02/14/2014. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/shared/src/ListShape.cpp b/libraries/shared/src/ListShape.cpp index 319c3a1287..255330c713 100644 --- a/libraries/shared/src/ListShape.cpp +++ b/libraries/shared/src/ListShape.cpp @@ -1,6 +1,6 @@ // // ListShape.cpp -// libraries/physics/src +// libraries/shared/src // // Created by Andrew Meadows on 02/20/2014. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/shared/src/ListShape.h b/libraries/shared/src/ListShape.h index 0c1d2ddbb0..6352ef3f07 100644 --- a/libraries/shared/src/ListShape.h +++ b/libraries/shared/src/ListShape.h @@ -1,6 +1,6 @@ // // ListShape.h -// libraries/physics/src +// libraries/shared/src // // Created by Andrew Meadows on 02/20/2014. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/shared/src/PlaneShape.cpp b/libraries/shared/src/PlaneShape.cpp index 012c418580..a247641122 100644 --- a/libraries/shared/src/PlaneShape.cpp +++ b/libraries/shared/src/PlaneShape.cpp @@ -1,6 +1,6 @@ // // PlaneShape.cpp -// libraries/physics/src +// libraries/shared/src // // Created by Andrzej Kapolka on 4/10/2014. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/shared/src/PlaneShape.h b/libraries/shared/src/PlaneShape.h index bb2c0ba408..8d6de326af 100644 --- a/libraries/shared/src/PlaneShape.h +++ b/libraries/shared/src/PlaneShape.h @@ -1,6 +1,6 @@ // // PlaneShape.h -// libraries/physics/src +// libraries/shared/src // // Created by Andrzej Kapolka on 4/9/2014. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/shared/src/Shape.h b/libraries/shared/src/Shape.h index 2cc309e1fa..dd318c2776 100644 --- a/libraries/shared/src/Shape.h +++ b/libraries/shared/src/Shape.h @@ -1,6 +1,6 @@ // // Shape.h -// libraries/physics/src +// libraries/shared/src // // Created by Andrew Meadows on 2014. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/shared/src/ShapeCollider.cpp b/libraries/shared/src/ShapeCollider.cpp index 32d785b46a..b4f9d984f7 100644 --- a/libraries/shared/src/ShapeCollider.cpp +++ b/libraries/shared/src/ShapeCollider.cpp @@ -1,6 +1,6 @@ // // ShapeCollider.cpp -// libraries/physics/src +// libraries/shared/src // // Created by Andrew Meadows on 02/20/2014. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/shared/src/ShapeCollider.h b/libraries/shared/src/ShapeCollider.h index 16023ac6a5..da37adcd49 100644 --- a/libraries/shared/src/ShapeCollider.h +++ b/libraries/shared/src/ShapeCollider.h @@ -1,6 +1,6 @@ // // ShapeCollider.h -// libraries/physics/src +// libraries/shared/src // // Created by Andrew Meadows on 02/20/2014. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/shared/src/SphereShape.cpp b/libraries/shared/src/SphereShape.cpp index d63ff412df..4c47ae91c0 100644 --- a/libraries/shared/src/SphereShape.cpp +++ b/libraries/shared/src/SphereShape.cpp @@ -1,6 +1,6 @@ // // SphereShape.cpp -// libraries/physics/src +// libraries/shared/src // // Created by Andrew Meadows on 2014.06.17 // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/shared/src/SphereShape.h b/libraries/shared/src/SphereShape.h index c8562a99da..3bce2e96a1 100644 --- a/libraries/shared/src/SphereShape.h +++ b/libraries/shared/src/SphereShape.h @@ -1,6 +1,6 @@ // // SphereShape.h -// libraries/physics/src +// libraries/shared/src // // Created by Andrew Meadows on 2014. // Copyright 2014 High Fidelity, Inc. From 85e7c6166b2e6542f6ad83ff0f7ea2cf4645d636 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 3 Dec 2014 12:10:26 -0800 Subject: [PATCH 061/105] support for spherical entities --- libraries/entities/src/BoxEntityItem.cpp | 14 +++----------- libraries/entities/src/BoxEntityItem.h | 2 ++ libraries/entities/src/EntityItem.cpp | 4 ++++ libraries/entities/src/EntityItem.h | 5 +++++ libraries/entities/src/SphereEntityItem.cpp | 6 ++++++ libraries/entities/src/SphereEntityItem.h | 2 ++ libraries/physics/src/EntityMotionState.cpp | 4 +--- 7 files changed, 23 insertions(+), 14 deletions(-) diff --git a/libraries/entities/src/BoxEntityItem.cpp b/libraries/entities/src/BoxEntityItem.cpp index ecd1306297..560ef05054 100644 --- a/libraries/entities/src/BoxEntityItem.cpp +++ b/libraries/entities/src/BoxEntityItem.cpp @@ -96,16 +96,8 @@ void BoxEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitst APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor()); } -/* -#ifdef USE_BULLET_PHYSICS -EntityMotionState* BoxEntityItem::createMotionState() { - if (!_motionState) { - _motionState = new EntityMotionState(this); - glm::vec3 extents = getDimensionsInMeters(); - _motionState->setVolume(extents.x * extents.y * extents.z); - } - return _motionState; +void BoxEntityItem::computeShapeInfo(ShapeInfo& info) const { + glm::vec3 halfExtents = 0.5f * getDimensionsInMeters(); + info.setBox(halfExtents); } -#endif // USE_BULLET_PHYSICS -*/ diff --git a/libraries/entities/src/BoxEntityItem.h b/libraries/entities/src/BoxEntityItem.h index bea4f0c32a..7325432937 100644 --- a/libraries/entities/src/BoxEntityItem.h +++ b/libraries/entities/src/BoxEntityItem.h @@ -50,6 +50,8 @@ public: _color[GREEN_INDEX] = value.green; _color[BLUE_INDEX] = value.blue; } + + void computeShapeInfo(ShapeInfo& info) const; protected: rgbColor _color; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 928645b349..5e3d648b45 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -946,6 +946,10 @@ float EntityItem::getRadius() const { return radius; } +void EntityItem::computeShapeInfo(ShapeInfo& info) const { + info.clear(); +} + void EntityItem::recalculateCollisionShape() { AACube entityAACube = getMinimumAACube(); entityAACube.scale(TREE_SCALE); // scale to meters diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index e865b4a3f5..23f8695417 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -22,6 +22,7 @@ #include // for EncodeBitstreamParams class #include // for OctreeElement::AppendState #include +#include #include #include "EntityItemID.h" @@ -279,6 +280,7 @@ public: void applyHardCollision(const CollisionInfo& collisionInfo); virtual const Shape& getCollisionShapeInMeters() const { return _collisionShape; } virtual bool contains(const glm::vec3& point) const { return getAABox().contains(point); } + virtual void computeShapeInfo(ShapeInfo& info) const; // updateFoo() methods to be used when changes need to be accumulated in the _updateFlags void updatePosition(const glm::vec3& value); @@ -348,6 +350,9 @@ protected: void setRadius(float value); AACubeShape _collisionShape; + + // _physicsInfo is a hook reserved for use by the EntitySimulation, which is guaranteed to set _physicsInfo + // to a non-NULL value when the EntityItem has a representation in the physics engine. void* _physicsInfo; // only set by EntitySimulation SimulationState _simulationState; // only set by EntitySimulation diff --git a/libraries/entities/src/SphereEntityItem.cpp b/libraries/entities/src/SphereEntityItem.cpp index f5b8eb27e9..72c470931b 100644 --- a/libraries/entities/src/SphereEntityItem.cpp +++ b/libraries/entities/src/SphereEntityItem.cpp @@ -93,3 +93,9 @@ void SphereEntityItem::recalculateCollisionShape() { float largestDiameter = glm::max(dimensionsInMeters.x, dimensionsInMeters.y, dimensionsInMeters.z); _sphereShape.setRadius(largestDiameter / 2.0f); } + +void SphereEntityItem::computeShapeInfo(ShapeInfo& info) const { + glm::vec3 halfExtents = 0.5f * getDimensionsInMeters(); + // TODO: support ellipsoid shapes + info.setSphere(halfExtents.x); +} diff --git a/libraries/entities/src/SphereEntityItem.h b/libraries/entities/src/SphereEntityItem.h index 21cb58223b..4a07ad5837 100644 --- a/libraries/entities/src/SphereEntityItem.h +++ b/libraries/entities/src/SphereEntityItem.h @@ -55,6 +55,8 @@ public: // TODO: implement proper contains for 3D ellipsoid //virtual bool contains(const glm::vec3& point) const; + + void computeShapeInfo(ShapeInfo& info) const; protected: virtual void recalculateCollisionShape(); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index f08b32afb2..0620ae73aa 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -107,9 +107,7 @@ void EntityMotionState::applyGravity() const { } void EntityMotionState::computeShapeInfo(ShapeInfo& info) { - // HACK: for now we make everything a box. - glm::vec3 halfExtents = 0.5f * _entity->getDimensionsInMeters(); - info.setBox(halfExtents); + _entity->computeShapeInfo(info); } void EntityMotionState::getBoundingCubes(AACube& oldCube, AACube& newCube) { From d6c97be78e2fdd2f7c899f9bdd8406b2b421f10a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 3 Dec 2014 20:17:42 -0800 Subject: [PATCH 062/105] using an infinite plane for the ground --- libraries/physics/src/PhysicsEngine.cpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index a6013111b8..922b33d48c 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -147,22 +147,21 @@ void PhysicsEngine::init() { // TODO: set up gravity zones _dynamicsWorld->setGravity(btVector3(0.0f, 0.0f, 0.0f)); - // GROUND HACK: In the meantime we add a big planar floor to catch falling objects - // NOTE: we don't care about memory leaking groundShape and groundObject --> - // they'll exist until the executable exits. - const float halfSide = 200.0f; - const float halfHeight = 1.0f; - - btCollisionShape* groundShape = new btBoxShape(btVector3(halfSide, halfHeight, halfSide)); + // GROUND HACK: add a big planar floor (and walls for testing) to catch falling objects btTransform groundTransform; groundTransform.setIdentity(); - groundTransform.setOrigin(btVector3(halfSide, -halfHeight, halfSide)); + for (int i = 0; i < 3; ++i) { + btVector3 normal(0.0f, 0.0f, 0.0f); + normal[i] = 1.0f; + btCollisionShape* plane = new btStaticPlaneShape(normal, 0.0f); - btCollisionObject* groundObject = new btCollisionObject(); - groundObject->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT); - groundObject->setCollisionShape(groundShape); - groundObject->setWorldTransform(groundTransform); - _dynamicsWorld->addCollisionObject(groundObject); + btCollisionObject* groundObject = new btCollisionObject(); + groundObject->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT); + groundObject->setCollisionShape(plane); + + groundObject->setWorldTransform(groundTransform); + _dynamicsWorld->addCollisionObject(groundObject); + } } } From a519775cb3d10adf8f9021357890fbf2c5d7476a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 8 Dec 2014 17:15:58 -0800 Subject: [PATCH 063/105] unecessary EntitySimulation::entityChanged() calls --- libraries/entities/src/UpdateEntityOperator.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/libraries/entities/src/UpdateEntityOperator.cpp b/libraries/entities/src/UpdateEntityOperator.cpp index 4da24fb28a..4eedfb0d8d 100644 --- a/libraries/entities/src/UpdateEntityOperator.cpp +++ b/libraries/entities/src/UpdateEntityOperator.cpp @@ -301,10 +301,6 @@ bool UpdateEntityOperator::preRecursion(OctreeElement* element) { // set the entity properties and mark our element as changed. uint32_t oldUpdateFlags = _existingEntity->getUpdateFlags(); bool somethingChanged = _existingEntity->setProperties(_properties); - if (somethingChanged && !oldUpdateFlags && _existingEntity->getUpdateFlags()) { - // this entity hasn't yet been added to changed list - _tree->entityChanged(_existingEntity); - } if (_wantDebug) { qDebug() << " *** set properties ***"; } @@ -313,10 +309,6 @@ bool UpdateEntityOperator::preRecursion(OctreeElement* element) { entityTreeElement->addEntityItem(_existingEntity); uint32_t oldUpdateFlags = _existingEntity->getUpdateFlags(); bool somethingChanged = _existingEntity->setProperties(_properties); // still need to update the properties! - if (somethingChanged && !oldUpdateFlags && _existingEntity->getUpdateFlags()) { - // this entity hasn't yet been added to changed list - _tree->entityChanged(_existingEntity); - } _tree->setContainingElement(_entityItemID, entityTreeElement); if (_wantDebug) { qDebug() << " *** ADDING ENTITY to ELEMENT and MAP and SETTING PROPERTIES ***"; From d4c72ab203f306079b52e4c86c5d6c29d4b02045 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 8 Dec 2014 17:16:45 -0800 Subject: [PATCH 064/105] handle case where EntityItem's script has changed --- libraries/entities/src/EntityTree.cpp | 28 ++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index f5e6260270..4a517fc058 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -107,23 +107,29 @@ bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProp UpdateEntityOperator theOperator(this, containingElement, existingEntity, tempProperties); recurseTreeWithOperator(&theOperator); _isDirty = true; - if (_simulation && existingEntity->getUpdateFlags() != 0) { - _simulation->entityChanged(existingEntity); - } } } } else { + uint32_t preFlags = existingEntity->getDirtyFlags(); UpdateEntityOperator theOperator(this, containingElement, existingEntity, properties); recurseTreeWithOperator(&theOperator); _isDirty = true; - if (_simulation && existingEntity->getUpdateFlags() != 0) { - _simulation->entityChanged(existingEntity); - } + uint32_t newFlags = existingEntity->getDirtyFlags() & ~oldFlags; + if (newFlags) { + if (newFlags & EntityItem::DIRTY_SCRIPT) { + emit entityScriptChanging(existingEntity->getEntityItemID()); + existingEntity->clearDirtyFlags(EntityItem::DIRTY_SCRIPT); + } - uint32_t flags = existingEntity->getUpdateFlags(); - if (flags & EntityItem::UPDATE_SCRIPT) { - emit entityScriptChanging(existingEntity->getEntityItemID()); + if (_simulation) { + if (newFlags & ENTITY_SIMULATION_FLAGS) { + _simulation->entityChanged(existingEntity); + } + } else { + // normally the _simulation clears ALL updateFlags, but since there is none we do it explicitly + existingEntity->clearDirtyFlags(); + } } } @@ -588,7 +594,7 @@ void EntityTree::updateChangedEntities(quint64 now, QSet& entities clearEntityState(thisEntity); } else { uint32_t flags = thisEntity->getUpdateFlags(); - if (flags & EntityItem::UPDATE_SCRIPT) { + if (flags & EntityItem::DIRTY_SCRIPT) { emit entityScriptChanging(thisEntity->getEntityItemID()); } @@ -597,7 +603,7 @@ void EntityTree::updateChangedEntities(quint64 now, QSet& entities _physicsEngine->updateEntity(thisEntity->getMotionState(), flags); } } - thisEntity->clearUpdateFlags(); + thisEntity->clearDirtyFlags(); } _changedEntities.clear(); } From b0cc3a85097dffd3ea13099481820cef9d34e2cf Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 8 Dec 2014 17:18:07 -0800 Subject: [PATCH 065/105] add logic for when to update moving entity --- libraries/physics/src/EntityMotionState.cpp | 67 ++++++++-- libraries/physics/src/EntityMotionState.h | 33 ++++- libraries/physics/src/PhysicsEngine.cpp | 115 ++++++++++++------ libraries/physics/src/PhysicsEngine.h | 20 ++- .../physics/src/ThreadSafeDynamicsWorld.h | 5 + 5 files changed, 192 insertions(+), 48 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 0620ae73aa..c57d3fe2e0 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -16,21 +16,33 @@ #endif // USE_BULLET_PHYSICS #include "EntityMotionState.h" -// TODO: store _cachedWorldOffset in a more central location -- VoxelTree and others also need to know about it +// TODO: store _worldOffset in a more central location -- VoxelTree and others also need to know about it // origin of physics simulation in world frame -glm::vec3 _cachedWorldOffset(0.0f); +glm::vec3 _worldOffset(0.0f); // static void EntityMotionState::setWorldOffset(const glm::vec3& offset) { - _cachedWorldOffset = offset; + _worldOffset = offset; } // static const glm::vec3& getWorldOffset() { - return _cachedWorldOffset; + return _worldOffset; } -EntityMotionState::EntityMotionState(EntityItem* entity) : _entity(entity) { +EntityMotionState::EntityMotionState(EntityItem* entity) + : _entity(entity), + _sentMoving(false), + _notMoving(true), + _recievedNotMoving(false), + _sentFrame(0), + _sentPosition(0.0f), + _sentRotation(), + _sentVelocity(0.0f), + _sentVelocity(0.0f), + _sentAngularVelocity(0.0f), + _sentGravity(0.0f) +{ assert(entity != NULL); _oldBoundingCube = _entity->getMaximumAACube(); } @@ -38,7 +50,7 @@ EntityMotionState::EntityMotionState(EntityItem* entity) : _entity(entity) { EntityMotionState::~EntityMotionState() { } -MotionType EntityMotionState::getMotionType() const { +MotionType EntityMotionState::computeMotionType() const { // HACK: According to EntityTree the meaning of "static" is "not moving" whereas // to Bullet it means "can't move". For demo purposes we temporarily interpret // Entity::weightless to mean Bullet::static. @@ -53,7 +65,7 @@ MotionType EntityMotionState::getMotionType() const { // it is an opportunity for outside code to update the object's simulation position void EntityMotionState::getWorldTransform (btTransform &worldTrans) const { btVector3 pos; - glmToBullet(_entity->getPositionInMeters() - _cachedWorldOffset, pos); + glmToBullet(_entity->getPositionInMeters() - _worldOffset, pos); worldTrans.setOrigin(pos); btQuaternion rot; @@ -70,7 +82,7 @@ void EntityMotionState::setWorldTransform (const btTransform &worldTrans) { if (! (updateFlags & EntityItem::UPDATE_POSITION)) { glm::vec3 pos; bulletToGLM(worldTrans.getOrigin(), pos); - _entity->setPositionInMeters(pos + _cachedWorldOffset); + _entity->setPositionInMeters(pos + _worldOffset); glm::quat rot; bulletToGLM(worldTrans.getRotation(), rot); @@ -116,3 +128,42 @@ void EntityMotionState::getBoundingCubes(AACube& oldCube, AACube& newCube) { _oldBoundingCube = newCube; } +const float FIXED_SUBSTEP = 1.0f / 60.0f; +bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame, float subStepRemainder) const { + // TODO: Andrew to test this and make sure it works as expected + assert(_body); + float dt = (float)(simulationFrame - _sentFrame) * FIXED_SUBSTEP + subStepRemainder; + const float DEFAULT_UPDATE_PERIOD = 10.0f;j + if (dt > DEFAULT_UPDATE_PERIOD) { + return ! (_notMoving && _recievedNotMoving); + } + if (_sentMoving && _notMoving) { + return true; + } + + // compute position error + glm::vec3 expectedPosition = _sentPosition + dt * (_sentVelocity + (0.5f * dt) * _sentGravity); + + glm::vec3 actualPos; + btTransform worldTrans = _body->getWorldTransform(); + bulletToGLM(worldTrans.getOrigin(), actualPos); + + float dx2 = glm::length2(actualPosition - expectedPosition); + const MAX_POSITION_ERROR_SQUARED = 0.001; // 0.001 m^2 ~~> 0.03 m + if (dx2 > MAX_POSITION_ERROR_SQUARED) { + return true; + } + + // compute rotation error + float spin = glm::length(_sentAngularVelocity); + glm::quat expectedRotation = _sentRotation; + const float MIN_SPIN = 1.0e-4f; + if (spin > MIN_SPIN) { + glm::vec3 axis = _sentAngularVelocity / spin; + expectedRotation = glm::angleAxis(dt * spin, axis) * _sentRotation; + } + const float MIN_ROTATION_DOT = 0.98f; + glm::quat actualRotation; + bulletToGLM(worldTrans.getRotation(), actualRotation); + return (glm::dot(actualRotation, expectedRotation) < MIN_ROTATION_DOT); +} diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 91186c823c..4f05ea53ec 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -14,6 +14,8 @@ #include +#include "PhysicsEngineParams.h" + #ifdef USE_BULLET_PHYSICS #include "ObjectMotionState.h" #else // USE_BULLET_PHYSICS @@ -26,20 +28,35 @@ public: class EntityItem; +// From the MotionState's perspective: +// Inside = physics simulation +// Outside = external agents (scripts, user interaction, other simulations) + class EntityMotionState : public ObjectMotionState { public: + // The WorldOffset is used to keep the positions of objects in the simulation near the origin, to + // reduce numerical error when computing vector differences. In other words: The EntityMotionState + // class translates between the simulation-frame and the world-frame as known by the render pipeline, + // various object trees, etc. The EntityMotionState class uses a static "worldOffset" to help in + // the translations. static void setWorldOffset(const glm::vec3& offset); static const glm::vec3& getWorldOffset(); EntityMotionState(EntityItem* item); virtual ~EntityMotionState(); - MotionType getMotionType() const; + /// \return MOTION_TYPE_DYNAMIC or MOTION_TYPE_STATIC based on params set in EntityItem + MotionType computeMotionType() const; #ifdef USE_BULLET_PHYSICS + // this relays incoming position/rotation to the RigidBody void getWorldTransform (btTransform &worldTrans) const; + + // this relays outgoing position/rotation to the EntityItem void setWorldTransform (const btTransform &worldTrans); #endif // USE_BULLET_PHYSICS + + // these relay incoming values to the RigidBody void applyVelocities() const; void applyGravity() const; @@ -47,9 +64,23 @@ public: void getBoundingCubes(AACube& oldCube, AACube& newCube); + bool shouldSendUpdate(uint32_t simulationFrame, float subStepRemainder) const; + protected: EntityItem* _entity; AACube _oldBoundingCube; + + bool _sentMoving; + bool _notMoving; + bool _receivedNotMoving; + // TODO: Andrew to talk to Brad about what to do about lost packets ^^^ + + uint32_t _sentFrame; + glm::vec3 _sentPosition; + glm::quat _sentRotation;; + glm::vec3 _sentVelocity; + glm::vec3 _sentAngularVelocity; + glm::vec3 _sentGravity; }; #endif // hifi_EntityMotionState_h diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 922b33d48c..cb7cd99193 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -25,7 +25,8 @@ PhysicsEngine::PhysicsEngine(const glm::vec3& offset) _constraintSolver(NULL), _dynamicsWorld(NULL), _originOffset(offset), - _voxels() { + _voxels(), + _frameCount(0) { } PhysicsEngine::~PhysicsEngine() { @@ -38,41 +39,85 @@ void PhysicsEngine::setEntityTree(EntityTree* tree) { _entityTree = tree; } -/// \param[out] entitiesToDelete list of entities removed from simulation and should be deleted. -void PhysicsEngine::updateEntities(QSet& entitiesToDelete) { - // relay changes - QSet::iterator item_itr = _changedEntities.begin(); - while (item_itr != _changedEntities.end()) { +void PhysicsEngine::relayIncomingChangesToSimulation() { + // process incoming changes + QSet::iterator item_itr = _incomingPhysics.begin(); + while (item_itr != _incomingPhysics.end()) { EntityItem* entity = *item_itr; void* physicsInfo = entity->getPhysicsInfo(); if (physicsInfo) { ObjectMotionState* motionState = static_cast(physicsInfo); + uint32_t preOutgoingFlags = motionState->getOutgoingUpdateFlags(); updateObject(motionState, entity->getUpdateFlags()); + uint32_t postOutgoingFlags = motionState->getOutgoingUpdateFlags(); + if (preOutgoingFlags && !postOutgoingFlags) { + _outgoingPhysics.remove(entity); + } } entity->clearUpdateFlags(); ++item_itr; } - _changedEntities.clear(); + _incomingPhysics.clear(); +} - // hunt for entities who have expired - // TODO: make EntityItems use an expiry to make this work faster. - item_itr = _mortalEntities.begin(); - while (item_itr != _mortalEntities.end()) { +/// \param[out] entitiesToDelete list of entities removed from simulation and should be deleted. +void PhysicsEngine::updateEntities(QSet& entitiesToDelete) { + // TODO: Andrew to make this work. + EnitySimulation::updateEntities(entitiesToDelete); + + item_itr = _outgoingPhysics.begin(); + uint32_t simulationFrame = getSimulationFrame(); + float subStepRemainder = getSubStepRemainder(); + while (item_itr != _outgoingPhysics.end()) { EntityItem* entity = *item_itr; - // always check to see if the lifetime has expired, for immortal entities this is always false - if (entity->lifetimeHasExpired()) { - qDebug() << "Lifetime has expired for entity:" << entity->getEntityItemID(); - entitiesToDelete.insert(entity); - // remove entity from the list - item_itr = _mortalEntities.erase(item_itr); - _entities.remove(entity); - } else if (entity->isImmortal()) { - // remove entity from the list - item_itr = _mortalEntities.erase(item_itr); - } else { - ++item_itr; + void* physicsInfo = entity->getPhysicsInfo(); + if (physicsInfo) { + ObjectMotionState* motionState = static_cast(physicsInfo); + if (motionState->shouldSendUpdate(simulationFrame, subStepRemainder)) { + EntityItemProperties properties = entity->getProperties(); + motionState->pushToProperties(properties); + + /* + properties.setVelocity(newVelocity); + properties.setPosition(newPosition); + properties.setRotation(newRotation); + properties.setAngularVelocity(newAngularVelocity); + properties.setLastEdited(now); + */ + + EntityItemID id(entity->getID()); + _packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties); + ++itemItr; + } else if (motionState->shouldRemoveFromOutgoingPhysics()) { + itemItr = _outgoingPhysics.erase(itemItr); + } else { + ++itemItr; + } } } + + item_itr = _movedEntities.begin(); + AACube domainBounds(glm::vec3(0.0f,0.0f,0.0f), 1.0f); + while (item_itr != _movedEntities.end()) { + EntityItem* entity = *item_itr; + void* physicsInfo = entity->getPhysicsInfo(); + if (physicsInfo) { + ObjectMotionState* motionState = static_cast(physicsInfo); + + AACube oldCube, newCube; + motionState->getBoundingCubes(oldCube, newCube); + + // check to see if this movement has sent the entity outside of the domain. + if (!domainBounds.touches(newCube)) { + //qDebug() << "Entity " << entity->getEntityItemID() << " moved out of domain bounds."; + entitiesToDelete << entity->getEntityItemID(); + clearEntityState(entity); + } else if (newCube != oldCube) { + moveOperator.addEntityToMoveList(entity, oldCube, newCube); + } + } + } + // TODO: check for entities that have exited the world boundaries } @@ -84,9 +129,6 @@ void PhysicsEngine::addEntity(EntityItem* entity) { if (!physicsInfo) { assert(!_entities.contains(entity)); _entities.insert(entity); - if (entity->isMortal()) { - _mortalEntities.insert(entity); - } EntityMotionState* motionState = new EntityMotionState(entity); if (addObject(motionState)) { entity->setPhysicsInfo(static_cast(motionState)); @@ -108,12 +150,11 @@ void PhysicsEngine::removeEntity(EntityItem* entity) { entity->setPhysicsInfo(NULL); } _entities.remove(entity); - _mortalEntities.remove(entity); } /// \param entity pointer to EntityItem to that may have changed in a way that would affect its simulation void PhysicsEngine::entityChanged(EntityItem* entity) { - _changedEntities.insert(entity); + _incomingPhysics.insert(entity); } void PhysicsEngine::clearEntities() { @@ -127,8 +168,7 @@ void PhysicsEngine::clearEntities() { } } _entities.clear(); - _changedEntities.clear(); - _mortalEntities.clear(); + _incomingPhysics.clear(); } // virtual @@ -165,15 +205,18 @@ void PhysicsEngine::init() { } } +const float FIXED_SUBSTEP = 1.0f / 60.0f; + void PhysicsEngine::stepSimulation() { - const float MAX_TIMESTEP = 1.0f / 30.0f; - const int MAX_NUM_SUBSTEPS = 2; - const float FIXED_SUBSTEP = 1.0f / 60.0f; + const int MAX_NUM_SUBSTEPS = 4; + const float MAX_TIMESTEP = (float)MAX_NUM_SUBSTEPS * FIXED_SUBSTEP; float dt = 1.0e-6f * (float)(_clock.getTimeMicroseconds()); _clock.reset(); float timeStep = btMin(dt, MAX_TIMESTEP); - _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, FIXED_SUBSTEP); + // TODO: Andrew to build a list of outgoingChanges when motionStates are synched, then send the updates out + int numSubSteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, FIXED_SUBSTEP); + _frameCount += (uint32_t)numSubSteps; } bool PhysicsEngine::addVoxel(const glm::vec3& position, float scale) { @@ -250,7 +293,7 @@ bool PhysicsEngine::addObject(ObjectMotionState* motionState) { btVector3 inertia(0.0f, 0.0f, 0.0f); float mass = 0.0f; btRigidBody* body = NULL; - switch(motionState->getMotionType()) { + switch(motionState->computeMotionType()) { case MOTION_TYPE_KINEMATIC: { body = new btRigidBody(mass, motionState, shape, inertia); body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); @@ -322,7 +365,7 @@ bool PhysicsEngine::updateObject(ObjectMotionState* motionState, uint32_t flags) // private void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags) { - MotionType newType = motionState->getMotionType(); + MotionType newType = motionState->computeMotionType(); // pull body out of physics engine _dynamicsWorld->removeRigidBody(body); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 2656a3f8cf..20ca033e65 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -112,6 +112,18 @@ public: /// \return true if entity updated bool updateObject(ObjectMotionState* motionState, uint32_t flags); + /// \return duration of fixed simulation substep + float getFixedSubStep() const; + + /// \return number of simulation frames the physics engine has taken + uint32_t getFrameCount() const { return _frameCount; } + + /// \return substep remainder used for Bullet MotionState extrapolation + // Bullet will extrapolate the positions provided to MotionState::setWorldTransform() in an effort to provide + // smoother visible motion when the render frame rate does not match that of the simulation loop. We provide + // access to this fraction for improved filtering of update packets to interested parties. + float getSubStepRemainder() { _dynamicsWorld->getLocalTimeAccumulation(); } + protected: void updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); void updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); @@ -129,9 +141,11 @@ private: btHashMap _voxels; // EntitySimulation stuff - QSet _entities; - QSet _changedEntities; - QSet _mortalEntities; + QSet _entities; // all entities that we track + QSet _incomingPhysics; // entities with pending physics changes by script or packet + QSet _outgoingPhysics; // entites with pending transform changes by physics simulation + + uint32_t _frameCount; }; #else // USE_BULLET_PHYSICS diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.h b/libraries/physics/src/ThreadSafeDynamicsWorld.h index 980ba7ae88..96cff8bda1 100644 --- a/libraries/physics/src/ThreadSafeDynamicsWorld.h +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.h @@ -38,6 +38,11 @@ public: int stepSimulation( btScalar timeStep, int maxSubSteps=1, btScalar fixedTimeStep=btScalar(1.)/btScalar(60.)); void synchronizeMotionStates(); + // btDiscreteDynamicsWorld::m_localTime is the portion of real-time that has not yet been simulated + // but is used for MotionState::setWorldTransform() extrapolation (a feature that Bullet uses to provide + // smoother rendering of objects when the physics simulation loop is ansynchronous to the render loop). + float getLocalTimeAccumulation() const { return m_localTime; } + private: EntityTree* _entities; }; From 699e632e68485bb50c1f7a2e44bc36d6f2261dc8 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 9 Dec 2014 12:45:21 -0800 Subject: [PATCH 066/105] remove EntityItem::SimulationState after bad merge --- libraries/entities/src/EntityItem.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 40f66b0a38..c01e9b9ceb 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -307,8 +307,6 @@ public: void* getPhysicsInfo() const { return _physicsInfo; } void setPhysicsInfo(void* data) { _physicsInfo = data; } - SimulationState getSimulationState() const { return _simulationState; } - void setSimulationState(SimulationState state) { _simulationState = state; } protected: @@ -358,7 +356,6 @@ protected: // _physicsInfo is a hook reserved for use by the EntitySimulation, which is guaranteed to set _physicsInfo // to a non-NULL value when the EntityItem has a representation in the physics engine. void* _physicsInfo; // only set by EntitySimulation - SimulationState _simulationState; // only set by EntitySimulation AACube _oldMaximumAACube; // remember this so we know where the entity used to live in the tree // DirtyFlags are set whenever a property changes that the EntitySimulation needs to know about. From bc22e5723c05db62e788a852681d11979949f2db Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 9 Dec 2014 12:55:58 -0800 Subject: [PATCH 067/105] bundle the flags that EntitySimulation cares about --- libraries/entities/src/EntitySimulation.h | 13 +++++++++++++ libraries/entities/src/EntityTree.cpp | 4 ++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index 506e2ed9d0..c87521e8a3 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -16,8 +16,21 @@ #include +#include "EntityItem.h" #include "EntityTree.h" +// the EntitySimulation needs to know when these things change on an entity, +// so it can sort EntityItem or relay its state to the PhysicsEngine. +const int DIRTY_SIMULATION_FLAGS = + EntityItem::DIRTY_POSITION | + EntityItem::DIRTY_VELOCITY | + EntityItem::DIRTY_MASS | + EntityItem::DIRTY_COLLISION_GROUP | + EntityItem::DIRTY_MOTION_TYPE | + EntityItem::DIRTY_SHAPE | + EntityItem::DIRTY_LIFETIME | + EntityItem::DIRTY_UPDATEABLE; + class EntitySimulation { public: EntitySimulation() : _entityTree(NULL) { } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index d07211f790..f7addeaa8b 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -137,7 +137,7 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro entity->setOldMaximumAACube(entity->getMaximumAACube()); _isDirty = true; - uint32_t newFlags = entity->getDirtyFlags() & ~oldFlags; + uint32_t newFlags = entity->getDirtyFlags() & ~preFlags; if (newFlags) { if (newFlags & EntityItem::DIRTY_SCRIPT) { emit entityScriptChanging(entity->getEntityItemID()); @@ -145,7 +145,7 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro } if (_simulation) { - if (newFlags & ENTITY_SIMULATION_FLAGS) { + if (newFlags & DIRTY_SIMULATION_FLAGS) { _simulation->entityChanged(entity); } } else { From c4d076b0bb95cdaf84a7a7c69cead49361efbd28 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 10 Dec 2014 16:59:17 -0800 Subject: [PATCH 068/105] added comments about macro behavior --- libraries/entities/src/EntityItemProperties.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 642e24beec..2aaa7a4528 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -136,6 +136,13 @@ public: void debugDump() const; void setLastEdited(quint64 usecTime) { _lastEdited = usecTime; } + // Note: DEFINE_PROPERTY(PROP_FOO, Foo, foo, type) creates the following methods and variables: + // type getFoo() const; + // void setFoo(type); + // bool fooChanged() const; + // type _foo; + // bool _fooChanged; + DEFINE_PROPERTY(PROP_VISIBLE, Visible, visible, bool); DEFINE_PROPERTY_REF_WITH_SETTER(PROP_POSITION, Position, position, glm::vec3); DEFINE_PROPERTY_REF(PROP_DIMENSIONS, Dimensions, dimensions, glm::vec3); From 4c74c041c29800f0e3c391e69188d862cf77a6de Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 10 Dec 2014 16:59:49 -0800 Subject: [PATCH 069/105] remove unused cruft --- libraries/entities/src/EntityTree.cpp | 91 ------------------- libraries/entities/src/EntityTreeElement.cpp | 1 - .../entities/src/UpdateEntityOperator.cpp | 2 - 3 files changed, 94 deletions(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index f7addeaa8b..5edc66b5eb 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -586,97 +586,6 @@ void EntityTree::entityChanged(EntityItem* entity) { } } -/* TODO: andrew to port this to new EntitySimuation -void EntityTree::addEntityToPhysicsEngine(EntityItem* entity) { -#ifdef USE_BULLET_PHYSICS - EntityMotionState* motionState = entity->createMotionState(); - if (!_physicsEngine->addEntity(static_cast(motionState))) { - // failed to add to engine: probably because of bad shape, - // probably because entity is too big or too small - entity->destroyMotionState(); - } -#endif // USE_BULLET_PHYSICS -} - -void EntityTree::removeEntityFromPhysicsEngine(EntityItem* entity) { -#ifdef USE_BULLET_PHYSICS - EntityMotionState* motionState = entity->getMotionState(); - if (motionState) { - _physicsEngine->removeEntity(static_cast(motionState)); - } -#endif // USE_BULLET_PHYSICS -} - -void EntityTree::updateChangedEntities(quint64 now, QSet& entitiesToDelete) { - // TODO: switch these to iterators so we can remove items that get deleted - foreach (EntityItem* thisEntity, _changedEntities) { - // check to see if the lifetime has expired, for immortal entities this is always false - if (thisEntity->lifetimeHasExpired()) { - qDebug() << "Lifetime has expired for entity:" << thisEntity->getEntityItemID(); - entitiesToDelete << thisEntity->getEntityItemID(); - clearEntityState(thisEntity); - } else { - uint32_t flags = thisEntity->getUpdateFlags(); - if (flags & EntityItem::DIRTY_SCRIPT) { - emit entityScriptChanging(thisEntity->getEntityItemID()); - } - - updateEntityState(thisEntity); - if (_physicsEngine && thisEntity->getMotionState()) { - _physicsEngine->updateEntity(thisEntity->getMotionState(), flags); - } - } - thisEntity->clearDirtyFlags(); - } - _changedEntities.clear(); -} - -void EntityTree::updateMovingEntities(quint64 now, QSet& entitiesToDelete) { - PerformanceTimer perfTimer("updateMovingEntities"); - if (_movingEntities.size() > 0) { - MovingEntitiesOperator moveOperator(this); - { - PerformanceTimer perfTimer("_movingEntities"); - - // TODO: switch these to iterators so we can remove items that get deleted - for (int i = 0; i < _movingEntities.size(); i++) { - EntityItem* thisEntity = _movingEntities[i]; - - // always check to see if the lifetime has expired, for immortal entities this is always false - if (thisEntity->lifetimeHasExpired()) { - qDebug() << "Lifetime has expired for entity:" << thisEntity->getEntityItemID(); - entitiesToDelete << thisEntity->getEntityItemID(); - clearEntityState(thisEntity); - } else { - AACube oldCube, newCube; - EntityMotionState* motionState = thisEntity->getMotionState(); - if (motionState) { - motionState->getBoundingCubes(oldCube, newCube); - } else { - oldCube = thisEntity->getMaximumAACube(); - thisEntity->update(now); - newCube = thisEntity->getMaximumAACube(); - } - - // check to see if this movement has sent the entity outside of the domain. - AACube domainBounds(glm::vec3(0.0f,0.0f,0.0f), 1.0f); - if (!domainBounds.touches(newCube)) { - qDebug() << "Entity " << thisEntity->getEntityItemID() << " moved out of domain bounds."; - entitiesToDelete << thisEntity->getEntityItemID(); - clearEntityState(thisEntity); - } else if (newCube != oldCube) { - moveOperator.addEntityToMoveList(thisEntity, oldCube, newCube); - updateEntityState(thisEntity); - } - } - } - deleteEntities(idsToDelete); - } - unlock(); - } -} -*/ - void EntityTree::update() { if (_simulation) { lockForWrite(); diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index c564d6972b..e998f810b5 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -764,7 +764,6 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int // TODO: Do we need to also do this? // 3) remember the old cube for the entity so we can mark it as dirty if (entityItem) { - uint32_t oldFlags = entityItem->getUpdateFlags(); bool bestFitBefore = bestFitEntityBounds(entityItem); EntityTreeElement* currentContainingElement = _myTree->getContainingElement(entityItemID); diff --git a/libraries/entities/src/UpdateEntityOperator.cpp b/libraries/entities/src/UpdateEntityOperator.cpp index 4eedfb0d8d..2b5a54647d 100644 --- a/libraries/entities/src/UpdateEntityOperator.cpp +++ b/libraries/entities/src/UpdateEntityOperator.cpp @@ -299,7 +299,6 @@ bool UpdateEntityOperator::preRecursion(OctreeElement* element) { } // set the entity properties and mark our element as changed. - uint32_t oldUpdateFlags = _existingEntity->getUpdateFlags(); bool somethingChanged = _existingEntity->setProperties(_properties); if (_wantDebug) { qDebug() << " *** set properties ***"; @@ -307,7 +306,6 @@ bool UpdateEntityOperator::preRecursion(OctreeElement* element) { } else { // otherwise, this is an add case. entityTreeElement->addEntityItem(_existingEntity); - uint32_t oldUpdateFlags = _existingEntity->getUpdateFlags(); bool somethingChanged = _existingEntity->setProperties(_properties); // still need to update the properties! _tree->setContainingElement(_entityItemID, entityTreeElement); if (_wantDebug) { From ab7515017541659731720e31c131660b2128fc3e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 10 Dec 2014 17:00:23 -0800 Subject: [PATCH 070/105] moved position/velocity send history to base class --- libraries/physics/src/EntityMotionState.cpp | 116 +++++++++++--------- libraries/physics/src/EntityMotionState.h | 20 +--- libraries/physics/src/ObjectMotionState.cpp | 51 ++++++++- libraries/physics/src/ObjectMotionState.h | 35 +++++- 4 files changed, 148 insertions(+), 74 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index c57d3fe2e0..a5203b5afd 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -10,6 +10,7 @@ // #include +#include #ifdef USE_BULLET_PHYSICS #include "BulletUtil.h" @@ -32,19 +33,8 @@ const glm::vec3& getWorldOffset() { EntityMotionState::EntityMotionState(EntityItem* entity) : _entity(entity), - _sentMoving(false), - _notMoving(true), - _recievedNotMoving(false), - _sentFrame(0), - _sentPosition(0.0f), - _sentRotation(), - _sentVelocity(0.0f), - _sentVelocity(0.0f), - _sentAngularVelocity(0.0f), - _sentGravity(0.0f) -{ + _outgoingPhysicsDirtyFlags(0) { assert(entity != NULL); - _oldBoundingCube = _entity->getMaximumAACube(); } EntityMotionState::~EntityMotionState() { @@ -78,8 +68,8 @@ void EntityMotionState::getWorldTransform (btTransform &worldTrans) const { // This callback is invoked by the physics simulation at the end of each simulation frame... // iff the corresponding RigidBody is DYNAMIC and has moved. void EntityMotionState::setWorldTransform (const btTransform &worldTrans) { - uint32_t updateFlags = _entity->getUpdateFlags(); - if (! (updateFlags & EntityItem::UPDATE_POSITION)) { + uint32_t dirytFlags = _entity->getDirtyFlags(); + if (! (dirytFlags & EntityItem::DIRTY_POSITION)) { glm::vec3 pos; bulletToGLM(worldTrans.getOrigin(), pos); _entity->setPositionInMeters(pos + _worldOffset); @@ -89,13 +79,14 @@ void EntityMotionState::setWorldTransform (const btTransform &worldTrans) { _entity->setRotation(rot); } - if (! (updateFlags & EntityItem::UPDATE_VELOCITY)) { + if (! (dirytFlags & EntityItem::DIRTY_VELOCITY)) { glm::vec3 v; getVelocity(v); _entity->setVelocityInMeters(v); getAngularVelocity(v); _entity->setAngularVelocity(v); } + _outgoingDirtyFlags = OUTGOING_DIRTY_PHYSICS_FLAGS; } #endif // USE_BULLET_PHYSICS @@ -122,48 +113,65 @@ void EntityMotionState::computeShapeInfo(ShapeInfo& info) { _entity->computeShapeInfo(info); } -void EntityMotionState::getBoundingCubes(AACube& oldCube, AACube& newCube) { - oldCube = _oldBoundingCube; - newCube = _entity->getMaximumAACube(); - _oldBoundingCube = newCube; -} +void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender) { + if (_outgoingPhysicsDirtyFlags) { + EntityItemProperties properties = _entity->getProperties(); -const float FIXED_SUBSTEP = 1.0f / 60.0f; -bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame, float subStepRemainder) const { - // TODO: Andrew to test this and make sure it works as expected - assert(_body); - float dt = (float)(simulationFrame - _sentFrame) * FIXED_SUBSTEP + subStepRemainder; - const float DEFAULT_UPDATE_PERIOD = 10.0f;j - if (dt > DEFAULT_UPDATE_PERIOD) { - return ! (_notMoving && _recievedNotMoving); - } - if (_sentMoving && _notMoving) { - return true; - } + if (_outgoingPhysicsDirtyFlags == OUTGOING_DIRTY_PHYSICS_FLAGS) { + // common case: physics engine has changed object position/velocity - // compute position error - glm::vec3 expectedPosition = _sentPosition + dt * (_sentVelocity + (0.5f * dt) * _sentGravity); - - glm::vec3 actualPos; - btTransform worldTrans = _body->getWorldTransform(); - bulletToGLM(worldTrans.getOrigin(), actualPos); + btTransform worldTrans = _body->getWorldTransform(); + bulletToGLM(worldTrans.getOrigin(), _sentPosition); + properties.setPosition(_sentPosition); + + bulletToGLM(worldTrans.getRotation(), _sentRotation); + properties.setRotation(_sentRotation); + + if (_body->isActive()) { + bulletToGLM(_body->getLinearVelocity(), _sentVelocity); + bulletToGLM(_body->getAngularVelocity(), _sentAngularVelocity); + bulletToGLM(_body->getGravity(), _sentAcceleration); + } else { + _sentVelocity = _sentAngularVelocity = _sentAcceleration = glm::vec3(0.0f); + } + properties.setVelocity(_sentVelocity); + properties.setGravity(_sentAcceleration); + properties.setAngularVelocity(_sentAngularVelocity); + } else { + // uncommon case: physics engine change collided with incoming external change + // we only send data for flags that are set - float dx2 = glm::length2(actualPosition - expectedPosition); - const MAX_POSITION_ERROR_SQUARED = 0.001; // 0.001 m^2 ~~> 0.03 m - if (dx2 > MAX_POSITION_ERROR_SQUARED) { - return true; - } + if (_outgoingPhysicsDirtyFlags & EntityItem::DIRTY_POSITION) { + btTransform worldTrans = _body->getWorldTransform(); + bulletToGLM(worldTrans.getOrigin(), _sentPosition); + properties.setPosition(_sentPosition); + + bulletToGLM(worldTrans.getRotation(), _sentRotation); + properties.setRotation(_sentRotation); + } + + if (_outgoingPhysicsDirtyFlags & EntityItem::DIRTY_VELOCITY) { + if (_body->isActive()) { + bulletToGLM(_body->getLinearVelocity(), _sentVelocity); + bulletToGLM(_body->getAngularVelocity(), _sentAngularVelocity); + bulletToGLM(_body->getGravity(), _sentAcceleration); + } else { + _sentVelocity = _sentAngularVelocity = _sentAcceleration = glm::vec3(0.0f); + } + properties.setVelocity(_sentVelocity); + properties.setAngularVelocity(_sentAngularVelocity); + properties.setGravity(_sentAcceleration); + } + } + // TODO: Figure out what LastEdited is used for... + //properties.setLastEdited(now); - // compute rotation error - float spin = glm::length(_sentAngularVelocity); - glm::quat expectedRotation = _sentRotation; - const float MIN_SPIN = 1.0e-4f; - if (spin > MIN_SPIN) { - glm::vec3 axis = _sentAngularVelocity / spin; - expectedRotation = glm::angleAxis(dt * spin, axis) * _sentRotation; + glm::vec3 zero(0.0f); + _sentMoving = (_sentVelocity == zero && _sentAngularVelocity == zero && _sentAcceleration == zero); + + EntityItemID id(_entity->getID()); + EntityEditPacketSender* entityPacketSender = static_cast(packetSender); + entityPacketSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties); } - const float MIN_ROTATION_DOT = 0.98f; - glm::quat actualRotation; - bulletToGLM(worldTrans.getRotation(), actualRotation); - return (glm::dot(actualRotation, expectedRotation) < MIN_ROTATION_DOT); + _outgoingPhysicsDirtyFlags = 0; } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 4f05ea53ec..d2151d2da5 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -14,8 +14,6 @@ #include -#include "PhysicsEngineParams.h" - #ifdef USE_BULLET_PHYSICS #include "ObjectMotionState.h" #else // USE_BULLET_PHYSICS @@ -62,25 +60,11 @@ public: void computeShapeInfo(ShapeInfo& info); - void getBoundingCubes(AACube& oldCube, AACube& newCube); - - bool shouldSendUpdate(uint32_t simulationFrame, float subStepRemainder) const; + void sendUpdate(OctreeEditPacketSender* packetSender); protected: EntityItem* _entity; - AACube _oldBoundingCube; - - bool _sentMoving; - bool _notMoving; - bool _receivedNotMoving; - // TODO: Andrew to talk to Brad about what to do about lost packets ^^^ - - uint32_t _sentFrame; - glm::vec3 _sentPosition; - glm::quat _sentRotation;; - glm::vec3 _sentVelocity; - glm::vec3 _sentAngularVelocity; - glm::vec3 _sentGravity; + uint32_t _outgoingPhysicsDirtyFlags; }; #endif // hifi_EntityMotionState_h diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 9a57db3dae..bfa1149bc6 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -36,7 +36,16 @@ ObjectMotionState::ObjectMotionState() : _restitution(DEFAULT_RESTITUTION), _wasInWorld(false), _motionType(MOTION_TYPE_STATIC), - _body(NULL) { + _body(NULL), + _sentMoving(false), + _weKnowRecipientHasReceivedNotMoving(false), + _outgoingDirtyFlags(0), + _sentFrame(0), + _sentPosition(0.0f), + _sentRotation(), + _sentVelocity(0.0f), + _sentAngularVelocity(0.0f), + _sentAcceleration(0.0f) { } ObjectMotionState::~ObjectMotionState() { @@ -86,4 +95,44 @@ void ObjectMotionState::getAngularVelocity(glm::vec3& angularVelocityOut) const bulletToGLM(_body->getAngularVelocity(), angularVelocityOut); } +const float FIXED_SUBSTEP = 1.0f / 60.0f; + +bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame, float subStepRemainder) const { + assert(_body); + float dt = (float)(simulationFrame - _sentFrame) * FIXED_SUBSTEP + subStepRemainder; + const float DEFAULT_UPDATE_PERIOD = 10.0f; + if (dt > DEFAULT_UPDATE_PERIOD) { + return !isAtRest(); + } + if (_sentMoving && !_body->isActive()) { + return true; + } + + // compute position error + glm::vec3 expectedPosition = _sentPosition + dt * (_sentVelocity + (0.5f * dt) * _sentAcceleration); + + glm::vec3 position; + btTransform worldTrans = _body->getWorldTransform(); + bulletToGLM(worldTrans.getOrigin(), position); + + float dx2 = glm::length2(position - expectedPosition); + const float MAX_POSITION_ERROR_SQUARED = 0.001f; // 0.001 m^2 ~~> 0.03 m + if (dx2 > MAX_POSITION_ERROR_SQUARED) { + return true; + } + + // compute rotation error + float spin = glm::length(_sentAngularVelocity); + glm::quat expectedRotation = _sentRotation; + const float MIN_SPIN = 1.0e-4f; + if (spin > MIN_SPIN) { + glm::vec3 axis = _sentAngularVelocity / spin; + expectedRotation = glm::angleAxis(dt * spin, axis) * _sentRotation; + } + const float MIN_ROTATION_DOT = 0.98f; + glm::quat actualRotation; + bulletToGLM(worldTrans.getRotation(), actualRotation); + return (glm::dot(actualRotation, expectedRotation) < MIN_ROTATION_DOT); +} + #endif // USE_BULLET_PHYSICS diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 10e001f7c4..c387bb1dad 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -16,15 +16,31 @@ #include #include +#include // for EntityItem::DIRTY_FOO bitmasks #include "ShapeInfo.h" +// The update flags trigger two varieties of updates: "hard" which require the body to be pulled +// and re-added to the physics engine and "easy" which just updates the body properties. +typedef unsigned int uint32_t; +const uint32_t HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_MOTION_TYPE | EntityItem::DIRTY_SHAPE); +const uint32_t EASY_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY | + EntityItem::DIRTY_MASS | EntityItem::DIRTY_COLLISION_GROUP); + +// These are the set of incoming flags that the PhysicsEngine needs to hear about: +const uint32_t DIRTY_PHYSICS_FLAGS = HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSICS_FLAGS; + +// These are the outgoing flags that the PhysicsEngine can affect: +const uint32_t OUTGOING_DIRTY_PHYSICS_FLAGS = EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY; + enum MotionType { MOTION_TYPE_STATIC, // no motion MOTION_TYPE_DYNAMIC, // motion according to physical laws MOTION_TYPE_KINEMATIC // keyframed motion }; +class OctreeEditPacketSender; + class ObjectMotionState : public btMotionState { public: ObjectMotionState(); @@ -55,8 +71,14 @@ public: void getVelocity(glm::vec3& velocityOut) const; void getAngularVelocity(glm::vec3& angularVelocityOut) const; - friend class PhysicsEngine; + void clearOutgoingDirtyFlags(uint32_t flags) { _outgoingDirtyFlags &= ~flags; } + bool isAtRest() const { return !(_body->isActive()) && _weKnowRecipientHasReceivedNotMoving; } + virtual bool shouldSendUpdate(uint32_t simulationFrame, float subStepRemainder) const; + virtual void sendUpdate(OctreeEditPacketSender* packetSender) = 0; + virtual MotionType computeMotionType() const = 0; + + friend class PhysicsEngine; protected: float _density; float _volume; @@ -67,6 +89,17 @@ protected: // _body has NO setters -- it is only changed by PhysicsEngine btRigidBody* _body; + + bool _sentMoving; // true if last update was moving + bool _weKnowRecipientHasReceivedNotMoving; + + uint32_t _outgoingDirtyFlags; + uint32_t _sentFrame; + glm::vec3 _sentPosition; + glm::quat _sentRotation;; + glm::vec3 _sentVelocity; + glm::vec3 _sentAngularVelocity; + glm::vec3 _sentAcceleration; }; #endif // USE_BULLET_PHYSICS From f9ba4d355c7b2b226dc96ecf08420df2ad355bdc Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 10 Dec 2014 17:01:20 -0800 Subject: [PATCH 071/105] implement EntitySimulation API in PhysicsEngine --- libraries/physics/src/PhysicsEngine.cpp | 172 +++++++++--------------- libraries/physics/src/PhysicsEngine.h | 60 +++------ 2 files changed, 76 insertions(+), 156 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index cb7cd99193..50290f6753 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -8,6 +8,10 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +// TODO: make _incomingEntityChanges to be list of MotionState*'s. +// TODO: make MotionState able to clear incoming flags +// TODO: make MotionState::setWorldTransform() put itself on _incomingChanges list +// TODO: give PhysicsEngine instance an _entityPacketSender #include "PhysicsEngine.h" #ifdef USE_BULLET_PHYSICS @@ -32,104 +36,32 @@ PhysicsEngine::PhysicsEngine(const glm::vec3& offset) PhysicsEngine::~PhysicsEngine() { } -/// \param tree pointer to EntityTree which is stored internally -void PhysicsEngine::setEntityTree(EntityTree* tree) { - assert(_entityTree == NULL); - assert(tree); - _entityTree = tree; -} +// begin EntitySimulation overrides +void PhysicsEngine::updateEntitiesInternal(const quint64& now) { + // relay outgoing changes: from physics engine to EntityItem's -void PhysicsEngine::relayIncomingChangesToSimulation() { - // process incoming changes - QSet::iterator item_itr = _incomingPhysics.begin(); - while (item_itr != _incomingPhysics.end()) { - EntityItem* entity = *item_itr; - void* physicsInfo = entity->getPhysicsInfo(); - if (physicsInfo) { - ObjectMotionState* motionState = static_cast(physicsInfo); - uint32_t preOutgoingFlags = motionState->getOutgoingUpdateFlags(); - updateObject(motionState, entity->getUpdateFlags()); - uint32_t postOutgoingFlags = motionState->getOutgoingUpdateFlags(); - if (preOutgoingFlags && !postOutgoingFlags) { - _outgoingPhysics.remove(entity); - } - } - entity->clearUpdateFlags(); - ++item_itr; - } - _incomingPhysics.clear(); -} - -/// \param[out] entitiesToDelete list of entities removed from simulation and should be deleted. -void PhysicsEngine::updateEntities(QSet& entitiesToDelete) { - // TODO: Andrew to make this work. - EnitySimulation::updateEntities(entitiesToDelete); - - item_itr = _outgoingPhysics.begin(); - uint32_t simulationFrame = getSimulationFrame(); + QSet::iterator stateItr = _outgoingPhysics.begin(); + uint32_t frame = getFrameCount(); float subStepRemainder = getSubStepRemainder(); - while (item_itr != _outgoingPhysics.end()) { - EntityItem* entity = *item_itr; - void* physicsInfo = entity->getPhysicsInfo(); - if (physicsInfo) { - ObjectMotionState* motionState = static_cast(physicsInfo); - if (motionState->shouldSendUpdate(simulationFrame, subStepRemainder)) { - EntityItemProperties properties = entity->getProperties(); - motionState->pushToProperties(properties); - - /* - properties.setVelocity(newVelocity); - properties.setPosition(newPosition); - properties.setRotation(newRotation); - properties.setAngularVelocity(newAngularVelocity); - properties.setLastEdited(now); - */ - - EntityItemID id(entity->getID()); - _packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties); - ++itemItr; - } else if (motionState->shouldRemoveFromOutgoingPhysics()) { - itemItr = _outgoingPhysics.erase(itemItr); - } else { - ++itemItr; - } + while (stateItr != _outgoingPhysics.end()) { + ObjectMotionState* state = *stateItr; + if (state->shouldSendUpdate(frame, subStepRemainder)) { + state->sendUpdate(_entityPacketSender); + ++stateItr; + } else if (state->isAtRest()) { + stateItr = _outgoingPhysics.erase(stateItr); + } else { + ++stateItr; } } - - item_itr = _movedEntities.begin(); - AACube domainBounds(glm::vec3(0.0f,0.0f,0.0f), 1.0f); - while (item_itr != _movedEntities.end()) { - EntityItem* entity = *item_itr; - void* physicsInfo = entity->getPhysicsInfo(); - if (physicsInfo) { - ObjectMotionState* motionState = static_cast(physicsInfo); - - AACube oldCube, newCube; - motionState->getBoundingCubes(oldCube, newCube); - - // check to see if this movement has sent the entity outside of the domain. - if (!domainBounds.touches(newCube)) { - //qDebug() << "Entity " << entity->getEntityItemID() << " moved out of domain bounds."; - entitiesToDelete << entity->getEntityItemID(); - clearEntityState(entity); - } else if (newCube != oldCube) { - moveOperator.addEntityToMoveList(entity, oldCube, newCube); - } - } - } - - // TODO: check for entities that have exited the world boundaries } -/// \param entity pointer to EntityItem to add to the simulation -/// \sideeffect the EntityItem::_simulationState member may be updated to indicate membership to internal list -void PhysicsEngine::addEntity(EntityItem* entity) { +void PhysicsEngine::addEntityInternal(EntityItem* entity) { assert(entity); void* physicsInfo = entity->getPhysicsInfo(); if (!physicsInfo) { - assert(!_entities.contains(entity)); - _entities.insert(entity); EntityMotionState* motionState = new EntityMotionState(entity); + _entityMotionStates.insert(motionState); if (addObject(motionState)) { entity->setPhysicsInfo(static_cast(motionState)); } else { @@ -139,36 +71,52 @@ void PhysicsEngine::addEntity(EntityItem* entity) { } } -/// \param entity pointer to EntityItem to removed from the simulation -/// \sideeffect the EntityItem::_simulationState member may be updated to indicate non-membership to internal list -void PhysicsEngine::removeEntity(EntityItem* entity) { +void PhysicsEngine::removeEntityInternal(EntityItem* entity) { assert(entity); void* physicsInfo = entity->getPhysicsInfo(); if (physicsInfo) { ObjectMotionState* motionState = static_cast(physicsInfo); removeObject(motionState); entity->setPhysicsInfo(NULL); + _entityMotionStates.remove(motionState); } - _entities.remove(entity); } -/// \param entity pointer to EntityItem to that may have changed in a way that would affect its simulation -void PhysicsEngine::entityChanged(EntityItem* entity) { - _incomingPhysics.insert(entity); +void PhysicsEngine::entityChangedInternal(EntityItem* entity) { + // queue incoming changes: from external sources (script, EntityServer, etc) to physics engine + _incomingEntityChanges.insert(entity); } -void PhysicsEngine::clearEntities() { +void PhysicsEngine::clearEntitiesInternal() { // For now we assume this would only be called on shutdown in which case we can just let the memory get lost. - QSet::const_iterator entityItr = _entities.begin(); - for (entityItr = _entities.begin(); entityItr != _entities.end(); ++entityItr) { - void* physicsInfo = (*entityItr)->getPhysicsInfo(); + QSet::const_iterator stateItr = _entityMotionStates.begin(); + for (stateItr = _entityMotionStates.begin(); stateItr != _entityMotionStates.end(); ++stateItr) { + removeObject(*stateItr); + } + _entityMotionStates.clear(); + _incomingEntityChanges.clear(); +} +// end EntitySimulation overrides + +void PhysicsEngine::relayIncomingChangesToSimulation() { + // process incoming changes + QSet::iterator itemItr = _incomingEntityChanges.begin(); + while (itemItr != _incomingEntityChanges.end()) { + EntityItem* entity = *itemItr; + void* physicsInfo = entity->getPhysicsInfo(); if (physicsInfo) { ObjectMotionState* motionState = static_cast(physicsInfo); - removeObject(motionState); + uint32_t flags = entity->getDirtyFlags(); + if (flags & DIRTY_PHYSICS_FLAGS) { + updateObject(motionState, flags); + // this incoming change will override any outgoing changes to the same parameters + motionState->clearOutgoingDirtyFlags(flags); + } } - } - _entities.clear(); - _incomingPhysics.clear(); + entity->clearDirtyFlags(); + ++itemItr; + } + _incomingEntityChanges.clear(); } // virtual @@ -353,10 +301,10 @@ bool PhysicsEngine::updateObject(ObjectMotionState* motionState, uint32_t flags) return false; } - if (flags & PHYSICS_UPDATE_HARD) { + if (flags & HARD_DIRTY_PHYSICS_FLAGS) { // a hard update requires the body be pulled out of physics engine, changed, then reinserted updateObjectHard(body, motionState, flags); - } else if (flags & PHYSICS_UPDATE_EASY) { + } else if (flags & EASY_DIRTY_PHYSICS_FLAGS) { // an easy update does not require that the body be pulled out of physics engine updateObjectEasy(body, motionState, flags); } @@ -370,7 +318,7 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio // pull body out of physics engine _dynamicsWorld->removeRigidBody(body); - if (flags & PHYSICS_UPDATE_SHAPE) { + if (flags & EntityItem::DIRTY_SHAPE) { btCollisionShape* oldShape = body->getCollisionShape(); ShapeInfo info; motionState->computeShapeInfo(info); @@ -384,9 +332,9 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio _shapeManager.releaseShape(newShape); } // MASS bit should be set whenever SHAPE is set - assert(flags & PHYSICS_UPDATE_MASS); + assert(flags & EntityItem::DIRTY_MASS); } - bool easyUpdate = flags & PHYSICS_UPDATE_EASY; + bool easyUpdate = flags & EASY_DIRTY_PHYSICS_FLAGS; if (easyUpdate) { updateObjectEasy(body, motionState, flags); } @@ -406,7 +354,7 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio case MOTION_TYPE_DYNAMIC: { int collisionFlags = body->getCollisionFlags() & ~(btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT); body->setCollisionFlags(collisionFlags); - if (! (flags & PHYSICS_UPDATE_MASS)) { + if (! (flags & EntityItem::DIRTY_MASS)) { // always update mass properties when going dynamic (unless it's already been done) btVector3 inertia(0.0f, 0.0f, 0.0f); float mass = motionState->getMass(); @@ -441,19 +389,19 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio // private void PhysicsEngine::updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags) { - if (flags & PHYSICS_UPDATE_POSITION) { + if (flags & EntityItem::DIRTY_POSITION) { btTransform transform; motionState->getWorldTransform(transform); body->setWorldTransform(transform); } - if (flags & PHYSICS_UPDATE_VELOCITY) { + if (flags & EntityItem::DIRTY_VELOCITY) { motionState->applyVelocities(); motionState->applyGravity(); } body->setRestitution(motionState->_restitution); body->setFriction(motionState->_friction); - if (flags & PHYSICS_UPDATE_MASS) { + if (flags & EntityItem::DIRTY_MASS) { float mass = motionState->getMass(); btVector3 inertia(0.0f, 0.0f, 0.0f); body->getCollisionShape()->calculateLocalInertia(mass, inertia); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 20ca033e65..c48ca8f7de 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -12,24 +12,8 @@ #ifndef hifi_PhysicsEngine_h #define hifi_PhysicsEngine_h -enum PhysicsUpdateFlag { - PHYSICS_UPDATE_POSITION = 0x0001, - PHYSICS_UPDATE_VELOCITY = 0x0002, - PHYSICS_UPDATE_GRAVITY = 0x0004, - PHYSICS_UPDATE_MASS = 0x0008, - PHYSICS_UPDATE_COLLISION_GROUP = 0x0010, - PHYSICS_UPDATE_MOTION_TYPE = 0x0020, - PHYSICS_UPDATE_SHAPE = 0x0040 -}; - typedef unsigned int uint32_t; -// The update flags trigger two varieties of updates: "hard" which require the body to be pulled -// and re-added to the physics engine and "easy" which just updates the body properties. -const uint32_t PHYSICS_UPDATE_HARD = PHYSICS_UPDATE_MOTION_TYPE | PHYSICS_UPDATE_SHAPE; -const uint32_t PHYSICS_UPDATE_EASY = PHYSICS_UPDATE_POSITION | PHYSICS_UPDATE_VELOCITY | - PHYSICS_UPDATE_GRAVITY | PHYSICS_UPDATE_MASS | PHYSICS_UPDATE_COLLISION_GROUP; - #ifdef USE_BULLET_PHYSICS #include @@ -40,6 +24,7 @@ const uint32_t PHYSICS_UPDATE_EASY = PHYSICS_UPDATE_POSITION | PHYSICS_UPDATE_VE #include "BulletUtil.h" #include "ObjectMotionState.h" +#include "ObjectMotionState.h" #include "PositionHashKey.h" #include "ShapeManager.h" #include "ThreadSafeDynamicsWorld.h" @@ -54,30 +39,12 @@ public: ~PhysicsEngine(); - // override from EntitySimulation - /// \param tree pointer to EntityTree which is stored internally - void setEntityTree(EntityTree* tree); - - // override from EntitySimulation - /// \param[out] entitiesToDelete list of entities removed from simulation and should be deleted. - void updateEntities(QSet& entitiesToDelete); - - // override from EntitySimulation - /// \param entity pointer to EntityItem to add to the simulation - /// \sideeffect the EntityItem::_simulationState member may be updated to indicate membership to internal list - void addEntity(EntityItem* entity); - - // override from EntitySimulation - /// \param entity pointer to EntityItem to removed from the simulation - /// \sideeffect the EntityItem::_simulationState member may be updated to indicate non-membership to internal list - void removeEntity(EntityItem* entity); - - // override from EntitySimulation - /// \param entity pointer to EntityItem to that may have changed in a way that would affect its simulation - void entityChanged(EntityItem* entity); - - // override from EntitySimulation - void clearEntities(); + // overrides from EntitySimulation + void updateEntitiesInternal(const quint64& now); + void addEntityInternal(EntityItem* entity); + void removeEntityInternal(EntityItem* entity); + void entityChangedInternal(EntityItem* entity); + void clearEntitiesInternal(); virtual void init(); @@ -112,6 +79,9 @@ public: /// \return true if entity updated bool updateObject(ObjectMotionState* motionState, uint32_t flags); + /// process queue of changed from external sources + void relayIncomingChangesToSimulation(); + /// \return duration of fixed simulation substep float getFixedSubStep() const; @@ -122,7 +92,7 @@ public: // Bullet will extrapolate the positions provided to MotionState::setWorldTransform() in an effort to provide // smoother visible motion when the render frame rate does not match that of the simulation loop. We provide // access to this fraction for improved filtering of update packets to interested parties. - float getSubStepRemainder() { _dynamicsWorld->getLocalTimeAccumulation(); } + float getSubStepRemainder() { return _dynamicsWorld->getLocalTimeAccumulation(); } protected: void updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); @@ -141,9 +111,11 @@ private: btHashMap _voxels; // EntitySimulation stuff - QSet _entities; // all entities that we track - QSet _incomingPhysics; // entities with pending physics changes by script or packet - QSet _outgoingPhysics; // entites with pending transform changes by physics simulation + QSet _entityMotionStates; // all entities that we track + QSet _incomingEntityChanges; // entities with pending physics changes by script or packet + QSet _outgoingPhysics; // MotionStates with pending transform changes from physics simulation + + EntityEditPacketSender* _entityPacketSender; uint32_t _frameCount; }; From d9f183458a4dc8591b6ae4d5d1a7e73523adb513 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 11 Dec 2014 08:43:01 -0800 Subject: [PATCH 072/105] _entityMotionStates is Qset of EntityMotionState* --- libraries/physics/src/PhysicsEngine.cpp | 6 +++--- libraries/physics/src/PhysicsEngine.h | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 50290f6753..1d8e8190d1 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -12,11 +12,11 @@ // TODO: make MotionState able to clear incoming flags // TODO: make MotionState::setWorldTransform() put itself on _incomingChanges list // TODO: give PhysicsEngine instance an _entityPacketSender +// TODO: provide some sort of "reliable" send for "stopped" update #include "PhysicsEngine.h" #ifdef USE_BULLET_PHYSICS -#include "EntityMotionState.h" #include "ShapeInfoUtil.h" #include "ThreadSafeDynamicsWorld.h" @@ -75,7 +75,7 @@ void PhysicsEngine::removeEntityInternal(EntityItem* entity) { assert(entity); void* physicsInfo = entity->getPhysicsInfo(); if (physicsInfo) { - ObjectMotionState* motionState = static_cast(physicsInfo); + EntityMotionState* motionState = static_cast(physicsInfo); removeObject(motionState); entity->setPhysicsInfo(NULL); _entityMotionStates.remove(motionState); @@ -89,7 +89,7 @@ void PhysicsEngine::entityChangedInternal(EntityItem* entity) { void PhysicsEngine::clearEntitiesInternal() { // For now we assume this would only be called on shutdown in which case we can just let the memory get lost. - QSet::const_iterator stateItr = _entityMotionStates.begin(); + QSet::const_iterator stateItr = _entityMotionStates.begin(); for (stateItr = _entityMotionStates.begin(); stateItr != _entityMotionStates.end(); ++stateItr) { removeObject(*stateItr); } diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index c48ca8f7de..99a23a9b65 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -23,8 +23,7 @@ typedef unsigned int uint32_t; #include #include "BulletUtil.h" -#include "ObjectMotionState.h" -#include "ObjectMotionState.h" +#include "EntityMotionState.h" #include "PositionHashKey.h" #include "ShapeManager.h" #include "ThreadSafeDynamicsWorld.h" @@ -111,7 +110,7 @@ private: btHashMap _voxels; // EntitySimulation stuff - QSet _entityMotionStates; // all entities that we track + QSet _entityMotionStates; // all entities that we track QSet _incomingEntityChanges; // entities with pending physics changes by script or packet QSet _outgoingPhysics; // MotionStates with pending transform changes from physics simulation From 11f1ad1d7f65b6c29655fafbb4dc00d90d2a5d54 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 11 Dec 2014 10:52:34 -0800 Subject: [PATCH 073/105] move worldOffset into ObjectMotionState add more methods for getting/clearing incoming/outgoing flags --- libraries/physics/src/EntityMotionState.cpp | 24 ++++----------------- libraries/physics/src/EntityMotionState.h | 12 ++++------- libraries/physics/src/ObjectMotionState.cpp | 16 ++++++++++++++ libraries/physics/src/ObjectMotionState.h | 12 +++++++++++ 4 files changed, 36 insertions(+), 28 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index a5203b5afd..5fc5f7688b 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -17,20 +17,6 @@ #endif // USE_BULLET_PHYSICS #include "EntityMotionState.h" -// TODO: store _worldOffset in a more central location -- VoxelTree and others also need to know about it -// origin of physics simulation in world frame -glm::vec3 _worldOffset(0.0f); - -// static -void EntityMotionState::setWorldOffset(const glm::vec3& offset) { - _worldOffset = offset; -} - -// static -const glm::vec3& getWorldOffset() { - return _worldOffset; -} - EntityMotionState::EntityMotionState(EntityItem* entity) : _entity(entity), _outgoingPhysicsDirtyFlags(0) { @@ -55,14 +41,12 @@ MotionType EntityMotionState::computeMotionType() const { // it is an opportunity for outside code to update the object's simulation position void EntityMotionState::getWorldTransform (btTransform &worldTrans) const { btVector3 pos; - glmToBullet(_entity->getPositionInMeters() - _worldOffset, pos); + glmToBullet(_entity->getPositionInMeters() - ObjectMotionState::getWorldOffset(), pos); worldTrans.setOrigin(pos); btQuaternion rot; glmToBullet(_entity->getRotation(), rot); worldTrans.setRotation(rot); - - applyVelocities(); } // This callback is invoked by the physics simulation at the end of each simulation frame... @@ -72,7 +56,7 @@ void EntityMotionState::setWorldTransform (const btTransform &worldTrans) { if (! (dirytFlags & EntityItem::DIRTY_POSITION)) { glm::vec3 pos; bulletToGLM(worldTrans.getOrigin(), pos); - _entity->setPositionInMeters(pos + _worldOffset); + _entity->setPositionInMeters(pos + ObjectMotionState::getWorldOffset()); glm::quat rot; bulletToGLM(worldTrans.getRotation(), rot); @@ -122,7 +106,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender) { btTransform worldTrans = _body->getWorldTransform(); bulletToGLM(worldTrans.getOrigin(), _sentPosition); - properties.setPosition(_sentPosition); + properties.setPosition(_sentPosition + ObjectMotionState::getWorldOffset()); bulletToGLM(worldTrans.getRotation(), _sentRotation); properties.setRotation(_sentRotation); @@ -144,7 +128,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender) { if (_outgoingPhysicsDirtyFlags & EntityItem::DIRTY_POSITION) { btTransform worldTrans = _body->getWorldTransform(); bulletToGLM(worldTrans.getOrigin(), _sentPosition); - properties.setPosition(_sentPosition); + properties.setPosition(_sentPosition + ObjectMotionState::getWorldOffset()); bulletToGLM(worldTrans.getRotation(), _sentRotation); properties.setRotation(_sentRotation); diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index d2151d2da5..562efde87e 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -32,14 +32,6 @@ class EntityItem; class EntityMotionState : public ObjectMotionState { public: - // The WorldOffset is used to keep the positions of objects in the simulation near the origin, to - // reduce numerical error when computing vector differences. In other words: The EntityMotionState - // class translates between the simulation-frame and the world-frame as known by the render pipeline, - // various object trees, etc. The EntityMotionState class uses a static "worldOffset" to help in - // the translations. - static void setWorldOffset(const glm::vec3& offset); - static const glm::vec3& getWorldOffset(); - EntityMotionState(EntityItem* item); virtual ~EntityMotionState(); @@ -62,6 +54,10 @@ public: void sendUpdate(OctreeEditPacketSender* packetSender); + uint32_t getIncomingDirtyFlags() const { return _entity->getDirtyFlags(); } + void clearIncomingDirtyFlags(uint32_t flags) { _entity->clearDirtyFlags(flags); } + void clearConflictingDirtyFlags() { _outgoingDirtyFlags &= ~_entity->getDirtyFlags(); } + protected: EntityItem* _entity; uint32_t _outgoingPhysicsDirtyFlags; diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index bfa1149bc6..b80a996d0c 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -29,6 +29,19 @@ const float MAX_FRICTION = 10.0f; const float DEFAULT_RESTITUTION = 0.0f; +// origin of physics simulation in world frame +glm::vec3 _worldOffset(0.0f); + +// static +void ObjectMotionState::setWorldOffset(const glm::vec3& offset) { + _worldOffset = offset; +} + +// static +const glm::vec3& ObjectMotionState::getWorldOffset() { + return _worldOffset; +} + ObjectMotionState::ObjectMotionState() : _density(DEFAULT_DENSITY), _volume(DEFAULT_VOLUME), @@ -108,6 +121,9 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame, float subStep return true; } + // NOTE: math in done the simulation-frame, which is NOT necessarily the same + // as the world-frame due to _worldOffset + // compute position error glm::vec3 expectedPosition = _sentPosition + dt * (_sentVelocity + (0.5f * dt) * _sentAcceleration); diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index c387bb1dad..1341cb6168 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -43,6 +43,14 @@ class OctreeEditPacketSender; class ObjectMotionState : public btMotionState { public: + // The WorldOffset is used to keep the positions of objects in the simulation near the origin, to + // reduce numerical error when computing vector differences. In other words: The EntityMotionState + // class translates between the simulation-frame and the world-frame as known by the render pipeline, + // various object trees, etc. The EntityMotionState class uses a static "worldOffset" to help in + // the translations. + static void setWorldOffset(const glm::vec3& offset); + static const glm::vec3& getWorldOffset(); + ObjectMotionState(); ~ObjectMotionState(); @@ -71,7 +79,11 @@ public: void getVelocity(glm::vec3& velocityOut) const; void getAngularVelocity(glm::vec3& angularVelocityOut) const; + virtual uint32_t getIncomingDirtyFlags() const = 0; + virtual void clearIncomingDirtyFlags(uint32_t flags) = 0; void clearOutgoingDirtyFlags(uint32_t flags) { _outgoingDirtyFlags &= ~flags; } + virtual void clearConflictingDirtyFlags() = 0; + bool isAtRest() const { return !(_body->isActive()) && _weKnowRecipientHasReceivedNotMoving; } virtual bool shouldSendUpdate(uint32_t simulationFrame, float subStepRemainder) const; virtual void sendUpdate(OctreeEditPacketSender* packetSender) = 0; From cc0e82b97f01e95f2a86e6ec44af012c7956145d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 11 Dec 2014 10:56:22 -0800 Subject: [PATCH 074/105] incoming changes is now QSet --- libraries/physics/src/PhysicsEngine.cpp | 64 +++++++++++-------------- libraries/physics/src/PhysicsEngine.h | 7 +-- 2 files changed, 29 insertions(+), 42 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 1d8e8190d1..9fb6bdfe26 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -8,7 +8,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// TODO: make _incomingEntityChanges to be list of MotionState*'s. +// TODO DONE: make _incomingChanges to be list of MotionState*'s. // TODO: make MotionState able to clear incoming flags // TODO: make MotionState::setWorldTransform() put itself on _incomingChanges list // TODO: give PhysicsEngine instance an _entityPacketSender @@ -38,8 +38,6 @@ PhysicsEngine::~PhysicsEngine() { // begin EntitySimulation overrides void PhysicsEngine::updateEntitiesInternal(const quint64& now) { - // relay outgoing changes: from physics engine to EntityItem's - QSet::iterator stateItr = _outgoingPhysics.begin(); uint32_t frame = getFrameCount(); float subStepRemainder = getSubStepRemainder(); @@ -84,7 +82,12 @@ void PhysicsEngine::removeEntityInternal(EntityItem* entity) { void PhysicsEngine::entityChangedInternal(EntityItem* entity) { // queue incoming changes: from external sources (script, EntityServer, etc) to physics engine - _incomingEntityChanges.insert(entity); + assert(entity); + void* physicsInfo = entity->getPhysicsInfo(); + if (physicsInfo) { + ObjectMotionState* motionState = static_cast(physicsInfo); + _incomingChanges.insert(motionState); + } } void PhysicsEngine::clearEntitiesInternal() { @@ -94,29 +97,34 @@ void PhysicsEngine::clearEntitiesInternal() { removeObject(*stateItr); } _entityMotionStates.clear(); - _incomingEntityChanges.clear(); + _incomingChanges.clear(); } // end EntitySimulation overrides void PhysicsEngine::relayIncomingChangesToSimulation() { // process incoming changes - QSet::iterator itemItr = _incomingEntityChanges.begin(); - while (itemItr != _incomingEntityChanges.end()) { - EntityItem* entity = *itemItr; - void* physicsInfo = entity->getPhysicsInfo(); - if (physicsInfo) { - ObjectMotionState* motionState = static_cast(physicsInfo); - uint32_t flags = entity->getDirtyFlags(); - if (flags & DIRTY_PHYSICS_FLAGS) { - updateObject(motionState, flags); - // this incoming change will override any outgoing changes to the same parameters - motionState->clearOutgoingDirtyFlags(flags); + QSet::iterator stateItr = _incomingChanges.begin(); + while (stateItr != _incomingChanges.end()) { + ObjectMotionState* motionState = *stateItr; + motionState->clearConflictingDirtyFlags(); + uint32_t flags = motionState->getIncomingDirtyFlags() & DIRTY_PHYSICS_FLAGS; + + btRigidBody* body = motionState->_body; + if (body) { + if (flags & HARD_DIRTY_PHYSICS_FLAGS) { + // a HARD update requires the body be pulled out of physics engine, changed, then reinserted + // but it also handles all EASY changes + updateObjectHard(body, motionState, flags); + } else if (flags) { + // an EASY update does NOT require that the body be pulled out of physics engine + updateObjectEasy(body, motionState, flags); } } - entity->clearDirtyFlags(); - ++itemItr; - } - _incomingEntityChanges.clear(); + + motionState->clearIncomingDirtyFlags(flags); + ++stateItr; + } + _incomingChanges.clear(); } // virtual @@ -295,22 +303,6 @@ bool PhysicsEngine::removeObject(ObjectMotionState* motionState) { return false; } -bool PhysicsEngine::updateObject(ObjectMotionState* motionState, uint32_t flags) { - btRigidBody* body = motionState->_body; - if (!body) { - return false; - } - - if (flags & HARD_DIRTY_PHYSICS_FLAGS) { - // a hard update requires the body be pulled out of physics engine, changed, then reinserted - updateObjectHard(body, motionState, flags); - } else if (flags & EASY_DIRTY_PHYSICS_FLAGS) { - // an easy update does not require that the body be pulled out of physics engine - updateObjectEasy(body, motionState, flags); - } - return true; -} - // private void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags) { MotionType newType = motionState->computeMotionType(); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 99a23a9b65..c0145cca0f 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -73,11 +73,6 @@ public: /// \return true if Object removed bool removeObject(ObjectMotionState* motionState); - /// \param motionState pointer to Object's MotionState - /// \param flags set of bits indicating what categories of properties need to be updated - /// \return true if entity updated - bool updateObject(ObjectMotionState* motionState, uint32_t flags); - /// process queue of changed from external sources void relayIncomingChangesToSimulation(); @@ -111,7 +106,7 @@ private: // EntitySimulation stuff QSet _entityMotionStates; // all entities that we track - QSet _incomingEntityChanges; // entities with pending physics changes by script or packet + QSet _incomingChanges; // entities with pending physics changes by script or packet QSet _outgoingPhysics; // MotionStates with pending transform changes from physics simulation EntityEditPacketSender* _entityPacketSender; From 572ceb75a40a725547258d5d5d35c41e90147e69 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 11 Dec 2014 12:07:53 -0800 Subject: [PATCH 075/105] clarification of what outgoing flags are about --- libraries/physics/src/EntityMotionState.cpp | 33 ++++++++++----------- libraries/physics/src/EntityMotionState.h | 1 - libraries/physics/src/ObjectMotionState.cpp | 2 +- libraries/physics/src/ObjectMotionState.h | 5 ++-- libraries/physics/src/PhysicsEngine.cpp | 18 +++++++---- libraries/physics/src/PhysicsEngine.h | 2 +- 6 files changed, 31 insertions(+), 30 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 5fc5f7688b..2d01d49639 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -52,25 +52,22 @@ void EntityMotionState::getWorldTransform (btTransform &worldTrans) const { // This callback is invoked by the physics simulation at the end of each simulation frame... // iff the corresponding RigidBody is DYNAMIC and has moved. void EntityMotionState::setWorldTransform (const btTransform &worldTrans) { - uint32_t dirytFlags = _entity->getDirtyFlags(); - if (! (dirytFlags & EntityItem::DIRTY_POSITION)) { - glm::vec3 pos; - bulletToGLM(worldTrans.getOrigin(), pos); - _entity->setPositionInMeters(pos + ObjectMotionState::getWorldOffset()); - - glm::quat rot; - bulletToGLM(worldTrans.getRotation(), rot); - _entity->setRotation(rot); - } + glm::vec3 pos; + bulletToGLM(worldTrans.getOrigin(), pos); + _entity->setPositionInMeters(pos + ObjectMotionState::getWorldOffset()); - if (! (dirytFlags & EntityItem::DIRTY_VELOCITY)) { - glm::vec3 v; - getVelocity(v); - _entity->setVelocityInMeters(v); - getAngularVelocity(v); - _entity->setAngularVelocity(v); - } - _outgoingDirtyFlags = OUTGOING_DIRTY_PHYSICS_FLAGS; + glm::quat rot; + bulletToGLM(worldTrans.getRotation(), rot); + _entity->setRotation(rot); + + glm::vec3 v; + getVelocity(v); + _entity->setVelocityInMeters(v); + + getAngularVelocity(v); + _entity->setAngularVelocity(v); + + _outgoingPacketFlags = DIRTY_PHYSICS_FLAGS; } #endif // USE_BULLET_PHYSICS diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 562efde87e..3391ed3020 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -56,7 +56,6 @@ public: uint32_t getIncomingDirtyFlags() const { return _entity->getDirtyFlags(); } void clearIncomingDirtyFlags(uint32_t flags) { _entity->clearDirtyFlags(flags); } - void clearConflictingDirtyFlags() { _outgoingDirtyFlags &= ~_entity->getDirtyFlags(); } protected: EntityItem* _entity; diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index b80a996d0c..e2fd2b7a66 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -52,7 +52,7 @@ ObjectMotionState::ObjectMotionState() : _body(NULL), _sentMoving(false), _weKnowRecipientHasReceivedNotMoving(false), - _outgoingDirtyFlags(0), + _outgoingPacketFlags(0), _sentFrame(0), _sentPosition(0.0f), _sentRotation(), diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 1341cb6168..ec9900a6be 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -81,8 +81,7 @@ public: virtual uint32_t getIncomingDirtyFlags() const = 0; virtual void clearIncomingDirtyFlags(uint32_t flags) = 0; - void clearOutgoingDirtyFlags(uint32_t flags) { _outgoingDirtyFlags &= ~flags; } - virtual void clearConflictingDirtyFlags() = 0; + void clearOutgoingPacketFlags(uint32_t flags) { _outgoingPacketFlags &= ~flags; } bool isAtRest() const { return !(_body->isActive()) && _weKnowRecipientHasReceivedNotMoving; } virtual bool shouldSendUpdate(uint32_t simulationFrame, float subStepRemainder) const; @@ -105,7 +104,7 @@ protected: bool _sentMoving; // true if last update was moving bool _weKnowRecipientHasReceivedNotMoving; - uint32_t _outgoingDirtyFlags; + uint32_t _outgoingPacketFlags; uint32_t _sentFrame; glm::vec3 _sentPosition; glm::quat _sentRotation;; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 9fb6bdfe26..9d3f8d80b7 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -9,8 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // // TODO DONE: make _incomingChanges to be list of MotionState*'s. -// TODO: make MotionState able to clear incoming flags +// TODO DONE: make MotionState able to clear incoming flags // TODO: make MotionState::setWorldTransform() put itself on _incomingChanges list +// TODO: make sure incoming and outgoing pipelines are connected // TODO: give PhysicsEngine instance an _entityPacketSender // TODO: provide some sort of "reliable" send for "stopped" update @@ -38,16 +39,16 @@ PhysicsEngine::~PhysicsEngine() { // begin EntitySimulation overrides void PhysicsEngine::updateEntitiesInternal(const quint64& now) { - QSet::iterator stateItr = _outgoingPhysics.begin(); + QSet::iterator stateItr = _outgoingPackets.begin(); uint32_t frame = getFrameCount(); float subStepRemainder = getSubStepRemainder(); - while (stateItr != _outgoingPhysics.end()) { + while (stateItr != _outgoingPackets.end()) { ObjectMotionState* state = *stateItr; if (state->shouldSendUpdate(frame, subStepRemainder)) { state->sendUpdate(_entityPacketSender); ++stateItr; } else if (state->isAtRest()) { - stateItr = _outgoingPhysics.erase(stateItr); + stateItr = _outgoingPackets.erase(stateItr); } else { ++stateItr; } @@ -106,7 +107,6 @@ void PhysicsEngine::relayIncomingChangesToSimulation() { QSet::iterator stateItr = _incomingChanges.begin(); while (stateItr != _incomingChanges.end()) { ObjectMotionState* motionState = *stateItr; - motionState->clearConflictingDirtyFlags(); uint32_t flags = motionState->getIncomingDirtyFlags() & DIRTY_PHYSICS_FLAGS; btRigidBody* body = motionState->_body; @@ -121,7 +121,13 @@ void PhysicsEngine::relayIncomingChangesToSimulation() { } } - motionState->clearIncomingDirtyFlags(flags); + // NOTE: the order of operations is: + // (1) relayIncomingChanges() + // (2) step simulation + // (3) send outgoing packets + // This means incoming changes here (step (1)) should trump corresponding outgoing changes + motionState->clearOutgoingPacketFlags(flags); // trump + motionState->clearIncomingDirtyFlags(flags); // processed ++stateItr; } _incomingChanges.clear(); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index c0145cca0f..9d02486ec1 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -107,7 +107,7 @@ private: // EntitySimulation stuff QSet _entityMotionStates; // all entities that we track QSet _incomingChanges; // entities with pending physics changes by script or packet - QSet _outgoingPhysics; // MotionStates with pending transform changes from physics simulation + QSet _outgoingPackets; // MotionStates with pending changes that need to be sent over wire EntityEditPacketSender* _entityPacketSender; From 4977bfb708a56314da40e041ca112fc0ca690123 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 11 Dec 2014 12:40:43 -0800 Subject: [PATCH 076/105] ObjectMotionState puts self on outgoing queue --- libraries/physics/src/EntityMotionState.cpp | 2 ++ libraries/physics/src/ObjectMotionState.cpp | 13 +++++++++++++ libraries/physics/src/ObjectMotionState.h | 5 +++++ libraries/physics/src/PhysicsEngine.cpp | 6 ++++-- 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 2d01d49639..91a654592c 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -68,6 +68,8 @@ void EntityMotionState::setWorldTransform (const btTransform &worldTrans) { _entity->setAngularVelocity(v); _outgoingPacketFlags = DIRTY_PHYSICS_FLAGS; + + ObjectMotionState::enqueueOutgoingPacket(this); } #endif // USE_BULLET_PHYSICS diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index e2fd2b7a66..90557a1488 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -31,6 +31,7 @@ const float DEFAULT_RESTITUTION = 0.0f; // origin of physics simulation in world frame glm::vec3 _worldOffset(0.0f); +QSet* _outgoingPacketQueue; // static void ObjectMotionState::setWorldOffset(const glm::vec3& offset) { @@ -42,6 +43,18 @@ const glm::vec3& ObjectMotionState::getWorldOffset() { return _worldOffset; } +// static +void ObjectMotionState::setOutgoingPacketQueue(QSet* outgoing) { + assert(outgoing); + _outgoingPacketQueue = outgoing; +} + +// static +void ObjectMotionState::enqueueOutgoingPacket(ObjectMotionState* state) { + assert(_outgoingPacketQueue); + _outgoingPacketQueue->insert(state); +} + ObjectMotionState::ObjectMotionState() : _density(DEFAULT_DENSITY), _volume(DEFAULT_VOLUME), diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index ec9900a6be..6b05740984 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -51,6 +51,11 @@ public: static void setWorldOffset(const glm::vec3& offset); static const glm::vec3& getWorldOffset(); + // The OutgoingPacketQueue is a QSet of ObjectMotionState*'s that need to send update packets to the EntityServer. + // All ObjectMotionState's with outgoing changes put themselves on the list. + static void setOutgoingPacketQueue(QSet* queue); + static void enqueueOutgoingPacket(ObjectMotionState* state); + ObjectMotionState(); ~ObjectMotionState(); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 9d3f8d80b7..107222af1a 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -10,10 +10,11 @@ // // TODO DONE: make _incomingChanges to be list of MotionState*'s. // TODO DONE: make MotionState able to clear incoming flags -// TODO: make MotionState::setWorldTransform() put itself on _incomingChanges list -// TODO: make sure incoming and outgoing pipelines are connected +// TODO DONE: make MotionState::setWorldTransform() put itself on _incomingChanges list // TODO: give PhysicsEngine instance an _entityPacketSender +// TODO: make sure incoming and outgoing pipelines are connected // TODO: provide some sort of "reliable" send for "stopped" update +// TODO: make sure code compiles when BULLET is not found #include "PhysicsEngine.h" #ifdef USE_BULLET_PHYSICS @@ -165,6 +166,7 @@ void PhysicsEngine::init() { _dynamicsWorld->addCollisionObject(groundObject); } } + ObjectMotionState::setOutgoingPacketQueue(&_outgoingPackets); } const float FIXED_SUBSTEP = 1.0f / 60.0f; From c3f8f8ab982d7647e4a194bcb560d14648ac5050 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 11 Dec 2014 13:29:29 -0800 Subject: [PATCH 077/105] init PhysicsEngine with an EntityEditPacketSender --- interface/src/Application.cpp | 2 +- libraries/physics/src/PhysicsEngine.cpp | 8 ++++++-- libraries/physics/src/PhysicsEngine.h | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 70587bf2f7..e18fc1b7a9 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2070,7 +2070,7 @@ void Application::init() { EntityTree* tree = _entities.getTree(); _physicsEngine.setEntityTree(tree); tree->setSimulation(&_physicsEngine); - _physicsEngine.init(); + _physicsEngine.init(&_entityEditSender); #endif // USE_BULLET_PHYSICS } diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 107222af1a..3b6c48b3b4 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -11,7 +11,7 @@ // TODO DONE: make _incomingChanges to be list of MotionState*'s. // TODO DONE: make MotionState able to clear incoming flags // TODO DONE: make MotionState::setWorldTransform() put itself on _incomingChanges list -// TODO: give PhysicsEngine instance an _entityPacketSender +// TODO DONE: give PhysicsEngine instance an _entityPacketSender // TODO: make sure incoming and outgoing pipelines are connected // TODO: provide some sort of "reliable" send for "stopped" update // TODO: make sure code compiles when BULLET is not found @@ -32,6 +32,7 @@ PhysicsEngine::PhysicsEngine(const glm::vec3& offset) _dynamicsWorld(NULL), _originOffset(offset), _voxels(), + _entityPacketSender(NULL), _frameCount(0) { } @@ -135,7 +136,7 @@ void PhysicsEngine::relayIncomingChangesToSimulation() { } // virtual -void PhysicsEngine::init() { +void PhysicsEngine::init(EntityEditPacketSender* packetSender) { // _entityTree should be set prior to the init() call assert(_entityTree); @@ -166,6 +167,9 @@ void PhysicsEngine::init() { _dynamicsWorld->addCollisionObject(groundObject); } } + + assert(packetSender); + _entityPacketSender = packetSender; ObjectMotionState::setOutgoingPacketQueue(&_outgoingPackets); } diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 9d02486ec1..0e995636d8 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -45,7 +45,7 @@ public: void entityChangedInternal(EntityItem* entity); void clearEntitiesInternal(); - virtual void init(); + virtual void init(EntityEditPacketSender* packetSender); void stepSimulation(); From ad7641c7e00ef37d935dc33122e2f59950ed1c98 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 11 Dec 2014 16:05:45 -0800 Subject: [PATCH 078/105] repairs to build when Bullet not found --- libraries/physics/src/EntityMotionState.cpp | 2 ++ libraries/physics/src/EntityMotionState.h | 3 +-- libraries/physics/src/ObjectMotionState.h | 24 +++++++++---------- libraries/physics/src/PhysicsEngine.cpp | 3 ++- .../physics/src/ThreadSafeDynamicsWorld.cpp | 2 ++ .../physics/src/ThreadSafeDynamicsWorld.h | 13 ++++++++-- tests/physics/src/ShapeInfoTests.cpp | 2 ++ 7 files changed, 32 insertions(+), 17 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 91a654592c..66d15115fb 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -97,6 +97,7 @@ void EntityMotionState::computeShapeInfo(ShapeInfo& info) { } void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender) { +#ifdef USE_BULLET_PHYSICS if (_outgoingPhysicsDirtyFlags) { EntityItemProperties properties = _entity->getProperties(); @@ -157,4 +158,5 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender) { entityPacketSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties); } _outgoingPhysicsDirtyFlags = 0; +#endif // USE_BULLET_PHYSICS } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 3391ed3020..b411d256ca 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -14,9 +14,8 @@ #include -#ifdef USE_BULLET_PHYSICS #include "ObjectMotionState.h" -#else // USE_BULLET_PHYSICS +#ifndef USE_BULLET_PHYSICS // ObjectMotionState stubbery class ObjectMotionState { public: diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 6b05740984..9b0db65e0a 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -12,13 +12,11 @@ #ifndef hifi_ObjectMotionState_h #define hifi_ObjectMotionState_h -#ifdef USE_BULLET_PHYSICS - -#include -#include -#include // for EntityItem::DIRTY_FOO bitmasks - -#include "ShapeInfo.h" +enum MotionType { + MOTION_TYPE_STATIC, // no motion + MOTION_TYPE_DYNAMIC, // motion according to physical laws + MOTION_TYPE_KINEMATIC // keyframed motion +}; // The update flags trigger two varieties of updates: "hard" which require the body to be pulled // and re-added to the physics engine and "easy" which just updates the body properties. @@ -33,11 +31,13 @@ const uint32_t DIRTY_PHYSICS_FLAGS = HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSI // These are the outgoing flags that the PhysicsEngine can affect: const uint32_t OUTGOING_DIRTY_PHYSICS_FLAGS = EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY; -enum MotionType { - MOTION_TYPE_STATIC, // no motion - MOTION_TYPE_DYNAMIC, // motion according to physical laws - MOTION_TYPE_KINEMATIC // keyframed motion -}; +#ifdef USE_BULLET_PHYSICS + +#include +#include +#include // for EntityItem::DIRTY_FOO bitmasks + +#include "ShapeInfo.h" class OctreeEditPacketSender; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 3b6c48b3b4..465a56c7fc 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -12,9 +12,10 @@ // TODO DONE: make MotionState able to clear incoming flags // TODO DONE: make MotionState::setWorldTransform() put itself on _incomingChanges list // TODO DONE: give PhysicsEngine instance an _entityPacketSender +// TODO DONE: make sure code compiles when BULLET is not found // TODO: make sure incoming and outgoing pipelines are connected // TODO: provide some sort of "reliable" send for "stopped" update -// TODO: make sure code compiles when BULLET is not found +// TODO: test entity updates (second viewer sees physics results from first) #include "PhysicsEngine.h" #ifdef USE_BULLET_PHYSICS diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp index 4660e02c2f..e70bdc7210 100644 --- a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp @@ -19,6 +19,7 @@ #include "ThreadSafeDynamicsWorld.h" +#ifdef USE_BULLET_PHYSICS ThreadSafeDynamicsWorld::ThreadSafeDynamicsWorld( btDispatcher* dispatcher, btBroadphaseInterface* pairCache, @@ -87,3 +88,4 @@ int ThreadSafeDynamicsWorld::stepSimulation( btScalar timeStep, int maxSubSteps, clearForces(); return subSteps; } +#endif // USE_BULLET_PHYSICS diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.h b/libraries/physics/src/ThreadSafeDynamicsWorld.h index 96cff8bda1..3f3bc2517b 100644 --- a/libraries/physics/src/ThreadSafeDynamicsWorld.h +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.h @@ -18,12 +18,12 @@ #ifndef hifi_ThreadSafeDynamicsWorld_h #define hifi_ThreadSafeDynamicsWorld_h +#ifdef USE_BULLET_PHYSICS #include class EntityTree; -ATTRIBUTE_ALIGNED16(class) ThreadSafeDynamicsWorld : public btDiscreteDynamicsWorld -{ +ATTRIBUTE_ALIGNED16(class) ThreadSafeDynamicsWorld : public btDiscreteDynamicsWorld { public: BT_DECLARE_ALIGNED_ALLOCATOR(); @@ -47,4 +47,13 @@ private: EntityTree* _entities; }; +#else // USE_BULLET_PHYSICS +// stubbery for ThreadSafeDynamicsWorld when Bullet not available +class ThreadSafeDynamicsWorld { +public: + ThreadSafeDynamicsWorld() {} +}; + +#endif // USE_BULLET_PHYSICS + #endif // hifi_ThreadSafeDynamicsWorld_h diff --git a/tests/physics/src/ShapeInfoTests.cpp b/tests/physics/src/ShapeInfoTests.cpp index 8784ce1266..a4db3a5764 100644 --- a/tests/physics/src/ShapeInfoTests.cpp +++ b/tests/physics/src/ShapeInfoTests.cpp @@ -11,8 +11,10 @@ #include +#ifdef USE_BULLET_PHYSICS #include #include +#endif // USE_BULLET_PHYSICS #include #include From fd8e3f6169840d4a2b5f3d915a4abe14d33954ca Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 12 Dec 2014 13:28:12 -0800 Subject: [PATCH 079/105] add moved entities to lists for sorting and also for outgoing packet updates --- libraries/entities/src/EntitySimulation.cpp | 10 ++- libraries/entities/src/EntitySimulation.h | 8 +++ .../entities/src/SimpleEntitySimulation.cpp | 1 + libraries/physics/src/EntityMotionState.cpp | 38 +++++++---- libraries/physics/src/EntityMotionState.h | 8 ++- libraries/physics/src/ObjectMotionState.cpp | 33 +++------ libraries/physics/src/ObjectMotionState.h | 15 ++-- libraries/physics/src/PhysicsEngine.cpp | 68 +++++++++++++++---- libraries/physics/src/PhysicsEngine.h | 3 +- 9 files changed, 119 insertions(+), 65 deletions(-) diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index 223df588d5..0090b2d862 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -101,13 +101,14 @@ void EntitySimulation::sortEntitiesThatMoved() { } ++itemItr; } - _entitiesToBeSorted.clear(); - if (moveOperator.hasMovingEntities()) { PerformanceTimer perfTimer("recurseTreeWithOperator"); _entityTree->recurseTreeWithOperator(&moveOperator); moveOperator.finish(); } + + sortEntitiesThatMovedInternal(); + _entitiesToBeSorted.clear(); } void EntitySimulation::addEntity(EntityItem* entity) { @@ -123,6 +124,10 @@ void EntitySimulation::addEntity(EntityItem* entity) { _updateableEntities.insert(entity); } addEntityInternal(entity); + + // DirtyFlags are used to signal changes to entities that have already been added, + // so we can clear them for this entity which has just been added. + entity->clearDirtyFlags(); } void EntitySimulation::removeEntity(EntityItem* entity) { @@ -174,7 +179,6 @@ void EntitySimulation::entityChanged(EntityItem* entity) { } entityChangedInternal(entity); } - entity->clearDirtyFlags(); } void EntitySimulation::clearEntities() { diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index c87521e8a3..a32a1226c7 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -62,10 +62,18 @@ protected: // These pure virtual methods are protected because they are not to be called will-nilly. The base class // calls them in the right places. + + // NOTE: updateEntitiesInternal() should clear all dirty flags on each changed entity as side effect virtual void updateEntitiesInternal(const quint64& now) = 0; + virtual void addEntityInternal(EntityItem* entity) = 0; + virtual void removeEntityInternal(EntityItem* entity) = 0; + virtual void entityChangedInternal(EntityItem* entity) = 0; + + virtual void sortEntitiesThatMovedInternal() {} + virtual void clearEntitiesInternal() = 0; void expireMortalEntities(const quint64& now); diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index 84d8e16f2c..6d45768c26 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -56,6 +56,7 @@ void SimpleEntitySimulation::entityChangedInternal(EntityItem* entity) { _movableButStoppedEntities.remove(entity); } } + entity->clearDirtyFlags(); } void SimpleEntitySimulation::clearEntitiesInternal() { diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 66d15115fb..a4fd5cc498 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -17,9 +17,22 @@ #endif // USE_BULLET_PHYSICS #include "EntityMotionState.h" +QSet* _outgoingEntityList; + +// static +void EntityMotionState::setOutgoingEntityList(QSet* list) { + assert(list); + _outgoingEntityList = list; +} + +// static +void EntityMotionState::enqueueOutgoingEntity(EntityItem* entity) { + assert(_outgoingEntityList); + _outgoingEntityList->insert(entity); +} + EntityMotionState::EntityMotionState(EntityItem* entity) - : _entity(entity), - _outgoingPhysicsDirtyFlags(0) { + : _entity(entity) { assert(entity != NULL); } @@ -68,8 +81,7 @@ void EntityMotionState::setWorldTransform (const btTransform &worldTrans) { _entity->setAngularVelocity(v); _outgoingPacketFlags = DIRTY_PHYSICS_FLAGS; - - ObjectMotionState::enqueueOutgoingPacket(this); + EntityMotionState::enqueueOutgoingEntity(_entity); } #endif // USE_BULLET_PHYSICS @@ -98,11 +110,12 @@ void EntityMotionState::computeShapeInfo(ShapeInfo& info) { void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender) { #ifdef USE_BULLET_PHYSICS - if (_outgoingPhysicsDirtyFlags) { + if (_outgoingPacketFlags) { EntityItemProperties properties = _entity->getProperties(); - if (_outgoingPhysicsDirtyFlags == OUTGOING_DIRTY_PHYSICS_FLAGS) { - // common case: physics engine has changed object position/velocity + if (_outgoingPacketFlags == OUTGOING_DIRTY_PHYSICS_FLAGS) { + // all outgoing physics flags are set + // This is the common case: physics engine has changed object position/velocity. btTransform worldTrans = _body->getWorldTransform(); bulletToGLM(worldTrans.getOrigin(), _sentPosition); @@ -122,10 +135,11 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender) { properties.setGravity(_sentAcceleration); properties.setAngularVelocity(_sentAngularVelocity); } else { - // uncommon case: physics engine change collided with incoming external change - // we only send data for flags that are set + // subset of outgoing physics flags are set + // This is an uncommon case: physics engine change collided with incoming external change + // we only send data for flags that haven't been cleared. - if (_outgoingPhysicsDirtyFlags & EntityItem::DIRTY_POSITION) { + if (_outgoingPacketFlags & EntityItem::DIRTY_POSITION) { btTransform worldTrans = _body->getWorldTransform(); bulletToGLM(worldTrans.getOrigin(), _sentPosition); properties.setPosition(_sentPosition + ObjectMotionState::getWorldOffset()); @@ -134,7 +148,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender) { properties.setRotation(_sentRotation); } - if (_outgoingPhysicsDirtyFlags & EntityItem::DIRTY_VELOCITY) { + if (_outgoingPacketFlags & EntityItem::DIRTY_VELOCITY) { if (_body->isActive()) { bulletToGLM(_body->getLinearVelocity(), _sentVelocity); bulletToGLM(_body->getAngularVelocity(), _sentAngularVelocity); @@ -156,7 +170,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender) { EntityItemID id(_entity->getID()); EntityEditPacketSender* entityPacketSender = static_cast(packetSender); entityPacketSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties); + _outgoingPacketFlags = 0; } - _outgoingPhysicsDirtyFlags = 0; #endif // USE_BULLET_PHYSICS } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index b411d256ca..87dd3b14eb 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -31,6 +31,13 @@ class EntityItem; class EntityMotionState : public ObjectMotionState { public: + + // The OutgoingEntityQueue is a pointer to a QSet (owned by an EntitySimulation) of EntityItem*'s + // that have been changed by the physics simulation. + // All ObjectMotionState's with outgoing changes put themselves on the list. + static void setOutgoingEntityList(QSet* list); + static void enqueueOutgoingEntity(EntityItem* entity); + EntityMotionState(EntityItem* item); virtual ~EntityMotionState(); @@ -58,7 +65,6 @@ public: protected: EntityItem* _entity; - uint32_t _outgoingPhysicsDirtyFlags; }; #endif // hifi_EntityMotionState_h diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 90557a1488..da23a4093c 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -31,7 +31,6 @@ const float DEFAULT_RESTITUTION = 0.0f; // origin of physics simulation in world frame glm::vec3 _worldOffset(0.0f); -QSet* _outgoingPacketQueue; // static void ObjectMotionState::setWorldOffset(const glm::vec3& offset) { @@ -43,17 +42,6 @@ const glm::vec3& ObjectMotionState::getWorldOffset() { return _worldOffset; } -// static -void ObjectMotionState::setOutgoingPacketQueue(QSet* outgoing) { - assert(outgoing); - _outgoingPacketQueue = outgoing; -} - -// static -void ObjectMotionState::enqueueOutgoingPacket(ObjectMotionState* state) { - assert(_outgoingPacketQueue); - _outgoingPacketQueue->insert(state); -} ObjectMotionState::ObjectMotionState() : _density(DEFAULT_DENSITY), @@ -127,24 +115,23 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame, float subStep assert(_body); float dt = (float)(simulationFrame - _sentFrame) * FIXED_SUBSTEP + subStepRemainder; const float DEFAULT_UPDATE_PERIOD = 10.0f; - if (dt > DEFAULT_UPDATE_PERIOD) { - return !isAtRest(); - } - if (_sentMoving && !_body->isActive()) { + if (dt > DEFAULT_UPDATE_PERIOD || (_sentMoving && !_body->isActive())) { return true; } + // Else we measure the error between current and extrapolated transform (according to expected behavior + // of remote EntitySimulation) and return true if the error is significant. - // NOTE: math in done the simulation-frame, which is NOT necessarily the same - // as the world-frame due to _worldOffset + // NOTE: math in done the simulation-frame, which is NOT necessarily the same as the world-frame + // due to _worldOffset. // compute position error - glm::vec3 expectedPosition = _sentPosition + dt * (_sentVelocity + (0.5f * dt) * _sentAcceleration); + glm::vec3 extrapolatedPosition = _sentPosition + dt * (_sentVelocity + (0.5f * dt) * _sentAcceleration); glm::vec3 position; btTransform worldTrans = _body->getWorldTransform(); bulletToGLM(worldTrans.getOrigin(), position); - float dx2 = glm::length2(position - expectedPosition); + float dx2 = glm::length2(position - extrapolatedPosition); const float MAX_POSITION_ERROR_SQUARED = 0.001f; // 0.001 m^2 ~~> 0.03 m if (dx2 > MAX_POSITION_ERROR_SQUARED) { return true; @@ -152,16 +139,16 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame, float subStep // compute rotation error float spin = glm::length(_sentAngularVelocity); - glm::quat expectedRotation = _sentRotation; + glm::quat extrapolatedRotation = _sentRotation; const float MIN_SPIN = 1.0e-4f; if (spin > MIN_SPIN) { glm::vec3 axis = _sentAngularVelocity / spin; - expectedRotation = glm::angleAxis(dt * spin, axis) * _sentRotation; + extrapolatedRotation = glm::angleAxis(dt * spin, axis) * _sentRotation; } const float MIN_ROTATION_DOT = 0.98f; glm::quat actualRotation; bulletToGLM(worldTrans.getRotation(), actualRotation); - return (glm::dot(actualRotation, expectedRotation) < MIN_ROTATION_DOT); + return (glm::dot(actualRotation, extrapolatedRotation) < MIN_ROTATION_DOT); } #endif // USE_BULLET_PHYSICS diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 9b0db65e0a..5e441a4746 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -12,6 +12,8 @@ #ifndef hifi_ObjectMotionState_h #define hifi_ObjectMotionState_h +#include + enum MotionType { MOTION_TYPE_STATIC, // no motion MOTION_TYPE_DYNAMIC, // motion according to physical laws @@ -51,18 +53,9 @@ public: static void setWorldOffset(const glm::vec3& offset); static const glm::vec3& getWorldOffset(); - // The OutgoingPacketQueue is a QSet of ObjectMotionState*'s that need to send update packets to the EntityServer. - // All ObjectMotionState's with outgoing changes put themselves on the list. - static void setOutgoingPacketQueue(QSet* queue); - static void enqueueOutgoingPacket(ObjectMotionState* state); - ObjectMotionState(); ~ObjectMotionState(); - //// these override methods of the btMotionState base class - //virtual void getWorldTransform (btTransform &worldTrans) const; - //virtual void setWorldTransform (const btTransform &worldTrans); - virtual void applyVelocities() const = 0; virtual void applyGravity() const = 0; @@ -88,7 +81,7 @@ public: virtual void clearIncomingDirtyFlags(uint32_t flags) = 0; void clearOutgoingPacketFlags(uint32_t flags) { _outgoingPacketFlags &= ~flags; } - bool isAtRest() const { return !(_body->isActive()) && _weKnowRecipientHasReceivedNotMoving; } + bool doesNotNeedToSendUpdate() const { return !_body->isActive() && _weKnowRecipientHasReceivedNotMoving; } virtual bool shouldSendUpdate(uint32_t simulationFrame, float subStepRemainder) const; virtual void sendUpdate(OctreeEditPacketSender* packetSender) = 0; @@ -111,7 +104,7 @@ protected: uint32_t _outgoingPacketFlags; uint32_t _sentFrame; - glm::vec3 _sentPosition; + glm::vec3 _sentPosition; // in simulation-frame (not world-frame) glm::quat _sentRotation;; glm::vec3 _sentVelocity; glm::vec3 _sentAngularVelocity; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 465a56c7fc..198946e96d 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -42,16 +42,23 @@ PhysicsEngine::~PhysicsEngine() { // begin EntitySimulation overrides void PhysicsEngine::updateEntitiesInternal(const quint64& now) { + // NOTE: the grand order of operations is: + // (1) relay incoming changes + // (2) step simulation + // (3) synchronize outgoing motion states + // (4) send outgoing packets + + // this is step (4) QSet::iterator stateItr = _outgoingPackets.begin(); uint32_t frame = getFrameCount(); float subStepRemainder = getSubStepRemainder(); while (stateItr != _outgoingPackets.end()) { ObjectMotionState* state = *stateItr; - if (state->shouldSendUpdate(frame, subStepRemainder)) { + if (state->doesNotNeedToSendUpdate()) { + stateItr = _outgoingPackets.erase(stateItr); + } else if (state->shouldSendUpdate(frame, subStepRemainder)) { state->sendUpdate(_entityPacketSender); ++stateItr; - } else if (state->isAtRest()) { - stateItr = _outgoingPackets.erase(stateItr); } else { ++stateItr; } @@ -63,11 +70,12 @@ void PhysicsEngine::addEntityInternal(EntityItem* entity) { void* physicsInfo = entity->getPhysicsInfo(); if (!physicsInfo) { EntityMotionState* motionState = new EntityMotionState(entity); - _entityMotionStates.insert(motionState); if (addObject(motionState)) { entity->setPhysicsInfo(static_cast(motionState)); + _entityMotionStates.insert(motionState); } else { - // We failed to add the object to the simulation. Probably because we couldn't create a shape for it. + // We failed to add the entity to the simulation. Probably because we couldn't create a shape for it. + qDebug() << "failed to add entity " << entity->getEntityItemID() << " to physics engine"; delete motionState; } } @@ -81,6 +89,8 @@ void PhysicsEngine::removeEntityInternal(EntityItem* entity) { removeObject(motionState); entity->setPhysicsInfo(NULL); _entityMotionStates.remove(motionState); + _incomingChanges.remove(motionState); + _outgoingPackets.remove(motionState); } } @@ -91,6 +101,23 @@ void PhysicsEngine::entityChangedInternal(EntityItem* entity) { if (physicsInfo) { ObjectMotionState* motionState = static_cast(physicsInfo); _incomingChanges.insert(motionState); + } else { + // try to add this entity again (maybe something changed such that it will work this time) + addEntity(entity); + } +} + +void PhysicsEngine::sortEntitiesThatMovedInternal() { + // entities that have been simulated forward (hence in the _entitiesToBeSorted list) + // also need to be put in the outgoingPackets list + QSet::iterator entityItr = _entitiesToBeSorted.begin(); + while (entityItr != _entitiesToBeSorted.end()) { + EntityItem* entity = *entityItr; + void* physicsInfo = entity->getPhysicsInfo(); + assert(physicsInfo); + ObjectMotionState* motionState = static_cast(physicsInfo); + _outgoingPackets.insert(motionState); + ++entityItr; } } @@ -102,6 +129,7 @@ void PhysicsEngine::clearEntitiesInternal() { } _entityMotionStates.clear(); _incomingChanges.clear(); + _outgoingPackets.clear(); } // end EntitySimulation overrides @@ -124,13 +152,16 @@ void PhysicsEngine::relayIncomingChangesToSimulation() { } } - // NOTE: the order of operations is: - // (1) relayIncomingChanges() + // NOTE: the grand order of operations is: + // (1) relay incoming changes // (2) step simulation - // (3) send outgoing packets - // This means incoming changes here (step (1)) should trump corresponding outgoing changes - motionState->clearOutgoingPacketFlags(flags); // trump - motionState->clearIncomingDirtyFlags(flags); // processed + // (3) synchronize outgoing motion states + // (4) send outgoing packets + // + // We're in the middle of step (1) hence incoming changes should trump corresponding + // outgoing changes at this point. + motionState->clearOutgoingPacketFlags(flags); // clear outgoing flags that were trumped + motionState->clearIncomingDirtyFlags(flags); // clear incoming flags that were processed ++stateItr; } _incomingChanges.clear(); @@ -171,19 +202,28 @@ void PhysicsEngine::init(EntityEditPacketSender* packetSender) { assert(packetSender); _entityPacketSender = packetSender; - ObjectMotionState::setOutgoingPacketQueue(&_outgoingPackets); + EntityMotionState::setOutgoingEntityList(&_entitiesToBeSorted); } const float FIXED_SUBSTEP = 1.0f / 60.0f; void PhysicsEngine::stepSimulation() { + // NOTE: the grand order of operations is: + // (1) relay incoming changes + // (2) step simulation + // (3) synchronize outgoing motion states + // (4) send outgoing packets + + // this is step (1) + relayIncomingChangesToSimulation(); + const int MAX_NUM_SUBSTEPS = 4; const float MAX_TIMESTEP = (float)MAX_NUM_SUBSTEPS * FIXED_SUBSTEP; - float dt = 1.0e-6f * (float)(_clock.getTimeMicroseconds()); _clock.reset(); float timeStep = btMin(dt, MAX_TIMESTEP); - // TODO: Andrew to build a list of outgoingChanges when motionStates are synched, then send the updates out + + // steps (2) and (3) are performed by ThreadSafeDynamicsWorld::stepSimulation()) int numSubSteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, FIXED_SUBSTEP); _frameCount += (uint32_t)numSubSteps; } diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 0e995636d8..5d506fced6 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -38,11 +38,12 @@ public: ~PhysicsEngine(); - // overrides from EntitySimulation + // overrides for EntitySimulation void updateEntitiesInternal(const quint64& now); void addEntityInternal(EntityItem* entity); void removeEntityInternal(EntityItem* entity); void entityChangedInternal(EntityItem* entity); + void sortEntitiesThatMovedInternal(); void clearEntitiesInternal(); virtual void init(EntityEditPacketSender* packetSender); From 0f488bca023f5771c91414c94dcc0efeb0a94229 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 15 Dec 2014 14:28:53 -0800 Subject: [PATCH 080/105] differentiation btw _lastEdited and _lastSimulated --- libraries/entities/src/EntityItem.cpp | 10 +++++++--- libraries/entities/src/EntityItem.h | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 0faea7cc1c..d2e3acb86d 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -458,7 +458,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef ByteCountCoded updateDeltaCoder = encodedUpdateDelta; quint64 updateDelta = updateDeltaCoder; if (overwriteLocalData) { - _lastSimulated = _lastUpdated = lastEditedFromBufferAdjusted + updateDelta; // don't adjust for clock skew since we already did that for _lastEdited + _lastUpdated = lastEditedFromBufferAdjusted + updateDelta; // don't adjust for clock skew since we already did that for _lastEdited + _lastSimulated = now; if (wantDebug) { qDebug() << "_lastUpdated =" << _lastUpdated; qDebug() << "_lastEdited=" << _lastEdited; @@ -619,8 +620,6 @@ void EntityItem::simulate(const quint64& now) { } } - _lastSimulated = now; - if (wantDebug) { qDebug() << " ********** EntityItem::update() .... SETTING _lastSimulated=" << _lastSimulated; } @@ -730,6 +729,8 @@ void EntityItem::simulate(const quint64& now) { } } } + + _lastSimulated = now; } bool EntityItem::isMoving() const { @@ -819,6 +820,9 @@ bool EntityItem::setProperties(const EntityItemProperties& properties, bool forc "now=" << now << " getLastEdited()=" << getLastEdited(); } setLastEdited(properties._lastEdited); + if (getDirtyFlags() & EntityItem::DIRTY_POSITION) { + _lastSimulated = usecTimestampNow(); + } } return somethingChanged; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index c01e9b9ceb..ef88cb772f 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -86,7 +86,7 @@ public: /// Last edited time of this entity universal usecs quint64 getLastEdited() const { return _lastEdited; } void setLastEdited(quint64 lastEdited) - { _lastEdited = _lastSimulated = _lastUpdated = lastEdited; _changedOnServer = glm::max(lastEdited, _changedOnServer); } + { _lastEdited = _lastUpdated = lastEdited; _changedOnServer = glm::max(lastEdited, _changedOnServer); } float getEditedAgo() const /// Elapsed seconds since this entity was last edited { return (float)(usecTimestampNow() - getLastEdited()) / (float)USECS_PER_SECOND; } From b3731e95308ce2f50e2770ed6005cda122e4b899 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 15 Dec 2014 14:36:27 -0800 Subject: [PATCH 081/105] hack for "reliable" packet send when objects stop moving --- libraries/physics/src/EntityMotionState.cpp | 16 +++++++-- libraries/physics/src/EntityMotionState.h | 2 +- libraries/physics/src/ObjectMotionState.cpp | 39 +++++++++++++++++---- libraries/physics/src/ObjectMotionState.h | 6 ++-- libraries/physics/src/PhysicsEngine.cpp | 6 ++-- 5 files changed, 53 insertions(+), 16 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index a4fd5cc498..bb87155bc3 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -108,7 +108,7 @@ void EntityMotionState::computeShapeInfo(ShapeInfo& info) { _entity->computeShapeInfo(info); } -void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender) { +void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame) { #ifdef USE_BULLET_PHYSICS if (_outgoingPacketFlags) { EntityItemProperties properties = _entity->getProperties(); @@ -165,12 +165,22 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender) { //properties.setLastEdited(now); glm::vec3 zero(0.0f); - _sentMoving = (_sentVelocity == zero && _sentAngularVelocity == zero && _sentAcceleration == zero); + _sentMoving = !(_sentVelocity == zero && _sentAngularVelocity == zero && _sentAcceleration == zero); + // RELIABLE_SEND_HACK: count number of updates for entities at rest so we can stop sending them after some limit. + if (_sentMoving) { + _numNonMovingUpdates = 0; + } else { + _numNonMovingUpdates++; + } EntityItemID id(_entity->getID()); EntityEditPacketSender* entityPacketSender = static_cast(packetSender); entityPacketSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties); - _outgoingPacketFlags = 0; + + // The outgoing flags only itemized WHAT to send, not WHETHER to send, hence we always set them + // to the full set. These flags may be momentarily cleared by incoming external changes. + _outgoingPacketFlags = DIRTY_PHYSICS_FLAGS; + _sentFrame = frame; } #endif // USE_BULLET_PHYSICS } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 87dd3b14eb..ffd9e006e9 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -58,7 +58,7 @@ public: void computeShapeInfo(ShapeInfo& info); - void sendUpdate(OctreeEditPacketSender* packetSender); + void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame); uint32_t getIncomingDirtyFlags() const { return _entity->getDirtyFlags(); } void clearIncomingDirtyFlags(uint32_t flags) { _entity->clearDirtyFlags(flags); } diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index da23a4093c..1d315d4983 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -52,8 +52,8 @@ ObjectMotionState::ObjectMotionState() : _motionType(MOTION_TYPE_STATIC), _body(NULL), _sentMoving(false), - _weKnowRecipientHasReceivedNotMoving(false), - _outgoingPacketFlags(0), + _numNonMovingUpdates(0), + _outgoingPacketFlags(DIRTY_PHYSICS_FLAGS), _sentFrame(0), _sentPosition(0.0f), _sentRotation(), @@ -109,21 +109,48 @@ void ObjectMotionState::getAngularVelocity(glm::vec3& angularVelocityOut) const bulletToGLM(_body->getAngularVelocity(), angularVelocityOut); } +// RELIABLE_SEND_HACK: until we have truly reliable resends of non-moving updates +// we alwasy resend packets for objects that have stopped moving up to some max limit. +const int MAX_NUM_NON_MOVING_UPDATES = 5; + +bool ObjectMotionState::doesNotNeedToSendUpdate() const { + return !_body->isActive() && _numNonMovingUpdates > MAX_NUM_NON_MOVING_UPDATES; +} + const float FIXED_SUBSTEP = 1.0f / 60.0f; bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame, float subStepRemainder) const { assert(_body); float dt = (float)(simulationFrame - _sentFrame) * FIXED_SUBSTEP + subStepRemainder; - const float DEFAULT_UPDATE_PERIOD = 10.0f; - if (dt > DEFAULT_UPDATE_PERIOD || (_sentMoving && !_body->isActive())) { - return true; + bool isActive = _body->isActive(); + + if (isActive) { + const float MAX_UPDATE_PERIOD_FOR_ACTIVE_THINGS = 10.0f; + if (dt > MAX_UPDATE_PERIOD_FOR_ACTIVE_THINGS) { + return true; + } + } else if (_sentMoving) { + if (!isActive) { + // this object just went inactive so send an update immediately + return true; + } + } else { + const float NON_MOVING_UPDATE_PERIOD = 1.0f; + if (dt > NON_MOVING_UPDATE_PERIOD && _numNonMovingUpdates < MAX_NUM_NON_MOVING_UPDATES) { + // RELIABLE_SEND_HACK: since we're not yet using a reliable method for non-moving update packets we repeat these + // at a faster rate than the MAX period above, and only send a limited number of them. + return true; + } } + // Else we measure the error between current and extrapolated transform (according to expected behavior // of remote EntitySimulation) and return true if the error is significant. // NOTE: math in done the simulation-frame, which is NOT necessarily the same as the world-frame // due to _worldOffset. + // TODO: Andrew to reconcile Bullet and legacy damping coefficients. + // compute position error glm::vec3 extrapolatedPosition = _sentPosition + dt * (_sentVelocity + (0.5f * dt) * _sentAcceleration); @@ -131,7 +158,7 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame, float subStep btTransform worldTrans = _body->getWorldTransform(); bulletToGLM(worldTrans.getOrigin(), position); - float dx2 = glm::length2(position - extrapolatedPosition); + float dx2 = glm::distance2(position, extrapolatedPosition); const float MAX_POSITION_ERROR_SQUARED = 0.001f; // 0.001 m^2 ~~> 0.03 m if (dx2 > MAX_POSITION_ERROR_SQUARED) { return true; diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 5e441a4746..ea9dcad0fc 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -81,9 +81,9 @@ public: virtual void clearIncomingDirtyFlags(uint32_t flags) = 0; void clearOutgoingPacketFlags(uint32_t flags) { _outgoingPacketFlags &= ~flags; } - bool doesNotNeedToSendUpdate() const { return !_body->isActive() && _weKnowRecipientHasReceivedNotMoving; } + bool doesNotNeedToSendUpdate() const; virtual bool shouldSendUpdate(uint32_t simulationFrame, float subStepRemainder) const; - virtual void sendUpdate(OctreeEditPacketSender* packetSender) = 0; + virtual void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame) = 0; virtual MotionType computeMotionType() const = 0; @@ -100,7 +100,7 @@ protected: btRigidBody* _body; bool _sentMoving; // true if last update was moving - bool _weKnowRecipientHasReceivedNotMoving; + int _numNonMovingUpdates; // RELIABLE_SEND_HACK for "not so reliable" resends of packets for non-moving objects uint32_t _outgoingPacketFlags; uint32_t _sentFrame; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 198946e96d..f0f080e7c1 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -13,9 +13,9 @@ // TODO DONE: make MotionState::setWorldTransform() put itself on _incomingChanges list // TODO DONE: give PhysicsEngine instance an _entityPacketSender // TODO DONE: make sure code compiles when BULLET is not found -// TODO: make sure incoming and outgoing pipelines are connected -// TODO: provide some sort of "reliable" send for "stopped" update +// TODO DONE: make sure incoming and outgoing pipelines are connected // TODO: test entity updates (second viewer sees physics results from first) +// TODO: provide some sort of "reliable" send for "stopped" update #include "PhysicsEngine.h" #ifdef USE_BULLET_PHYSICS @@ -57,7 +57,7 @@ void PhysicsEngine::updateEntitiesInternal(const quint64& now) { if (state->doesNotNeedToSendUpdate()) { stateItr = _outgoingPackets.erase(stateItr); } else if (state->shouldSendUpdate(frame, subStepRemainder)) { - state->sendUpdate(_entityPacketSender); + state->sendUpdate(_entityPacketSender, frame); ++stateItr; } else { ++stateItr; From 31486a81c192f2a5320433b8da5cdb14f33ffef4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 15 Dec 2014 14:41:04 -0800 Subject: [PATCH 082/105] updated TODO notes --- libraries/physics/src/PhysicsEngine.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index f0f080e7c1..4d0d48ddfc 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -14,8 +14,9 @@ // TODO DONE: give PhysicsEngine instance an _entityPacketSender // TODO DONE: make sure code compiles when BULLET is not found // TODO DONE: make sure incoming and outgoing pipelines are connected +// TODO DONE: provide some sort of "reliable" send for "stopped" update // TODO: test entity updates (second viewer sees physics results from first) -// TODO: provide some sort of "reliable" send for "stopped" update +// TODO: reconcile hifi damping with bullet damping for improved ballistic predictions #include "PhysicsEngine.h" #ifdef USE_BULLET_PHYSICS From 5efd996548c7ec2887aff220b16195d5cd44c73f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 17 Dec 2014 12:37:49 -0800 Subject: [PATCH 083/105] clarifying some comments on member variables --- libraries/entities/src/EntityItem.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 217657bad3..4a6db73789 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -317,9 +317,9 @@ protected: bool _newlyCreated; quint64 _lastSimulated; // last time this entity called simulate() quint64 _lastUpdated; // last time this entity called update() - quint64 _lastEdited; // this is the last official local or remote edit time - quint64 _lastEditedFromRemote; // this is the last time we received and edit from the server - quint64 _lastEditedFromRemoteInRemoteTime; // time in server time space the last time we received and edit from the server + quint64 _lastEdited; // last official local or remote edit time + quint64 _lastEditedFromRemote; // last time we received and edit from the server + quint64 _lastEditedFromRemoteInRemoteTime; // last time we received and edit from the server (in server-time-frame) quint64 _created; quint64 _changedOnServer; From 8de309a7a95f8f0928dfc7cd8929c308f3dd5a7b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 17 Dec 2014 12:38:26 -0800 Subject: [PATCH 084/105] more correct _created and _lastEdited --- libraries/entities/src/EntityItem.cpp | 42 ++++++------ libraries/entities/src/EntityItemProperties.h | 4 +- libraries/entities/src/EntityTypes.cpp | 6 +- libraries/physics/src/EntityMotionState.cpp | 67 +++++++++---------- 4 files changed, 59 insertions(+), 60 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index d2e3acb86d..7819063074 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -53,14 +53,13 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) { _creatorTokenID = entityItemID.creatorTokenID; // init values with defaults before calling setProperties - //uint64_t now = usecTimestampNow(); _lastEdited = 0; _lastEditedFromRemote = 0; _lastEditedFromRemoteInRemoteTime = 0; _lastSimulated = 0; _lastUpdated = 0; - _created = 0; // TODO: when do we actually want to make this "now" + _created = usecTimestampNow(); _changedOnServer = 0; _position = glm::vec3(0,0,0); @@ -100,17 +99,17 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) { EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) { _type = EntityTypes::Unknown; - _lastEdited = 0; - _lastEditedFromRemote = 0; - _lastEditedFromRemoteInRemoteTime = 0; - _lastSimulated = 0; - _lastUpdated = 0; - _created = properties.getCreated(); + quint64 now = usecTimestampNow(); + _created = properties.getCreated() < now ? properties.getCreated() : now; + _lastEdited = _lastEditedFromRemote = _lastSimulated = _lastUpdated = _lastEditedFromRemoteInRemoteTime = _created; _physicsInfo = NULL; _dirtyFlags = 0; _changedOnServer = 0; initFromEntityItemID(entityItemID); setProperties(properties, true); // force copy + if (_lastEdited == 0) { + _lastEdited = _created; + } } EntityItem::~EntityItem() { @@ -142,7 +141,6 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packetData, EncodeBitstreamParams& params, EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData) const { - // ALL this fits... // object ID [16 bytes] // ByteCountCoded(type code) [~1 byte] @@ -372,7 +370,10 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef bytesRead += sizeof(createdFromBuffer); createdFromBuffer -= clockSkew; - _created = createdFromBuffer; // TODO: do we ever want to discard this??? + if (createdFromBuffer < _created) { + _created = createdFromBuffer; + _lastEdited = 0; + } if (wantDebug) { quint64 lastEdited = getLastEdited(); @@ -390,8 +391,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef quint64 lastEditedFromBuffer = 0; quint64 lastEditedFromBufferAdjusted = 0; - // BOOKMARK: TODO: figure out if we can catch remote updates to EntityItems and build a list in the Tree - // that is then relayed to the physics engine (and other data structures that cache EntityItem data) // TODO: we could make this encoded as a delta from _created // _lastEdited memcpy(&lastEditedFromBuffer, dataAt, sizeof(lastEditedFromBuffer)); @@ -423,14 +422,14 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef if (fromSameServerEdit) { // If this is from the same sever packet, then check against any local changes since we got // the most recent packet from this server time - if (_lastEdited > _lastEditedFromRemote) { + if (_lastEdited >= _lastEditedFromRemote) { ignoreServerPacket = true; } } else { // If this isn't from the same sever packet, then honor our skew adjusted times... // If we've changed our local tree more recently than the new data from this packet // then we will not be changing our values, instead we just read and skip the data - if (_lastEdited > lastEditedFromBufferAdjusted) { + if (_lastEdited >= lastEditedFromBufferAdjusted) { ignoreServerPacket = true; } } @@ -446,7 +445,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef qDebug() << "USING NEW data from server!!! ****************"; } - _lastEdited = lastEditedFromBufferAdjusted; + // don't allow _lastEdited to be in the future + _lastEdited = lastEditedFromBufferAdjusted < now ? lastEditedFromBufferAdjusted : now; _lastEditedFromRemote = now; _lastEditedFromRemoteInRemoteTime = lastEditedFromBuffer; @@ -783,10 +783,13 @@ bool EntityItem::setProperties(const EntityItemProperties& properties, bool forc // handle the setting of created timestamps for the basic new entity case if (forceCopy) { + quint64 now = usecTimestampNow(); if (properties.getCreated() == UNKNOWN_CREATED_TIME) { - _created = usecTimestampNow(); + _created = now; } else if (properties.getCreated() != USE_EXISTING_CREATED_TIME) { - _created = properties.getCreated(); + quint64 created = properties.getCreated(); + // don't allow _created to be in the future + _created = created < now ? created : now; } } @@ -813,13 +816,14 @@ bool EntityItem::setProperties(const EntityItemProperties& properties, bool forc if (somethingChanged) { somethingChangedNotification(); // notify derived classes that something has changed bool wantDebug = false; + uint64_t now = usecTimestampNow(); if (wantDebug) { - uint64_t now = usecTimestampNow(); int elapsed = now - getLastEdited(); qDebug() << "EntityItem::setProperties() AFTER update... edited AGO=" << elapsed << "now=" << now << " getLastEdited()=" << getLastEdited(); } - setLastEdited(properties._lastEdited); + // don't allow _lastEdited to be in the future + setLastEdited( properties._lastEdited < now ? properties._lastEdited : now); if (getDirtyFlags() & EntityItem::DIRTY_POSITION) { _lastSimulated = usecTimestampNow(); } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 2aaa7a4528..24759ba4ba 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -95,8 +95,8 @@ enum EntityPropertyList { typedef PropertyFlags EntityPropertyFlags; -const quint64 UNKNOWN_CREATED_TIME = (quint64)(-1); -const quint64 USE_EXISTING_CREATED_TIME = (quint64)(-2); +const quint64 UNKNOWN_CREATED_TIME = 0; +const quint64 USE_EXISTING_CREATED_TIME = 1; /// A collection of properties of an entity item used in the scripting API. Translates between the actual properties of an diff --git a/libraries/entities/src/EntityTypes.cpp b/libraries/entities/src/EntityTypes.cpp index 194df024e0..397fd15a2f 100644 --- a/libraries/entities/src/EntityTypes.cpp +++ b/libraries/entities/src/EntityTypes.cpp @@ -71,7 +71,6 @@ bool EntityTypes::registerEntityType(EntityType entityType, const char* name, En EntityItem* EntityTypes::constructEntityItem(EntityType entityType, const EntityItemID& entityID, const EntityItemProperties& properties) { - EntityItem* newEntityItem = NULL; EntityTypeFactory factory = NULL; if (entityType >= 0 && entityType <= LAST) { @@ -129,7 +128,10 @@ EntityItem* EntityTypes::constructEntityItem(const unsigned char* data, int byte EntityItemID tempEntityID(actualID); EntityItemProperties tempProperties; - tempProperties.setCreated(usecTimestampNow()); // this is temporary... + + quint64 now = usecTimestampNow(); + tempProperties.setCreated(now); + tempProperties.setLastEdited(now); return constructEntityItem(entityType, tempEntityID, tempProperties); } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index bb87155bc3..acfbb954e2 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -113,65 +113,58 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ if (_outgoingPacketFlags) { EntityItemProperties properties = _entity->getProperties(); - if (_outgoingPacketFlags == OUTGOING_DIRTY_PHYSICS_FLAGS) { - // all outgoing physics flags are set - // This is the common case: physics engine has changed object position/velocity. - + if (_outgoingPacketFlags & EntityItem::DIRTY_POSITION) { btTransform worldTrans = _body->getWorldTransform(); bulletToGLM(worldTrans.getOrigin(), _sentPosition); properties.setPosition(_sentPosition + ObjectMotionState::getWorldOffset()); bulletToGLM(worldTrans.getRotation(), _sentRotation); properties.setRotation(_sentRotation); - + } + + if (_outgoingPacketFlags & EntityItem::DIRTY_VELOCITY) { if (_body->isActive()) { bulletToGLM(_body->getLinearVelocity(), _sentVelocity); bulletToGLM(_body->getAngularVelocity(), _sentAngularVelocity); - bulletToGLM(_body->getGravity(), _sentAcceleration); + + // if the speeds are very small we zero them out + const float MINIMUM_EXTRAPOLATION_SPEED_SQUARED = 4.0e-6f; // 2mm/sec + bool zeroSpeed = (glm::length2(_sentVelocity) < MINIMUM_EXTRAPOLATION_SPEED_SQUARED); + if (zeroSpeed) { + _sentVelocity = glm::vec3(0.0f); + } + const float MINIMUM_EXTRAPOLATION_SPIN_SQUARED = 0.004f; // ~0.01 rotation/sec + bool zeroSpin = glm::length2(_sentAngularVelocity) < MINIMUM_EXTRAPOLATION_SPIN_SQUARED; + if (zeroSpin) { + _sentAngularVelocity = glm::vec3(0.0f); + } + + _sentMoving = ! (zeroSpeed && zeroSpin); } else { - _sentVelocity = _sentAngularVelocity = _sentAcceleration = glm::vec3(0.0f); + _sentVelocity = _sentAngularVelocity = glm::vec3(0.0f); + _sentMoving = false; } properties.setVelocity(_sentVelocity); + bulletToGLM(_body->getGravity(), _sentAcceleration); properties.setGravity(_sentAcceleration); properties.setAngularVelocity(_sentAngularVelocity); - } else { - // subset of outgoing physics flags are set - // This is an uncommon case: physics engine change collided with incoming external change - // we only send data for flags that haven't been cleared. - - if (_outgoingPacketFlags & EntityItem::DIRTY_POSITION) { - btTransform worldTrans = _body->getWorldTransform(); - bulletToGLM(worldTrans.getOrigin(), _sentPosition); - properties.setPosition(_sentPosition + ObjectMotionState::getWorldOffset()); - - bulletToGLM(worldTrans.getRotation(), _sentRotation); - properties.setRotation(_sentRotation); - } - - if (_outgoingPacketFlags & EntityItem::DIRTY_VELOCITY) { - if (_body->isActive()) { - bulletToGLM(_body->getLinearVelocity(), _sentVelocity); - bulletToGLM(_body->getAngularVelocity(), _sentAngularVelocity); - bulletToGLM(_body->getGravity(), _sentAcceleration); - } else { - _sentVelocity = _sentAngularVelocity = _sentAcceleration = glm::vec3(0.0f); - } - properties.setVelocity(_sentVelocity); - properties.setAngularVelocity(_sentAngularVelocity); - properties.setGravity(_sentAcceleration); - } } - // TODO: Figure out what LastEdited is used for... - //properties.setLastEdited(now); - glm::vec3 zero(0.0f); - _sentMoving = !(_sentVelocity == zero && _sentAngularVelocity == zero && _sentAcceleration == zero); // RELIABLE_SEND_HACK: count number of updates for entities at rest so we can stop sending them after some limit. if (_sentMoving) { _numNonMovingUpdates = 0; } else { _numNonMovingUpdates++; } + if (_numNonMovingUpdates <= 1) { + // we only update lastEdited when we're sending new physics data + // (i.e. NOT when we just simulate the positions forward, nore when we resend non-moving data) + quint64 lastSimulated = _entity->getLastSimulated(); + _entity->setLastEdited(lastSimulated); + properties.setLastEdited(lastSimulated); + } else { + properties.setLastEdited(_entity->getLastEdited()); + } EntityItemID id(_entity->getID()); EntityEditPacketSender* entityPacketSender = static_cast(packetSender); From 905d7f50eb5d4ea8e65482c733388f42cbdb61a4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 17 Dec 2014 12:39:48 -0800 Subject: [PATCH 085/105] comments on TODO list --- libraries/physics/src/PhysicsEngine.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 4d0d48ddfc..5ceaeb470e 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -15,7 +15,8 @@ // TODO DONE: make sure code compiles when BULLET is not found // TODO DONE: make sure incoming and outgoing pipelines are connected // TODO DONE: provide some sort of "reliable" send for "stopped" update -// TODO: test entity updates (second viewer sees physics results from first) +// TODO DONE: test entity updates (second viewer sees physics results from first) +// TODO DONE: debug path of updates through EntityServer // TODO: reconcile hifi damping with bullet damping for improved ballistic predictions #include "PhysicsEngine.h" From c6afa0f7e1478d04b8b91b6a79cdac520e07cedf Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 17 Dec 2014 14:17:30 -0800 Subject: [PATCH 086/105] remove test hack for higher than normal ground --- libraries/physics/src/PhysicsEngine.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index c18161573c..5ceaeb470e 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -191,8 +191,7 @@ void PhysicsEngine::init(EntityEditPacketSender* packetSender) { for (int i = 0; i < 3; ++i) { btVector3 normal(0.0f, 0.0f, 0.0f); normal[i] = 1.0f; - //btCollisionShape* plane = new btStaticPlaneShape(normal, 0.0f); - btCollisionShape* plane = new btStaticPlaneShape(normal, 0.5f); + btCollisionShape* plane = new btStaticPlaneShape(normal, 0.0f); btCollisionObject* groundObject = new btCollisionObject(); groundObject->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT); From 547c4cdaf9a1def5b4dce69827950fe5df5f7f11 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 17 Dec 2014 14:52:38 -0800 Subject: [PATCH 087/105] make non-bullet entity simulation work again --- libraries/entities/src/EntityItem.cpp | 55 ++++----------------------- 1 file changed, 8 insertions(+), 47 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 58b93abebd..7e62ddb643 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -658,13 +658,13 @@ void EntityItem::simulate(const quint64& now) { } } - if (hasVelocity() || hasGravity()) { + if (hasVelocity()) { glm::vec3 position = getPosition(); glm::vec3 velocity = getVelocity(); glm::vec3 newPosition = position + (velocity * timeElapsed); if (wantDebug) { - qDebug() << " EntityItem::update()...."; + qDebug() << " EntityItem::simulate()...."; qDebug() << " timeElapsed:" << timeElapsed; qDebug() << " old AACube:" << getMaximumAACube(); qDebug() << " old position:" << position; @@ -711,32 +711,13 @@ void EntityItem::simulate(const quint64& now) { qDebug() << " newVelocity:" << velocity; } } - } - } - - if (hasVelocity()) { - glm::vec3 position = getPosition(); - glm::vec3 velocity = getVelocity(); - glm::vec3 newPosition = position + (velocity * timeElapsed); - - if (wantDebug) { - qDebug() << " EntityItem::simulate()...."; - qDebug() << " timeElapsed:" << timeElapsed; - qDebug() << " old AACube:" << getMaximumAACube(); - qDebug() << " old position:" << position; - qDebug() << " old velocity:" << velocity; - qDebug() << " old getAABox:" << getAABox(); - qDebug() << " getDistanceToBottomOfEntity():" << getDistanceToBottomOfEntity() * (float)TREE_SCALE << " in meters"; - qDebug() << " newPosition:" << newPosition; - qDebug() << " glm::distance(newPosition, position):" << glm::distance(newPosition, position); - } - - position = newPosition; - - // handle bounces off the ground... We bounce at the distance to the bottom of our entity - if (position.y <= getDistanceToBottomOfEntity()) { - velocity = velocity * glm::vec3(1,-1,1); + if (wantDebug) { + qDebug() << " velocity AFTER dampingResistance:" << velocity; + qDebug() << " glm::length(velocity):" << glm::length(velocity); + qDebug() << " EPSILON_VELOCITY_LENGTH:" << EPSILON_VELOCITY_LENGTH; + } + // if we've slowed considerably, then just stop moving if (glm::length(velocity) <= EPSILON_VELOCITY_LENGTH) { velocity = NO_VELOCITY; @@ -746,26 +727,6 @@ void EntityItem::simulate(const quint64& now) { setPosition(position); // this will automatically recalculate our collision shape setVelocity(velocity); - position.y = getDistanceToBottomOfEntity(); - } - - // handle gravity.... - if (hasGravity()) { - // handle resting on surface case, this is definitely a bit of a hack, and it only works on the - // "ground" plane of the domain, but for now it what we've got - if (isRestingOnSurface()) { - velocity.y = 0.0f; - position.y = getDistanceToBottomOfEntity(); - } else { - velocity += getGravity() * timeElapsed; - } - } - - // handle damping for velocity - float dampingTimescale = getDamping(); - if (dampingTimescale > 0.0f) { - float dampingFactor = glm::clamp(timeElapsed / dampingTimescale, 0.0f, 1.0f); - velocity *= (1.0f - dampingFactor); if (wantDebug) { qDebug() << " new position:" << position; qDebug() << " new velocity:" << velocity; From dab1f026d7ed72fe3600aa990f9313a289a59780 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 18 Dec 2014 13:56:18 -0800 Subject: [PATCH 088/105] simpler EntityItem::simulate() bypass for bullet --- libraries/entities/src/EntityItem.cpp | 187 +++++++++++++------------- 1 file changed, 95 insertions(+), 92 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 7f04c882e0..efe6bcd56b 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -587,6 +587,11 @@ bool EntityItem::isRestingOnSurface() const { } void EntityItem::simulate(const quint64& now) { + if (_physicsInfo) { + // we rely on bullet for simulation, so bail + return; + } + bool wantDebug = false; if (_lastSimulated == 0) { @@ -636,110 +641,108 @@ void EntityItem::simulate(const quint64& now) { qDebug() << " ********** EntityItem::simulate() .... SETTING _lastSimulated=" << _lastSimulated; } - if (!_physicsInfo) { - if (hasAngularVelocity()) { - glm::quat rotation = getRotation(); - glm::vec3 angularVelocity = glm::radians(getAngularVelocity()); - float angularSpeed = glm::length(angularVelocity); - - if (angularSpeed < EPSILON_VELOCITY_LENGTH) { - setAngularVelocity(NO_ANGULAR_VELOCITY); - } else { - float angle = timeElapsed * angularSpeed; - glm::quat dQ = glm::angleAxis(angle, glm::normalize(angularVelocity)); - rotation = dQ * rotation; - setRotation(rotation); - - // handle damping for angular velocity - float dampingTimescale = getAngularDamping(); - if (dampingTimescale > 0.0f) { - float dampingFactor = glm::clamp(timeElapsed / dampingTimescale, 0.0f, 1.0f); - glm::vec3 newAngularVelocity = (1.0f - dampingFactor) * getAngularVelocity(); - setAngularVelocity(newAngularVelocity); - if (wantDebug) { - qDebug() << " dampingTimescale :" << dampingTimescale; - qDebug() << " newAngularVelocity:" << newAngularVelocity; - } + if (hasAngularVelocity()) { + glm::quat rotation = getRotation(); + glm::vec3 angularVelocity = glm::radians(getAngularVelocity()); + float angularSpeed = glm::length(angularVelocity); + + if (angularSpeed < EPSILON_VELOCITY_LENGTH) { + setAngularVelocity(NO_ANGULAR_VELOCITY); + } else { + float angle = timeElapsed * angularSpeed; + glm::quat dQ = glm::angleAxis(angle, glm::normalize(angularVelocity)); + rotation = dQ * rotation; + setRotation(rotation); + + // handle damping for angular velocity + float dampingTimescale = getAngularDamping(); + if (dampingTimescale > 0.0f) { + float dampingFactor = glm::clamp(timeElapsed / dampingTimescale, 0.0f, 1.0f); + glm::vec3 newAngularVelocity = (1.0f - dampingFactor) * getAngularVelocity(); + setAngularVelocity(newAngularVelocity); + if (wantDebug) { + qDebug() << " dampingTimescale :" << dampingTimescale; + qDebug() << " newAngularVelocity:" << newAngularVelocity; } } } - - if (hasVelocity() || hasGravity()) { - glm::vec3 position = getPosition(); - glm::vec3 velocity = getVelocity(); - glm::vec3 newPosition = position + (velocity * timeElapsed); - - if (wantDebug) { - qDebug() << " EntityItem::simulate()...."; - qDebug() << " timeElapsed:" << timeElapsed; - qDebug() << " old AACube:" << getMaximumAACube(); - qDebug() << " old position:" << position; - qDebug() << " old velocity:" << velocity; - qDebug() << " old getAABox:" << getAABox(); - qDebug() << " getDistanceToBottomOfEntity():" << getDistanceToBottomOfEntity() * (float)TREE_SCALE << " in meters"; - qDebug() << " newPosition:" << newPosition; - qDebug() << " glm::distance(newPosition, position):" << glm::distance(newPosition, position); - } - - position = newPosition; - - // handle bounces off the ground... We bounce at the distance to the bottom of our entity - if (position.y <= getDistanceToBottomOfEntity()) { - velocity = velocity * glm::vec3(1,-1,1); - - // if we've slowed considerably, then just stop moving - if (glm::length(velocity) <= EPSILON_VELOCITY_LENGTH) { - velocity = NO_VELOCITY; - } - - position.y = getDistanceToBottomOfEntity(); - } - - // handle gravity.... - if (hasGravity()) { - // handle resting on surface case, this is definitely a bit of a hack, and it only works on the - // "ground" plane of the domain, but for now it what we've got - if (isRestingOnSurface()) { - velocity.y = 0.0f; - position.y = getDistanceToBottomOfEntity(); - } else { - velocity += getGravity() * timeElapsed; - } - } + } - // handle damping for velocity - float dampingTimescale = getDamping(); - if (dampingTimescale > 0.0f) { - float dampingFactor = glm::clamp(timeElapsed / dampingTimescale, 0.0f, 1.0f); - velocity *= (1.0f - dampingFactor); - if (wantDebug) { - qDebug() << " dampingTimescale:" << dampingTimescale; - qDebug() << " newVelocity:" << velocity; - } - } + if (hasVelocity() || hasGravity()) { + glm::vec3 position = getPosition(); + glm::vec3 velocity = getVelocity(); + glm::vec3 newPosition = position + (velocity * timeElapsed); + + if (wantDebug) { + qDebug() << " EntityItem::simulate()...."; + qDebug() << " timeElapsed:" << timeElapsed; + qDebug() << " old AACube:" << getMaximumAACube(); + qDebug() << " old position:" << position; + qDebug() << " old velocity:" << velocity; + qDebug() << " old getAABox:" << getAABox(); + qDebug() << " getDistanceToBottomOfEntity():" << getDistanceToBottomOfEntity() * (float)TREE_SCALE << " in meters"; + qDebug() << " newPosition:" << newPosition; + qDebug() << " glm::distance(newPosition, position):" << glm::distance(newPosition, position); + } + + position = newPosition; + + // handle bounces off the ground... We bounce at the distance to the bottom of our entity + if (position.y <= getDistanceToBottomOfEntity()) { + velocity = velocity * glm::vec3(1,-1,1); - if (wantDebug) { - qDebug() << " velocity AFTER dampingResistance:" << velocity; - qDebug() << " glm::length(velocity):" << glm::length(velocity); - qDebug() << " EPSILON_VELOCITY_LENGTH:" << EPSILON_VELOCITY_LENGTH; - } - // if we've slowed considerably, then just stop moving if (glm::length(velocity) <= EPSILON_VELOCITY_LENGTH) { velocity = NO_VELOCITY; } - - // NOTE: the simulation should NOT set any DirtyFlags on this entity - setPosition(position); // this will automatically recalculate our collision shape - setVelocity(velocity); - if (wantDebug) { - qDebug() << " new position:" << position; - qDebug() << " new velocity:" << velocity; - qDebug() << " new AACube:" << getMaximumAACube(); - qDebug() << " old getAABox:" << getAABox(); + position.y = getDistanceToBottomOfEntity(); + } + + // handle gravity.... + if (hasGravity()) { + // handle resting on surface case, this is definitely a bit of a hack, and it only works on the + // "ground" plane of the domain, but for now it what we've got + if (isRestingOnSurface()) { + velocity.y = 0.0f; + position.y = getDistanceToBottomOfEntity(); + } else { + velocity += getGravity() * timeElapsed; } } + + // handle damping for velocity + float dampingTimescale = getDamping(); + if (dampingTimescale > 0.0f) { + float dampingFactor = glm::clamp(timeElapsed / dampingTimescale, 0.0f, 1.0f); + velocity *= (1.0f - dampingFactor); + if (wantDebug) { + qDebug() << " dampingTimescale:" << dampingTimescale; + qDebug() << " newVelocity:" << velocity; + } + } + + if (wantDebug) { + qDebug() << " velocity AFTER dampingResistance:" << velocity; + qDebug() << " glm::length(velocity):" << glm::length(velocity); + qDebug() << " EPSILON_VELOCITY_LENGTH:" << EPSILON_VELOCITY_LENGTH; + } + + // round velocity to zero if it's close enough... + if (glm::length(velocity) <= EPSILON_VELOCITY_LENGTH) { + velocity = NO_VELOCITY; + } + + // NOTE: the simulation should NOT set any DirtyFlags on this entity + setPosition(position); // this will automatically recalculate our collision shape + setVelocity(velocity); + + if (wantDebug) { + qDebug() << " new position:" << position; + qDebug() << " new velocity:" << velocity; + qDebug() << " new AACube:" << getMaximumAACube(); + qDebug() << " old getAABox:" << getAABox(); + } } _lastSimulated = now; From 25b00977be7243f879a4baf4915db0d73830fe06 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 18 Dec 2014 17:34:39 -0800 Subject: [PATCH 089/105] fix cmake config for bullet after c++-11 changes --- cmake/macros/IncludeBullet.cmake | 7 ++++--- libraries/physics/CMakeLists.txt | 3 +++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/cmake/macros/IncludeBullet.cmake b/cmake/macros/IncludeBullet.cmake index 53b7224bb8..a238b33660 100644 --- a/cmake/macros/IncludeBullet.cmake +++ b/cmake/macros/IncludeBullet.cmake @@ -10,8 +10,9 @@ macro(INCLUDE_BULLET) find_package(Bullet) if (BULLET_FOUND) - include_directories(SYSTEM "${BULLET_INCLUDE_DIRS}") - list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${BULLET_LIBRARIES}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_BULLET_PHYSICS") + include_directories("${BULLET_INCLUDE_DIRS}") + if (APPLE OR UNIX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_BULLET_PHYSICS -isystem ${BULLET_INCLUDE_DIRS}") + endif () endif (BULLET_FOUND) endmacro(INCLUDE_BULLET) diff --git a/libraries/physics/CMakeLists.txt b/libraries/physics/CMakeLists.txt index 15e1ab238c..c0ce72d45c 100644 --- a/libraries/physics/CMakeLists.txt +++ b/libraries/physics/CMakeLists.txt @@ -5,6 +5,9 @@ setup_hifi_library() include_glm() include_bullet() +if (BULLET_FOUND) + target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES}) +endif (BULLET_FOUND) link_hifi_libraries(shared fbx entities) include_hifi_library_headers(fbx) From bef14a46ac6bbb23546e067cc9d552cd5c0060e5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 29 Dec 2014 10:41:19 -0800 Subject: [PATCH 090/105] remove commented out cruft --- libraries/entities/src/EntityTreeElement.cpp | 17 ----------------- libraries/entities/src/EntityTreeElement.h | 2 -- 2 files changed, 19 deletions(-) diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 2f20ce8cee..3753aae963 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -679,23 +679,6 @@ EntityItem* EntityTreeElement::getEntityWithEntityItemID(const EntityItemID& id) return foundEntity; } -/* TODO: probably move the cleanupEntities() stuff into EntityTree -void EntityTreeElement::cleanupEntities(PhysicsEngine* physicsEngine) { - uint16_t numberOfEntities = _entityItems->size(); - for (uint16_t i = 0; i < numberOfEntities; i++) { - EntityItem* entity = (*_entityItems)[i]; - EntityMotionState* motionState = entity->getMotionState(); - if (motionState) { - assert(physicsEngine); - physicsEngine->removeObject(static_cast(motionState)); - entity->destroyMotionState(); - } - delete entity; - } - _entityItems->clear(); -} -*/ - bool EntityTreeElement::removeEntityWithEntityItemID(const EntityItemID& id) { bool foundEntity = false; uint16_t numberOfEntities = _entityItems->size(); diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index 076fec1d66..a0b6921c71 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -175,8 +175,6 @@ public: EntityItem* getEntityWithEntityItemID(const EntityItemID& id); - // TODO: probably move the cleanupEntities() stuff into EntityTree - //void cleanupEntities(PhysicsEngine* physicsEngine); bool removeEntityWithEntityItemID(const EntityItemID& id); bool removeEntityItem(EntityItem* entity); From 0ec56816c057979cb69feecaa121e927d2d96817 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 29 Dec 2014 10:43:09 -0800 Subject: [PATCH 091/105] remove unused variable cruft --- libraries/entities/src/UpdateEntityOperator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/UpdateEntityOperator.cpp b/libraries/entities/src/UpdateEntityOperator.cpp index 2b5a54647d..9cee11d73c 100644 --- a/libraries/entities/src/UpdateEntityOperator.cpp +++ b/libraries/entities/src/UpdateEntityOperator.cpp @@ -299,14 +299,14 @@ bool UpdateEntityOperator::preRecursion(OctreeElement* element) { } // set the entity properties and mark our element as changed. - bool somethingChanged = _existingEntity->setProperties(_properties); + _existingEntity->setProperties(_properties); if (_wantDebug) { qDebug() << " *** set properties ***"; } } else { // otherwise, this is an add case. entityTreeElement->addEntityItem(_existingEntity); - bool somethingChanged = _existingEntity->setProperties(_properties); // still need to update the properties! + _existingEntity->setProperties(_properties); // still need to update the properties! _tree->setContainingElement(_entityItemID, entityTreeElement); if (_wantDebug) { qDebug() << " *** ADDING ENTITY to ELEMENT and MAP and SETTING PROPERTIES ***"; From b078850c6a459f39f89548c98a7b909360ea6a3a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 29 Dec 2014 10:46:56 -0800 Subject: [PATCH 092/105] remove personal TODO list from code file --- libraries/physics/src/PhysicsEngine.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 5ceaeb470e..49e93e7f06 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -8,16 +8,6 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// TODO DONE: make _incomingChanges to be list of MotionState*'s. -// TODO DONE: make MotionState able to clear incoming flags -// TODO DONE: make MotionState::setWorldTransform() put itself on _incomingChanges list -// TODO DONE: give PhysicsEngine instance an _entityPacketSender -// TODO DONE: make sure code compiles when BULLET is not found -// TODO DONE: make sure incoming and outgoing pipelines are connected -// TODO DONE: provide some sort of "reliable" send for "stopped" update -// TODO DONE: test entity updates (second viewer sees physics results from first) -// TODO DONE: debug path of updates through EntityServer -// TODO: reconcile hifi damping with bullet damping for improved ballistic predictions #include "PhysicsEngine.h" #ifdef USE_BULLET_PHYSICS From 58f3436d9bf5bb9ba7f5eb7a20cb91f3625707a8 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 29 Dec 2014 10:50:06 -0800 Subject: [PATCH 093/105] fix bug in != operator --- libraries/shared/src/AACube.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/AACube.h b/libraries/shared/src/AACube.h index 6de27ad433..b29bc49bef 100644 --- a/libraries/shared/src/AACube.h +++ b/libraries/shared/src/AACube.h @@ -79,7 +79,7 @@ inline bool operator==(const AACube& a, const AACube& b) { } inline bool operator!=(const AACube& a, const AACube& b) { - return a.getCorner() != b.getCorner() || a.getScale() == b.getScale(); + return a.getCorner() != b.getCorner() || a.getScale() != b.getScale(); } inline QDebug operator<<(QDebug debug, const AACube& cube) { From 8cb809231051ffc832871ef803a554a107370f52 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 29 Dec 2014 10:55:47 -0800 Subject: [PATCH 094/105] remove unused code I forget what I was using UUIDHashKey for --- libraries/physics/src/UUIDHashKey.h | 31 ----------------------------- 1 file changed, 31 deletions(-) delete mode 100644 libraries/physics/src/UUIDHashKey.h diff --git a/libraries/physics/src/UUIDHashKey.h b/libraries/physics/src/UUIDHashKey.h deleted file mode 100644 index fcc6209d5a..0000000000 --- a/libraries/physics/src/UUIDHashKey.h +++ /dev/null @@ -1,31 +0,0 @@ -// -// UUIDHashKey.h -// libraries/physcis/src -// -// Created by Andrew Meadows 2014.11.05 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_UUIDHashKey_h -#define hifi_UUIDHashKey_h - -#include - -class UUIDHashKey { -public: - UUIDHashKey(const QUuid& id) : _hash(0), _id(id) { _hash = (int)(qHash(id)); } - - bool equals(const UUIDHashKey& other) const { - return _hash == other._hash && _id == other._id; - } - - unsigned int getHash() const { return (unsigned int)_hash; } -protected: - int _hash; - QUuid _id; -}; - -#endif // hifi_UUIDHashKey_h From 71ab4a57804bb2fe8ead0f97038b106943b6bcc4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 29 Dec 2014 11:07:57 -0800 Subject: [PATCH 095/105] fix unit ShapeManager unit tests --- tests/physics/src/ShapeManagerTests.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/physics/src/ShapeManagerTests.cpp b/tests/physics/src/ShapeManagerTests.cpp index ba1b6ff388..5be247f25f 100644 --- a/tests/physics/src/ShapeManagerTests.cpp +++ b/tests/physics/src/ShapeManagerTests.cpp @@ -139,11 +139,12 @@ void ShapeManagerTests::addManyShapes() { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: i = " << i << " null box shape for scale = " << scale << std::endl; } - info.setSphere(s); + float radius = 0.5f * s; + info.setSphere(radius); shape = shapeManager.getShape(info); if (!shape) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: i = " << i << " null sphere shape for radius = " << s << std::endl; + << " ERROR: i = " << i << " null sphere shape for radius = " << radius << std::endl; } } int numShapes = shapeManager.getNumShapes(); From 439cdbdac1f6ed326c2050d09fd1f545188443a6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 29 Dec 2014 11:15:09 -0800 Subject: [PATCH 096/105] re-expose unit tests for legacy shapes --- tests/physics/src/main.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/physics/src/main.cpp b/tests/physics/src/main.cpp index 2318ee2dca..bcf26f4115 100644 --- a/tests/physics/src/main.cpp +++ b/tests/physics/src/main.cpp @@ -8,15 +8,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -//#include "ShapeColliderTests.h" -//#include "VerletShapeTests.h" +#include "ShapeColliderTests.h" +#include "VerletShapeTests.h" #include "ShapeInfoTests.h" #include "ShapeManagerTests.h" #include "BulletUtilTests.h" int main(int argc, char** argv) { - //ShapeColliderTests::runAllTests(); - //VerletShapeTests::runAllTests(); + ShapeColliderTests::runAllTests(); + VerletShapeTests::runAllTests(); ShapeInfoTests::runAllTests(); ShapeManagerTests::runAllTests(); BulletUtilTests::runAllTests(); From 213133c705ad48561bdfd269726587bd2d6b2ae2 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 29 Dec 2014 15:19:25 -0800 Subject: [PATCH 097/105] restoring EntityTreeElement::cleanupEntities() --- libraries/entities/src/EntityTree.cpp | 3 +++ libraries/entities/src/EntityTreeElement.cpp | 9 +++++++++ libraries/entities/src/EntityTreeElement.h | 1 + 3 files changed, 13 insertions(+) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 84cdf2f3be..3849256053 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -42,6 +42,9 @@ void EntityTree::eraseAllOctreeElements(bool createNewRoot) { if (_simulation) { _simulation->clearEntities(); } + foreach (EntityTreeElement* element, _entityToElementMap) { + element->cleanupEntities(); + } _entityToElementMap.clear(); Octree::eraseAllOctreeElements(createNewRoot); } diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 3753aae963..0c30415a1a 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -679,6 +679,15 @@ EntityItem* EntityTreeElement::getEntityWithEntityItemID(const EntityItemID& id) return foundEntity; } +void EntityTreeElement::cleanupEntities() { + uint16_t numberOfEntities = _entityItems->size(); + for (uint16_t i = 0; i < numberOfEntities; i++) { + EntityItem* entity = (*_entityItems)[i]; + delete entity; + } + _entityItems->clear(); +} + bool EntityTreeElement::removeEntityWithEntityItemID(const EntityItemID& id) { bool foundEntity = false; uint16_t numberOfEntities = _entityItems->size(); diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index a0b6921c71..4fbe9db323 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -175,6 +175,7 @@ public: EntityItem* getEntityWithEntityItemID(const EntityItemID& id); + void cleanupEntities(); /// called by EntityTree on cleanup this will free all entities bool removeEntityWithEntityItemID(const EntityItemID& id); bool removeEntityItem(EntityItem* entity); From 97f44b64fc4964c91d2ce909df35ee3b552f55e7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 29 Dec 2014 15:27:54 -0800 Subject: [PATCH 098/105] assert NULL EntityItem::_physicsInfo in dtor --- libraries/entities/src/EntityItem.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index efe6bcd56b..586ee5461e 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -115,6 +115,8 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert } EntityItem::~EntityItem() { + // be sure to clean up _physicsInfo before calling this dtor + assert(_physicsInfo == NULL); } EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& params) const { From a97b8b0ea9a76a2bebb7d4a78788d2a5b34f3d71 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 29 Dec 2014 16:33:41 -0800 Subject: [PATCH 099/105] fix memory leak of EntityMotionState's --- libraries/physics/src/EntityMotionState.cpp | 3 +++ libraries/physics/src/PhysicsEngine.cpp | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index acfbb954e2..be771fd801 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -37,6 +37,9 @@ EntityMotionState::EntityMotionState(EntityItem* entity) } EntityMotionState::~EntityMotionState() { + assert(_entity); + _entity->setPhysicsInfo(NULL); + _entity = NULL; } MotionType EntityMotionState::computeMotionType() const { diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 49e93e7f06..a6317b4fcf 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -79,10 +79,10 @@ void PhysicsEngine::removeEntityInternal(EntityItem* entity) { if (physicsInfo) { EntityMotionState* motionState = static_cast(physicsInfo); removeObject(motionState); - entity->setPhysicsInfo(NULL); _entityMotionStates.remove(motionState); _incomingChanges.remove(motionState); _outgoingPackets.remove(motionState); + delete motionState; } } @@ -118,6 +118,7 @@ void PhysicsEngine::clearEntitiesInternal() { QSet::const_iterator stateItr = _entityMotionStates.begin(); for (stateItr = _entityMotionStates.begin(); stateItr != _entityMotionStates.end(); ++stateItr) { removeObject(*stateItr); + delete (*stateItr); } _entityMotionStates.clear(); _incomingChanges.clear(); From ce14c823a1a0c14100f01bb6889703c3ac1c28a1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 29 Dec 2014 16:41:27 -0800 Subject: [PATCH 100/105] add comment about stubbed ObjectMotionState for when Bullet lib is not found --- libraries/physics/src/EntityMotionState.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index ffd9e006e9..ca938f9c5e 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -19,7 +19,8 @@ // ObjectMotionState stubbery class ObjectMotionState { public: - bool _foo; + // so that this stub implementation is not completely empty we give the class a data member + bool _stubData; }; #endif // USE_BULLET_PHYSICS From ba873deb4918bbb10d60c3c5c3625b0decdaafb3 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 30 Dec 2014 11:38:24 -0800 Subject: [PATCH 101/105] ignore Entity updates that don't change anything --- libraries/entities/src/EntityItem.cpp | 45 ++++++++++++++++++--------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 586ee5461e..314a6c7a6f 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1000,8 +1000,17 @@ void EntityItem::recalculateCollisionShape() { // TODO: use motionState to update physics object } +const float MIN_POSITION_DELTA = 0.0001f; +const float MIN_DIMENSION_DELTA = 0.0001f; +const float MIN_ALIGNMENT_DOT = 0.9999f; +const float MIN_MASS_DELTA = 0.001f; +const float MIN_VELOCITY_DELTA = 0.025f; +const float MIN_GRAVITY_DELTA = 0.001f; +const float MIN_SPIN_DELTA = 0.0003f; + void EntityItem::updatePosition(const glm::vec3& value) { - if (_position != value) { + glm::vec3 debugPosition = value * (float) TREE_SCALE; + if (glm::distance(_position, value) * (float)TREE_SCALE > MIN_POSITION_DELTA) { _position = value; recalculateCollisionShape(); _dirtyFlags |= EntityItem::DIRTY_POSITION; @@ -1010,7 +1019,7 @@ void EntityItem::updatePosition(const glm::vec3& value) { void EntityItem::updatePositionInMeters(const glm::vec3& value) { glm::vec3 position = glm::clamp(value / (float) TREE_SCALE, 0.0f, 1.0f); - if (_position != position) { + if (glm::distance(_position, position) * (float)TREE_SCALE > MIN_POSITION_DELTA) { _position = position; recalculateCollisionShape(); _dirtyFlags |= EntityItem::DIRTY_POSITION; @@ -1018,7 +1027,7 @@ void EntityItem::updatePositionInMeters(const glm::vec3& value) { } void EntityItem::updateDimensions(const glm::vec3& value) { - if (_dimensions != value) { + if (glm::distance(_dimensions, value) * (float)TREE_SCALE > MIN_DIMENSION_DELTA) { _dimensions = value; recalculateCollisionShape(); _dirtyFlags |= (EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS); @@ -1027,7 +1036,7 @@ void EntityItem::updateDimensions(const glm::vec3& value) { void EntityItem::updateDimensionsInMeters(const glm::vec3& value) { glm::vec3 dimensions = value / (float) TREE_SCALE; - if (_dimensions != dimensions) { + if (glm::distance(_dimensions, dimensions) * (float)TREE_SCALE > MIN_DIMENSION_DELTA) { _dimensions = dimensions; recalculateCollisionShape(); _dirtyFlags |= (EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS); @@ -1035,7 +1044,7 @@ void EntityItem::updateDimensionsInMeters(const glm::vec3& value) { } void EntityItem::updateRotation(const glm::quat& rotation) { - if (_rotation != rotation) { + if (glm::dot(_rotation, rotation) < MIN_ALIGNMENT_DOT) { _rotation = rotation; recalculateCollisionShape(); _dirtyFlags |= EntityItem::DIRTY_POSITION; @@ -1043,29 +1052,37 @@ void EntityItem::updateRotation(const glm::quat& rotation) { } void EntityItem::updateMass(float value) { - if (_mass != value) { + if (fabsf(_mass - value) > MIN_MASS_DELTA) { _mass = value; _dirtyFlags |= EntityItem::DIRTY_MASS; } } -void EntityItem::updateVelocity(const glm::vec3& value) { - if (_velocity != value) { - _velocity = value; +void EntityItem::updateVelocity(const glm::vec3& value) { + if (glm::distance(_velocity, value) * (float)TREE_SCALE > MIN_VELOCITY_DELTA) { + if (glm::length(value) * (float)TREE_SCALE < MIN_VELOCITY_DELTA) { + _velocity = glm::vec3(0.0f); + } else { + _velocity = value; + } _dirtyFlags |= EntityItem::DIRTY_VELOCITY; } } void EntityItem::updateVelocityInMeters(const glm::vec3& value) { glm::vec3 velocity = value / (float) TREE_SCALE; - if (_velocity != velocity) { - _velocity = velocity; + if (glm::distance(_velocity, velocity) * (float)TREE_SCALE > MIN_VELOCITY_DELTA) { + if (glm::length(value) < MIN_VELOCITY_DELTA) { + _velocity = glm::vec3(0.0f); + } else { + _velocity = velocity; + } _dirtyFlags |= EntityItem::DIRTY_VELOCITY; } } void EntityItem::updateGravity(const glm::vec3& value) { - if (_gravity != value) { + if (glm::distance(_gravity, value) * (float)TREE_SCALE > MIN_GRAVITY_DELTA) { _gravity = value; _dirtyFlags |= EntityItem::DIRTY_VELOCITY; } @@ -1073,14 +1090,14 @@ void EntityItem::updateGravity(const glm::vec3& value) { void EntityItem::updateGravityInMeters(const glm::vec3& value) { glm::vec3 gravity = value / (float) TREE_SCALE; - if (_gravity != gravity) { + if ( glm::distance(_gravity, gravity) * (float)TREE_SCALE > MIN_GRAVITY_DELTA) { _gravity = gravity; _dirtyFlags |= EntityItem::DIRTY_VELOCITY; } } void EntityItem::updateAngularVelocity(const glm::vec3& value) { - if (_angularVelocity != value) { + if (glm::distance(_angularVelocity, value) > MIN_SPIN_DELTA) { _angularVelocity = value; _dirtyFlags |= EntityItem::DIRTY_VELOCITY; } From da551a0a7677af37dd7f5ff85096f25f2666a53a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 30 Dec 2014 11:56:39 -0800 Subject: [PATCH 102/105] restore script change detection to what it was --- libraries/entities/src/EntityItem.cpp | 11 ++--------- libraries/entities/src/EntityItem.h | 4 ---- libraries/entities/src/EntityTree.cpp | 9 ++++----- libraries/entities/src/EntityTreeElement.cpp | 7 +++++++ 4 files changed, 13 insertions(+), 18 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 314a6c7a6f..d0b019467c 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -522,7 +522,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY_SETTER(PROP_GRAVITY, glm::vec3, updateGravity); READ_ENTITY_PROPERTY(PROP_DAMPING, float, _damping); READ_ENTITY_PROPERTY_SETTER(PROP_LIFETIME, float, updateLifetime); - READ_ENTITY_PROPERTY_STRING(PROP_SCRIPT, updateScript); + READ_ENTITY_PROPERTY_STRING(PROP_SCRIPT, setScript); READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, _registrationPoint); READ_ENTITY_PROPERTY_SETTER(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity); READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, _angularDamping); @@ -806,7 +806,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(gravity, updateGravityInMeters); SET_ENTITY_PROPERTY_FROM_PROPERTIES(damping, setDamping); SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, updateLifetime); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, updateScript); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, setScript); SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, setRegistrationPoint); SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularVelocity, updateAngularVelocity); SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularDamping, setAngularDamping); @@ -1124,10 +1124,3 @@ void EntityItem::updateLifetime(float value) { } } -void EntityItem::updateScript(const QString& value) { - if (_script != value) { - _script = value; - _dirtyFlags |= EntityItem::DIRTY_SCRIPT; - } -} - diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 5da7ec67fb..7acb55e8c3 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -51,9 +51,6 @@ public: DIRTY_SHAPE = 0x0020, DIRTY_LIFETIME = 0x0040, DIRTY_UPDATEABLE = 0x0080, - // add new simulation-relevant flags above - // all other flags below - DIRTY_SCRIPT = 0x8000 }; DONT_ALLOW_INSTANTIATION // This class can not be instantiated directly @@ -294,7 +291,6 @@ public: void updateIgnoreForCollisions(bool value); void updateCollisionsWillMove(bool value); void updateLifetime(float value); - void updateScript(const QString& value); uint32_t getDirtyFlags() const { return _dirtyFlags; } void clearDirtyFlags(uint32_t mask = 0xffff) { _dirtyFlags &= ~mask; } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 3849256053..73d944b084 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -139,11 +139,6 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro uint32_t newFlags = entity->getDirtyFlags() & ~preFlags; if (newFlags) { - if (newFlags & EntityItem::DIRTY_SCRIPT) { - emit entityScriptChanging(entity->getEntityItemID()); - entity->clearDirtyFlags(EntityItem::DIRTY_SCRIPT); - } - if (_simulation) { if (newFlags & DIRTY_SIMULATION_FLAGS) { _simulation->entityChanged(entity); @@ -224,6 +219,10 @@ void EntityTree::trackDeletedEntity(EntityItem* entity) { } } +void EntityTree::emitEntityScriptChanging(const EntityItemID& entityItemID) { + emit entityScriptChanging(entityItemID); +} + void EntityTree::setSimulation(EntitySimulation* simulation) { if (simulation) { // assert that the simulation's backpointer has already been properly connected diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 0c30415a1a..55693b6ff9 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -760,6 +760,7 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int // TODO: Do we need to also do this? // 3) remember the old cube for the entity so we can mark it as dirty if (entityItem) { + QString entityScriptBefore = entityItem->getScript(); bool bestFitBefore = bestFitEntityBounds(entityItem); EntityTreeElement* currentContainingElement = _myTree->getContainingElement(entityItemID); @@ -780,6 +781,12 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int } } } + + QString entityScriptAfter = entityItem->getScript(); + if (entityScriptBefore != entityScriptAfter) { + _myTree->emitEntityScriptChanging(entityItemID); // the entity script has changed + } + } else { entityItem = EntityTypes::constructEntityItem(dataAt, bytesLeftToRead, args); if (entityItem) { From e43d7b7369de6d900712aee7e35853a338f02d7b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 30 Dec 2014 12:05:28 -0800 Subject: [PATCH 103/105] fix indentation in ctor init --- libraries/physics/src/ObjectMotionState.cpp | 32 ++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 1d315d4983..fc97a2a789 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -44,22 +44,22 @@ const glm::vec3& ObjectMotionState::getWorldOffset() { ObjectMotionState::ObjectMotionState() : - _density(DEFAULT_DENSITY), - _volume(DEFAULT_VOLUME), - _friction(DEFAULT_FRICTION), - _restitution(DEFAULT_RESTITUTION), - _wasInWorld(false), - _motionType(MOTION_TYPE_STATIC), - _body(NULL), - _sentMoving(false), - _numNonMovingUpdates(0), - _outgoingPacketFlags(DIRTY_PHYSICS_FLAGS), - _sentFrame(0), - _sentPosition(0.0f), - _sentRotation(), - _sentVelocity(0.0f), - _sentAngularVelocity(0.0f), - _sentAcceleration(0.0f) { + _density(DEFAULT_DENSITY), + _volume(DEFAULT_VOLUME), + _friction(DEFAULT_FRICTION), + _restitution(DEFAULT_RESTITUTION), + _wasInWorld(false), + _motionType(MOTION_TYPE_STATIC), + _body(NULL), + _sentMoving(false), + _numNonMovingUpdates(0), + _outgoingPacketFlags(DIRTY_PHYSICS_FLAGS), + _sentFrame(0), + _sentPosition(0.0f), + _sentRotation(), + _sentVelocity(0.0f), + _sentAngularVelocity(0.0f), + _sentAcceleration(0.0f) { } ObjectMotionState::~ObjectMotionState() { From 5e2246625b1b49f0b6b2749c1cfc97b371b14011 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 30 Dec 2014 12:09:22 -0800 Subject: [PATCH 104/105] fix layout to abide by the coding standard --- libraries/physics/src/EntityMotionState.cpp | 4 ++-- libraries/physics/src/EntityMotionState.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index be771fd801..8dddc6e5cc 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -55,7 +55,7 @@ MotionType EntityMotionState::computeMotionType() const { // (irregardless of MotionType: STATIC, DYNAMIC, or KINEMATIC) // (2) at the beginning of each simulation frame for KINEMATIC RigidBody's -- // it is an opportunity for outside code to update the object's simulation position -void EntityMotionState::getWorldTransform (btTransform &worldTrans) const { +void EntityMotionState::getWorldTransform(btTransform& worldTrans) const { btVector3 pos; glmToBullet(_entity->getPositionInMeters() - ObjectMotionState::getWorldOffset(), pos); worldTrans.setOrigin(pos); @@ -67,7 +67,7 @@ void EntityMotionState::getWorldTransform (btTransform &worldTrans) const { // This callback is invoked by the physics simulation at the end of each simulation frame... // iff the corresponding RigidBody is DYNAMIC and has moved. -void EntityMotionState::setWorldTransform (const btTransform &worldTrans) { +void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { glm::vec3 pos; bulletToGLM(worldTrans.getOrigin(), pos); _entity->setPositionInMeters(pos + ObjectMotionState::getWorldOffset()); diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index ca938f9c5e..379470087f 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -47,10 +47,10 @@ public: #ifdef USE_BULLET_PHYSICS // this relays incoming position/rotation to the RigidBody - void getWorldTransform (btTransform &worldTrans) const; + void getWorldTransform(btTransform& worldTrans) const; // this relays outgoing position/rotation to the EntityItem - void setWorldTransform (const btTransform &worldTrans); + void setWorldTransform(const btTransform& worldTrans); #endif // USE_BULLET_PHYSICS // these relay incoming values to the RigidBody From 6f72d4ad81b0298fd81ed9408a31eaa7f10a72be Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 30 Dec 2014 13:15:57 -0800 Subject: [PATCH 105/105] easier to read Bullet to GLM conversions and back --- libraries/physics/src/BulletUtil.h | 21 ++++++---------- libraries/physics/src/EntityMotionState.cpp | 28 +++++++-------------- libraries/physics/src/ObjectMotionState.cpp | 22 ++++++---------- libraries/physics/src/ShapeInfoUtil.cpp | 15 ++++------- tests/physics/src/BulletUtilTests.cpp | 12 +++------ 5 files changed, 33 insertions(+), 65 deletions(-) diff --git a/libraries/physics/src/BulletUtil.h b/libraries/physics/src/BulletUtil.h index 41d78dd97e..78524a122e 100644 --- a/libraries/physics/src/BulletUtil.h +++ b/libraries/physics/src/BulletUtil.h @@ -18,25 +18,20 @@ #include #include -inline void bulletToGLM(const btVector3& b, glm::vec3& g) { - g = glm::vec3(b.getX(), b.getY(), b.getZ()); +inline glm::vec3 bulletToGLM(const btVector3& b) { + return glm::vec3(b.getX(), b.getY(), b.getZ()); } -inline void bulletToGLM(const btQuaternion& b, glm::quat& g) { - g.x = b.getX(); - g.y = b.getY(); - g.z = b.getZ(); - g.w = b.getW(); +inline glm::quat bulletToGLM(const btQuaternion& b) { + return glm::quat(b.getW(), b.getX(), b.getY(), b.getZ()); } -inline void glmToBullet(const glm::vec3& g, btVector3& b) { - b.setX(g.x); - b.setY(g.y); - b.setZ(g.z); +inline btVector3 glmToBullet(const glm::vec3& g) { + return btVector3(g.x, g.y, g.z); } -inline void glmToBullet(const glm::quat& g, btQuaternion& b) { - b = btQuaternion(g.x, g.y, g.z, g.w); +inline btQuaternion glmToBullet(const glm::quat& g) { + return btQuaternion(g.x, g.y, g.z, g.w); } #endif // USE_BULLET_PHYSICS diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 8dddc6e5cc..6e26f2b9de 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -56,25 +56,15 @@ MotionType EntityMotionState::computeMotionType() const { // (2) at the beginning of each simulation frame for KINEMATIC RigidBody's -- // it is an opportunity for outside code to update the object's simulation position void EntityMotionState::getWorldTransform(btTransform& worldTrans) const { - btVector3 pos; - glmToBullet(_entity->getPositionInMeters() - ObjectMotionState::getWorldOffset(), pos); - worldTrans.setOrigin(pos); - - btQuaternion rot; - glmToBullet(_entity->getRotation(), rot); - worldTrans.setRotation(rot); + worldTrans.setOrigin(glmToBullet(_entity->getPositionInMeters() - ObjectMotionState::getWorldOffset())); + worldTrans.setRotation(glmToBullet(_entity->getRotation())); } // This callback is invoked by the physics simulation at the end of each simulation frame... // iff the corresponding RigidBody is DYNAMIC and has moved. void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { - glm::vec3 pos; - bulletToGLM(worldTrans.getOrigin(), pos); - _entity->setPositionInMeters(pos + ObjectMotionState::getWorldOffset()); - - glm::quat rot; - bulletToGLM(worldTrans.getRotation(), rot); - _entity->setRotation(rot); + _entity->setPositionInMeters(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset()); + _entity->setRotation(bulletToGLM(worldTrans.getRotation())); glm::vec3 v; getVelocity(v); @@ -118,17 +108,17 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ if (_outgoingPacketFlags & EntityItem::DIRTY_POSITION) { btTransform worldTrans = _body->getWorldTransform(); - bulletToGLM(worldTrans.getOrigin(), _sentPosition); + _sentPosition = bulletToGLM(worldTrans.getOrigin()); properties.setPosition(_sentPosition + ObjectMotionState::getWorldOffset()); - bulletToGLM(worldTrans.getRotation(), _sentRotation); + _sentRotation = bulletToGLM(worldTrans.getRotation()); properties.setRotation(_sentRotation); } if (_outgoingPacketFlags & EntityItem::DIRTY_VELOCITY) { if (_body->isActive()) { - bulletToGLM(_body->getLinearVelocity(), _sentVelocity); - bulletToGLM(_body->getAngularVelocity(), _sentAngularVelocity); + _sentVelocity = bulletToGLM(_body->getLinearVelocity()); + _sentAngularVelocity = bulletToGLM(_body->getAngularVelocity()); // if the speeds are very small we zero them out const float MINIMUM_EXTRAPOLATION_SPEED_SQUARED = 4.0e-6f; // 2mm/sec @@ -148,7 +138,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ _sentMoving = false; } properties.setVelocity(_sentVelocity); - bulletToGLM(_body->getGravity(), _sentAcceleration); + _sentAcceleration = bulletToGLM(_body->getGravity()); properties.setGravity(_sentAcceleration); properties.setAngularVelocity(_sentAngularVelocity); } diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index fc97a2a789..ded2291229 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -84,29 +84,23 @@ void ObjectMotionState::setVolume(float volume) { } void ObjectMotionState::setVelocity(const glm::vec3& velocity) const { - btVector3 v; - glmToBullet(velocity, v); - _body->setLinearVelocity(v); + _body->setLinearVelocity(glmToBullet(velocity)); } void ObjectMotionState::setAngularVelocity(const glm::vec3& velocity) const { - btVector3 v; - glmToBullet(velocity, v); - _body->setAngularVelocity(v); + _body->setAngularVelocity(glmToBullet(velocity)); } void ObjectMotionState::setGravity(const glm::vec3& gravity) const { - btVector3 g; - glmToBullet(gravity, g); - _body->setGravity(g); + _body->setGravity(glmToBullet(gravity)); } void ObjectMotionState::getVelocity(glm::vec3& velocityOut) const { - bulletToGLM(_body->getLinearVelocity(), velocityOut); + velocityOut = bulletToGLM(_body->getLinearVelocity()); } void ObjectMotionState::getAngularVelocity(glm::vec3& angularVelocityOut) const { - bulletToGLM(_body->getAngularVelocity(), angularVelocityOut); + angularVelocityOut = bulletToGLM(_body->getAngularVelocity()); } // RELIABLE_SEND_HACK: until we have truly reliable resends of non-moving updates @@ -154,9 +148,8 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame, float subStep // compute position error glm::vec3 extrapolatedPosition = _sentPosition + dt * (_sentVelocity + (0.5f * dt) * _sentAcceleration); - glm::vec3 position; btTransform worldTrans = _body->getWorldTransform(); - bulletToGLM(worldTrans.getOrigin(), position); + glm::vec3 position = bulletToGLM(worldTrans.getOrigin()); float dx2 = glm::distance2(position, extrapolatedPosition); const float MAX_POSITION_ERROR_SQUARED = 0.001f; // 0.001 m^2 ~~> 0.03 m @@ -173,8 +166,7 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame, float subStep extrapolatedRotation = glm::angleAxis(dt * spin, axis) * _sentRotation; } const float MIN_ROTATION_DOT = 0.98f; - glm::quat actualRotation; - bulletToGLM(worldTrans.getRotation(), actualRotation); + glm::quat actualRotation = bulletToGLM(worldTrans.getRotation()); return (glm::dot(actualRotation, extrapolatedRotation) < MIN_ROTATION_DOT); } diff --git a/libraries/physics/src/ShapeInfoUtil.cpp b/libraries/physics/src/ShapeInfoUtil.cpp index 3d8e0b77a8..f562201f73 100644 --- a/libraries/physics/src/ShapeInfoUtil.cpp +++ b/libraries/physics/src/ShapeInfoUtil.cpp @@ -62,9 +62,7 @@ void ShapeInfoUtil::collectInfoFromShape(const btCollisionShape* shape, ShapeInf switch(type) { case BOX_SHAPE: { const btBoxShape* boxShape = static_cast(shape); - glm::vec3 halfExtents; - bulletToGLM(boxShape->getHalfExtentsWithMargin(), halfExtents); - info.setBox(halfExtents); + info.setBox(bulletToGLM(boxShape->getHalfExtentsWithMargin())); } break; case SPHERE_SHAPE: { @@ -99,9 +97,8 @@ btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) { const QVector& data = info.getData(); switch(info.getType()) { case BOX_SHAPE: { - btVector3 halfExtents; - glmToBullet(data[0], halfExtents); - shape = new btBoxShape(halfExtents); + // data[0] is halfExtents + shape = new btBoxShape(glmToBullet(data[0])); } break; case SPHERE_SHAPE: { @@ -110,11 +107,9 @@ btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) { } break; case CYLINDER_SHAPE: { - btVector3 halfExtents; - glmToBullet(data[0], halfExtents); // NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X - // halfExtents = btVector3(radius, halfHeight, unused) - shape = new btCylinderShape(halfExtents); + // data[0] = btVector3(radius, halfHeight, unused) + shape = new btCylinderShape(glmToBullet(data[0])); } break; case CAPSULE_SHAPE: { diff --git a/tests/physics/src/BulletUtilTests.cpp b/tests/physics/src/BulletUtilTests.cpp index 823d0d01b2..06b1815c6e 100644 --- a/tests/physics/src/BulletUtilTests.cpp +++ b/tests/physics/src/BulletUtilTests.cpp @@ -19,8 +19,7 @@ #ifdef USE_BULLET_PHYSICS void BulletUtilTests::fromBulletToGLM() { btVector3 bV(1.23f, 4.56f, 7.89f); - glm::vec3 gV; - bulletToGLM(bV, gV); + glm::vec3 gV = bulletToGLM(bV); if (gV.x != bV.getX()) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: x mismatch bullet.x = " << bV.getX() << " != glm.x = " << gV.x << std::endl; @@ -39,8 +38,7 @@ void BulletUtilTests::fromBulletToGLM() { axis.normalize(); btQuaternion bQ(axis, angle); - glm::quat gQ; - bulletToGLM(bQ, gQ); + glm::quat gQ = bulletToGLM(bQ); if (gQ.x != bQ.getX()) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: x mismatch bullet.x = " << bQ.getX() << " != glm.x = " << gQ.x << std::endl; @@ -61,8 +59,7 @@ void BulletUtilTests::fromBulletToGLM() { void BulletUtilTests::fromGLMToBullet() { glm::vec3 gV(1.23f, 4.56f, 7.89f); - btVector3 bV; - glmToBullet(gV, bV); + btVector3 bV = glmToBullet(gV); if (gV.x != bV.getX()) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: x mismatch glm.x = " << gV.x << " != bullet.x = " << bV.getX() << std::endl; @@ -81,8 +78,7 @@ void BulletUtilTests::fromGLMToBullet() { axis.normalize(); btQuaternion bQ(axis, angle); - glm::quat gQ; - bulletToGLM(bQ, gQ); + glm::quat gQ = bulletToGLM(bQ); if (gQ.x != bQ.getX()) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: x mismatch glm.x = " << gQ.x << " != bullet.x = " << bQ.getX() << std::endl;