From 549e3fac5f528573f62b22bd774cfec6e8b45255 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 20 Jan 2015 10:45:58 -0800 Subject: [PATCH 01/12] store backpointer to MotionState in btRigidBody --- libraries/physics/src/ObjectMotionState.cpp | 13 +++++++++++++ libraries/physics/src/ObjectMotionState.h | 7 +++++-- libraries/physics/src/PhysicsEngine.cpp | 12 ++++++------ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index f4997b679c..cab36b8370 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -170,3 +170,16 @@ void ObjectMotionState::removeKinematicController() { _kinematicController = NULL; } } + +void ObjectMotionState::setRigidBody(btRigidBody* body) { + // give the body a (void*) back-pointer to this ObjectMotionState + if (_body != body) { + if (_body) { + _body->setUserPointer(NULL); + } + _body = body; + if (_body) { + _body->setUserPointer(this); + } + } +} diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 4d454554cb..0620d030b2 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -88,9 +88,13 @@ public: virtual void addKinematicController() = 0; virtual void removeKinematicController(); + btRigidBody* getRigidBody() const { return _body; } + friend class PhysicsEngine; protected: - // TODO: move these materials properties to EntityItem + void setRigidBody(btRigidBody* body); + + // TODO: move these materials properties outside of ObjectMotionState float _friction; float _restitution; float _linearDamping; @@ -98,7 +102,6 @@ protected: MotionType _motionType; - // _body has NO setters -- it is only changed by PhysicsEngine btRigidBody* _body; bool _sentMoving; // true if last update was moving diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 90fd6c65cd..ca64184bd7 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -132,7 +132,7 @@ void PhysicsEngine::relayIncomingChangesToSimulation() { ObjectMotionState* motionState = *stateItr; uint32_t flags = motionState->getIncomingDirtyFlags() & DIRTY_PHYSICS_FLAGS; - btRigidBody* body = motionState->_body; + btRigidBody* body = motionState->getRigidBody(); if (body) { if (flags & HARD_DIRTY_PHYSICS_FLAGS) { // a HARD update requires the body be pulled out of physics engine, changed, then reinserted @@ -258,7 +258,7 @@ bool PhysicsEngine::addObject(ObjectMotionState* motionState) { body = new btRigidBody(mass, motionState, shape, inertia); body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); body->updateInertiaTensor(); - motionState->_body = body; + motionState->setRigidBody(body); motionState->addKinematicController(); const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec @@ -270,7 +270,7 @@ bool PhysicsEngine::addObject(ObjectMotionState* motionState) { shape->calculateLocalInertia(mass, inertia); body = new btRigidBody(mass, motionState, shape, inertia); body->updateInertiaTensor(); - motionState->_body = body; + motionState->setRigidBody(body); motionState->updateObjectVelocities(); // NOTE: Bullet will deactivate any object whose velocity is below these thresholds for longer than 2 seconds. // (the 2 seconds is determined by: static btRigidBody::gDeactivationTime @@ -284,7 +284,7 @@ bool PhysicsEngine::addObject(ObjectMotionState* motionState) { body = new btRigidBody(mass, motionState, shape, inertia); body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT); body->updateInertiaTensor(); - motionState->_body = body; + motionState->setRigidBody(body); break; } } @@ -301,7 +301,7 @@ bool PhysicsEngine::addObject(ObjectMotionState* motionState) { bool PhysicsEngine::removeObject(ObjectMotionState* motionState) { assert(motionState); - btRigidBody* body = motionState->_body; + btRigidBody* body = motionState->getRigidBody(); if (body) { const btCollisionShape* shape = body->getCollisionShape(); ShapeInfo shapeInfo; @@ -309,7 +309,7 @@ bool PhysicsEngine::removeObject(ObjectMotionState* motionState) { _dynamicsWorld->removeRigidBody(body); _shapeManager.releaseShape(shapeInfo); delete body; - motionState->_body = NULL; + motionState->setRigidBody(NULL); motionState->removeKinematicController(); return true; } From 0154c613d0af2f8c806e70026b7c21dc41788943 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 20 Jan 2015 11:02:48 -0800 Subject: [PATCH 02/12] change FrameCount to NumSubsteps for more accuracy --- libraries/physics/src/KinematicController.cpp | 4 ++-- libraries/physics/src/KinematicController.h | 2 +- libraries/physics/src/PhysicsEngine.cpp | 24 ++++++++++++------- libraries/physics/src/PhysicsEngine.h | 4 +++- .../src/SimpleEntityKinematicController.cpp | 6 ++--- 5 files changed, 24 insertions(+), 16 deletions(-) diff --git a/libraries/physics/src/KinematicController.cpp b/libraries/physics/src/KinematicController.cpp index abcf669694..354b285bc1 100644 --- a/libraries/physics/src/KinematicController.cpp +++ b/libraries/physics/src/KinematicController.cpp @@ -13,10 +13,10 @@ #include "PhysicsEngine.h" KinematicController::KinematicController() { - _lastFrame = PhysicsEngine::getFrameCount(); + _lastSubstep = PhysicsEngine::getNumSubsteps(); } void KinematicController::start() { _enabled = true; - _lastFrame = PhysicsEngine::getFrameCount(); + _lastSubstep = PhysicsEngine::getNumSubsteps(); } diff --git a/libraries/physics/src/KinematicController.h b/libraries/physics/src/KinematicController.h index 382d4cbfd9..60b8548607 100644 --- a/libraries/physics/src/KinematicController.h +++ b/libraries/physics/src/KinematicController.h @@ -30,7 +30,7 @@ public: protected: bool _enabled = false; - uint32_t _lastFrame; + uint32_t _lastSubstep; }; #endif // hifi_KinematicController_h diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index ca64184bd7..af4a49aefe 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -13,11 +13,11 @@ #include "ShapeInfoUtil.h" #include "ThreadSafeDynamicsWorld.h" -static uint32_t _frameCount; +static uint32_t _numSubsteps; // static -uint32_t PhysicsEngine::getFrameCount() { - return _frameCount; +uint32_t PhysicsEngine::getNumSubsteps() { + return _numSubsteps; } PhysicsEngine::PhysicsEngine(const glm::vec3& offset) @@ -47,8 +47,8 @@ void PhysicsEngine::updateEntitiesInternal(const quint64& now) { ObjectMotionState* state = *stateItr; if (state->doesNotNeedToSendUpdate()) { stateItr = _outgoingPackets.erase(stateItr); - } else if (state->shouldSendUpdate(_frameCount)) { - state->sendUpdate(_entityPacketSender, _frameCount); + } else if (state->shouldSendUpdate(_numSubsteps)) { + state->sendUpdate(_entityPacketSender, _numSubsteps); ++stateItr; } else { ++stateItr; @@ -141,7 +141,7 @@ void PhysicsEngine::relayIncomingChangesToSimulation() { } else if (flags) { // an EASY update does NOT require that the body be pulled out of physics engine // hence the MotionState has all the knowledge and authority to perform the update. - motionState->updateObjectEasy(flags, _frameCount); + motionState->updateObjectEasy(flags, _numSubsteps); } } @@ -216,8 +216,8 @@ void PhysicsEngine::stepSimulation() { float timeStep = btMin(dt, MAX_TIMESTEP); // This is step (2). - int numSubSteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP); - _frameCount += (uint32_t)numSubSteps; + int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP); + _numSubsteps += (uint32_t)numSubsteps; unlock(); // This is step (3) which is done outside of stepSimulation() so we can lock _entityTree. @@ -233,6 +233,12 @@ void PhysicsEngine::stepSimulation() { _dynamicsWorld->synchronizeMotionStates(); unlock(); _entityTree->unlock(); + + handleCollisionEvents(); +} + +void PhysicsEngine::handleCollisionEvents() { + } // Bullet collision flags are as follows: @@ -352,7 +358,7 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio } bool easyUpdate = flags & EASY_DIRTY_PHYSICS_FLAGS; if (easyUpdate) { - motionState->updateObjectEasy(flags, _frameCount); + motionState->updateObjectEasy(flags, _numSubsteps); } // update the motion parameters diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index f37f12ea8d..7304f598e2 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -33,7 +33,7 @@ class ObjectMotionState; class PhysicsEngine : public EntitySimulation { public: - static uint32_t getFrameCount(); + static uint32_t getNumSubsteps(); PhysicsEngine(const glm::vec3& offset); @@ -51,6 +51,8 @@ public: void stepSimulation(); + void handleCollisionEvents(); + /// \param offset position of simulation origin in domain-frame void setOriginOffset(const glm::vec3& offset) { _originOffset = offset; } diff --git a/libraries/physics/src/SimpleEntityKinematicController.cpp b/libraries/physics/src/SimpleEntityKinematicController.cpp index 478ec1d12f..e834d4e91b 100644 --- a/libraries/physics/src/SimpleEntityKinematicController.cpp +++ b/libraries/physics/src/SimpleEntityKinematicController.cpp @@ -13,9 +13,9 @@ #include "SimpleEntityKinematicController.h" void SimpleEntityKinematicController:: stepForward() { - uint32_t frame = PhysicsEngine::getFrameCount(); - float dt = (frame - _lastFrame) * PHYSICS_ENGINE_FIXED_SUBSTEP; + uint32_t substep = PhysicsEngine::getNumSubsteps(); + float dt = (substep - _lastSubstep) * PHYSICS_ENGINE_FIXED_SUBSTEP; _entity->simulateSimpleKinematicMotion(dt); - _lastFrame = frame; + _lastSubstep = substep; } From 5da38834e2e762f387ecc23cd1c48bdd92e12020 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 20 Jan 2015 11:16:40 -0800 Subject: [PATCH 03/12] introduce notion of NumSteps vs NumSubsteps --- libraries/physics/src/PhysicsEngine.cpp | 12 +++--------- libraries/physics/src/PhysicsEngine.h | 23 +++++++++++------------ 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index af4a49aefe..870fdc6a9d 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -21,13 +21,7 @@ uint32_t PhysicsEngine::getNumSubsteps() { } PhysicsEngine::PhysicsEngine(const glm::vec3& offset) - : _collisionConfig(NULL), - _collisionDispatcher(NULL), - _broadphaseFilter(NULL), - _constraintSolver(NULL), - _dynamicsWorld(NULL), - _originOffset(offset), - _entityPacketSender(NULL) { + : _originOffset(offset) { } PhysicsEngine::~PhysicsEngine() { @@ -234,10 +228,10 @@ void PhysicsEngine::stepSimulation() { unlock(); _entityTree->unlock(); - handleCollisionEvents(); + computeCollisionEvents(); } -void PhysicsEngine::handleCollisionEvents() { +void PhysicsEngine::computeCollisionEvents() { } diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 7304f598e2..1f4efc6b06 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -33,8 +33,10 @@ class ObjectMotionState; class PhysicsEngine : public EntitySimulation { public: + // TODO: find a good way to make this a non-static method static uint32_t getNumSubsteps(); + PhysicsEngine() = delete; // prevent compiler from creating default ctor PhysicsEngine(const glm::vec3& offset); ~PhysicsEngine(); @@ -51,7 +53,7 @@ public: void stepSimulation(); - void handleCollisionEvents(); + void computeCollisionEvents(); /// \param offset position of simulation origin in domain-frame void setOriginOffset(const glm::vec3& offset) { _originOffset = offset; } @@ -70,22 +72,18 @@ public: /// process queue of changed from external sources void relayIncomingChangesToSimulation(); - /// \return duration of fixed simulation substep - float getFixedSubStep() const; - -protected: +private: void updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); void updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); btClock _clock; - btDefaultCollisionConfiguration* _collisionConfig; - btCollisionDispatcher* _collisionDispatcher; - btBroadphaseInterface* _broadphaseFilter; - btSequentialImpulseConstraintSolver* _constraintSolver; - ThreadSafeDynamicsWorld* _dynamicsWorld; + btDefaultCollisionConfiguration* _collisionConfig = NULL; + btCollisionDispatcher* _collisionDispatcher = NULL; + btBroadphaseInterface* _broadphaseFilter = NULL; + btSequentialImpulseConstraintSolver* _constraintSolver = NULL; + ThreadSafeDynamicsWorld* _dynamicsWorld = NULL; ShapeManager _shapeManager; -private: glm::vec3 _originOffset; // EntitySimulation stuff @@ -93,7 +91,8 @@ private: QSet _incomingChanges; // entities with pending physics changes by script or packet QSet _outgoingPackets; // MotionStates with pending changes that need to be sent over wire - EntityEditPacketSender* _entityPacketSender; + EntityEditPacketSender* _entityPacketSender = NULL; + uint32_t _numSteps = 0; // do not confuse with static _numSubsteps }; #endif // hifi_PhysicsEngine_h From 790d07d3461732094c87a928f3bc5eb0df7505cd Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 20 Jan 2015 14:18:10 -0800 Subject: [PATCH 04/12] track known contacts and generate collision events --- libraries/physics/src/ObjectMotionState.cpp | 8 ++++ libraries/physics/src/ObjectMotionState.h | 3 ++ libraries/physics/src/PhysicsEngine.cpp | 53 ++++++++++++++++++++- libraries/physics/src/PhysicsEngine.h | 17 ++++++- 4 files changed, 79 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index cab36b8370..929ddab3e0 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -171,6 +171,14 @@ void ObjectMotionState::removeKinematicController() { } } +void ObjectMotionState::handleContactEvent(ContactEventType type, ObjectMotionState* otherState) { + if (type == CONTACT_TYPE_START) { + std::cout << "adebug start " << (void*)(this) << " vs " << (void*)(otherState) << std::endl; // adebug + } else if (type == CONTACT_TYPE_END) { + std::cout << "adebug end " << (void*)(this) << " vs " << (void*)(otherState) << std::endl; // adebug + } +} + void ObjectMotionState::setRigidBody(btRigidBody* body) { // give the body a (void*) back-pointer to this ObjectMotionState if (_body != body) { diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 0620d030b2..2eda618d93 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -17,6 +17,7 @@ #include +#include "ContactInfo.h" #include "ShapeInfo.h" enum MotionType { @@ -88,6 +89,8 @@ public: virtual void addKinematicController() = 0; virtual void removeKinematicController(); + virtual void handleContactEvent(ContactEventType type, ObjectMotionState* otherState); + btRigidBody* getRigidBody() const { return _body; } friend class PhysicsEngine; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 870fdc6a9d..5a2881da71 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -154,6 +154,20 @@ void PhysicsEngine::relayIncomingChangesToSimulation() { _incomingChanges.clear(); } +void PhysicsEngine::removeContacts(ObjectMotionState* motionState) { + // trigger events for new/existing/old contacts + ContactMap::iterator contactItr = _contactMap.begin(); + while (contactItr != _contactMap.end()) { + if (contactItr->first._a == motionState || contactItr->first._b == motionState) { + ContactMap::iterator iterToDelete = contactItr; + ++contactItr; + _contactMap.erase(iterToDelete); + } else { + ++contactItr; + } + } +} + // virtual void PhysicsEngine::init(EntityEditPacketSender* packetSender) { // _entityTree should be set prior to the init() call @@ -232,7 +246,42 @@ void PhysicsEngine::stepSimulation() { } void PhysicsEngine::computeCollisionEvents() { - + // update all contacts + int numManifolds = _collisionDispatcher->getNumManifolds(); + for (int i = 0; i < numManifolds; ++i) { + btPersistentManifold* contactManifold = _collisionDispatcher->getManifoldByIndexInternal(i); + if (contactManifold->getNumContacts() > 0) { + const btCollisionObject* objectA = static_cast(contactManifold->getBody0()); + const btCollisionObject* objectB = static_cast(contactManifold->getBody1()); + + void* a = objectA->getUserPointer(); + void* b = objectB->getUserPointer(); + if (a || b ) { + _contactMap[ContactKey(a, b)].update(_numSubsteps); + } + } + } + + // scan known contacts and trigger events + ContactMap::iterator contactItr = _contactMap.begin(); + while (contactItr != _contactMap.end()) { + ContactEventType type = contactItr->second.computeType(_numSubsteps); + ObjectMotionState* A = static_cast(contactItr->first._a); + ObjectMotionState* B = static_cast(contactItr->first._b); + if (A) { + A->handleContactEvent(type, B); + } + if (B) { + B->handleContactEvent(type, A); + } + if (type == CONTACT_TYPE_END) { + ContactMap::iterator iterToDelete = contactItr; + ++contactItr; + _contactMap.erase(iterToDelete); + } else { + ++contactItr; + } + } } // Bullet collision flags are as follows: @@ -311,6 +360,8 @@ bool PhysicsEngine::removeObject(ObjectMotionState* motionState) { delete body; motionState->setRigidBody(NULL); motionState->removeKinematicController(); + + removeContacts(motionState); return true; } return false; diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 1f4efc6b06..9db9f5a33a 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -23,6 +23,7 @@ const float PHYSICS_ENGINE_FIXED_SUBSTEP = 1.0f / 60.0f; #include #include "BulletUtil.h" +#include "ContactInfo.h" #include "EntityMotionState.h" #include "ShapeManager.h" #include "ThreadSafeDynamicsWorld.h" @@ -31,6 +32,18 @@ const float HALF_SIMULATION_EXTENT = 512.0f; // meters class ObjectMotionState; +// simple class for keeping track of contacts +class ContactKey { +public: + ContactKey() = delete; + ContactKey(void* a, void* b) : _a(a), _b(b) {} + bool operator<(const ContactKey& other) const { return _a < other._a || (_a == other._a && _b < other._b); } + void* _a; + void* _b; +}; + +typedef std::map ContactMap; + class PhysicsEngine : public EntitySimulation { public: // TODO: find a good way to make this a non-static method @@ -73,6 +86,7 @@ public: void relayIncomingChangesToSimulation(); private: + void removeContacts(ObjectMotionState* motionState); void updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); void updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); @@ -92,7 +106,8 @@ private: QSet _outgoingPackets; // MotionStates with pending changes that need to be sent over wire EntityEditPacketSender* _entityPacketSender = NULL; - uint32_t _numSteps = 0; // do not confuse with static _numSubsteps + + ContactMap _contactMap; }; #endif // hifi_PhysicsEngine_h From e82b07caf827af3c9c7a975ecc72ced33e319125 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Wed, 21 Jan 2015 11:26:08 -0600 Subject: [PATCH 05/12] Updated Windows build instructions --- BUILD_WIN.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/BUILD_WIN.md b/BUILD_WIN.md index cf8308c552..883b30b085 100644 --- a/BUILD_WIN.md +++ b/BUILD_WIN.md @@ -132,6 +132,35 @@ This package contains only headers, so there's nothing to add to the PATH. Be careful with glm. For the folder other libraries would normally call 'include', the folder containing the headers, glm opts to use 'glm'. You will have a glm folder nested inside the top-level glm folder. +###Bullet + +Bullet 2.82 source can be downloaded [here](https://code.google.com/p/bullet/downloads/detail?name=bullet-2.82-r2704.zip). Bullet does not come with prebuilt libraries, you need to make those yourself. + +* Download the zip file and extract into a temporary folder +* Create a directory named cmakebuild. Bullet comes with a build\ directory by default, however, that directory is intended for use with premake, and considering premake doesn't support VS2013, I prefer to run the cmake build on its own directory. +* Make the following modifications to Bullet's source: + 1. In file: Extras\HACD\hacdICHull.cpp --- in line: 17 --- insert: #include + 2. In file: src\MiniCL\cl_MiniCL_Defs.h --- comment lines 364 to 372 + 3. In file: CMakeLists.txt set to ON the option USE_MSVC_RUNTIME_LIBRARY_DLL in line 27 + +Then create the Visual Studio solution and build the libraries - run the following commands from a Visual Studio 2013 command prompt, from within the cmakebuild directory created before: + +```shell +cmake .. -G "Visual Studio 12" +msbuild BULLET_PHYSICS.sln /p:Configuration=Debug +``` + +This will create Debug libraries in cmakebuild\lib\Debug you can replace Debug with Release in the msbuild command and that will generate Release libraries in cmakebuild\lib\Release. + +You now have Bullet libraries compiled, now you need to put them in the right place for hifi to find them: + +* Create a directory named bullet\ inside your %HIFI_LIB_DIR% +* Create two directores named lib\ and include\ inside bullet\ +* Copy all the contents inside src\ from the bullet unzip path into %HIFI_LIB_DIR%\bullet\include\ +* Copy all the contents inside cmakebuild\lib\ into %HIFI_LIB_DIR\bullet\lib + +*Note that the INSTALL target should handle the copying of files into an install directory automatically, however, without modifications to Cmake, the install target didn't work right for me, please update this instructions if you get that working right - Leo " + ###Build High Fidelity using Visual Studio Follow the same build steps from the CMake section, but pass a different generator to CMake. From 93edd8203875fd0d27544449ecdedeede212c987 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Wed, 21 Jan 2015 11:28:50 -0600 Subject: [PATCH 06/12] Markdown fix --- BUILD_WIN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILD_WIN.md b/BUILD_WIN.md index 883b30b085..c12724a88f 100644 --- a/BUILD_WIN.md +++ b/BUILD_WIN.md @@ -159,7 +159,7 @@ You now have Bullet libraries compiled, now you need to put them in the right pl * Copy all the contents inside src\ from the bullet unzip path into %HIFI_LIB_DIR%\bullet\include\ * Copy all the contents inside cmakebuild\lib\ into %HIFI_LIB_DIR\bullet\lib -*Note that the INSTALL target should handle the copying of files into an install directory automatically, however, without modifications to Cmake, the install target didn't work right for me, please update this instructions if you get that working right - Leo " +_Note that the INSTALL target should handle the copying of files into an install directory automatically, however, without modifications to Cmake, the install target didn't work right for me, please update this instructions if you get that working right - Leo _ ###Build High Fidelity using Visual Studio Follow the same build steps from the CMake section, but pass a different generator to CMake. From a825f2a4953c51684734e6d778c122c5373d6015 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Wed, 21 Jan 2015 11:31:24 -0600 Subject: [PATCH 07/12] Markdown fix --- BUILD_WIN.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BUILD_WIN.md b/BUILD_WIN.md index c12724a88f..3ccc4881c1 100644 --- a/BUILD_WIN.md +++ b/BUILD_WIN.md @@ -139,7 +139,7 @@ Bullet 2.82 source can be downloaded [here](https://code.google.com/p/bullet/dow * Download the zip file and extract into a temporary folder * Create a directory named cmakebuild. Bullet comes with a build\ directory by default, however, that directory is intended for use with premake, and considering premake doesn't support VS2013, I prefer to run the cmake build on its own directory. * Make the following modifications to Bullet's source: - 1. In file: Extras\HACD\hacdICHull.cpp --- in line: 17 --- insert: #include + 1. In file: Extras\HACD\hacdICHull.cpp --- in line: 17 --- insert: #include <algorithm> 2. In file: src\MiniCL\cl_MiniCL_Defs.h --- comment lines 364 to 372 3. In file: CMakeLists.txt set to ON the option USE_MSVC_RUNTIME_LIBRARY_DLL in line 27 @@ -159,7 +159,7 @@ You now have Bullet libraries compiled, now you need to put them in the right pl * Copy all the contents inside src\ from the bullet unzip path into %HIFI_LIB_DIR%\bullet\include\ * Copy all the contents inside cmakebuild\lib\ into %HIFI_LIB_DIR\bullet\lib -_Note that the INSTALL target should handle the copying of files into an install directory automatically, however, without modifications to Cmake, the install target didn't work right for me, please update this instructions if you get that working right - Leo _ +_Note that the INSTALL target should handle the copying of files into an install directory automatically, however, without modifications to Cmake, the install target didn't work right for me, please update this instructions if you get that working right - Leo <leo@highfidelity.io>_ ###Build High Fidelity using Visual Studio Follow the same build steps from the CMake section, but pass a different generator to CMake. From 86583f3f3f3cb1a5c714536bfdee9b848011c30a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 21 Jan 2015 11:27:32 -0800 Subject: [PATCH 08/12] physics collisions emit script collision events --- interface/src/Application.cpp | 21 +++-------- interface/src/Application.h | 1 - .../entities/src/EntityCollisionSystem.cpp | 13 ++----- .../entities/src/EntityCollisionSystem.h | 9 +---- libraries/entities/src/EntitySimulation.h | 7 +++- libraries/physics/src/ContactInfo.cpp | 29 +++++++++++++++ libraries/physics/src/ContactInfo.h | 37 +++++++++++++++++++ libraries/physics/src/EntityMotionState.cpp | 1 + libraries/physics/src/EntityMotionState.h | 2 + libraries/physics/src/ObjectMotionState.cpp | 8 ---- libraries/physics/src/ObjectMotionState.h | 11 +++++- libraries/physics/src/PhysicsEngine.cpp | 31 +++++++++++----- libraries/physics/src/PhysicsEngine.h | 2 + 13 files changed, 119 insertions(+), 53 deletions(-) create mode 100644 libraries/physics/src/ContactInfo.cpp create mode 100644 libraries/physics/src/ContactInfo.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4dfe8313c6..78fd0f943e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -192,7 +192,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _justStarted(true), _physicsEngine(glm::vec3(0.0f)), _entities(true, this, this), - _entityCollisionSystem(), _entityClipboardRenderer(false, this, this), _entityClipboard(), _viewFrustum(), @@ -1689,17 +1688,16 @@ void Application::init() { _entities.init(); _entities.setViewFrustum(getViewFrustum()); - EntityTree* entityTree = _entities.getTree(); - - _entityCollisionSystem.init(&_entityEditSender, entityTree, &_avatarManager); - - entityTree->setSimulation(&_entityCollisionSystem); + EntityTree* tree = _entities.getTree(); + _physicsEngine.setEntityTree(tree); + tree->setSimulation(&_physicsEngine); + _physicsEngine.init(&_entityEditSender); - connect(&_entityCollisionSystem, &EntityCollisionSystem::entityCollisionWithEntity, + connect(&_physicsEngine, &EntitySimulation::emitEntityCollisionWithEntity, ScriptEngine::getEntityScriptingInterface(), &EntityScriptingInterface::entityCollisionWithEntity); // connect the _entityCollisionSystem to our EntityTreeRenderer since that's what handles running entity scripts - connect(&_entityCollisionSystem, &EntityCollisionSystem::entityCollisionWithEntity, + connect(&_physicsEngine, &EntitySimulation::emitEntityCollisionWithEntity, &_entities, &EntityTreeRenderer::entityCollisionWithEntity); // connect the _entities (EntityTreeRenderer) to our script engine's EntityScriptingInterface for firing @@ -1723,10 +1721,6 @@ void Application::init() { // save settings when avatar changes connect(_myAvatar, &MyAvatar::transformChanged, this, &Application::bumpSettings); - EntityTree* tree = _entities.getTree(); - _physicsEngine.setEntityTree(tree); - tree->setSimulation(&_physicsEngine); - _physicsEngine.init(&_entityEditSender); // make sure our texture cache knows about window size changes DependencyManager::get()->associateWithWidget(glCanvas.data()); @@ -2047,9 +2041,6 @@ void Application::update(float deltaTime) { // NOTE: the _entities.update() call below will wait for lock // and will simulate entity motion (the EntityTree has been given an EntitySimulation). _entities.update(); // update the models... - // The _entityCollisionSystem.updateCollisions() call below merely tries for lock, - // and on failure it skips collision detection. - _entityCollisionSystem.updateCollisions(); // collide the entities... } { diff --git a/interface/src/Application.h b/interface/src/Application.h index a875c6b9fe..c79cf8a989 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -466,7 +466,6 @@ private: PhysicsEngine _physicsEngine; EntityTreeRenderer _entities; - EntityCollisionSystem _entityCollisionSystem; EntityTreeRenderer _entityClipboardRenderer; EntityTree _entityClipboard; diff --git a/libraries/entities/src/EntityCollisionSystem.cpp b/libraries/entities/src/EntityCollisionSystem.cpp index 172850bc64..12d4e9e61e 100644 --- a/libraries/entities/src/EntityCollisionSystem.cpp +++ b/libraries/entities/src/EntityCollisionSystem.cpp @@ -62,14 +62,6 @@ void EntityCollisionSystem::checkEntity(EntityItem* entity) { updateCollisionWithAvatars(entity); } -void EntityCollisionSystem::emitGlobalEntityCollisionWithEntity(EntityItem* entityA, - EntityItem* entityB, const Collision& collision) { - - EntityItemID idA = entityA->getEntityItemID(); - EntityItemID idB = entityB->getEntityItemID(); - emit entityCollisionWithEntity(idA, idB, collision); -} - void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) { if (entityA->getIgnoreForCollisions()) { @@ -193,7 +185,10 @@ void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) { Collision collision; collision.penetration = penetration; collision.contactPoint = (0.5f * (float)TREE_SCALE) * (entityA->getPosition() + entityB->getPosition()); - emitGlobalEntityCollisionWithEntity(entityA, entityB, collision); + + EntityItemID idA = entityA->getEntityItemID(); + EntityItemID idB = entityB->getEntityItemID(); + emitEntityCollisionWithEntity(idA, idB, collision); } } } diff --git a/libraries/entities/src/EntityCollisionSystem.h b/libraries/entities/src/EntityCollisionSystem.h index ce7d57bef7..d6cafd88f3 100644 --- a/libraries/entities/src/EntityCollisionSystem.h +++ b/libraries/entities/src/EntityCollisionSystem.h @@ -31,8 +31,7 @@ class AvatarData; class EntityEditPacketSender; class EntityTree; -class EntityCollisionSystem : public QObject, public SimpleEntitySimulation { -Q_OBJECT +class EntityCollisionSystem : public SimpleEntitySimulation { public: EntityCollisionSystem(); @@ -45,19 +44,13 @@ public: void checkEntity(EntityItem* Entity); void updateCollisionWithEntities(EntityItem* Entity); void updateCollisionWithAvatars(EntityItem* Entity); - void queueEntityPropertiesUpdate(EntityItem* Entity); - -signals: - void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); private: void applyHardCollision(EntityItem* entity, const CollisionInfo& collisionInfo); static bool updateOperation(OctreeElement* element, void* extraData); - void emitGlobalEntityCollisionWithEntity(EntityItem* entityA, EntityItem* entityB, const Collision& penetration); EntityEditPacketSender* _packetSender; - AbstractAudioInterface* _audio; AvatarHashMap* _avatars; CollisionList _collisions; }; diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index dee6b1c43a..a7e18b67df 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -12,6 +12,7 @@ #ifndef hifi_EntitySimulation_h #define hifi_EntitySimulation_h +#include #include #include @@ -31,7 +32,8 @@ const int DIRTY_SIMULATION_FLAGS = EntityItem::DIRTY_LIFETIME | EntityItem::DIRTY_UPDATEABLE; -class EntitySimulation { +class EntitySimulation : public QObject { +Q_OBJECT public: EntitySimulation() : _mutex(QMutex::Recursive), _entityTree(NULL) { } virtual ~EntitySimulation() { setEntityTree(NULL); } @@ -61,6 +63,9 @@ public: EntityTree* getEntityTree() { return _entityTree; } +signals: + void emitEntityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); + protected: // These pure virtual methods are protected because they are not to be called will-nilly. The base class diff --git a/libraries/physics/src/ContactInfo.cpp b/libraries/physics/src/ContactInfo.cpp new file mode 100644 index 0000000000..71887b2dc9 --- /dev/null +++ b/libraries/physics/src/ContactInfo.cpp @@ -0,0 +1,29 @@ +// +// ContactEvent.cpp +// libraries/physcis/src +// +// Created by Andrew Meadows 2015.01.20 +// Copyright 2015 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 "BulletUtil.h" +#include "ContactInfo.h" + +void ContactInfo::update(uint32_t currentStep, btManifoldPoint& p, const glm::vec3& worldOffset) { + _lastStep = currentStep; + ++_numSteps; + contactPoint = bulletToGLM(p.m_positionWorldOnB) + worldOffset; + penetration = bulletToGLM(p.m_distance1 * p.m_normalWorldOnB); + // TODO: also report normal + //_normal = bulletToGLM(p.m_normalWorldOnB); +} + +ContactEventType ContactInfo::computeType(uint32_t thisStep) { + if (_lastStep != thisStep) { + return CONTACT_EVENT_TYPE_END; + } + return (_numSteps == 1) ? CONTACT_EVENT_TYPE_START : CONTACT_EVENT_TYPE_CONTINUE; +} diff --git a/libraries/physics/src/ContactInfo.h b/libraries/physics/src/ContactInfo.h new file mode 100644 index 0000000000..2c3c3a1e6f --- /dev/null +++ b/libraries/physics/src/ContactInfo.h @@ -0,0 +1,37 @@ +// +// ContactEvent.h +// libraries/physcis/src +// +// Created by Andrew Meadows 2015.01.20 +// Copyright 2015 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_ContactEvent_h +#define hifi_ContactEvent_h + +#include +#include + +#include "RegisteredMetaTypes.h" + +enum ContactEventType { + CONTACT_EVENT_TYPE_START, + CONTACT_EVENT_TYPE_CONTINUE, + CONTACT_EVENT_TYPE_END +}; + +class ContactInfo : public Collision +{ +public: + void update(uint32_t currentStep, btManifoldPoint& p, const glm::vec3& worldOffset); + ContactEventType computeType(uint32_t thisStep); +private: + uint32_t _lastStep = 0; + uint32_t _numSteps = 0; +}; + + +#endif // hifi_ContactEvent_h diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 9ff4a9d0e1..8b6fb1ea9f 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -33,6 +33,7 @@ void EntityMotionState::enqueueOutgoingEntity(EntityItem* entity) { EntityMotionState::EntityMotionState(EntityItem* entity) : _entity(entity) { + _type = MOTION_STATE_TYPE_ENTITY; assert(entity != NULL); } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index da06d46451..8eb639688a 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -60,6 +60,8 @@ public: uint32_t getIncomingDirtyFlags() const; void clearIncomingDirtyFlags(uint32_t flags) { _entity->clearDirtyFlags(flags); } + EntityItem* getEntity() const { return _entity; } + protected: EntityItem* _entity; }; diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 929ddab3e0..cab36b8370 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -171,14 +171,6 @@ void ObjectMotionState::removeKinematicController() { } } -void ObjectMotionState::handleContactEvent(ContactEventType type, ObjectMotionState* otherState) { - if (type == CONTACT_TYPE_START) { - std::cout << "adebug start " << (void*)(this) << " vs " << (void*)(otherState) << std::endl; // adebug - } else if (type == CONTACT_TYPE_END) { - std::cout << "adebug end " << (void*)(this) << " vs " << (void*)(otherState) << std::endl; // adebug - } -} - void ObjectMotionState::setRigidBody(btRigidBody* body) { // give the body a (void*) back-pointer to this ObjectMotionState if (_body != body) { diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 2eda618d93..223664ceec 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -26,6 +26,12 @@ enum MotionType { MOTION_TYPE_KINEMATIC // keyframed motion }; +enum MotionStateType { + MOTION_STATE_TYPE_UNKNOWN, + MOTION_STATE_TYPE_ENTITY, + MOTION_STATE_TYPE_AVATAR +}; + // 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 HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_MOTION_TYPE | EntityItem::DIRTY_SHAPE); @@ -59,6 +65,7 @@ public: virtual void updateObjectEasy(uint32_t flags, uint32_t frame) = 0; virtual void updateObjectVelocities() = 0; + MotionStateType getType() const { return _type; } virtual MotionType getMotionType() const { return _motionType; } virtual void computeShapeInfo(ShapeInfo& info) = 0; @@ -89,14 +96,14 @@ public: virtual void addKinematicController() = 0; virtual void removeKinematicController(); - virtual void handleContactEvent(ContactEventType type, ObjectMotionState* otherState); - btRigidBody* getRigidBody() const { return _body; } friend class PhysicsEngine; protected: void setRigidBody(btRigidBody* body); + MotionStateType _type = MOTION_STATE_TYPE_UNKNOWN; + // TODO: move these materials properties outside of ObjectMotionState float _friction; float _restitution; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 5a2881da71..ca14261c3b 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -256,8 +256,9 @@ void PhysicsEngine::computeCollisionEvents() { void* a = objectA->getUserPointer(); void* b = objectB->getUserPointer(); - if (a || b ) { - _contactMap[ContactKey(a, b)].update(_numSubsteps); + if (a || b) { + // the manifold has up to 4 distinct points, but only extract info from the first + _contactMap[ContactKey(a, b)].update(_numSubsteps, contactManifold->getContactPoint(0), _originOffset); } } } @@ -265,16 +266,28 @@ void PhysicsEngine::computeCollisionEvents() { // scan known contacts and trigger events ContactMap::iterator contactItr = _contactMap.begin(); while (contactItr != _contactMap.end()) { - ContactEventType type = contactItr->second.computeType(_numSubsteps); ObjectMotionState* A = static_cast(contactItr->first._a); ObjectMotionState* B = static_cast(contactItr->first._b); - if (A) { - A->handleContactEvent(type, B); + + // TODO: make triggering these events clean and efficient. The code at this context shouldn't + // have to figure out what kind of object (entity, avatar, etc) these are in order to properly + // emit a collision event. + if (A && A->getType() == MOTION_STATE_TYPE_ENTITY) { + EntityItemID idA = static_cast(A)->getEntity()->getEntityItemID(); + EntityItemID idB; + if (B && B->getType() == MOTION_STATE_TYPE_ENTITY) { + idB = static_cast(B)->getEntity()->getEntityItemID(); + } + emitEntityCollisionWithEntity(idA, idB, contactItr->second); + } else if (B && B->getType() == MOTION_STATE_TYPE_ENTITY) { + EntityItemID idA; + EntityItemID idB = static_cast(B)->getEntity()->getEntityItemID(); + emitEntityCollisionWithEntity(idA, idB, contactItr->second); } - if (B) { - B->handleContactEvent(type, A); - } - if (type == CONTACT_TYPE_END) { + + // TODO: enable scripts to filter based on contact event type + ContactEventType type = contactItr->second.computeType(_numSubsteps); + if (type == CONTACT_EVENT_TYPE_END) { ContactMap::iterator iterToDelete = contactItr; ++contactItr; _contactMap.erase(iterToDelete); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 9db9f5a33a..fdd4107421 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -38,11 +38,13 @@ public: ContactKey() = delete; ContactKey(void* a, void* b) : _a(a), _b(b) {} bool operator<(const ContactKey& other) const { return _a < other._a || (_a == other._a && _b < other._b); } + bool operator==(const ContactKey& other) const { return _a == other._a && _b == other._b; } void* _a; void* _b; }; typedef std::map ContactMap; +typedef std::pair ContactMapElement; class PhysicsEngine : public EntitySimulation { public: From 6840daa0b5dbd697bea72328ddff2896bfc5e9a8 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 21 Jan 2015 11:55:28 -0800 Subject: [PATCH 09/12] removing tabs from formatting --- libraries/physics/src/PhysicsEngine.cpp | 42 ++++++++++++------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index a8b168681e..dea321be22 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -159,14 +159,14 @@ void PhysicsEngine::relayIncomingChangesToSimulation() { void PhysicsEngine::removeContacts(ObjectMotionState* motionState) { // trigger events for new/existing/old contacts - ContactMap::iterator contactItr = _contactMap.begin(); - while (contactItr != _contactMap.end()) { + ContactMap::iterator contactItr = _contactMap.begin(); + while (contactItr != _contactMap.end()) { if (contactItr->first._a == motionState || contactItr->first._b == motionState) { - ContactMap::iterator iterToDelete = contactItr; - ++contactItr; - _contactMap.erase(iterToDelete); + ContactMap::iterator iterToDelete = contactItr; + ++contactItr; + _contactMap.erase(iterToDelete); } else { - ++contactItr; + ++contactItr; } } } @@ -251,26 +251,26 @@ void PhysicsEngine::stepSimulation() { void PhysicsEngine::computeCollisionEvents() { // update all contacts int numManifolds = _collisionDispatcher->getNumManifolds(); - for (int i = 0; i < numManifolds; ++i) { - btPersistentManifold* contactManifold = _collisionDispatcher->getManifoldByIndexInternal(i); + for (int i = 0; i < numManifolds; ++i) { + btPersistentManifold* contactManifold = _collisionDispatcher->getManifoldByIndexInternal(i); if (contactManifold->getNumContacts() > 0) { - const btCollisionObject* objectA = static_cast(contactManifold->getBody0()); - const btCollisionObject* objectB = static_cast(contactManifold->getBody1()); + const btCollisionObject* objectA = static_cast(contactManifold->getBody0()); + const btCollisionObject* objectB = static_cast(contactManifold->getBody1()); void* a = objectA->getUserPointer(); void* b = objectB->getUserPointer(); if (a || b) { // the manifold has up to 4 distinct points, but only extract info from the first - _contactMap[ContactKey(a, b)].update(_numSubsteps, contactManifold->getContactPoint(0), _originOffset); + _contactMap[ContactKey(a, b)].update(_numSubsteps, contactManifold->getContactPoint(0), _originOffset); } } } - + // scan known contacts and trigger events - ContactMap::iterator contactItr = _contactMap.begin(); - while (contactItr != _contactMap.end()) { - ObjectMotionState* A = static_cast(contactItr->first._a); - ObjectMotionState* B = static_cast(contactItr->first._b); + ContactMap::iterator contactItr = _contactMap.begin(); + while (contactItr != _contactMap.end()) { + ObjectMotionState* A = static_cast(contactItr->first._a); + ObjectMotionState* B = static_cast(contactItr->first._b); // TODO: make triggering these events clean and efficient. The code at this context shouldn't // have to figure out what kind of object (entity, avatar, etc) these are in order to properly @@ -289,13 +289,13 @@ void PhysicsEngine::computeCollisionEvents() { } // TODO: enable scripts to filter based on contact event type - ContactEventType type = contactItr->second.computeType(_numSubsteps); + ContactEventType type = contactItr->second.computeType(_numSubsteps); if (type == CONTACT_EVENT_TYPE_END) { - ContactMap::iterator iterToDelete = contactItr; - ++contactItr; - _contactMap.erase(iterToDelete); + ContactMap::iterator iterToDelete = contactItr; + ++contactItr; + _contactMap.erase(iterToDelete); } else { - ++contactItr; + ++contactItr; } } } From 2171427bbdff69e5861c55cdfa822f895b344746 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 21 Jan 2015 12:31:06 -0800 Subject: [PATCH 10/12] Update style.css to use pt instead of px for proper rendering on hidpi screens --- examples/html/style.css | 66 ++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/examples/html/style.css b/examples/html/style.css index ad78d0234c..08ca32aba5 100644 --- a/examples/html/style.css +++ b/examples/html/style.css @@ -8,7 +8,7 @@ body { background-color: rgb(76, 76, 76); color: rgb(204, 204, 204); font-family: Arial; - font-size: 11px; + font-size: 8.25pt; -webkit-touch-callout: none; -webkit-user-select: none; @@ -31,25 +31,25 @@ body { .color-box { display: inline-block; - width: 20px; - height: 20px; - border: 1px solid black; - margin: 2px; + width: 15pt; + height: 15pt; + border: 0.75pt solid black; + margin: 1.5pt; cursor: pointer; } .color-box.highlight { - width: 18px; - height: 18px; - border: 2px solid black; + width: 13.5pt; + height: 13.5pt; + border: 1.5pt solid black; } .section-header { background: #AAA; - border-bottom: 1px solid #CCC; + border-bottom: 0.75pt solid #CCC; background-color: #333333; color: #999; - padding: 4px; + padding: 3pt; } .section-header label { @@ -61,7 +61,7 @@ body { .property-section { display: block; margin: 10 10; - height: 30px; + height: 22.5pt; } .property-section label { @@ -73,7 +73,7 @@ body { } .grid-section { - border-top: 1px solid #DDD; + border-top: 0.75pt solid #DDD; background-color: #efefef; } @@ -81,8 +81,8 @@ input[type=button] { cursor: pointer; background-color: #608e96; border-color: #608e96; - border-radius: 5px; - padding: 5px 10px; + border-radius: 3.75pt; + padding: 3.75pt 7.5pt; border: 0; color: #fff; font-weight: bold; @@ -90,8 +90,8 @@ input[type=button] { textarea, input { margin: 0; - padding: 2px; - border: 1px solid #999; + padding: 1.5pt; + border: 0.75pt solid #999; background-color: #eee; } @@ -112,13 +112,13 @@ input.coord { table#entity-table { border-collapse: collapse; font-family: Sans-Serif; - font-size: 10px; + font-size: 7.5pt; width: 100%; } #entity-table tr { cursor: pointer; - border-bottom: 1px solid rgb(63, 63, 63) + border-bottom: 0.75pt solid rgb(63, 63, 63) } #entity-table tr.selected { @@ -128,15 +128,15 @@ table#entity-table { #entity-table th { background-color: #333; color: #fff; - border: 0px black solid; + border: 0pt black solid; text-align: left; word-wrap: nowrap; white-space: nowrap; } #entity-table td { - font-size: 11px; - border: 0px black solid; + font-size: 8.25pt; + border: 0pt black solid; word-wrap: nowrap; white-space: nowrap; text-overflow: ellipsis; @@ -148,21 +148,21 @@ table#entity-table { } th#entity-type { - width: 60px; + width: 33.75pt; } div.input-area { display: inline-block; - font-size: 10px; + font-size: 7.5pt; } input { } #type { - font-size: 14px; + font-size: 10.5pt; } #type label { @@ -173,22 +173,22 @@ input { background-color: rgb(102, 102, 102); color: rgb(204, 204, 204); border: none; - font-size: 10px; + font-size: 7.5pt; } #properties-list input[type=button] { cursor: pointer; background-color: rgb(51, 102, 102); border-color: #608e96; - border-radius: 5px; - padding: 5px 10px; + border-radius: 3.75pt; + padding: 3.75pt 7.5pt; border: 0; color: rgb(204, 204, 204); } #properties-list .property { - padding: 8px 8px; - border-top: 1px solid rgb(63, 63, 63); + padding: 6pt 6pt; + border-top: 0.75pt solid rgb(63, 63, 63); min-height: 1em; } @@ -203,11 +203,11 @@ table#properties-list { } #properties-list > div { - margin: 4px 0; + margin: 3pt 0; } #properties-list { - border-bottom: 1px solid #e5e5e5; + border-bottom: 0.75pt solid #e5e5e5; } #properties-list .label { @@ -221,11 +221,11 @@ table#properties-list { } #properties-list .value > div{ - padding: 4px 0; + padding: 3pt 0; } col#col-label { - width: 130px; + width: 97.5pt; } div.outer { From 1c38b08e8f25d5452e623ea20a07a40648f8f49d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 21 Jan 2015 14:07:23 -0800 Subject: [PATCH 11/12] remane emitEntityCollision... to entityCollision... --- interface/src/Application.cpp | 4 ++-- libraries/entities/src/EntityCollisionSystem.cpp | 2 +- libraries/entities/src/EntitySimulation.h | 2 +- libraries/physics/src/PhysicsEngine.cpp | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 78fd0f943e..86af8b0e91 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1693,11 +1693,11 @@ void Application::init() { tree->setSimulation(&_physicsEngine); _physicsEngine.init(&_entityEditSender); - connect(&_physicsEngine, &EntitySimulation::emitEntityCollisionWithEntity, + connect(&_physicsEngine, &EntitySimulation::entityCollisionWithEntity, ScriptEngine::getEntityScriptingInterface(), &EntityScriptingInterface::entityCollisionWithEntity); // connect the _entityCollisionSystem to our EntityTreeRenderer since that's what handles running entity scripts - connect(&_physicsEngine, &EntitySimulation::emitEntityCollisionWithEntity, + connect(&_physicsEngine, &EntitySimulation::entityCollisionWithEntity, &_entities, &EntityTreeRenderer::entityCollisionWithEntity); // connect the _entities (EntityTreeRenderer) to our script engine's EntityScriptingInterface for firing diff --git a/libraries/entities/src/EntityCollisionSystem.cpp b/libraries/entities/src/EntityCollisionSystem.cpp index 12d4e9e61e..6d27e7d0cc 100644 --- a/libraries/entities/src/EntityCollisionSystem.cpp +++ b/libraries/entities/src/EntityCollisionSystem.cpp @@ -188,7 +188,7 @@ void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) { EntityItemID idA = entityA->getEntityItemID(); EntityItemID idB = entityB->getEntityItemID(); - emitEntityCollisionWithEntity(idA, idB, collision); + emit entityCollisionWithEntity(idA, idB, collision); } } } diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index a7e18b67df..e7f2219c19 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -64,7 +64,7 @@ public: EntityTree* getEntityTree() { return _entityTree; } signals: - void emitEntityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); + void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); protected: diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index dea321be22..02304b3b8d 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -281,11 +281,11 @@ void PhysicsEngine::computeCollisionEvents() { if (B && B->getType() == MOTION_STATE_TYPE_ENTITY) { idB = static_cast(B)->getEntity()->getEntityItemID(); } - emitEntityCollisionWithEntity(idA, idB, contactItr->second); + emit entityCollisionWithEntity(idA, idB, contactItr->second); } else if (B && B->getType() == MOTION_STATE_TYPE_ENTITY) { EntityItemID idA; EntityItemID idB = static_cast(B)->getEntity()->getEntityItemID(); - emitEntityCollisionWithEntity(idA, idB, contactItr->second); + emit entityCollisionWithEntity(idA, idB, contactItr->second); } // TODO: enable scripts to filter based on contact event type From 1b7074e52a0278e8a3a06b8165f8fe91e5712636 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 21 Jan 2015 14:16:34 -0800 Subject: [PATCH 12/12] purge EntityCollisionSystem --- interface/src/Application.h | 1 - .../entities/src/EntityCollisionSystem.cpp | 297 ------------------ .../entities/src/EntityCollisionSystem.h | 58 ---- 3 files changed, 356 deletions(-) delete mode 100644 libraries/entities/src/EntityCollisionSystem.cpp delete mode 100644 libraries/entities/src/EntityCollisionSystem.h diff --git a/interface/src/Application.h b/interface/src/Application.h index c79cf8a989..3b793978a8 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -25,7 +25,6 @@ #include #include -#include #include #include #include diff --git a/libraries/entities/src/EntityCollisionSystem.cpp b/libraries/entities/src/EntityCollisionSystem.cpp deleted file mode 100644 index 6d27e7d0cc..0000000000 --- a/libraries/entities/src/EntityCollisionSystem.cpp +++ /dev/null @@ -1,297 +0,0 @@ -// -// EntityCollisionSystem.cpp -// libraries/entities/src -// -// Created by Brad Hefta-Gaub on 9/23/14. -// Copyright 2013-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 -#include -#include -#include -#include - -#include "EntityCollisionSystem.h" -#include "EntityEditPacketSender.h" -#include "EntityItem.h" -#include "EntityTreeElement.h" -#include "EntityTree.h" - -const int MAX_COLLISIONS_PER_Entity = 16; - -EntityCollisionSystem::EntityCollisionSystem() - : SimpleEntitySimulation(), - _packetSender(NULL), - _avatars(NULL), - _collisions(MAX_COLLISIONS_PER_Entity) { -} - -void EntityCollisionSystem::init(EntityEditPacketSender* packetSender, - EntityTree* entities, AvatarHashMap* avatars) { - assert(entities); - setEntityTree(entities); - _packetSender = packetSender; - _avatars = avatars; -} - -EntityCollisionSystem::~EntityCollisionSystem() { -} - -void EntityCollisionSystem::updateCollisions() { - PerformanceTimer perfTimer("collisions"); - assert(_entityTree); - // update all Entities - if (_entityTree->tryLockForWrite()) { - foreach (EntityItem* entity, _movingEntities) { - checkEntity(entity); - } - _entityTree->unlock(); - } -} - - -void EntityCollisionSystem::checkEntity(EntityItem* entity) { - updateCollisionWithEntities(entity); - updateCollisionWithAvatars(entity); -} - -void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) { - - if (entityA->getIgnoreForCollisions()) { - return; // bail early if this entity is to be ignored... - } - - // don't collide entities with unknown IDs, - if (!entityA->isKnownID()) { - return; - } - - glm::vec3 penetration; - EntityItem* entityB = NULL; - - const int MAX_COLLISIONS_PER_ENTITY = 32; - CollisionList collisions(MAX_COLLISIONS_PER_ENTITY); - bool shapeCollisionsAccurate = false; - - bool shapeCollisions = _entityTree->findShapeCollisions(&entityA->getCollisionShapeInMeters(), - collisions, Octree::NoLock, &shapeCollisionsAccurate); - - if (shapeCollisions) { - for(int i = 0; i < collisions.size(); i++) { - - CollisionInfo* collision = collisions[i]; - penetration = collision->_penetration; - entityB = static_cast(collision->_extraData); - - // The collision _extraData should be a valid entity, but if for some reason - // it's NULL then continue with a warning. - if (!entityB) { - qDebug() << "UNEXPECTED - we have a collision with missing _extraData. Something went wrong down below!"; - continue; // skip this loop pass if the entity is NULL - } - - // don't collide entities with unknown IDs, - if (!entityB->isKnownID()) { - continue; // skip this loop pass if the entity has an unknown ID - } - - // NOTE: 'penetration' is the depth that 'entityA' overlaps 'entityB'. It points from A into B. - glm::vec3 penetrationInTreeUnits = penetration / (float)(TREE_SCALE); - - // Even if the Entities overlap... when the Entities are already moving appart - // we don't want to count this as a collision. - glm::vec3 relativeVelocity = entityA->getVelocity() - entityB->getVelocity(); - - bool fullyEnclosedCollision = glm::length(penetrationInTreeUnits) > entityA->getLargestDimension(); - - bool wantToMoveA = entityA->getCollisionsWillMove(); - bool wantToMoveB = entityB->getCollisionsWillMove(); - bool movingTowardEachOther = glm::dot(relativeVelocity, penetrationInTreeUnits) > 0.0f; - - // only do collisions if the entities are moving toward each other and one or the other - // of the entities are movable from collisions - bool doCollisions = !fullyEnclosedCollision && movingTowardEachOther && (wantToMoveA || wantToMoveB); - - if (doCollisions) { - - quint64 now = usecTimestampNow(); - - glm::vec3 axis = glm::normalize(penetration); - glm::vec3 axialVelocity = glm::dot(relativeVelocity, axis) * axis; - - float massA = entityA->computeMass(); - float massB = entityB->computeMass(); - float totalMass = massA + massB; - float massRatioA = (2.0f * massB / totalMass); - float massRatioB = (2.0f * massA / totalMass); - - // in the event that one of our entities is non-moving, then fix up these ratios - if (wantToMoveA && !wantToMoveB) { - massRatioA = 2.0f; - massRatioB = 0.0f; - } - - if (!wantToMoveA && wantToMoveB) { - massRatioA = 0.0f; - massRatioB = 2.0f; - } - - // unless the entity is configured to not be moved by collision, calculate it's new position - // and velocity and apply it - if (wantToMoveA) { - // handle Entity A - glm::vec3 newVelocityA = entityA->getVelocity() - axialVelocity * massRatioA; - glm::vec3 newPositionA = entityA->getPosition() - 0.5f * penetrationInTreeUnits; - - EntityItemProperties propertiesA = entityA->getProperties(); - EntityItemID idA(entityA->getID()); - propertiesA.setVelocity(newVelocityA * (float)TREE_SCALE); - propertiesA.setPosition(newPositionA * (float)TREE_SCALE); - propertiesA.setLastEdited(now); - - // NOTE: EntityTree::updateEntity() will cause the entity to get sorted correctly in the EntitySimulation, - // thereby waking up static non-moving entities. - _entityTree->updateEntity(entityA, propertiesA); - _packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, idA, propertiesA); - } - - // unless the entity is configured to not be moved by collision, calculate it's new position - // and velocity and apply it - if (wantToMoveB) { - glm::vec3 newVelocityB = entityB->getVelocity() + axialVelocity * massRatioB; - glm::vec3 newPositionB = entityB->getPosition() + 0.5f * penetrationInTreeUnits; - - EntityItemProperties propertiesB = entityB->getProperties(); - - EntityItemID idB(entityB->getID()); - propertiesB.setVelocity(newVelocityB * (float)TREE_SCALE); - propertiesB.setPosition(newPositionB * (float)TREE_SCALE); - propertiesB.setLastEdited(now); - - // NOTE: EntityTree::updateEntity() will cause the entity to get sorted correctly in the EntitySimulation, - // thereby waking up static non-moving entities. - _entityTree->updateEntity(entityB, propertiesB); - _packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, idB, propertiesB); - } - - // NOTE: Do this after updating the entities so that the callback can delete the entities if they want to - Collision collision; - collision.penetration = penetration; - collision.contactPoint = (0.5f * (float)TREE_SCALE) * (entityA->getPosition() + entityB->getPosition()); - - EntityItemID idA = entityA->getEntityItemID(); - EntityItemID idB = entityB->getEntityItemID(); - emit entityCollisionWithEntity(idA, idB, collision); - } - } - } -} - -void EntityCollisionSystem::updateCollisionWithAvatars(EntityItem* entity) { - - // Entities that are in hand, don't collide with avatars - if (!_avatars) { - return; - } - - if (entity->getIgnoreForCollisions() || !entity->getCollisionsWillMove()) { - return; // bail early if this entity is to be ignored or wont move - } - - glm::vec3 center = entity->getPosition() * (float)(TREE_SCALE); - float radius = entity->getRadius() * (float)(TREE_SCALE); - const float ELASTICITY = 0.9f; - const float DAMPING = 0.1f; - glm::vec3 penetration; - - _collisions.clear(); - foreach (const AvatarSharedPointer& avatarPointer, _avatars->getAvatarHash()) { - AvatarData* avatar = avatarPointer.data(); - - float totalRadius = avatar->getBoundingRadius() + radius; - glm::vec3 relativePosition = center - avatar->getPosition(); - if (glm::dot(relativePosition, relativePosition) > (totalRadius * totalRadius)) { - continue; - } - - if (avatar->findSphereCollisions(center, radius, _collisions)) { - int numCollisions = _collisions.size(); - for (int i = 0; i < numCollisions; ++i) { - CollisionInfo* collision = _collisions.getCollision(i); - collision->_damping = DAMPING; - collision->_elasticity = ELASTICITY; - - collision->_addedVelocity /= (float)(TREE_SCALE); - glm::vec3 relativeVelocity = collision->_addedVelocity - entity->getVelocity(); - - if (glm::dot(relativeVelocity, collision->_penetration) <= 0.0f) { - // only collide when Entity and collision point are moving toward each other - // (doing this prevents some "collision snagging" when Entity penetrates the object) - collision->_penetration /= (float)(TREE_SCALE); - applyHardCollision(entity, *collision); - } - } - } - } -} - -void EntityCollisionSystem::applyHardCollision(EntityItem* entity, const CollisionInfo& collisionInfo) { - - // don't collide entities with unknown IDs, - if (!entity->isKnownID()) { - return; - } - - // HALTING_* params are determined using expected acceleration of gravity over some timescale. - // This is a HACK for entities that bounce in a 1.0 gravitational field and should eventually be made more universal. - const float HALTING_ENTITY_PERIOD = 0.0167f; // ~1/60th of a second - const float HALTING_ENTITY_SPEED = 9.8 * HALTING_ENTITY_PERIOD / (float)(TREE_SCALE); - - // - // Update the entity in response to a hard collision. Position will be reset exactly - // to outside the colliding surface. Velocity will be modified according to elasticity. - // - // if elasticity = 0.0, collision is inelastic (vel normal to collision is lost) - // if elasticity = 1.0, collision is 100% elastic. - // - glm::vec3 position = entity->getPosition(); - glm::vec3 velocity = entity->getVelocity(); - - const float EPSILON = 0.0f; - glm::vec3 relativeVelocity = collisionInfo._addedVelocity - velocity; - float velocityDotPenetration = glm::dot(relativeVelocity, collisionInfo._penetration); - if (velocityDotPenetration < EPSILON) { - // entity is moving into collision surface - // - // TODO: do something smarter here by comparing the mass of the entity vs that of the other thing - // (other's mass could be stored in the Collision Info). The smaller mass should surrender more - // position offset and should slave more to the other's velocity in the static-friction case. - position -= collisionInfo._penetration; - - if (glm::length(relativeVelocity) < HALTING_ENTITY_SPEED) { - // static friction kicks in and entities moves with colliding object - velocity = collisionInfo._addedVelocity; - } else { - glm::vec3 direction = glm::normalize(collisionInfo._penetration); - velocity += glm::dot(relativeVelocity, direction) * (1.0f + collisionInfo._elasticity) * direction; // dynamic reflection - velocity += glm::clamp(collisionInfo._damping, 0.0f, 1.0f) * (relativeVelocity - glm::dot(relativeVelocity, direction) * direction); // dynamic friction - } - } - - EntityItemProperties properties = entity->getProperties(); - EntityItemID entityItemID(entity->getID()); - - properties.setPosition(position * (float)TREE_SCALE); - properties.setVelocity(velocity * (float)TREE_SCALE); - properties.setLastEdited(usecTimestampNow()); - - _entityTree->updateEntity(entity, properties); - _packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, entityItemID, properties); -} diff --git a/libraries/entities/src/EntityCollisionSystem.h b/libraries/entities/src/EntityCollisionSystem.h deleted file mode 100644 index d6cafd88f3..0000000000 --- a/libraries/entities/src/EntityCollisionSystem.h +++ /dev/null @@ -1,58 +0,0 @@ -// -// EntityCollisionSystem.h -// libraries/entities/src -// -// Created by Brad Hefta-Gaub on 9/23/14. -// Copyright 2013-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_EntityCollisionSystem_h -#define hifi_EntityCollisionSystem_h - -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include "EntityItem.h" -#include "SimpleEntitySimulation.h" - -class AbstractAudioInterface; -class AvatarData; -class EntityEditPacketSender; -class EntityTree; - -class EntityCollisionSystem : public SimpleEntitySimulation { -public: - EntityCollisionSystem(); - - void init(EntityEditPacketSender* packetSender, EntityTree* entities, AvatarHashMap* _avatars = NULL); - - ~EntityCollisionSystem(); - - void updateCollisions(); - - void checkEntity(EntityItem* Entity); - void updateCollisionWithEntities(EntityItem* Entity); - void updateCollisionWithAvatars(EntityItem* Entity); - -private: - void applyHardCollision(EntityItem* entity, const CollisionInfo& collisionInfo); - - static bool updateOperation(OctreeElement* element, void* extraData); - - EntityEditPacketSender* _packetSender; - AvatarHashMap* _avatars; - CollisionList _collisions; -}; - -#endif // hifi_EntityCollisionSystem_h