From 304850372e174f438acb73e71c8d0a4b50ee779e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 28 Apr 2015 10:05:10 -0700 Subject: [PATCH 01/89] initial implementation of PhysicalEntitySimulation --- .../physics/src/PhysicalEntitySimulation.cpp | 333 ++++++++++++++++++ .../physics/src/PhysicalEntitySimulation.h | 66 ++++ 2 files changed, 399 insertions(+) create mode 100644 libraries/physics/src/PhysicalEntitySimulation.cpp create mode 100644 libraries/physics/src/PhysicalEntitySimulation.h diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp new file mode 100644 index 0000000000..382e405203 --- /dev/null +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -0,0 +1,333 @@ +// +// PhysicalEntitySimulation.cpp +// libraries/physcis/src +// +// Created by Andrew Meadows 2015.04.27 +// 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 + +#include "PhysicalEntitySimulation.h" +#include "ShapeInfoUtil.h" +#include "PhysicsHelpers.h" +#include "ThreadSafeDynamicsWorld.h" +#include "PhysicsLogging.h" + +PhysicalEntitySimulation::PhysicalEntitySimulation() : +} + +PhysicalEntitySimulation::~PhysicalEntitySimulation() { +} + +void PhysicalEntitySimulation::init( + EntityTree* tree, + PhysicsEngine* physicsEngine, + ShapeManager* shapeManager, + EntityEditPacketSender* packetSender) { + assert(tree); + setEntityTree(tree); + + assert(*physicsEngine); + _physicsEngine = physicsEngine; + + assert(*shapeManager); + _shapeManager = shapeManager; + + assert(packetSender); + _entityPacketSender = packetSender; +} + +// begin EntitySimulation overrides +void PhysicalEntitySimulation::updateEntitiesInternal(const quint64& now) { + // TODO: add back non-physical kinematic objects and step them forward here +} + +/* { + uint32_t numSubsteps = _physicsEngine->getNumSubsteps(); + if (_lastNumSubstepsAtUpdateInternal != numSubsteps) { + _lastNumSubstepsAtUpdateInternal = numSubsteps; + + SetOfMotionStates::iterator stateItr = _outgoingPackets.begin(); + while (stateItr != _outgoingPackets.end()) { + ObjectMotionState* state = *stateItr; + if (state->doesNotNeedToSendUpdate()) { + stateItr = _outgoingPackets.erase(stateItr); + } else if (state->shouldSendUpdate(numSubsteps)) { + state->sendUpdate(_entityPacketSender, numSubsteps); + ++stateItr; + } else { + ++stateItr; + } + } + } +} */ + +void PhysicalEntitySimulation::addEntityInternal(EntityItem* entity) { + assert(entity); + void* physicsInfo = entity->getPhysicsInfo(); + if (!physicsInfo) { + _pendingAdds.insert(entity); + } +} + +void PhysicalEntitySimulation::get { + if (entity->isReadyToComputeShape()) { + ShapeInfo shapeInfo; + entity->computeShapeInfo(shapeInfo); + btCollisionShape* shape = _physicsEngine->getShape(shapeInfo); + if (shape) { + EntityMotionState* motionState = new EntityMotionState(entity); + entity->setPhysicsInfo(static_cast(motionState)); + _physicalEntities.insert(motionState); + _physicsEngine->addObject(shapeInfo, shape, motionState); + motionState->setPhysical(true); + } + } + } +} + +void PhysicalEntitySimulation::removeEntityInternal(EntityItem* entity) { + assert(entity); + void* physicsInfo = entity->getPhysicsInfo(); + if (physicsInfo) { + ObjectMotionState* motionState = static_cast(physicsInfo); + _pendingRemoves.insert(motionState); + } +} + +void PhysicalEntitySimulation::entityChangedInternal(EntityItem* entity) { + // queue incoming changes: from external sources (script, EntityServer, etc) to physics engine + assert(entity); + void* physicsInfo = entity->getPhysicsInfo(); + if (physicsInfo) { + ObjectMotionState* motionState = static_cast(physicsInfo); + _pendingUpdates.insert(motionState); + } else { + if (!entity->ignoreForCollisions()) { + // The intent is for this object to be in the PhysicsEngine. + // Perhaps it's shape has changed and it can now be added? + _pendingAdds.insert(entity); + } + } +} + +void PhysicalEntitySimulation::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; + } +} + +void PhysicalEntitySimulation::clearEntitiesInternal() { + SetOfMotionStates::const_iterator stateItr = _physicalEntities.begin(); + for (stateItr = _physicalEntities.begin(); stateItr != _physicalEntities.end(); ++stateItr) { + removeObjectFromBullet(*stateItr); + delete (*stateItr); + } + _physicalEntities.clear(); + _pendingRemoves.clear(); + _pendingAdds.clear(); + _pendingUpdates.clear(); +} +// end EntitySimulation overrides + + +SetOfMotionState& PhysicalEntitySimulation::getObjectsToRemove() { + _tempSet.clear(); + for (auto entityItr : _pendingRemoves) { + EntityItem* entity = *entityItr; + _pendingAdds.remove(entity); + _pendingUpdates.remove(entity); + ObjectMotionState* motionState = static_cast(entity->getPhysicsInfo()); + if (motionState) { + _tempSet.push_back(motionState); + } + } + // DO NOT clear _pendingRemoves -- we still need to remove from _physicalEntities + // and then communicate to the EntityTree that they can really can be deleted. + // TODO: build the pipeline for this. + //_pendingRemoves.clear(); + return _tempSet; +} + +SetOfMotionState& PhysicalEntitySimulation::getObjectsToAdd() { + _tempSet.clear(); + SetOfEntities::iterator entityItr = _pendingAdds.begin(); + while (entityItr != _pendingAdds.end()) { + EntityItem* entity = *entityItr; + assert(!entity->getPhysicsInfo()); + + if (entity->isReadyToComputeShape()) { + ShapeInfo shapeInfo; + entity->computeShapeInfo(shapeInfo); + btCollisionShape* shape = _shapeManager->getShape(shapeInfo); + if (shape) { + shapeInfo.setShape(shape); + EntityMotionState* motionState = new EntityMotionState(entity); + entity->setPhysicsInfo(static_cast(motionState)); + _physicalEntities.insert(motionState); + entityItr = _pendingAdds.erase(entityItr); + // TODO: figure out how to get shapeInfo (or relevant info) to PhysicsEngine during add + //_physicsEngine->addObject(shapeInfo, motionState); + } else { + ++entityItr; + } + } + _tempSet.push_back(motionState); + } + return _tempSet; +} + +SetOfMotionState& PhysicalEntitySimulation::getObjectsToUpdate() { + _tempSet.clear(); + for (auto entityItr : _pendingUpdates) { + EntityItem* entity = *entityItr; + ObjectMotionState* motionState = static_cast(entity->getPhysicsInfo()); + if (motionState) { + _tempSet.push_back(motionState); + } + } + _pendingUpdates.clear(); + return _tempSet; +} + +void PhysicalEntitySimulation::clearIncomingChanges() { + // TODO: finalize deletes in the EntityTree? + // or should we allow EntityMotionState::_entity to be NULL during normal operation? + // (In order to do this _pendingDeletes would have to be list of MotionStates, or something) +} + +void PhysicalEntitySimulation::bump(EntityItem* bumpEntity) { +} + +/* useful CRUFT +void PhysicalEntitySimulation::relayIncomingChangesToSimulation() { + BT_PROFILE("incomingChanges"); + // process incoming changes + SetOfMotionStates::iterator stateItr = _incomingChanges.begin(); + while (stateItr != _incomingChanges.end()) { + ObjectMotionState* motionState = *stateItr; + ++stateItr; + uint32_t flags = motionState->getIncomingDirtyFlags() & DIRTY_PHYSICS_FLAGS; + + bool removeMotionState = false; + 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 + // but it also handles all EASY changes + bool success = updateObjectHard(body, motionState, flags); + if (!success) { + // NOTE: since updateObjectHard() failed we know that motionState has been removed + // from simulation and body has been deleted. Depending on what else has changed + // we might need to remove motionState altogether... + if (flags & EntityItem::DIRTY_VELOCITY) { + motionState->updateKinematicState(_numSubsteps); + if (motionState->isKinematic()) { + // all is NOT lost, we still need to move this object around kinematically + _nonPhysicalKinematicEntities.insert(motionState); + } else { + // no need to keep motionState around + removeMotionState = true; + } + } else { + // no need to keep motionState around + removeMotionState = true; + } + } + } 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, _numSubsteps); + } + if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) { + motionState->resetMeasuredBodyAcceleration(); + } + } else { + // the only way we should ever get here (motionState exists but no body) is when the object + // is undergoing non-physical kinematic motion. + assert(_nonPhysicalKinematicEntities.contains(motionState)); + + // it is possible that the changes are such that the object can now be added to the physical simulation + if (flags & EntityItem::DIRTY_SHAPE) { + ShapeInfo shapeInfo; + motionState->computeObjectShapeInfo(shapeInfo); + btCollisionShape* shape = _shapeManager.getShape(shapeInfo); + if (shape) { + addObject(shapeInfo, shape, motionState); + _nonPhysicalKinematicEntities.remove(motionState); + } else if (flags & EntityItem::DIRTY_VELOCITY) { + // although we couldn't add the object to the simulation, might need to update kinematic motion... + motionState->updateKinematicState(_numSubsteps); + if (!motionState->isKinematic()) { + _nonPhysicalKinematicEntities.remove(motionState); + removeMotionState = true; + } + } + } else if (flags & EntityItem::DIRTY_VELOCITY) { + // although we still can't add to physics simulation, might need to update kinematic motion... + motionState->updateKinematicState(_numSubsteps); + if (!motionState->isKinematic()) { + _nonPhysicalKinematicEntities.remove(motionState); + removeMotionState = true; + } + } + } + if (removeMotionState) { + // if we get here then there is no need to keep this motionState around (no physics or kinematics) + _outgoingPackets.remove(motionState); + if (motionState->getType() == MOTION_STATE_TYPE_ENTITY) { + _physicalEntities.remove(static_cast(motionState)); + } + // NOTE: motionState will clean up its own backpointers in the Object + delete motionState; + continue; + } + + // NOTE: the grand order of operations is: + // (1) relay incoming changes + // (2) step simulation + // (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 + } + _incomingChanges.clear(); +} + +{ + // TODO: re-enable non-physical-kinematics + // step non-physical kinematic objects + SetOfMotionStates::iterator stateItr = _nonPhysicalKinematicEntities.begin(); + // TODO?: need to occasionally scan for stopped non-physical kinematics objects + while (stateItr != _nonPhysicalKinematicEntities.end()) { + ObjectMotionState* motionState = *stateItr; + motionState->stepKinematicSimulation(now); + ++stateItr; + } +} + +void PhysicalEntitySimulation::stepNonPhysicalKinematics(const quint64& now) { + SetOfMotionStates::iterator stateItr = _nonPhysicalKinematicEntities.begin(); + // TODO?: need to occasionally scan for stopped non-physical kinematics objects + while (stateItr != _nonPhysicalKinematicEntities.end()) { + ObjectMotionState* motionState = *stateItr; + motionState->stepKinematicSimulation(now); + ++stateItr; + } +} +*/ diff --git a/libraries/physics/src/PhysicalEntitySimulation.h b/libraries/physics/src/PhysicalEntitySimulation.h new file mode 100644 index 0000000000..3929e152cd --- /dev/null +++ b/libraries/physics/src/PhysicalEntitySimulation.h @@ -0,0 +1,66 @@ +// +// PhysicalEntitySimulation.h +// libraries/physcis/src +// +// Created by Andrew Meadows 2015.04.27 +// 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_PhysicalEntitySimulation_h +#define hifi_PhysicalEntitySimulation_h + +#include + +#include +#include +#include + +#include +#include + +#include "PhysicsEngine.h" + +typedef QSet SetOfEntities; + +class PhysicalEntitySimulation :public EntitySimulation { +public: + PhysicalEntitySimulation(); + ~PhysicalEntitySimulation(); + + void init(EntityTree* tree, PhysicsEngine* engine, EntityEditPacketSender* packetSender); + + // overrides for EntitySimulation + void updateEntitiesInternal(const quint64& now); + void addEntityInternal(EntityItem* entity); + void removeEntityInternal(EntityItem* entity); + void entityChangedInternal(EntityItem* entity); + void sortEntitiesThatMovedInternal(); + void clearEntitiesInternal(); + + SetOfMotionState& getObjectsToRemove(); + SetOfMotionState& getObjectsToAdd(); + SetOfMotionState& getObjectsToUpdate(); + + void clearIncomingChanges(); + +private: + void bump(EntityItem* bumpEntity); + + SetOfEntities _pendingRemoves; // entities to be removed from simulation + SetOfEntities _pendingAdds; // entities to be be added to simulation + SetOfEntities _pendingUpdates; // entities to be updated in simulation + + SetOfMotionStates _physicalEntities; // MotionStates of entities in PhysicsEngine + VectorOfMotionStates _tempSet; // temporary list valid immediately after call to getObjectsToRemove/Add/Update() + + ShapeManager* _shapeManager = nullptr; + PhysicsEngine* _physicsEngine = nullptr; + EntityEditPacketSender* _entityPacketSender = nullptr; + + uint32_t _lastNumSubstepsAtUpdateInternal = 0; +}; + +#endif // hifi_PhysicalEntitySimulation_h From 34974272af9392fc916e0054ccd8b558b0272d33 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 28 Apr 2015 10:06:05 -0700 Subject: [PATCH 02/89] proposal for PhysicsEngine API in Application --- interface/src/Application.cpp | 17 +++++++++++++---- interface/src/Application.h | 4 ++++ libraries/physics/src/PhysicsEngine.cpp | 4 +++- libraries/physics/src/PhysicsEngine.h | 12 ++++++------ 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 485f616a6c..ad80ea2193 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2032,11 +2032,11 @@ void Application::init() { _entities.init(); _entities.setViewFrustum(getViewFrustum()); - EntityTree* tree = _entities.getTree(); - _physicsEngine.setEntityTree(tree); - tree->setSimulation(&_physicsEngine); - _physicsEngine.init(&_entityEditSender); + _physicsEngine.init(); + EntityTree* tree = _entities.getTree(); + _entitySimulation.init(tree, &_physicsEngine, &_shapeManager, &_entityEditSender); + tree->setSimulation(&_entitySimulation); auto entityScriptingInterface = DependencyManager::get(); @@ -2325,7 +2325,16 @@ void Application::update(float deltaTime) { { PerformanceTimer perfTimer("physics"); _myAvatar->relayDriveKeysToCharacterController(); + + _physicsEngine.removeObjects(_entitySimulation.getObjectsToRemove()); + _physicsEngine.addObjects(_entitySimulation.getObjectsToAdd()); + _physicsEngine.updateObjects(_entitySimulation.getObjectsToUpdate()); + _entitySimulation.clearIncomingChanges(); + _physicsEngine.stepSimulation(); + + _entitySimulation.handleOutgoingChanges(_physicsEngine.getOutgoingChanges()); + _physicsEngine.clearOutgoingChanges(); _physicsEngine.dumpStatsIfNecessary(); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 89de18dde5..8cbd67950d 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -32,8 +32,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -498,6 +500,8 @@ private: bool _justStarted; Stars _stars; + ShapeManager _shapeManager; + PhysicalEntitySimulation _entitySimulation; PhysicsEngine _physicsEngine; EntityTreeRenderer _entities; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 5422917aa7..ccd2706fcd 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -268,7 +268,7 @@ void PhysicsEngine::removeContacts(ObjectMotionState* motionState) { } // virtual -void PhysicsEngine::init(EntityEditPacketSender* packetSender) { +void PhysicsEngine::init() { // _entityTree should be set prior to the init() call assert(_entityTree); @@ -287,9 +287,11 @@ void PhysicsEngine::init(EntityEditPacketSender* packetSender) { _dynamicsWorld->setGravity(btVector3(0.0f, 0.0f, 0.0f)); } + /* TODO: move this to PhysicalEntitySimulation assert(packetSender); _entityPacketSender = packetSender; EntityMotionState::setOutgoingEntityList(&_entitiesToBeSorted); + */ } void PhysicsEngine::stepSimulation() { diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index af140f0f24..ff3c515f08 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -25,13 +25,14 @@ #include "DynamicCharacterController.h" #include "ContactInfo.h" #include "EntityMotionState.h" -#include "ShapeManager.h" #include "ThreadSafeDynamicsWorld.h" const float HALF_SIMULATION_EXTENT = 512.0f; // meters class ObjectMotionState; +typedef QSet SetOfMotionStates; + // simple class for keeping track of contacts class ContactKey { public: @@ -64,7 +65,7 @@ public: void sortEntitiesThatMovedInternal(); void clearEntitiesInternal(); - virtual void init(EntityEditPacketSender* packetSender); + virtual void init(); void stepSimulation(); void stepNonPhysicalKinematics(const quint64& now); @@ -107,15 +108,14 @@ private: btSequentialImpulseConstraintSolver* _constraintSolver = NULL; ThreadSafeDynamicsWorld* _dynamicsWorld = NULL; btGhostPairCallback* _ghostPairCallback = NULL; - ShapeManager _shapeManager; glm::vec3 _originOffset; // EntitySimulation stuff QSet _entityMotionStates; // all entities that we track - QSet _nonPhysicalKinematicObjects; // not in physics simulation, but still need kinematic simulation - QSet _incomingChanges; // entities with pending physics changes by script or packet - QSet _outgoingPackets; // MotionStates with pending changes that need to be sent over wire + SetOfMotionStates _nonPhysicalKinematicObjects; // not in physics simulation, but still need kinematic simulation + SetOfMotionStates _incomingChanges; // entities with pending physics changes by script or packet + SetOfMotionStates _outgoingPackets; // MotionStates with pending changes that need to be sent over wire EntityEditPacketSender* _entityPacketSender = NULL; From 14b6ee608a4e4eff6673b4ac215383f00193faa9 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 28 Apr 2015 15:07:37 -0700 Subject: [PATCH 03/89] more PhysicalEntitySimulation implementation with changes to API's accordingly (does not compile yet) --- interface/src/Application.cpp | 3 +- libraries/entities/src/EntityItem.cpp | 12 +- libraries/entities/src/EntityItem.h | 19 +- libraries/entities/src/EntitySimulation.cpp | 194 +++++++++++------- libraries/entities/src/EntitySimulation.h | 33 +-- libraries/entities/src/EntityTree.cpp | 18 +- libraries/physics/src/EntityMotionState.cpp | 1 - .../physics/src/PhysicalEntitySimulation.cpp | 77 ++++--- .../physics/src/PhysicalEntitySimulation.h | 15 +- 9 files changed, 219 insertions(+), 153 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4e5007c06c..0ddbc351ad 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2356,8 +2356,7 @@ void Application::update(float deltaTime) { _physicsEngine.removeObjects(_entitySimulation.getObjectsToRemove()); _physicsEngine.addObjects(_entitySimulation.getObjectsToAdd()); - _physicsEngine.updateObjects(_entitySimulation.getObjectsToUpdate()); - _entitySimulation.clearIncomingChanges(); + _physicsEngine.updateObjects(_entitySimulation.getObjectsToChange()); _physicsEngine.stepSimulation(); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 1d358f175a..ad04752132 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -63,9 +63,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : _simulatorID(ENTITY_ITEM_DEFAULT_SIMULATOR_ID), _simulatorIDChangedTime(0), _marketplaceID(ENTITY_ITEM_DEFAULT_MARKETPLACE_ID), - _physicsInfo(NULL), - _dirtyFlags(0), - _element(NULL) + _dirtyFlags(0) { quint64 now = usecTimestampNow(); _lastSimulated = now; @@ -78,9 +76,11 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert } EntityItem::~EntityItem() { - // be sure to clean up _physicsInfo before calling this dtor - assert(_physicsInfo == NULL); - assert(_element == NULL); + // these pointers MUST be NULL at delete, else we probably have a dangling backpointer + // to this EntityItem in the corresponding data structure. + assert(!_element); + assert(!_simulation); + assert(!_physicsInfo); } EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& params) const { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index e71f88d723..dd8b3abb37 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -28,7 +28,7 @@ #include "EntityItemPropertiesDefaults.h" #include "EntityTypes.h" -class EntityTree; +class EntitySimulation; class EntityTreeElement; class EntityTreeElementExtraEncodeData; @@ -44,7 +44,12 @@ class EntityTreeElementExtraEncodeData; /// 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. class EntityItem { + // These two classes manage lists of EntityItem pointers and must be able to cleanup pointers when an EntityItem is deleted. + // To make the cleanup robust each EntityItem has backpointers to its manager classes (which are only ever set/cleared by + // the managers themselves, hence they are fiends) whose NULL status can be used to determine which managers still need to + // do cleanup. friend class EntityTreeElement; + friend class EntitySimulation; public: enum EntityDirtyFlags { DIRTY_POSITION = 0x0001, @@ -293,9 +298,9 @@ public: bool isMoving() const; void* getPhysicsInfo() const { return _physicsInfo; } - void setPhysicsInfo(void* data) { _physicsInfo = data; } EntityTreeElement* getElement() const { return _element; } + EntitySimulation* getSimulation() const { return _simulation; } static void setSendPhysicsUpdates(bool value) { _sendPhysicsUpdates = value; } static bool getSendPhysicsUpdates() { return _sendPhysicsUpdates; } @@ -306,6 +311,7 @@ public: glm::vec3 entityToWorld(const glm::vec3& point) const; protected: + void setPhysicsInfo(void* data) { _physicsInfo = data; } static bool _sendPhysicsUpdates; EntityTypes::EntityType _type; @@ -365,14 +371,13 @@ protected: /// set radius in domain scale units (0.0 - 1.0) this will also reset dimensions to be equal for each axis void setRadius(float value); - // _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 = NULL; // only set by EntitySimulation - // DirtyFlags are set whenever a property changes that the EntitySimulation needs to know about. uint32_t _dirtyFlags; // things that have changed from EXTERNAL changes (via script or packet) but NOT from simulation - EntityTreeElement* _element; // back pointer to containing Element + // these backpointers are only ever set/cleared by friends: + EntityTreeElement* _element = nullptr; // set by EntityTreeElement + EntitySimulation* _simulation = nullptr; // set by EntitySimulation + void* _physicsInfo = nullptr; // set by EntitySimulation }; diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index a390521ed8..da08e5cd76 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -19,13 +19,13 @@ void EntitySimulation::setEntityTree(EntityTree* tree) { if (_entityTree && _entityTree != tree) { _mortalEntities.clear(); _nextExpiry = quint64(-1); - _updateableEntities.clear(); - _entitiesToBeSorted.clear(); + _entitiesToUpdate.clear(); + _entitiesToSort.clear(); } _entityTree = tree; } -void EntitySimulation::updateEntities(QSet& entitiesToDelete) { +void EntitySimulation::updateEntities() { quint64 now = usecTimestampNow(); // these methods may accumulate entries in _entitiesToBeDeleted @@ -33,10 +33,27 @@ void EntitySimulation::updateEntities(QSet& entitiesToDelete) { callUpdateOnEntitiesThatNeedIt(now); updateEntitiesInternal(now); sortEntitiesThatMoved(); +} - // at this point we harvest _entitiesToBeDeleted - entitiesToDelete.unite(_entitiesToDelete); - _entitiesToDelete.clear(); +void EntitySimulation::getEntitiesToDelete(SetOfEntities& entitiesToDelete) { + SetOfEntities::iterator entityItr = _entitiesToDelete.begin(); + while (entityItr != _entitiesToDelete.end()) { + EntityItem* entity = *entityItr; + if (entity->_simulation != this) { + if (entity->_element) { + // this entity is still in its tree, so we insert into the external list + entitiesToDelete.insert(entity); + } else { + // no more backpointers, so it should be safe to delete + delete entity; + } + // we're done with the entity in this context, so remove it from our internal list + entityItr = _entitiesToDelete.erase(entityItr); + } else { + // internal cleanup will happen later (probably in updateEntitiesInternal()) + ++entityItr; + } + } } // private @@ -44,16 +61,16 @@ void EntitySimulation::expireMortalEntities(const quint64& now) { if (now > _nextExpiry) { // only search for expired entities if we expect to find one _nextExpiry = quint64(-1); - QSet::iterator itemItr = _mortalEntities.begin(); + SetOfEntities::iterator itemItr = _mortalEntities.begin(); while (itemItr != _mortalEntities.end()) { EntityItem* entity = *itemItr; quint64 expiry = entity->getExpiry(); if (expiry < now) { _entitiesToDelete.insert(entity); itemItr = _mortalEntities.erase(itemItr); - _updateableEntities.remove(entity); - _entitiesToBeSorted.remove(entity); - removeEntityInternal(entity); + _entitiesToUpdate.remove(entity); + _entitiesToSort.remove(entity); + deleteEntityInternal(entity); } else { if (expiry < _nextExpiry) { // remeber the smallest _nextExpiry so we know when to start the next search @@ -68,13 +85,13 @@ void EntitySimulation::expireMortalEntities(const quint64& now) { // private void EntitySimulation::callUpdateOnEntitiesThatNeedIt(const quint64& now) { PerformanceTimer perfTimer("updatingEntities"); - QSet::iterator itemItr = _updateableEntities.begin(); - while (itemItr != _updateableEntities.end()) { + SetOfEntities::iterator itemItr = _entitiesToUpdate.begin(); + while (itemItr != _entitiesToUpdate.end()) { EntityItem* entity = *itemItr; // TODO: catch transition from needing update to not as a "change" // so we don't have to scan for it here. if (!entity->needsToCallUpdate()) { - itemItr = _updateableEntities.erase(itemItr); + itemItr = _entitiesToUpdate.erase(itemItr); } else { entity->update(now); ++itemItr; @@ -89,8 +106,8 @@ void EntitySimulation::sortEntitiesThatMoved() { PerformanceTimer perfTimer("sortingEntities"); MovingEntitiesOperator moveOperator(_entityTree); AACube domainBounds(glm::vec3(0.0f,0.0f,0.0f), (float)TREE_SCALE); - QSet::iterator itemItr = _entitiesToBeSorted.begin(); - while (itemItr != _entitiesToBeSorted.end()) { + SetOfEntities::iterator itemItr = _entitiesToSort.begin(); + while (itemItr != _entitiesToSort.end()) { EntityItem* entity = *itemItr; // check to see if this movement has sent the entity outside of the domain. AACube newCube = entity->getMaximumAACube(); @@ -98,9 +115,9 @@ void EntitySimulation::sortEntitiesThatMoved() { qCDebug(entities) << "Entity " << entity->getEntityItemID() << " moved out of domain bounds."; _entitiesToDelete.insert(entity); _mortalEntities.remove(entity); - _updateableEntities.remove(entity); - removeEntityInternal(entity); - itemItr = _entitiesToBeSorted.erase(itemItr); + _entitiesToUpdate.remove(entity); + deleteEntityInternal(entity); + itemItr = _entitiesToSort.erase(itemItr); } else { moveOperator.addEntityToMoveList(entity, newCube); ++itemItr; @@ -112,83 +129,120 @@ void EntitySimulation::sortEntitiesThatMoved() { } sortEntitiesThatMovedInternal(); - _entitiesToBeSorted.clear(); + _entitiesToSort.clear(); } void EntitySimulation::addEntity(EntityItem* entity) { assert(entity); - if (entity->isMortal()) { - _mortalEntities.insert(entity); - quint64 expiry = entity->getExpiry(); - if (expiry < _nextExpiry) { - _nextExpiry = expiry; + if (!entity->_simulation) { + entity->_simulation = this; + if (entity->isMortal()) { + _mortalEntities.insert(entity); + quint64 expiry = entity->getExpiry(); + if (expiry < _nextExpiry) { + _nextExpiry = expiry; + } } + if (entity->needsToCallUpdate()) { + _entitiesToUpdate.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(); } - if (entity->needsToCallUpdate()) { - _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) { assert(entity); - _updateableEntities.remove(entity); - _mortalEntities.remove(entity); - _entitiesToBeSorted.remove(entity); - _entitiesToDelete.remove(entity); - removeEntityInternal(entity); + if (entity->_simulation == this) { + _entitiesToUpdate.remove(entity); + _mortalEntities.remove(entity); + _entitiesToSort.remove(entity); + if (entity->_tree) { + // the tree still references this entity, but it's being removed from this simulation + _entitiesToDelete.remove(entity); + removeEntityInternal(entity); + } else { + // we're the last to reference this entity, so we really need to delete it + deleteEntityInternal(entity); + } + } else if (!entity->_tree) { + // nothing else is referencing this entity, so we delete it now + delete entity; + } } -void EntitySimulation::entityChanged(EntityItem* entity) { +void EntitySimulation::deleteEntity(EntityItem* entity) { assert(entity); - - // Although it is not the responsibility of the EntitySimulation to sort the tree for EXTERNAL changes - // it IS responsibile for triggering deletes for entities that leave the bounds of the domain, hence - // we must check for that case here, however we rely on the change event to have set DIRTY_POSITION flag. - bool wasRemoved = false; - uint32_t dirtyFlags = entity->getDirtyFlags(); - if (dirtyFlags & EntityItem::DIRTY_POSITION) { - AACube domainBounds(glm::vec3(0.0f,0.0f,0.0f), (float)TREE_SCALE); - AACube newCube = entity->getMaximumAACube(); - if (!domainBounds.touches(newCube)) { - qCDebug(entities) << "Entity " << entity->getEntityItemID() << " moved out of domain bounds."; + if (entity->_simulation == this) { + _entitiesToUpdate.remove(entity); + _mortalEntities.remove(entity); + _entitiesToSort.remove(entity); + deleteEntityInternal(entity); + } else { + if (entity->_tree) { + // the tree still references this entity, so we put it on the list + // which will be harvested by the tree later _entitiesToDelete.insert(entity); - _mortalEntities.remove(entity); - _updateableEntities.remove(entity); - removeEntityInternal(entity); - wasRemoved = true; + } else { + // nothing else is referencing this entity, so we delete it now + delete entity; } } - if (!wasRemoved) { - if (dirtyFlags & EntityItem::DIRTY_LIFETIME) { - if (entity->isMortal()) { - _mortalEntities.insert(entity); - quint64 expiry = entity->getExpiry(); - if (expiry < _nextExpiry) { - _nextExpiry = expiry; - } - } else { +} + +void EntitySimulation::changeEntity(EntityItem* entity) { + assert(entity); + if (entity->_simulation == this) { + // Although it is not the responsibility of the EntitySimulation to sort the tree for EXTERNAL changes + // it IS responsibile for triggering deletes for entities that leave the bounds of the domain, hence + // we must check for that case here, however we rely on the change event to have set DIRTY_POSITION flag. + bool wasRemoved = false; + uint32_t dirtyFlags = entity->getDirtyFlags(); + if (dirtyFlags & EntityItem::DIRTY_POSITION) { + AACube domainBounds(glm::vec3(0.0f,0.0f,0.0f), (float)TREE_SCALE); + AACube newCube = entity->getMaximumAACube(); + if (!domainBounds.touches(newCube)) { + qCDebug(entities) << "Entity " << entity->getEntityItemID() << " moved out of domain bounds."; + _entitiesToDelete.insert(entity); _mortalEntities.remove(entity); + _entitiesToUpdate.remove(entity); + deleteEntityInternal(entity); + wasRemoved = true; } - entity->clearDirtyFlags(EntityItem::DIRTY_LIFETIME); } - if (entity->needsToCallUpdate()) { - _updateableEntities.insert(entity); - } else { - _updateableEntities.remove(entity); + if (!wasRemoved) { + if (dirtyFlags & EntityItem::DIRTY_LIFETIME) { + if (entity->isMortal()) { + _mortalEntities.insert(entity); + quint64 expiry = entity->getExpiry(); + if (expiry < _nextExpiry) { + _nextExpiry = expiry; + } + } else { + _mortalEntities.remove(entity); + } + entity->clearDirtyFlags(EntityItem::DIRTY_LIFETIME); + } + if (entity->needsToCallUpdate()) { + _entitiesToUpdate.insert(entity); + } else { + _entitiesToUpdate.remove(entity); + } + changeEntityInternal(entity); } - entityChangedInternal(entity); + } else { + // this entity is not yet in this simulation but something (the tree) assumes that it is --> try to add it + addEntity(entity); } } void EntitySimulation::clearEntities() { _mortalEntities.clear(); _nextExpiry = quint64(-1); - _updateableEntities.clear(); - _entitiesToBeSorted.clear(); + _entitiesToUpdate.clear(); + _entitiesToSort.clear(); clearEntitiesInternal(); } diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index 1eb4fdc951..a145b3cc80 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -20,6 +20,8 @@ #include "EntityItem.h" #include "EntityTree.h" +typedef QSet SetOfEntities; + // 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 = @@ -44,20 +46,25 @@ public: /// \param tree pointer to EntityTree which is stored internally void setEntityTree(EntityTree* tree); - /// \param[out] entitiesToDelete list of entities removed from simulation and should be deleted. - void updateEntities(QSet& entitiesToDelete); + void updateEntities(); - /// \param entity pointer to EntityItem to add to the simulation - /// \sideeffect the EntityItem::_simulationState member may be updated to indicate membership to internal list + /// \param entity pointer to EntityItem to be added + /// \sideeffect sets relevant backpointers in entity, but maybe later when appropriate data structures are locked void 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 + /// \param entity pointer to EntityItem to be removed + /// \brief the actual removal may happen later when appropriate data structures are locked + /// \sideeffect nulls relevant backpointers in entity void removeEntity(EntityItem* entity); + /// \param pointer to EntityItem to be removed from simulation, and deleted if possible + /// \brief actual removal/delete may happen later when appropriate data structures are locked + /// \sideeffect nulls relevant backpointers in entity + void deleteEntity(EntityItem* entity); + /// \param entity pointer to EntityItem to that may have changed in a way that would affect its simulation /// call this whenever an entity was changed from some EXTERNAL event (NOT by the EntitySimulation itself) - void entityChanged(EntityItem* entity); + void changeEntity(EntityItem* entity); void clearEntities(); @@ -78,7 +85,9 @@ protected: virtual void removeEntityInternal(EntityItem* entity) = 0; - virtual void entityChangedInternal(EntityItem* entity) = 0; + virtual void deleteEntityInternal(EntityItem* entity) = 0; + + virtual void changeEntityInternal(EntityItem* entity) = 0; virtual void sortEntitiesThatMovedInternal() {} @@ -95,11 +104,11 @@ protected: // We maintain multiple lists, each for its distinct purpose. // An entity may be in more than one list. - QSet _mortalEntities; // entities that have an expiry + SetOfEntities _mortalEntities; // entities that have an expiry quint64 _nextExpiry; - QSet _updateableEntities; // entities that need update() called - QSet _entitiesToBeSorted; // entities that were moved by THIS simulation and might need to be resorted in the tree - QSet _entitiesToDelete; + SetOfEntities _entitiesToUpdate; // entities that need update() called + SetOfEntities _entitiesToSort; // entities that were moved by THIS simulation and might need to be resorted in the tree + SetOfEntities _entitiesToDelete; }; #endif // hifi_EntitySimulation_h diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 436339b3fe..f59a22d137 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -163,7 +163,7 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro if (_simulation) { if (newFlags & DIRTY_SIMULATION_FLAGS) { _simulation->lock(); - _simulation->entityChanged(entity); + _simulation->changeEntity(entity); _simulation->unlock(); } } else { @@ -349,10 +349,12 @@ void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator) _recentlyDeletedEntitiesLock.unlock(); } - if (_simulation) { - _simulation->removeEntity(theEntity); + if (_simulation && theEntity->getSimulation()) { + // delegate entity destruction to the simulation so it can clean up its own pointers + _simulation->deleteEntity(theEntity); + } else { + delete theEntity; // we can delete the entity directly now } - delete theEntity; // now actually delete the entity! } if (_simulation) { _simulation->unlock(); @@ -742,7 +744,7 @@ void EntityTree::releaseSceneEncodeData(OctreeElementExtraEncodeData* extraEncod void EntityTree::entityChanged(EntityItem* entity) { if (_simulation) { _simulation->lock(); - _simulation->entityChanged(entity); + _simulation->changeEntity(entity); _simulation->unlock(); } } @@ -750,10 +752,12 @@ void EntityTree::entityChanged(EntityItem* entity) { void EntityTree::update() { if (_simulation) { lockForWrite(); - QSet entitiesToDelete; _simulation->lock(); - _simulation->updateEntities(entitiesToDelete); + _simulation->updateEntities(); + SetOfEntities entitiesToDelete; + _simulation->getEntitiesToDelete(entitiesToDelete); _simulation->unlock(); + if (entitiesToDelete.size() > 0) { // translate into list of ID's QSet idsToDelete; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index a7245c32d4..3fa45953d4 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -47,7 +47,6 @@ EntityMotionState::EntityMotionState(EntityItem* entity) : EntityMotionState::~EntityMotionState() { assert(_entity); - _entity->setPhysicsInfo(NULL); _entity = NULL; } diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index 382e405203..32d15d5d3e 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -74,28 +74,26 @@ void PhysicalEntitySimulation::addEntityInternal(EntityItem* entity) { } } -void PhysicalEntitySimulation::get { - if (entity->isReadyToComputeShape()) { - ShapeInfo shapeInfo; - entity->computeShapeInfo(shapeInfo); - btCollisionShape* shape = _physicsEngine->getShape(shapeInfo); - if (shape) { - EntityMotionState* motionState = new EntityMotionState(entity); - entity->setPhysicsInfo(static_cast(motionState)); - _physicalEntities.insert(motionState); - _physicsEngine->addObject(shapeInfo, shape, motionState); - motionState->setPhysical(true); - } - } - } -} - void PhysicalEntitySimulation::removeEntityInternal(EntityItem* entity) { assert(entity); void* physicsInfo = entity->getPhysicsInfo(); if (physicsInfo) { ObjectMotionState* motionState = static_cast(physicsInfo); _pendingRemoves.insert(motionState); + } else { + entity->_simulation = nullptr; + } +} + +void PhysicalEntitySimulation::deleteEntityInternal(EntityItem* entity) { + assert(entity); + void* physicsInfo = entity->getPhysicsInfo(); + if (physicsInfo) { + ObjectMotionState* motionState = static_cast(physicsInfo); + _pendingRemoves.insert(motionState); + } else { + entity->_simulation = nullptr; + delete entity; } } @@ -105,7 +103,7 @@ void PhysicalEntitySimulation::entityChangedInternal(EntityItem* entity) { void* physicsInfo = entity->getPhysicsInfo(); if (physicsInfo) { ObjectMotionState* motionState = static_cast(physicsInfo); - _pendingUpdates.insert(motionState); + _pendingChanges.insert(motionState); } else { if (!entity->ignoreForCollisions()) { // The intent is for this object to be in the PhysicsEngine. @@ -119,49 +117,52 @@ void PhysicalEntitySimulation::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()) { + for (auto entityItr : _entitiesToBeSorted) { EntityItem* entity = *entityItr; void* physicsInfo = entity->getPhysicsInfo(); assert(physicsInfo); - ObjectMotionState* motionState = static_cast(physicsInfo); - _outgoingPackets.insert(motionState); - ++entityItr; + // BOOKMARK XXX -- Andrew to fix this next + _outgoingPackets.insert(static_cast(physicsInfo)); } } void PhysicalEntitySimulation::clearEntitiesInternal() { + // TODO: we should probably wait to lock the _physicsEngine so we don't mess up data structures + // while it is in the middle of a simulation step. As it is, we're probably in shutdown mode + // anyway, so maybe the simulation was already properly shutdown? Cross our fingers... SetOfMotionStates::const_iterator stateItr = _physicalEntities.begin(); - for (stateItr = _physicalEntities.begin(); stateItr != _physicalEntities.end(); ++stateItr) { - removeObjectFromBullet(*stateItr); - delete (*stateItr); + for (auto stateItr : _physicalEntities) { + EntityMotionState motionState = static_cast(*stateItr); + _physicsEngine->removeObjectFromBullet(motionState); + EntityItem* entity = motionState->_entity; + _entity->setPhysicsInfo(nullptr); + delete motionState; } _physicalEntities.clear(); _pendingRemoves.clear(); _pendingAdds.clear(); - _pendingUpdates.clear(); + _pendingChanges.clear(); } // end EntitySimulation overrides -SetOfMotionState& PhysicalEntitySimulation::getObjectsToRemove() { +VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToRemove() { _tempSet.clear(); for (auto entityItr : _pendingRemoves) { EntityItem* entity = *entityItr; + _physicalEntities.remove(entity); _pendingAdds.remove(entity); - _pendingUpdates.remove(entity); + _pendingChanges.remove(entity); ObjectMotionState* motionState = static_cast(entity->getPhysicsInfo()); if (motionState) { _tempSet.push_back(motionState); } } - // DO NOT clear _pendingRemoves -- we still need to remove from _physicalEntities - // and then communicate to the EntityTree that they can really can be deleted. - // TODO: build the pipeline for this. - //_pendingRemoves.clear(); + _pendingRemoves.clear(); return _tempSet; } -SetOfMotionState& PhysicalEntitySimulation::getObjectsToAdd() { +VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToAdd() { _tempSet.clear(); SetOfEntities::iterator entityItr = _pendingAdds.begin(); while (entityItr != _pendingAdds.end()) { @@ -189,25 +190,19 @@ SetOfMotionState& PhysicalEntitySimulation::getObjectsToAdd() { return _tempSet; } -SetOfMotionState& PhysicalEntitySimulation::getObjectsToUpdate() { +VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToChange() { _tempSet.clear(); - for (auto entityItr : _pendingUpdates) { + for (auto entityItr : _pendingChanges) { EntityItem* entity = *entityItr; ObjectMotionState* motionState = static_cast(entity->getPhysicsInfo()); if (motionState) { _tempSet.push_back(motionState); } } - _pendingUpdates.clear(); + _pendingChanges.clear(); return _tempSet; } -void PhysicalEntitySimulation::clearIncomingChanges() { - // TODO: finalize deletes in the EntityTree? - // or should we allow EntityMotionState::_entity to be NULL during normal operation? - // (In order to do this _pendingDeletes would have to be list of MotionStates, or something) -} - void PhysicalEntitySimulation::bump(EntityItem* bumpEntity) { } diff --git a/libraries/physics/src/PhysicalEntitySimulation.h b/libraries/physics/src/PhysicalEntitySimulation.h index 3929e152cd..ea8c545bc6 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.h +++ b/libraries/physics/src/PhysicalEntitySimulation.h @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -23,7 +24,8 @@ #include "PhysicsEngine.h" -typedef QSet SetOfEntities; +typedef QSet SetOfMotionStates; +typedef QVector VectorOfMotionStates; class PhysicalEntitySimulation :public EntitySimulation { public: @@ -36,22 +38,21 @@ public: void updateEntitiesInternal(const quint64& now); void addEntityInternal(EntityItem* entity); void removeEntityInternal(EntityItem* entity); + void deleteEntityInternal(EntityItem* entity); void entityChangedInternal(EntityItem* entity); void sortEntitiesThatMovedInternal(); void clearEntitiesInternal(); - SetOfMotionState& getObjectsToRemove(); - SetOfMotionState& getObjectsToAdd(); - SetOfMotionState& getObjectsToUpdate(); - - void clearIncomingChanges(); + VectorOfMotionStates& getObjectsToRemove(); + VectorOfMotionStates& getObjectsToAdd(); + VectorOfMotionStates& getObjectsToChange(); private: void bump(EntityItem* bumpEntity); SetOfEntities _pendingRemoves; // entities to be removed from simulation SetOfEntities _pendingAdds; // entities to be be added to simulation - SetOfEntities _pendingUpdates; // entities to be updated in simulation + SetOfEntities _pendingChanges; // entities already in simulation that need to be changed SetOfMotionStates _physicalEntities; // MotionStates of entities in PhysicsEngine VectorOfMotionStates _tempSet; // temporary list valid immediately after call to getObjectsToRemove/Add/Update() From 2f9306ee77dc7d77ad577f0196b0e1191d93f467 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 28 Apr 2015 16:28:03 -0700 Subject: [PATCH 04/89] SimpleEntitySimulation abides to new API --- .../entities/src/SimpleEntitySimulation.cpp | 16 ++++++++++++++-- libraries/entities/src/SimpleEntitySimulation.h | 9 +++++---- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index 6343ed3e47..495b2e97bf 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -19,7 +19,7 @@ const quint64 AUTO_REMOVE_SIMULATION_OWNER_USEC = 2 * USECS_PER_SECOND; void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { // now is usecTimestampNow() - QSet::iterator itemItr = _movingEntities.begin(); + SetOfEntities::iterator itemItr = _movingEntities.begin(); while (itemItr != _movingEntities.end()) { EntityItem* entity = *itemItr; if (!entity->isMoving()) { @@ -65,11 +65,23 @@ void SimpleEntitySimulation::removeEntityInternal(EntityItem* entity) { _movingEntities.remove(entity); _movableButStoppedEntities.remove(entity); _hasSimulationOwnerEntities.remove(entity); + entity->_simulation = nullptr; +} + +void SimpleEntitySimulation::deleteEntityInternal(EntityItem* entity) { + _movingEntities.remove(entity); + _movableButStoppedEntities.remove(entity); + _hasSimulationOwnerEntities.remove(entity); + entity->_simulation = nullptr; + if (!entity->_tree) { + // we held the last reference to this entity, so delete it + delete entity; + } } const int SIMPLE_SIMULATION_DIRTY_FLAGS = EntityItem::DIRTY_VELOCITY | EntityItem::DIRTY_MOTION_TYPE; -void SimpleEntitySimulation::entityChangedInternal(EntityItem* entity) { +void SimpleEntitySimulation::changeEntityInternal(EntityItem* entity) { int dirtyFlags = entity->getDirtyFlags(); if (dirtyFlags & SIMPLE_SIMULATION_DIRTY_FLAGS) { if (entity->isMoving()) { diff --git a/libraries/entities/src/SimpleEntitySimulation.h b/libraries/entities/src/SimpleEntitySimulation.h index af79ec0131..fa625e4783 100644 --- a/libraries/entities/src/SimpleEntitySimulation.h +++ b/libraries/entities/src/SimpleEntitySimulation.h @@ -25,12 +25,13 @@ protected: virtual void updateEntitiesInternal(const quint64& now); virtual void addEntityInternal(EntityItem* entity); virtual void removeEntityInternal(EntityItem* entity); - virtual void entityChangedInternal(EntityItem* entity); + virtual void deleteEntityInternal(EntityItem* entity); + virtual void changeEntityInternal(EntityItem* entity); virtual void clearEntitiesInternal(); - QSet _movingEntities; - QSet _movableButStoppedEntities; - QSet _hasSimulationOwnerEntities; + SetOfEntities _movingEntities; + SetOfEntities _movableButStoppedEntities; + SetOfEntities _hasSimulationOwnerEntities; }; #endif // hifi_SimpleEntitySimulation_h From c0a57533178cbd74380eba19b95be89b55c5559f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 28 Apr 2015 17:12:29 -0700 Subject: [PATCH 05/89] PhysicalEntitySimulation sends outgoing packets --- .../entities/src/SimpleEntitySimulation.cpp | 2 +- .../physics/src/PhysicalEntitySimulation.cpp | 35 +++++++++++++------ .../physics/src/PhysicalEntitySimulation.h | 6 ++++ 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index 495b2e97bf..14e0374ea7 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -27,7 +27,7 @@ void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { _movableButStoppedEntities.insert(entity); } else { entity->simulate(now); - _entitiesToBeSorted.insert(entity); + _entitiesToSort.insert(entity); ++itemItr; } } diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index 32d15d5d3e..bd656e878c 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -46,16 +46,16 @@ void PhysicalEntitySimulation::updateEntitiesInternal(const quint64& now) { // TODO: add back non-physical kinematic objects and step them forward here } -/* { +void PhysicalEntitySimulation::sendOutgoingPackets() { uint32_t numSubsteps = _physicsEngine->getNumSubsteps(); if (_lastNumSubstepsAtUpdateInternal != numSubsteps) { _lastNumSubstepsAtUpdateInternal = numSubsteps; - SetOfMotionStates::iterator stateItr = _outgoingPackets.begin(); - while (stateItr != _outgoingPackets.end()) { - ObjectMotionState* state = *stateItr; + SetOfMotionStates::iterator stateItr = _outgoingChanges.begin(); + while (stateItr != _outgoingChanges.end()) { + EntityMotionState* state = static_cast(*stateItr); if (state->doesNotNeedToSendUpdate()) { - stateItr = _outgoingPackets.erase(stateItr); + stateItr = _outgoingChanges.erase(stateItr); } else if (state->shouldSendUpdate(numSubsteps)) { state->sendUpdate(_entityPacketSender, numSubsteps); ++stateItr; @@ -64,7 +64,7 @@ void PhysicalEntitySimulation::updateEntitiesInternal(const quint64& now) { } } } -} */ +} void PhysicalEntitySimulation::addEntityInternal(EntityItem* entity) { assert(entity); @@ -114,15 +114,15 @@ void PhysicalEntitySimulation::entityChangedInternal(EntityItem* entity) { } void PhysicalEntitySimulation::sortEntitiesThatMovedInternal() { - // entities that have been simulated forward (hence in the _entitiesToBeSorted list) + // entities that have been simulated forward (hence in the _entitiesToSort list) // also need to be put in the outgoingPackets list - QSet::iterator entityItr = _entitiesToBeSorted.begin(); - for (auto entityItr : _entitiesToBeSorted) { + QSet::iterator entityItr = _entitiesToSort.begin(); + for (auto entityItr : _entitiesToSort) { EntityItem* entity = *entityItr; void* physicsInfo = entity->getPhysicsInfo(); assert(physicsInfo); // BOOKMARK XXX -- Andrew to fix this next - _outgoingPackets.insert(static_cast(physicsInfo)); + _outgoingChanges.insert(static_cast(physicsInfo)); } } @@ -203,6 +203,21 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToChange() { return _tempSet; } +void PhysicalEntitySimulation::handleOutgoingChanges(SetOfMotionStates& motionStates) { + SetOfMotionStates::iterator stateItr = motionStates.begin(); + while (stateItr != motionStates.end()) { + ObjectMotionState* state = *stateItr; + if (state->getType() == MOTION_STATE_TYPE_ENTITY) { + EntityMotionState* entityState = static_cast(state); + _outgoingChanges.insert(entityState); + stateItr = motionStates.erase(stateItr); + } else { + ++stateItr; + } + } + sendOutgoingPackets(); +} + void PhysicalEntitySimulation::bump(EntityItem* bumpEntity) { } diff --git a/libraries/physics/src/PhysicalEntitySimulation.h b/libraries/physics/src/PhysicalEntitySimulation.h index ea8c545bc6..905ff05291 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.h +++ b/libraries/physics/src/PhysicalEntitySimulation.h @@ -47,13 +47,19 @@ public: VectorOfMotionStates& getObjectsToAdd(); VectorOfMotionStates& getObjectsToChange(); + void handleOutgoingChanges(SetOfMotionStates& motionStates); + private: void bump(EntityItem* bumpEntity); + // incoming changes SetOfEntities _pendingRemoves; // entities to be removed from simulation SetOfEntities _pendingAdds; // entities to be be added to simulation SetOfEntities _pendingChanges; // entities already in simulation that need to be changed + // outgoing changes + SetOfEntities _outgoingChanges; // entities for which we need to send updates to entity-server + SetOfMotionStates _physicalEntities; // MotionStates of entities in PhysicsEngine VectorOfMotionStates _tempSet; // temporary list valid immediately after call to getObjectsToRemove/Add/Update() From ab38572620cac7ed821f1bb1e2a3f0c291b2559b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 29 Apr 2015 09:48:02 -0700 Subject: [PATCH 06/89] new PhysicsEngine API is mostly in place doesn't compile, of course large code movements are done non-physical kinematics have been lost -- will readd in PhysicalEntitySimuation class --- interface/src/Application.cpp | 9 +- libraries/physics/src/EntityMotionState.cpp | 146 +++++- libraries/physics/src/EntityMotionState.h | 36 +- libraries/physics/src/ObjectMotionState.cpp | 139 +----- libraries/physics/src/ObjectMotionState.h | 40 +- .../physics/src/PhysicalEntitySimulation.cpp | 21 +- .../physics/src/PhysicalEntitySimulation.h | 9 +- libraries/physics/src/PhysicsEngine.cpp | 435 +++++------------- libraries/physics/src/PhysicsEngine.h | 54 +-- libraries/physics/src/PhysicsTypedefs.h | 23 + .../physics/src/ThreadSafeDynamicsWorld.cpp | 28 +- .../physics/src/ThreadSafeDynamicsWorld.h | 7 + 12 files changed, 374 insertions(+), 573 deletions(-) create mode 100644 libraries/physics/src/PhysicsTypedefs.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0ddbc351ad..0c139d94cb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2356,13 +2356,14 @@ void Application::update(float deltaTime) { _physicsEngine.removeObjects(_entitySimulation.getObjectsToRemove()); _physicsEngine.addObjects(_entitySimulation.getObjectsToAdd()); - _physicsEngine.updateObjects(_entitySimulation.getObjectsToChange()); + _physicsEngine.changeObjects(_entitySimulation.getObjectsToChange()); _physicsEngine.stepSimulation(); - _entitySimulation.handleOutgoingChanges(_physicsEngine.getOutgoingChanges()); - _physicsEngine.clearOutgoingChanges(); - _physicsEngine.dumpStatsIfNecessary(); + if (_physicsEngine.hasOutgoingChanges()) { + _entitySimulation.handleOutgoingChanges(_physicsEngine.getOutgoingChanges()); + _physicsEngine.dumpStatsIfNecessary(); + } } if (!_aboutToQuit) { diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 3fa45953d4..d289826436 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -21,33 +21,31 @@ static const float ACCELERATION_EQUIVALENT_EPSILON_RATIO = 0.1f; static const quint8 STEPS_TO_DECIDE_BALLISTIC = 4; -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) : +EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItem* entity) : + ObjectMotionState(shape), _entity(entity), + _sentMoving(false), + _numNonMovingUpdates(0), + _outgoingPacketFlags(DIRTY_PHYSICS_FLAGS), + _sentStep(0), + _sentPosition(0.0f), + _sentRotation(), + _sentVelocity(0.0f), + _sentAngularVelocity(0.0f), + _sentGravity(0.0f), + _sentAcceleration(0.0f), _accelerationNearlyGravityCount(0), _shouldClaimSimulationOwnership(false), _movingStepsWithoutSimulationOwner(0) { _type = MOTION_STATE_TYPE_ENTITY; - assert(entity != NULL); + assert(entity != nullptr); } EntityMotionState::~EntityMotionState() { assert(_entity); - _entity = NULL; + _entity = nullptr; } MotionType EntityMotionState::computeObjectMotionType() const { @@ -126,7 +124,6 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { } _outgoingPacketFlags = DIRTY_PHYSICS_FLAGS; - EntityMotionState::enqueueOutgoingEntity(_entity); #ifdef WANT_DEBUG quint64 now = usecTimestampNow(); @@ -195,18 +192,119 @@ void EntityMotionState::updateBodyVelocities() { } } -void EntityMotionState::computeObjectShapeInfo(ShapeInfo& shapeInfo) { - if (_entity->isReadyToComputeShape()) { - _entity->computeShapeInfo(shapeInfo); - } +// 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 EntityMotionState::doesNotNeedToSendUpdate() const { + return !_body->isActive() && _numNonMovingUpdates > MAX_NUM_NON_MOVING_UPDATES; } -float EntityMotionState::computeObjectMass(const ShapeInfo& shapeInfo) const { - return _entity->computeMass(); +bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { + assert(_body); + // if we've never checked before, our _sentStep will be 0, and we need to initialize our state + if (_sentStep == 0) { + btTransform xform = _body->getWorldTransform(); + _sentPosition = bulletToGLM(xform.getOrigin()); + _sentRotation = bulletToGLM(xform.getRotation()); + _sentVelocity = bulletToGLM(_body->getLinearVelocity()); + _sentAngularVelocity = bulletToGLM(_body->getAngularVelocity()); + _sentStep = simulationStep; + return false; + } + + #ifdef WANT_DEBUG + glm::vec3 wasPosition = _sentPosition; + glm::quat wasRotation = _sentRotation; + glm::vec3 wasAngularVelocity = _sentAngularVelocity; + #endif + + int numSteps = simulationStep - _sentStep; + float dt = (float)(numSteps) * PHYSICS_ENGINE_FIXED_SUBSTEP; + _sentStep = simulationStep; + bool isActive = _body->isActive(); + + if (!isActive) { + if (_sentMoving) { + // 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 is done in the simulation-frame, which is NOT necessarily the same as the world-frame + // due to _worldOffset. + + // compute position error + if (glm::length2(_sentVelocity) > 0.0f) { + _sentVelocity += _sentAcceleration * dt; + _sentVelocity *= powf(1.0f - _body->getLinearDamping(), dt); + _sentPosition += dt * _sentVelocity; + } + + btTransform worldTrans = _body->getWorldTransform(); + glm::vec3 position = bulletToGLM(worldTrans.getOrigin()); + + float dx2 = glm::distance2(position, _sentPosition); + + const float MAX_POSITION_ERROR_SQUARED = 0.001f; // 0.001 m^2 ~~> 0.03 m + if (dx2 > MAX_POSITION_ERROR_SQUARED) { + + #ifdef WANT_DEBUG + qCDebug(physics) << ".... (dx2 > MAX_POSITION_ERROR_SQUARED) ...."; + qCDebug(physics) << "wasPosition:" << wasPosition; + qCDebug(physics) << "bullet position:" << position; + qCDebug(physics) << "_sentPosition:" << _sentPosition; + qCDebug(physics) << "dx2:" << dx2; + #endif + + return true; + } + + if (glm::length2(_sentAngularVelocity) > 0.0f) { + // compute rotation error + float attenuation = powf(1.0f - _body->getAngularDamping(), dt); + _sentAngularVelocity *= attenuation; + + // Bullet caps the effective rotation velocity inside its rotation integration step, therefore + // we must integrate with the same algorithm and timestep in order achieve similar results. + for (int i = 0; i < numSteps; ++i) { + _sentRotation = glm::normalize(computeBulletRotationStep(_sentAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP) * _sentRotation); + } + } + const float MIN_ROTATION_DOT = 0.99f; // 0.99 dot threshold coresponds to about 16 degrees of slop + glm::quat actualRotation = bulletToGLM(worldTrans.getRotation()); + + #ifdef WANT_DEBUG + if ((fabsf(glm::dot(actualRotation, _sentRotation)) < MIN_ROTATION_DOT)) { + qCDebug(physics) << ".... ((fabsf(glm::dot(actualRotation, _sentRotation)) < MIN_ROTATION_DOT)) ...."; + + qCDebug(physics) << "wasAngularVelocity:" << wasAngularVelocity; + qCDebug(physics) << "_sentAngularVelocity:" << _sentAngularVelocity; + + qCDebug(physics) << "length wasAngularVelocity:" << glm::length(wasAngularVelocity); + qCDebug(physics) << "length _sentAngularVelocity:" << glm::length(_sentAngularVelocity); + + qCDebug(physics) << "wasRotation:" << wasRotation; + qCDebug(physics) << "bullet actualRotation:" << actualRotation; + qCDebug(physics) << "_sentRotation:" << _sentRotation; + } + #endif + + return (fabsf(glm::dot(actualRotation, _sentRotation)) < MIN_ROTATION_DOT); } bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { - if (!ObjectMotionState::shouldSendUpdate(simulationFrame)) { + if (!remoteSimulationOutOfSync(simulationFrame)) { return false; } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 98d05a0420..f5eac220b4 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -25,13 +25,7 @@ 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); + EntityMotionState(btCollisionShape* shape, EntityItem* item); virtual ~EntityMotionState(); /// \return MOTION_TYPE_DYNAMIC or MOTION_TYPE_STATIC based on params set in EntityItem @@ -56,8 +50,13 @@ public: virtual void computeObjectShapeInfo(ShapeInfo& shapeInfo); virtual float computeObjectMass(const ShapeInfo& shapeInfo) const; - virtual bool shouldSendUpdate(uint32_t simulationFrame); - virtual void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t step); + bool doesNotNeedToSendUpdate() const; + bool remoteSimulationOutOfSync(uint32_t simulationStep); + bool shouldSendUpdate(uint32_t simulationFrame); + void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t step); + + void setShouldClaimSimulationOwnership(bool value) { } + bool getShouldClaimSimulationOwnership() { return false; } virtual uint32_t getIncomingDirtyFlags() const; virtual void clearIncomingDirtyFlags(uint32_t flags) { _entity->clearDirtyFlags(flags); } @@ -66,10 +65,6 @@ public: void resetAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount = 0; } quint8 getAccelerationNearlyGravityCount() { return _accelerationNearlyGravityCount; } - virtual EntityItem* getEntity() const { return _entity; } - virtual void setShouldClaimSimulationOwnership(bool value) { _shouldClaimSimulationOwnership = value; } - virtual bool getShouldClaimSimulationOwnership() { return _shouldClaimSimulationOwnership; } - virtual float getObjectRestitution() const { return _entity->getRestitution(); } virtual float getObjectFriction() const { return _entity->getFriction(); } virtual float getObjectLinearDamping() const { return _entity->getDamping(); } @@ -81,8 +76,23 @@ public: virtual const glm::vec3& getObjectAngularVelocity() const { return _entity->getAngularVelocity(); } virtual const glm::vec3& getObjectGravity() const { return _entity->getGravity(); } + void clearOutgoingPacketFlags(uint32_t flags) { _outgoingPacketFlags &= ~flags; } + protected: EntityItem* _entity; + + bool _sentMoving; // true if last update was moving + int _numNonMovingUpdates; // RELIABLE_SEND_HACK for "not so reliable" resends of packets for non-moving objects + + uint32_t _outgoingPacketFlags; + uint32_t _sentStep; + glm::vec3 _sentPosition; // in simulation-frame (not world-frame) + glm::quat _sentRotation;; + glm::vec3 _sentVelocity; + glm::vec3 _sentAngularVelocity; // radians per second + glm::vec3 _sentGravity; + glm::vec3 _sentAcceleration; + quint8 _accelerationNearlyGravityCount; bool _shouldClaimSimulationOwnership; quint32 _movingStepsWithoutSimulationOwner; diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index d8eb86f0b4..c0cba484c2 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -42,27 +42,21 @@ void ObjectMotionState::setWorldSimulationStep(uint32_t step) { _worldSimulationStep = step; } -ObjectMotionState::ObjectMotionState() : +ObjectMotionState::ObjectMotionState(btCollisionShape* shape) : _motionType(MOTION_TYPE_STATIC), - _body(NULL), - _sentMoving(false), - _numNonMovingUpdates(0), - _outgoingPacketFlags(DIRTY_PHYSICS_FLAGS), - _sentStep(0), - _sentPosition(0.0f), - _sentRotation(), - _sentVelocity(0.0f), - _sentAngularVelocity(0.0f), - _sentGravity(0.0f), - _sentAcceleration(0.0f), + _shape(shape), + _body(nullptr), + _mass(0.0f), _lastSimulationStep(0), _lastVelocity(0.0f), - _measuredAcceleration(0.0f) { + _measuredAcceleration(0.0f) +{ + assert(_shape); } ObjectMotionState::~ObjectMotionState() { // NOTE: you MUST remove this MotionState from the world before you call the dtor. - assert(_body == NULL); + assert(_body == nullptr); } void ObjectMotionState::measureBodyAcceleration() { @@ -106,122 +100,11 @@ void ObjectMotionState::getAngularVelocity(glm::vec3& angularVelocityOut) const angularVelocityOut = bulletToGLM(_body->getAngularVelocity()); } -// 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; -} - -bool ObjectMotionState::shouldSendUpdate(uint32_t simulationStep) { - assert(_body); - // if we've never checked before, our _sentStep will be 0, and we need to initialize our state - if (_sentStep == 0) { - btTransform xform = _body->getWorldTransform(); - _sentPosition = bulletToGLM(xform.getOrigin()); - _sentRotation = bulletToGLM(xform.getRotation()); - _sentVelocity = bulletToGLM(_body->getLinearVelocity()); - _sentAngularVelocity = bulletToGLM(_body->getAngularVelocity()); - _sentStep = simulationStep; - return false; - } - - #ifdef WANT_DEBUG - glm::vec3 wasPosition = _sentPosition; - glm::quat wasRotation = _sentRotation; - glm::vec3 wasAngularVelocity = _sentAngularVelocity; - #endif - - int numSteps = simulationStep - _sentStep; - float dt = (float)(numSteps) * PHYSICS_ENGINE_FIXED_SUBSTEP; - _sentStep = simulationStep; - bool isActive = _body->isActive(); - - if (!isActive) { - if (_sentMoving) { - // 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 is done in the simulation-frame, which is NOT necessarily the same as the world-frame - // due to _worldOffset. - - // compute position error - if (glm::length2(_sentVelocity) > 0.0f) { - _sentVelocity += _sentAcceleration * dt; - _sentVelocity *= powf(1.0f - _body->getLinearDamping(), dt); - _sentPosition += dt * _sentVelocity; - } - - btTransform worldTrans = _body->getWorldTransform(); - glm::vec3 position = bulletToGLM(worldTrans.getOrigin()); - - float dx2 = glm::distance2(position, _sentPosition); - - const float MAX_POSITION_ERROR_SQUARED = 0.001f; // 0.001 m^2 ~~> 0.03 m - if (dx2 > MAX_POSITION_ERROR_SQUARED) { - - #ifdef WANT_DEBUG - qCDebug(physics) << ".... (dx2 > MAX_POSITION_ERROR_SQUARED) ...."; - qCDebug(physics) << "wasPosition:" << wasPosition; - qCDebug(physics) << "bullet position:" << position; - qCDebug(physics) << "_sentPosition:" << _sentPosition; - qCDebug(physics) << "dx2:" << dx2; - #endif - - return true; - } - - if (glm::length2(_sentAngularVelocity) > 0.0f) { - // compute rotation error - float attenuation = powf(1.0f - _body->getAngularDamping(), dt); - _sentAngularVelocity *= attenuation; - - // Bullet caps the effective rotation velocity inside its rotation integration step, therefore - // we must integrate with the same algorithm and timestep in order achieve similar results. - for (int i = 0; i < numSteps; ++i) { - _sentRotation = glm::normalize(computeBulletRotationStep(_sentAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP) * _sentRotation); - } - } - const float MIN_ROTATION_DOT = 0.99f; // 0.99 dot threshold coresponds to about 16 degrees of slop - glm::quat actualRotation = bulletToGLM(worldTrans.getRotation()); - - #ifdef WANT_DEBUG - if ((fabsf(glm::dot(actualRotation, _sentRotation)) < MIN_ROTATION_DOT)) { - qCDebug(physics) << ".... ((fabsf(glm::dot(actualRotation, _sentRotation)) < MIN_ROTATION_DOT)) ...."; - - qCDebug(physics) << "wasAngularVelocity:" << wasAngularVelocity; - qCDebug(physics) << "_sentAngularVelocity:" << _sentAngularVelocity; - - qCDebug(physics) << "length wasAngularVelocity:" << glm::length(wasAngularVelocity); - qCDebug(physics) << "length _sentAngularVelocity:" << glm::length(_sentAngularVelocity); - - qCDebug(physics) << "wasRotation:" << wasRotation; - qCDebug(physics) << "bullet actualRotation:" << actualRotation; - qCDebug(physics) << "_sentRotation:" << _sentRotation; - } - #endif - - return (fabsf(glm::dot(actualRotation, _sentRotation)) < MIN_ROTATION_DOT); -} - void ObjectMotionState::setRigidBody(btRigidBody* body) { // give the body a (void*) back-pointer to this ObjectMotionState if (_body != body) { if (_body) { - _body->setUserPointer(NULL); + _body->setUserPointer(nullptr); } _body = body; if (_body) { @@ -230,7 +113,3 @@ void ObjectMotionState::setRigidBody(btRigidBody* body) { } } -void ObjectMotionState::setKinematic(bool kinematic, uint32_t substep) { - _isKinematic = kinematic; - _lastKinematicSubstep = substep; -} diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 7c00eedd09..caa46de497 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -62,7 +62,7 @@ public: // The WorldSimulationStep is a cached copy of number of SubSteps of the simulation, used for local time measurements. static void setWorldSimulationStep(uint32_t step); - ObjectMotionState(); + ObjectMotionState(btCollisionShape* shape); ~ObjectMotionState(); void measureBodyAcceleration(); @@ -77,8 +77,8 @@ public: MotionStateType getType() const { return _type; } virtual MotionType getMotionType() const { return _motionType; } - virtual void computeObjectShapeInfo(ShapeInfo& info) = 0; - virtual float computeObjectMass(const ShapeInfo& shapeInfo) const = 0; + void setMass(float mass) { _mass = fabsf(mass); } + float getMass() { return _mass; } void setBodyVelocity(const glm::vec3& velocity) const; void setBodyAngularVelocity(const glm::vec3& velocity) const; @@ -89,32 +89,16 @@ public: virtual uint32_t getIncomingDirtyFlags() const = 0; virtual void clearIncomingDirtyFlags(uint32_t flags) = 0; - void clearOutgoingPacketFlags(uint32_t flags) { _outgoingPacketFlags &= ~flags; } - - bool doesNotNeedToSendUpdate() const; - virtual bool shouldSendUpdate(uint32_t simulationStep); - virtual void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame) = 0; virtual MotionType computeObjectMotionType() const = 0; - virtual void updateKinematicState(uint32_t substep) = 0; - + btCollisionShape* getShape() const { return _shape; } btRigidBody* getRigidBody() const { return _body; } - bool isKinematic() const { return _isKinematic; } - - void setKinematic(bool kinematic, uint32_t substep); - virtual void stepKinematicSimulation(quint64 now) = 0; - virtual bool isMoving() const = 0; friend class PhysicsEngine; - // these are here so we can call into EntityMotionObject with a base-class pointer - virtual EntityItem* getEntity() const { return NULL; } - virtual void setShouldClaimSimulationOwnership(bool value) { } - virtual bool getShouldClaimSimulationOwnership() { return false; } - // These pure virtual methods must be implemented for each MotionState type // and make it possible to implement more complicated methods in this base class. @@ -136,22 +120,10 @@ protected: MotionType _motionType; // type of motion: KINEMATIC, DYNAMIC, or STATIC + btCollisionShape* _shape; btRigidBody* _body; - bool _isKinematic = false; - uint32_t _lastKinematicSubstep = 0; - - bool _sentMoving; // true if last update was moving - int _numNonMovingUpdates; // RELIABLE_SEND_HACK for "not so reliable" resends of packets for non-moving objects - - uint32_t _outgoingPacketFlags; - uint32_t _sentStep; - glm::vec3 _sentPosition; // in simulation-frame (not world-frame) - glm::quat _sentRotation;; - glm::vec3 _sentVelocity; - glm::vec3 _sentAngularVelocity; // radians per second - glm::vec3 _sentGravity; - glm::vec3 _sentAcceleration; + float _mass; uint32_t _lastSimulationStep; glm::vec3 _lastVelocity; diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index bd656e878c..cd45025bc6 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -9,13 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include - #include "PhysicalEntitySimulation.h" -#include "ShapeInfoUtil.h" +#include "PhysicsEngine.h" #include "PhysicsHelpers.h" -#include "ThreadSafeDynamicsWorld.h" #include "PhysicsLogging.h" +#include "ShapeInfoUtil.h" PhysicalEntitySimulation::PhysicalEntitySimulation() : } @@ -174,8 +172,7 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToAdd() { entity->computeShapeInfo(shapeInfo); btCollisionShape* shape = _shapeManager->getShape(shapeInfo); if (shape) { - shapeInfo.setShape(shape); - EntityMotionState* motionState = new EntityMotionState(entity); + EntityMotionState* motionState = new EntityMotionState(shape, entity); entity->setPhysicsInfo(static_cast(motionState)); _physicalEntities.insert(motionState); entityItr = _pendingAdds.erase(entityItr); @@ -203,16 +200,16 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToChange() { return _tempSet; } -void PhysicalEntitySimulation::handleOutgoingChanges(SetOfMotionStates& motionStates) { - SetOfMotionStates::iterator stateItr = motionStates.begin(); - while (stateItr != motionStates.end()) { +void PhysicalEntitySimulation::handleOutgoingChanges(VectorOfMotionStates& motionStates) { + for (auto stateItr : motionStates) { ObjectMotionState* state = *stateItr; if (state->getType() == MOTION_STATE_TYPE_ENTITY) { EntityMotionState* entityState = static_cast(state); _outgoingChanges.insert(entityState); - stateItr = motionStates.erase(stateItr); - } else { - ++stateItr; + // BOOKMARK TODO: + // * process _outgoingChanges. + // * move entityUpdate stuff out of EntityMotionState::setWorldTransform() and into new function. + // * lock entityTree in new function } } sendOutgoingPackets(); diff --git a/libraries/physics/src/PhysicalEntitySimulation.h b/libraries/physics/src/PhysicalEntitySimulation.h index 905ff05291..e7f8cf7104 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.h +++ b/libraries/physics/src/PhysicalEntitySimulation.h @@ -14,18 +14,15 @@ #include -#include -#include #include #include #include #include -#include "PhysicsEngine.h" +#include "PhysicsTypedefs.h" -typedef QSet SetOfMotionStates; -typedef QVector VectorOfMotionStates; +class PhysicsEngine; class PhysicalEntitySimulation :public EntitySimulation { public: @@ -47,7 +44,7 @@ public: VectorOfMotionStates& getObjectsToAdd(); VectorOfMotionStates& getObjectsToChange(); - void handleOutgoingChanges(SetOfMotionStates& motionStates); + void handleOutgoingChanges(VectorOfMotionStates& motionStates); private: void bump(EntityItem* bumpEntity); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 13590281de..4e4c4a89ce 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -11,9 +11,10 @@ #include +#include "ObjectMotionState.h" #include "PhysicsEngine.h" -#include "ShapeInfoUtil.h" #include "PhysicsHelpers.h" +#include "ShapeInfoUtil.h" #include "ThreadSafeDynamicsWorld.h" #include "PhysicsLogging.h" @@ -26,12 +27,12 @@ uint32_t PhysicsEngine::getNumSubsteps() { PhysicsEngine::PhysicsEngine(const glm::vec3& offset) : _originOffset(offset), - _characterController(NULL) { + _characterController(nullptr) { } PhysicsEngine::~PhysicsEngine() { if (_characterController) { - _characterController->setDynamicsWorld(NULL); + _characterController->setDynamicsWorld(nullptr); } // TODO: delete engine components... if we ever plan to create more than one instance delete _collisionConfig; @@ -42,217 +43,114 @@ PhysicsEngine::~PhysicsEngine() { delete _ghostPairCallback; } -// begin EntitySimulation overrides -void PhysicsEngine::updateEntitiesInternal(const quint64& now) { - // no need to send updates unless the physics simulation has actually stepped - if (_lastNumSubstepsAtUpdateInternal != _numSubsteps) { - _lastNumSubstepsAtUpdateInternal = _numSubsteps; - // NOTE: the grand order of operations is: - // (1) relay incoming changes - // (2) step simulation - // (3) synchronize outgoing motion states - // (4) send outgoing packets +void PhysicsEngine::init() { + if (!_dynamicsWorld) { + _collisionConfig = new btDefaultCollisionConfiguration(); + _collisionDispatcher = new btCollisionDispatcher(_collisionConfig); + _broadphaseFilter = new btDbvtBroadphase(); + _constraintSolver = new btSequentialImpulseConstraintSolver; + _dynamicsWorld = new ThreadSafeDynamicsWorld(_collisionDispatcher, _broadphaseFilter, _constraintSolver, _collisionConfig); + + _ghostPairCallback = new btGhostPairCallback(); + _dynamicsWorld->getPairCache()->setInternalGhostPairCallback(_ghostPairCallback); + + // 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)); + } +} + +void PhysicsEngine::removeObjects(VectorOfMotionStates& objects) { + for (auto object : objects) { + assert(object); - // this is step (4) - QSet::iterator stateItr = _outgoingPackets.begin(); - while (stateItr != _outgoingPackets.end()) { - ObjectMotionState* state = *stateItr; - if (state->doesNotNeedToSendUpdate()) { - stateItr = _outgoingPackets.erase(stateItr); - } else if (state->shouldSendUpdate(_numSubsteps)) { - state->sendUpdate(_entityPacketSender, _numSubsteps); - ++stateItr; - } else { - ++stateItr; + // wake up anything touching this object + bump(object); + + btRigidBody* body = object->getRigidBody(); + _dynamicsWorld->removeRigidBody(body); + + // NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it. + object->setRigidBody(nullptr); + delete body; + removeContacts(object); + object->releaseShape(); + } +} + +void PhysicsEngine::addObjects(VectorOfMotionStates& objects) { + for (auto object : objects) { + assert(object); + btCollisionShape* shape = object->getShape(); + assert(shape); + + btVector3 inertia(0.0f, 0.0f, 0.0f); + float mass = 0.0f; + btRigidBody* body = nullptr; + switch(object->computeObjectMotionType()) { + case MOTION_TYPE_KINEMATIC: { + body = new btRigidBody(mass, object, shape, inertia); + body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); + body->updateInertiaTensor(); + object->setRigidBody(body); + const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec + const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec + body->setSleepingThresholds(KINEMATIC_LINEAR_VELOCITY_THRESHOLD, KINEMATIC_ANGULAR_VELOCITY_THRESHOLD); + break; } - } - } -} - -void PhysicsEngine::addEntityInternal(EntityItem* entity) { - assert(entity); - void* physicsInfo = entity->getPhysicsInfo(); - if (!physicsInfo) { - if (entity->isReadyToComputeShape()) { - ShapeInfo shapeInfo; - entity->computeShapeInfo(shapeInfo); - btCollisionShape* shape = _shapeManager.getShape(shapeInfo); - if (shape) { - EntityMotionState* motionState = new EntityMotionState(entity); - entity->setPhysicsInfo(static_cast(motionState)); - _entityMotionStates.insert(motionState); - addObject(shapeInfo, shape, motionState); - } else if (entity->isMoving()) { - EntityMotionState* motionState = new EntityMotionState(entity); - entity->setPhysicsInfo(static_cast(motionState)); - _entityMotionStates.insert(motionState); - - motionState->setKinematic(true, _numSubsteps); - _nonPhysicalKinematicObjects.insert(motionState); - // We failed to add the entity to the simulation. Probably because we couldn't create a shape for it. - //qCDebug(physics) << "failed to add entity " << entity->getEntityItemID() << " to physics engine"; - } - } - } -} - -void PhysicsEngine::removeEntityInternal(EntityItem* entity) { - assert(entity); - void* physicsInfo = entity->getPhysicsInfo(); - if (physicsInfo) { - EntityMotionState* motionState = static_cast(physicsInfo); - if (motionState->getRigidBody()) { - removeObjectFromBullet(motionState); - } else { - // only need to hunt in this list when there is no RigidBody - _nonPhysicalKinematicObjects.remove(motionState); - } - _entityMotionStates.remove(motionState); - _incomingChanges.remove(motionState); - _outgoingPackets.remove(motionState); - // NOTE: EntityMotionState dtor will remove its backpointer from EntityItem - delete motionState; - } -} - -void PhysicsEngine::entityChangedInternal(EntityItem* entity) { - // queue incoming changes: from external sources (script, EntityServer, etc) to physics engine - assert(entity); - void* physicsInfo = entity->getPhysicsInfo(); - if (physicsInfo) { - if ((entity->getDirtyFlags() & (HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSICS_FLAGS)) > 0) { - 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; - } -} - -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(); - for (stateItr = _entityMotionStates.begin(); stateItr != _entityMotionStates.end(); ++stateItr) { - removeObjectFromBullet(*stateItr); - delete (*stateItr); - } - _entityMotionStates.clear(); - _nonPhysicalKinematicObjects.clear(); - _incomingChanges.clear(); - _outgoingPackets.clear(); -} -// end EntitySimulation overrides - -void PhysicsEngine::relayIncomingChangesToSimulation() { - BT_PROFILE("incomingChanges"); - // process incoming changes - QSet::iterator stateItr = _incomingChanges.begin(); - while (stateItr != _incomingChanges.end()) { - ObjectMotionState* motionState = *stateItr; - ++stateItr; - uint32_t flags = motionState->getIncomingDirtyFlags() & DIRTY_PHYSICS_FLAGS; - - bool removeMotionState = false; - 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 - // but it also handles all EASY changes - bool success = updateBodyHard(body, motionState, flags); - if (!success) { - // NOTE: since updateBodyHard() failed we know that motionState has been removed - // from simulation and body has been deleted. Depending on what else has changed - // we might need to remove motionState altogether... - if (flags & EntityItem::DIRTY_VELOCITY) { - motionState->updateKinematicState(_numSubsteps); - if (motionState->isKinematic()) { - // all is NOT lost, we still need to move this object around kinematically - _nonPhysicalKinematicObjects.insert(motionState); - } else { - // no need to keep motionState around - removeMotionState = true; - } - } else { - // no need to keep motionState around - removeMotionState = true; - } + case MOTION_TYPE_DYNAMIC: { + mass = object->getMass(); + shape->calculateLocalInertia(mass, inertia); + body = new btRigidBody(mass, object, shape, inertia); + body->updateInertiaTensor(); + object->setRigidBody(body); + object->updateBodyVelocities(); + // 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 + const float DYNAMIC_LINEAR_VELOCITY_THRESHOLD = 0.05f; // 5 cm/sec + const float DYNAMIC_ANGULAR_VELOCITY_THRESHOLD = 0.087266f; // ~5 deg/sec + body->setSleepingThresholds(DYNAMIC_LINEAR_VELOCITY_THRESHOLD, DYNAMIC_ANGULAR_VELOCITY_THRESHOLD); + if (!object->isMoving()) { + // try to initialize this object as inactive + body->forceActivationState(ISLAND_SLEEPING); } - } 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->updateBodyEasy(flags, _numSubsteps); + break; } - if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) { - motionState->resetMeasuredBodyAcceleration(); - } - } else { - // the only way we should ever get here (motionState exists but no body) is when the object - // is undergoing non-physical kinematic motion. - assert(_nonPhysicalKinematicObjects.contains(motionState)); - - // it is possible that the changes are such that the object can now be added to the physical simulation - if (flags & EntityItem::DIRTY_SHAPE) { - ShapeInfo shapeInfo; - motionState->computeObjectShapeInfo(shapeInfo); - btCollisionShape* shape = _shapeManager.getShape(shapeInfo); - if (shape) { - addObject(shapeInfo, shape, motionState); - _nonPhysicalKinematicObjects.remove(motionState); - } else if (flags & EntityItem::DIRTY_VELOCITY) { - // although we couldn't add the object to the simulation, might need to update kinematic motion... - motionState->updateKinematicState(_numSubsteps); - if (!motionState->isKinematic()) { - _nonPhysicalKinematicObjects.remove(motionState); - removeMotionState = true; - } - } - } else if (flags & EntityItem::DIRTY_VELOCITY) { - // although we still can't add to physics simulation, might need to update kinematic motion... - motionState->updateKinematicState(_numSubsteps); - if (!motionState->isKinematic()) { - _nonPhysicalKinematicObjects.remove(motionState); - removeMotionState = true; - } + case MOTION_TYPE_STATIC: + default: { + body = new btRigidBody(mass, object, shape, inertia); + body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT); + body->updateInertiaTensor(); + object->setRigidBody(body); + break; } } - if (removeMotionState) { - // if we get here then there is no need to keep this motionState around (no physics or kinematics) - _outgoingPackets.remove(motionState); - if (motionState->getType() == MOTION_STATE_TYPE_ENTITY) { - _entityMotionStates.remove(static_cast(motionState)); - } - // NOTE: motionState will clean up its own backpointers in the Object - delete motionState; - continue; - } - - // NOTE: the grand order of operations is: - // (1) relay incoming changes - // (2) step simulation - // (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 + body->setFlags(BT_DISABLE_WORLD_GRAVITY); + object->updateBodyMaterialProperties(); + + _dynamicsWorld->addRigidBody(body); + object->resetMeasuredBodyAcceleration(); + } +} + +void PhysicsEngine::changeObjects(VectorOfMotionStates& objects) { + for (auto object : objects) { + uint32_t flags = object->getIncomingDirtyFlags() & DIRTY_PHYSICS_FLAGS; + + btRigidBody* body = object->getRigidBody(); + 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 + updateBodyHard(body, object, flags); + } 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. + object->updateBodyEasy(flags, _numSubsteps); + } + if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) { + object->resetMeasuredBodyAcceleration(); + } } - _incomingChanges.clear(); } void PhysicsEngine::removeContacts(ObjectMotionState* motionState) { @@ -269,33 +167,6 @@ void PhysicsEngine::removeContacts(ObjectMotionState* motionState) { } } -// 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 ThreadSafeDynamicsWorld(_collisionDispatcher, _broadphaseFilter, _constraintSolver, _collisionConfig); - - _ghostPairCallback = new btGhostPairCallback(); - _dynamicsWorld->getPairCache()->setInternalGhostPairCallback(_ghostPairCallback); - - // 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)); - } - - /* TODO: move this to PhysicalEntitySimulation - assert(packetSender); - _entityPacketSender = packetSender; - EntityMotionState::setOutgoingEntityList(&_entitiesToBeSorted); - */ -} - void PhysicsEngine::stepSimulation() { lock(); CProfileManager::Reset(); @@ -306,9 +177,6 @@ void PhysicsEngine::stepSimulation() { // (3) synchronize outgoing motion states // (4) send outgoing packets - // This is step (1) pull incoming changes - relayIncomingChangesToSimulation(); - const int MAX_NUM_SUBSTEPS = 4; const float MAX_TIMESTEP = (float)MAX_NUM_SUBSTEPS * PHYSICS_ENGINE_FIXED_SUBSTEP; float dt = 1.0e-6f * (float)(_clock.getTimeMicroseconds()); @@ -318,7 +186,7 @@ void PhysicsEngine::stepSimulation() { // TODO: move character->preSimulation() into relayIncomingChanges if (_characterController) { if (_characterController->needsRemoval()) { - _characterController->setDynamicsWorld(NULL); + _characterController->setDynamicsWorld(nullptr); } _characterController->updateShapeIfNecessary(); if (_characterController->needsAddition()) { @@ -327,51 +195,20 @@ void PhysicsEngine::stepSimulation() { _characterController->preSimulation(timeStep); } - // This is step (2) step simulation int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP); - _numSubsteps += (uint32_t)numSubsteps; - stepNonPhysicalKinematics(usecTimestampNow()); - unlock(); - - // TODO: make all of this harvest stuff into one function: relayOutgoingChanges() if (numSubsteps > 0) { BT_PROFILE("postSimulation"); - // This is step (3) which is done outside of stepSimulation() so we can lock _entityTree. - // - // Unfortunately we have to unlock the simulation (above) before we try to lock the _entityTree - // to avoid deadlock -- the _entityTree may try to lock its EntitySimulation (from which this - // PhysicsEngine derives) when updating/adding/deleting entities so we need to wait for our own - // lock on the tree before we re-lock ourselves. - // - // TODO: untangle these lock sequences. + _numSubsteps += (uint32_t)numSubsteps; ObjectMotionState::setWorldSimulationStep(_numSubsteps); - _entityTree->lockForWrite(); - lock(); - _dynamicsWorld->synchronizeMotionStates(); if (_characterController) { _characterController->postSimulation(); } - computeCollisionEvents(); - - unlock(); - _entityTree->unlock(); + _hasOutgoingChanges = true; } } -void PhysicsEngine::stepNonPhysicalKinematics(const quint64& now) { - BT_PROFILE("nonPhysicalKinematics"); - QSet::iterator stateItr = _nonPhysicalKinematicObjects.begin(); - // TODO?: need to occasionally scan for stopped non-physical kinematics objects - while (stateItr != _nonPhysicalKinematicObjects.end()) { - ObjectMotionState* motionState = *stateItr; - motionState->stepKinematicSimulation(now); - ++stateItr; - } -} - - void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB) { assert(objectA); assert(objectB); @@ -379,14 +216,14 @@ void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const auto nodeList = DependencyManager::get(); QUuid myNodeID = nodeList->getSessionUUID(); const btCollisionObject* characterCollisionObject = - _characterController ? _characterController->getCollisionObject() : NULL; + _characterController ? _characterController->getCollisionObject() : nullptr; assert(!myNodeID.isNull()); ObjectMotionState* a = static_cast(objectA->getUserPointer()); ObjectMotionState* b = static_cast(objectB->getUserPointer()); - EntityItem* entityA = a ? a->getEntity() : NULL; - EntityItem* entityB = b ? b->getEntity() : NULL; + EntityItem* entityA = a ? a->getEntity() : nullptr; + EntityItem* entityB = b ? b->getEntity() : nullptr; bool aIsDynamic = entityA && !objectA->isStaticOrKinematicObject(); bool bIsDynamic = entityB && !objectB->isStaticOrKinematicObject(); @@ -407,7 +244,6 @@ void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const } } - void PhysicsEngine::computeCollisionEvents() { BT_PROFILE("computeCollisionEvents"); @@ -478,6 +314,12 @@ void PhysicsEngine::computeCollisionEvents() { ++_numContactFrames; } +VectorOfMotionStates& PhysicsEngine::getOutgoingChanges() { + _dynamicsWorld.synchronizeMotionStates(); + _hasOutgoingChanges = false; + return _dynamicsWorld.getChangedMotionStates(); +} + void PhysicsEngine::dumpStatsIfNecessary() { if (_dumpNextStats) { _dumpNextStats = false; @@ -500,14 +342,13 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap btVector3 inertia(0.0f, 0.0f, 0.0f); float mass = 0.0f; - btRigidBody* body = NULL; + btRigidBody* body = nullptr; switch(motionState->computeObjectMotionType()) { case MOTION_TYPE_KINEMATIC: { body = new btRigidBody(mass, motionState, shape, inertia); body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); body->updateInertiaTensor(); motionState->setRigidBody(body); - motionState->setKinematic(true, _numSubsteps); const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec body->setSleepingThresholds(KINEMATIC_LINEAR_VELOCITY_THRESHOLD, KINEMATIC_ANGULAR_VELOCITY_THRESHOLD); @@ -519,7 +360,6 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap body = new btRigidBody(mass, motionState, shape, inertia); body->updateInertiaTensor(); motionState->setRigidBody(body); - motionState->setKinematic(false, _numSubsteps); motionState->updateBodyVelocities(); // 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 @@ -538,7 +378,6 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT); body->updateInertiaTensor(); motionState->setRigidBody(body); - motionState->setKinematic(false, _numSubsteps); break; } } @@ -549,6 +388,8 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap motionState->resetMeasuredBodyAcceleration(); } +/* TODO: convert bump() to take an ObjectMotionState. +* Expose SimulationID to ObjectMotionState*/ void PhysicsEngine::bump(EntityItem* bumpEntity) { // If this node is doing something like deleting an entity, scan for contacts involving the // entity. For each found, flag the other entity involved as being simulated by this node. @@ -565,8 +406,8 @@ void PhysicsEngine::bump(EntityItem* bumpEntity) { if (a && b) { EntityMotionState* entityMotionStateA = static_cast(a); EntityMotionState* entityMotionStateB = static_cast(b); - EntityItem* entityA = entityMotionStateA ? entityMotionStateA->getEntity() : NULL; - EntityItem* entityB = entityMotionStateB ? entityMotionStateB->getEntity() : NULL; + EntityItem* entityA = entityMotionStateA ? entityMotionStateA->getEntity() : nullptr; + EntityItem* entityB = entityMotionStateB ? entityMotionStateB->getEntity() : nullptr; if (entityA && entityB) { if (entityA == bumpEntity) { entityMotionStateB->setShouldClaimSimulationOwnership(true); @@ -588,29 +429,9 @@ void PhysicsEngine::bump(EntityItem* bumpEntity) { unlock(); } -void PhysicsEngine::removeObjectFromBullet(ObjectMotionState* motionState) { - assert(motionState); - btRigidBody* body = motionState->getRigidBody(); - - // wake up anything touching this object - EntityItem* entityItem = motionState ? motionState->getEntity() : NULL; - bump(entityItem); - - if (body) { - const btCollisionShape* shape = body->getCollisionShape(); - _dynamicsWorld->removeRigidBody(body); - _shapeManager.releaseShape(shape); - // NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it. - motionState->setRigidBody(NULL); - delete body; - motionState->setKinematic(false, _numSubsteps); - - removeContacts(motionState); - } -} - // private bool PhysicsEngine::updateBodyHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags) { + // BOOKMARK TODO: move as much of this stuff into MotionState as possible. MotionType newType = motionState->computeObjectMotionType(); // pull body out of physics engine @@ -630,9 +451,8 @@ bool PhysicsEngine::updateBodyHard(btRigidBody* body, ObjectMotionState* motionS _shapeManager.releaseShape(oldShape); // NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it. - motionState->setRigidBody(NULL); + motionState->setRigidBody(nullptr); delete body; - motionState->setKinematic(false, _numSubsteps); removeContacts(motionState); return false; } else if (newShape != oldShape) { @@ -668,7 +488,6 @@ bool PhysicsEngine::updateBodyHard(btRigidBody* body, ObjectMotionState* motionS body->setMassProps(0.0f, btVector3(0.0f, 0.0f, 0.0f)); body->updateInertiaTensor(); - motionState->setKinematic(true, _numSubsteps); break; } case MOTION_TYPE_DYNAMIC: { @@ -685,7 +504,6 @@ bool PhysicsEngine::updateBodyHard(btRigidBody* body, ObjectMotionState* motionS body->updateInertiaTensor(); } body->forceActivationState(ACTIVE_TAG); - motionState->setKinematic(false, _numSubsteps); break; } default: { @@ -700,7 +518,6 @@ bool PhysicsEngine::updateBodyHard(btRigidBody* body, ObjectMotionState* motionS body->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f)); body->setAngularVelocity(btVector3(0.0f, 0.0f, 0.0f)); - motionState->setKinematic(false, _numSubsteps); break; } } @@ -717,8 +534,8 @@ void PhysicsEngine::setCharacterController(DynamicCharacterController* character lock(); if (_characterController) { // remove the character from the DynamicsWorld immediately - _characterController->setDynamicsWorld(NULL); - _characterController = NULL; + _characterController->setDynamicsWorld(nullptr); + _characterController = nullptr; } // the character will be added to the DynamicsWorld later _characterController = character; diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 9a93563757..a6bacfa389 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -14,25 +14,20 @@ #include -#include +#include #include #include -#include -#include - #include "BulletUtil.h" -#include "DynamicCharacterController.h" #include "ContactInfo.h" -#include "EntityMotionState.h" +#include "DynamicCharacterController.h" +#include "PhysicsTypedefs.h" #include "ThreadSafeDynamicsWorld.h" const float HALF_SIMULATION_EXTENT = 512.0f; // meters class ObjectMotionState; -typedef QSet SetOfMotionStates; - // simple class for keeping track of contacts class ContactKey { public: @@ -40,37 +35,32 @@ public: 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; // EntityMotionState pointer - void* _b; // EntityMotionState pointer + void* _a; // ObjectMotionState pointer + void* _b; // ObjectMotionState pointer }; typedef std::map ContactMap; typedef std::pair ContactMapElement; -class PhysicsEngine : public EntitySimulation { +class PhysicsEngine { 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(); + void init(); - // 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(); + /// process queue of changed from external sources + void removeObjects(VectorOfMotionStates& objects); + void addObjects(VectorOfMotionStates& objects); + void changeObjects(VectorOfMotionStates& objects); void stepSimulation(); - void stepNonPhysicalKinematics(const quint64& now); void computeCollisionEvents(); + bool hasOutgoingChanges() const { return _hasOutgoingChanges; } + VectorOfMotionStates& getOutgoingChanges(); void dumpStatsIfNecessary(); /// \param offset position of simulation origin in domain-frame @@ -83,26 +73,17 @@ public: /// \return true if Object added void addObject(const ShapeInfo& shapeInfo, btCollisionShape* shape, ObjectMotionState* motionState); - /// process queue of changed from external sources - void relayIncomingChangesToSimulation(); - void setCharacterController(DynamicCharacterController* character); void dumpNextStats() { _dumpNextStats = true; } - void bump(EntityItem* bumpEntity); - private: - /// \param motionState pointer to Object's MotionState - void removeObjectFromBullet(ObjectMotionState* motionState); - void removeContacts(ObjectMotionState* motionState); void doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB); // return 'true' of update was successful bool updateBodyHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); - void updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); btClock _clock; btDefaultCollisionConfiguration* _collisionConfig = NULL; @@ -114,14 +95,6 @@ private: glm::vec3 _originOffset; - // EntitySimulation stuff - QSet _entityMotionStates; // all entities that we track - SetOfMotionStates _nonPhysicalKinematicObjects; // not in physics simulation, but still need kinematic simulation - SetOfMotionStates _incomingChanges; // entities with pending physics changes by script or packet - SetOfMotionStates _outgoingPackets; // MotionStates with pending changes that need to be sent over wire - - EntityEditPacketSender* _entityPacketSender = NULL; - ContactMap _contactMap; uint32_t _numContactFrames = 0; uint32_t _lastNumSubstepsAtUpdateInternal = 0; @@ -130,6 +103,7 @@ private: DynamicCharacterController* _characterController = NULL; bool _dumpNextStats = false; + bool _hasOutgoingChanges = false; }; #endif // hifi_PhysicsEngine_h diff --git a/libraries/physics/src/PhysicsTypedefs.h b/libraries/physics/src/PhysicsTypedefs.h new file mode 100644 index 0000000000..9d9685a758 --- /dev/null +++ b/libraries/physics/src/PhysicsTypedefs.h @@ -0,0 +1,23 @@ +// +// PhysicsTypedefs.h +// libraries/physcis/src +// +// Created by Andrew Meadows 2015.04.29 +// 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_PhysicsTypedefs_h +#define hifi_PhysicsTypedefs_h + +#include +#include + +class ObjectMotionState; + +typedef QSet SetOfMotionStates; +typedef QVector VectorOfMotionStates; + +#endif //hifi_PhysicsTypedefs_h diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp index a345b915db..4ea4f2e170 100644 --- a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp @@ -57,7 +57,7 @@ int ThreadSafeDynamicsWorld::stepSimulation( btScalar timeStep, int maxSubSteps, /*//process some debugging flags if (getDebugDrawer()) { - btIDebugDraw* debugDrawer = getDebugDrawer (); + btIDebugDraw* debugDrawer = getDebugDrawer(); gDisableDeactivation = (debugDrawer->getDebugMode() & btIDebugDraw::DBG_NoDeactivation) != 0; }*/ if (subSteps) { @@ -84,3 +84,29 @@ int ThreadSafeDynamicsWorld::stepSimulation( btScalar timeStep, int maxSubSteps, return subSteps; } + +void ThreadSafeDynamicsWorld::synchronizeMotionStates() { + _changedMotionStates.clear(); + BT_PROFILE("synchronizeMotionStates"); + if (m_synchronizeAllMotionStates) { + //iterate over all collision objects + for (int i=0;igetMotionState()); + } + } + } else { + //iterate over all active rigid bodies + for (int i=0;iisActive()) { + synchronizeSingleMotionState(body); + _changedMotionStates.push_back(body->getMotionState()); + } + } + } +} + diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.h b/libraries/physics/src/ThreadSafeDynamicsWorld.h index 832efb9b60..6f8ddaa4b8 100644 --- a/libraries/physics/src/ThreadSafeDynamicsWorld.h +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.h @@ -20,6 +20,8 @@ #include +#include "PhysicsTypedefs.h" + ATTRIBUTE_ALIGNED16(class) ThreadSafeDynamicsWorld : public btDiscreteDynamicsWorld { public: BT_DECLARE_ALIGNED_ALLOCATOR(); @@ -37,6 +39,11 @@ public: // 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; } + + VectorOfMotionStates& getChangedMotionStates() const { return _changedMotionStates; } + +private: + VectorOfMotionStates _changedMotionStates; }; #endif // hifi_ThreadSafeDynamicsWorld_h From 31ab16ac6224a59dcfe77269f2108eea1257d801 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 29 Apr 2015 16:16:44 -0700 Subject: [PATCH 07/89] move stuff into ObjectMotionState --- interface/src/Application.cpp | 1 + libraries/physics/src/EntityMotionState.cpp | 310 +++++++----------- libraries/physics/src/EntityMotionState.h | 8 +- libraries/physics/src/ObjectMotionState.cpp | 116 ++++++- libraries/physics/src/ObjectMotionState.h | 32 +- .../physics/src/PhysicalEntitySimulation.cpp | 148 +-------- .../physics/src/PhysicalEntitySimulation.h | 4 +- libraries/physics/src/PhysicsEngine.cpp | 138 +------- libraries/physics/src/PhysicsEngine.h | 3 - 9 files changed, 279 insertions(+), 481 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0c139d94cb..ab5cc5b6c6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2060,6 +2060,7 @@ void Application::init() { _entities.init(); _entities.setViewFrustum(getViewFrustum()); + ObjectMotionState::setShapeManager(&_shapeManager); _physicsEngine.init(); EntityTree* tree = _entities.getTree(); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index d289826436..fddb89c399 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -27,7 +27,6 @@ EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItem* entity _entity(entity), _sentMoving(false), _numNonMovingUpdates(0), - _outgoingPacketFlags(DIRTY_PHYSICS_FLAGS), _sentStep(0), _sentPosition(0.0f), _sentRotation(), @@ -123,8 +122,6 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { setShouldClaimSimulationOwnership(true); } - _outgoingPacketFlags = DIRTY_PHYSICS_FLAGS; - #ifdef WANT_DEBUG quint64 now = usecTimestampNow(); qCDebug(physics) << "EntityMotionState::setWorldTransform()... changed entity:" << _entity->getEntityItemID(); @@ -134,64 +131,6 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { #endif } -void EntityMotionState::updateBodyEasy(uint32_t flags, uint32_t step) { - if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY | EntityItem::DIRTY_PHYSICS_NO_WAKE)) { - if (flags & EntityItem::DIRTY_POSITION) { - _sentPosition = getObjectPosition() - ObjectMotionState::getWorldOffset(); - btTransform worldTrans; - worldTrans.setOrigin(glmToBullet(_sentPosition)); - - _sentRotation = getObjectRotation(); - worldTrans.setRotation(glmToBullet(_sentRotation)); - - _body->setWorldTransform(worldTrans); - } - if (flags & EntityItem::DIRTY_VELOCITY) { - updateBodyVelocities(); - } - _sentStep = step; - - if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) { - _body->activate(); - } - } - - if (flags & EntityItem::DIRTY_MATERIAL) { - updateBodyMaterialProperties(); - } - - if (flags & EntityItem::DIRTY_MASS) { - ShapeInfo shapeInfo; - _entity->computeShapeInfo(shapeInfo); - float mass = computeObjectMass(shapeInfo); - btVector3 inertia(0.0f, 0.0f, 0.0f); - _body->getCollisionShape()->calculateLocalInertia(mass, inertia); - _body->setMassProps(mass, inertia); - _body->updateInertiaTensor(); - } -} - -void EntityMotionState::updateBodyMaterialProperties() { - _body->setRestitution(getObjectRestitution()); - _body->setFriction(getObjectFriction()); - _body->setDamping(fabsf(btMin(getObjectLinearDamping(), 1.0f)), fabsf(btMin(getObjectAngularDamping(), 1.0f))); -} - -void EntityMotionState::updateBodyVelocities() { - if (_body) { - _sentVelocity = getObjectLinearVelocity(); - setBodyVelocity(_sentVelocity); - - _sentAngularVelocity = getObjectAngularVelocity(); - setBodyAngularVelocity(_sentAngularVelocity); - - _sentGravity = getObjectGravity(); - setBodyGravity(_sentGravity); - - _body->setActivationState(ACTIVE_TAG); - } -} - // 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; @@ -328,140 +267,132 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ if (!_entity->isKnownID()) { return; // never update entities that are unknown } - if (_outgoingPacketFlags) { - EntityItemProperties properties = _entity->getProperties(); - float gravityLength = glm::length(_entity->getGravity()); - float accVsGravity = glm::abs(glm::length(_measuredAcceleration) - gravityLength); - if (accVsGravity < ACCELERATION_EQUIVALENT_EPSILON_RATIO * gravityLength) { - // acceleration measured during the most recent simulation step was close to gravity. - if (getAccelerationNearlyGravityCount() < STEPS_TO_DECIDE_BALLISTIC) { - // only increment this if we haven't reached the threshold yet. this is to avoid - // overflowing the counter. - incrementAccelerationNearlyGravityCount(); - } - } else { - // acceleration wasn't similar to this entities gravity, so reset the went-ballistic counter - resetAccelerationNearlyGravityCount(); + EntityItemProperties properties = _entity->getProperties(); + + float gravityLength = glm::length(_entity->getGravity()); + float accVsGravity = glm::abs(glm::length(_measuredAcceleration) - gravityLength); + if (accVsGravity < ACCELERATION_EQUIVALENT_EPSILON_RATIO * gravityLength) { + // acceleration measured during the most recent simulation step was close to gravity. + if (getAccelerationNearlyGravityCount() < STEPS_TO_DECIDE_BALLISTIC) { + // only increment this if we haven't reached the threshold yet. this is to avoid + // overflowing the counter. + incrementAccelerationNearlyGravityCount(); } - - // if this entity has been accelerated at close to gravity for a certain number of simulation-steps, let - // the entity server's estimates include gravity. - if (getAccelerationNearlyGravityCount() >= STEPS_TO_DECIDE_BALLISTIC) { - _entity->setAcceleration(_entity->getGravity()); - } else { - _entity->setAcceleration(glm::vec3(0.0f)); - } - - if (_outgoingPacketFlags & EntityItem::DIRTY_POSITION) { - btTransform worldTrans = _body->getWorldTransform(); - _sentPosition = bulletToGLM(worldTrans.getOrigin()); - properties.setPosition(_sentPosition + ObjectMotionState::getWorldOffset()); - - _sentRotation = bulletToGLM(worldTrans.getRotation()); - properties.setRotation(_sentRotation); - } - - bool zeroSpeed = true; - bool zeroSpin = true; - - if (_outgoingPacketFlags & EntityItem::DIRTY_VELOCITY) { - if (_body->isActive()) { - _sentVelocity = bulletToGLM(_body->getLinearVelocity()); - _sentAngularVelocity = bulletToGLM(_body->getAngularVelocity()); - - // if the speeds are very small we zero them out - const float MINIMUM_EXTRAPOLATION_SPEED_SQUARED = 1.0e-4f; // 1cm/sec - 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 - zeroSpin = glm::length2(_sentAngularVelocity) < MINIMUM_EXTRAPOLATION_SPIN_SQUARED; - if (zeroSpin) { - _sentAngularVelocity = glm::vec3(0.0f); - } - - _sentMoving = ! (zeroSpeed && zeroSpin); - } else { - _sentVelocity = _sentAngularVelocity = glm::vec3(0.0f); - _sentMoving = false; - } - properties.setVelocity(_sentVelocity); - _sentGravity = _entity->getGravity(); - properties.setGravity(_entity->getGravity()); - _sentAcceleration = _entity->getAcceleration(); - properties.setAcceleration(_sentAcceleration); - properties.setAngularVelocity(_sentAngularVelocity); - } - - auto nodeList = DependencyManager::get(); - QUuid myNodeID = nodeList->getSessionUUID(); - QUuid simulatorID = _entity->getSimulatorID(); - - if (getShouldClaimSimulationOwnership()) { - properties.setSimulatorID(myNodeID); - setShouldClaimSimulationOwnership(false); - } else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { - // we are the simulator and the entity has stopped. give up "simulator" status - _entity->setSimulatorID(QUuid()); - properties.setSimulatorID(QUuid()); - } else if (simulatorID == myNodeID && !_body->isActive()) { - // it's not active. don't keep simulation ownership. - _entity->setSimulatorID(QUuid()); - properties.setSimulatorID(QUuid()); - } - - // 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, nor when we resend non-moving data) - // NOTE: Andrew & Brad to discuss. Let's make sure we're using lastEdited, lastSimulated, and lastUpdated correctly - quint64 lastSimulated = _entity->getLastSimulated(); - _entity->setLastEdited(lastSimulated); - properties.setLastEdited(lastSimulated); - - #ifdef WANT_DEBUG - quint64 now = usecTimestampNow(); - qCDebug(physics) << "EntityMotionState::sendUpdate()"; - qCDebug(physics) << " EntityItemId:" << _entity->getEntityItemID() - << "---------------------------------------------"; - qCDebug(physics) << " lastSimulated:" << debugTime(lastSimulated, now); - #endif //def WANT_DEBUG - - } else { - properties.setLastEdited(_entity->getLastEdited()); - } - - if (EntityItem::getSendPhysicsUpdates()) { - EntityItemID id(_entity->getID()); - EntityEditPacketSender* entityPacketSender = static_cast(packetSender); - #ifdef WANT_DEBUG - qCDebug(physics) << "EntityMotionState::sendUpdate()... calling queueEditEntityMessage()..."; - #endif - - entityPacketSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties); - } else { - #ifdef WANT_DEBUG - qCDebug(physics) << "EntityMotionState::sendUpdate()... NOT sending update as requested."; - #endif - } - - // 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; - _sentStep = step; + } else { + // acceleration wasn't similar to this entities gravity, so reset the went-ballistic counter + resetAccelerationNearlyGravityCount(); } + + // if this entity has been accelerated at close to gravity for a certain number of simulation-steps, let + // the entity server's estimates include gravity. + if (getAccelerationNearlyGravityCount() >= STEPS_TO_DECIDE_BALLISTIC) { + _entity->setAcceleration(_entity->getGravity()); + } else { + _entity->setAcceleration(glm::vec3(0.0f)); + } + + btTransform worldTrans = _body->getWorldTransform(); + _sentPosition = bulletToGLM(worldTrans.getOrigin()); + properties.setPosition(_sentPosition + ObjectMotionState::getWorldOffset()); + + _sentRotation = bulletToGLM(worldTrans.getRotation()); + properties.setRotation(_sentRotation); + + bool zeroSpeed = true; + bool zeroSpin = true; + + if (_body->isActive()) { + _sentVelocity = bulletToGLM(_body->getLinearVelocity()); + _sentAngularVelocity = bulletToGLM(_body->getAngularVelocity()); + + // if the speeds are very small we zero them out + const float MINIMUM_EXTRAPOLATION_SPEED_SQUARED = 1.0e-4f; // 1cm/sec + 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 + zeroSpin = glm::length2(_sentAngularVelocity) < MINIMUM_EXTRAPOLATION_SPIN_SQUARED; + if (zeroSpin) { + _sentAngularVelocity = glm::vec3(0.0f); + } + + _sentMoving = ! (zeroSpeed && zeroSpin); + } else { + _sentVelocity = _sentAngularVelocity = glm::vec3(0.0f); + _sentMoving = false; + } + properties.setVelocity(_sentVelocity); + _sentGravity = _entity->getGravity(); + properties.setGravity(_entity->getGravity()); + _sentAcceleration = _entity->getAcceleration(); + properties.setAcceleration(_sentAcceleration); + properties.setAngularVelocity(_sentAngularVelocity); + + auto nodeList = DependencyManager::get(); + QUuid myNodeID = nodeList->getSessionUUID(); + QUuid simulatorID = _entity->getSimulatorID(); + + if (getShouldClaimSimulationOwnership()) { + properties.setSimulatorID(myNodeID); + setShouldClaimSimulationOwnership(false); + } else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { + // we are the simulator and the entity has stopped. give up "simulator" status + _entity->setSimulatorID(QUuid()); + properties.setSimulatorID(QUuid()); + } else if (simulatorID == myNodeID && !_body->isActive()) { + // it's not active. don't keep simulation ownership. + _entity->setSimulatorID(QUuid()); + properties.setSimulatorID(QUuid()); + } + + // 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, nor when we resend non-moving data) + // NOTE: Andrew & Brad to discuss. Let's make sure we're using lastEdited, lastSimulated, and lastUpdated correctly + quint64 lastSimulated = _entity->getLastSimulated(); + _entity->setLastEdited(lastSimulated); + properties.setLastEdited(lastSimulated); + + #ifdef WANT_DEBUG + quint64 now = usecTimestampNow(); + qCDebug(physics) << "EntityMotionState::sendUpdate()"; + qCDebug(physics) << " EntityItemId:" << _entity->getEntityItemID() + << "---------------------------------------------"; + qCDebug(physics) << " lastSimulated:" << debugTime(lastSimulated, now); + #endif //def WANT_DEBUG + + } else { + properties.setLastEdited(_entity->getLastEdited()); + } + + if (EntityItem::getSendPhysicsUpdates()) { + EntityItemID id(_entity->getID()); + EntityEditPacketSender* entityPacketSender = static_cast(packetSender); + #ifdef WANT_DEBUG + qCDebug(physics) << "EntityMotionState::sendUpdate()... calling queueEditEntityMessage()..."; + #endif + + entityPacketSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties); + } else { + #ifdef WANT_DEBUG + qCDebug(physics) << "EntityMotionState::sendUpdate()... NOT sending update as requested."; + #endif + } + + _sentStep = step; } uint32_t EntityMotionState::getIncomingDirtyFlags() const { - uint32_t dirtyFlags = _entity->getDirtyFlags(); - + return _entity->getDirtyFlags(); +/* TODO: reimplement this motion-type adjustment if (_body) { // we add DIRTY_MOTION_TYPE if the body's motion type disagrees with entity velocity settings int bodyFlags = _body->getCollisionFlags(); @@ -472,4 +403,5 @@ uint32_t EntityMotionState::getIncomingDirtyFlags() const { } } return dirtyFlags; +*/ } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index f5eac220b4..9e8cf16c4f 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -42,11 +42,6 @@ public: // this relays outgoing position/rotation to the EntityItem virtual void setWorldTransform(const btTransform& worldTrans); - // these relay incoming values to the RigidBody - virtual void updateBodyEasy(uint32_t flags, uint32_t step); - virtual void updateBodyMaterialProperties(); - virtual void updateBodyVelocities(); - virtual void computeObjectShapeInfo(ShapeInfo& shapeInfo); virtual float computeObjectMass(const ShapeInfo& shapeInfo) const; @@ -76,7 +71,7 @@ public: virtual const glm::vec3& getObjectAngularVelocity() const { return _entity->getAngularVelocity(); } virtual const glm::vec3& getObjectGravity() const { return _entity->getGravity(); } - void clearOutgoingPacketFlags(uint32_t flags) { _outgoingPacketFlags &= ~flags; } + EntityItem* getEntityItem() const { return _entityItem; } protected: EntityItem* _entity; @@ -84,7 +79,6 @@ protected: bool _sentMoving; // true if last update was moving int _numNonMovingUpdates; // RELIABLE_SEND_HACK for "not so reliable" resends of packets for non-moving objects - uint32_t _outgoingPacketFlags; uint32_t _sentStep; glm::vec3 _sentPosition; // in simulation-frame (not world-frame) glm::quat _sentRotation;; diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index c0cba484c2..a49555a0d7 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -42,6 +42,18 @@ void ObjectMotionState::setWorldSimulationStep(uint32_t step) { _worldSimulationStep = step; } +// static +ShapeManager* _shapeManager = nullptr; +void ObjectMotionState::setShapeManager(ShapeManager* shapeManager) { + assert(shapeManager); + _shapeManager = shapeManager; +} + +ShapeManager* ObjectMotionState::getShapeManager() { + assert(_shapeManager); // you must properly set _shapeManager before calling getShapeManager() + return _shapeManager; +} + ObjectMotionState::ObjectMotionState(btCollisionShape* shape) : _motionType(MOTION_TYPE_STATIC), _shape(shape), @@ -57,6 +69,12 @@ ObjectMotionState::ObjectMotionState(btCollisionShape* shape) : ObjectMotionState::~ObjectMotionState() { // NOTE: you MUST remove this MotionState from the world before you call the dtor. assert(_body == nullptr); + if (_shape) { + // the ObjectMotionState owns a reference to its shape in the ShapeManager + // se we must release it + getShapeManager()->releaseShape(_shape); + _shape = nullptr; + } } void ObjectMotionState::measureBodyAcceleration() { @@ -80,7 +98,7 @@ void ObjectMotionState::resetMeasuredBodyAcceleration() { _lastVelocity = bulletToGLM(_body->getLinearVelocity()); } -void ObjectMotionState::setBodyVelocity(const glm::vec3& velocity) const { +void ObjectMotionState::setBodyLinearVelocity(const glm::vec3& velocity) const { _body->setLinearVelocity(glmToBullet(velocity)); } @@ -92,12 +110,12 @@ void ObjectMotionState::setBodyGravity(const glm::vec3& gravity) const { _body->setGravity(glmToBullet(gravity)); } -void ObjectMotionState::getVelocity(glm::vec3& velocityOut) const { - velocityOut = bulletToGLM(_body->getLinearVelocity()); +glm::vec3 ObjectMotionState::getBodyVelocity() const { + return bulletToGLM(_body->getLinearVelocity()); } -void ObjectMotionState::getAngularVelocity(glm::vec3& angularVelocityOut) const { - angularVelocityOut = bulletToGLM(_body->getAngularVelocity()); +glm::vec3 ObjectMotionState::getBodyAngularVelocity() const { + return bulletToGLM(_body->getAngularVelocity()); } void ObjectMotionState::setRigidBody(btRigidBody* body) { @@ -113,3 +131,91 @@ void ObjectMotionState::setRigidBody(btRigidBody* body) { } } +void ObjectMotionState::handleEasyChanges(uint32_t flags) { + if (flags & EntityItem::DIRTY_POSITION) { + btTransform worldTrans; + if (flags & EntityItem::DIRTY_ROTATION) { + worldTrans = getObjectTransform(); + } else { + worldTrans = _body->getWorldTransform(); + worldTrans.setOrigin(getObjectPosition()); + } + _body->setWorldTransform(worldTrans); + } else { + btTransform worldTrans = _body->getWorldTransform(); + worldTrans.setRotation(getObjectRotation()); + _body->setWorldTransform(worldTrans); + } + + if (flags & EntityItem::DIRTY_LINEAR_VELOCITY) { + _body->setLinearVelocity(glmToBullet(getObjectLinearVelocity())); + } + if (flags & EntityItem::DIRTY_ANGULAR_VELOCITY) { + _body->setAngularVelocity(glmToBullet(getObjectAngularVelocity())); + } + + if (flags & EntityItem::DIRTY_MATERIAL) { + updateBodyMaterialProperties(); + } + + if (flags & EntityItem::DIRTY_MASS) { + float mass = getMass(); + btVector3 inertia(0.0f, 0.0f, 0.0f); + _body->getCollisionShape()->calculateLocalInertia(mass, inertia); + _body->setMassProps(mass, inertia); + _body->updateInertiaTensor(); + } + + if (flags & EntityItem::DIRTY_ACTIVATION) { + _body->activate(); + } +} + +void ObjectMotionState::handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* engine) { + if (flags & EntityItem::DIRTY_SHAPE) { + // make sure the new shape is valid + ShapeInfo shapeInfo; + motionState->computeObjectShapeInfo(shapeInfo); + btCollisionShape* newShape = getShapeManager()->getShape(shapeInfo); + if (!newShape) { + // failed to generate new shape! + // remove shape-change flag + flags &= ~EntityItem::DIRTY_SHAPE; + // TODO: force this object out of PhysicsEngine rather than just use the old shape + if (flags & HARD_DIRTY_PHYSICS_FLAGS == 0) { + // no HARD flags remain, so do any EASY changes + if (flags & EASY_DIRTY_PHYSICS_FLAGS) { + handleEasyChanges(flags); + } + return; + } + } + engine->removeRigidBody(_body); + getShapeManager()->removeReference(_shape); + _shape = newShape; + _body->setShape(_shape); + if (flags & EASY_DIRTY_PHYSICS_FLAGS) { + handleEasyChanges(flags); + } + engine->addRigidBody(_body, motionType, mass); + } else { + engine->removeRigidBody(_body); + if (flags & EASY_DIRTY_PHYSICS_FLAGS) { + handleEasyChanges(flags); + } + engine->addRigidBody(_body, motionType, mass); + } +} + +void ObjectMotionState::updateBodyMaterialProperties() { + _body->setRestitution(getObjectRestitution()); + _body->setFriction(getObjectFriction()); + _body->setDamping(fabsf(btMin(getObjectLinearDamping(), 1.0f)), fabsf(btMin(getObjectAngularDamping(), 1.0f))); +} + +void ObjectMotionState::updateBodyVelocities() { + setBodyVelocity(getObjectLinearVelocity()); + setBodyAngularVelocity(getObjectAngularVelocity(); + setBodyGravity(getObjectGravity(); + _body->setActivationState(ACTIVE_TAG); +} diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index caa46de497..83046d9cca 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -51,16 +51,14 @@ extern const int MAX_NUM_NON_MOVING_UPDATES; 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. + // These poroperties of the PhysicsEngine are "global" within the context of all ObjectMotionStates + // (assuming just one PhysicsEngine). They are cached as statics for fast calculations in the + // ObjectMotionState context. static void setWorldOffset(const glm::vec3& offset); static const glm::vec3& getWorldOffset(); - - // The WorldSimulationStep is a cached copy of number of SubSteps of the simulation, used for local time measurements. static void setWorldSimulationStep(uint32_t step); + static void setShapeManager(ShapeManager* shapeManager); + static ShapeManager* getShapeManager(); ObjectMotionState(btCollisionShape* shape); ~ObjectMotionState(); @@ -68,11 +66,11 @@ public: void measureBodyAcceleration(); void resetMeasuredBodyAcceleration(); - // An EASY update does not require the object to be removed and then reinserted into the PhysicsEngine - virtual void updateBodyEasy(uint32_t flags, uint32_t frame) = 0; + void handleEasyChanges(); + void handleHardAndEasyChanges(); - virtual void updateBodyMaterialProperties() = 0; - virtual void updateBodyVelocities() = 0; + virtual void updateBodyMaterialProperties(); + virtual void updateBodyVelocities(); MotionStateType getType() const { return _type; } virtual MotionType getMotionType() const { return _motionType; } @@ -80,12 +78,12 @@ public: void setMass(float mass) { _mass = fabsf(mass); } float getMass() { return _mass; } - void setBodyVelocity(const glm::vec3& velocity) const; + void setBodyLinearVelocity(const glm::vec3& velocity) const; void setBodyAngularVelocity(const glm::vec3& velocity) const; void setBodyGravity(const glm::vec3& gravity) const; - void getVelocity(glm::vec3& velocityOut) const; - void getAngularVelocity(glm::vec3& angularVelocityOut) const; + glm::vec3 getBodyVelocity() const; + glm::vec3 getBodyAngularVelocity() const; virtual uint32_t getIncomingDirtyFlags() const = 0; virtual void clearIncomingDirtyFlags(uint32_t flags) = 0; @@ -97,8 +95,6 @@ public: virtual bool isMoving() const = 0; - friend class PhysicsEngine; - // These pure virtual methods must be implemented for each MotionState type // and make it possible to implement more complicated methods in this base class. @@ -113,16 +109,16 @@ public: virtual const glm::vec3& getObjectAngularVelocity() const = 0; virtual const glm::vec3& getObjectGravity() const = 0; + friend class PhysicsEngine; + protected: void setRigidBody(btRigidBody* body); MotionStateType _type = MOTION_STATE_TYPE_UNKNOWN; // type of MotionState - MotionType _motionType; // type of motion: KINEMATIC, DYNAMIC, or STATIC btCollisionShape* _shape; btRigidBody* _body; - float _mass; uint32_t _lastSimulationStep; diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index cd45025bc6..08d899bb6f 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -51,7 +51,7 @@ void PhysicalEntitySimulation::sendOutgoingPackets() { SetOfMotionStates::iterator stateItr = _outgoingChanges.begin(); while (stateItr != _outgoingChanges.end()) { - EntityMotionState* state = static_cast(*stateItr); + EntityMotionState* state = *stateItr; if (state->doesNotNeedToSendUpdate()) { stateItr = _outgoingChanges.erase(stateItr); } else if (state->shouldSendUpdate(numSubsteps)) { @@ -112,6 +112,7 @@ void PhysicalEntitySimulation::entityChangedInternal(EntityItem* entity) { } void PhysicalEntitySimulation::sortEntitiesThatMovedInternal() { + /* // entities that have been simulated forward (hence in the _entitiesToSort list) // also need to be put in the outgoingPackets list QSet::iterator entityItr = _entitiesToSort.begin(); @@ -122,6 +123,7 @@ void PhysicalEntitySimulation::sortEntitiesThatMovedInternal() { // BOOKMARK XXX -- Andrew to fix this next _outgoingChanges.insert(static_cast(physicsInfo)); } + */ } void PhysicalEntitySimulation::clearEntitiesInternal() { @@ -145,7 +147,7 @@ void PhysicalEntitySimulation::clearEntitiesInternal() { VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToRemove() { - _tempSet.clear(); + _tempVector.clear(); for (auto entityItr : _pendingRemoves) { EntityItem* entity = *entityItr; _physicalEntities.remove(entity); @@ -153,15 +155,15 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToRemove() { _pendingChanges.remove(entity); ObjectMotionState* motionState = static_cast(entity->getPhysicsInfo()); if (motionState) { - _tempSet.push_back(motionState); + _tempVector.push_back(motionState); } } _pendingRemoves.clear(); - return _tempSet; + return _tempVector; } VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToAdd() { - _tempSet.clear(); + _tempVector.clear(); SetOfEntities::iterator entityItr = _pendingAdds.begin(); while (entityItr != _pendingAdds.end()) { EntityItem* entity = *entityItr; @@ -182,34 +184,32 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToAdd() { ++entityItr; } } - _tempSet.push_back(motionState); + _tempVector.push_back(motionState); } - return _tempSet; + return _tempVector; } VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToChange() { - _tempSet.clear(); + _tempVector.clear(); for (auto entityItr : _pendingChanges) { EntityItem* entity = *entityItr; ObjectMotionState* motionState = static_cast(entity->getPhysicsInfo()); if (motionState) { - _tempSet.push_back(motionState); + _tempVector.push_back(motionState); } } _pendingChanges.clear(); - return _tempSet; + return _tempVector; } void PhysicalEntitySimulation::handleOutgoingChanges(VectorOfMotionStates& motionStates) { + // walk the motionStates looking for those that correspond to entities for (auto stateItr : motionStates) { ObjectMotionState* state = *stateItr; if (state->getType() == MOTION_STATE_TYPE_ENTITY) { EntityMotionState* entityState = static_cast(state); _outgoingChanges.insert(entityState); - // BOOKMARK TODO: - // * process _outgoingChanges. - // * move entityUpdate stuff out of EntityMotionState::setWorldTransform() and into new function. - // * lock entityTree in new function + _entitiesToSort.insert(entityState->getEntityItem()); } } sendOutgoingPackets(); @@ -218,123 +218,3 @@ void PhysicalEntitySimulation::handleOutgoingChanges(VectorOfMotionStates& motio void PhysicalEntitySimulation::bump(EntityItem* bumpEntity) { } -/* useful CRUFT -void PhysicalEntitySimulation::relayIncomingChangesToSimulation() { - BT_PROFILE("incomingChanges"); - // process incoming changes - SetOfMotionStates::iterator stateItr = _incomingChanges.begin(); - while (stateItr != _incomingChanges.end()) { - ObjectMotionState* motionState = *stateItr; - ++stateItr; - uint32_t flags = motionState->getIncomingDirtyFlags() & DIRTY_PHYSICS_FLAGS; - - bool removeMotionState = false; - 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 - // but it also handles all EASY changes - bool success = updateObjectHard(body, motionState, flags); - if (!success) { - // NOTE: since updateObjectHard() failed we know that motionState has been removed - // from simulation and body has been deleted. Depending on what else has changed - // we might need to remove motionState altogether... - if (flags & EntityItem::DIRTY_VELOCITY) { - motionState->updateKinematicState(_numSubsteps); - if (motionState->isKinematic()) { - // all is NOT lost, we still need to move this object around kinematically - _nonPhysicalKinematicEntities.insert(motionState); - } else { - // no need to keep motionState around - removeMotionState = true; - } - } else { - // no need to keep motionState around - removeMotionState = true; - } - } - } 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, _numSubsteps); - } - if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) { - motionState->resetMeasuredBodyAcceleration(); - } - } else { - // the only way we should ever get here (motionState exists but no body) is when the object - // is undergoing non-physical kinematic motion. - assert(_nonPhysicalKinematicEntities.contains(motionState)); - - // it is possible that the changes are such that the object can now be added to the physical simulation - if (flags & EntityItem::DIRTY_SHAPE) { - ShapeInfo shapeInfo; - motionState->computeObjectShapeInfo(shapeInfo); - btCollisionShape* shape = _shapeManager.getShape(shapeInfo); - if (shape) { - addObject(shapeInfo, shape, motionState); - _nonPhysicalKinematicEntities.remove(motionState); - } else if (flags & EntityItem::DIRTY_VELOCITY) { - // although we couldn't add the object to the simulation, might need to update kinematic motion... - motionState->updateKinematicState(_numSubsteps); - if (!motionState->isKinematic()) { - _nonPhysicalKinematicEntities.remove(motionState); - removeMotionState = true; - } - } - } else if (flags & EntityItem::DIRTY_VELOCITY) { - // although we still can't add to physics simulation, might need to update kinematic motion... - motionState->updateKinematicState(_numSubsteps); - if (!motionState->isKinematic()) { - _nonPhysicalKinematicEntities.remove(motionState); - removeMotionState = true; - } - } - } - if (removeMotionState) { - // if we get here then there is no need to keep this motionState around (no physics or kinematics) - _outgoingPackets.remove(motionState); - if (motionState->getType() == MOTION_STATE_TYPE_ENTITY) { - _physicalEntities.remove(static_cast(motionState)); - } - // NOTE: motionState will clean up its own backpointers in the Object - delete motionState; - continue; - } - - // NOTE: the grand order of operations is: - // (1) relay incoming changes - // (2) step simulation - // (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 - } - _incomingChanges.clear(); -} - -{ - // TODO: re-enable non-physical-kinematics - // step non-physical kinematic objects - SetOfMotionStates::iterator stateItr = _nonPhysicalKinematicEntities.begin(); - // TODO?: need to occasionally scan for stopped non-physical kinematics objects - while (stateItr != _nonPhysicalKinematicEntities.end()) { - ObjectMotionState* motionState = *stateItr; - motionState->stepKinematicSimulation(now); - ++stateItr; - } -} - -void PhysicalEntitySimulation::stepNonPhysicalKinematics(const quint64& now) { - SetOfMotionStates::iterator stateItr = _nonPhysicalKinematicEntities.begin(); - // TODO?: need to occasionally scan for stopped non-physical kinematics objects - while (stateItr != _nonPhysicalKinematicEntities.end()) { - ObjectMotionState* motionState = *stateItr; - motionState->stepKinematicSimulation(now); - ++stateItr; - } -} -*/ diff --git a/libraries/physics/src/PhysicalEntitySimulation.h b/libraries/physics/src/PhysicalEntitySimulation.h index e7f8cf7104..ece564639c 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.h +++ b/libraries/physics/src/PhysicalEntitySimulation.h @@ -55,10 +55,10 @@ private: SetOfEntities _pendingChanges; // entities already in simulation that need to be changed // outgoing changes - SetOfEntities _outgoingChanges; // entities for which we need to send updates to entity-server + QSet _outgoingChanges; // entities for which we need to send updates to entity-server SetOfMotionStates _physicalEntities; // MotionStates of entities in PhysicsEngine - VectorOfMotionStates _tempSet; // temporary list valid immediately after call to getObjectsToRemove/Add/Update() + VectorOfMotionStates _tempVector; // temporary list, valid by reference immediately after call to getObjectsToRemove/Add/Update() ShapeManager* _shapeManager = nullptr; PhysicsEngine* _physicsEngine = nullptr; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 4e4c4a89ce..e6a256ca1e 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -14,7 +14,6 @@ #include "ObjectMotionState.h" #include "PhysicsEngine.h" #include "PhysicsHelpers.h" -#include "ShapeInfoUtil.h" #include "ThreadSafeDynamicsWorld.h" #include "PhysicsLogging.h" @@ -81,75 +80,18 @@ void PhysicsEngine::removeObjects(VectorOfMotionStates& objects) { void PhysicsEngine::addObjects(VectorOfMotionStates& objects) { for (auto object : objects) { assert(object); - btCollisionShape* shape = object->getShape(); - assert(shape); - - btVector3 inertia(0.0f, 0.0f, 0.0f); - float mass = 0.0f; - btRigidBody* body = nullptr; - switch(object->computeObjectMotionType()) { - case MOTION_TYPE_KINEMATIC: { - body = new btRigidBody(mass, object, shape, inertia); - body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); - body->updateInertiaTensor(); - object->setRigidBody(body); - const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec - const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec - body->setSleepingThresholds(KINEMATIC_LINEAR_VELOCITY_THRESHOLD, KINEMATIC_ANGULAR_VELOCITY_THRESHOLD); - break; - } - case MOTION_TYPE_DYNAMIC: { - mass = object->getMass(); - shape->calculateLocalInertia(mass, inertia); - body = new btRigidBody(mass, object, shape, inertia); - body->updateInertiaTensor(); - object->setRigidBody(body); - object->updateBodyVelocities(); - // 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 - const float DYNAMIC_LINEAR_VELOCITY_THRESHOLD = 0.05f; // 5 cm/sec - const float DYNAMIC_ANGULAR_VELOCITY_THRESHOLD = 0.087266f; // ~5 deg/sec - body->setSleepingThresholds(DYNAMIC_LINEAR_VELOCITY_THRESHOLD, DYNAMIC_ANGULAR_VELOCITY_THRESHOLD); - if (!object->isMoving()) { - // try to initialize this object as inactive - body->forceActivationState(ISLAND_SLEEPING); - } - break; - } - case MOTION_TYPE_STATIC: - default: { - body = new btRigidBody(mass, object, shape, inertia); - body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT); - body->updateInertiaTensor(); - object->setRigidBody(body); - break; - } - } - body->setFlags(BT_DISABLE_WORLD_GRAVITY); - object->updateBodyMaterialProperties(); - - _dynamicsWorld->addRigidBody(body); - object->resetMeasuredBodyAcceleration(); + addObject(object); } } void PhysicsEngine::changeObjects(VectorOfMotionStates& objects) { for (auto object : objects) { uint32_t flags = object->getIncomingDirtyFlags() & DIRTY_PHYSICS_FLAGS; - - btRigidBody* body = object->getRigidBody(); 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 - updateBodyHard(body, object, flags); - } 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. - object->updateBodyEasy(flags, _numSubsteps); + object->handleHardAndEasyChanges(flags, this); + } else { + object->handleEasyChanges(flags); } - if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) { - object->resetMeasuredBodyAcceleration(); - } } } @@ -168,7 +110,6 @@ void PhysicsEngine::removeContacts(ObjectMotionState* motionState) { } void PhysicsEngine::stepSimulation() { - lock(); CProfileManager::Reset(); BT_PROFILE("stepSimulation"); // NOTE: the grand order of operations is: @@ -210,6 +151,7 @@ void PhysicsEngine::stepSimulation() { } void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB) { + BT_PROFILE("ownershipInfection"); assert(objectA); assert(objectB); @@ -315,6 +257,7 @@ void PhysicsEngine::computeCollisionEvents() { } VectorOfMotionStates& PhysicsEngine::getOutgoingChanges() { + BT_PROFILE("copyOutgoingChanges"); _dynamicsWorld.synchronizeMotionStates(); _hasOutgoingChanges = false; return _dynamicsWorld.getChangedMotionStates(); @@ -336,9 +279,10 @@ void PhysicsEngine::dumpStatsIfNecessary() { // CF_DISABLE_VISUALIZE_OBJECT = 32, //disable debug drawing // CF_DISABLE_SPU_COLLISION_PROCESSING = 64//disable parallel/SPU processing -void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shape, ObjectMotionState* motionState) { - assert(shape); +void PhysicsEngine::addObject(ObjectMotionState* motionState) { assert(motionState); + btCollisionShape* shape = motionState->getShape(); + assert(shape); btVector3 inertia(0.0f, 0.0f, 0.0f); float mass = 0.0f; @@ -349,13 +293,14 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); body->updateInertiaTensor(); motionState->setRigidBody(body); + motionState->updateBodyVelocities(); const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec body->setSleepingThresholds(KINEMATIC_LINEAR_VELOCITY_THRESHOLD, KINEMATIC_ANGULAR_VELOCITY_THRESHOLD); break; } case MOTION_TYPE_DYNAMIC: { - mass = motionState->computeObjectMass(shapeInfo); + mass = motionState->getMass(); shape->calculateLocalInertia(mass, inertia); body = new btRigidBody(mass, motionState, shape, inertia); body->updateInertiaTensor(); @@ -393,7 +338,6 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap void PhysicsEngine::bump(EntityItem* bumpEntity) { // If this node is doing something like deleting an entity, scan for contacts involving the // entity. For each found, flag the other entity involved as being simulated by this node. - lock(); int numManifolds = _collisionDispatcher->getNumManifolds(); for (int i = 0; i < numManifolds; ++i) { btPersistentManifold* contactManifold = _collisionDispatcher->getManifoldByIndexInternal(i); @@ -426,60 +370,15 @@ void PhysicsEngine::bump(EntityItem* bumpEntity) { } } } - unlock(); } -// private -bool PhysicsEngine::updateBodyHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags) { - // BOOKMARK TODO: move as much of this stuff into MotionState as possible. - MotionType newType = motionState->computeObjectMotionType(); - +void PhysicsEngine::removeRigidBody(btRigidBody* body) { // pull body out of physics engine _dynamicsWorld->removeRigidBody(body); +} - if (flags & EntityItem::DIRTY_SHAPE) { - // MASS bit should be set whenever SHAPE is set - assert(flags & EntityItem::DIRTY_MASS); - - // get new shape - btCollisionShape* oldShape = body->getCollisionShape(); - ShapeInfo shapeInfo; - motionState->computeObjectShapeInfo(shapeInfo); - btCollisionShape* newShape = _shapeManager.getShape(shapeInfo); - if (!newShape) { - // FAIL! we are unable to support these changes! - _shapeManager.releaseShape(oldShape); - - // NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it. - motionState->setRigidBody(nullptr); - delete body; - removeContacts(motionState); - return false; - } else if (newShape != oldShape) { - // BUG: if shape doesn't change but density does then we won't compute new mass properties - // TODO: fix this BUG by replacing DIRTY_MASS with DIRTY_DENSITY and then fix logic accordingly. - body->setCollisionShape(newShape); - _shapeManager.releaseShape(oldShape); - - // compute mass properties - float mass = motionState->computeObjectMass(shapeInfo); - btVector3 inertia(0.0f, 0.0f, 0.0f); - body->getCollisionShape()->calculateLocalInertia(mass, inertia); - body->setMassProps(mass, inertia); - body->updateInertiaTensor(); - } else { - // whoops, shape hasn't changed after all so we must release the reference - // that was created when looking it up - _shapeManager.releaseShape(newShape); - } - } - bool easyUpdate = flags & EASY_DIRTY_PHYSICS_FLAGS; - if (easyUpdate) { - motionState->updateBodyEasy(flags, _numSubsteps); - } - - // update the motion parameters - switch (newType) { +void PhysicsEngine::addRigidBody(btRigidBody* body, MotionType motionType, float mass) { + switch (motionType) { case MOTION_TYPE_KINEMATIC: { int collisionFlags = body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT; collisionFlags &= ~(btCollisionObject::CF_STATIC_OBJECT); @@ -495,9 +394,6 @@ bool PhysicsEngine::updateBodyHard(btRigidBody* body, ObjectMotionState* motionS body->setCollisionFlags(collisionFlags); if (! (flags & EntityItem::DIRTY_MASS)) { // always update mass properties when going dynamic (unless it's already been done above) - ShapeInfo shapeInfo; - motionState->computeObjectShapeInfo(shapeInfo); - float mass = motionState->computeObjectMass(shapeInfo); btVector3 inertia(0.0f, 0.0f, 0.0f); body->getCollisionShape()->calculateLocalInertia(mass, inertia); body->setMassProps(mass, inertia); @@ -522,16 +418,13 @@ bool PhysicsEngine::updateBodyHard(btRigidBody* body, ObjectMotionState* motionS } } - // reinsert body into physics engine _dynamicsWorld->addRigidBody(body); body->activate(); - return true; } void PhysicsEngine::setCharacterController(DynamicCharacterController* character) { if (_characterController != character) { - lock(); if (_characterController) { // remove the character from the DynamicsWorld immediately _characterController->setDynamicsWorld(nullptr); @@ -539,7 +432,6 @@ void PhysicsEngine::setCharacterController(DynamicCharacterController* character } // the character will be added to the DynamicsWorld later _characterController = character; - unlock(); } } diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index a6bacfa389..3b3467a2c9 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -82,9 +82,6 @@ private: void doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB); - // return 'true' of update was successful - bool updateBodyHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); - btClock _clock; btDefaultCollisionConfiguration* _collisionConfig = NULL; btCollisionDispatcher* _collisionDispatcher = NULL; From 9c5f51917a457b42d01ad5b6522cb15110d182a8 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 29 Apr 2015 16:26:46 -0700 Subject: [PATCH 08/89] declare EntitySimulation::getEntitiesToDelete() --- libraries/entities/src/EntitySimulation.cpp | 11 ++++++----- libraries/entities/src/EntitySimulation.h | 2 ++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index da08e5cd76..bd1dbcc63e 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -160,15 +160,15 @@ void EntitySimulation::removeEntity(EntityItem* entity) { _entitiesToUpdate.remove(entity); _mortalEntities.remove(entity); _entitiesToSort.remove(entity); - if (entity->_tree) { - // the tree still references this entity, but it's being removed from this simulation + if (entity->_element) { + // some EntityTreeElement still references this entity, but it's being removed from this simulation _entitiesToDelete.remove(entity); removeEntityInternal(entity); } else { // we're the last to reference this entity, so we really need to delete it deleteEntityInternal(entity); } - } else if (!entity->_tree) { + } else if (!entity->_element) { // nothing else is referencing this entity, so we delete it now delete entity; } @@ -182,8 +182,8 @@ void EntitySimulation::deleteEntity(EntityItem* entity) { _entitiesToSort.remove(entity); deleteEntityInternal(entity); } else { - if (entity->_tree) { - // the tree still references this entity, so we put it on the list + if (entity->_element) { + // some EntityTreeElement still references this entity, so we put it on the list // which will be harvested by the tree later _entitiesToDelete.insert(entity); } else { @@ -246,3 +246,4 @@ void EntitySimulation::clearEntities() { _entitiesToSort.clear(); clearEntitiesInternal(); } + diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index a145b3cc80..509c13a5a2 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -70,6 +70,8 @@ public: EntityTree* getEntityTree() { return _entityTree; } + void getEntitiesToDelete(SetOfEntities& entitiesToDelete); + signals: void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); From c3901939e61678d278f33bd02150e6f80e7633fd Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 30 Apr 2015 13:02:18 -0700 Subject: [PATCH 09/89] make some things compile after reorganization --- libraries/entities/src/EntityItem.h | 2 +- libraries/entities/src/EntitySimulation.cpp | 6 +- libraries/entities/src/EntitySimulation.h | 2 + .../entities/src/SimpleEntitySimulation.cpp | 6 +- libraries/physics/src/EntityMotionState.cpp | 65 +++++---- libraries/physics/src/EntityMotionState.h | 16 ++- libraries/physics/src/ObjectMotionState.cpp | 72 ++++------ libraries/physics/src/ObjectMotionState.h | 26 ++-- .../physics/src/PhysicalEntitySimulation.cpp | 92 +++++++------ .../physics/src/PhysicalEntitySimulation.h | 6 +- libraries/physics/src/PhysicsEngine.cpp | 127 ++++++++++-------- libraries/physics/src/PhysicsEngine.h | 8 +- .../physics/src/ThreadSafeDynamicsWorld.cpp | 5 +- .../physics/src/ThreadSafeDynamicsWorld.h | 4 +- 14 files changed, 232 insertions(+), 205 deletions(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index dd8b3abb37..e4c1652b3f 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -299,6 +299,7 @@ public: void* getPhysicsInfo() const { return _physicsInfo; } + void setPhysicsInfo(void* data) { _physicsInfo = data; } EntityTreeElement* getElement() const { return _element; } EntitySimulation* getSimulation() const { return _simulation; } @@ -311,7 +312,6 @@ public: glm::vec3 entityToWorld(const glm::vec3& point) const; protected: - void setPhysicsInfo(void* data) { _physicsInfo = data; } static bool _sendPhysicsUpdates; EntityTypes::EntityType _type; diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index bd1dbcc63e..1cf3ba42e6 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -56,7 +56,7 @@ void EntitySimulation::getEntitiesToDelete(SetOfEntities& entitiesToDelete) { } } -// private +// protected void EntitySimulation::expireMortalEntities(const quint64& now) { if (now > _nextExpiry) { // only search for expired entities if we expect to find one @@ -82,7 +82,7 @@ void EntitySimulation::expireMortalEntities(const quint64& now) { } } -// private +// protected void EntitySimulation::callUpdateOnEntitiesThatNeedIt(const quint64& now) { PerformanceTimer perfTimer("updatingEntities"); SetOfEntities::iterator itemItr = _entitiesToUpdate.begin(); @@ -99,7 +99,7 @@ void EntitySimulation::callUpdateOnEntitiesThatNeedIt(const quint64& now) { } } -// private +// protected void EntitySimulation::sortEntitiesThatMoved() { // NOTE: this is only for entities that have been moved by THIS EntitySimulation. // External changes to entity position/shape are expected to be sorted outside of the EntitySimulation. diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index 509c13a5a2..69bfe2622a 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -77,6 +77,8 @@ signals: protected: + void clearEntitySimulation(EntityItem* entity) { entity->_simulation = nullptr; } + // These pure virtual methods are protected because they are not to be called will-nilly. The base class // calls them in the right places. diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index 14e0374ea7..43d187796a 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -65,15 +65,15 @@ void SimpleEntitySimulation::removeEntityInternal(EntityItem* entity) { _movingEntities.remove(entity); _movableButStoppedEntities.remove(entity); _hasSimulationOwnerEntities.remove(entity); - entity->_simulation = nullptr; + clearEntitySimulation(entity); } void SimpleEntitySimulation::deleteEntityInternal(EntityItem* entity) { _movingEntities.remove(entity); _movableButStoppedEntities.remove(entity); _hasSimulationOwnerEntities.remove(entity); - entity->_simulation = nullptr; - if (!entity->_tree) { + clearEntitySimulation(entity); + if (!entity->getElement()) { // we held the last reference to this entity, so delete it delete entity; } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index fddb89c399..fd1a53a0ce 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -54,21 +54,6 @@ MotionType EntityMotionState::computeObjectMotionType() const { return _entity->isMoving() ? MOTION_TYPE_KINEMATIC : MOTION_TYPE_STATIC; } -void EntityMotionState::updateKinematicState(uint32_t substep) { - setKinematic(_entity->isMoving(), substep); -} - -void EntityMotionState::stepKinematicSimulation(quint64 now) { - assert(_isKinematic); - // NOTE: this is non-physical kinematic motion which steps to real run-time (now) - // which is different from physical kinematic motion (inside getWorldTransform()) - // which steps in physics simulation time. - _entity->simulate(now); - // TODO: we can't use measureBodyAcceleration() here because the entity - // has no RigidBody and the timestep is a little bit out of sync with the physics simulation anyway. - // Hence we must manually measure kinematic velocity and acceleration. -} - bool EntityMotionState::isMoving() const { return _entity->isMoving(); } @@ -79,18 +64,18 @@ bool EntityMotionState::isMoving() const { // (2) at the beginning of each simulation step for KINEMATIC RigidBody's -- // it is an opportunity for outside code to update the object's simulation position void EntityMotionState::getWorldTransform(btTransform& worldTrans) const { - if (_isKinematic) { + if (_motionType == MOTION_TYPE_KINEMATIC) { // This is physical kinematic motion which steps strictly by the subframe count // of the physics simulation. - uint32_t substep = PhysicsEngine::getNumSubsteps(); - float dt = (substep - _lastKinematicSubstep) * PHYSICS_ENGINE_FIXED_SUBSTEP; + uint32_t thisStep = ObjectMotionState::getWorldSimulationStep(); + float dt = (thisStep - _lastKinematicStep) * PHYSICS_ENGINE_FIXED_SUBSTEP; _entity->simulateKinematicMotion(dt); _entity->setLastSimulated(usecTimestampNow()); - // bypass const-ness so we can remember the substep - const_cast(this)->_lastKinematicSubstep = substep; + // bypass const-ness so we can remember the step + const_cast(this)->_lastKinematicStep = thisStep; } - worldTrans.setOrigin(glmToBullet(_entity->getPosition() - ObjectMotionState::getWorldOffset())); + worldTrans.setOrigin(glmToBullet(getObjectPosition())); worldTrans.setRotation(glmToBullet(_entity->getRotation())); } @@ -101,13 +86,8 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { _entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset()); _entity->setRotation(bulletToGLM(worldTrans.getRotation())); - glm::vec3 v; - getVelocity(v); - _entity->setVelocity(v); - - glm::vec3 av; - getAngularVelocity(av); - _entity->setAngularVelocity(av); + _entity->setVelocity(getBodyLinearVelocity()); + _entity->setAngularVelocity(getBodyAngularVelocity()); _entity->setLastSimulated(usecTimestampNow()); @@ -405,3 +385,32 @@ uint32_t EntityMotionState::getIncomingDirtyFlags() const { return dirtyFlags; */ } + +void EntityMotionState::resetMeasuredBodyAcceleration() { + _lastMeasureStep = ObjectMotionState::getWorldSimulationStep(); + _lastVelocity = bulletToGLM(_body->getLinearVelocity()); + _measuredAcceleration = glm::vec3(0.0f); +} + +void EntityMotionState::measureBodyAcceleration() { + // try to manually measure the true acceleration of the object + uint32_t thisStep = ObjectMotionState::getWorldSimulationStep(); + uint32_t numSubsteps = thisStep - _lastMeasureStep; + if (numSubsteps > 0) { + float dt = ((float)numSubsteps * PHYSICS_ENGINE_FIXED_SUBSTEP); + float invDt = 1.0f / dt; + _lastMeasureStep = thisStep; + + // Note: the integration equation for velocity uses damping: v1 = (v0 + a * dt) * (1 - D)^dt + // hence the equation for acceleration is: a = (v1 / (1 - D)^dt - v0) / dt + glm::vec3 velocity = bulletToGLM(_body->getLinearVelocity()); + _measuredAcceleration = (velocity / powf(1.0f - _body->getLinearDamping(), dt) - _lastVelocity) * invDt; + _lastVelocity = velocity; + } +} + +// virtual +void EntityMotionState::setMotionType(MotionType motionType) { + ObjectMotionState::setMotionType(motionType); + resetMeasuredBodyAcceleration(); +} diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 9e8cf16c4f..db3ced229b 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -31,9 +31,6 @@ public: /// \return MOTION_TYPE_DYNAMIC or MOTION_TYPE_STATIC based on params set in EntityItem virtual MotionType computeObjectMotionType() const; - virtual void updateKinematicState(uint32_t substep); - virtual void stepKinematicSimulation(quint64 now); - virtual bool isMoving() const; // this relays incoming position/rotation to the RigidBody @@ -65,15 +62,20 @@ public: virtual float getObjectLinearDamping() const { return _entity->getDamping(); } virtual float getObjectAngularDamping() const { return _entity->getAngularDamping(); } - virtual const glm::vec3& getObjectPosition() const { return _entity->getPosition(); } + virtual glm::vec3 getObjectPosition() const { return _entity->getPosition() - ObjectMotionState::getWorldOffset(); } virtual const glm::quat& getObjectRotation() const { return _entity->getRotation(); } virtual const glm::vec3& getObjectLinearVelocity() const { return _entity->getVelocity(); } virtual const glm::vec3& getObjectAngularVelocity() const { return _entity->getAngularVelocity(); } virtual const glm::vec3& getObjectGravity() const { return _entity->getGravity(); } - EntityItem* getEntityItem() const { return _entityItem; } + EntityItem* getEntity() const { return _entity; } + + void resetMeasuredBodyAcceleration(); + void measureBodyAcceleration(); protected: + virtual void setMotionType(MotionType motionType); + EntityItem* _entity; bool _sentMoving; // true if last update was moving @@ -87,6 +89,10 @@ protected: glm::vec3 _sentGravity; glm::vec3 _sentAcceleration; + uint32_t _lastMeasureStep; + glm::vec3 _lastVelocity; + glm::vec3 _measuredAcceleration; + quint8 _accelerationNearlyGravityCount; bool _shouldClaimSimulationOwnership; quint32 _movingStepsWithoutSimulationOwner; diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index a49555a0d7..e5bb80512c 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -36,22 +36,26 @@ const glm::vec3& ObjectMotionState::getWorldOffset() { } // static -uint32_t _worldSimulationStep = 0; +uint32_t worldSimulationStep = 0; void ObjectMotionState::setWorldSimulationStep(uint32_t step) { - assert(step > _worldSimulationStep); - _worldSimulationStep = step; + assert(step > worldSimulationStep); + worldSimulationStep = step; +} + +uint32_t ObjectMotionState::getWorldSimulationStep() { + return worldSimulationStep; } // static -ShapeManager* _shapeManager = nullptr; -void ObjectMotionState::setShapeManager(ShapeManager* shapeManager) { - assert(shapeManager); - _shapeManager = shapeManager; +ShapeManager* shapeManager = nullptr; +void ObjectMotionState::setShapeManager(ShapeManager* manager) { + assert(manager); + shapeManager = manager; } ShapeManager* ObjectMotionState::getShapeManager() { - assert(_shapeManager); // you must properly set _shapeManager before calling getShapeManager() - return _shapeManager; + assert(shapeManager); // you must properly set shapeManager before calling getShapeManager() + return shapeManager; } ObjectMotionState::ObjectMotionState(btCollisionShape* shape) : @@ -59,43 +63,8 @@ ObjectMotionState::ObjectMotionState(btCollisionShape* shape) : _shape(shape), _body(nullptr), _mass(0.0f), - _lastSimulationStep(0), - _lastVelocity(0.0f), - _measuredAcceleration(0.0f) + _lastKinematicStep(worldSimulationStep) { - assert(_shape); -} - -ObjectMotionState::~ObjectMotionState() { - // NOTE: you MUST remove this MotionState from the world before you call the dtor. - assert(_body == nullptr); - if (_shape) { - // the ObjectMotionState owns a reference to its shape in the ShapeManager - // se we must release it - getShapeManager()->releaseShape(_shape); - _shape = nullptr; - } -} - -void ObjectMotionState::measureBodyAcceleration() { - // try to manually measure the true acceleration of the object - uint32_t numSubsteps = _worldSimulationStep - _lastSimulationStep; - if (numSubsteps > 0) { - float dt = ((float)numSubsteps * PHYSICS_ENGINE_FIXED_SUBSTEP); - float invDt = 1.0f / dt; - _lastSimulationStep = _worldSimulationStep; - - // Note: the integration equation for velocity uses damping: v1 = (v0 + a * dt) * (1 - D)^dt - // hence the equation for acceleration is: a = (v1 / (1 - D)^dt - v0) / dt - glm::vec3 velocity = bulletToGLM(_body->getLinearVelocity()); - _measuredAcceleration = (velocity / powf(1.0f - _body->getLinearDamping(), dt) - _lastVelocity) * invDt; - _lastVelocity = velocity; - } -} - -void ObjectMotionState::resetMeasuredBodyAcceleration() { - _lastSimulationStep = _worldSimulationStep; - _lastVelocity = bulletToGLM(_body->getLinearVelocity()); } void ObjectMotionState::setBodyLinearVelocity(const glm::vec3& velocity) const { @@ -110,7 +79,7 @@ void ObjectMotionState::setBodyGravity(const glm::vec3& gravity) const { _body->setGravity(glmToBullet(gravity)); } -glm::vec3 ObjectMotionState::getBodyVelocity() const { +glm::vec3 ObjectMotionState::getBodyLinearVelocity() const { return bulletToGLM(_body->getLinearVelocity()); } @@ -118,6 +87,17 @@ glm::vec3 ObjectMotionState::getBodyAngularVelocity() const { return bulletToGLM(_body->getAngularVelocity()); } +void ObjectMotionState::releaseShape() { + if (_shape) { + shapeManager->releaseShape(_shape); + _shape = nullptr; + } +} + +void ObjectMotionState::setMotionType(MotionType motionType) { + _motionType = motionType; +} + 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 83046d9cca..a96bf1de13 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -18,7 +18,7 @@ #include #include "ContactInfo.h" -#include "ShapeInfo.h" +#include "ShapeManager.h" enum MotionType { MOTION_TYPE_STATIC, // no motion @@ -46,6 +46,7 @@ const uint32_t OUTGOING_DIRTY_PHYSICS_FLAGS = EntityItem::DIRTY_POSITION | Entit class OctreeEditPacketSender; +class PhysicsEngine; extern const int MAX_NUM_NON_MOVING_UPDATES; @@ -56,18 +57,18 @@ public: // ObjectMotionState context. static void setWorldOffset(const glm::vec3& offset); static const glm::vec3& getWorldOffset(); + static void setWorldSimulationStep(uint32_t step); - static void setShapeManager(ShapeManager* shapeManager); + static uint32_t getWorldSimulationStep(); + + static void setShapeManager(ShapeManager* manager); static ShapeManager* getShapeManager(); ObjectMotionState(btCollisionShape* shape); ~ObjectMotionState(); - void measureBodyAcceleration(); - void resetMeasuredBodyAcceleration(); - - void handleEasyChanges(); - void handleHardAndEasyChanges(); + void handleEasyChanges(uint32_t flags); + void handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* engine); virtual void updateBodyMaterialProperties(); virtual void updateBodyVelocities(); @@ -82,7 +83,7 @@ public: void setBodyAngularVelocity(const glm::vec3& velocity) const; void setBodyGravity(const glm::vec3& gravity) const; - glm::vec3 getBodyVelocity() const; + glm::vec3 getBodyLinearVelocity() const; glm::vec3 getBodyAngularVelocity() const; virtual uint32_t getIncomingDirtyFlags() const = 0; @@ -93,6 +94,8 @@ public: btCollisionShape* getShape() const { return _shape; } btRigidBody* getRigidBody() const { return _body; } + void releaseShape(); + virtual bool isMoving() const = 0; // These pure virtual methods must be implemented for each MotionState type @@ -103,7 +106,7 @@ public: virtual float getObjectLinearDamping() const = 0; virtual float getObjectAngularDamping() const = 0; - virtual const glm::vec3& getObjectPosition() const = 0; + virtual glm::vec3 getObjectPosition() const = 0; virtual const glm::quat& getObjectRotation() const = 0; virtual const glm::vec3& getObjectLinearVelocity() const = 0; virtual const glm::vec3& getObjectAngularVelocity() const = 0; @@ -112,6 +115,7 @@ public: friend class PhysicsEngine; protected: + virtual void setMotionType(MotionType motionType); void setRigidBody(btRigidBody* body); MotionStateType _type = MOTION_STATE_TYPE_UNKNOWN; // type of MotionState @@ -121,9 +125,7 @@ protected: btRigidBody* _body; float _mass; - uint32_t _lastSimulationStep; - glm::vec3 _lastVelocity; - glm::vec3 _measuredAcceleration; + uint32_t _lastKinematicStep; }; #endif // hifi_ObjectMotionState_h diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index 08d899bb6f..9e6716cd38 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -9,13 +9,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "EntityMotionState.h" #include "PhysicalEntitySimulation.h" #include "PhysicsEngine.h" #include "PhysicsHelpers.h" #include "PhysicsLogging.h" #include "ShapeInfoUtil.h" +#include "ShapeManager.h" -PhysicalEntitySimulation::PhysicalEntitySimulation() : +PhysicalEntitySimulation::PhysicalEntitySimulation() { } PhysicalEntitySimulation::~PhysicalEntitySimulation() { @@ -29,10 +31,10 @@ void PhysicalEntitySimulation::init( assert(tree); setEntityTree(tree); - assert(*physicsEngine); + assert(physicsEngine); _physicsEngine = physicsEngine; - assert(*shapeManager); + assert(shapeManager); _shapeManager = shapeManager; assert(packetSender); @@ -44,26 +46,6 @@ void PhysicalEntitySimulation::updateEntitiesInternal(const quint64& now) { // TODO: add back non-physical kinematic objects and step them forward here } -void PhysicalEntitySimulation::sendOutgoingPackets() { - uint32_t numSubsteps = _physicsEngine->getNumSubsteps(); - if (_lastNumSubstepsAtUpdateInternal != numSubsteps) { - _lastNumSubstepsAtUpdateInternal = numSubsteps; - - SetOfMotionStates::iterator stateItr = _outgoingChanges.begin(); - while (stateItr != _outgoingChanges.end()) { - EntityMotionState* state = *stateItr; - if (state->doesNotNeedToSendUpdate()) { - stateItr = _outgoingChanges.erase(stateItr); - } else if (state->shouldSendUpdate(numSubsteps)) { - state->sendUpdate(_entityPacketSender, numSubsteps); - ++stateItr; - } else { - ++stateItr; - } - } - } -} - void PhysicalEntitySimulation::addEntityInternal(EntityItem* entity) { assert(entity); void* physicsInfo = entity->getPhysicsInfo(); @@ -76,10 +58,9 @@ void PhysicalEntitySimulation::removeEntityInternal(EntityItem* entity) { assert(entity); void* physicsInfo = entity->getPhysicsInfo(); if (physicsInfo) { - ObjectMotionState* motionState = static_cast(physicsInfo); - _pendingRemoves.insert(motionState); + _pendingRemoves.insert(entity); } else { - entity->_simulation = nullptr; + clearEntitySimulation(entity); } } @@ -87,10 +68,9 @@ void PhysicalEntitySimulation::deleteEntityInternal(EntityItem* entity) { assert(entity); void* physicsInfo = entity->getPhysicsInfo(); if (physicsInfo) { - ObjectMotionState* motionState = static_cast(physicsInfo); - _pendingRemoves.insert(motionState); + _pendingRemoves.insert(entity); } else { - entity->_simulation = nullptr; + clearEntitySimulation(entity); delete entity; } } @@ -100,10 +80,9 @@ void PhysicalEntitySimulation::entityChangedInternal(EntityItem* entity) { assert(entity); void* physicsInfo = entity->getPhysicsInfo(); if (physicsInfo) { - ObjectMotionState* motionState = static_cast(physicsInfo); - _pendingChanges.insert(motionState); + _pendingChanges.insert(entity); } else { - if (!entity->ignoreForCollisions()) { + if (!entity->getIgnoreForCollisions()) { // The intent is for this object to be in the PhysicsEngine. // Perhaps it's shape has changed and it can now be added? _pendingAdds.insert(entity); @@ -130,14 +109,16 @@ void PhysicalEntitySimulation::clearEntitiesInternal() { // TODO: we should probably wait to lock the _physicsEngine so we don't mess up data structures // while it is in the middle of a simulation step. As it is, we're probably in shutdown mode // anyway, so maybe the simulation was already properly shutdown? Cross our fingers... - SetOfMotionStates::const_iterator stateItr = _physicalEntities.begin(); + + _physicsEngine->deleteObjects(_physicalEntities); + for (auto stateItr : _physicalEntities) { - EntityMotionState motionState = static_cast(*stateItr); - _physicsEngine->removeObjectFromBullet(motionState); - EntityItem* entity = motionState->_entity; - _entity->setPhysicsInfo(nullptr); + EntityMotionState* motionState = static_cast(&(*stateItr)); + EntityItem* entity = motionState->getEntity(); + entity->setPhysicsInfo(nullptr); delete motionState; } + _physicalEntities.clear(); _pendingRemoves.clear(); _pendingAdds.clear(); @@ -149,13 +130,13 @@ void PhysicalEntitySimulation::clearEntitiesInternal() { VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToRemove() { _tempVector.clear(); for (auto entityItr : _pendingRemoves) { - EntityItem* entity = *entityItr; - _physicalEntities.remove(entity); + EntityItem* entity = &(*entityItr); _pendingAdds.remove(entity); _pendingChanges.remove(entity); - ObjectMotionState* motionState = static_cast(entity->getPhysicsInfo()); + EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); if (motionState) { _tempVector.push_back(motionState); + _physicalEntities.remove(motionState); } } _pendingRemoves.clear(); @@ -176,15 +157,14 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToAdd() { if (shape) { EntityMotionState* motionState = new EntityMotionState(shape, entity); entity->setPhysicsInfo(static_cast(motionState)); + motionState->setMass(entity->computeMass()); _physicalEntities.insert(motionState); + _tempVector.push_back(motionState); entityItr = _pendingAdds.erase(entityItr); - // TODO: figure out how to get shapeInfo (or relevant info) to PhysicsEngine during add - //_physicsEngine->addObject(shapeInfo, motionState); } else { ++entityItr; } } - _tempVector.push_back(motionState); } return _tempVector; } @@ -192,7 +172,7 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToAdd() { VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToChange() { _tempVector.clear(); for (auto entityItr : _pendingChanges) { - EntityItem* entity = *entityItr; + EntityItem* entity = &(*entityItr); ObjectMotionState* motionState = static_cast(entity->getPhysicsInfo()); if (motionState) { _tempVector.push_back(motionState); @@ -205,14 +185,32 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToChange() { void PhysicalEntitySimulation::handleOutgoingChanges(VectorOfMotionStates& motionStates) { // walk the motionStates looking for those that correspond to entities for (auto stateItr : motionStates) { - ObjectMotionState* state = *stateItr; + ObjectMotionState* state = &(*stateItr); if (state->getType() == MOTION_STATE_TYPE_ENTITY) { EntityMotionState* entityState = static_cast(state); _outgoingChanges.insert(entityState); - _entitiesToSort.insert(entityState->getEntityItem()); + _entitiesToSort.insert(entityState->getEntity()); + } + } + + // send outgoing packets + uint32_t numSubsteps = _physicsEngine->getNumSubsteps(); + if (_lastStepSendPackets != numSubsteps) { + _lastStepSendPackets = numSubsteps; + + QSet::iterator stateItr = _outgoingChanges.begin(); + while (stateItr != _outgoingChanges.end()) { + EntityMotionState* state = *stateItr; + if (state->doesNotNeedToSendUpdate()) { + stateItr = _outgoingChanges.erase(stateItr); + } else if (state->shouldSendUpdate(numSubsteps)) { + state->sendUpdate(_entityPacketSender, numSubsteps); + ++stateItr; + } else { + ++stateItr; + } } } - sendOutgoingPackets(); } void PhysicalEntitySimulation::bump(EntityItem* bumpEntity) { diff --git a/libraries/physics/src/PhysicalEntitySimulation.h b/libraries/physics/src/PhysicalEntitySimulation.h index ece564639c..2d49aa5d8a 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.h +++ b/libraries/physics/src/PhysicalEntitySimulation.h @@ -22,14 +22,16 @@ #include "PhysicsTypedefs.h" +class EntityMotionState; class PhysicsEngine; +class ShapeManager; class PhysicalEntitySimulation :public EntitySimulation { public: PhysicalEntitySimulation(); ~PhysicalEntitySimulation(); - void init(EntityTree* tree, PhysicsEngine* engine, EntityEditPacketSender* packetSender); + void init(EntityTree* tree, PhysicsEngine* engine, ShapeManager* shapeManager, EntityEditPacketSender* packetSender); // overrides for EntitySimulation void updateEntitiesInternal(const quint64& now); @@ -64,7 +66,7 @@ private: PhysicsEngine* _physicsEngine = nullptr; EntityEditPacketSender* _entityPacketSender = nullptr; - uint32_t _lastNumSubstepsAtUpdateInternal = 0; + uint32_t _lastStepSendPackets = 0; }; #endif // hifi_PhysicalEntitySimulation_h diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index e6a256ca1e..af4ec42df8 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -68,11 +68,26 @@ void PhysicsEngine::removeObjects(VectorOfMotionStates& objects) { btRigidBody* body = object->getRigidBody(); _dynamicsWorld->removeRigidBody(body); + removeContacts(object); // NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it. object->setRigidBody(nullptr); delete body; + object->releaseShape(); + } +} + +void PhysicsEngine::deleteObjects(SetOfMotionStates& objects) { + for (auto object : objects) { + assert(object); + + btRigidBody* body = object->getRigidBody(); + _dynamicsWorld->removeRigidBody(body); removeContacts(object); + + // NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it. + object->setRigidBody(nullptr); + delete body; object->releaseShape(); } } @@ -151,6 +166,7 @@ void PhysicsEngine::stepSimulation() { } void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB) { + /* TODO: Andrew to make this work for ObjectMotionState BT_PROFILE("ownershipInfection"); assert(objectA); assert(objectB); @@ -184,6 +200,7 @@ void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const a->setShouldClaimSimulationOwnership(true); } } + */ } void PhysicsEngine::computeCollisionEvents() { @@ -215,7 +232,13 @@ void PhysicsEngine::computeCollisionEvents() { doOwnershipInfection(objectA, objectB); } } - + + fireCollisionEvents(); + ++_numContactFrames; +} + +void PhysicsEngine::fireCollisionEvents() { + /* TODO: Andrew to make this work for ObjectMotionStates const uint32_t CONTINUE_EVENT_FILTER_FREQUENCY = 10; // scan known contacts and trigger events @@ -253,14 +276,14 @@ void PhysicsEngine::computeCollisionEvents() { ++contactItr; } } - ++_numContactFrames; + */ } VectorOfMotionStates& PhysicsEngine::getOutgoingChanges() { BT_PROFILE("copyOutgoingChanges"); - _dynamicsWorld.synchronizeMotionStates(); + _dynamicsWorld->synchronizeMotionStates(); _hasOutgoingChanges = false; - return _dynamicsWorld.getChangedMotionStates(); + return _dynamicsWorld->getChangedMotionStates(); } void PhysicsEngine::dumpStatsIfNecessary() { @@ -287,7 +310,9 @@ void PhysicsEngine::addObject(ObjectMotionState* motionState) { btVector3 inertia(0.0f, 0.0f, 0.0f); float mass = 0.0f; btRigidBody* body = nullptr; - switch(motionState->computeObjectMotionType()) { + MotionType motionType = motionState->computeObjectMotionType(); + motionState->setMotionType(motionType); + switch(motionType) { case MOTION_TYPE_KINEMATIC: { body = new btRigidBody(mass, motionState, shape, inertia); body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); @@ -330,11 +355,50 @@ void PhysicsEngine::addObject(ObjectMotionState* motionState) { motionState->updateBodyMaterialProperties(); _dynamicsWorld->addRigidBody(body); - motionState->resetMeasuredBodyAcceleration(); } -/* TODO: convert bump() to take an ObjectMotionState. -* Expose SimulationID to ObjectMotionState*/ +void PhysicsEngine::bump(ObjectMotionState* object) { + /* TODO: Andrew to implement this + // If this node is doing something like deleting an entity, scan for contacts involving the + // entity. For each found, flag the other entity involved as being simulated by this node. + 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()); + if (objectA && objectB) { + void* a = objectA->getUserPointer(); + void* b = objectB->getUserPointer(); + if (a && b) { + EntityMotionState* entityMotionStateA = static_cast(a); + EntityMotionState* entityMotionStateB = static_cast(b); + EntityItem* entityA = entityMotionStateA ? entityMotionStateA->getEntity() : nullptr; + EntityItem* entityB = entityMotionStateB ? entityMotionStateB->getEntity() : nullptr; + if (entityA && entityB) { + if (entityA == bumpEntity) { + entityMotionStateB->setShouldClaimSimulationOwnership(true); + if (!objectB->isActive()) { + objectB->setActivationState(ACTIVE_TAG); + } + } + if (entityB == bumpEntity) { + entityMotionStateA->setShouldClaimSimulationOwnership(true); + if (!objectA->isActive()) { + objectA->setActivationState(ACTIVE_TAG); + } + } + } + } + } + } + } + */ +} + +/* +// TODO: convert bump() to take an ObjectMotionState. +// Expose SimulationID to ObjectMotionState void PhysicsEngine::bump(EntityItem* bumpEntity) { // If this node is doing something like deleting an entity, scan for contacts involving the // entity. For each found, flag the other entity involved as being simulated by this node. @@ -371,58 +435,13 @@ void PhysicsEngine::bump(EntityItem* bumpEntity) { } } } +*/ void PhysicsEngine::removeRigidBody(btRigidBody* body) { // pull body out of physics engine _dynamicsWorld->removeRigidBody(body); } -void PhysicsEngine::addRigidBody(btRigidBody* body, MotionType motionType, float mass) { - switch (motionType) { - 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 & EntityItem::DIRTY_MASS)) { - // always update mass properties when going dynamic (unless it's already been done above) - btVector3 inertia(0.0f, 0.0f, 0.0f); - body->getCollisionShape()->calculateLocalInertia(mass, inertia); - body->setMassProps(mass, inertia); - body->updateInertiaTensor(); - } - body->forceActivationState(ACTIVE_TAG); - 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); - - 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; - } - } - - _dynamicsWorld->addRigidBody(body); - - body->activate(); -} - void PhysicsEngine::setCharacterController(DynamicCharacterController* character) { if (_characterController != character) { if (_characterController) { diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 3b3467a2c9..4625df605e 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -53,11 +53,13 @@ public: /// process queue of changed from external sources void removeObjects(VectorOfMotionStates& objects); + void deleteObjects(SetOfMotionStates& objects); void addObjects(VectorOfMotionStates& objects); void changeObjects(VectorOfMotionStates& objects); void stepSimulation(); void computeCollisionEvents(); + void fireCollisionEvents(); bool hasOutgoingChanges() const { return _hasOutgoingChanges; } VectorOfMotionStates& getOutgoingChanges(); @@ -71,7 +73,11 @@ public: /// \param motionState pointer to Object's MotionState /// \return true if Object added - void addObject(const ShapeInfo& shapeInfo, btCollisionShape* shape, ObjectMotionState* motionState); + void addObject(ObjectMotionState* motionState); + + void bump(ObjectMotionState* motionState); + + void removeRigidBody(btRigidBody* body); void setCharacterController(DynamicCharacterController* character); diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp index 4ea4f2e170..7774f277b6 100644 --- a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp @@ -17,6 +17,7 @@ #include +#include "ObjectMotionState.h" #include "ThreadSafeDynamicsWorld.h" ThreadSafeDynamicsWorld::ThreadSafeDynamicsWorld( @@ -95,7 +96,7 @@ void ThreadSafeDynamicsWorld::synchronizeMotionStates() { btRigidBody* body = btRigidBody::upcast(colObj); if (body) { synchronizeSingleMotionState(body); - _changedMotionStates.push_back(body->getMotionState()); + _changedMotionStates.push_back(static_cast(body->getMotionState())); } } } else { @@ -104,7 +105,7 @@ void ThreadSafeDynamicsWorld::synchronizeMotionStates() { btRigidBody* body = m_nonStaticRigidBodies[i]; if (body->isActive()) { synchronizeSingleMotionState(body); - _changedMotionStates.push_back(body->getMotionState()); + _changedMotionStates.push_back(static_cast(body->getMotionState())); } } } diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.h b/libraries/physics/src/ThreadSafeDynamicsWorld.h index 6f8ddaa4b8..4a96eae311 100644 --- a/libraries/physics/src/ThreadSafeDynamicsWorld.h +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.h @@ -18,6 +18,7 @@ #ifndef hifi_ThreadSafeDynamicsWorld_h #define hifi_ThreadSafeDynamicsWorld_h +#include #include #include "PhysicsTypedefs.h" @@ -34,13 +35,14 @@ public: // virtual overrides from btDiscreteDynamicsWorld 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; } - VectorOfMotionStates& getChangedMotionStates() const { return _changedMotionStates; } + VectorOfMotionStates& getChangedMotionStates() { return _changedMotionStates; } private: VectorOfMotionStates _changedMotionStates; From 195dd1420c178d53db7dae4e9c7bece375cccebd Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 30 Apr 2015 13:17:13 -0700 Subject: [PATCH 10/89] DIRTY_PHYSICS_ACTIVATION not DIRTY_PHYSICS_NO_WAKE also add separate flag for rotation and separate flags for linear vs angular velocity and some combined flag masks for convenience --- libraries/entities/src/EntityItem.cpp | 21 ++++++++++++-------- libraries/entities/src/EntityItem.h | 22 ++++++++++++--------- libraries/physics/src/ObjectMotionState.cpp | 2 +- 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index ad04752132..29b7fc6a85 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -579,7 +579,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY_STRING(PROP_MARKETPLACE_ID, setMarketplaceID); } - if (overwriteLocalData && (getDirtyFlags() & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY))) { + if (overwriteLocalData && (getDirtyFlags() & (EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES))) { // NOTE: This code is attempting to "repair" the old data we just got from the server to make it more // closely match where the entities should be if they'd stepped forward in time to "now". The server // is sending us data with a known "last simulated" time. That time is likely in the past, and therefore @@ -940,7 +940,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { if (_created != UNKNOWN_CREATED_TIME) { setLastEdited(now); } - if (getDirtyFlags() & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) { + if (getDirtyFlags() & (EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES)) { // TODO: Andrew & Brad to discuss. Is this correct? Maybe it is. Need to think through all cases. _lastSimulated = now; } @@ -1107,7 +1107,10 @@ void EntityItem::updatePositionInDomainUnits(const glm::vec3& value) { void EntityItem::updatePosition(const glm::vec3& value) { if (value != _position) { auto distance = glm::distance(_position, value); - _dirtyFlags |= (distance > MIN_POSITION_DELTA) ? EntityItem::DIRTY_POSITION : EntityItem::DIRTY_PHYSICS_NO_WAKE; + _dirtyFlags |= EntityItem::DIRTY_POSITION; + if (distance > MIN_POSITION_DELTA) { + dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; + } _position = value; } } @@ -1127,7 +1130,10 @@ void EntityItem::updateDimensions(const glm::vec3& value) { void EntityItem::updateRotation(const glm::quat& rotation) { if (rotation != _rotation) { auto alignmentDot = glm::abs(glm::dot(_rotation, rotation)); - _dirtyFlags |= (alignmentDot < MIN_ALIGNMENT_DOT) ? EntityItem::DIRTY_POSITION : EntityItem::DIRTY_PHYSICS_NO_WAKE; + _dirtyFlags |= EntityItem::DIRTY_ROTATION; + if (alignmentDot < MIN_ALIGNMENT_DOT) { + dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; + } _rotation = rotation; } } @@ -1168,7 +1174,7 @@ void EntityItem::updateVelocity(const glm::vec3& value) { } else { _velocity = value; } - _dirtyFlags |= EntityItem::DIRTY_VELOCITY; + _dirtyFlags |= EntityItem::DIRTY_LINEAR_VELOCITY; } } @@ -1187,21 +1193,20 @@ void EntityItem::updateGravityInDomainUnits(const glm::vec3& value) { void EntityItem::updateGravity(const glm::vec3& value) { if (glm::distance(_gravity, value) > MIN_GRAVITY_DELTA) { _gravity = value; - _dirtyFlags |= EntityItem::DIRTY_VELOCITY; + _dirtyFlags |= EntityItem::DIRTY_LINEAR_VELOCITY; } } void EntityItem::updateAcceleration(const glm::vec3& value) { if (glm::distance(_acceleration, value) > MIN_ACCELERATION_DELTA) { _acceleration = value; - _dirtyFlags |= EntityItem::DIRTY_VELOCITY; } } void EntityItem::updateAngularVelocity(const glm::vec3& value) { auto distance = glm::distance(_angularVelocity, value); if (distance > MIN_SPIN_DELTA) { - _dirtyFlags |= EntityItem::DIRTY_VELOCITY; + _dirtyFlags |= EntityItem::DIRTY_ANGULAR_VELOCITY; if (glm::length(value) < MIN_SPIN_DELTA) { _angularVelocity = ENTITY_ITEM_ZERO_VEC3; } else { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index e4c1652b3f..0fa3a50b06 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -53,15 +53,19 @@ class EntityItem { public: enum EntityDirtyFlags { DIRTY_POSITION = 0x0001, - DIRTY_VELOCITY = 0x0002, - DIRTY_MASS = 0x0004, - DIRTY_COLLISION_GROUP = 0x0008, - DIRTY_MOTION_TYPE = 0x0010, - DIRTY_SHAPE = 0x0020, - DIRTY_LIFETIME = 0x0040, - DIRTY_UPDATEABLE = 0x0080, - DIRTY_MATERIAL = 0x00100, - DIRTY_PHYSICS_NO_WAKE = 0x0200 // we want to update values in physics engine without "waking" the object up + DIRTY_ROTATOION = 0x0002; + DIRTY_LINEAR_VELOCITY = 0x0004, + DIRTY_ANGULAR_VELOCITY = 0x0008, + DIRTY_MASS = 0x0010, + DIRTY_COLLISION_GROUP = 0x0020, + DIRTY_MOTION_TYPE = 0x0040, + DIRTY_SHAPE = 0x0080, + DIRTY_LIFETIME = 0x0100, + DIRTY_UPDATEABLE = 0x0200, + DIRTY_MATERIAL = 0x00400, + DIRTY_PHYSICS_ACTIVATION = 0x0800, // we want to activate the object + DIRTY_TRANSFORM = DIRTY_POSITION | DIRTY_ROTATION, + DIRTY_VELOCITIES = DIRTY_LINEAR_VELOCITY | DIRTY_ANGULAR_VELOCITY }; DONT_ALLOW_INSTANTIATION // This class can not be instantiated directly diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index e5bb80512c..e8f8b40c72 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -146,7 +146,7 @@ void ObjectMotionState::handleEasyChanges(uint32_t flags) { _body->updateInertiaTensor(); } - if (flags & EntityItem::DIRTY_ACTIVATION) { + if (flags & EntityItem::DIRTY_PHYSICS_ACTIVATION) { _body->activate(); } } From 9f8b266a030a8b350db77b5f67b5f39dd9edb0ef Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 30 Apr 2015 13:56:37 -0700 Subject: [PATCH 11/89] fix some compile problems --- libraries/entities/src/EntityItem.cpp | 4 ++-- libraries/entities/src/EntityItem.h | 2 +- libraries/entities/src/EntitySimulation.h | 7 +++++-- libraries/entities/src/SimpleEntitySimulation.cpp | 2 +- libraries/physics/src/ObjectMotionState.h | 4 ++-- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 29b7fc6a85..f94efef4be 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1109,7 +1109,7 @@ void EntityItem::updatePosition(const glm::vec3& value) { auto distance = glm::distance(_position, value); _dirtyFlags |= EntityItem::DIRTY_POSITION; if (distance > MIN_POSITION_DELTA) { - dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; + _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; } _position = value; } @@ -1132,7 +1132,7 @@ void EntityItem::updateRotation(const glm::quat& rotation) { auto alignmentDot = glm::abs(glm::dot(_rotation, rotation)); _dirtyFlags |= EntityItem::DIRTY_ROTATION; if (alignmentDot < MIN_ALIGNMENT_DOT) { - dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; + _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; } _rotation = rotation; } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 0fa3a50b06..4250d10da8 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -53,7 +53,7 @@ class EntityItem { public: enum EntityDirtyFlags { DIRTY_POSITION = 0x0001, - DIRTY_ROTATOION = 0x0002; + DIRTY_ROTATION = 0x0002, DIRTY_LINEAR_VELOCITY = 0x0004, DIRTY_ANGULAR_VELOCITY = 0x0008, DIRTY_MASS = 0x0010, diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index 69bfe2622a..b975207f87 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -26,13 +26,16 @@ typedef QSet SetOfEntities; // 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_ROTATION | + EntityItem::DIRTY_LINEAR_VELOCITY | + EntityItem::DIRTY_ANGULAR_VELOCITY | EntityItem::DIRTY_MASS | EntityItem::DIRTY_COLLISION_GROUP | EntityItem::DIRTY_MOTION_TYPE | EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_LIFETIME | - EntityItem::DIRTY_UPDATEABLE; + EntityItem::DIRTY_UPDATEABLE | + EntityItem::DIRTY_MATERIAL; class EntitySimulation : public QObject { Q_OBJECT diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index 43d187796a..7739a9a28c 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -79,7 +79,7 @@ void SimpleEntitySimulation::deleteEntityInternal(EntityItem* entity) { } } -const int SIMPLE_SIMULATION_DIRTY_FLAGS = EntityItem::DIRTY_VELOCITY | EntityItem::DIRTY_MOTION_TYPE; +const int SIMPLE_SIMULATION_DIRTY_FLAGS = EntityItem::DIRTY_VELOCITIES | EntityItem::DIRTY_MOTION_TYPE; void SimpleEntitySimulation::changeEntityInternal(EntityItem* entity) { int dirtyFlags = entity->getDirtyFlags(); diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index a96bf1de13..ca731bd2b6 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -35,14 +35,14 @@ enum MotionStateType { // 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); -const uint32_t EASY_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY | +const uint32_t EASY_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES | EntityItem::DIRTY_MASS | EntityItem::DIRTY_COLLISION_GROUP | EntityItem::DIRTY_MATERIAL); // 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; +const uint32_t OUTGOING_DIRTY_PHYSICS_FLAGS = EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES; class OctreeEditPacketSender; From 4cb469dd79544a4cf42e5c9fae8556bd4df061d4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 1 May 2015 08:28:32 -0700 Subject: [PATCH 12/89] cleanup how MotionStates are deleted from physics also fixed some compile errors removed cruft --- interface/src/Application.cpp | 2 +- libraries/physics/src/EntityMotionState.h | 1 - libraries/physics/src/ObjectMotionState.cpp | 22 +-- libraries/physics/src/ObjectMotionState.h | 2 + .../physics/src/PhysicalEntitySimulation.cpp | 27 +-- .../physics/src/PhysicalEntitySimulation.h | 12 +- libraries/physics/src/PhysicsEngine.cpp | 163 ++++++++++-------- libraries/physics/src/PhysicsEngine.h | 12 +- 8 files changed, 127 insertions(+), 114 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ab5cc5b6c6..d48ed1af92 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2355,7 +2355,7 @@ void Application::update(float deltaTime) { PerformanceTimer perfTimer("physics"); _myAvatar->relayDriveKeysToCharacterController(); - _physicsEngine.removeObjects(_entitySimulation.getObjectsToRemove()); + _physicsEngine.deleteObjects(_entitySimulation.getObjectsToRemove()); _physicsEngine.addObjects(_entitySimulation.getObjectsToAdd()); _physicsEngine.changeObjects(_entitySimulation.getObjectsToChange()); diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index db3ced229b..e00969e007 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -40,7 +40,6 @@ public: virtual void setWorldTransform(const btTransform& worldTrans); virtual void computeObjectShapeInfo(ShapeInfo& shapeInfo); - virtual float computeObjectMass(const ShapeInfo& shapeInfo) const; bool doesNotNeedToSendUpdate() const; bool remoteSimulationOutOfSync(uint32_t simulationStep); diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index e8f8b40c72..9486b4a8a1 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -115,15 +115,15 @@ void ObjectMotionState::handleEasyChanges(uint32_t flags) { if (flags & EntityItem::DIRTY_POSITION) { btTransform worldTrans; if (flags & EntityItem::DIRTY_ROTATION) { - worldTrans = getObjectTransform(); + worldTrans.setRotation(glmToBullet(getObjectRotation())); } else { worldTrans = _body->getWorldTransform(); - worldTrans.setOrigin(getObjectPosition()); } + worldTrans.setOrigin(glmToBullet(getObjectPosition())); _body->setWorldTransform(worldTrans); } else { btTransform worldTrans = _body->getWorldTransform(); - worldTrans.setRotation(getObjectRotation()); + worldTrans.setRotation(glmToBullet(getObjectRotation())); _body->setWorldTransform(worldTrans); } @@ -155,14 +155,13 @@ void ObjectMotionState::handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* if (flags & EntityItem::DIRTY_SHAPE) { // make sure the new shape is valid ShapeInfo shapeInfo; - motionState->computeObjectShapeInfo(shapeInfo); + computeObjectShapeInfo(shapeInfo); btCollisionShape* newShape = getShapeManager()->getShape(shapeInfo); if (!newShape) { - // failed to generate new shape! - // remove shape-change flag + // failed to generate new shape! --> keep old shape and remove shape-change flag flags &= ~EntityItem::DIRTY_SHAPE; // TODO: force this object out of PhysicsEngine rather than just use the old shape - if (flags & HARD_DIRTY_PHYSICS_FLAGS == 0) { + if ((flags & HARD_DIRTY_PHYSICS_FLAGS) == 0) { // no HARD flags remain, so do any EASY changes if (flags & EASY_DIRTY_PHYSICS_FLAGS) { handleEasyChanges(flags); @@ -170,21 +169,18 @@ void ObjectMotionState::handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* return; } } - engine->removeRigidBody(_body); - getShapeManager()->removeReference(_shape); + getShapeManager()->releaseShape(_shape); _shape = newShape; - _body->setShape(_shape); + _body->setCollisionShape(_shape); if (flags & EASY_DIRTY_PHYSICS_FLAGS) { handleEasyChanges(flags); } - engine->addRigidBody(_body, motionType, mass); } else { - engine->removeRigidBody(_body); if (flags & EASY_DIRTY_PHYSICS_FLAGS) { handleEasyChanges(flags); } - engine->addRigidBody(_body, motionType, mass); } + engine->reinsertObject(this); } void ObjectMotionState::updateBodyMaterialProperties() { diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index ca731bd2b6..0d82395c76 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -90,6 +90,8 @@ public: virtual void clearIncomingDirtyFlags(uint32_t flags) = 0; virtual MotionType computeObjectMotionType() const = 0; + virtual void computeObjectShapeInfo(ShapeInfo& shapeInfo); + btCollisionShape* getShape() const { return _shape; } btRigidBody* getRigidBody() const { return _body; } diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index 9e6716cd38..f117ed4c1c 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -59,8 +59,6 @@ void PhysicalEntitySimulation::removeEntityInternal(EntityItem* entity) { void* physicsInfo = entity->getPhysicsInfo(); if (physicsInfo) { _pendingRemoves.insert(entity); - } else { - clearEntitySimulation(entity); } } @@ -69,9 +67,6 @@ void PhysicalEntitySimulation::deleteEntityInternal(EntityItem* entity) { void* physicsInfo = entity->getPhysicsInfo(); if (physicsInfo) { _pendingRemoves.insert(entity); - } else { - clearEntitySimulation(entity); - delete entity; } } @@ -110,16 +105,18 @@ void PhysicalEntitySimulation::clearEntitiesInternal() { // while it is in the middle of a simulation step. As it is, we're probably in shutdown mode // anyway, so maybe the simulation was already properly shutdown? Cross our fingers... - _physicsEngine->deleteObjects(_physicalEntities); - - for (auto stateItr : _physicalEntities) { + // first disconnect each MotionStates from its Entity + for (auto stateItr : _physicalObjects) { EntityMotionState* motionState = static_cast(&(*stateItr)); EntityItem* entity = motionState->getEntity(); entity->setPhysicsInfo(nullptr); - delete motionState; } - _physicalEntities.clear(); + // then delete the objects (aka MotionStates) + _physicsEngine->deleteObjects(_physicalObjects); + + // finally clear all lists (which now have only dangling pointers) + _physicalObjects.clear(); _pendingRemoves.clear(); _pendingAdds.clear(); _pendingChanges.clear(); @@ -127,7 +124,7 @@ void PhysicalEntitySimulation::clearEntitiesInternal() { // end EntitySimulation overrides -VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToRemove() { +VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToDelete() { _tempVector.clear(); for (auto entityItr : _pendingRemoves) { EntityItem* entity = &(*entityItr); @@ -135,8 +132,12 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToRemove() { _pendingChanges.remove(entity); EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); if (motionState) { + _physicalObjects.remove(motionState); + // disconnect EntityMotionState from its Entity + // NOTE: EntityMotionState still has a back pointer to its Entity, but is about to be deleted + // (by PhysicsEngine) and shouldn't actually access its Entity during this process. + entity->setPhysicsInfo(nullptr); _tempVector.push_back(motionState); - _physicalEntities.remove(motionState); } } _pendingRemoves.clear(); @@ -158,7 +159,7 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToAdd() { EntityMotionState* motionState = new EntityMotionState(shape, entity); entity->setPhysicsInfo(static_cast(motionState)); motionState->setMass(entity->computeMass()); - _physicalEntities.insert(motionState); + _physicalObjects.insert(motionState); _tempVector.push_back(motionState); entityItr = _pendingAdds.erase(entityItr); } else { diff --git a/libraries/physics/src/PhysicalEntitySimulation.h b/libraries/physics/src/PhysicalEntitySimulation.h index 2d49aa5d8a..523121cefe 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.h +++ b/libraries/physics/src/PhysicalEntitySimulation.h @@ -42,7 +42,7 @@ public: void sortEntitiesThatMovedInternal(); void clearEntitiesInternal(); - VectorOfMotionStates& getObjectsToRemove(); + VectorOfMotionStates& getObjectsToDelete(); VectorOfMotionStates& getObjectsToAdd(); VectorOfMotionStates& getObjectsToChange(); @@ -52,15 +52,15 @@ private: void bump(EntityItem* bumpEntity); // incoming changes - SetOfEntities _pendingRemoves; // entities to be removed from simulation - SetOfEntities _pendingAdds; // entities to be be added to simulation - SetOfEntities _pendingChanges; // entities already in simulation that need to be changed + SetOfEntities _pendingRemoves; // entities to be removed from PhysicsEngine (and their MotionState deleted) + SetOfEntities _pendingAdds; // entities to be be added to PhysicsEngine (and a their MotionState created) + SetOfEntities _pendingChanges; // entities already in PhysicsEngine that need their physics changed // outgoing changes QSet _outgoingChanges; // entities for which we need to send updates to entity-server - SetOfMotionStates _physicalEntities; // MotionStates of entities in PhysicsEngine - VectorOfMotionStates _tempVector; // temporary list, valid by reference immediately after call to getObjectsToRemove/Add/Update() + SetOfMotionStates _physicalObjects; // MotionStates of entities in PhysicsEngine + VectorOfMotionStates _tempVector; // temporary array, valid by reference immediately after call to getObjectsToRemove/Add/Update() ShapeManager* _shapeManager = nullptr; PhysicsEngine* _physicsEngine = nullptr; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index af4ec42df8..7b9a534cac 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -59,42 +59,113 @@ void PhysicsEngine::init() { } } -void PhysicsEngine::removeObjects(VectorOfMotionStates& objects) { - for (auto object : objects) { - assert(object); - - // wake up anything touching this object - bump(object); +void PhysicsEngine::addObject(ObjectMotionState* motionState) { + assert(motionState); - btRigidBody* body = object->getRigidBody(); - _dynamicsWorld->removeRigidBody(body); - removeContacts(object); + btVector3 inertia(0.0f, 0.0f, 0.0f); + float mass = 0.0f; + // NOTE: the body may or may not already exist, depending on whether this corresponds to a reinsertion, or a new insertion. + btRigidBody* body = motionState->getRigidBody(); + MotionType motionType = motionState->computeObjectMotionType(); + motionState->setMotionType(motionType); + switch(motionType) { + case MOTION_TYPE_KINEMATIC: { + if (!body) { + btCollisionShape* shape = motionState->getShape(); + assert(shape); + body = new btRigidBody(mass, motionState, shape, inertia); + } else { + body->setMassProps(mass, inertia); + } + body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); + body->updateInertiaTensor(); + motionState->setRigidBody(body); + motionState->updateBodyVelocities(); + const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec + const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec + body->setSleepingThresholds(KINEMATIC_LINEAR_VELOCITY_THRESHOLD, KINEMATIC_ANGULAR_VELOCITY_THRESHOLD); + break; + } + case MOTION_TYPE_DYNAMIC: { + mass = motionState->getMass(); + btCollisionShape* shape = motionState->getShape(); + assert(shape); + shape->calculateLocalInertia(mass, inertia); + if (!body) { + body = new btRigidBody(mass, motionState, shape, inertia); + } else { + body->setMassProps(mass, inertia); + } + body->updateInertiaTensor(); + motionState->setRigidBody(body); + motionState->updateBodyVelocities(); + // 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 + const float DYNAMIC_LINEAR_VELOCITY_THRESHOLD = 0.05f; // 5 cm/sec + const float DYNAMIC_ANGULAR_VELOCITY_THRESHOLD = 0.087266f; // ~5 deg/sec + body->setSleepingThresholds(DYNAMIC_LINEAR_VELOCITY_THRESHOLD, DYNAMIC_ANGULAR_VELOCITY_THRESHOLD); + if (!motionState->isMoving()) { + // try to initialize this object as inactive + body->forceActivationState(ISLAND_SLEEPING); + } + break; + } + case MOTION_TYPE_STATIC: + default: { + if (!body) { + body = new btRigidBody(mass, motionState, shape, inertia); + } else { + body->setMassProps(mass, inertia); + } + body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT); + body->updateInertiaTensor(); + motionState->setRigidBody(body); + break; + } + } + body->setFlags(BT_DISABLE_WORLD_GRAVITY); + motionState->updateBodyMaterialProperties(); + + _dynamicsWorld->addRigidBody(body); +} + +void PhysicsEngine::removeObject(ObjectMotionState* object) { + // wake up anything touching this object + bump(object); + removeContacts(object); + + btRigidBody* body = object->getRigidBody(); + assert(body); + _dynamicsWorld->removeRigidBody(body); +} + +void PhysicsEngine::deleteObjects(VectorOfMotionStates& objects) { + for (auto object : objects) { + removeObject(object); // NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it. object->setRigidBody(nullptr); delete body; object->releaseShape(); + delete object; } } +// Same as above, but takes a Set instead of a Vector. Only called during teardown. void PhysicsEngine::deleteObjects(SetOfMotionStates& objects) { for (auto object : objects) { - assert(object); - - btRigidBody* body = object->getRigidBody(); _dynamicsWorld->removeRigidBody(body); - removeContacts(object); - + // NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it. object->setRigidBody(nullptr); delete body; object->releaseShape(); + delete object; } } void PhysicsEngine::addObjects(VectorOfMotionStates& objects) { for (auto object : objects) { - assert(object); addObject(object); } } @@ -302,62 +373,13 @@ void PhysicsEngine::dumpStatsIfNecessary() { // CF_DISABLE_VISUALIZE_OBJECT = 32, //disable debug drawing // CF_DISABLE_SPU_COLLISION_PROCESSING = 64//disable parallel/SPU processing -void PhysicsEngine::addObject(ObjectMotionState* motionState) { - assert(motionState); - btCollisionShape* shape = motionState->getShape(); - assert(shape); - - btVector3 inertia(0.0f, 0.0f, 0.0f); - float mass = 0.0f; - btRigidBody* body = nullptr; - MotionType motionType = motionState->computeObjectMotionType(); - motionState->setMotionType(motionType); - switch(motionType) { - case MOTION_TYPE_KINEMATIC: { - body = new btRigidBody(mass, motionState, shape, inertia); - body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); - body->updateInertiaTensor(); - motionState->setRigidBody(body); - motionState->updateBodyVelocities(); - const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec - const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec - body->setSleepingThresholds(KINEMATIC_LINEAR_VELOCITY_THRESHOLD, KINEMATIC_ANGULAR_VELOCITY_THRESHOLD); - break; - } - case MOTION_TYPE_DYNAMIC: { - mass = motionState->getMass(); - shape->calculateLocalInertia(mass, inertia); - body = new btRigidBody(mass, motionState, shape, inertia); - body->updateInertiaTensor(); - motionState->setRigidBody(body); - motionState->updateBodyVelocities(); - // 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 - const float DYNAMIC_LINEAR_VELOCITY_THRESHOLD = 0.05f; // 5 cm/sec - const float DYNAMIC_ANGULAR_VELOCITY_THRESHOLD = 0.087266f; // ~5 deg/sec - body->setSleepingThresholds(DYNAMIC_LINEAR_VELOCITY_THRESHOLD, DYNAMIC_ANGULAR_VELOCITY_THRESHOLD); - if (!motionState->isMoving()) { - // try to initialize this object as inactive - body->forceActivationState(ISLAND_SLEEPING); - } - break; - } - case MOTION_TYPE_STATIC: - default: { - body = new btRigidBody(mass, motionState, shape, inertia); - body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT); - body->updateInertiaTensor(); - motionState->setRigidBody(body); - break; - } - } - body->setFlags(BT_DISABLE_WORLD_GRAVITY); - motionState->updateBodyMaterialProperties(); - - _dynamicsWorld->addRigidBody(body); +void PhysicsEngine::reinsertObject(ObjectMotionState* object) { + removeObject(object); + addObject(object); } void PhysicsEngine::bump(ObjectMotionState* object) { + assert(object); /* TODO: Andrew to implement this // If this node is doing something like deleting an entity, scan for contacts involving the // entity. For each found, flag the other entity involved as being simulated by this node. @@ -437,11 +459,6 @@ void PhysicsEngine::bump(EntityItem* bumpEntity) { } */ -void PhysicsEngine::removeRigidBody(btRigidBody* body) { - // pull body out of physics engine - _dynamicsWorld->removeRigidBody(body); -} - void PhysicsEngine::setCharacterController(DynamicCharacterController* character) { if (_characterController != character) { if (_characterController) { diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 4625df605e..416ceee3e5 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -51,9 +51,11 @@ public: ~PhysicsEngine(); void init(); - /// process queue of changed from external sources - void removeObjects(VectorOfMotionStates& objects); - void deleteObjects(SetOfMotionStates& objects); + void addObject(ObjectMotionState* motionState); + void removeObject(ObjectMotionState* motionState); + + void deleteObjects(VectorOfMotionStates& objects); + void deleteObjects(SetOfMotionStates& objects); // only called during teardown void addObjects(VectorOfMotionStates& objects); void changeObjects(VectorOfMotionStates& objects); @@ -71,10 +73,6 @@ public: /// \return position of simulation origin in domain-frame const glm::vec3& getOriginOffset() const { return _originOffset; } - /// \param motionState pointer to Object's MotionState - /// \return true if Object added - void addObject(ObjectMotionState* motionState); - void bump(ObjectMotionState* motionState); void removeRigidBody(btRigidBody* body); From 31ca5b9eefed7d82b6268e7c2ccd716c6e49b23c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 1 May 2015 10:43:58 -0700 Subject: [PATCH 13/89] add EntityTree::_pendingDelete for delayed deletes for case where EntitySimuation needs time to remove pointers --- libraries/entities/src/EntityTree.cpp | 32 ++++++++++++++++++++------- libraries/entities/src/EntityTree.h | 2 ++ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index f59a22d137..b9ff2f3727 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -350,10 +350,12 @@ void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator) } if (_simulation && theEntity->getSimulation()) { - // delegate entity destruction to the simulation so it can clean up its own pointers - _simulation->deleteEntity(theEntity); + _simulation->removeEntity(theEntity); + // we need to give the simulation time to cleanup its own pointers + // so we push theEntity onto the _pendingDeletes and check again later. + _pendingDeletes.insert(theEntity); } else { - delete theEntity; // we can delete the entity directly now + delete theEntity; // we can delete the entity immediately } } if (_simulation) { @@ -754,16 +756,30 @@ void EntityTree::update() { lockForWrite(); _simulation->lock(); _simulation->updateEntities(); - SetOfEntities entitiesToDelete; - _simulation->getEntitiesToDelete(entitiesToDelete); + _simulation->getEntitiesToDelete(_pendingDeletes); _simulation->unlock(); - if (entitiesToDelete.size() > 0) { + if (_pendingDeletes.size() > 0) { // translate into list of ID's QSet idsToDelete; - foreach (EntityItem* entity, entitiesToDelete) { - idsToDelete.insert(entity->getEntityItemID()); + SetOfEntities::iterator entityItr = _pendingDeletes.begin(); + while (entityItr != _pendingDeletes.end()) { + EntityItem* entity = *entityItr; + if (entity->getElement()) { + // this entity is still in an element so we push it's ID on a list (and delete the roundabout way) + idsToDelete.insert(entity->getEntityItemID()); + entityItr = _pendingDeletes.erase(entityItr); + } else if (!entity->getSimulation()) { + // the entity is not in any simulation so we can delete immediately + delete entity; + entityItr = _pendingDeletes.erase(entityItr); + } else { + // we're waiting for the simulation to cleanup its own data structure + // so we leave it on the _pendingDeletes and will try again later + ++entityItr; + } } + // delete these things the roundabout way deleteEntities(idsToDelete, true); } unlock(); diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 3f01dec408..aa4925be2f 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -18,6 +18,7 @@ #include "EntityTreeElement.h" #include "DeleteEntityOperator.h" +typedef QSet SetOfEntities; class Model; class EntitySimulation; @@ -197,6 +198,7 @@ private: QHash _changedEntityIDs; EntitySimulation* _simulation; + SetOfEntities _pendingDeletes; bool _wantEditLogging = false; }; From b023fe582a700a90ee6541f00140570c6ac9d4b4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 1 May 2015 10:44:50 -0700 Subject: [PATCH 14/89] make things compile --- interface/src/Application.cpp | 7 ++-- libraries/entities/src/EntitySimulation.cpp | 38 +++---------------- libraries/entities/src/EntitySimulation.h | 21 +++------- .../entities/src/SimpleEntitySimulation.cpp | 11 ------ .../entities/src/SimpleEntitySimulation.h | 1 - libraries/physics/src/EntityMotionState.cpp | 4 ++ libraries/physics/src/ObjectMotionState.cpp | 11 ++++-- libraries/physics/src/ObjectMotionState.h | 2 +- .../physics/src/PhysicalEntitySimulation.cpp | 14 +------ .../physics/src/PhysicalEntitySimulation.h | 5 ++- libraries/physics/src/PhysicsEngine.cpp | 17 +++++---- libraries/physics/src/PhysicsEngine.h | 1 + 12 files changed, 43 insertions(+), 89 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d48ed1af92..616a660d43 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -70,6 +70,7 @@ #include #include #include +#include #include #include #include @@ -2069,11 +2070,11 @@ void Application::init() { auto entityScriptingInterface = DependencyManager::get(); - connect(&_physicsEngine, &EntitySimulation::entityCollisionWithEntity, + connect(&_entitySimulation, &EntitySimulation::entityCollisionWithEntity, entityScriptingInterface.data(), &EntityScriptingInterface::entityCollisionWithEntity); // connect the _entityCollisionSystem to our EntityTreeRenderer since that's what handles running entity scripts - connect(&_physicsEngine, &EntitySimulation::entityCollisionWithEntity, + connect(&_entitySimulation, &EntitySimulation::entityCollisionWithEntity, &_entities, &EntityTreeRenderer::entityCollisionWithEntity); // connect the _entities (EntityTreeRenderer) to our script engine's EntityScriptingInterface for firing @@ -2355,7 +2356,7 @@ void Application::update(float deltaTime) { PerformanceTimer perfTimer("physics"); _myAvatar->relayDriveKeysToCharacterController(); - _physicsEngine.deleteObjects(_entitySimulation.getObjectsToRemove()); + _physicsEngine.deleteObjects(_entitySimulation.getObjectsToDelete()); _physicsEngine.addObjects(_entitySimulation.getObjectsToAdd()); _physicsEngine.changeObjects(_entitySimulation.getObjectsToChange()); diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index 1cf3ba42e6..7ea8c0a330 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -70,7 +70,7 @@ void EntitySimulation::expireMortalEntities(const quint64& now) { itemItr = _mortalEntities.erase(itemItr); _entitiesToUpdate.remove(entity); _entitiesToSort.remove(entity); - deleteEntityInternal(entity); + removeEntityInternal(entity); } else { if (expiry < _nextExpiry) { // remeber the smallest _nextExpiry so we know when to start the next search @@ -116,7 +116,7 @@ void EntitySimulation::sortEntitiesThatMoved() { _entitiesToDelete.insert(entity); _mortalEntities.remove(entity); _entitiesToUpdate.remove(entity); - deleteEntityInternal(entity); + removeEntityInternal(entity); itemItr = _entitiesToSort.erase(itemItr); } else { moveOperator.addEntityToMoveList(entity, newCube); @@ -160,36 +160,7 @@ void EntitySimulation::removeEntity(EntityItem* entity) { _entitiesToUpdate.remove(entity); _mortalEntities.remove(entity); _entitiesToSort.remove(entity); - if (entity->_element) { - // some EntityTreeElement still references this entity, but it's being removed from this simulation - _entitiesToDelete.remove(entity); - removeEntityInternal(entity); - } else { - // we're the last to reference this entity, so we really need to delete it - deleteEntityInternal(entity); - } - } else if (!entity->_element) { - // nothing else is referencing this entity, so we delete it now - delete entity; - } -} - -void EntitySimulation::deleteEntity(EntityItem* entity) { - assert(entity); - if (entity->_simulation == this) { - _entitiesToUpdate.remove(entity); - _mortalEntities.remove(entity); - _entitiesToSort.remove(entity); - deleteEntityInternal(entity); - } else { - if (entity->_element) { - // some EntityTreeElement still references this entity, so we put it on the list - // which will be harvested by the tree later - _entitiesToDelete.insert(entity); - } else { - // nothing else is referencing this entity, so we delete it now - delete entity; - } + removeEntityInternal(entity); } } @@ -209,7 +180,8 @@ void EntitySimulation::changeEntity(EntityItem* entity) { _entitiesToDelete.insert(entity); _mortalEntities.remove(entity); _entitiesToUpdate.remove(entity); - deleteEntityInternal(entity); + _entitiesToSort.remove(entity); + removeEntityInternal(entity); wasRemoved = true; } } diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index b975207f87..03db85e399 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -20,8 +20,6 @@ #include "EntityItem.h" #include "EntityTree.h" -typedef QSet SetOfEntities; - // 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 = @@ -51,6 +49,9 @@ public: void updateEntities(); + friend EntityTree; + +protected: // these only called by the EntityTree? /// \param entity pointer to EntityItem to be added /// \sideeffect sets relevant backpointers in entity, but maybe later when appropriate data structures are locked void addEntity(EntityItem* entity); @@ -60,17 +61,14 @@ public: /// \sideeffect nulls relevant backpointers in entity void removeEntity(EntityItem* entity); - /// \param pointer to EntityItem to be removed from simulation, and deleted if possible - /// \brief actual removal/delete may happen later when appropriate data structures are locked - /// \sideeffect nulls relevant backpointers in entity - void deleteEntity(EntityItem* entity); - /// \param entity pointer to EntityItem to that may have changed in a way that would affect its simulation /// call this whenever an entity was changed from some EXTERNAL event (NOT by the EntitySimulation itself) void changeEntity(EntityItem* entity); void clearEntities(); +public: + EntityTree* getEntityTree() { return _entityTree; } void getEntitiesToDelete(SetOfEntities& entitiesToDelete); @@ -84,20 +82,11 @@ 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 deleteEntityInternal(EntityItem* entity) = 0; - virtual void changeEntityInternal(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 7739a9a28c..b6e444a0a9 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -68,17 +68,6 @@ void SimpleEntitySimulation::removeEntityInternal(EntityItem* entity) { clearEntitySimulation(entity); } -void SimpleEntitySimulation::deleteEntityInternal(EntityItem* entity) { - _movingEntities.remove(entity); - _movableButStoppedEntities.remove(entity); - _hasSimulationOwnerEntities.remove(entity); - clearEntitySimulation(entity); - if (!entity->getElement()) { - // we held the last reference to this entity, so delete it - delete entity; - } -} - const int SIMPLE_SIMULATION_DIRTY_FLAGS = EntityItem::DIRTY_VELOCITIES | EntityItem::DIRTY_MOTION_TYPE; void SimpleEntitySimulation::changeEntityInternal(EntityItem* entity) { diff --git a/libraries/entities/src/SimpleEntitySimulation.h b/libraries/entities/src/SimpleEntitySimulation.h index fa625e4783..b63047ef0e 100644 --- a/libraries/entities/src/SimpleEntitySimulation.h +++ b/libraries/entities/src/SimpleEntitySimulation.h @@ -25,7 +25,6 @@ protected: virtual void updateEntitiesInternal(const quint64& now); virtual void addEntityInternal(EntityItem* entity); virtual void removeEntityInternal(EntityItem* entity); - virtual void deleteEntityInternal(EntityItem* entity); virtual void changeEntityInternal(EntityItem* entity); virtual void clearEntitiesInternal(); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index fd1a53a0ce..d8fcc47b60 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -111,6 +111,10 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { #endif } +void EntityMotionState::computeObjectShapeInfo(ShapeInfo& shapeInfo) { + _entity->computeShapeInfo(shapeInfo); +} + // 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; diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 9486b4a8a1..47e8e7d861 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -67,6 +67,11 @@ ObjectMotionState::ObjectMotionState(btCollisionShape* shape) : { } +ObjectMotionState::~ObjectMotionState() { + assert(!_body); + assert(!_shape); +} + void ObjectMotionState::setBodyLinearVelocity(const glm::vec3& velocity) const { _body->setLinearVelocity(glmToBullet(velocity)); } @@ -190,8 +195,8 @@ void ObjectMotionState::updateBodyMaterialProperties() { } void ObjectMotionState::updateBodyVelocities() { - setBodyVelocity(getObjectLinearVelocity()); - setBodyAngularVelocity(getObjectAngularVelocity(); - setBodyGravity(getObjectGravity(); + setBodyLinearVelocity(getObjectLinearVelocity()); + setBodyAngularVelocity(getObjectAngularVelocity()); + setBodyGravity(getObjectGravity()); _body->setActivationState(ACTIVE_TAG); } diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 0d82395c76..253ce57847 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -90,7 +90,7 @@ public: virtual void clearIncomingDirtyFlags(uint32_t flags) = 0; virtual MotionType computeObjectMotionType() const = 0; - virtual void computeObjectShapeInfo(ShapeInfo& shapeInfo); + virtual void computeObjectShapeInfo(ShapeInfo& shapeInfo) = 0; btCollisionShape* getShape() const { return _shape; } diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index f117ed4c1c..fe104e82ec 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -55,22 +55,12 @@ void PhysicalEntitySimulation::addEntityInternal(EntityItem* entity) { } void PhysicalEntitySimulation::removeEntityInternal(EntityItem* entity) { - assert(entity); - void* physicsInfo = entity->getPhysicsInfo(); - if (physicsInfo) { + if (entity->getPhysicsInfo()) { _pendingRemoves.insert(entity); } } -void PhysicalEntitySimulation::deleteEntityInternal(EntityItem* entity) { - assert(entity); - void* physicsInfo = entity->getPhysicsInfo(); - if (physicsInfo) { - _pendingRemoves.insert(entity); - } -} - -void PhysicalEntitySimulation::entityChangedInternal(EntityItem* entity) { +void PhysicalEntitySimulation::changeEntityInternal(EntityItem* entity) { // queue incoming changes: from external sources (script, EntityServer, etc) to physics engine assert(entity); void* physicsInfo = entity->getPhysicsInfo(); diff --git a/libraries/physics/src/PhysicalEntitySimulation.h b/libraries/physics/src/PhysicalEntitySimulation.h index 523121cefe..3cbebadd12 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.h +++ b/libraries/physics/src/PhysicalEntitySimulation.h @@ -33,15 +33,16 @@ public: void init(EntityTree* tree, PhysicsEngine* engine, ShapeManager* shapeManager, EntityEditPacketSender* packetSender); +protected: // only called by EntitySimulation // overrides for EntitySimulation void updateEntitiesInternal(const quint64& now); void addEntityInternal(EntityItem* entity); void removeEntityInternal(EntityItem* entity); - void deleteEntityInternal(EntityItem* entity); - void entityChangedInternal(EntityItem* entity); + void changeEntityInternal(EntityItem* entity); void sortEntitiesThatMovedInternal(); void clearEntitiesInternal(); +public: VectorOfMotionStates& getObjectsToDelete(); VectorOfMotionStates& getObjectsToAdd(); VectorOfMotionStates& getObjectsToChange(); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 7b9a534cac..1029dc064f 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -113,7 +113,8 @@ void PhysicsEngine::addObject(ObjectMotionState* motionState) { case MOTION_TYPE_STATIC: default: { if (!body) { - body = new btRigidBody(mass, motionState, shape, inertia); + assert(motionState->getShape()); + body = new btRigidBody(mass, motionState, motionState->getShape(), inertia); } else { body->setMassProps(mass, inertia); } @@ -144,6 +145,7 @@ void PhysicsEngine::deleteObjects(VectorOfMotionStates& objects) { removeObject(object); // NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it. + btRigidBody* body = object->getRigidBody(); object->setRigidBody(nullptr); delete body; object->releaseShape(); @@ -151,9 +153,10 @@ void PhysicsEngine::deleteObjects(VectorOfMotionStates& objects) { } } -// Same as above, but takes a Set instead of a Vector. Only called during teardown. +// Same as above, but takes a Set instead of a Vector and ommits some cleanup operations. Only called during teardown. void PhysicsEngine::deleteObjects(SetOfMotionStates& objects) { for (auto object : objects) { + btRigidBody* body = object->getRigidBody(); _dynamicsWorld->removeRigidBody(body); // NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it. @@ -181,6 +184,11 @@ void PhysicsEngine::changeObjects(VectorOfMotionStates& objects) { } } +void PhysicsEngine::reinsertObject(ObjectMotionState* object) { + removeObject(object); + addObject(object); +} + void PhysicsEngine::removeContacts(ObjectMotionState* motionState) { // trigger events for new/existing/old contacts ContactMap::iterator contactItr = _contactMap.begin(); @@ -373,11 +381,6 @@ void PhysicsEngine::dumpStatsIfNecessary() { // CF_DISABLE_VISUALIZE_OBJECT = 32, //disable debug drawing // CF_DISABLE_SPU_COLLISION_PROCESSING = 64//disable parallel/SPU processing -void PhysicsEngine::reinsertObject(ObjectMotionState* object) { - removeObject(object); - addObject(object); -} - void PhysicsEngine::bump(ObjectMotionState* object) { assert(object); /* TODO: Andrew to implement this diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 416ceee3e5..b05ebd05db 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -58,6 +58,7 @@ public: void deleteObjects(SetOfMotionStates& objects); // only called during teardown void addObjects(VectorOfMotionStates& objects); void changeObjects(VectorOfMotionStates& objects); + void reinsertObject(ObjectMotionState* object); void stepSimulation(); void computeCollisionEvents(); From c2d614b88481c6f69bb63ee5254e3a7a5e4d5788 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 1 May 2015 11:19:01 -0700 Subject: [PATCH 15/89] remove _movableButStoppedEntities --- .../entities/src/SimpleEntitySimulation.cpp | 16 ++++------------ libraries/entities/src/SimpleEntitySimulation.h | 1 - 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index b6e444a0a9..e4662638e3 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -22,13 +22,12 @@ void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { SetOfEntities::iterator itemItr = _movingEntities.begin(); while (itemItr != _movingEntities.end()) { EntityItem* entity = *itemItr; - if (!entity->isMoving()) { - itemItr = _movingEntities.erase(itemItr); - _movableButStoppedEntities.insert(entity); - } else { + if (entity->isMoving()) { entity->simulate(now); _entitiesToSort.insert(entity); ++itemItr; + } else { + itemItr = _movingEntities.erase(itemItr); } } @@ -53,9 +52,7 @@ void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { void SimpleEntitySimulation::addEntityInternal(EntityItem* entity) { if (entity->isMoving()) { _movingEntities.insert(entity); - } else if (entity->getCollisionsWillMove()) { - _movableButStoppedEntities.insert(entity); - } + } if (!entity->getSimulatorID().isNull()) { _hasSimulationOwnerEntities.insert(entity); } @@ -63,7 +60,6 @@ void SimpleEntitySimulation::addEntityInternal(EntityItem* entity) { void SimpleEntitySimulation::removeEntityInternal(EntityItem* entity) { _movingEntities.remove(entity); - _movableButStoppedEntities.remove(entity); _hasSimulationOwnerEntities.remove(entity); clearEntitySimulation(entity); } @@ -75,11 +71,8 @@ void SimpleEntitySimulation::changeEntityInternal(EntityItem* entity) { if (dirtyFlags & SIMPLE_SIMULATION_DIRTY_FLAGS) { if (entity->isMoving()) { _movingEntities.insert(entity); - } else if (entity->getCollisionsWillMove()) { - _movableButStoppedEntities.remove(entity); } else { _movingEntities.remove(entity); - _movableButStoppedEntities.remove(entity); } if (!entity->getSimulatorID().isNull()) { _hasSimulationOwnerEntities.insert(entity); @@ -90,7 +83,6 @@ void SimpleEntitySimulation::changeEntityInternal(EntityItem* entity) { void SimpleEntitySimulation::clearEntitiesInternal() { _movingEntities.clear(); - _movableButStoppedEntities.clear(); _hasSimulationOwnerEntities.clear(); } diff --git a/libraries/entities/src/SimpleEntitySimulation.h b/libraries/entities/src/SimpleEntitySimulation.h index b63047ef0e..454d168556 100644 --- a/libraries/entities/src/SimpleEntitySimulation.h +++ b/libraries/entities/src/SimpleEntitySimulation.h @@ -29,7 +29,6 @@ protected: virtual void clearEntitiesInternal(); SetOfEntities _movingEntities; - SetOfEntities _movableButStoppedEntities; SetOfEntities _hasSimulationOwnerEntities; }; From 3c9474b736bfea08bc6f6a4df6381410b5673ee8 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 1 May 2015 13:43:50 -0700 Subject: [PATCH 16/89] non-phys kinematic objs move to EntitySimulation out of SimpleEntitySimulation --- libraries/entities/src/EntitySimulation.cpp | 35 ++++++++++++++++++- libraries/entities/src/EntitySimulation.h | 17 +++++---- .../entities/src/SimpleEntitySimulation.cpp | 35 +++---------------- .../entities/src/SimpleEntitySimulation.h | 1 - .../physics/src/PhysicalEntitySimulation.cpp | 15 -------- .../physics/src/PhysicalEntitySimulation.h | 1 - 6 files changed, 50 insertions(+), 54 deletions(-) diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index 7ea8c0a330..e7dd208cc7 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -21,6 +21,7 @@ void EntitySimulation::setEntityTree(EntityTree* tree) { _nextExpiry = quint64(-1); _entitiesToUpdate.clear(); _entitiesToSort.clear(); + _simpleKinematicEntities.clear(); } _entityTree = tree; } @@ -31,6 +32,7 @@ void EntitySimulation::updateEntities() { // these methods may accumulate entries in _entitiesToBeDeleted expireMortalEntities(now); callUpdateOnEntitiesThatNeedIt(now); + moveSimpleKinematics(now); updateEntitiesInternal(now); sortEntitiesThatMoved(); } @@ -56,6 +58,20 @@ void EntitySimulation::getEntitiesToDelete(SetOfEntities& entitiesToDelete) { } } +void EntitySimulation::addEntityInternal(EntityItem* entity) { + if (entity->isMoving() && !entity->getPhysicsInfo()) { + _simpleKinematicEntities.insert(entity); + } +} + +void EntitySimulation::changeEntityInternal(EntityItem* entity) { + if (entity->isMoving() && !entity->getPhysicsInfo()) { + _simpleKinematicEntities.insert(entity); + } else { + _simpleKinematicEntities.remove(entity); + } +} + // protected void EntitySimulation::expireMortalEntities(const quint64& now) { if (now > _nextExpiry) { @@ -70,6 +86,7 @@ void EntitySimulation::expireMortalEntities(const quint64& now) { itemItr = _mortalEntities.erase(itemItr); _entitiesToUpdate.remove(entity); _entitiesToSort.remove(entity); + _simpleKinematicEntities.remove(entity); removeEntityInternal(entity); } else { if (expiry < _nextExpiry) { @@ -116,6 +133,7 @@ void EntitySimulation::sortEntitiesThatMoved() { _entitiesToDelete.insert(entity); _mortalEntities.remove(entity); _entitiesToUpdate.remove(entity); + _simpleKinematicEntities.remove(entity); removeEntityInternal(entity); itemItr = _entitiesToSort.erase(itemItr); } else { @@ -128,7 +146,6 @@ void EntitySimulation::sortEntitiesThatMoved() { _entityTree->recurseTreeWithOperator(&moveOperator); } - sortEntitiesThatMovedInternal(); _entitiesToSort.clear(); } @@ -160,6 +177,7 @@ void EntitySimulation::removeEntity(EntityItem* entity) { _entitiesToUpdate.remove(entity); _mortalEntities.remove(entity); _entitiesToSort.remove(entity); + _simpleKinematicEntities.remove(entity); removeEntityInternal(entity); } } @@ -181,6 +199,7 @@ void EntitySimulation::changeEntity(EntityItem* entity) { _mortalEntities.remove(entity); _entitiesToUpdate.remove(entity); _entitiesToSort.remove(entity); + _simpleKinematicEntities.remove(entity); removeEntityInternal(entity); wasRemoved = true; } @@ -216,6 +235,20 @@ void EntitySimulation::clearEntities() { _nextExpiry = quint64(-1); _entitiesToUpdate.clear(); _entitiesToSort.clear(); + _simpleKinematicEntities.clear(); clearEntitiesInternal(); } +void EntitySimulation::moveSimpleKinematics(const quint64& now) { + SetOfEntities::iterator itemItr = _simpleKinematicEntities.begin(); + while (itemItr != _simpleKinematicEntities.end()) { + EntityItem* entity = *itemItr; + if (entity->isMoving() && !entity->getPhysicsInfo()) { + entity->simulate(now); + _entitiesToSort.insert(entity); + ++itemItr; + } else { + itemItr = _simpleKinematicEntities.erase(itemItr); + } + } +} diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index 03db85e399..b6d3abd64a 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -67,6 +67,8 @@ protected: // these only called by the EntityTree? void clearEntities(); + void moveSimpleKinematics(const quint64& now); + public: EntityTree* getEntityTree() { return _entityTree; } @@ -83,10 +85,9 @@ 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. virtual void updateEntitiesInternal(const quint64& now) = 0; - virtual void addEntityInternal(EntityItem* entity) = 0; + virtual void addEntityInternal(EntityItem* entity); virtual void removeEntityInternal(EntityItem* entity) = 0; - virtual void changeEntityInternal(EntityItem* entity) = 0; - virtual void sortEntitiesThatMovedInternal() {} + virtual void changeEntityInternal(EntityItem* entity); virtual void clearEntitiesInternal() = 0; void expireMortalEntities(const quint64& now); @@ -102,9 +103,13 @@ protected: // An entity may be in more than one list. SetOfEntities _mortalEntities; // entities that have an expiry quint64 _nextExpiry; - SetOfEntities _entitiesToUpdate; // entities that need update() called - SetOfEntities _entitiesToSort; // entities that were moved by THIS simulation and might need to be resorted in the tree - SetOfEntities _entitiesToDelete; + SetOfEntities _entitiesToUpdate; // entities that need to call EntityItem::update() + SetOfEntities _entitiesToSort; // entities that were moved by simulation (and might need resort in EntityTree) + SetOfEntities _entitiesToDelete; // entities that this simulation decided to delete (EntityTree will do the actual deletes) + SetOfEntities _simpleKinematicEntities; // entities that are undergoing (non-colliding) kinematic motion" + +private: + void moveSimpleKinematics(); }; #endif // hifi_EntitySimulation_h diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index e4662638e3..017ff23473 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -18,28 +18,15 @@ const quint64 AUTO_REMOVE_SIMULATION_OWNER_USEC = 2 * USECS_PER_SECOND; void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { - // now is usecTimestampNow() - SetOfEntities::iterator itemItr = _movingEntities.begin(); - while (itemItr != _movingEntities.end()) { - EntityItem* entity = *itemItr; - if (entity->isMoving()) { - entity->simulate(now); - _entitiesToSort.insert(entity); - ++itemItr; - } else { - itemItr = _movingEntities.erase(itemItr); - } - } - // If an Entity has a simulation owner and we don't get an update for some amount of time, // clear the owner. This guards against an interface failing to release the Entity when it // has finished simulating it. - itemItr = _hasSimulationOwnerEntities.begin(); + SetOfEntities::iterator itemItr = _hasSimulationOwnerEntities.begin(); while (itemItr != _hasSimulationOwnerEntities.end()) { EntityItem* entity = *itemItr; if (entity->getSimulatorID().isNull()) { itemItr = _hasSimulationOwnerEntities.erase(itemItr); - } else if (usecTimestampNow() - entity->getLastChangedOnServer() >= AUTO_REMOVE_SIMULATION_OWNER_USEC) { + } else if (now - entity->getLastChangedOnServer() >= AUTO_REMOVE_SIMULATION_OWNER_USEC) { qCDebug(entities) << "auto-removing simulation owner" << entity->getSimulatorID(); entity->setSimulatorID(QUuid()); itemItr = _hasSimulationOwnerEntities.erase(itemItr); @@ -50,16 +37,13 @@ void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { } void SimpleEntitySimulation::addEntityInternal(EntityItem* entity) { - if (entity->isMoving()) { - _movingEntities.insert(entity); - } + EntitySimulation::addEntityInternal(entity); if (!entity->getSimulatorID().isNull()) { _hasSimulationOwnerEntities.insert(entity); } } void SimpleEntitySimulation::removeEntityInternal(EntityItem* entity) { - _movingEntities.remove(entity); _hasSimulationOwnerEntities.remove(entity); clearEntitySimulation(entity); } @@ -67,22 +51,13 @@ void SimpleEntitySimulation::removeEntityInternal(EntityItem* entity) { const int SIMPLE_SIMULATION_DIRTY_FLAGS = EntityItem::DIRTY_VELOCITIES | EntityItem::DIRTY_MOTION_TYPE; void SimpleEntitySimulation::changeEntityInternal(EntityItem* entity) { - int dirtyFlags = entity->getDirtyFlags(); - if (dirtyFlags & SIMPLE_SIMULATION_DIRTY_FLAGS) { - if (entity->isMoving()) { - _movingEntities.insert(entity); - } else { - _movingEntities.remove(entity); - } - if (!entity->getSimulatorID().isNull()) { - _hasSimulationOwnerEntities.insert(entity); - } + if (!entity->getSimulatorID().isNull()) { + _hasSimulationOwnerEntities.insert(entity); } entity->clearDirtyFlags(); } void SimpleEntitySimulation::clearEntitiesInternal() { - _movingEntities.clear(); _hasSimulationOwnerEntities.clear(); } diff --git a/libraries/entities/src/SimpleEntitySimulation.h b/libraries/entities/src/SimpleEntitySimulation.h index 454d168556..3a6934adfa 100644 --- a/libraries/entities/src/SimpleEntitySimulation.h +++ b/libraries/entities/src/SimpleEntitySimulation.h @@ -28,7 +28,6 @@ protected: virtual void changeEntityInternal(EntityItem* entity); virtual void clearEntitiesInternal(); - SetOfEntities _movingEntities; SetOfEntities _hasSimulationOwnerEntities; }; diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index fe104e82ec..d8ed858b83 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -75,21 +75,6 @@ void PhysicalEntitySimulation::changeEntityInternal(EntityItem* entity) { } } -void PhysicalEntitySimulation::sortEntitiesThatMovedInternal() { - /* - // entities that have been simulated forward (hence in the _entitiesToSort list) - // also need to be put in the outgoingPackets list - QSet::iterator entityItr = _entitiesToSort.begin(); - for (auto entityItr : _entitiesToSort) { - EntityItem* entity = *entityItr; - void* physicsInfo = entity->getPhysicsInfo(); - assert(physicsInfo); - // BOOKMARK XXX -- Andrew to fix this next - _outgoingChanges.insert(static_cast(physicsInfo)); - } - */ -} - void PhysicalEntitySimulation::clearEntitiesInternal() { // TODO: we should probably wait to lock the _physicsEngine so we don't mess up data structures // while it is in the middle of a simulation step. As it is, we're probably in shutdown mode diff --git a/libraries/physics/src/PhysicalEntitySimulation.h b/libraries/physics/src/PhysicalEntitySimulation.h index 3cbebadd12..1b2689a020 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.h +++ b/libraries/physics/src/PhysicalEntitySimulation.h @@ -39,7 +39,6 @@ protected: // only called by EntitySimulation void addEntityInternal(EntityItem* entity); void removeEntityInternal(EntityItem* entity); void changeEntityInternal(EntityItem* entity); - void sortEntitiesThatMovedInternal(); void clearEntitiesInternal(); public: From 42ec39c578631011918fea091d02aa0e399218d0 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 1 May 2015 14:39:33 -0700 Subject: [PATCH 17/89] add ObjectMotionType::bump(), use in PhysicsEngine --- libraries/physics/src/EntityMotionState.cpp | 5 ++ libraries/physics/src/EntityMotionState.h | 2 + libraries/physics/src/ObjectMotionState.h | 2 + libraries/physics/src/PhysicsEngine.cpp | 85 +++++---------------- 4 files changed, 26 insertions(+), 68 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index d8fcc47b60..2ad2cf5c7d 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -390,6 +390,11 @@ uint32_t EntityMotionState::getIncomingDirtyFlags() const { */ } +// virtual +void EntityMotionState::bump() { + setShouldClaimSimulationOwnership(true); +} + void EntityMotionState::resetMeasuredBodyAcceleration() { _lastMeasureStep = ObjectMotionState::getWorldSimulationStep(); _lastVelocity = bulletToGLM(_body->getLinearVelocity()); diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index e00969e007..43e1f64c82 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -67,6 +67,8 @@ public: virtual const glm::vec3& getObjectAngularVelocity() const { return _entity->getAngularVelocity(); } virtual const glm::vec3& getObjectGravity() const { return _entity->getGravity(); } + virtual void bump(); + EntityItem* getEntity() const { return _entity; } void resetMeasuredBodyAcceleration(); diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 253ce57847..e885d46046 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -114,6 +114,8 @@ public: virtual const glm::vec3& getObjectAngularVelocity() const = 0; virtual const glm::vec3& getObjectGravity() const = 0; + virtual void bump() = 0; + friend class PhysicsEngine; protected: diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 1029dc064f..01f3b41604 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -381,86 +381,35 @@ void PhysicsEngine::dumpStatsIfNecessary() { // CF_DISABLE_VISUALIZE_OBJECT = 32, //disable debug drawing // CF_DISABLE_SPU_COLLISION_PROCESSING = 64//disable parallel/SPU processing -void PhysicsEngine::bump(ObjectMotionState* object) { - assert(object); - /* TODO: Andrew to implement this - // If this node is doing something like deleting an entity, scan for contacts involving the - // entity. For each found, flag the other entity involved as being simulated by this node. - 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()); - if (objectA && objectB) { - void* a = objectA->getUserPointer(); - void* b = objectB->getUserPointer(); - if (a && b) { - EntityMotionState* entityMotionStateA = static_cast(a); - EntityMotionState* entityMotionStateB = static_cast(b); - EntityItem* entityA = entityMotionStateA ? entityMotionStateA->getEntity() : nullptr; - EntityItem* entityB = entityMotionStateB ? entityMotionStateB->getEntity() : nullptr; - if (entityA && entityB) { - if (entityA == bumpEntity) { - entityMotionStateB->setShouldClaimSimulationOwnership(true); - if (!objectB->isActive()) { - objectB->setActivationState(ACTIVE_TAG); - } - } - if (entityB == bumpEntity) { - entityMotionStateA->setShouldClaimSimulationOwnership(true); - if (!objectA->isActive()) { - objectA->setActivationState(ACTIVE_TAG); - } - } - } - } - } - } - } - */ -} +void PhysicsEngine::bump(ObjectMotionState* motionState) { + // Find all objects that touch the object corresponding to motionState and flag the other objects + // for simulation ownership by the local simulation. + + assert(motionState); + btCollisionObject* object = motionState->getRigidBody(); -/* -// TODO: convert bump() to take an ObjectMotionState. -// Expose SimulationID to ObjectMotionState -void PhysicsEngine::bump(EntityItem* bumpEntity) { - // If this node is doing something like deleting an entity, scan for contacts involving the - // entity. For each found, flag the other entity involved as being simulated by this node. 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()); - if (objectA && objectB) { - void* a = objectA->getUserPointer(); - void* b = objectB->getUserPointer(); - if (a && b) { - EntityMotionState* entityMotionStateA = static_cast(a); - EntityMotionState* entityMotionStateB = static_cast(b); - EntityItem* entityA = entityMotionStateA ? entityMotionStateA->getEntity() : nullptr; - EntityItem* entityB = entityMotionStateB ? entityMotionStateB->getEntity() : nullptr; - if (entityA && entityB) { - if (entityA == bumpEntity) { - entityMotionStateB->setShouldClaimSimulationOwnership(true); - if (!objectB->isActive()) { - objectB->setActivationState(ACTIVE_TAG); - } - } - if (entityB == bumpEntity) { - entityMotionStateA->setShouldClaimSimulationOwnership(true); - if (!objectA->isActive()) { - objectA->setActivationState(ACTIVE_TAG); - } - } - } + if (objectB == object) { + ObjectMotionState* motionStateA = static_cast(objectA->getUserPointer()); + if (motionStateA) { + motionStateA->bump(); + objectA->setActivationState(ACTIVE_TAG); + } + } else if (objectA == object) { + ObjectMotionState* motionStateB = static_cast(objectB->getUserPointer()); + if (motionStateB) { + motionStateB->bump(); + objectB->setActivationState(ACTIVE_TAG); } } } } } -*/ void PhysicsEngine::setCharacterController(DynamicCharacterController* character) { if (_characterController != character) { From 0a102575ee5a10a485fdca7069966e331e2bd5ab Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 1 May 2015 16:56:00 -0700 Subject: [PATCH 18/89] fix simulation ownership infection --- interface/src/Application.cpp | 5 ++++ interface/src/Application.h | 1 + libraries/physics/src/PhysicsEngine.cpp | 39 +++++++------------------ libraries/physics/src/PhysicsEngine.h | 5 ++++ 4 files changed, 21 insertions(+), 29 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b34ab3ce79..f4496424ee 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -432,6 +432,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : connect(nodeList.data(), &NodeList::nodeKilled, this, &Application::nodeKilled); connect(nodeList.data(), SIGNAL(nodeKilled(SharedNodePointer)), SLOT(nodeKilled(SharedNodePointer))); connect(nodeList.data(), &NodeList::uuidChanged, _myAvatar, &MyAvatar::setSessionUUID); + connect(nodeList.data(), &NodeList::uuidChanged, this, &Application::setSessionUUID); connect(nodeList.data(), &NodeList::limitOfSilentDomainCheckInsReached, nodeList.data(), &NodeList::reset); connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch); @@ -3870,6 +3871,9 @@ bool Application::acceptURL(const QString& urlString) { return false; } +void Application::setSessionUUID(const QUuid& sessionUUID) { + _physicsEngine.setSessionUUID(sessionUUID); +} bool Application::askToSetAvatarUrl(const QString& url) { QUrl realUrl(url); @@ -4482,3 +4486,4 @@ void Application::friendsWindowClosed() { void Application::postLambdaEvent(std::function f) { QCoreApplication::postEvent(this, new LambdaEvent(f)); } + diff --git a/interface/src/Application.h b/interface/src/Application.h index 192b9cec25..b1c50250ea 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -351,6 +351,7 @@ signals: void beforeAboutToQuit(); public slots: + void setSessionUUID(const QUuid& sessionUUID); void domainChanged(const QString& domainHostname); void updateWindowTitle(); void nodeAdded(SharedNodePointer node); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 01f3b41604..92db98a03f 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -9,8 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include - #include "ObjectMotionState.h" #include "PhysicsEngine.h" #include "PhysicsHelpers.h" @@ -245,41 +243,24 @@ void PhysicsEngine::stepSimulation() { } void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB) { - /* TODO: Andrew to make this work for ObjectMotionState BT_PROFILE("ownershipInfection"); - assert(objectA); - assert(objectB); - - auto nodeList = DependencyManager::get(); - QUuid myNodeID = nodeList->getSessionUUID(); - const btCollisionObject* characterCollisionObject = - _characterController ? _characterController->getCollisionObject() : nullptr; - - assert(!myNodeID.isNull()); + if (_sessionID.isNull()) { + return; + } + const btCollisionObject* characterObject = _characterController ? _characterController->getCollisionObject() : nullptr; ObjectMotionState* a = static_cast(objectA->getUserPointer()); ObjectMotionState* b = static_cast(objectB->getUserPointer()); - EntityItem* entityA = a ? a->getEntity() : nullptr; - EntityItem* entityB = b ? b->getEntity() : nullptr; - bool aIsDynamic = entityA && !objectA->isStaticOrKinematicObject(); - bool bIsDynamic = entityB && !objectB->isStaticOrKinematicObject(); - // collisions cause infectious spread of simulation-ownership. we also attempt to take - // ownership of anything that collides with our avatar. - if ((aIsDynamic && (entityA->getSimulatorID() == myNodeID)) || - // (a && a->getShouldClaimSimulationOwnership()) || - (objectA == characterCollisionObject)) { - if (bIsDynamic) { - b->setShouldClaimSimulationOwnership(true); + if (b && ((a && !objectA->isStaticOrKinematicObject()) || (objectA == characterObject))) { + if (!objectB->isStaticOrKinematicObject()) { + b->bump(); } - } else if ((bIsDynamic && (entityB->getSimulatorID() == myNodeID)) || - // (b && b->getShouldClaimSimulationOwnership()) || - (objectB == characterCollisionObject)) { - if (aIsDynamic) { - a->setShouldClaimSimulationOwnership(true); + } else if (a && ((b && !objectB->isStaticOrKinematicObject()) || (objectB == characterObject))) { + if (!objectA->isStaticOrKinematicObject()) { + a->bump(); } } - */ } void PhysicsEngine::computeCollisionEvents() { diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index b05ebd05db..c470bc0331 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -14,6 +14,7 @@ #include +#include #include #include #include @@ -51,6 +52,8 @@ public: ~PhysicsEngine(); void init(); + void setSessionUUID(const QUuid& sessionID) { _sessionID = sessionID; } + void addObject(ObjectMotionState* motionState); void removeObject(ObjectMotionState* motionState); @@ -106,6 +109,8 @@ private: bool _dumpNextStats = false; bool _hasOutgoingChanges = false; + + QUuid _sessionID; }; #endif // hifi_PhysicsEngine_h From 35ed755b138785db58b1c2083071c356eda947b4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sun, 3 May 2015 09:26:28 -0700 Subject: [PATCH 19/89] make EntityItem::getID() const --- libraries/entities/src/EntityItem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 4250d10da8..5e3e94b272 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -75,7 +75,7 @@ public: virtual ~EntityItem(); // ID and EntityItemID related methods - QUuid getID() const { return _id; } + const QUuid& getID() const { return _id; } void setID(const QUuid& id) { _id = id; } uint32_t getCreatorTokenID() const { return _creatorTokenID; } void setCreatorTokenID(uint32_t creatorTokenID) { _creatorTokenID = creatorTokenID; } From cb37b884d2a7806001940beb3da15d3ee9d6b808 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sun, 3 May 2015 09:26:49 -0700 Subject: [PATCH 20/89] add ObjectMotionState::getObjectID() --- libraries/physics/src/EntityMotionState.h | 2 ++ libraries/physics/src/ObjectMotionState.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 43e1f64c82..d407fd8ae8 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -67,6 +67,8 @@ public: virtual const glm::vec3& getObjectAngularVelocity() const { return _entity->getAngularVelocity(); } virtual const glm::vec3& getObjectGravity() const { return _entity->getGravity(); } + virtual const QUuid& getObjectID() const { return _entity->getID(); } + virtual void bump(); EntityItem* getEntity() const { return _entity; } diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index e885d46046..d0dc9afc88 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -114,6 +114,8 @@ public: virtual const glm::vec3& getObjectAngularVelocity() const = 0; virtual const glm::vec3& getObjectGravity() const = 0; + virtual const QUuid& getObjectID() const = 0; + virtual void bump() = 0; friend class PhysicsEngine; From fef84730bf4b22810ebfa029d095c49d6f06d79d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sun, 3 May 2015 09:27:15 -0700 Subject: [PATCH 21/89] remake foundation for CollisionEvents --- interface/src/Application.cpp | 1 + .../physics/src/PhysicalEntitySimulation.cpp | 4 +- .../physics/src/PhysicalEntitySimulation.h | 5 +-- libraries/physics/src/PhysicsEngine.cpp | 42 ++++++++----------- libraries/physics/src/PhysicsEngine.h | 28 +++++++++++-- 5 files changed, 48 insertions(+), 32 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f4496424ee..30a248e64d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2386,6 +2386,7 @@ void Application::update(float deltaTime) { if (_physicsEngine.hasOutgoingChanges()) { _entitySimulation.handleOutgoingChanges(_physicsEngine.getOutgoingChanges()); + _entitySimulation.handleCollisionEvents(_physicsEngine.getCollisionEvents()); _physicsEngine.dumpStatsIfNecessary(); } } diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index d8ed858b83..0f76613cb3 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -11,7 +11,6 @@ #include "EntityMotionState.h" #include "PhysicalEntitySimulation.h" -#include "PhysicsEngine.h" #include "PhysicsHelpers.h" #include "PhysicsLogging.h" #include "ShapeInfoUtil.h" @@ -189,6 +188,7 @@ void PhysicalEntitySimulation::handleOutgoingChanges(VectorOfMotionStates& motio } } -void PhysicalEntitySimulation::bump(EntityItem* bumpEntity) { +void PhysicalEntitySimulation::handleCollisionEvents(CollisionEvents& collisionEvents) { + // BOOKMARK TODO: emit events } diff --git a/libraries/physics/src/PhysicalEntitySimulation.h b/libraries/physics/src/PhysicalEntitySimulation.h index 1b2689a020..b7c091df82 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.h +++ b/libraries/physics/src/PhysicalEntitySimulation.h @@ -20,10 +20,10 @@ #include #include +#include "PhysicsEngine.h" #include "PhysicsTypedefs.h" class EntityMotionState; -class PhysicsEngine; class ShapeManager; class PhysicalEntitySimulation :public EntitySimulation { @@ -47,10 +47,9 @@ public: VectorOfMotionStates& getObjectsToChange(); void handleOutgoingChanges(VectorOfMotionStates& motionStates); + void handleCollisionEvents(CollisionEvents& collisionEvents); private: - void bump(EntityItem* bumpEntity); - // incoming changes SetOfEntities _pendingRemoves; // entities to be removed from PhysicsEngine (and their MotionState deleted) SetOfEntities _pendingAdds; // entities to be be added to PhysicsEngine (and a their MotionState created) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 92db98a03f..2ff2347f86 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -237,12 +237,13 @@ void PhysicsEngine::stepSimulation() { if (_characterController) { _characterController->postSimulation(); } - computeCollisionEvents(); + updateContactMap(); _hasOutgoingChanges = true; } } void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB) { + // BOOKMARK TODO: move this to PhysicalEntitySimulation BT_PROFILE("ownershipInfection"); if (_sessionID.isNull()) { return; @@ -263,8 +264,9 @@ void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const } } -void PhysicsEngine::computeCollisionEvents() { - BT_PROFILE("computeCollisionEvents"); +void PhysicsEngine::updateContactMap() { + BT_PROFILE("updateContactMap"); + ++_numContactFrames; // update all contacts every frame int numManifolds = _collisionDispatcher->getNumManifolds(); @@ -292,39 +294,31 @@ void PhysicsEngine::computeCollisionEvents() { doOwnershipInfection(objectA, objectB); } } - - fireCollisionEvents(); - ++_numContactFrames; } -void PhysicsEngine::fireCollisionEvents() { - /* TODO: Andrew to make this work for ObjectMotionStates +CollisionEvents& PhysicsEngine::getCollisionEvents() { const uint32_t CONTINUE_EVENT_FILTER_FREQUENCY = 10; + _collisionEvents.clear(); // 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); - - // 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. - // TODO: enable scripts to filter based on contact event type ContactEventType type = contactItr->second.computeType(_numContactFrames); - if(type != CONTACT_EVENT_TYPE_CONTINUE || _numSubsteps % CONTINUE_EVENT_FILTER_FREQUENCY == 0){ + if(type != CONTACT_EVENT_TYPE_CONTINUE || _numSubsteps % CONTINUE_EVENT_FILTER_FREQUENCY == 0) { + ObjectMotionState* A = static_cast(contactItr->first._a); + ObjectMotionState* B = static_cast(contactItr->first._b); + if (A && A->getType() == MOTION_STATE_TYPE_ENTITY) { - EntityItemID idA = static_cast(A)->getEntity()->getEntityItemID(); - EntityItemID idB; + QUuid idA = A->getObjectID(); + QUuid idB; if (B && B->getType() == MOTION_STATE_TYPE_ENTITY) { - idB = static_cast(B)->getEntity()->getEntityItemID(); + idB = B->getObjectID(); } - emit entityCollisionWithEntity(idA, idB, contactItr->second); + _collisionEvents.push_back(CollisionEvent(type, idA, idB)); } else if (B && B->getType() == MOTION_STATE_TYPE_ENTITY) { - EntityItemID idA; - EntityItemID idB = static_cast(B)->getEntity()->getEntityItemID(); - emit entityCollisionWithEntity(idA, idB, contactItr->second); + QUuid idB = B->getObjectID(); + _collisionEvents.push_back(CollisionEvent(type, idB, QUuid())); } } @@ -336,7 +330,7 @@ void PhysicsEngine::fireCollisionEvents() { ++contactItr; } } - */ + return _collisionEvents; } VectorOfMotionStates& PhysicsEngine::getOutgoingChanges() { diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index c470bc0331..91b871f49c 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -41,7 +41,21 @@ public: }; typedef std::map ContactMap; -typedef std::pair ContactMapElement; + +class CollisionEvent { +public: + CollisionEvent() : _type(CONTACT_EVENT_TYPE_START), _idA(), _idB() {} + CollisionEvent(ContactEventType type, const QUuid& idA, const QUuid& idB) : _type(type), _idA(idA), _idB(idB) {} + + ContactEventType _type; // START, CONTINUE, or END + QUuid _idA; + QUuid _idB; + // TODO: add is info to contact callback + //glm::vec3 _position; // world-frame + //glm::vec3 _normal; // world-frame +}; + +typedef QVector CollisionEvents; class PhysicsEngine { public: @@ -64,11 +78,17 @@ public: void reinsertObject(ObjectMotionState* object); void stepSimulation(); - void computeCollisionEvents(); - void fireCollisionEvents(); + void updateContactMap(); bool hasOutgoingChanges() const { return _hasOutgoingChanges; } + + /// \return reference to list of changed MotionStates. The list is only valid until beginning of next simulation loop. VectorOfMotionStates& getOutgoingChanges(); + + /// \return reference to list of CollisionEvent's. The list is only valid until beginning of next simulation loop. + CollisionEvents& getCollisionEvents(); + + /// \brief prints timings for last frame if stats have been requested. void dumpStatsIfNecessary(); /// \param offset position of simulation origin in domain-frame @@ -77,6 +97,7 @@ public: /// \return position of simulation origin in domain-frame const glm::vec3& getOriginOffset() const { return _originOffset; } + /// \brief call bump on any objects that touch the object corresponding to motionState void bump(ObjectMotionState* motionState); void removeRigidBody(btRigidBody* body); @@ -111,6 +132,7 @@ private: bool _hasOutgoingChanges = false; QUuid _sessionID; + CollisionEvents _collisionEvents; }; #endif // hifi_PhysicsEngine_h From 96acf96b76e8bb1e70ccf1b613e8075df833f411 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 4 May 2015 13:32:57 -0700 Subject: [PATCH 22/89] entity-entity collision events emit signals again --- libraries/physics/src/ContactInfo.cpp | 10 ++++------ libraries/physics/src/ContactInfo.h | 17 +++++++++-------- .../physics/src/PhysicalEntitySimulation.cpp | 8 +++++++- libraries/physics/src/PhysicsEngine.cpp | 15 +++++++++++---- libraries/physics/src/PhysicsEngine.h | 18 ++---------------- libraries/shared/src/RegisteredMetaTypes.cpp | 3 +++ libraries/shared/src/RegisteredMetaTypes.h | 17 ++++++++++++++--- 7 files changed, 50 insertions(+), 38 deletions(-) diff --git a/libraries/physics/src/ContactInfo.cpp b/libraries/physics/src/ContactInfo.cpp index 71887b2dc9..c2ea6e8671 100644 --- a/libraries/physics/src/ContactInfo.cpp +++ b/libraries/physics/src/ContactInfo.cpp @@ -9,16 +9,14 @@ // 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) { +void ContactInfo::update(uint32_t currentStep, const btManifoldPoint& p) { _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); + positionWorldOnB = p.m_positionWorldOnB; + normalWorldOnB = p.m_normalWorldOnB; + distance = p.m_distance1; } ContactEventType ContactInfo::computeType(uint32_t thisStep) { diff --git a/libraries/physics/src/ContactInfo.h b/libraries/physics/src/ContactInfo.h index 2c3c3a1e6f..11c908a414 100644 --- a/libraries/physics/src/ContactInfo.h +++ b/libraries/physics/src/ContactInfo.h @@ -17,17 +17,18 @@ #include "RegisteredMetaTypes.h" -enum ContactEventType { - CONTACT_EVENT_TYPE_START, - CONTACT_EVENT_TYPE_CONTINUE, - CONTACT_EVENT_TYPE_END -}; -class ContactInfo : public Collision -{ +class ContactInfo { public: - void update(uint32_t currentStep, btManifoldPoint& p, const glm::vec3& worldOffset); + void update(uint32_t currentStep, const btManifoldPoint& p); ContactEventType computeType(uint32_t thisStep); + + const btVector3& getPositionWorldOnB() const { return positionWorldOnB; } + btVector3 getPositionWorldOnA() const { return positionWorldOnB + normalWorldOnB * distance; } + + btVector3 positionWorldOnB; + btVector3 normalWorldOnB; + btScalar distance; private: uint32_t _lastStep = 0; uint32_t _numSteps = 0; diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index 0f76613cb3..ae7a2eaf1a 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -189,6 +189,12 @@ void PhysicalEntitySimulation::handleOutgoingChanges(VectorOfMotionStates& motio } void PhysicalEntitySimulation::handleCollisionEvents(CollisionEvents& collisionEvents) { - // BOOKMARK TODO: emit events + for (auto collision : collisionEvents) { + // NOTE: The collision event is always aligned such that idA is never NULL. + // however idB may be NULL. + if (!collision.idB.isNull()) { + emit entityCollisionWithEntity(collision.idA, collision.idB, collision); + } + } } diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 2ff2347f86..e148daced2 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -288,7 +288,7 @@ void PhysicsEngine::updateContactMap() { ObjectMotionState* b = static_cast(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(_numContactFrames, contactManifold->getContactPoint(0), _originOffset); + _contactMap[ContactKey(a, b)].update(_numContactFrames, contactManifold->getContactPoint(0)); } doOwnershipInfection(objectA, objectB); @@ -304,7 +304,8 @@ CollisionEvents& PhysicsEngine::getCollisionEvents() { ContactMap::iterator contactItr = _contactMap.begin(); while (contactItr != _contactMap.end()) { - ContactEventType type = contactItr->second.computeType(_numContactFrames); + ContactInfo& contact = contactItr->second; + ContactEventType type = contact.computeType(_numContactFrames); if(type != CONTACT_EVENT_TYPE_CONTINUE || _numSubsteps % CONTINUE_EVENT_FILTER_FREQUENCY == 0) { ObjectMotionState* A = static_cast(contactItr->first._a); ObjectMotionState* B = static_cast(contactItr->first._b); @@ -315,10 +316,16 @@ CollisionEvents& PhysicsEngine::getCollisionEvents() { if (B && B->getType() == MOTION_STATE_TYPE_ENTITY) { idB = B->getObjectID(); } - _collisionEvents.push_back(CollisionEvent(type, idA, idB)); + glm::vec3 position = bulletToGLM(contact.getPositionWorldOnB()) + _originOffset; + glm::vec3 penetration = bulletToGLM(contact.distance * contact.normalWorldOnB); + _collisionEvents.push_back(Collision(type, idA, idB, position, penetration)); } else if (B && B->getType() == MOTION_STATE_TYPE_ENTITY) { QUuid idB = B->getObjectID(); - _collisionEvents.push_back(CollisionEvent(type, idB, QUuid())); + glm::vec3 position = bulletToGLM(contact.getPositionWorldOnA()) + _originOffset; + // NOTE: we're flipping the order of A and B (so that the first objectID is never NULL) + // hence we must negate the penetration. + glm::vec3 penetration = - bulletToGLM(contact.distance * contact.normalWorldOnB); + _collisionEvents.push_back(Collision(type, idB, QUuid(), position, penetration)); } } diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 91b871f49c..a5a1d4ac10 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -41,21 +41,7 @@ public: }; typedef std::map ContactMap; - -class CollisionEvent { -public: - CollisionEvent() : _type(CONTACT_EVENT_TYPE_START), _idA(), _idB() {} - CollisionEvent(ContactEventType type, const QUuid& idA, const QUuid& idB) : _type(type), _idA(idA), _idB(idB) {} - - ContactEventType _type; // START, CONTINUE, or END - QUuid _idA; - QUuid _idB; - // TODO: add is info to contact callback - //glm::vec3 _position; // world-frame - //glm::vec3 _normal; // world-frame -}; - -typedef QVector CollisionEvents; +typedef QVector CollisionEvents; class PhysicsEngine { public: @@ -85,7 +71,7 @@ public: /// \return reference to list of changed MotionStates. The list is only valid until beginning of next simulation loop. VectorOfMotionStates& getOutgoingChanges(); - /// \return reference to list of CollisionEvent's. The list is only valid until beginning of next simulation loop. + /// \return reference to list of Collision events. The list is only valid until beginning of next simulation loop. CollisionEvents& getCollisionEvents(); /// \brief prints timings for last frame if stats have been requested. diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index 4099384aea..8c9d0c27bd 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -187,6 +187,9 @@ void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay) { QScriptValue collisionToScriptValue(QScriptEngine* engine, const Collision& collision) { QScriptValue obj = engine->newObject(); + obj.setProperty("type", collision.type); + obj.setProperty("idA", quuidToScriptValue(engine, collision.idA)); + obj.setProperty("idB", quuidToScriptValue(engine, collision.idB)); obj.setProperty("penetration", vec3toScriptValue(engine, collision.penetration)); obj.setProperty("contactPoint", vec3toScriptValue(engine, collision.contactPoint)); return obj; diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index ca4898b65c..14f30c20fc 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -13,6 +13,7 @@ #define hifi_RegisteredMetaTypes_h #include +#include #include #include @@ -65,11 +66,21 @@ Q_DECLARE_METATYPE(PickRay) QScriptValue pickRayToScriptValue(QScriptEngine* engine, const PickRay& pickRay); void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay); +enum ContactEventType { + CONTACT_EVENT_TYPE_START, + CONTACT_EVENT_TYPE_CONTINUE, + CONTACT_EVENT_TYPE_END +}; + class Collision { public: - Collision() : contactPoint(0.0f), penetration(0.0f) { } - Collision(const glm::vec3& contactPoint, const glm::vec3& penetration) : - contactPoint(contactPoint), penetration(penetration) { } + Collision() : type(CONTACT_EVENT_TYPE_START), idA(), idB(), contactPoint(0.0f), penetration(0.0f) { } + Collision(ContactEventType cType, const QUuid& cIdA, const QUuid& cIdB, const glm::vec3& cPoint, const glm::vec3& cPenetration) + : type(cType), idA(cIdA), idB(cIdB), contactPoint(cPoint), penetration(cPenetration) { } + + ContactEventType type; + QUuid idA; + QUuid idB; glm::vec3 contactPoint; glm::vec3 penetration; }; From 0932682c2a343c273b35fcd77e34fcd3f71eb2f4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 4 May 2015 13:35:36 -0700 Subject: [PATCH 23/89] remove comment --- libraries/physics/src/PhysicsEngine.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index e148daced2..6deba06334 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -243,7 +243,6 @@ void PhysicsEngine::stepSimulation() { } void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB) { - // BOOKMARK TODO: move this to PhysicalEntitySimulation BT_PROFILE("ownershipInfection"); if (_sessionID.isNull()) { return; From 066e36c3e7e16933e06783f9bfbbc43bebf33bfb Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 4 May 2015 16:52:36 -0700 Subject: [PATCH 24/89] fix crash bugs (don't reference NULL pointers) --- libraries/physics/src/EntityMotionState.cpp | 10 ++++++---- libraries/physics/src/PhysicalEntitySimulation.cpp | 4 +++- libraries/physics/src/ThreadSafeDynamicsWorld.cpp | 12 ++++++++---- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 2ad2cf5c7d..30e4de7e11 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -375,8 +375,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ } uint32_t EntityMotionState::getIncomingDirtyFlags() const { - return _entity->getDirtyFlags(); -/* TODO: reimplement this motion-type adjustment + uint32_t dirtyFlags = _entity->getDirtyFlags(); if (_body) { // we add DIRTY_MOTION_TYPE if the body's motion type disagrees with entity velocity settings int bodyFlags = _body->getCollisionFlags(); @@ -387,7 +386,6 @@ uint32_t EntityMotionState::getIncomingDirtyFlags() const { } } return dirtyFlags; -*/ } // virtual @@ -397,7 +395,11 @@ void EntityMotionState::bump() { void EntityMotionState::resetMeasuredBodyAcceleration() { _lastMeasureStep = ObjectMotionState::getWorldSimulationStep(); - _lastVelocity = bulletToGLM(_body->getLinearVelocity()); + if (_body) { + _lastVelocity = bulletToGLM(_body->getLinearVelocity()); + } else { + _lastVelocity = glm::vec3(0.0f); + } _measuredAcceleration = glm::vec3(0.0f); } diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index ae7a2eaf1a..5db5697b1d 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -84,6 +84,7 @@ void PhysicalEntitySimulation::clearEntitiesInternal() { EntityMotionState* motionState = static_cast(&(*stateItr)); EntityItem* entity = motionState->getEntity(); entity->setPhysicsInfo(nullptr); + clearEntitySimulation(entity); } // then delete the objects (aka MotionStates) @@ -113,6 +114,7 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToDelete() { entity->setPhysicsInfo(nullptr); _tempVector.push_back(motionState); } + clearEntitySimulation(entity); } _pendingRemoves.clear(); return _tempVector; @@ -161,7 +163,7 @@ void PhysicalEntitySimulation::handleOutgoingChanges(VectorOfMotionStates& motio // walk the motionStates looking for those that correspond to entities for (auto stateItr : motionStates) { ObjectMotionState* state = &(*stateItr); - if (state->getType() == MOTION_STATE_TYPE_ENTITY) { + if (state && state->getType() == MOTION_STATE_TYPE_ENTITY) { EntityMotionState* entityState = static_cast(state); _outgoingChanges.insert(entityState); _entitiesToSort.insert(entityState->getEntity()); diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp index 7774f277b6..a2d3ee97d3 100644 --- a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp @@ -95,8 +95,10 @@ void ThreadSafeDynamicsWorld::synchronizeMotionStates() { btCollisionObject* colObj = m_collisionObjects[i]; btRigidBody* body = btRigidBody::upcast(colObj); if (body) { - synchronizeSingleMotionState(body); - _changedMotionStates.push_back(static_cast(body->getMotionState())); + if (body->getMotionState()) { + synchronizeSingleMotionState(body); + _changedMotionStates.push_back(static_cast(body->getMotionState())); + } } } } else { @@ -104,8 +106,10 @@ void ThreadSafeDynamicsWorld::synchronizeMotionStates() { for (int i=0;iisActive()) { - synchronizeSingleMotionState(body); - _changedMotionStates.push_back(static_cast(body->getMotionState())); + if (body->getMotionState()) { + synchronizeSingleMotionState(body); + _changedMotionStates.push_back(static_cast(body->getMotionState())); + } } } } From e38bfaa48c8658ccf5ed704399563da4f2a6d7c0 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 5 May 2015 10:09:07 -0700 Subject: [PATCH 25/89] allow for EntitityMotionState::_entity to be NULL --- .../physics/src/PhysicalEntitySimulation.cpp | 98 ++++++++++++------- .../physics/src/PhysicalEntitySimulation.h | 12 ++- 2 files changed, 70 insertions(+), 40 deletions(-) diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index 5db5697b1d..166c858851 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -47,30 +47,57 @@ void PhysicalEntitySimulation::updateEntitiesInternal(const quint64& now) { void PhysicalEntitySimulation::addEntityInternal(EntityItem* entity) { assert(entity); - void* physicsInfo = entity->getPhysicsInfo(); - if (!physicsInfo) { - _pendingAdds.insert(entity); + if (entity->getIgnoreForCollisions() && entity->isMoving()) { + std::cout << "adebug addEntityInternal for NPK entity " << (void*)(entity) << std::endl; // adebug + _simpleKinematicEntities.insert(entity); + } else { + EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); + if (!motionState) { + std::cout << "adebug addEntityInternal for entity " << (void*)(entity) << std::endl; // adebug + _pendingAdds.insert(entity); + } else { + // Adding entity already in simulation? assert that this is case, + // since otherwise we probably have an orphaned EntityMotionState. + std::cout << "adebug WTF? re-adding entity " << (void*)(entity) << std::endl; // adebug + assert(_physicalObjects.find(motionState) != _physicalObjects.end()); + } } } void PhysicalEntitySimulation::removeEntityInternal(EntityItem* entity) { - if (entity->getPhysicsInfo()) { - _pendingRemoves.insert(entity); + EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); + if (motionState) { + motionState->clearEntity(); + entity->setPhysicsInfo(nullptr); + _pendingRemoves.insert(motionState); } } void PhysicalEntitySimulation::changeEntityInternal(EntityItem* entity) { // queue incoming changes: from external sources (script, EntityServer, etc) to physics engine assert(entity); - void* physicsInfo = entity->getPhysicsInfo(); - if (physicsInfo) { - _pendingChanges.insert(entity); - } else { - if (!entity->getIgnoreForCollisions()) { - // The intent is for this object to be in the PhysicsEngine. - // Perhaps it's shape has changed and it can now be added? - _pendingAdds.insert(entity); + EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); + if (motionState) { + if (entity->getIgnoreForCollisions()) { + // the entity should be removed from the physical simulation + _pendingChanges.remove(motionState); + _physicalObjects.remove(motionState); + _pendingRemoves.insert(motionState); + if (entity->isMoving()) { + _simpleKinematicEntities.insert(entity); + } + } else { + _pendingChanges.insert(motionState); } + } else if (!entity->getIgnoreForCollisions()) { + // The intent is for this object to be in the PhysicsEngine. + // Perhaps it's shape has changed and it can now be added? + _pendingAdds.insert(entity); + _simpleKinematicEntities.remove(entity); // just in case it's non-physical-kinematic + } else if (entity->isMoving()) { + _simpleKinematicEntities.insert(entity); + } else { + _simpleKinematicEntities.remove(entity); // just in case it's non-physical-kinematic } } @@ -83,8 +110,10 @@ void PhysicalEntitySimulation::clearEntitiesInternal() { for (auto stateItr : _physicalObjects) { EntityMotionState* motionState = static_cast(&(*stateItr)); EntityItem* entity = motionState->getEntity(); - entity->setPhysicsInfo(nullptr); - clearEntitySimulation(entity); + if (entity) { + entity->setPhysicsInfo(nullptr); + } + motionState->clearEntity(); } // then delete the objects (aka MotionStates) @@ -101,20 +130,19 @@ void PhysicalEntitySimulation::clearEntitiesInternal() { VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToDelete() { _tempVector.clear(); - for (auto entityItr : _pendingRemoves) { - EntityItem* entity = &(*entityItr); - _pendingAdds.remove(entity); - _pendingChanges.remove(entity); - EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); - if (motionState) { - _physicalObjects.remove(motionState); - // disconnect EntityMotionState from its Entity - // NOTE: EntityMotionState still has a back pointer to its Entity, but is about to be deleted - // (by PhysicsEngine) and shouldn't actually access its Entity during this process. + for (auto stateItr : _pendingRemoves) { + EntityMotionState* motionState = &(*stateItr); + _pendingChanges.remove(motionState); + _physicalObjects.remove(motionState); + + EntityItem* entity = motionState->getEntity(); + if (entity) { + _pendingAdds.remove(entity); + std::cout << "adebug disconnect MotionState " << (void*)(motionState) << " from entity " << (void*)(entity) << std::endl; // adebug entity->setPhysicsInfo(nullptr); - _tempVector.push_back(motionState); + motionState->clearEntity(); } - clearEntitySimulation(entity); + _tempVector.push_back(motionState); } _pendingRemoves.clear(); return _tempVector; @@ -126,13 +154,16 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToAdd() { while (entityItr != _pendingAdds.end()) { EntityItem* entity = *entityItr; assert(!entity->getPhysicsInfo()); - - if (entity->isReadyToComputeShape()) { + if (entity->getIgnoreForCollisions()) { + // this entity should no longer be on the internal _pendingAdds + entityItr = _pendingAdds.erase(entityItr); + } else if (entity->isReadyToComputeShape()) { ShapeInfo shapeInfo; entity->computeShapeInfo(shapeInfo); btCollisionShape* shape = _shapeManager->getShape(shapeInfo); if (shape) { EntityMotionState* motionState = new EntityMotionState(shape, entity); + std::cout << "adebug create MotionState " << (void*)(motionState) << " for entity " << (void*)(entity) << std::endl; // adebug entity->setPhysicsInfo(static_cast(motionState)); motionState->setMass(entity->computeMass()); _physicalObjects.insert(motionState); @@ -148,12 +179,9 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToAdd() { VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToChange() { _tempVector.clear(); - for (auto entityItr : _pendingChanges) { - EntityItem* entity = &(*entityItr); - ObjectMotionState* motionState = static_cast(entity->getPhysicsInfo()); - if (motionState) { - _tempVector.push_back(motionState); - } + for (auto stateItr : _pendingChanges) { + EntityMotionState* motionState = &(*stateItr); + _tempVector.push_back(motionState); } _pendingChanges.clear(); return _tempVector; diff --git a/libraries/physics/src/PhysicalEntitySimulation.h b/libraries/physics/src/PhysicalEntitySimulation.h index b7c091df82..64ab1bf011 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.h +++ b/libraries/physics/src/PhysicalEntitySimulation.h @@ -26,6 +26,8 @@ class EntityMotionState; class ShapeManager; +typedef QSet SetOfEntityMotionStates; + class PhysicalEntitySimulation :public EntitySimulation { public: PhysicalEntitySimulation(); @@ -51,15 +53,15 @@ public: private: // incoming changes - SetOfEntities _pendingRemoves; // entities to be removed from PhysicsEngine (and their MotionState deleted) - SetOfEntities _pendingAdds; // entities to be be added to PhysicsEngine (and a their MotionState created) - SetOfEntities _pendingChanges; // entities already in PhysicsEngine that need their physics changed + SetOfEntityMotionStates _pendingRemoves; // EntityMotionStates to be removed from PhysicsEngine (and deleted) + SetOfEntities _pendingAdds; // entities to be be added to PhysicsEngine (and a their EntityMotionState created) + SetOfEntityMotionStates _pendingChanges; // EntityMotionStates already in PhysicsEngine that need their physics changed // outgoing changes - QSet _outgoingChanges; // entities for which we need to send updates to entity-server + QSet _outgoingChanges; // EntityMotionStates for which we need to send updates to entity-server SetOfMotionStates _physicalObjects; // MotionStates of entities in PhysicsEngine - VectorOfMotionStates _tempVector; // temporary array, valid by reference immediately after call to getObjectsToRemove/Add/Update() + VectorOfMotionStates _tempVector; // temporary array reference, valid immediately after getObjectsToRemove() (and friends) ShapeManager* _shapeManager = nullptr; PhysicsEngine* _physicsEngine = nullptr; From d5f4c5a0ef9f43bbcb5e913995a630ed4dc5a9c4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 5 May 2015 10:10:08 -0700 Subject: [PATCH 26/89] add/delete/cleanup of physical entities works --- libraries/entities/src/EntityItem.cpp | 5 +- libraries/entities/src/EntityItem.h | 3 +- libraries/entities/src/EntitySimulation.cpp | 162 +++++++++--------- libraries/entities/src/EntitySimulation.h | 16 +- libraries/entities/src/EntityTree.cpp | 37 ++-- libraries/entities/src/EntityTree.h | 6 +- .../entities/src/SimpleEntitySimulation.cpp | 1 - 7 files changed, 110 insertions(+), 120 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index f94efef4be..4d3321674a 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -63,7 +63,8 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : _simulatorID(ENTITY_ITEM_DEFAULT_SIMULATOR_ID), _simulatorIDChangedTime(0), _marketplaceID(ENTITY_ITEM_DEFAULT_MARKETPLACE_ID), - _dirtyFlags(0) + _dirtyFlags(0), + _simulated(false) { quint64 now = usecTimestampNow(); _lastSimulated = now; @@ -78,8 +79,8 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert EntityItem::~EntityItem() { // these pointers MUST be NULL at delete, else we probably have a dangling backpointer // to this EntityItem in the corresponding data structure. + assert(!_simulated); assert(!_element); - assert(!_simulation); assert(!_physicsInfo); } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 5e3e94b272..c82c993e0f 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -305,7 +305,6 @@ public: void setPhysicsInfo(void* data) { _physicsInfo = data; } EntityTreeElement* getElement() const { return _element; } - EntitySimulation* getSimulation() const { return _simulation; } static void setSendPhysicsUpdates(bool value) { _sendPhysicsUpdates = value; } static bool getSendPhysicsUpdates() { return _sendPhysicsUpdates; } @@ -380,8 +379,8 @@ protected: // these backpointers are only ever set/cleared by friends: EntityTreeElement* _element = nullptr; // set by EntityTreeElement - EntitySimulation* _simulation = nullptr; // set by EntitySimulation void* _physicsInfo = nullptr; // set by EntitySimulation + bool _simulated; // set by EntitySimulation }; diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index e7dd208cc7..4300bacafa 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -37,28 +37,20 @@ void EntitySimulation::updateEntities() { sortEntitiesThatMoved(); } -void EntitySimulation::getEntitiesToDelete(SetOfEntities& entitiesToDelete) { - SetOfEntities::iterator entityItr = _entitiesToDelete.begin(); - while (entityItr != _entitiesToDelete.end()) { - EntityItem* entity = *entityItr; - if (entity->_simulation != this) { - if (entity->_element) { - // this entity is still in its tree, so we insert into the external list - entitiesToDelete.insert(entity); - } else { - // no more backpointers, so it should be safe to delete - delete entity; - } - // we're done with the entity in this context, so remove it from our internal list - entityItr = _entitiesToDelete.erase(entityItr); - } else { - // internal cleanup will happen later (probably in updateEntitiesInternal()) - ++entityItr; - } +void EntitySimulation::getEntitiesToDelete(VectorOfEntities& entitiesToDelete) { + static int adebug = 0; ++adebug; + for (auto entityItr : _entitiesToDelete) { + EntityItem* entity = &(*entityItr); + // this entity is still in its tree, so we insert into the external list + std::cout << "adebug EntitySimulation relays entityToDelete " << (void*)(entity) << " this = " << (void*)(this) << std::endl; // adebug + entitiesToDelete.push_back(entity); + ++entityItr; } + _entitiesToDelete.clear(); } void EntitySimulation::addEntityInternal(EntityItem* entity) { + entity->_simulated = true; if (entity->isMoving() && !entity->getPhysicsInfo()) { _simpleKinematicEntities.insert(entity); } @@ -87,7 +79,9 @@ void EntitySimulation::expireMortalEntities(const quint64& now) { _entitiesToUpdate.remove(entity); _entitiesToSort.remove(entity); _simpleKinematicEntities.remove(entity); + std::cout << "adebug expireMortalEntities " << (void*)(entity) << std::endl; // adebug removeEntityInternal(entity); + entity->_simulated = false; } else { if (expiry < _nextExpiry) { // remeber the smallest _nextExpiry so we know when to start the next search @@ -134,7 +128,9 @@ void EntitySimulation::sortEntitiesThatMoved() { _mortalEntities.remove(entity); _entitiesToUpdate.remove(entity); _simpleKinematicEntities.remove(entity); + std::cout << "adebug entity moved out of bounds " << (void*)(entity) << std::endl; // adebug removeEntityInternal(entity); + entity->_simulated = false; itemItr = _entitiesToSort.erase(itemItr); } else { moveOperator.addEntityToMoveList(entity, newCube); @@ -150,83 +146,90 @@ void EntitySimulation::sortEntitiesThatMoved() { } void EntitySimulation::addEntity(EntityItem* entity) { + //static int foo = 0; foo++; assert(entity); - if (!entity->_simulation) { - entity->_simulation = this; - if (entity->isMortal()) { - _mortalEntities.insert(entity); - quint64 expiry = entity->getExpiry(); - if (expiry < _nextExpiry) { - _nextExpiry = expiry; - } + std::cout << "adebug EntitySimulation addEntity " << (void*)(entity) << std::endl; // adebug + //if (foo > 1) { + // //assert(false); // adebug + //} + if (entity->isMortal()) { + _mortalEntities.insert(entity); + quint64 expiry = entity->getExpiry(); + if (expiry < _nextExpiry) { + _nextExpiry = expiry; } - if (entity->needsToCallUpdate()) { - _entitiesToUpdate.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(); } + if (entity->needsToCallUpdate()) { + _entitiesToUpdate.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) { assert(entity); - if (entity->_simulation == this) { - _entitiesToUpdate.remove(entity); - _mortalEntities.remove(entity); - _entitiesToSort.remove(entity); - _simpleKinematicEntities.remove(entity); - removeEntityInternal(entity); - } + _entitiesToUpdate.remove(entity); + _mortalEntities.remove(entity); + _entitiesToSort.remove(entity); + _simpleKinematicEntities.remove(entity); + std::cout << "adebug removeEntity " << (void*)(entity) << std::endl; // adebug + removeEntityInternal(entity); + entity->_simulated = false; } void EntitySimulation::changeEntity(EntityItem* entity) { assert(entity); - if (entity->_simulation == this) { - // Although it is not the responsibility of the EntitySimulation to sort the tree for EXTERNAL changes - // it IS responsibile for triggering deletes for entities that leave the bounds of the domain, hence - // we must check for that case here, however we rely on the change event to have set DIRTY_POSITION flag. - bool wasRemoved = false; - uint32_t dirtyFlags = entity->getDirtyFlags(); - if (dirtyFlags & EntityItem::DIRTY_POSITION) { - AACube domainBounds(glm::vec3(0.0f,0.0f,0.0f), (float)TREE_SCALE); - AACube newCube = entity->getMaximumAACube(); - if (!domainBounds.touches(newCube)) { - qCDebug(entities) << "Entity " << entity->getEntityItemID() << " moved out of domain bounds."; - _entitiesToDelete.insert(entity); - _mortalEntities.remove(entity); - _entitiesToUpdate.remove(entity); - _entitiesToSort.remove(entity); - _simpleKinematicEntities.remove(entity); - removeEntityInternal(entity); - wasRemoved = true; - } + if (!entity->_simulated) { + // This entity was either never added to the simulation or has been removed + // (probably for pending delete), so we don't want to keep a pointer to it + // on any internal lists. + std::cout << "adebug WTF? changing non-simulated entity " << (void*)(entity) << std::endl; // adebug + return; + } + + // Although it is not the responsibility of the EntitySimulation to sort the tree for EXTERNAL changes + // it IS responsibile for triggering deletes for entities that leave the bounds of the domain, hence + // we must check for that case here, however we rely on the change event to have set DIRTY_POSITION flag. + bool wasRemoved = false; + uint32_t dirtyFlags = entity->getDirtyFlags(); + if (dirtyFlags & EntityItem::DIRTY_POSITION) { + AACube domainBounds(glm::vec3(0.0f,0.0f,0.0f), (float)TREE_SCALE); + AACube newCube = entity->getMaximumAACube(); + if (!domainBounds.touches(newCube)) { + qCDebug(entities) << "Entity " << entity->getEntityItemID() << " moved out of domain bounds."; + _entitiesToDelete.insert(entity); + _mortalEntities.remove(entity); + _entitiesToUpdate.remove(entity); + _entitiesToSort.remove(entity); + _simpleKinematicEntities.remove(entity); + std::cout << "adebug changeEntity out of bounds " << (void*)(entity) << std::endl; // adebug + removeEntityInternal(entity); + entity->_simulated = false; + wasRemoved = true; } - if (!wasRemoved) { - if (dirtyFlags & EntityItem::DIRTY_LIFETIME) { - if (entity->isMortal()) { - _mortalEntities.insert(entity); - quint64 expiry = entity->getExpiry(); - if (expiry < _nextExpiry) { - _nextExpiry = expiry; - } - } else { - _mortalEntities.remove(entity); + } + if (!wasRemoved) { + if (dirtyFlags & EntityItem::DIRTY_LIFETIME) { + if (entity->isMortal()) { + _mortalEntities.insert(entity); + quint64 expiry = entity->getExpiry(); + if (expiry < _nextExpiry) { + _nextExpiry = expiry; } - entity->clearDirtyFlags(EntityItem::DIRTY_LIFETIME); - } - if (entity->needsToCallUpdate()) { - _entitiesToUpdate.insert(entity); } else { - _entitiesToUpdate.remove(entity); + _mortalEntities.remove(entity); } - changeEntityInternal(entity); + entity->clearDirtyFlags(EntityItem::DIRTY_LIFETIME); } - } else { - // this entity is not yet in this simulation but something (the tree) assumes that it is --> try to add it - addEntity(entity); + if (entity->needsToCallUpdate()) { + _entitiesToUpdate.insert(entity); + } else { + _entitiesToUpdate.remove(entity); + } + changeEntityInternal(entity); } } @@ -248,6 +251,7 @@ void EntitySimulation::moveSimpleKinematics(const quint64& now) { _entitiesToSort.insert(entity); ++itemItr; } else { + // the entity is no longer non-physical-kinematic itemItr = _simpleKinematicEntities.erase(itemItr); } } diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index b6d3abd64a..13d30b7a37 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -14,12 +14,16 @@ #include #include +#include #include #include "EntityItem.h" #include "EntityTree.h" +typedef QSet SetOfEntities; +typedef QVector VectorOfEntities; + // 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 = @@ -49,7 +53,7 @@ public: void updateEntities(); - friend EntityTree; + friend class EntityTree; protected: // these only called by the EntityTree? /// \param entity pointer to EntityItem to be added @@ -73,15 +77,13 @@ public: EntityTree* getEntityTree() { return _entityTree; } - void getEntitiesToDelete(SetOfEntities& entitiesToDelete); + void getEntitiesToDelete(VectorOfEntities& entitiesToDelete); signals: void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); protected: - void clearEntitySimulation(EntityItem* entity) { entity->_simulation = nullptr; } - // These pure virtual methods are protected because they are not to be called will-nilly. The base class // calls them in the right places. virtual void updateEntitiesInternal(const quint64& now) = 0; @@ -104,9 +106,9 @@ protected: SetOfEntities _mortalEntities; // entities that have an expiry quint64 _nextExpiry; SetOfEntities _entitiesToUpdate; // entities that need to call EntityItem::update() - SetOfEntities _entitiesToSort; // entities that were moved by simulation (and might need resort in EntityTree) - SetOfEntities _entitiesToDelete; // entities that this simulation decided to delete (EntityTree will do the actual deletes) - SetOfEntities _simpleKinematicEntities; // entities that are undergoing (non-colliding) kinematic motion" + SetOfEntities _entitiesToSort; // entities moved by simulation (and might need resort in EntityTree) + SetOfEntities _entitiesToDelete; // entities simulation decided needed to be deleted (EntityTree will actually delete) + SetOfEntities _simpleKinematicEntities; // entities undergoing non-colliding kinematic motion private: void moveSimpleKinematics(); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 611947197c..88ac052396 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -349,14 +349,11 @@ void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator) _recentlyDeletedEntitiesLock.unlock(); } - if (_simulation && theEntity->getSimulation()) { + if (_simulation) { _simulation->removeEntity(theEntity); - // we need to give the simulation time to cleanup its own pointers - // so we push theEntity onto the _pendingDeletes and check again later. - _pendingDeletes.insert(theEntity); - } else { - delete theEntity; // we can delete the entity immediately - } + } + std::cout << "adebug 001 delete entity " << (void*)(theEntity) << std::endl; // adebug + delete theEntity; // we can delete the entity immediately } if (_simulation) { _simulation->unlock(); @@ -756,28 +753,18 @@ void EntityTree::update() { lockForWrite(); _simulation->lock(); _simulation->updateEntities(); - _simulation->getEntitiesToDelete(_pendingDeletes); + VectorOfEntities pendingDeletes; + _simulation->getEntitiesToDelete(pendingDeletes); _simulation->unlock(); - if (_pendingDeletes.size() > 0) { + if (pendingDeletes.size() > 0) { // translate into list of ID's QSet idsToDelete; - SetOfEntities::iterator entityItr = _pendingDeletes.begin(); - while (entityItr != _pendingDeletes.end()) { - EntityItem* entity = *entityItr; - if (entity->getElement()) { - // this entity is still in an element so we push it's ID on a list (and delete the roundabout way) - idsToDelete.insert(entity->getEntityItemID()); - entityItr = _pendingDeletes.erase(entityItr); - } else if (!entity->getSimulation()) { - // the entity is not in any simulation so we can delete immediately - delete entity; - entityItr = _pendingDeletes.erase(entityItr); - } else { - // we're waiting for the simulation to cleanup its own data structure - // so we leave it on the _pendingDeletes and will try again later - ++entityItr; - } + for (auto entityItr : pendingDeletes) { + EntityItem* entity = &(*entityItr); + assert(!entity->getPhysicsInfo()); // adebug -- remove this after testing + std::cout << "adebug delete entity " << (void*)(entity) << " the roundabout way" << std::endl; // adebug + idsToDelete.insert(entity->getEntityItemID()); } // delete these things the roundabout way deleteEntities(idsToDelete, true); diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index f56348b66f..e5c4e68f2f 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -12,14 +12,13 @@ #ifndef hifi_EntityTree_h #define hifi_EntityTree_h -#include +#include #include + #include "EntityTreeElement.h" #include "DeleteEntityOperator.h" -typedef QSet SetOfEntities; - class Model; class EntitySimulation; @@ -198,7 +197,6 @@ private: QHash _changedEntityIDs; EntitySimulation* _simulation; - SetOfEntities _pendingDeletes; bool _wantEditLogging = false; }; diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index 017ff23473..aa1e224a24 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -45,7 +45,6 @@ void SimpleEntitySimulation::addEntityInternal(EntityItem* entity) { void SimpleEntitySimulation::removeEntityInternal(EntityItem* entity) { _hasSimulationOwnerEntities.remove(entity); - clearEntitySimulation(entity); } const int SIMPLE_SIMULATION_DIRTY_FLAGS = EntityItem::DIRTY_VELOCITIES | EntityItem::DIRTY_MOTION_TYPE; From cfad016ba31289150c52414fa286c5db0d79d61b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 5 May 2015 10:14:19 -0700 Subject: [PATCH 27/89] woops, forgot to these changes in last commit --- libraries/physics/src/EntityMotionState.cpp | 30 ++++++++++++++++----- libraries/physics/src/EntityMotionState.h | 4 +++ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 30e4de7e11..52d0577a6e 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -43,11 +43,18 @@ EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItem* entity } EntityMotionState::~EntityMotionState() { - assert(_entity); + // be sure to clear _entity before calling the destructor + assert(!_entity); +} + +void EntityMotionState::clearEntity() { _entity = nullptr; } MotionType EntityMotionState::computeObjectMotionType() const { + if (!_entity) { + return MOTION_TYPE_STATIC; + } if (_entity->getCollisionsWillMove()) { return MOTION_TYPE_DYNAMIC; } @@ -55,7 +62,7 @@ MotionType EntityMotionState::computeObjectMotionType() const { } bool EntityMotionState::isMoving() const { - return _entity->isMoving(); + return _entity && _entity->isMoving(); } // This callback is invoked by the physics simulation in two cases: @@ -64,6 +71,9 @@ bool EntityMotionState::isMoving() const { // (2) at the beginning of each simulation step for KINEMATIC RigidBody's -- // it is an opportunity for outside code to update the object's simulation position void EntityMotionState::getWorldTransform(btTransform& worldTrans) const { + if (!_entity) { + return; + } if (_motionType == MOTION_TYPE_KINEMATIC) { // This is physical kinematic motion which steps strictly by the subframe count // of the physics simulation. @@ -82,6 +92,9 @@ void EntityMotionState::getWorldTransform(btTransform& worldTrans) const { // This callback is invoked by the physics simulation at the end of each simulation step... // iff the corresponding RigidBody is DYNAMIC and has moved. void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { + if (!_entity) { + return; + } measureBodyAcceleration(); _entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset()); _entity->setRotation(bulletToGLM(worldTrans.getRotation())); @@ -112,7 +125,9 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { } void EntityMotionState::computeObjectShapeInfo(ShapeInfo& shapeInfo) { - _entity->computeShapeInfo(shapeInfo); + if (_entity) { + _entity->computeShapeInfo(shapeInfo); + } } // RELIABLE_SEND_HACK: until we have truly reliable resends of non-moving updates @@ -227,7 +242,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { } bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { - if (!remoteSimulationOutOfSync(simulationFrame)) { + if (!_entity || !remoteSimulationOutOfSync(simulationFrame)) { return false; } @@ -248,7 +263,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { } void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_t step) { - if (!_entity->isKnownID()) { + if (!_entity || !_entity->isKnownID()) { return; // never update entities that are unknown } @@ -375,8 +390,9 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ } uint32_t EntityMotionState::getIncomingDirtyFlags() const { - uint32_t dirtyFlags = _entity->getDirtyFlags(); - if (_body) { + uint32_t dirtyFlags = 0; + if (_body && _entity) { + _entity->getDirtyFlags(); // we add DIRTY_MOTION_TYPE if the body's motion type disagrees with entity velocity settings int bodyFlags = _body->getCollisionFlags(); bool isMoving = _entity->isMoving(); diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index d407fd8ae8..a1d4c6f2b6 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -76,7 +76,11 @@ public: void resetMeasuredBodyAcceleration(); void measureBodyAcceleration(); + friend class PhysicalEntitySimulation; + protected: + void clearEntity(); + virtual void setMotionType(MotionType motionType); EntityItem* _entity; From 6be3cc6efb44fd2b1608e50dc9e271d7f1b5282d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 5 May 2015 10:18:03 -0700 Subject: [PATCH 28/89] remove debug stuff --- libraries/entities/src/EntitySimulation.cpp | 12 ------------ libraries/entities/src/EntityTree.cpp | 4 +--- libraries/physics/src/PhysicalEntitySimulation.cpp | 6 +----- 3 files changed, 2 insertions(+), 20 deletions(-) diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index 4300bacafa..f11ffd015d 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -38,11 +38,9 @@ void EntitySimulation::updateEntities() { } void EntitySimulation::getEntitiesToDelete(VectorOfEntities& entitiesToDelete) { - static int adebug = 0; ++adebug; for (auto entityItr : _entitiesToDelete) { EntityItem* entity = &(*entityItr); // this entity is still in its tree, so we insert into the external list - std::cout << "adebug EntitySimulation relays entityToDelete " << (void*)(entity) << " this = " << (void*)(this) << std::endl; // adebug entitiesToDelete.push_back(entity); ++entityItr; } @@ -79,7 +77,6 @@ void EntitySimulation::expireMortalEntities(const quint64& now) { _entitiesToUpdate.remove(entity); _entitiesToSort.remove(entity); _simpleKinematicEntities.remove(entity); - std::cout << "adebug expireMortalEntities " << (void*)(entity) << std::endl; // adebug removeEntityInternal(entity); entity->_simulated = false; } else { @@ -128,7 +125,6 @@ void EntitySimulation::sortEntitiesThatMoved() { _mortalEntities.remove(entity); _entitiesToUpdate.remove(entity); _simpleKinematicEntities.remove(entity); - std::cout << "adebug entity moved out of bounds " << (void*)(entity) << std::endl; // adebug removeEntityInternal(entity); entity->_simulated = false; itemItr = _entitiesToSort.erase(itemItr); @@ -146,12 +142,7 @@ void EntitySimulation::sortEntitiesThatMoved() { } void EntitySimulation::addEntity(EntityItem* entity) { - //static int foo = 0; foo++; assert(entity); - std::cout << "adebug EntitySimulation addEntity " << (void*)(entity) << std::endl; // adebug - //if (foo > 1) { - // //assert(false); // adebug - //} if (entity->isMortal()) { _mortalEntities.insert(entity); quint64 expiry = entity->getExpiry(); @@ -175,7 +166,6 @@ void EntitySimulation::removeEntity(EntityItem* entity) { _mortalEntities.remove(entity); _entitiesToSort.remove(entity); _simpleKinematicEntities.remove(entity); - std::cout << "adebug removeEntity " << (void*)(entity) << std::endl; // adebug removeEntityInternal(entity); entity->_simulated = false; } @@ -186,7 +176,6 @@ void EntitySimulation::changeEntity(EntityItem* entity) { // This entity was either never added to the simulation or has been removed // (probably for pending delete), so we don't want to keep a pointer to it // on any internal lists. - std::cout << "adebug WTF? changing non-simulated entity " << (void*)(entity) << std::endl; // adebug return; } @@ -205,7 +194,6 @@ void EntitySimulation::changeEntity(EntityItem* entity) { _entitiesToUpdate.remove(entity); _entitiesToSort.remove(entity); _simpleKinematicEntities.remove(entity); - std::cout << "adebug changeEntity out of bounds " << (void*)(entity) << std::endl; // adebug removeEntityInternal(entity); entity->_simulated = false; wasRemoved = true; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 88ac052396..c90fa6df87 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -352,7 +352,6 @@ void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator) if (_simulation) { _simulation->removeEntity(theEntity); } - std::cout << "adebug 001 delete entity " << (void*)(theEntity) << std::endl; // adebug delete theEntity; // we can delete the entity immediately } if (_simulation) { @@ -762,8 +761,7 @@ void EntityTree::update() { QSet idsToDelete; for (auto entityItr : pendingDeletes) { EntityItem* entity = &(*entityItr); - assert(!entity->getPhysicsInfo()); // adebug -- remove this after testing - std::cout << "adebug delete entity " << (void*)(entity) << " the roundabout way" << std::endl; // adebug + assert(!entity->getPhysicsInfo()); // TODO: Andrew to remove this after testing idsToDelete.insert(entity->getEntityItemID()); } // delete these things the roundabout way diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index 166c858851..e5af03cbba 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -48,17 +48,15 @@ void PhysicalEntitySimulation::updateEntitiesInternal(const quint64& now) { void PhysicalEntitySimulation::addEntityInternal(EntityItem* entity) { assert(entity); if (entity->getIgnoreForCollisions() && entity->isMoving()) { - std::cout << "adebug addEntityInternal for NPK entity " << (void*)(entity) << std::endl; // adebug _simpleKinematicEntities.insert(entity); } else { EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); if (!motionState) { - std::cout << "adebug addEntityInternal for entity " << (void*)(entity) << std::endl; // adebug _pendingAdds.insert(entity); } else { + // DEBUG -- Andrew to remove this after testing // Adding entity already in simulation? assert that this is case, // since otherwise we probably have an orphaned EntityMotionState. - std::cout << "adebug WTF? re-adding entity " << (void*)(entity) << std::endl; // adebug assert(_physicalObjects.find(motionState) != _physicalObjects.end()); } } @@ -138,7 +136,6 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToDelete() { EntityItem* entity = motionState->getEntity(); if (entity) { _pendingAdds.remove(entity); - std::cout << "adebug disconnect MotionState " << (void*)(motionState) << " from entity " << (void*)(entity) << std::endl; // adebug entity->setPhysicsInfo(nullptr); motionState->clearEntity(); } @@ -163,7 +160,6 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToAdd() { btCollisionShape* shape = _shapeManager->getShape(shapeInfo); if (shape) { EntityMotionState* motionState = new EntityMotionState(shape, entity); - std::cout << "adebug create MotionState " << (void*)(motionState) << " for entity " << (void*)(entity) << std::endl; // adebug entity->setPhysicsInfo(static_cast(motionState)); motionState->setMass(entity->computeMass()); _physicalObjects.insert(motionState); From 25ff9e4b5922a6d39abdfd80d0a6d7ba4d7ae665 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 5 May 2015 10:27:48 -0700 Subject: [PATCH 29/89] fix warning about order of ctor initialization --- libraries/entities/src/EntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 96f024691d..d2cb6f4626 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -64,9 +64,9 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : _simulatorIDChangedTime(0), _marketplaceID(ENTITY_ITEM_DEFAULT_MARKETPLACE_ID), _name(ENTITY_ITEM_DEFAULT_NAME), - _physicsInfo(nullptr), _dirtyFlags(0), _element(nullptr), + _physicsInfo(nullptr), _simulated(false) { quint64 now = usecTimestampNow(); From 813d702fc574b8793c6d496c8e340d9e96274e60 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 5 May 2015 11:00:25 -0700 Subject: [PATCH 30/89] fix infinite loop in while --- libraries/physics/src/PhysicalEntitySimulation.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index e5af03cbba..98968c045a 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -168,6 +168,8 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToAdd() { } else { ++entityItr; } + } else { + ++entityItr; } } return _tempVector; From 1cd93b9ec8508d295a0f4eeaea808dd7e7e88077 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 5 May 2015 13:14:22 -0700 Subject: [PATCH 31/89] pull andrew's branch, add back in visual indicator of an entity being active in bullet --- libraries/entities-renderer/CMakeLists.txt | 7 +++- .../src/RenderableDebugableEntityItem.cpp | 35 +++++++++++++++++-- .../src/RenderableDebugableEntityItem.h | 1 + libraries/entities/src/EntityItem.cpp | 22 +++++++----- libraries/entities/src/EntityTree.cpp | 3 +- libraries/physics/src/EntityMotionState.cpp | 3 +- libraries/physics/src/PhysicsEngine.cpp | 13 +++++++ libraries/physics/src/PhysicsEngine.h | 2 ++ 8 files changed, 71 insertions(+), 15 deletions(-) diff --git a/libraries/entities-renderer/CMakeLists.txt b/libraries/entities-renderer/CMakeLists.txt index c0880ed15d..6c7fa04a21 100644 --- a/libraries/entities-renderer/CMakeLists.txt +++ b/libraries/entities-renderer/CMakeLists.txt @@ -7,4 +7,9 @@ add_dependency_external_projects(glm) find_package(GLM REQUIRED) target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) -link_hifi_libraries(shared gpu script-engine render-utils) \ No newline at end of file +add_dependency_external_projects(bullet) +find_package(Bullet REQUIRED) +target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${BULLET_INCLUDE_DIRS}) +target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES}) + +link_hifi_libraries(shared gpu script-engine render-utils) diff --git a/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp b/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp index 94b554b96a..0410d78e80 100644 --- a/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "RenderableDebugableEntityItem.h" @@ -23,7 +24,6 @@ void RenderableDebugableEntityItem::renderBoundingBox(EntityItem* entity, Render glm::vec3 center = entity->getCenter(); glm::vec3 dimensions = entity->getDimensions(); glm::quat rotation = entity->getRotation(); - glm::vec4 greenColor(0.0f, 1.0f, 0.0f, 1.0f); glPushMatrix(); glTranslatef(position.x, position.y, position.z); @@ -34,14 +34,41 @@ void RenderableDebugableEntityItem::renderBoundingBox(EntityItem* entity, Render glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); glScalef(dimensions.x, dimensions.y, dimensions.z); if (puffedOut) { - DependencyManager::get()->renderWireCube(1.2f, greenColor); + glm::vec4 redColor(1.0f, 0.0f, 0.0f, 1.0f); + DependencyManager::get()->renderWireCube(1.2f, redColor); } else { + glm::vec4 greenColor(0.0f, 1.0f, 0.0f, 1.0f); DependencyManager::get()->renderWireCube(1.0f, greenColor); } glPopMatrix(); glPopMatrix(); } +void RenderableDebugableEntityItem::renderHoverDot(EntityItem* entity, RenderArgs* args) { + glm::vec3 position = entity->getPosition(); + glm::vec3 center = entity->getCenter(); + glm::vec3 dimensions = entity->getDimensions(); + glm::quat rotation = entity->getRotation(); + glm::vec4 blueColor(0.0f, 0.0f, 1.0f, 1.0f); + float radius = 0.05f; + + glPushMatrix(); + glTranslatef(position.x, position.y + dimensions.y + radius, position.z); + glm::vec3 axis = glm::axis(rotation); + glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); + + glPushMatrix(); + glm::vec3 positionToCenter = center - position; + glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); + + glScalef(radius, radius, radius); + + const int SLICES = 8; + const int STACKS = 8; + DependencyManager::get()->renderSolidSphere(0.5f, SLICES, STACKS, blueColor); + glPopMatrix(); + glPopMatrix(); +} void RenderableDebugableEntityItem::render(EntityItem* entity, RenderArgs* args) { bool debugSimulationOwnership = args->_debugFlags & RenderArgs::RENDER_DEBUG_SIMULATION_OWNERSHIP; @@ -52,4 +79,8 @@ void RenderableDebugableEntityItem::render(EntityItem* entity, RenderArgs* args) renderBoundingBox(entity, args, true); } } + + if (PhysicsEngine::physicsInfoIsActive(entity->getPhysicsInfo())) { + renderHoverDot(entity, args); + } } diff --git a/libraries/entities-renderer/src/RenderableDebugableEntityItem.h b/libraries/entities-renderer/src/RenderableDebugableEntityItem.h index 9a8344c96d..f3550cb116 100644 --- a/libraries/entities-renderer/src/RenderableDebugableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableDebugableEntityItem.h @@ -17,6 +17,7 @@ class RenderableDebugableEntityItem { public: static void renderBoundingBox(EntityItem* entity, RenderArgs* args, bool puffedOut); + static void renderHoverDot(EntityItem* entity, RenderArgs* args); static void render(EntityItem* entity, RenderArgs* args); }; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index d2cb6f4626..c5083d5cf8 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -313,10 +313,10 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // if this bitstream indicates that this node is the simulation owner, ignore any physics-related updates. glm::vec3 savePosition = _position; glm::quat saveRotation = _rotation; - glm::vec3 saveVelocity = _velocity; - glm::vec3 saveAngularVelocity = _angularVelocity; - glm::vec3 saveGravity = _gravity; - glm::vec3 saveAcceleration = _acceleration; + // glm::vec3 saveVelocity = _velocity; + // glm::vec3 saveAngularVelocity = _angularVelocity; + // glm::vec3 saveGravity = _gravity; + // glm::vec3 saveAcceleration = _acceleration; // Header bytes @@ -401,8 +401,10 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef if (lastEditedFromBufferAdjusted > now) { lastEditedFromBufferAdjusted = now; } - + +#if 0 // XXX bool fromSameServerEdit = (lastEditedFromBuffer == _lastEditedFromRemoteInRemoteTime); +#endif #ifdef WANT_DEBUG qCDebug(entities) << "data from server **************** "; @@ -419,6 +421,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef bool ignoreServerPacket = false; // assume we'll use this server packet +#if 0 // XXX Trying to eliminate this code as a possible source of deviation between interfaces // If this packet is from the same server edit as the last packet we accepted from the server // we probably want to use it. if (fromSameServerEdit) { @@ -435,6 +438,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef ignoreServerPacket = true; } } +#endif if (ignoreServerPacket) { overwriteLocalData = false; @@ -618,10 +622,10 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // this node, so our version has to be newer than what the packet contained. _position = savePosition; _rotation = saveRotation; - _velocity = saveVelocity; - _angularVelocity = saveAngularVelocity; - _gravity = saveGravity; - _acceleration = saveAcceleration; + // _velocity = saveVelocity; + // _angularVelocity = saveAngularVelocity; + // _gravity = saveGravity; + // _acceleration = saveAcceleration; } return bytesRead; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index c90fa6df87..dbbbbc0cd2 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -145,8 +145,7 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro // squash the physics-related changes. properties.setSimulatorIDChanged(false); properties.setPositionChanged(false); - properties.setVelocityChanged(false); - properties.setAccelerationChanged(false); + properties.setRotationChanged(false); } else { qCDebug(entities) << "allowing simulatorID change"; } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 52d0577a6e..dc095590da 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -111,7 +111,8 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { _movingStepsWithoutSimulationOwner = 0; } - if (_movingStepsWithoutSimulationOwner > 4) { // XXX maybe meters from our characterController ? + if (_movingStepsWithoutSimulationOwner > 100) { // XXX maybe meters from our characterController ? + qDebug() << "XXX XXX XXX -- claiming something I saw moving"; setShouldClaimSimulationOwnership(true); } diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index dca922d0f3..3f699692c6 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -405,3 +405,16 @@ void PhysicsEngine::setCharacterController(DynamicCharacterController* character } } +bool PhysicsEngine::physicsInfoIsActive(void* physicsInfo) { + if (!physicsInfo) { + return false; + } + + ObjectMotionState* motionState = static_cast(physicsInfo); + btRigidBody* body = motionState->getRigidBody(); + if (!body) { + return false; + } + + return body->isActive(); +} diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index a5a1d4ac10..9341bfb855 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -92,6 +92,8 @@ public: void dumpNextStats() { _dumpNextStats = true; } + static bool physicsInfoIsActive(void* physicsInfo); + private: void removeContacts(ObjectMotionState* motionState); From 82828f0b9300256345cc28538d304bb19eab635b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 5 May 2015 13:52:10 -0700 Subject: [PATCH 32/89] print when bullet and local octree don't agree on position of an entity --- .../src/RenderableDebugableEntityItem.cpp | 9 +++++++++ libraries/physics/src/PhysicsEngine.cpp | 18 ++++++++++++++++++ libraries/physics/src/PhysicsEngine.h | 1 + 3 files changed, 28 insertions(+) diff --git a/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp b/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp index 0410d78e80..196d3c2898 100644 --- a/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp @@ -83,4 +83,13 @@ void RenderableDebugableEntityItem::render(EntityItem* entity, RenderArgs* args) if (PhysicsEngine::physicsInfoIsActive(entity->getPhysicsInfo())) { renderHoverDot(entity, args); } + + glm::vec3 position; + glm::quat rotation; + if (PhysicsEngine::getBodyLocation(entity->getPhysicsInfo(), position, rotation)) { + glm::vec3 positionOffset = glm::abs(position - entity->getPosition()); + if (positionOffset[0] > 0.001 || positionOffset[1] > 0.001 || positionOffset[2] > 0.001) { + qDebug() << positionOffset[0] << positionOffset[1] << positionOffset[2]; + } + } } diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 3f699692c6..75cba104d2 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -418,3 +418,21 @@ bool PhysicsEngine::physicsInfoIsActive(void* physicsInfo) { return body->isActive(); } + +bool PhysicsEngine::getBodyLocation(void* physicsInfo, glm::vec3& positionReturn, glm::quat& rotationReturn) { + if (!physicsInfo) { + return false; + } + + ObjectMotionState* motionState = static_cast(physicsInfo); + btRigidBody* body = motionState->getRigidBody(); + if (!body) { + return false; + } + + const btTransform& worldTrans = body->getCenterOfMassTransform(); + positionReturn = bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset(); + rotationReturn = bulletToGLM(worldTrans.getRotation()); + + return true; +} diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 9341bfb855..8b947d2510 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -93,6 +93,7 @@ public: void dumpNextStats() { _dumpNextStats = true; } static bool physicsInfoIsActive(void* physicsInfo); + static bool getBodyLocation(void* physicsInfo, glm::vec3& positionReturn, glm::quat& rotationReturn); private: void removeContacts(ObjectMotionState* motionState); From 8523a96e2b26430dc728b3d1c52783766a9d1b78 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 5 May 2015 15:34:26 -0700 Subject: [PATCH 33/89] implement setShouldClaimSimulationOwnership() --- libraries/physics/src/EntityMotionState.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index a1d4c6f2b6..7bd1aa7f8b 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -46,7 +46,7 @@ public: bool shouldSendUpdate(uint32_t simulationFrame); void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t step); - void setShouldClaimSimulationOwnership(bool value) { } + void setShouldClaimSimulationOwnership(bool value) { _shouldClaimSimulationOwnership = value; } bool getShouldClaimSimulationOwnership() { return false; } virtual uint32_t getIncomingDirtyFlags() const; From 2668ff6d0aa417e5e1d223a5e813de88cae3603b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 5 May 2015 15:34:50 -0700 Subject: [PATCH 34/89] check for DIRTY_ROTATION bit when copying rotation --- libraries/physics/src/ObjectMotionState.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 39317ea9c1..2eb63c26d7 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -121,7 +121,7 @@ void ObjectMotionState::handleEasyChanges(uint32_t flags) { } worldTrans.setOrigin(glmToBullet(getObjectPosition())); _body->setWorldTransform(worldTrans); - } else { + } else if (flags & EntityItem::DIRTY_ROTATION) { btTransform worldTrans = _body->getWorldTransform(); worldTrans.setRotation(glmToBullet(getObjectRotation())); _body->setWorldTransform(worldTrans); From c35edd8eb433f2ebe6d5b2dc3c674189da0bcc40 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 5 May 2015 16:40:10 -0700 Subject: [PATCH 35/89] some debugging on Andrew's refactor --- .../src/RenderableDebugableEntityItem.cpp | 16 ++++++++++------ libraries/entities/src/EntityItem.cpp | 2 ++ libraries/entities/src/EntitySimulation.cpp | 2 +- libraries/entities/src/EntityTree.cpp | 2 +- libraries/physics/src/EntityMotionState.cpp | 3 ++- libraries/physics/src/ObjectMotionState.h | 3 ++- 6 files changed, 18 insertions(+), 10 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp b/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp index 196d3c2898..4d38d0d747 100644 --- a/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp @@ -86,10 +86,14 @@ void RenderableDebugableEntityItem::render(EntityItem* entity, RenderArgs* args) glm::vec3 position; glm::quat rotation; - if (PhysicsEngine::getBodyLocation(entity->getPhysicsInfo(), position, rotation)) { - glm::vec3 positionOffset = glm::abs(position - entity->getPosition()); - if (positionOffset[0] > 0.001 || positionOffset[1] > 0.001 || positionOffset[2] > 0.001) { - qDebug() << positionOffset[0] << positionOffset[1] << positionOffset[2]; - } - } + + // + // XXX for future debugging + // + // if (PhysicsEngine::getBodyLocation(entity->getPhysicsInfo(), position, rotation)) { + // glm::vec3 positionOffset = glm::abs(position - entity->getPosition()); + // if (positionOffset[0] > 0.001 || positionOffset[1] > 0.001 || positionOffset[2] > 0.001) { + // qDebug() << positionOffset[0] << positionOffset[1] << positionOffset[2]; + // } + // } } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index c5083d5cf8..a3bb410b2c 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1189,6 +1189,7 @@ void EntityItem::updateVelocity(const glm::vec3& value) { _velocity = value; } _dirtyFlags |= EntityItem::DIRTY_LINEAR_VELOCITY; + _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; } } @@ -1221,6 +1222,7 @@ void EntityItem::updateAngularVelocity(const glm::vec3& value) { auto distance = glm::distance(_angularVelocity, value); if (distance > MIN_SPIN_DELTA) { _dirtyFlags |= EntityItem::DIRTY_ANGULAR_VELOCITY; + _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; if (glm::length(value) < MIN_SPIN_DELTA) { _angularVelocity = ENTITY_ITEM_ZERO_VEC3; } else { diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index f11ffd015d..761a496c44 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -48,7 +48,6 @@ void EntitySimulation::getEntitiesToDelete(VectorOfEntities& entitiesToDelete) { } void EntitySimulation::addEntityInternal(EntityItem* entity) { - entity->_simulated = true; if (entity->isMoving() && !entity->getPhysicsInfo()) { _simpleKinematicEntities.insert(entity); } @@ -154,6 +153,7 @@ void EntitySimulation::addEntity(EntityItem* entity) { _entitiesToUpdate.insert(entity); } addEntityInternal(entity); + entity->_simulated = true; // 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. diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index dbbbbc0cd2..5aea021e7a 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -159,7 +159,7 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro uint32_t newFlags = entity->getDirtyFlags() & ~preFlags; if (newFlags) { - if (_simulation) { + if (_simulation) { if (newFlags & DIRTY_SIMULATION_FLAGS) { _simulation->lock(); _simulation->changeEntity(entity); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index dc095590da..a9faff36b4 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -393,7 +393,8 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ uint32_t EntityMotionState::getIncomingDirtyFlags() const { uint32_t dirtyFlags = 0; if (_body && _entity) { - _entity->getDirtyFlags(); + dirtyFlags = _entity->getDirtyFlags(); + _entity->clearDirtyFlags(); // we add DIRTY_MOTION_TYPE if the body's motion type disagrees with entity velocity settings int bodyFlags = _body->getCollisionFlags(); bool isMoving = _entity->isMoving(); diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index d0dc9afc88..b2fcf8ceae 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -36,7 +36,8 @@ enum MotionStateType { // 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); const uint32_t EASY_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES | - EntityItem::DIRTY_MASS | EntityItem::DIRTY_COLLISION_GROUP | EntityItem::DIRTY_MATERIAL); + EntityItem::DIRTY_MASS | EntityItem::DIRTY_COLLISION_GROUP | + EntityItem::DIRTY_MATERIAL | EntityItem::DIRTY_PHYSICS_ACTIVATION); // 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; From 550820ee4507ca97d8639b9ebe6e5571e100a7e7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 5 May 2015 16:48:56 -0700 Subject: [PATCH 36/89] set EntityItem::_simulated in the correct location --- libraries/entities/src/EntitySimulation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index f11ffd015d..761a496c44 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -48,7 +48,6 @@ void EntitySimulation::getEntitiesToDelete(VectorOfEntities& entitiesToDelete) { } void EntitySimulation::addEntityInternal(EntityItem* entity) { - entity->_simulated = true; if (entity->isMoving() && !entity->getPhysicsInfo()) { _simpleKinematicEntities.insert(entity); } @@ -154,6 +153,7 @@ void EntitySimulation::addEntity(EntityItem* entity) { _entitiesToUpdate.insert(entity); } addEntityInternal(entity); + entity->_simulated = true; // 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. From d4701b43100230fd767bb6eb9ba06d0b57aed479 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 5 May 2015 16:49:41 -0700 Subject: [PATCH 37/89] namechange getIncomingDF --> getAndClearIncomingDF --- libraries/physics/src/EntityMotionState.cpp | 5 +++-- libraries/physics/src/EntityMotionState.h | 3 +-- libraries/physics/src/ObjectMotionState.h | 6 +++--- libraries/physics/src/PhysicsEngine.cpp | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 52d0577a6e..8c38761de3 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -389,10 +389,11 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ _sentStep = step; } -uint32_t EntityMotionState::getIncomingDirtyFlags() const { +uint32_t EntityMotionState::getAndClearIncomingDirtyFlags() const { uint32_t dirtyFlags = 0; if (_body && _entity) { - _entity->getDirtyFlags(); + dirtyFlags = _entity->getDirtyFlags(); + _entity->clearDirtyFlags(); // we add DIRTY_MOTION_TYPE if the body's motion type disagrees with entity velocity settings int bodyFlags = _body->getCollisionFlags(); bool isMoving = _entity->isMoving(); diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 7bd1aa7f8b..23cb64d3fc 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -49,8 +49,7 @@ public: void setShouldClaimSimulationOwnership(bool value) { _shouldClaimSimulationOwnership = value; } bool getShouldClaimSimulationOwnership() { return false; } - virtual uint32_t getIncomingDirtyFlags() const; - virtual void clearIncomingDirtyFlags(uint32_t flags) { _entity->clearDirtyFlags(flags); } + virtual uint32_t getAndClearIncomingDirtyFlags() const; void incrementAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount++; } void resetAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount = 0; } diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index d0dc9afc88..680adc725b 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -36,7 +36,8 @@ enum MotionStateType { // 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); const uint32_t EASY_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES | - EntityItem::DIRTY_MASS | EntityItem::DIRTY_COLLISION_GROUP | EntityItem::DIRTY_MATERIAL); + EntityItem::DIRTY_MASS | EntityItem::DIRTY_COLLISION_GROUP | EntityItem::DIRTY_MATERIAL | + EntityItem::DIRTY_PHYSICS_ACTIVATION); // 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; @@ -86,8 +87,7 @@ public: glm::vec3 getBodyLinearVelocity() const; glm::vec3 getBodyAngularVelocity() const; - virtual uint32_t getIncomingDirtyFlags() const = 0; - virtual void clearIncomingDirtyFlags(uint32_t flags) = 0; + virtual uint32_t getAndClearIncomingDirtyFlags() const = 0; virtual MotionType computeObjectMotionType() const = 0; virtual void computeObjectShapeInfo(ShapeInfo& shapeInfo) = 0; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index dca922d0f3..6ad19dcaf8 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -173,7 +173,7 @@ void PhysicsEngine::addObjects(VectorOfMotionStates& objects) { void PhysicsEngine::changeObjects(VectorOfMotionStates& objects) { for (auto object : objects) { - uint32_t flags = object->getIncomingDirtyFlags() & DIRTY_PHYSICS_FLAGS; + uint32_t flags = object->getAndClearIncomingDirtyFlags() & DIRTY_PHYSICS_FLAGS; if (flags & HARD_DIRTY_PHYSICS_FLAGS) { object->handleHardAndEasyChanges(flags, this); } else { From 50f73602f6c094abcd7ac7b2c374e6d59d12cd44 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 5 May 2015 16:51:07 -0700 Subject: [PATCH 38/89] cleanup PhysicalEntitySimulation::_outgoingChanges --- libraries/physics/src/PhysicalEntitySimulation.cpp | 2 ++ libraries/physics/src/PhysicalEntitySimulation.h | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index 98968c045a..8d2bd4f7c5 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -68,6 +68,7 @@ void PhysicalEntitySimulation::removeEntityInternal(EntityItem* entity) { motionState->clearEntity(); entity->setPhysicsInfo(nullptr); _pendingRemoves.insert(motionState); + _outgoingChanges.remove(motionState); } } @@ -81,6 +82,7 @@ void PhysicalEntitySimulation::changeEntityInternal(EntityItem* entity) { _pendingChanges.remove(motionState); _physicalObjects.remove(motionState); _pendingRemoves.insert(motionState); + _outgoingChanges.remove(motionState); if (entity->isMoving()) { _simpleKinematicEntities.insert(entity); } diff --git a/libraries/physics/src/PhysicalEntitySimulation.h b/libraries/physics/src/PhysicalEntitySimulation.h index 64ab1bf011..4fd54c60fb 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.h +++ b/libraries/physics/src/PhysicalEntitySimulation.h @@ -37,11 +37,11 @@ public: protected: // only called by EntitySimulation // overrides for EntitySimulation - void updateEntitiesInternal(const quint64& now); - void addEntityInternal(EntityItem* entity); - void removeEntityInternal(EntityItem* entity); - void changeEntityInternal(EntityItem* entity); - void clearEntitiesInternal(); + virtual void updateEntitiesInternal(const quint64& now); + virtual void addEntityInternal(EntityItem* entity); + virtual void removeEntityInternal(EntityItem* entity); + virtual void changeEntityInternal(EntityItem* entity); + virtual void clearEntitiesInternal(); public: VectorOfMotionStates& getObjectsToDelete(); @@ -58,7 +58,7 @@ private: SetOfEntityMotionStates _pendingChanges; // EntityMotionStates already in PhysicsEngine that need their physics changed // outgoing changes - QSet _outgoingChanges; // EntityMotionStates for which we need to send updates to entity-server + SetOfEntityMotionStates _outgoingChanges; // EntityMotionStates for which we need to send updates to entity-server SetOfMotionStates _physicalObjects; // MotionStates of entities in PhysicsEngine VectorOfMotionStates _tempVector; // temporary array reference, valid immediately after getObjectsToRemove() (and friends) From 7a5fe8a34e794c0c833b7f07f69699d6be7a3470 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 6 May 2015 09:05:13 -0700 Subject: [PATCH 39/89] quiet compiler --- interface/src/ui/ApplicationOverlay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 8704a61261..61f87d9588 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -835,7 +835,7 @@ void ApplicationOverlay::renderAudioMeter() { const glm::vec4 AUDIO_METER_GREEN = { 0.0, 1.0, 0.0, 1.0 }; const glm::vec4 AUDIO_METER_RED = { 1.0, 0.0, 0.0, 1.0 }; const float AUDIO_GREEN_START = 0.25 * AUDIO_METER_SCALE_WIDTH; - const float AUDIO_RED_START = 0.80 * AUDIO_METER_SCALE_WIDTH; + const float AUDIO_RED_START = 0.80f * AUDIO_METER_SCALE_WIDTH; const float CLIPPING_INDICATOR_TIME = 1.0f; const float AUDIO_METER_AVERAGING = 0.5; const float LOG2 = log(2.0f); From e61470517c344b17686be62043b1866da8253503 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 6 May 2015 11:01:16 -0700 Subject: [PATCH 40/89] track all entities added to simulation --- libraries/entities/src/EntitySimulation.cpp | 17 +++++++++++++++++ libraries/entities/src/EntitySimulation.h | 1 + 2 files changed, 18 insertions(+) diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index 761a496c44..d28e139205 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -77,6 +77,8 @@ void EntitySimulation::expireMortalEntities(const quint64& now) { _entitiesToSort.remove(entity); _simpleKinematicEntities.remove(entity); removeEntityInternal(entity); + + _allEntities.remove(entity); entity->_simulated = false; } else { if (expiry < _nextExpiry) { @@ -125,7 +127,10 @@ void EntitySimulation::sortEntitiesThatMoved() { _entitiesToUpdate.remove(entity); _simpleKinematicEntities.remove(entity); removeEntityInternal(entity); + + _allEntities.remove(entity); entity->_simulated = false; + itemItr = _entitiesToSort.erase(itemItr); } else { moveOperator.addEntityToMoveList(entity, newCube); @@ -153,6 +158,8 @@ void EntitySimulation::addEntity(EntityItem* entity) { _entitiesToUpdate.insert(entity); } addEntityInternal(entity); + + _allEntities.insert(entity); entity->_simulated = true; // DirtyFlags are used to signal changes to entities that have already been added, @@ -166,7 +173,10 @@ void EntitySimulation::removeEntity(EntityItem* entity) { _mortalEntities.remove(entity); _entitiesToSort.remove(entity); _simpleKinematicEntities.remove(entity); + _entitiesToDelete.remove(entity); removeEntityInternal(entity); + + _allEntities.remove(entity); entity->_simulated = false; } @@ -227,7 +237,14 @@ void EntitySimulation::clearEntities() { _entitiesToUpdate.clear(); _entitiesToSort.clear(); _simpleKinematicEntities.clear(); + _entitiesToDelete.clear(); + clearEntitiesInternal(); + + for (auto entityItr : _allEntities) { + entityItr->_simulated = false; + } + _allEntities.clear(); } void EntitySimulation::moveSimpleKinematics(const quint64& now) { diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index 13d30b7a37..a73afe9fd7 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -103,6 +103,7 @@ protected: // We maintain multiple lists, each for its distinct purpose. // An entity may be in more than one list. + SetOfEntities _allEntities; // tracks all entities added the simulation SetOfEntities _mortalEntities; // entities that have an expiry quint64 _nextExpiry; SetOfEntities _entitiesToUpdate; // entities that need to call EntityItem::update() From 129a3a82da30f077b176d1800fc4d23aeeb0cd55 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 6 May 2015 11:20:39 -0700 Subject: [PATCH 41/89] clear incoming flags after adding an entity to simulation. If an entity has a shape-type of none, don't keep asking it for a shape --- libraries/physics/src/ObjectMotionState.cpp | 1 + libraries/physics/src/PhysicalEntitySimulation.cpp | 3 ++- libraries/physics/src/PhysicsEngine.cpp | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 2eb63c26d7..022a466ae7 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -158,6 +158,7 @@ void ObjectMotionState::handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* computeObjectShapeInfo(shapeInfo); btCollisionShape* newShape = getShapeManager()->getShape(shapeInfo); if (!newShape) { + qCDebug(physics) << "Warning: failed to generate new shape!"; // failed to generate new shape! --> keep old shape and remove shape-change flag flags &= ~EntityItem::DIRTY_SHAPE; // TODO: force this object out of PhysicsEngine rather than just use the old shape diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index 8d2bd4f7c5..81f147540a 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -153,7 +153,7 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToAdd() { while (entityItr != _pendingAdds.end()) { EntityItem* entity = *entityItr; assert(!entity->getPhysicsInfo()); - if (entity->getIgnoreForCollisions()) { + if (entity->getShapeType() == SHAPE_TYPE_NONE || entity->getIgnoreForCollisions()) { // this entity should no longer be on the internal _pendingAdds entityItr = _pendingAdds.erase(entityItr); } else if (entity->isReadyToComputeShape()) { @@ -168,6 +168,7 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToAdd() { _tempVector.push_back(motionState); entityItr = _pendingAdds.erase(entityItr); } else { + qDebug() << "Warning! Failed to generate new shape for entity." << entity->getName(); ++entityItr; } } else { diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 4b90866ce7..b3cde1a9dd 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -126,6 +126,8 @@ void PhysicsEngine::addObject(ObjectMotionState* motionState) { motionState->updateBodyMaterialProperties(); _dynamicsWorld->addRigidBody(body); + + motionState->getAndClearIncomingDirtyFlags(); } void PhysicsEngine::removeObject(ObjectMotionState* object) { From 646661d03749a6fcb705b45c0e9ed51c047d5c38 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 6 May 2015 11:46:25 -0700 Subject: [PATCH 42/89] update body gravity when proper dirty bits are set --- libraries/physics/src/ObjectMotionState.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 2eb63c26d7..63322d25db 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -129,6 +129,7 @@ void ObjectMotionState::handleEasyChanges(uint32_t flags) { if (flags & EntityItem::DIRTY_LINEAR_VELOCITY) { _body->setLinearVelocity(glmToBullet(getObjectLinearVelocity())); + _body->setGravity(glmToBullet(getObjectGravity())); } if (flags & EntityItem::DIRTY_ANGULAR_VELOCITY) { _body->setAngularVelocity(glmToBullet(getObjectAngularVelocity())); From f0c778a802cd939a4cea8762c8c624adc67c1603 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 6 May 2015 11:46:42 -0700 Subject: [PATCH 43/89] fix bug preventing taking of simulation ownership --- libraries/physics/src/EntityMotionState.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 23cb64d3fc..737dc5b81c 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -47,7 +47,7 @@ public: void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t step); void setShouldClaimSimulationOwnership(bool value) { _shouldClaimSimulationOwnership = value; } - bool getShouldClaimSimulationOwnership() { return false; } + bool getShouldClaimSimulationOwnership() { return _shouldClaimSimulationOwnership; } virtual uint32_t getAndClearIncomingDirtyFlags() const; From 6e6fec158dda66c0c4d6d1290e549eb58eecf5ba Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 6 May 2015 11:47:33 -0700 Subject: [PATCH 44/89] split ignore/activation thresholds for updates --- libraries/entities/src/EntityItem.cpp | 122 ++++++++++++++++---------- libraries/entities/src/EntityItem.h | 1 - 2 files changed, 76 insertions(+), 47 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index a3bb410b2c..71a724c5cf 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -549,7 +549,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY_SETTER(PROP_GRAVITY, glm::vec3, updateGravityInDomainUnits); } if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ACCELERATION) { - READ_ENTITY_PROPERTY_SETTER(PROP_ACCELERATION, glm::vec3, updateAcceleration); + READ_ENTITY_PROPERTY_SETTER(PROP_ACCELERATION, glm::vec3, setAcceleration); } READ_ENTITY_PROPERTY(PROP_DAMPING, float, _damping); @@ -666,12 +666,17 @@ void EntityItem::setDensity(float density) { _density = glm::max(glm::min(density, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY); } +const float ACTIVATION_RELATIVE_DENSITY_DELTA = 0.01f; // 1 percent + void EntityItem::updateDensity(float density) { - const float MIN_DENSITY_CHANGE_FACTOR = 0.001f; // 0.1 percent - float newDensity = glm::max(glm::min(density, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY); - if (fabsf(_density - newDensity) / _density > MIN_DENSITY_CHANGE_FACTOR) { - _density = newDensity; - _dirtyFlags |= EntityItem::DIRTY_MASS; + float clampedDensity = glm::max(glm::min(density, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY); + if (_density != clampedDensity) { + _density = clampedDensity; + + if (fabsf(_density - clampedDensity) / _density > ACTIVATION_RELATIVE_DENSITY_DELTA) { + // the density has changed enough that we should update the physics simulation + _dirtyFlags |= EntityItem::DIRTY_MASS; + } } } @@ -925,7 +930,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(density, updateDensity); SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocity, updateVelocity); SET_ENTITY_PROPERTY_FROM_PROPERTIES(gravity, updateGravity); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(acceleration, updateAcceleration); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(acceleration, setAcceleration); SET_ENTITY_PROPERTY_FROM_PROPERTIES(damping, updateDamping); SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, updateLifetime); SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, setScript); @@ -1104,14 +1109,22 @@ void EntityItem::computeShapeInfo(ShapeInfo& info) { info.setParams(getShapeType(), 0.5f * getDimensions()); } -const float MIN_POSITION_DELTA = 0.0001f; -const float MIN_DIMENSIONS_DELTA = 0.0005f; -const float MIN_ALIGNMENT_DOT = 0.999999f; -const float MIN_VELOCITY_DELTA = 0.01f; -const float MIN_DAMPING_DELTA = 0.001f; -const float MIN_GRAVITY_DELTA = 0.001f; -const float MIN_ACCELERATION_DELTA = 0.001f; -const float MIN_SPIN_DELTA = 0.0003f; +// these thesholds determine what updates will be ignored (client and server) +const float IGNORE_POSITION_DELTA = 0.0001f; +const float IGNORE_DIMENSIONS_DELTA = 0.0005f; +const float IGNORE_ALIGNMENT_DOT = 0.99997f; +const float IGNORE_LINEAR_VELOCITY_DELTA = 0.001f; +const float IGNORE_DAMPING_DELTA = 0.001f; +const float IGNORE_GRAVITY_DELTA = 0.001f; +const float IGNORE_ANGULAR_VELOCITY_DELTA = 0.0002f; + +// these thresholds determine what updates will activate the physical object +const float ACTIVATION_POSITION_DELTA = 0.005f; +const float ACTIVATION_DIMENSIONS_DELTA = 0.005f; +const float ACTIVATION_ALIGNMENT_DOT = 0.99990f; +const float ACTIVATION_LINEAR_VELOCITY_DELTA = 0.01f; +const float ACTIVATION_GRAVITY_DELTA = 0.1f; +const float ACTIVATION_ANGULAR_VELOCITY_DELTA = 0.03f; void EntityItem::updatePositionInDomainUnits(const glm::vec3& value) { glm::vec3 position = value * (float)TREE_SCALE; @@ -1119,13 +1132,13 @@ void EntityItem::updatePositionInDomainUnits(const glm::vec3& value) { } void EntityItem::updatePosition(const glm::vec3& value) { - if (value != _position) { - auto distance = glm::distance(_position, value); + auto delta = glm::distance(_position, value); + if (delta > IGNORE_POSITION_DELTA) { _dirtyFlags |= EntityItem::DIRTY_POSITION; - if (distance > MIN_POSITION_DELTA) { + _position = value; + if (delta > ACTIVATION_POSITION_DELTA) { _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; } - _position = value; } } @@ -1135,20 +1148,27 @@ void EntityItem::updateDimensionsInDomainUnits(const glm::vec3& value) { } void EntityItem::updateDimensions(const glm::vec3& value) { - if (glm::distance(_dimensions, value) > MIN_DIMENSIONS_DELTA) { + auto delta = glm::distance(_dimensions, value); + if (delta > IGNORE_DIMENSIONS_DELTA) { _dimensions = value; - _dirtyFlags |= (EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS); + if (delta > ACTIVATION_DIMENSIONS_DELTA) { + // rebuilding the shape will always activate + _dirtyFlags |= (EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS); + } } } void EntityItem::updateRotation(const glm::quat& rotation) { - if (rotation != _rotation) { + if (_rotation != rotation) { + _rotation = rotation; + auto alignmentDot = glm::abs(glm::dot(_rotation, rotation)); - _dirtyFlags |= EntityItem::DIRTY_ROTATION; - if (alignmentDot < MIN_ALIGNMENT_DOT) { + if (alignmentDot < IGNORE_ALIGNMENT_DOT) { + _dirtyFlags |= EntityItem::DIRTY_ROTATION; + } + if (alignmentDot < ACTIVATION_ALIGNMENT_DOT) { _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; } - _rotation = rotation; } } @@ -1169,9 +1189,11 @@ void EntityItem::updateMass(float mass) { newDensity = glm::max(glm::min(mass / volume, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY); } - const float MIN_DENSITY_CHANGE_FACTOR = 0.001f; // 0.1 percent - if (fabsf(_density - newDensity) / _density > MIN_DENSITY_CHANGE_FACTOR) { - _density = newDensity; + float oldDensity = _density; + _density = newDensity; + + if (fabsf(_density - oldDensity) / _density > ACTIVATION_RELATIVE_DENSITY_DELTA) { + // the density has changed enough that we should update the physics simulation _dirtyFlags |= EntityItem::DIRTY_MASS; } } @@ -1182,20 +1204,26 @@ void EntityItem::updateVelocityInDomainUnits(const glm::vec3& value) { } void EntityItem::updateVelocity(const glm::vec3& value) { - if (glm::distance(_velocity, value) > MIN_VELOCITY_DELTA) { - if (glm::length(value) < MIN_VELOCITY_DELTA) { + auto delta = glm::distance(_velocity, value); + if (delta > IGNORE_LINEAR_VELOCITY_DELTA) { + const float MIN_LINEAR_SPEED = 0.001f; + if (glm::length(value) < MIN_LINEAR_SPEED) { _velocity = ENTITY_ITEM_ZERO_VEC3; } else { _velocity = value; } _dirtyFlags |= EntityItem::DIRTY_LINEAR_VELOCITY; - _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; + + if (delta > ACTIVATION_LINEAR_VELOCITY_DELTA) { + _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; + } } } void EntityItem::updateDamping(float value) { - if (fabsf(_damping - value) > MIN_DAMPING_DELTA) { - _damping = glm::clamp(value, 0.0f, 1.0f); + auto clampedDamping = glm::clamp(value, 0.0f, 1.0f); + if (fabsf(_damping - clampedDamping) > IGNORE_DAMPING_DELTA) { + _damping = clampedDamping; _dirtyFlags |= EntityItem::DIRTY_MATERIAL; } } @@ -1206,34 +1234,36 @@ void EntityItem::updateGravityInDomainUnits(const glm::vec3& value) { } void EntityItem::updateGravity(const glm::vec3& value) { - if (glm::distance(_gravity, value) > MIN_GRAVITY_DELTA) { + auto delta = glm::distance(_gravity, value); + if (delta > IGNORE_GRAVITY_DELTA) { _gravity = value; _dirtyFlags |= EntityItem::DIRTY_LINEAR_VELOCITY; - } -} - -void EntityItem::updateAcceleration(const glm::vec3& value) { - if (glm::distance(_acceleration, value) > MIN_ACCELERATION_DELTA) { - _acceleration = value; + if (delta > ACTIVATION_GRAVITY_DELTA) { + _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; + } } } void EntityItem::updateAngularVelocity(const glm::vec3& value) { - auto distance = glm::distance(_angularVelocity, value); - if (distance > MIN_SPIN_DELTA) { + auto delta = glm::distance(_angularVelocity, value); + if (delta > IGNORE_ANGULAR_VELOCITY_DELTA) { _dirtyFlags |= EntityItem::DIRTY_ANGULAR_VELOCITY; - _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; - if (glm::length(value) < MIN_SPIN_DELTA) { + const float MIN_ANGULAR_SPEED = 0.0002f; + if (glm::length(value) < MIN_ANGULAR_SPEED) { _angularVelocity = ENTITY_ITEM_ZERO_VEC3; } else { _angularVelocity = value; } + if (delta > ACTIVATION_ANGULAR_VELOCITY_DELTA) { + _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; + } } } void EntityItem::updateAngularDamping(float value) { - if (fabsf(_angularDamping - value) > MIN_DAMPING_DELTA) { - _angularDamping = glm::clamp(value, 0.0f, 1.0f); + auto clampedDamping = glm::clamp(value, 0.0f, 1.0f); + if (fabsf(_angularDamping - clampedDamping) > IGNORE_DAMPING_DELTA) { + _angularDamping = clampedDamping; _dirtyFlags |= EntityItem::DIRTY_MATERIAL; } } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index f76f311269..56b178cc4f 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -290,7 +290,6 @@ public: void updateDamping(float value); void updateGravityInDomainUnits(const glm::vec3& value); void updateGravity(const glm::vec3& value); - void updateAcceleration(const glm::vec3& value); void updateAngularVelocity(const glm::vec3& value); void updateAngularVelocityInDegrees(const glm::vec3& value) { updateAngularVelocity(glm::radians(value)); } void updateAngularDamping(float value); From c97b11a6e997b8a03cb80006e7019a0e7a4c35f0 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 6 May 2015 11:48:31 -0700 Subject: [PATCH 45/89] no ownership of kinematic objects on collision --- libraries/physics/src/PhysicsEngine.cpp | 28 ++++++++++++++++--------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 4b90866ce7..dc17e50972 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -253,11 +253,15 @@ void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const ObjectMotionState* a = static_cast(objectA->getUserPointer()); ObjectMotionState* b = static_cast(objectB->getUserPointer()); - if (b && ((a && !objectA->isStaticOrKinematicObject()) || (objectA == characterObject))) { + if (b && ((a && !objectA->isStaticObject()) || (objectA == characterObject))) { + // NOTE: we might own the simulation of a kinematic object (A) + // but we don't claim ownership of kinematic objects (B) based on collisions here. if (!objectB->isStaticOrKinematicObject()) { b->bump(); } - } else if (a && ((b && !objectB->isStaticOrKinematicObject()) || (objectB == characterObject))) { + } else if (a && ((b && !objectB->isStaticObject()) || (objectB == characterObject))) { + // SIMILARLY: we might own the simulation of a kinematic object (B) + // but we don't claim ownership of kinematic objects (A) based on collisions here. if (!objectA->isStaticOrKinematicObject()) { a->bump(); } @@ -377,16 +381,20 @@ void PhysicsEngine::bump(ObjectMotionState* motionState) { const btCollisionObject* objectA = static_cast(contactManifold->getBody0()); const btCollisionObject* objectB = static_cast(contactManifold->getBody1()); if (objectB == object) { - ObjectMotionState* motionStateA = static_cast(objectA->getUserPointer()); - if (motionStateA) { - motionStateA->bump(); - objectA->setActivationState(ACTIVE_TAG); + if (!objectA->isStaticOrKinematicObject()) { + ObjectMotionState* motionStateA = static_cast(objectA->getUserPointer()); + if (motionStateA) { + motionStateA->bump(); + objectA->setActivationState(ACTIVE_TAG); + } } } else if (objectA == object) { - ObjectMotionState* motionStateB = static_cast(objectB->getUserPointer()); - if (motionStateB) { - motionStateB->bump(); - objectB->setActivationState(ACTIVE_TAG); + if (!objectB->isStaticOrKinematicObject()) { + ObjectMotionState* motionStateB = static_cast(objectB->getUserPointer()); + if (motionStateB) { + motionStateB->bump(); + objectB->setActivationState(ACTIVE_TAG); + } } } } From 96a44314c98226007ad216e0f85986a53b787634 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 6 May 2015 13:29:54 -0700 Subject: [PATCH 46/89] don't have interface give up ownership --- libraries/physics/src/EntityMotionState.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index f0b1e45a62..42ab178978 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -339,12 +339,12 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ setShouldClaimSimulationOwnership(false); } else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { // we are the simulator and the entity has stopped. give up "simulator" status - _entity->setSimulatorID(QUuid()); - properties.setSimulatorID(QUuid()); + // _entity->setSimulatorID(QUuid()); + // properties.setSimulatorID(QUuid()); } else if (simulatorID == myNodeID && !_body->isActive()) { // it's not active. don't keep simulation ownership. - _entity->setSimulatorID(QUuid()); - properties.setSimulatorID(QUuid()); + // _entity->setSimulatorID(QUuid()); + // properties.setSimulatorID(QUuid()); } // RELIABLE_SEND_HACK: count number of updates for entities at rest so we can stop sending them after some limit. From fe308c0189a8a9691cacbc2646246743be7b389e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 6 May 2015 13:50:14 -0700 Subject: [PATCH 47/89] only do infection during collisions if one of the objects is being simulated by this interface --- libraries/physics/src/EntityMotionState.cpp | 14 ++++++++++++-- libraries/physics/src/EntityMotionState.h | 1 + libraries/physics/src/ObjectMotionState.h | 1 + libraries/physics/src/PhysicsEngine.cpp | 4 ++-- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 42ab178978..d6857de337 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -112,8 +112,8 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { } if (_movingStepsWithoutSimulationOwner > 100) { // XXX maybe meters from our characterController ? - qDebug() << "XXX XXX XXX -- claiming something I saw moving"; - setShouldClaimSimulationOwnership(true); + // qDebug() << "XXX XXX XXX -- claiming something I saw moving"; + // setShouldClaimSimulationOwnership(true); } #ifdef WANT_DEBUG @@ -406,6 +406,16 @@ uint32_t EntityMotionState::getAndClearIncomingDirtyFlags() const { return dirtyFlags; } + +// virtual +QUuid EntityMotionState::getSimulatorID() const { + if (_entity) { + return _entity->getSimulatorID(); + } + return QUuid(); +} + + // virtual void EntityMotionState::bump() { setShouldClaimSimulationOwnership(true); diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 737dc5b81c..49aead0050 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -68,6 +68,7 @@ public: virtual const QUuid& getObjectID() const { return _entity->getID(); } + virtual QUuid getSimulatorID() const; virtual void bump(); EntityItem* getEntity() const { return _entity; } diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 9d04f3e0c4..98d5b8e707 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -116,6 +116,7 @@ public: virtual const QUuid& getObjectID() const = 0; + virtual QUuid getSimulatorID() const = 0; virtual void bump() = 0; friend class PhysicsEngine; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index df1d6c6cee..c5f816424a 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -255,13 +255,13 @@ void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const ObjectMotionState* a = static_cast(objectA->getUserPointer()); ObjectMotionState* b = static_cast(objectB->getUserPointer()); - if (b && ((a && !objectA->isStaticObject()) || (objectA == characterObject))) { + if (b && ((a && a->getSimulatorID() == _sessionID && !objectA->isStaticObject()) || (objectA == characterObject))) { // NOTE: we might own the simulation of a kinematic object (A) // but we don't claim ownership of kinematic objects (B) based on collisions here. if (!objectB->isStaticOrKinematicObject()) { b->bump(); } - } else if (a && ((b && !objectB->isStaticObject()) || (objectB == characterObject))) { + } else if (a && ((b && b->getSimulatorID() == _sessionID && !objectB->isStaticObject()) || (objectB == characterObject))) { // SIMILARLY: we might own the simulation of a kinematic object (B) // but we don't claim ownership of kinematic objects (A) based on collisions here. if (!objectA->isStaticOrKinematicObject()) { From 86ec12b22c36eb75577fd68c5aeb4264eef686a9 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 6 May 2015 14:30:45 -0700 Subject: [PATCH 48/89] don't increase moving-without-simulator counter unless the thing is moving enough --- libraries/entities/src/EntityItem.h | 8 ++++++++ libraries/physics/src/EntityMotionState.cpp | 19 +++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 56b178cc4f..ed01aa7ca2 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -389,5 +389,13 @@ protected: }; +extern const float IGNORE_POSITION_DELTA; +extern const float IGNORE_DIMENSIONS_DELTA; +extern const float IGNORE_ALIGNMENT_DOT; +extern const float IGNORE_LINEAR_VELOCITY_DELTA; +extern const float IGNORE_DAMPING_DELTA; +extern const float IGNORE_GRAVITY_DELTA; +extern const float IGNORE_ANGULAR_VELOCITY_DELTA; + #endif // hifi_EntityItem_h diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index d6857de337..2e3013af0f 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -104,16 +104,23 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { _entity->setLastSimulated(usecTimestampNow()); - if (_entity->getSimulatorID().isNull() && isMoving()) { - // object is moving and has no owner. attempt to claim simulation ownership. - _movingStepsWithoutSimulationOwner++; + // if (_entity->getSimulatorID().isNull() && isMoving()) { + if (_entity->getSimulatorID().isNull()) { + // if object is moving and has no owner, attempt to claim simulation ownership. + auto alignmentDot = glm::abs(glm::dot(_sentRotation, _entity->getRotation())); + if (glm::distance(_sentPosition, _entity->getPosition()) > IGNORE_POSITION_DELTA || + alignmentDot < IGNORE_ALIGNMENT_DOT) { + _movingStepsWithoutSimulationOwner++; + } else { + _movingStepsWithoutSimulationOwner = 0; + } } else { _movingStepsWithoutSimulationOwner = 0; } - if (_movingStepsWithoutSimulationOwner > 100) { // XXX maybe meters from our characterController ? - // qDebug() << "XXX XXX XXX -- claiming something I saw moving"; - // setShouldClaimSimulationOwnership(true); + if (_movingStepsWithoutSimulationOwner > 50) { // XXX maybe meters from our characterController ? + qDebug() << "XXX XXX XXX -- claiming something I saw moving"; + setShouldClaimSimulationOwnership(true); } #ifdef WANT_DEBUG From b3af1840c798df4ee26ff393a1ef3912b23c9db3 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Thu, 7 May 2015 00:14:49 +0200 Subject: [PATCH 49/89] Added transparency and positioning updating of Planky button --- examples/example/games/planky.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/example/games/planky.js b/examples/example/games/planky.js index 77711958ea..3d8e5b9cf8 100644 --- a/examples/example/games/planky.js +++ b/examples/example/games/planky.js @@ -52,7 +52,7 @@ var button = Overlays.addOverlay('image', { width: BUTTON_DIMENSIONS.width, height: BUTTON_DIMENSIONS.height, imageURL: HIFI_PUBLIC_BUCKET + 'marketplace/hificontent/Games/blocks/planky_button.svg', - alpha: 1 + alpha: 0.8 }); @@ -133,7 +133,10 @@ function cleanup() { } function onUpdate() { - + if (windowWidth != Window.innerWidth) { + windowWidth = Window.innerWidth; + Overlays.editOverlay(button, {x: getButtonPosX()}); + } } Script.update.connect(onUpdate) From 4c3cbea2613d8c91660442d775594253ee32a9cb Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 6 May 2015 15:32:02 -0700 Subject: [PATCH 50/89] don't auto-remove simulation owner unless the Node is gone. put back code that causes interfaces to give up ownership --- libraries/entities/src/SimpleEntitySimulation.cpp | 11 ++++++++--- libraries/physics/src/EntityMotionState.cpp | 8 ++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index aa1e224a24..cda5937580 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -21,15 +21,20 @@ void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { // If an Entity has a simulation owner and we don't get an update for some amount of time, // clear the owner. This guards against an interface failing to release the Entity when it // has finished simulating it. + auto nodeList = DependencyManager::get(); + SetOfEntities::iterator itemItr = _hasSimulationOwnerEntities.begin(); while (itemItr != _hasSimulationOwnerEntities.end()) { EntityItem* entity = *itemItr; if (entity->getSimulatorID().isNull()) { itemItr = _hasSimulationOwnerEntities.erase(itemItr); } else if (now - entity->getLastChangedOnServer() >= AUTO_REMOVE_SIMULATION_OWNER_USEC) { - qCDebug(entities) << "auto-removing simulation owner" << entity->getSimulatorID(); - entity->setSimulatorID(QUuid()); - itemItr = _hasSimulationOwnerEntities.erase(itemItr); + SharedNodePointer ownerNode = nodeList->nodeWithUUID(entity->getSimulatorID()); + if (ownerNode.isNull() || !ownerNode->isAlive()) { + qCDebug(entities) << "auto-removing simulation owner" << entity->getSimulatorID(); + entity->setSimulatorID(QUuid()); + itemItr = _hasSimulationOwnerEntities.erase(itemItr); + } } else { ++itemItr; } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 2e3013af0f..01047efb4a 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -346,12 +346,12 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ setShouldClaimSimulationOwnership(false); } else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { // we are the simulator and the entity has stopped. give up "simulator" status - // _entity->setSimulatorID(QUuid()); - // properties.setSimulatorID(QUuid()); + _entity->setSimulatorID(QUuid()); + properties.setSimulatorID(QUuid()); } else if (simulatorID == myNodeID && !_body->isActive()) { // it's not active. don't keep simulation ownership. - // _entity->setSimulatorID(QUuid()); - // properties.setSimulatorID(QUuid()); + _entity->setSimulatorID(QUuid()); + properties.setSimulatorID(QUuid()); } // RELIABLE_SEND_HACK: count number of updates for entities at rest so we can stop sending them after some limit. From c63b8a93ec2ee7f6d06ee9afc73553eb1700c836 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 6 May 2015 15:48:45 -0700 Subject: [PATCH 51/89] oops fix endless loop --- libraries/entities/src/SimpleEntitySimulation.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index cda5937580..d8a5cacb51 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -34,6 +34,8 @@ void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { qCDebug(entities) << "auto-removing simulation owner" << entity->getSimulatorID(); entity->setSimulatorID(QUuid()); itemItr = _hasSimulationOwnerEntities.erase(itemItr); + } else { + ++itemItr; } } else { ++itemItr; From 584b64379146fe52d1038e04a19010bded8c3599 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 6 May 2015 16:01:00 -0700 Subject: [PATCH 52/89] lock entitySimulation during physics simulation --- interface/src/Application.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5c9842b777..2c30e9f32d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2420,15 +2420,19 @@ void Application::update(float deltaTime) { PerformanceTimer perfTimer("physics"); _myAvatar->relayDriveKeysToCharacterController(); + _entitySimulation.lock(); _physicsEngine.deleteObjects(_entitySimulation.getObjectsToDelete()); _physicsEngine.addObjects(_entitySimulation.getObjectsToAdd()); _physicsEngine.changeObjects(_entitySimulation.getObjectsToChange()); + _entitySimulation.unlock(); _physicsEngine.stepSimulation(); if (_physicsEngine.hasOutgoingChanges()) { + _entitySimulation.lock(); _entitySimulation.handleOutgoingChanges(_physicsEngine.getOutgoingChanges()); _entitySimulation.handleCollisionEvents(_physicsEngine.getCollisionEvents()); + _entitySimulation.unlock(); _physicsEngine.dumpStatsIfNecessary(); } } From 7b1886a285293d6ff9a235957bc4064103d0d6d6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 6 May 2015 16:01:25 -0700 Subject: [PATCH 53/89] harvest outgoing changes for non-NULL entities --- libraries/physics/src/PhysicalEntitySimulation.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index 81f147540a..bc3c5eda44 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -194,8 +194,11 @@ void PhysicalEntitySimulation::handleOutgoingChanges(VectorOfMotionStates& motio ObjectMotionState* state = &(*stateItr); if (state && state->getType() == MOTION_STATE_TYPE_ENTITY) { EntityMotionState* entityState = static_cast(state); - _outgoingChanges.insert(entityState); - _entitiesToSort.insert(entityState->getEntity()); + EntityItem* entity = entityState->getEntity(); + if (entity) { + _outgoingChanges.insert(entityState); + _entitiesToSort.insert(entityState->getEntity()); + } } } From 452e84d43f458b2818cc98eaeb0aad0859e9c250 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 6 May 2015 16:02:03 -0700 Subject: [PATCH 54/89] only update physics when proper flags are set --- libraries/physics/src/PhysicsEngine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index df1d6c6cee..ee86c49e35 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -178,7 +178,7 @@ void PhysicsEngine::changeObjects(VectorOfMotionStates& objects) { uint32_t flags = object->getAndClearIncomingDirtyFlags() & DIRTY_PHYSICS_FLAGS; if (flags & HARD_DIRTY_PHYSICS_FLAGS) { object->handleHardAndEasyChanges(flags, this); - } else { + } else if (flags & EASY_DIRTY_PHYSICS_FLAGS) { object->handleEasyChanges(flags); } } From b0ccabe38eb906b0b23e775b9f92a8c86da6048a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 6 May 2015 16:05:05 -0700 Subject: [PATCH 55/89] update a motionstate's idea of what the entity-server thinks when an incoming update packet arrives --- libraries/physics/src/EntityMotionState.cpp | 28 +++++++++++++++++++++ libraries/physics/src/EntityMotionState.h | 5 ++++ libraries/physics/src/ObjectMotionState.h | 4 +-- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 01047efb4a..1f4b45318f 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -47,6 +47,34 @@ EntityMotionState::~EntityMotionState() { assert(!_entity); } +void EntityMotionState::updateServerPhysicsVariables(uint32_t flags) { + if (flags & EntityItem::DIRTY_POSITION) { + _sentPosition = _entity->getPosition(); + } + if (flags & EntityItem::DIRTY_ROTATION) { + _sentRotation = _entity->getRotation(); + } + if (flags & EntityItem::DIRTY_LINEAR_VELOCITY) { + _sentVelocity = _entity->getVelocity(); + } + if (flags & EntityItem::DIRTY_ANGULAR_VELOCITY) { + _sentAngularVelocity = _entity->getAngularVelocity(); + } +} + +// virtual +void EntityMotionState::handleEasyChanges(uint32_t flags) { + updateServerPhysicsVariables(flags); + ObjectMotionState::handleEasyChanges(flags); +} + + +// virtual +void EntityMotionState::handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* engine) { + updateServerPhysicsVariables(flags); + ObjectMotionState::handleHardAndEasyChanges(flags, engine); +} + void EntityMotionState::clearEntity() { _entity = nullptr; } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 49aead0050..39f6bc0814 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -28,6 +28,10 @@ public: EntityMotionState(btCollisionShape* shape, EntityItem* item); virtual ~EntityMotionState(); + void updateServerPhysicsVariables(uint32_t flags); + virtual void handleEasyChanges(uint32_t flags); + virtual void handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* engine); + /// \return MOTION_TYPE_DYNAMIC or MOTION_TYPE_STATIC based on params set in EntityItem virtual MotionType computeObjectMotionType() const; @@ -88,6 +92,7 @@ protected: bool _sentMoving; // true if last update was moving int _numNonMovingUpdates; // RELIABLE_SEND_HACK for "not so reliable" resends of packets for non-moving objects + // TODO XXX rename _sent* to _server* uint32_t _sentStep; glm::vec3 _sentPosition; // in simulation-frame (not world-frame) glm::quat _sentRotation;; diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 98d5b8e707..4836cf52fd 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -68,8 +68,8 @@ public: ObjectMotionState(btCollisionShape* shape); ~ObjectMotionState(); - void handleEasyChanges(uint32_t flags); - void handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* engine); + virtual void handleEasyChanges(uint32_t flags); + virtual void handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* engine); virtual void updateBodyMaterialProperties(); virtual void updateBodyVelocities(); From 630f1ce9d9ce55a7e983e14e1c43fd9c65bbef14 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 6 May 2015 16:13:07 -0700 Subject: [PATCH 56/89] isMovingVsServer function --- libraries/physics/src/EntityMotionState.cpp | 19 +++++++++++-------- libraries/physics/src/EntityMotionState.h | 1 + 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 1f4b45318f..f9d054379a 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -93,6 +93,15 @@ bool EntityMotionState::isMoving() const { return _entity && _entity->isMoving(); } +bool EntityMotionState::isMovingVsServer() const { + auto alignmentDot = glm::abs(glm::dot(_sentRotation, _entity->getRotation())); + if (glm::distance(_sentPosition, _entity->getPosition()) > IGNORE_POSITION_DELTA || + alignmentDot < IGNORE_ALIGNMENT_DOT) { + return true; + } + return false; +} + // 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) @@ -133,15 +142,9 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { _entity->setLastSimulated(usecTimestampNow()); // if (_entity->getSimulatorID().isNull() && isMoving()) { - if (_entity->getSimulatorID().isNull()) { + if (_entity->getSimulatorID().isNull() && isMovingVsServer()) { // if object is moving and has no owner, attempt to claim simulation ownership. - auto alignmentDot = glm::abs(glm::dot(_sentRotation, _entity->getRotation())); - if (glm::distance(_sentPosition, _entity->getPosition()) > IGNORE_POSITION_DELTA || - alignmentDot < IGNORE_ALIGNMENT_DOT) { - _movingStepsWithoutSimulationOwner++; - } else { - _movingStepsWithoutSimulationOwner = 0; - } + _movingStepsWithoutSimulationOwner++; } else { _movingStepsWithoutSimulationOwner = 0; } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 39f6bc0814..71b1962368 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -36,6 +36,7 @@ public: virtual MotionType computeObjectMotionType() const; virtual bool isMoving() const; + virtual bool isMovingVsServer() const; // this relays incoming position/rotation to the RigidBody virtual void getWorldTransform(btTransform& worldTrans) const; From b76e22c9529f21b42e481d5f1d5290434bfe82e0 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Thu, 7 May 2015 01:14:16 +0200 Subject: [PATCH 57/89] spelling mistake --- examples/example/games/planky.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/example/games/planky.js b/examples/example/games/planky.js index 3d8e5b9cf8..450a411ad8 100644 --- a/examples/example/games/planky.js +++ b/examples/example/games/planky.js @@ -93,7 +93,7 @@ function resetBlocks() { type: 'Model', modelURL: HIFI_PUBLIC_BUCKET + 'marketplace/hificontent/Games/blocks/block.fbx', shapeType: 'box', - name: 'JengaBlock' + ((layerIndex * BLOCKS_PER_LAYER) + blockIndex), + name: 'PlankyBlock' + ((layerIndex * BLOCKS_PER_LAYER) + blockIndex), dimensions: BLOCK_SIZE, position: { x: basePosition.x + localTransform.x, From ba6f6d19cc4becb4051b37c879969555175058c3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 6 May 2015 16:20:16 -0700 Subject: [PATCH 58/89] disable updateServerPhysicsVariables --- libraries/physics/src/EntityMotionState.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index f9d054379a..c532c3e85e 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -48,6 +48,7 @@ EntityMotionState::~EntityMotionState() { } void EntityMotionState::updateServerPhysicsVariables(uint32_t flags) { + /* if (flags & EntityItem::DIRTY_POSITION) { _sentPosition = _entity->getPosition(); } @@ -60,6 +61,7 @@ void EntityMotionState::updateServerPhysicsVariables(uint32_t flags) { if (flags & EntityItem::DIRTY_ANGULAR_VELOCITY) { _sentAngularVelocity = _entity->getAngularVelocity(); } + */ } // virtual From cc5f2ee4510d4b662c6178cf1debee6b722fd2b3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 6 May 2015 16:26:27 -0700 Subject: [PATCH 59/89] in isMovingVsServer look at entity velocity only --- libraries/physics/src/EntityMotionState.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index c532c3e85e..27fa51b5d4 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -96,9 +96,17 @@ bool EntityMotionState::isMoving() const { } bool EntityMotionState::isMovingVsServer() const { - auto alignmentDot = glm::abs(glm::dot(_sentRotation, _entity->getRotation())); - if (glm::distance(_sentPosition, _entity->getPosition()) > IGNORE_POSITION_DELTA || - alignmentDot < IGNORE_ALIGNMENT_DOT) { + // auto alignmentDot = glm::abs(glm::dot(_sentRotation, _entity->getRotation())); + // if (glm::distance(_sentPosition, _entity->getPosition()) > IGNORE_POSITION_DELTA || + // alignmentDot < IGNORE_ALIGNMENT_DOT) { + // return true; + // } + // return false; + + if (glm::length(_entity->getVelocity()) > IGNORE_LINEAR_VELOCITY_DELTA) { + return true; + } + if (glm::length(_entity->getAngularVelocity()) > IGNORE_ANGULAR_VELOCITY_DELTA) { return true; } return false; From 5ac85581683407dc5a330dd63cd44decf9d838d8 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 6 May 2015 17:03:27 -0700 Subject: [PATCH 60/89] flash yellow box when transmitting an edit packet --- .../src/RenderableDebugableEntityItem.cpp | 19 ++++++++++--------- .../src/RenderableDebugableEntityItem.h | 2 +- .../src/RenderableModelEntityItem.cpp | 3 ++- libraries/entities/src/EntityItem.h | 5 +++++ .../entities/src/EntityScriptingInterface.cpp | 2 ++ libraries/physics/src/EntityMotionState.cpp | 1 + 6 files changed, 21 insertions(+), 11 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp b/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp index 4d38d0d747..98ec154d01 100644 --- a/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp @@ -19,7 +19,8 @@ #include "RenderableDebugableEntityItem.h" -void RenderableDebugableEntityItem::renderBoundingBox(EntityItem* entity, RenderArgs* args, bool puffedOut) { +void RenderableDebugableEntityItem::renderBoundingBox(EntityItem* entity, RenderArgs* args, + float puffedOut, glm::vec4& color) { glm::vec3 position = entity->getPosition(); glm::vec3 center = entity->getCenter(); glm::vec3 dimensions = entity->getDimensions(); @@ -33,13 +34,7 @@ void RenderableDebugableEntityItem::renderBoundingBox(EntityItem* entity, Render glm::vec3 positionToCenter = center - position; glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); glScalef(dimensions.x, dimensions.y, dimensions.z); - if (puffedOut) { - glm::vec4 redColor(1.0f, 0.0f, 0.0f, 1.0f); - DependencyManager::get()->renderWireCube(1.2f, redColor); - } else { - glm::vec4 greenColor(0.0f, 1.0f, 0.0f, 1.0f); - DependencyManager::get()->renderWireCube(1.0f, greenColor); - } + DependencyManager::get()->renderWireCube(1.0f + puffedOut, color); glPopMatrix(); glPopMatrix(); } @@ -76,7 +71,13 @@ void RenderableDebugableEntityItem::render(EntityItem* entity, RenderArgs* args) if (debugSimulationOwnership) { quint64 now = usecTimestampNow(); if (now - entity->getLastEditedFromRemote() < 0.1f * USECS_PER_SECOND) { - renderBoundingBox(entity, args, true); + glm::vec4 redColor(1.0f, 0.0f, 0.0f, 1.0f); + renderBoundingBox(entity, args, 0.2f, redColor); + } + + if (now - entity->getLastBroadcast() < 0.2f * USECS_PER_SECOND) { + glm::vec4 yellowColor(1.0f, 1.0f, 0.2f, 1.0f); + renderBoundingBox(entity, args, 0.3f, yellowColor); } } diff --git a/libraries/entities-renderer/src/RenderableDebugableEntityItem.h b/libraries/entities-renderer/src/RenderableDebugableEntityItem.h index f3550cb116..758bac353b 100644 --- a/libraries/entities-renderer/src/RenderableDebugableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableDebugableEntityItem.h @@ -16,7 +16,7 @@ class RenderableDebugableEntityItem { public: - static void renderBoundingBox(EntityItem* entity, RenderArgs* args, bool puffedOut); + static void renderBoundingBox(EntityItem* entity, RenderArgs* args, float puffedOut, glm::vec4& color); static void renderHoverDot(EntityItem* entity, RenderArgs* args); static void render(EntityItem* entity, RenderArgs* args); }; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index b3232bcb57..f097ae4e2f 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -192,7 +192,8 @@ void RenderableModelEntityItem::render(RenderArgs* args) { } if (!didDraw) { - RenderableDebugableEntityItem::renderBoundingBox(this, args, false); + glm::vec4 greenColor(0.0f, 1.0f, 0.0f, 1.0f); + RenderableDebugableEntityItem::renderBoundingBox(this, args, 0.0f, greenColor); } RenderableDebugableEntityItem::render(this, args); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index ed01aa7ca2..63d58fd40f 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -104,6 +104,10 @@ public: float getEditedAgo() const /// Elapsed seconds since this entity was last edited { return (float)(usecTimestampNow() - getLastEdited()) / (float)USECS_PER_SECOND; } + /// Last time we sent out an edit packet for this entity + quint64 getLastBroadcast() const { return _lastBroadcast; } + void setLastBroadcast(quint64 lastBroadcast) { _lastBroadcast = lastBroadcast; } + void markAsChangedOnServer() { _changedOnServer = usecTimestampNow(); } quint64 getLastChangedOnServer() const { return _changedOnServer; } @@ -328,6 +332,7 @@ protected: quint64 _lastSimulated; // last time this entity called simulate(), this includes velocity, angular velocity, and physics changes quint64 _lastUpdated; // last time this entity called update(), this includes animations and non-physics changes quint64 _lastEdited; // last official local or remote edit time + quint64 _lastBroadcast; // the last time we sent an edit packet about this entity quint64 _lastEditedFromRemote; // last time we received and edit from the server quint64 _lastEditedFromRemoteInRemoteTime; // last time we received an edit from the server (in server-time-frame) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 6632574db8..46ca70aa43 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -86,6 +86,7 @@ EntityItemID EntityScriptingInterface::addEntity(const EntityItemProperties& pro if (_entityTree) { _entityTree->lockForWrite(); EntityItem* entity = _entityTree->addEntity(id, propertiesWithSimID); + entity->setLastBroadcast(usecTimestampNow()); if (entity) { // This Node is creating a new object. If it's in motion, set this Node as the simulator. setSimId(propertiesWithSimID, entity); @@ -178,6 +179,7 @@ EntityItemID EntityScriptingInterface::editEntity(EntityItemID entityID, const E if (propertiesWithSimID.getType() == EntityTypes::Unknown) { EntityItem* entity = _entityTree->findEntityByEntityItemID(entityID); if (entity) { + entity->setLastBroadcast(usecTimestampNow()); propertiesWithSimID.setType(entity->getType()); setSimId(propertiesWithSimID, entity); } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 27fa51b5d4..f1c0daea26 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -429,6 +429,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ #endif entityPacketSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties); + _entity->setLastBroadcast(usecTimestampNow()); } else { #ifdef WANT_DEBUG qCDebug(physics) << "EntityMotionState::sendUpdate()... NOT sending update as requested."; From 411bf1a35ca12ac6ae6b776b7e8170f162a02a84 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 6 May 2015 17:48:10 -0700 Subject: [PATCH 61/89] fix for entity-server kinematic simulation --- libraries/entities/src/SimpleEntitySimulation.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index d8a5cacb51..518d10d056 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -57,6 +57,7 @@ void SimpleEntitySimulation::removeEntityInternal(EntityItem* entity) { const int SIMPLE_SIMULATION_DIRTY_FLAGS = EntityItem::DIRTY_VELOCITIES | EntityItem::DIRTY_MOTION_TYPE; void SimpleEntitySimulation::changeEntityInternal(EntityItem* entity) { + EntitySimulation::changeEntityInternal(entity); if (!entity->getSimulatorID().isNull()) { _hasSimulationOwnerEntities.insert(entity); } From 0eeff526d58a372311331fe6f9456ce9dc06bf2d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 7 May 2015 08:50:27 -0700 Subject: [PATCH 62/89] Add shortcut key for face tracker muting --- interface/src/Menu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 405f98c8d7..425f9d13d9 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -396,7 +396,7 @@ Menu::Menu() { #if defined(HAVE_FACESHIFT) || defined(HAVE_DDE) faceTrackingMenu->addSeparator(); addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::MuteFaceTracking, - 0, false, + Qt::CTRL | Qt::SHIFT | Qt::Key_F, false, qApp, SLOT(toggleFaceTrackerMute())); #endif From fe14202f512119ada1c633eda7dfa419eca8f597 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 7 May 2015 09:53:39 -0700 Subject: [PATCH 63/89] add getName passthrough to ObjecdtMotionState, don't compute model shapes until the model has been simulated --- .../entities-renderer/src/RenderableModelEntityItem.cpp | 5 +++++ libraries/fbx/src/OBJReader.cpp | 4 ++-- libraries/physics/src/EntityMotionState.cpp | 9 +++++++++ libraries/physics/src/EntityMotionState.h | 2 ++ libraries/physics/src/ObjectMotionState.h | 2 ++ 5 files changed, 20 insertions(+), 2 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index f097ae4e2f..43112d7d73 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -278,6 +278,11 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { return false; // hmm... } + if (_needsInitialSimulation) { + // the _model's offset will be wrong until _needsInitialSimulation is false + return false; + } + assert(!_model->getCollisionURL().isEmpty()); if (_model->getURL().isEmpty()) { diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index ebfa9b54f0..c4e2178b6b 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -484,7 +484,7 @@ FBXGeometry OBJReader::readOBJ(QIODevice* device, const QVariantHash& mapping, Q meshPart._material->setShininess(material->shininess); meshPart._material->setOpacity(material->opacity); } - qCDebug(modelformat) << "OBJ Reader part:" << meshPartCount << "name:" << leadFace.groupName << "material:" << groupMaterialName << "diffuse:" << meshPart._material->getDiffuse() << "faces:" << faceGroup.count() << "triangle indices will start with:" << mesh.vertices.count(); + // qCDebug(modelformat) << "OBJ Reader part:" << meshPartCount << "name:" << leadFace.groupName << "material:" << groupMaterialName << "diffuse:" << meshPart._material->getDiffuse() << "faces:" << faceGroup.count() << "triangle indices will start with:" << mesh.vertices.count(); foreach(OBJFace face, faceGroup) { glm::vec3 v0 = vertices[face.vertexIndices[0]]; glm::vec3 v1 = vertices[face.vertexIndices[1]]; @@ -526,7 +526,7 @@ FBXGeometry OBJReader::readOBJ(QIODevice* device, const QVariantHash& mapping, Q mesh.meshExtents.addPoint(vertex); geometry.meshExtents.addPoint(vertex); } - fbxDebugDump(geometry); + // fbxDebugDump(geometry); } catch(const std::exception& e) { qCDebug(modelformat) << "OBJ reader fail: " << e.what(); } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index f1c0daea26..1e5bdac32d 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -502,3 +502,12 @@ void EntityMotionState::setMotionType(MotionType motionType) { ObjectMotionState::setMotionType(motionType); resetMeasuredBodyAcceleration(); } + + +// virtual +QString EntityMotionState::getName() { + if (_entity) { + return _entity->getName(); + } + return ""; +} diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 71b1962368..1c45b40627 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -81,6 +81,8 @@ public: void resetMeasuredBodyAcceleration(); void measureBodyAcceleration(); + virtual QString getName(); + friend class PhysicalEntitySimulation; protected: diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 4836cf52fd..edfff27e8d 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -119,6 +119,8 @@ public: virtual QUuid getSimulatorID() const = 0; virtual void bump() = 0; + virtual QString getName() { return ""; } + friend class PhysicsEngine; protected: From 867fe184724c6b98ff61a81b5d23069a5784bc5e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 7 May 2015 10:11:36 -0700 Subject: [PATCH 64/89] put some code back now that entity-server is doing simple simulation again. don't draw blue physics-enabled dot unless debug menu-item is checked --- .../src/RenderableDebugableEntityItem.cpp | 21 ++++--------------- libraries/physics/src/EntityMotionState.cpp | 16 +++----------- 2 files changed, 7 insertions(+), 30 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp b/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp index 98ec154d01..017cb289f0 100644 --- a/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp @@ -79,22 +79,9 @@ void RenderableDebugableEntityItem::render(EntityItem* entity, RenderArgs* args) glm::vec4 yellowColor(1.0f, 1.0f, 0.2f, 1.0f); renderBoundingBox(entity, args, 0.3f, yellowColor); } + + if (PhysicsEngine::physicsInfoIsActive(entity->getPhysicsInfo())) { + renderHoverDot(entity, args); + } } - - if (PhysicsEngine::physicsInfoIsActive(entity->getPhysicsInfo())) { - renderHoverDot(entity, args); - } - - glm::vec3 position; - glm::quat rotation; - - // - // XXX for future debugging - // - // if (PhysicsEngine::getBodyLocation(entity->getPhysicsInfo(), position, rotation)) { - // glm::vec3 positionOffset = glm::abs(position - entity->getPosition()); - // if (positionOffset[0] > 0.001 || positionOffset[1] > 0.001 || positionOffset[2] > 0.001) { - // qDebug() << positionOffset[0] << positionOffset[1] << positionOffset[2]; - // } - // } } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 1e5bdac32d..1428287f8f 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -48,7 +48,6 @@ EntityMotionState::~EntityMotionState() { } void EntityMotionState::updateServerPhysicsVariables(uint32_t flags) { - /* if (flags & EntityItem::DIRTY_POSITION) { _sentPosition = _entity->getPosition(); } @@ -61,7 +60,6 @@ void EntityMotionState::updateServerPhysicsVariables(uint32_t flags) { if (flags & EntityItem::DIRTY_ANGULAR_VELOCITY) { _sentAngularVelocity = _entity->getAngularVelocity(); } - */ } // virtual @@ -96,17 +94,9 @@ bool EntityMotionState::isMoving() const { } bool EntityMotionState::isMovingVsServer() const { - // auto alignmentDot = glm::abs(glm::dot(_sentRotation, _entity->getRotation())); - // if (glm::distance(_sentPosition, _entity->getPosition()) > IGNORE_POSITION_DELTA || - // alignmentDot < IGNORE_ALIGNMENT_DOT) { - // return true; - // } - // return false; - - if (glm::length(_entity->getVelocity()) > IGNORE_LINEAR_VELOCITY_DELTA) { - return true; - } - if (glm::length(_entity->getAngularVelocity()) > IGNORE_ANGULAR_VELOCITY_DELTA) { + auto alignmentDot = glm::abs(glm::dot(_sentRotation, _entity->getRotation())); + if (glm::distance(_sentPosition, _entity->getPosition()) > IGNORE_POSITION_DELTA || + alignmentDot < IGNORE_ALIGNMENT_DOT) { return true; } return false; From fe5cfdf4954aa86802c12862f8018ab30eb5f306 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 7 May 2015 10:28:38 -0700 Subject: [PATCH 65/89] fix crash bug when obj deleted but dangling pointer still on _pendingAdd which would not be removed during getObjectsToDelete() because backpointers had been disconnected --- libraries/physics/src/PhysicalEntitySimulation.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index bc3c5eda44..cf88af4942 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -67,6 +67,12 @@ void PhysicalEntitySimulation::removeEntityInternal(EntityItem* entity) { if (motionState) { motionState->clearEntity(); entity->setPhysicsInfo(nullptr); + + // NOTE: we must remove entity from _pendingAdds immediately because we've disconnected the backpointers between + // motionState and entity and they can't be used to look up each other. However we don't need to remove + // motionState from _pendingChanges at this time becuase it will be removed during getObjectsToDelete(). + _pendingAdds.remove(entity); + _pendingRemoves.insert(motionState); _outgoingChanges.remove(motionState); } From 070140440da06fe132b34516259083ff15c93c9a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 7 May 2015 10:30:22 -0700 Subject: [PATCH 66/89] fix crash bug when invalid entity ptr accessed --- libraries/physics/src/EntityMotionState.cpp | 2 ++ libraries/physics/src/ObjectMotionState.h | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index f1c0daea26..58a0a2c53b 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -79,6 +79,8 @@ void EntityMotionState::handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* void EntityMotionState::clearEntity() { _entity = nullptr; + // set the type to INVALID so that external logic that pivots on the type won't try to access _entity + _type = MOTION_STATE_TYPE_INVALID; } MotionType EntityMotionState::computeObjectMotionType() const { diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 4836cf52fd..343ad2ce24 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -27,7 +27,7 @@ enum MotionType { }; enum MotionStateType { - MOTION_STATE_TYPE_UNKNOWN, + MOTION_STATE_TYPE_INVALID, MOTION_STATE_TYPE_ENTITY, MOTION_STATE_TYPE_AVATAR }; @@ -125,7 +125,7 @@ protected: virtual void setMotionType(MotionType motionType); void setRigidBody(btRigidBody* body); - MotionStateType _type = MOTION_STATE_TYPE_UNKNOWN; // type of MotionState + MotionStateType _type = MOTION_STATE_TYPE_INVALID; // type of MotionState MotionType _motionType; // type of motion: KINEMATIC, DYNAMIC, or STATIC btCollisionShape* _shape; From 9acdb3fb2889d5cc8b48e50b471c5ea77774b122 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 7 May 2015 10:47:50 -0700 Subject: [PATCH 67/89] Proper defaults for material properties and a fail-safe for missing uv coordinates. --- libraries/fbx/src/OBJReader.cpp | 5 ++++- libraries/fbx/src/OBJReader.h | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index ebfa9b54f0..186c7b03e8 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -484,7 +484,7 @@ FBXGeometry OBJReader::readOBJ(QIODevice* device, const QVariantHash& mapping, Q meshPart._material->setShininess(material->shininess); meshPart._material->setOpacity(material->opacity); } - qCDebug(modelformat) << "OBJ Reader part:" << meshPartCount << "name:" << leadFace.groupName << "material:" << groupMaterialName << "diffuse:" << meshPart._material->getDiffuse() << "faces:" << faceGroup.count() << "triangle indices will start with:" << mesh.vertices.count(); + qCDebug(modelformat) << "OBJ Reader part:" << meshPartCount << "name:" << leadFace.groupName << "material:" << groupMaterialName << "diffuse:" << meshPart._material->getDiffuse() << " texture:" << meshPart.diffuseTexture.filename << "faces:" << faceGroup.count() << "triangle indices will start with:" << mesh.vertices.count(); foreach(OBJFace face, faceGroup) { glm::vec3 v0 = vertices[face.vertexIndices[0]]; glm::vec3 v1 = vertices[face.vertexIndices[1]]; @@ -510,6 +510,9 @@ FBXGeometry OBJReader::readOBJ(QIODevice* device, const QVariantHash& mapping, Q << textureUVs[face.textureUVIndices[0]] << textureUVs[face.textureUVIndices[1]] << textureUVs[face.textureUVIndices[2]]; + } else { + glm::vec2 corner(0.0f, 1.0f); + mesh.texCoords << corner << corner << corner; } } } diff --git a/libraries/fbx/src/OBJReader.h b/libraries/fbx/src/OBJReader.h index a61665cb86..771c0b1b63 100644 --- a/libraries/fbx/src/OBJReader.h +++ b/libraries/fbx/src/OBJReader.h @@ -56,7 +56,7 @@ public: glm::vec3 specularColor; QByteArray diffuseTextureFilename; QByteArray specularTextureFilename; - OBJMaterial() : opacity(1.0f) {} + OBJMaterial() : shininess(96.0f), opacity(1.0f), diffuseColor(1.0f), specularColor(1.0f) {} }; class OBJReader: public QObject { // QObject so we can make network requests. From 653d2e72b1f5387f64f682848d6670f91601225c Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 7 May 2015 11:23:11 -0700 Subject: [PATCH 68/89] Skybox kind of working --- interface/src/Application.cpp | 6 +++ libraries/gpu/src/gpu/GLBackendState.cpp | 1 + libraries/gpu/src/gpu/GLBackendTexture.cpp | 3 +- libraries/gpu/src/gpu/Texture.h | 4 +- libraries/model/src/model/Material.cpp | 12 ----- libraries/model/src/model/Material.h | 21 -------- libraries/model/src/model/Skybox.cpp | 6 +-- libraries/model/src/model/Stage.cpp | 16 ++++++- libraries/model/src/model/Stage.h | 4 +- libraries/model/src/model/TextureStorage.cpp | 29 +++++++++++ libraries/model/src/model/TextureStorage.h | 48 +++++++++++++++++++ libraries/render-utils/src/TextureCache.cpp | 42 +++++++++++----- libraries/render-utils/src/TextureCache.h | 4 +- .../src/SceneScriptingInterface.cpp | 26 ++++++++++ .../src/SceneScriptingInterface.h | 3 +- 15 files changed, 167 insertions(+), 58 deletions(-) create mode 100755 libraries/model/src/model/TextureStorage.cpp create mode 100755 libraries/model/src/model/TextureStorage.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 021981a80e..bac2aceb75 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3212,6 +3212,12 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs } else if (skyStage->getBackgroundMode() == model::SunSkyStage::SKY_BOX) { auto skybox = skyStage->getSkybox(); if (skybox) { + if (!skybox->getCubemap()) { + auto texture = DependencyManager::get()-> + getTexture(QUrl("https://hifi-public.s3.amazonaws.com/ryan/CloudyDay.png"), CUBE_TEXTURE); + skybox->setCubemap(texture->getGPUTexture()); + } + gpu::Batch batch; model::Skybox::render(batch, _viewFrustum, *skybox); diff --git a/libraries/gpu/src/gpu/GLBackendState.cpp b/libraries/gpu/src/gpu/GLBackendState.cpp index 2d3eacd37f..5670fddb08 100644 --- a/libraries/gpu/src/gpu/GLBackendState.cpp +++ b/libraries/gpu/src/gpu/GLBackendState.cpp @@ -464,6 +464,7 @@ void GLBackend::getCurrentGLState(State::Data& state) { void GLBackend::syncPipelineStateCache() { State::Data state; + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); getCurrentGLState(state); State::Signature signature = State::evalSignature(state); diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 4387821cfd..df275e16ad 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -370,7 +370,8 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { glBindTexture(GL_TEXTURE_CUBE_MAP, object->_texture); const int NUM_FACES = 6; const GLenum FACE_LAYOUT[] = { - GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + // GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z }; diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 883b7c7098..19add9a47e 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -68,11 +68,11 @@ public: uint8 _maxMip = MAX_MIP_LEVEL; Desc() {} - Desc(const Filter filter) : _filter(filter) {} + Desc(const Filter filter, const WrapMode wrap = WRAP_REPEAT) : _filter(filter), _wrapModeU(wrap), _wrapModeV(wrap), _wrapModeW(wrap) {} }; Sampler() {} - Sampler(const Filter filter) : _desc(filter) {} + Sampler(const Filter filter, const WrapMode wrap = WRAP_REPEAT) : _desc(filter, wrap) {} Sampler(const Desc& desc) : _desc(desc) {} ~Sampler() {} diff --git a/libraries/model/src/model/Material.cpp b/libraries/model/src/model/Material.cpp index d27bdd4372..55572a5122 100755 --- a/libraries/model/src/model/Material.cpp +++ b/libraries/model/src/model/Material.cpp @@ -92,15 +92,3 @@ void Material::setTextureView(MapChannel channel, const gpu::TextureView& view) _textureMap[channel] = view; } -// TextureStorage -TextureStorage::TextureStorage(const QUrl& url) : gpu::Texture::Storage(), _url(url) { - init(); -} - -TextureStorage::~TextureStorage() { -} - -void TextureStorage::init() { - _gpuTexture = TexturePointer(Texture::createFromStorage(this)); -} - diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index 7e4417b55b..cd4c6d0373 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -23,27 +23,6 @@ namespace model { -typedef glm::vec3 Color; - -// TextureStorage is a specialized version of the gpu::Texture::Storage -// It adds the URL and the notion that it owns the gpu::Texture -class TextureStorage : public gpu::Texture::Storage { -public: - TextureStorage(const QUrl& url); - ~TextureStorage(); - - const QUrl& getUrl() const { return _url; } - const gpu::TexturePointer& getGPUTexture() const { return _gpuTexture; } - -protected: - gpu::TexturePointer _gpuTexture; - QUrl _url; - void init(); -}; -typedef std::shared_ptr< TextureStorage > TextureStoragePointer; - - - class Material { public: typedef gpu::BufferView UniformBufferView; diff --git a/libraries/model/src/model/Skybox.cpp b/libraries/model/src/model/Skybox.cpp index 8495baf600..b80d5fcb36 100755 --- a/libraries/model/src/model/Skybox.cpp +++ b/libraries/model/src/model/Skybox.cpp @@ -21,7 +21,7 @@ using namespace model; Skybox::Skybox() { - _cubemap.reset( gpu::Texture::createCube(gpu::Element::COLOR_RGBA_32, 1)); +/* _cubemap.reset( gpu::Texture::createCube(gpu::Element::COLOR_RGBA_32, 1)); unsigned char texels[] = { 255, 0, 0, 255, 0, 255, 255, 255, @@ -30,7 +30,7 @@ Skybox::Skybox() { 0, 255, 0, 255, 255, 0, 255, 255, }; - _cubemap->assignStoredMip(0, gpu::Element::COLOR_RGBA_32, sizeof(texels), texels); + _cubemap->assignStoredMip(0, gpu::Element::COLOR_RGBA_32, sizeof(texels), texels); */ } void Skybox::setColor(const Color& color) { @@ -43,7 +43,7 @@ void Skybox::setCubemap(const gpu::TexturePointer& cubemap) { void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Skybox& skybox) { - if (skybox.getCubemap()) { + if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) { static gpu::PipelinePointer thePipeline; static gpu::BufferPointer theBuffer; diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp index c29ebfe83e..e5d23e9191 100644 --- a/libraries/model/src/model/Stage.cpp +++ b/libraries/model/src/model/Stage.cpp @@ -190,7 +190,8 @@ const float NUM_HOURS_PER_DAY = 24.0f; const float NUM_HOURS_PER_HALF_DAY = NUM_HOURS_PER_DAY * 0.5f; SunSkyStage::SunSkyStage() : - _sunLight(new Light()) + _sunLight(new Light()), + _skybox(new Skybox()) { _sunLight->setType(Light::SUN); @@ -290,6 +291,19 @@ void SunSkyStage::updateGraphicsObject() const { _sunLight->setPosition(Vec3(0.0f, originAlt, 0.0f)); } + // Background + switch (getBackgroundMode()) { + case NO_BACKGROUND: { + break; + } + case SKY_DOME: { + break; + } + case SKY_BOX: { + break; + } + }; + static int firstTime = 0; if (firstTime == 0) { firstTime++; diff --git a/libraries/model/src/model/Stage.h b/libraries/model/src/model/Stage.h index b6a19b49cd..a5f39cb825 100644 --- a/libraries/model/src/model/Stage.h +++ b/libraries/model/src/model/Stage.h @@ -223,11 +223,11 @@ public: const SkyboxPointer& getSkybox() const { valid(); return _skybox; } protected: - BackgroundMode _backgroundMode = SKY_DOME; + BackgroundMode _backgroundMode = SKY_BOX; LightPointer _sunLight; AtmospherePointer _atmosphere; - SkyboxPointer _skybox; + mutable SkyboxPointer _skybox; gpu::PipelinePointer _skyPipeline; diff --git a/libraries/model/src/model/TextureStorage.cpp b/libraries/model/src/model/TextureStorage.cpp new file mode 100755 index 0000000000..cc01941424 --- /dev/null +++ b/libraries/model/src/model/TextureStorage.cpp @@ -0,0 +1,29 @@ +// +// TextureStorage.cpp +// libraries/model/src/model +// +// Created by Sam Gateau on 5/6/2015. +// 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 "TextureStorage.h" + +using namespace model; +using namespace gpu; + +// TextureStorage +TextureStorage::TextureStorage(const QUrl& url, Texture::Type type ) : Texture::Storage(), + _url(url), + _type(type) { + init(); +} + +TextureStorage::~TextureStorage() { +} + +void TextureStorage::init() { + _gpuTexture = TexturePointer(Texture::createFromStorage(this)); +} + diff --git a/libraries/model/src/model/TextureStorage.h b/libraries/model/src/model/TextureStorage.h new file mode 100755 index 0000000000..ec56438bf3 --- /dev/null +++ b/libraries/model/src/model/TextureStorage.h @@ -0,0 +1,48 @@ +// +// TextureStorage.h +// libraries/model/src/model +// +// Created by Sam Gateau on 5/6/2015. +// 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_model_TextureStorage_h +#define hifi_model_TextureStorage_h + +#include "gpu/Texture.h" + +#include "Material.h" + +#include + +namespace model { + +typedef glm::vec3 Color; + +// TextureStorage is a specialized version of the gpu::Texture::Storage +// It provides the mechanism to create a texture from a Url and the intended usage +// that guides the internal format used +class TextureStorage : public gpu::Texture::Storage { +public: + TextureStorage(const QUrl& url, gpu::Texture::Type type = gpu::Texture::TEX_2D); + ~TextureStorage(); + + const QUrl& getUrl() const { return _url; } + const gpu::Texture::Type getType() const { return _type; } + const gpu::TexturePointer& getGPUTexture() const { return _gpuTexture; } + +protected: + gpu::TexturePointer _gpuTexture; + QUrl _url; + gpu::Texture::Type _type; + + void init(); +}; +typedef std::shared_ptr< TextureStorage > TextureStoragePointer; + +}; + +#endif // hifi_model_TextureStorage_h + diff --git a/libraries/render-utils/src/TextureCache.cpp b/libraries/render-utils/src/TextureCache.cpp index 2f9960355f..ded6673683 100644 --- a/libraries/render-utils/src/TextureCache.cpp +++ b/libraries/render-utils/src/TextureCache.cpp @@ -417,17 +417,23 @@ void ImageReader::run() { return; } - // enforce a fixed maximum area (1024 * 2048) - const int MAXIMUM_AREA_SIZE = 2097152; int imageArea = image.width() * image.height(); - if (imageArea > MAXIMUM_AREA_SIZE) { - float scaleRatio = sqrtf((float)MAXIMUM_AREA_SIZE) / sqrtf((float)imageArea); - int resizeWidth = static_cast(std::floor(scaleRatio * static_cast(image.width()))); - int resizeHeight = static_cast(std::floor(scaleRatio * static_cast(image.height()))); - qCDebug(renderutils) << "Image greater than maximum size:" << _url << image.width() << image.height() << - " scaled to:" << resizeWidth << resizeHeight; - image = image.scaled(resizeWidth, resizeHeight, Qt::IgnoreAspectRatio); - imageArea = image.width() * image.height(); + auto ntex = dynamic_cast(&*texture); + if (ntex && (ntex->getType() == CUBE_TEXTURE)) { + qCDebug(renderutils) << "Cube map size:" << _url << image.width() << image.height(); + } else { + + // enforce a fixed maximum area (1024 * 2048) + const int MAXIMUM_AREA_SIZE = 2097152; + if (imageArea > MAXIMUM_AREA_SIZE) { + float scaleRatio = sqrtf((float)MAXIMUM_AREA_SIZE) / sqrtf((float)imageArea); + int resizeWidth = static_cast(std::floor(scaleRatio * static_cast(image.width()))); + int resizeHeight = static_cast(std::floor(scaleRatio * static_cast(image.height()))); + qCDebug(renderutils) << "Image greater than maximum size:" << _url << image.width() << image.height() << + " scaled to:" << resizeWidth << resizeHeight; + image = image.scaled(resizeWidth, resizeHeight, Qt::IgnoreAspectRatio); + imageArea = image.width() * image.height(); + } } const int EIGHT_BIT_MAXIMUM = 255; @@ -507,6 +513,7 @@ void NetworkTexture::setImage(const QImage& image, bool translucent, const QColo imageLoaded(image); if ((_width > 0) && (_height > 0)) { + bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); @@ -515,9 +522,18 @@ void NetworkTexture::setImage(const QImage& image, bool translucent, const QColo formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA)); formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA)); } - _gpuTexture = gpu::TexturePointer(gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); - _gpuTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); - _gpuTexture->autoGenerateMips(-1); + + if (_type == CUBE_TEXTURE) { + if (_height >= (6 * _width)) { + _gpuTexture = gpu::TexturePointer(gpu::Texture::createCube(formatGPU, image.width(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT, gpu::Sampler::WRAP_CLAMP))); + _gpuTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); + _gpuTexture->autoGenerateMips(-1); + } + } else { + _gpuTexture = gpu::TexturePointer(gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); + _gpuTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); + _gpuTexture->autoGenerateMips(-1); + } } } diff --git a/libraries/render-utils/src/TextureCache.h b/libraries/render-utils/src/TextureCache.h index e25a640ae7..3ff184c621 100644 --- a/libraries/render-utils/src/TextureCache.h +++ b/libraries/render-utils/src/TextureCache.h @@ -27,7 +27,7 @@ class NetworkTexture; typedef QSharedPointer NetworkTexturePointer; -enum TextureType { DEFAULT_TEXTURE, NORMAL_TEXTURE, SPECULAR_TEXTURE, EMISSIVE_TEXTURE, SPLAT_TEXTURE }; +enum TextureType { DEFAULT_TEXTURE, NORMAL_TEXTURE, SPECULAR_TEXTURE, EMISSIVE_TEXTURE, SPLAT_TEXTURE, CUBE_TEXTURE }; /// Stores cached textures, including render-to-texture targets. class TextureCache : public ResourceCache, public Dependency { @@ -164,7 +164,7 @@ public: int getOriginalHeight() const { return _originalHeight; } int getWidth() const { return _width; } int getHeight() const { return _height; } - + TextureType getType() const { return _type; } protected: virtual void downloadFinished(QNetworkReply* reply); diff --git a/libraries/script-engine/src/SceneScriptingInterface.cpp b/libraries/script-engine/src/SceneScriptingInterface.cpp index 2461487414..ad76dbcc38 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.cpp +++ b/libraries/script-engine/src/SceneScriptingInterface.cpp @@ -13,6 +13,9 @@ #include "SceneScriptingInterface.h" +#include "SceneScriptingInterface.h" + + void SceneScriptingInterface::setStageOrientation(const glm::quat& orientation) { _skyStage->setOriginOrientation(orientation); } @@ -86,6 +89,29 @@ bool SceneScriptingInterface::isStageSunModelEnabled() const { return _skyStage->isSunModelEnabled(); } +void SceneScriptingInterface::setBackgroundMode(const QString& mode) { + if (mode == QString("inherit")) { + _skyStage->setBackgroundMode(model::SunSkyStage::NO_BACKGROUND); + } else if (mode == QString("atmosphere")) { + _skyStage->setBackgroundMode(model::SunSkyStage::SKY_DOME); + } else if (mode == QString("skybox")) { + _skyStage->setBackgroundMode(model::SunSkyStage::SKY_BOX); + } +} + +QString SceneScriptingInterface::getBackgroundMode() const { + switch (_skyStage->getBackgroundMode()) { + case model::SunSkyStage::NO_BACKGROUND: + return QString("inherit"); + case model::SunSkyStage::SKY_DOME: + return QString("atmosphere"); + case model::SunSkyStage::SKY_BOX: + return QString("skybox"); + default: + return QString("inherit"); + }; +} + model::SunSkyStagePointer SceneScriptingInterface::getSkyStage() const { return _skyStage; } diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index c384153a0f..50aaae83ff 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -57,7 +57,8 @@ public: Q_INVOKABLE glm::vec3 getKeyLightDirection() const; - + Q_INVOKABLE void setBackgroundMode(const QString& mode); + Q_INVOKABLE QString getBackgroundMode() const; model::SunSkyStagePointer getSkyStage() const; From f0618501dd085f39989000c9cec8719f802f59b9 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 7 May 2015 11:29:42 -0700 Subject: [PATCH 69/89] fix non-physical kinematic motion also can set objects collisionless again --- libraries/entities/src/EntityItem.h | 2 + libraries/entities/src/ModelEntityItem.cpp | 57 ++++++++++--------- libraries/entities/src/ModelEntityItem.h | 2 + .../physics/src/PhysicalEntitySimulation.cpp | 34 ++++++----- 4 files changed, 51 insertions(+), 44 deletions(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 63d58fd40f..4f8282c29c 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -256,6 +256,8 @@ public: bool getCollisionsWillMove() const { return _collisionsWillMove; } void setCollisionsWillMove(bool value) { _collisionsWillMove = value; } + virtual bool shouldBePhysical() const { return !_ignoreForCollisions; } + bool getLocked() const { return _locked; } void setLocked(bool value) { _locked = value; } diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 1abb48abcd..b5ec5e11d4 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -33,8 +33,8 @@ EntityItem* ModelEntityItem::factory(const EntityItemID& entityID, const EntityI } ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - EntityItem(entityItemID, properties) -{ + EntityItem(entityItemID, properties) +{ _type = EntityTypes::Model; setProperties(properties); _lastAnimated = usecTimestampNow(); @@ -84,17 +84,17 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties) { } setLastEdited(properties._lastEdited); } - + return somethingChanged; } -int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, +int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData) { - + int bytesRead = 0; const unsigned char* dataAt = data; - + READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _color); READ_ENTITY_PROPERTY_STRING(PROP_MODEL_URL, setModelURL); if (args.bitstreamVersion < VERSION_ENTITIES_HAS_COLLISION_MODEL) { @@ -105,7 +105,7 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY_STRING(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL); } READ_ENTITY_PROPERTY_STRING(PROP_ANIMATION_URL, setAnimationURL); - + // Because we're using AnimationLoop which will reset the frame index if you change it's running state // we want to read these values in the order they appear in the buffer, but call our setters in an // order that allows AnimationLoop to preserve the correct frame rate. @@ -115,7 +115,7 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, animationFPS); READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, animationFrameIndex); READ_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool, animationIsPlaying); - + if (propertyFlags.getHasProperty(PROP_ANIMATION_PLAYING)) { if (animationIsPlaying != getAnimationIsPlaying()) { setAnimationIsPlaying(animationIsPlaying); @@ -148,12 +148,12 @@ EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams& requestedProperties += PROP_ANIMATION_SETTINGS; requestedProperties += PROP_TEXTURES; requestedProperties += PROP_SHAPE_TYPE; - + return requestedProperties; } -void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, +void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData, EntityPropertyFlags& requestedProperties, EntityPropertyFlags& propertyFlags, @@ -186,7 +186,7 @@ void ModelEntityItem::cleanupLoadedAnimations() { Animation* ModelEntityItem::getAnimation(const QString& url) { AnimationPointer animation; - + // if we don't already have this model then create it and initialize it if (_loadedAnimations.find(url) == _loadedAnimations.end()) { animation = DependencyManager::get()->getAnimation(url); @@ -204,7 +204,7 @@ void ModelEntityItem::mapJoints(const QStringList& modelJointNames) { } Animation* myAnimation = getAnimation(_animationURL); - + if (!_jointMappingCompleted) { QStringList animationJointNames = myAnimation->getJointNames(); @@ -229,7 +229,7 @@ QVector ModelEntityItem::getAnimationFrame() { if (animationFrameIndex < 0 || animationFrameIndex > frameCount) { animationFrameIndex = 0; } - + QVector rotations = frames[animationFrameIndex].rotations; frameData.resize(_jointMapping.size()); @@ -244,8 +244,8 @@ QVector ModelEntityItem::getAnimationFrame() { return frameData; } -bool ModelEntityItem::isAnimatingSomething() const { - return getAnimationIsPlaying() && +bool ModelEntityItem::isAnimatingSomething() const { + return getAnimationIsPlaying() && getAnimationFPS() != 0.0f && !getAnimationURL().isEmpty(); } @@ -278,7 +278,7 @@ void ModelEntityItem::debugDump() const { void ModelEntityItem::updateShapeType(ShapeType type) { // BEGIN_TEMPORARY_WORKAROUND // we have allowed inconsistent ShapeType's to be stored in SVO files in the past (this was a bug) - // but we are now enforcing the entity properties to be consistent. To make the possible we're + // but we are now enforcing the entity properties to be consistent. To make the possible we're // introducing a temporary workaround: we will ignore ShapeType updates that conflict with the // _compoundShapeURL. if (hasCompoundShapeURL()) { @@ -292,7 +292,7 @@ void ModelEntityItem::updateShapeType(ShapeType type) { } } -// virtual +// virtual ShapeType ModelEntityItem::getShapeType() const { if (_shapeType == SHAPE_TYPE_COMPOUND) { return hasCompoundShapeURL() ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE; @@ -309,9 +309,9 @@ void ModelEntityItem::setCompoundShapeURL(const QString& url) { } } -void ModelEntityItem::setAnimationURL(const QString& url) { +void ModelEntityItem::setAnimationURL(const QString& url) { _dirtyFlags |= EntityItem::DIRTY_UPDATEABLE; - _animationURL = url; + _animationURL = url; } void ModelEntityItem::setAnimationFrameIndex(float value) { @@ -327,7 +327,7 @@ void ModelEntityItem::setAnimationFrameIndex(float value) { _animationLoop.setFrameIndex(value); } -void ModelEntityItem::setAnimationSettings(const QString& value) { +void ModelEntityItem::setAnimationSettings(const QString& value) { // the animations setting is a JSON string that may contain various animation settings. // if it includes fps, frameIndex, or running, those values will be parsed out and // will over ride the regular animation settings @@ -388,21 +388,21 @@ void ModelEntityItem::setAnimationSettings(const QString& value) { setAnimationStartAutomatically(startAutomatically); } - _animationSettings = value; + _animationSettings = value; _dirtyFlags |= EntityItem::DIRTY_UPDATEABLE; } void ModelEntityItem::setAnimationIsPlaying(bool value) { _dirtyFlags |= EntityItem::DIRTY_UPDATEABLE; - _animationLoop.setRunning(value); + _animationLoop.setRunning(value); } void ModelEntityItem::setAnimationFPS(float value) { _dirtyFlags |= EntityItem::DIRTY_UPDATEABLE; - _animationLoop.setFPS(value); + _animationLoop.setFPS(value); } -QString ModelEntityItem::getAnimationSettings() const { +QString ModelEntityItem::getAnimationSettings() const { // the animations setting is a JSON string that may contain various animation settings. // if it includes fps, frameIndex, or running, those values will be parsed out and // will over ride the regular animation settings @@ -411,7 +411,7 @@ QString ModelEntityItem::getAnimationSettings() const { QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8()); QJsonObject settingsAsJsonObject = settingsAsJson.object(); QVariantMap settingsMap = settingsAsJsonObject.toVariantMap(); - + QVariant fpsValue(getAnimationFPS()); settingsMap["fps"] = fpsValue; @@ -435,10 +435,15 @@ QString ModelEntityItem::getAnimationSettings() const { QVariant startAutomaticallyValue(getAnimationStartAutomatically()); settingsMap["startAutomatically"] = startAutomaticallyValue; - + settingsAsJsonObject = QJsonObject::fromVariantMap(settingsMap); QJsonDocument newDocument(settingsAsJsonObject); QByteArray jsonByteArray = newDocument.toJson(QJsonDocument::Compact); QString jsonByteString(jsonByteArray); return jsonByteString; } + +// virtual +bool ModelEntityItem::shouldBePhysical() const { + return EntityItem::shouldBePhysical() && getShapeType() != SHAPE_TYPE_NONE; +} diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 6fe2adc928..d4a4efda04 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -117,6 +117,8 @@ public: static const QString DEFAULT_TEXTURES; const QString& getTextures() const { return _textures; } void setTextures(const QString& textures) { _textures = textures; } + + virtual bool shouldBePhysical() const; static void cleanupLoadedAnimations(); diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index cf88af4942..06d025244a 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -23,9 +23,9 @@ PhysicalEntitySimulation::~PhysicalEntitySimulation() { } void PhysicalEntitySimulation::init( - EntityTree* tree, - PhysicsEngine* physicsEngine, - ShapeManager* shapeManager, + EntityTree* tree, + PhysicsEngine* physicsEngine, + ShapeManager* shapeManager, EntityEditPacketSender* packetSender) { assert(tree); setEntityTree(tree); @@ -47,29 +47,24 @@ void PhysicalEntitySimulation::updateEntitiesInternal(const quint64& now) { void PhysicalEntitySimulation::addEntityInternal(EntityItem* entity) { assert(entity); - if (entity->getIgnoreForCollisions() && entity->isMoving()) { - _simpleKinematicEntities.insert(entity); - } else { + if (entity->shouldBePhysical()) { EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); if (!motionState) { _pendingAdds.insert(entity); - } else { - // DEBUG -- Andrew to remove this after testing - // Adding entity already in simulation? assert that this is case, - // since otherwise we probably have an orphaned EntityMotionState. - assert(_physicalObjects.find(motionState) != _physicalObjects.end()); } + } else if (entity->isMoving()) { + _simpleKinematicEntities.insert(entity); } } void PhysicalEntitySimulation::removeEntityInternal(EntityItem* entity) { EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); if (motionState) { - motionState->clearEntity(); + motionState->clearEntity(); entity->setPhysicsInfo(nullptr); // NOTE: we must remove entity from _pendingAdds immediately because we've disconnected the backpointers between - // motionState and entity and they can't be used to look up each other. However we don't need to remove + // motionState and entity and they can't be used to look up each other. However we don't need to remove // motionState from _pendingChanges at this time becuase it will be removed during getObjectsToDelete(). _pendingAdds.remove(entity); @@ -83,7 +78,7 @@ void PhysicalEntitySimulation::changeEntityInternal(EntityItem* entity) { assert(entity); EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); if (motionState) { - if (entity->getIgnoreForCollisions()) { + if (!entity->shouldBePhysical()) { // the entity should be removed from the physical simulation _pendingChanges.remove(motionState); _physicalObjects.remove(motionState); @@ -95,8 +90,8 @@ void PhysicalEntitySimulation::changeEntityInternal(EntityItem* entity) { } else { _pendingChanges.insert(motionState); } - } else if (!entity->getIgnoreForCollisions()) { - // The intent is for this object to be in the PhysicsEngine. + } else if (entity->shouldBePhysical()) { + // The intent is for this object to be in the PhysicsEngine, but it has no MotionState yet. // Perhaps it's shape has changed and it can now be added? _pendingAdds.insert(entity); _simpleKinematicEntities.remove(entity); // just in case it's non-physical-kinematic @@ -159,9 +154,12 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToAdd() { while (entityItr != _pendingAdds.end()) { EntityItem* entity = *entityItr; assert(!entity->getPhysicsInfo()); - if (entity->getShapeType() == SHAPE_TYPE_NONE || entity->getIgnoreForCollisions()) { + if (!entity->shouldBePhysical()) { // this entity should no longer be on the internal _pendingAdds entityItr = _pendingAdds.erase(entityItr); + if (entity->isMoving()) { + _simpleKinematicEntities.insert(entity); + } } else if (entity->isReadyToComputeShape()) { ShapeInfo shapeInfo; entity->computeShapeInfo(shapeInfo); @@ -207,7 +205,7 @@ void PhysicalEntitySimulation::handleOutgoingChanges(VectorOfMotionStates& motio } } } - + // send outgoing packets uint32_t numSubsteps = _physicsEngine->getNumSubsteps(); if (_lastStepSendPackets != numSubsteps) { From d9f17d010c3a184d56751bd4322a617cfd9ab350 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 7 May 2015 11:41:23 -0700 Subject: [PATCH 70/89] first cut at adding new zone properties to edit tools --- examples/html/entityProperties.html | 119 ++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 3e775ec698..d96fc7d76d 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -205,6 +205,24 @@ var elZoneStageDay = document.getElementById("property-zone-stage-day"); var elZoneStageHour = document.getElementById("property-zone-stage-hour"); + var elZoneBackgroundMode = document.getElementById("property-zone-background-mode"); + + var elZoneSkyboxColorRed = document.getElementById("property-zone-skybox-color-red"); + var elZoneSkyboxColorGreen = document.getElementById("property-zone-skybox-color-green"); + var elZoneSkyboxColorBlue = document.getElementById("property-zone-skybox-color-blue"); + var elZoneSkyboxURL = document.getElementById("property-zone-skybox-url"); + + var elZoneAtmosphereCenterX = document.getElementById("property-zone-atmosphere-center-x"); + var elZoneAtmosphereCenterY = document.getElementById("property-zone-atmosphere-center-y"); + var elZoneAtmosphereCenterZ = document.getElementById("property-zone-atmosphere-center-z"); + var elZoneAtmosphereInnerRadius = document.getElementById("property-zone-atmosphere-inner-radius"); + var elZoneAtmosphereOuterRadius = document.getElementById("property-zone-atmosphere-outer-radius"); + var elZoneAtmosphereMieScattering = document.getElementById("property-zone-atmosphere-mie-scattering"); + var elZoneAtmosphereRayleighScattering = document.getElementById("property-zone-atmosphere-rayleigh-scattering"); + var elZoneAtmosphereScatteringWavelengthsX = document.getElementById("property-zone-atmosphere-scattering-wavelengths-x"); + var elZoneAtmosphereScatteringWavelengthsY = document.getElementById("property-zone-atmosphere-scattering-wavelengths-y"); + var elZoneAtmosphereScatteringWavelengthsZ = document.getElementById("property-zone-atmosphere-scattering-wavelengths-z"); + if (window.EventBridge !== undefined) { EventBridge.scriptEventReceived.connect(function(data) { data = JSON.parse(data); @@ -386,6 +404,26 @@ elZoneStageHour.value = properties.stageHour; elShapeType.value = properties.shapeType; elCompoundShapeURL.value = properties.compoundShapeURL; + + elZoneBackgroundMode.value = properties.backgroundMode; + + elZoneSkyboxColorRed.value = properties.skybox.color.red; + elZoneSkyboxColorGreen.value = properties.skybox.color.green; + elZoneSkyboxColorBlue.value = properties.skybox.color.blue; + elZoneSkyboxURL.value = properties.skybox.url; + + elZoneAtmosphereCenterX.value = properties.atmosphere.center.x; + elZoneAtmosphereCenterY.value = properties.atmosphere.center.y; + elZoneAtmosphereCenterZ.value = properties.atmosphere.center.z; + elZoneAtmosphereInnerRadius.value = properties.atmosphere.innerRadius; + elZoneAtmosphereOuterRadius.value = properties.atmosphere.outerRadius; + elZoneAtmosphereMieScattering.value = properties.atmosphere.mieScattering; + elZoneAtmosphereRayleighScattering.value = properties.atmosphere.rayleighScattering; + elZoneAtmosphereScatteringWavelengthsX.value = properties.atmosphere.scatteringWavelengths.x; + elZoneAtmosphereScatteringWavelengthsY.value = properties.atmosphere.scatteringWavelengths.y; + elZoneAtmosphereScatteringWavelengthsZ.value = properties.atmosphere.scatteringWavelengths.z; + + } if (selected) { @@ -521,6 +559,21 @@ elZoneStageDay.addEventListener('change', createEmitNumberPropertyUpdateFunction('stageDay')); elZoneStageHour.addEventListener('change', createEmitNumberPropertyUpdateFunction('stageHour')); + elZoneBackgroundMode.addEventListener('change', createEmitTextPropertyUpdateFunction('backgroundMode')); + var zoneSkyboxColorChangeFunction = createEmitColorPropertyUpdateFunction( + 'skybox.color', elZoneSkyboxColorRed, elZoneSkyboxColorGreen, elZoneSkyboxColorBlue); + elZoneSkyboxURL.addEventListener('change', createEmitTextPropertyUpdateFunction('skybox.url')); + + var zoneAtmosphereCenterChangeFunction = createEmitVec3PropertyUpdateFunction( + 'atmosphere.center', elZoneAtmosphereCenterX, elZoneAtmosphereCenterY, elZoneAtmosphereCenterZ); + elZoneAtmosphereInnerRadius.addEventListener('change', createEmitNumberPropertyUpdateFunction('atmosphere.innerRadius')); + elZoneAtmosphereOuterRadius.addEventListener('change', createEmitNumberPropertyUpdateFunction('atmosphere.outerRadius')); + elZoneAtmosphereMieScattering.addEventListener('change', createEmitNumberPropertyUpdateFunction('atmosphere.mieScattering')); + elZoneAtmosphereRayleighScattering.addEventListener('change', createEmitNumberPropertyUpdateFunction('atmosphere.rayleighScattering')); + var zoneAtmosphereCenterChangeFunction = createEmitVec3PropertyUpdateFunction( + 'atmosphere.scatteringWavelengths', elZoneAtmosphereScatteringWavelengthsX, + elZoneAtmosphereScatteringWavelengthsY, elZoneAtmosphereScatteringWavelengthsZ); + elMoveSelectionToGrid.addEventListener("click", function() { EventBridge.emitWebEvent(JSON.stringify({ type: "action", @@ -958,6 +1011,72 @@ + +
+
Background Mode
+
+ +
+
+
+
Skybox Color
+
+
R
+
G
+
B
+
+
+
+
Skybox URL
+
+ +
+
+
+
Atmosphere Center
+
+
X
+
Y
+
Z
+
+
+
+
Atmosphere Inner Radius
+
+ +
+
+
+
Atmosphere Outer Radius
+
+ +
+
+
+
Atmosphere Mie Scattering
+
+ +
+
+
+
Atmosphere Rayleigh Scattering
+
+ +
+
+
+
Atmosphere Scattering Wavelenghts
+
+
X
+
Y
+
Z
+
+
+ From f52747d8c16b355919635f7e2177ac26287cb056 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 7 May 2015 11:53:57 -0700 Subject: [PATCH 71/89] re-enable code that ignores old packets --- libraries/entities/src/EntityItem.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 71a724c5cf..468fc164a2 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -402,9 +402,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef lastEditedFromBufferAdjusted = now; } -#if 0 // XXX bool fromSameServerEdit = (lastEditedFromBuffer == _lastEditedFromRemoteInRemoteTime); -#endif #ifdef WANT_DEBUG qCDebug(entities) << "data from server **************** "; @@ -421,7 +419,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef bool ignoreServerPacket = false; // assume we'll use this server packet -#if 0 // XXX Trying to eliminate this code as a possible source of deviation between interfaces // If this packet is from the same server edit as the last packet we accepted from the server // we probably want to use it. if (fromSameServerEdit) { @@ -438,7 +435,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef ignoreServerPacket = true; } } -#endif if (ignoreServerPacket) { overwriteLocalData = false; From 20fe43c85280d7433682eff6affa12f4f8dd250e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 7 May 2015 13:05:00 -0700 Subject: [PATCH 72/89] wire up new zone properties, fix bug in group proprties decode --- examples/html/entityProperties.html | 111 +++++++++++++++--- .../entities/src/AtmospherePropertyGroup.cpp | 8 ++ .../entities/src/EntityItemProperties.cpp | 4 + libraries/entities/src/EntityItemProperties.h | 3 + .../entities/src/EntityItemPropertiesMacros.h | 5 + .../entities/src/SkyboxPropertyGroup.cpp | 5 +- 6 files changed, 118 insertions(+), 18 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index d96fc7d76d..e525818e51 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -33,6 +33,21 @@ ); }; } + function createEmitGroupNumberPropertyUpdateFunction(group, propertyName) { + return function() { + var properties = {}; + properties[group] = {}; + properties[group][propertyName] = this.value; + EventBridge.emitWebEvent( + JSON.stringify({ + type: "update", + properties: properties, + }) + ); + }; + } + + function createEmitTextPropertyUpdateFunction(propertyName) { return function() { var properties = {}; @@ -46,6 +61,20 @@ }; } + function createEmitGroupTextPropertyUpdateFunction(group,propertyName) { + return function() { + var properties = {}; + properties[group] = {}; + properties[group][propertyName] = this.value; + EventBridge.emitWebEvent( + JSON.stringify({ + type: "update", + properties: properties, + }) + ); + }; + } + function createEmitVec3PropertyUpdateFunction(property, elX, elY, elZ) { return function() { var data = { @@ -62,6 +91,23 @@ } }; + function createEmitGroupVec3PropertyUpdateFunction(group, property, elX, elY, elZ) { + return function() { + var data = { + type: "update", + properties: { + } + }; + data.properties[group] = { }; + data.properties[group][property] = { + x: elX.value, + y: elY.value, + z: elZ.value, + }; + EventBridge.emitWebEvent(JSON.stringify(data)); + } + }; + function createEmitVec3PropertyUpdateFunctionWithMultiplier(property, elX, elY, elZ, multiplier) { return function() { var data = { @@ -94,6 +140,24 @@ } }; + function createEmitGroupColorPropertyUpdateFunction(group, property, elRed, elGreen, elBlue) { + return function() { + var data = { + type: "update", + properties: { + } + }; + data.properties[group] = { }; + + data.properties[group][property] = { + red: elRed.value, + green: elGreen.value, + blue: elBlue.value, + }; + EventBridge.emitWebEvent(JSON.stringify(data)); + } + }; + function loaded() { var allSections = []; var elID = document.getElementById("property-id"); @@ -559,20 +623,33 @@ elZoneStageDay.addEventListener('change', createEmitNumberPropertyUpdateFunction('stageDay')); elZoneStageHour.addEventListener('change', createEmitNumberPropertyUpdateFunction('stageHour')); - elZoneBackgroundMode.addEventListener('change', createEmitTextPropertyUpdateFunction('backgroundMode')); - var zoneSkyboxColorChangeFunction = createEmitColorPropertyUpdateFunction( - 'skybox.color', elZoneSkyboxColorRed, elZoneSkyboxColorGreen, elZoneSkyboxColorBlue); - elZoneSkyboxURL.addEventListener('change', createEmitTextPropertyUpdateFunction('skybox.url')); - var zoneAtmosphereCenterChangeFunction = createEmitVec3PropertyUpdateFunction( - 'atmosphere.center', elZoneAtmosphereCenterX, elZoneAtmosphereCenterY, elZoneAtmosphereCenterZ); - elZoneAtmosphereInnerRadius.addEventListener('change', createEmitNumberPropertyUpdateFunction('atmosphere.innerRadius')); - elZoneAtmosphereOuterRadius.addEventListener('change', createEmitNumberPropertyUpdateFunction('atmosphere.outerRadius')); - elZoneAtmosphereMieScattering.addEventListener('change', createEmitNumberPropertyUpdateFunction('atmosphere.mieScattering')); - elZoneAtmosphereRayleighScattering.addEventListener('change', createEmitNumberPropertyUpdateFunction('atmosphere.rayleighScattering')); - var zoneAtmosphereCenterChangeFunction = createEmitVec3PropertyUpdateFunction( - 'atmosphere.scatteringWavelengths', elZoneAtmosphereScatteringWavelengthsX, + elZoneBackgroundMode.addEventListener('change', createEmitTextPropertyUpdateFunction('backgroundMode')); + var zoneSkyboxColorChangeFunction = createEmitGroupColorPropertyUpdateFunction('skybox','color', + elZoneSkyboxColorRed, elZoneSkyboxColorGreen, elZoneSkyboxColorBlue); + elZoneSkyboxColorRed.addEventListener('change', zoneSkyboxColorChangeFunction); + elZoneSkyboxColorGreen.addEventListener('change', zoneSkyboxColorChangeFunction); + elZoneSkyboxColorBlue.addEventListener('change', zoneSkyboxColorChangeFunction); + + elZoneSkyboxURL.addEventListener('change', createEmitGroupTextPropertyUpdateFunction('skybox','url')); + + var zoneAtmosphereCenterChangeFunction = createEmitGroupVec3PropertyUpdateFunction( + 'atmosphere','center', elZoneAtmosphereCenterX, elZoneAtmosphereCenterY, elZoneAtmosphereCenterZ); + elZoneAtmosphereCenterX.addEventListener('change', zoneAtmosphereCenterChangeFunction); + elZoneAtmosphereCenterY.addEventListener('change', zoneAtmosphereCenterChangeFunction); + elZoneAtmosphereCenterZ.addEventListener('change', zoneAtmosphereCenterChangeFunction); + + + elZoneAtmosphereInnerRadius.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('atmosphere','innerRadius')); + elZoneAtmosphereOuterRadius.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('atmosphere','outerRadius')); + elZoneAtmosphereMieScattering.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('atmosphere','mieScattering')); + elZoneAtmosphereRayleighScattering.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('atmosphere','rayleighScattering')); + var zoneAtmosphereScatterWavelengthsChangeFunction = createEmitGroupVec3PropertyUpdateFunction( + 'atmosphere','scatteringWavelengths', elZoneAtmosphereScatteringWavelengthsX, elZoneAtmosphereScatteringWavelengthsY, elZoneAtmosphereScatteringWavelengthsZ); + elZoneAtmosphereScatteringWavelengthsX.addEventListener('change', zoneAtmosphereScatterWavelengthsChangeFunction); + elZoneAtmosphereScatteringWavelengthsY.addEventListener('change', zoneAtmosphereScatterWavelengthsChangeFunction); + elZoneAtmosphereScatteringWavelengthsZ.addEventListener('change', zoneAtmosphereScatterWavelengthsChangeFunction); elMoveSelectionToGrid.addEventListener("click", function() { EventBridge.emitWebEvent(JSON.stringify({ @@ -1059,21 +1136,21 @@
Atmosphere Mie Scattering
- +
Atmosphere Rayleigh Scattering
- +
Atmosphere Scattering Wavelenghts
-
X
-
Y
-
Z
+
X
+
Y
+
Z
diff --git a/libraries/entities/src/AtmospherePropertyGroup.cpp b/libraries/entities/src/AtmospherePropertyGroup.cpp index b9b49f8c45..c1210be24e 100644 --- a/libraries/entities/src/AtmospherePropertyGroup.cpp +++ b/libraries/entities/src/AtmospherePropertyGroup.cpp @@ -89,6 +89,14 @@ bool AtmospherePropertyGroup::decodeFromEditPacket(EntityPropertyFlags& property READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_RAYLEIGH_SCATTERING, float, _rayleighScattering); READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_SCATTERING_WAVELENGTHS, glm::vec3, _scatteringWavelengths); READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_HAS_STARS, bool, _hasStars); + + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ATMOSPHERE_CENTER, Center); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ATMOSPHERE_INNER_RADIUS, InnerRadius); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ATMOSPHERE_OUTER_RADIUS, OuterRadius); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ATMOSPHERE_MIE_SCATTERING, MieScattering); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ATMOSPHERE_RAYLEIGH_SCATTERING, RayleighScattering); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ATMOSPHERE_SCATTERING_WAVELENGTHS, ScatteringWavelengths); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ATMOSPHERE_HAS_STARS, HasStars); processedBytes += bytesRead; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index ab41367fa9..0b3472fc09 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -181,6 +181,10 @@ void EntityItemProperties::debugDump() const { qCDebug(entities) << " _dimensions=" << getDimensions(); qCDebug(entities) << " _modelURL=" << _modelURL; qCDebug(entities) << " _compoundShapeURL=" << _compoundShapeURL; + + getAtmosphere().debugDump(); + getSkybox().debugDump(); + qCDebug(entities) << " changed properties..."; EntityPropertyFlags props = getChangedProperties(); props.debugDumpBits(); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 8ea521a8e9..13b2377032 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -279,6 +279,9 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParticleRadius, particleRadius, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, MarketplaceID, marketplaceID, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, BackgroundMode, backgroundMode, ""); + + properties.getAtmosphere().debugDump(); + properties.getSkybox().debugDump(); debug << " last edited:" << properties.getLastEdited() << "\n"; debug << " edited ago:" << properties.getEditedAgo() << "\n"; diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index 3f25f9353e..1b10b6eb7a 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -107,6 +107,11 @@ } \ } +#define DECODE_GROUP_PROPERTY_HAS_CHANGED(P,N) \ + if (propertyFlags.getHasProperty(P)) { \ + set##N##Changed(true); \ + } + #define READ_ENTITY_PROPERTY_COLOR(P,M) \ if (propertyFlags.getHasProperty(P)) { \ if (overwriteLocalData) { \ diff --git a/libraries/entities/src/SkyboxPropertyGroup.cpp b/libraries/entities/src/SkyboxPropertyGroup.cpp index 8b304d0523..23530108ce 100644 --- a/libraries/entities/src/SkyboxPropertyGroup.cpp +++ b/libraries/entities/src/SkyboxPropertyGroup.cpp @@ -59,7 +59,10 @@ bool SkyboxPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlag READ_ENTITY_PROPERTY_XCOLOR(PROP_SKYBOX_COLOR, _color); READ_ENTITY_PROPERTY_STRING(PROP_SKYBOX_URL, setURL); - + + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_SKYBOX_COLOR, Color); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_SKYBOX_URL, URL); + processedBytes += bytesRead; return true; From 0347af968298e3456101990a5d1b9b9641b93edf Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 7 May 2015 14:03:50 -0700 Subject: [PATCH 73/89] minor cleanup --- libraries/physics/src/EntityMotionState.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index b2a34bced0..d3a1d67d4a 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -151,8 +151,10 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { _movingStepsWithoutSimulationOwner = 0; } - if (_movingStepsWithoutSimulationOwner > 50) { // XXX maybe meters from our characterController ? - qDebug() << "XXX XXX XXX -- claiming something I saw moving"; + int ownershipClaimDelay = 50; // TODO -- how to pick this? based on meters from our characterController? + + if (_movingStepsWithoutSimulationOwner > ownershipClaimDelay) { + qDebug() << "Warning -- claiming something I saw moving." << getName(); setShouldClaimSimulationOwnership(true); } From 1879a6780475bb02812496e76103d43840758f6e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 7 May 2015 14:41:08 -0700 Subject: [PATCH 74/89] cleanup --- libraries/entities/src/EntityItem.cpp | 17 --- libraries/entities/src/EntityItem.h | 28 +++-- libraries/entities/src/EntityTree.h | 1 + libraries/physics/src/EntityMotionState.cpp | 114 ++++++++++---------- libraries/physics/src/EntityMotionState.h | 16 +-- 5 files changed, 84 insertions(+), 92 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 468fc164a2..ee7ca54a98 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1105,23 +1105,6 @@ void EntityItem::computeShapeInfo(ShapeInfo& info) { info.setParams(getShapeType(), 0.5f * getDimensions()); } -// these thesholds determine what updates will be ignored (client and server) -const float IGNORE_POSITION_DELTA = 0.0001f; -const float IGNORE_DIMENSIONS_DELTA = 0.0005f; -const float IGNORE_ALIGNMENT_DOT = 0.99997f; -const float IGNORE_LINEAR_VELOCITY_DELTA = 0.001f; -const float IGNORE_DAMPING_DELTA = 0.001f; -const float IGNORE_GRAVITY_DELTA = 0.001f; -const float IGNORE_ANGULAR_VELOCITY_DELTA = 0.0002f; - -// these thresholds determine what updates will activate the physical object -const float ACTIVATION_POSITION_DELTA = 0.005f; -const float ACTIVATION_DIMENSIONS_DELTA = 0.005f; -const float ACTIVATION_ALIGNMENT_DOT = 0.99990f; -const float ACTIVATION_LINEAR_VELOCITY_DELTA = 0.01f; -const float ACTIVATION_GRAVITY_DELTA = 0.1f; -const float ACTIVATION_ANGULAR_VELOCITY_DELTA = 0.03f; - void EntityItem::updatePositionInDomainUnits(const glm::vec3& value) { glm::vec3 position = value * (float)TREE_SCALE; updatePosition(position); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 4f8282c29c..d9096bf429 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -32,6 +32,24 @@ class EntitySimulation; class EntityTreeElement; class EntityTreeElementExtraEncodeData; +// these thesholds determine what updates will be ignored (client and server) +const float IGNORE_POSITION_DELTA = 0.0001f; +const float IGNORE_DIMENSIONS_DELTA = 0.0005f; +const float IGNORE_ALIGNMENT_DOT = 0.99997f; +const float IGNORE_LINEAR_VELOCITY_DELTA = 0.001f; +const float IGNORE_DAMPING_DELTA = 0.001f; +const float IGNORE_GRAVITY_DELTA = 0.001f; +const float IGNORE_ANGULAR_VELOCITY_DELTA = 0.0002f; + +// these thresholds determine what updates will activate the physical object +const float ACTIVATION_POSITION_DELTA = 0.005f; +const float ACTIVATION_DIMENSIONS_DELTA = 0.005f; +const float ACTIVATION_ALIGNMENT_DOT = 0.99990f; +const float ACTIVATION_LINEAR_VELOCITY_DELTA = 0.01f; +const float ACTIVATION_GRAVITY_DELTA = 0.1f; +const float ACTIVATION_ANGULAR_VELOCITY_DELTA = 0.03f; + + #define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0; #define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() { }; @@ -395,14 +413,4 @@ protected: bool _simulated; // set by EntitySimulation }; - -extern const float IGNORE_POSITION_DELTA; -extern const float IGNORE_DIMENSIONS_DELTA; -extern const float IGNORE_ALIGNMENT_DOT; -extern const float IGNORE_LINEAR_VELOCITY_DELTA; -extern const float IGNORE_DAMPING_DELTA; -extern const float IGNORE_GRAVITY_DELTA; -extern const float IGNORE_ANGULAR_VELOCITY_DELTA; - - #endif // hifi_EntityItem_h diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index e5c4e68f2f..f99160f4ed 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -12,6 +12,7 @@ #ifndef hifi_EntityTree_h #define hifi_EntityTree_h +#include #include #include diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index d3a1d67d4a..c897da3ef9 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -27,13 +27,13 @@ EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItem* entity _entity(entity), _sentMoving(false), _numNonMovingUpdates(0), - _sentStep(0), - _sentPosition(0.0f), - _sentRotation(), - _sentVelocity(0.0f), - _sentAngularVelocity(0.0f), - _sentGravity(0.0f), - _sentAcceleration(0.0f), + _lastStep(0), + _serverPosition(0.0f), + _serverRotation(), + _serverVelocity(0.0f), + _serverAngularVelocity(0.0f), + _serverGravity(0.0f), + _serverAcceleration(0.0f), _accelerationNearlyGravityCount(0), _shouldClaimSimulationOwnership(false), _movingStepsWithoutSimulationOwner(0) @@ -49,16 +49,16 @@ EntityMotionState::~EntityMotionState() { void EntityMotionState::updateServerPhysicsVariables(uint32_t flags) { if (flags & EntityItem::DIRTY_POSITION) { - _sentPosition = _entity->getPosition(); + _serverPosition = _entity->getPosition(); } if (flags & EntityItem::DIRTY_ROTATION) { - _sentRotation = _entity->getRotation(); + _serverRotation = _entity->getRotation(); } if (flags & EntityItem::DIRTY_LINEAR_VELOCITY) { - _sentVelocity = _entity->getVelocity(); + _serverVelocity = _entity->getVelocity(); } if (flags & EntityItem::DIRTY_ANGULAR_VELOCITY) { - _sentAngularVelocity = _entity->getAngularVelocity(); + _serverAngularVelocity = _entity->getAngularVelocity(); } } @@ -96,8 +96,8 @@ bool EntityMotionState::isMoving() const { } bool EntityMotionState::isMovingVsServer() const { - auto alignmentDot = glm::abs(glm::dot(_sentRotation, _entity->getRotation())); - if (glm::distance(_sentPosition, _entity->getPosition()) > IGNORE_POSITION_DELTA || + auto alignmentDot = glm::abs(glm::dot(_serverRotation, _entity->getRotation())); + if (glm::distance(_serverPosition, _entity->getPosition()) > IGNORE_POSITION_DELTA || alignmentDot < IGNORE_ALIGNMENT_DOT) { return true; } @@ -183,26 +183,26 @@ bool EntityMotionState::doesNotNeedToSendUpdate() const { bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { assert(_body); - // if we've never checked before, our _sentStep will be 0, and we need to initialize our state - if (_sentStep == 0) { + // if we've never checked before, our _lastStep will be 0, and we need to initialize our state + if (_lastStep == 0) { btTransform xform = _body->getWorldTransform(); - _sentPosition = bulletToGLM(xform.getOrigin()); - _sentRotation = bulletToGLM(xform.getRotation()); - _sentVelocity = bulletToGLM(_body->getLinearVelocity()); - _sentAngularVelocity = bulletToGLM(_body->getAngularVelocity()); - _sentStep = simulationStep; + _serverPosition = bulletToGLM(xform.getOrigin()); + _serverRotation = bulletToGLM(xform.getRotation()); + _serverVelocity = bulletToGLM(_body->getLinearVelocity()); + _serverAngularVelocity = bulletToGLM(_body->getAngularVelocity()); + _lastStep = simulationStep; return false; } #ifdef WANT_DEBUG - glm::vec3 wasPosition = _sentPosition; - glm::quat wasRotation = _sentRotation; - glm::vec3 wasAngularVelocity = _sentAngularVelocity; + glm::vec3 wasPosition = _serverPosition; + glm::quat wasRotation = _serverRotation; + glm::vec3 wasAngularVelocity = _serverAngularVelocity; #endif - int numSteps = simulationStep - _sentStep; + int numSteps = simulationStep - _lastStep; float dt = (float)(numSteps) * PHYSICS_ENGINE_FIXED_SUBSTEP; - _sentStep = simulationStep; + _lastStep = simulationStep; bool isActive = _body->isActive(); if (!isActive) { @@ -226,16 +226,16 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { // due to _worldOffset. // compute position error - if (glm::length2(_sentVelocity) > 0.0f) { - _sentVelocity += _sentAcceleration * dt; - _sentVelocity *= powf(1.0f - _body->getLinearDamping(), dt); - _sentPosition += dt * _sentVelocity; + if (glm::length2(_serverVelocity) > 0.0f) { + _serverVelocity += _serverAcceleration * dt; + _serverVelocity *= powf(1.0f - _body->getLinearDamping(), dt); + _serverPosition += dt * _serverVelocity; } btTransform worldTrans = _body->getWorldTransform(); glm::vec3 position = bulletToGLM(worldTrans.getOrigin()); - float dx2 = glm::distance2(position, _sentPosition); + float dx2 = glm::distance2(position, _serverPosition); const float MAX_POSITION_ERROR_SQUARED = 0.001f; // 0.001 m^2 ~~> 0.03 m if (dx2 > MAX_POSITION_ERROR_SQUARED) { @@ -244,44 +244,44 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { qCDebug(physics) << ".... (dx2 > MAX_POSITION_ERROR_SQUARED) ...."; qCDebug(physics) << "wasPosition:" << wasPosition; qCDebug(physics) << "bullet position:" << position; - qCDebug(physics) << "_sentPosition:" << _sentPosition; + qCDebug(physics) << "_serverPosition:" << _serverPosition; qCDebug(physics) << "dx2:" << dx2; #endif return true; } - if (glm::length2(_sentAngularVelocity) > 0.0f) { + if (glm::length2(_serverAngularVelocity) > 0.0f) { // compute rotation error float attenuation = powf(1.0f - _body->getAngularDamping(), dt); - _sentAngularVelocity *= attenuation; + _serverAngularVelocity *= attenuation; // Bullet caps the effective rotation velocity inside its rotation integration step, therefore // we must integrate with the same algorithm and timestep in order achieve similar results. for (int i = 0; i < numSteps; ++i) { - _sentRotation = glm::normalize(computeBulletRotationStep(_sentAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP) * _sentRotation); + _serverRotation = glm::normalize(computeBulletRotationStep(_serverAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP) * _serverRotation); } } const float MIN_ROTATION_DOT = 0.99f; // 0.99 dot threshold coresponds to about 16 degrees of slop glm::quat actualRotation = bulletToGLM(worldTrans.getRotation()); #ifdef WANT_DEBUG - if ((fabsf(glm::dot(actualRotation, _sentRotation)) < MIN_ROTATION_DOT)) { - qCDebug(physics) << ".... ((fabsf(glm::dot(actualRotation, _sentRotation)) < MIN_ROTATION_DOT)) ...."; + if ((fabsf(glm::dot(actualRotation, _serverRotation)) < MIN_ROTATION_DOT)) { + qCDebug(physics) << ".... ((fabsf(glm::dot(actualRotation, _serverRotation)) < MIN_ROTATION_DOT)) ...."; qCDebug(physics) << "wasAngularVelocity:" << wasAngularVelocity; - qCDebug(physics) << "_sentAngularVelocity:" << _sentAngularVelocity; + qCDebug(physics) << "_serverAngularVelocity:" << _serverAngularVelocity; qCDebug(physics) << "length wasAngularVelocity:" << glm::length(wasAngularVelocity); - qCDebug(physics) << "length _sentAngularVelocity:" << glm::length(_sentAngularVelocity); + qCDebug(physics) << "length _serverAngularVelocity:" << glm::length(_serverAngularVelocity); qCDebug(physics) << "wasRotation:" << wasRotation; qCDebug(physics) << "bullet actualRotation:" << actualRotation; - qCDebug(physics) << "_sentRotation:" << _sentRotation; + qCDebug(physics) << "_serverRotation:" << _serverRotation; } #endif - return (fabsf(glm::dot(actualRotation, _sentRotation)) < MIN_ROTATION_DOT); + return (fabsf(glm::dot(actualRotation, _serverRotation)) < MIN_ROTATION_DOT); } bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { @@ -335,42 +335,42 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ } btTransform worldTrans = _body->getWorldTransform(); - _sentPosition = bulletToGLM(worldTrans.getOrigin()); - properties.setPosition(_sentPosition + ObjectMotionState::getWorldOffset()); + _serverPosition = bulletToGLM(worldTrans.getOrigin()); + properties.setPosition(_serverPosition + ObjectMotionState::getWorldOffset()); - _sentRotation = bulletToGLM(worldTrans.getRotation()); - properties.setRotation(_sentRotation); + _serverRotation = bulletToGLM(worldTrans.getRotation()); + properties.setRotation(_serverRotation); bool zeroSpeed = true; bool zeroSpin = true; if (_body->isActive()) { - _sentVelocity = bulletToGLM(_body->getLinearVelocity()); - _sentAngularVelocity = bulletToGLM(_body->getAngularVelocity()); + _serverVelocity = bulletToGLM(_body->getLinearVelocity()); + _serverAngularVelocity = bulletToGLM(_body->getAngularVelocity()); // if the speeds are very small we zero them out const float MINIMUM_EXTRAPOLATION_SPEED_SQUARED = 1.0e-4f; // 1cm/sec - zeroSpeed = (glm::length2(_sentVelocity) < MINIMUM_EXTRAPOLATION_SPEED_SQUARED); + zeroSpeed = (glm::length2(_serverVelocity) < MINIMUM_EXTRAPOLATION_SPEED_SQUARED); if (zeroSpeed) { - _sentVelocity = glm::vec3(0.0f); + _serverVelocity = glm::vec3(0.0f); } const float MINIMUM_EXTRAPOLATION_SPIN_SQUARED = 0.004f; // ~0.01 rotation/sec - zeroSpin = glm::length2(_sentAngularVelocity) < MINIMUM_EXTRAPOLATION_SPIN_SQUARED; + zeroSpin = glm::length2(_serverAngularVelocity) < MINIMUM_EXTRAPOLATION_SPIN_SQUARED; if (zeroSpin) { - _sentAngularVelocity = glm::vec3(0.0f); + _serverAngularVelocity = glm::vec3(0.0f); } _sentMoving = ! (zeroSpeed && zeroSpin); } else { - _sentVelocity = _sentAngularVelocity = glm::vec3(0.0f); + _serverVelocity = _serverAngularVelocity = glm::vec3(0.0f); _sentMoving = false; } - properties.setVelocity(_sentVelocity); - _sentGravity = _entity->getGravity(); + properties.setVelocity(_serverVelocity); + _serverGravity = _entity->getGravity(); properties.setGravity(_entity->getGravity()); - _sentAcceleration = _entity->getAcceleration(); - properties.setAcceleration(_sentAcceleration); - properties.setAngularVelocity(_sentAngularVelocity); + _serverAcceleration = _entity->getAcceleration(); + properties.setAcceleration(_serverAcceleration); + properties.setAngularVelocity(_serverAngularVelocity); auto nodeList = DependencyManager::get(); QUuid myNodeID = nodeList->getSessionUUID(); @@ -430,7 +430,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ #endif } - _sentStep = step; + _lastStep = step; } uint32_t EntityMotionState::getAndClearIncomingDirtyFlags() const { diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 1c45b40627..6028662aa0 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -95,14 +95,14 @@ protected: bool _sentMoving; // true if last update was moving int _numNonMovingUpdates; // RELIABLE_SEND_HACK for "not so reliable" resends of packets for non-moving objects - // TODO XXX rename _sent* to _server* - uint32_t _sentStep; - glm::vec3 _sentPosition; // in simulation-frame (not world-frame) - glm::quat _sentRotation;; - glm::vec3 _sentVelocity; - glm::vec3 _sentAngularVelocity; // radians per second - glm::vec3 _sentGravity; - glm::vec3 _sentAcceleration; + // these are for the prediction of the remote server's simple extrapolation + uint32_t _lastStep; // last step of server extrapolation + glm::vec3 _serverPosition; // in simulation-frame (not world-frame) + glm::quat _serverRotation; + glm::vec3 _serverVelocity; + glm::vec3 _serverAngularVelocity; // radians per second + glm::vec3 _serverGravity; + glm::vec3 _serverAcceleration; uint32_t _lastMeasureStep; glm::vec3 _lastVelocity; From e7e4d80be5132100a471678fd9695738be1ce4e4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 7 May 2015 15:22:58 -0700 Subject: [PATCH 75/89] always remove from _pendingAdds just in case --- libraries/physics/src/PhysicalEntitySimulation.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index 06d025244a..ed7b986800 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -62,15 +62,10 @@ void PhysicalEntitySimulation::removeEntityInternal(EntityItem* entity) { if (motionState) { motionState->clearEntity(); entity->setPhysicsInfo(nullptr); - - // NOTE: we must remove entity from _pendingAdds immediately because we've disconnected the backpointers between - // motionState and entity and they can't be used to look up each other. However we don't need to remove - // motionState from _pendingChanges at this time becuase it will be removed during getObjectsToDelete(). - _pendingAdds.remove(entity); - _pendingRemoves.insert(motionState); _outgoingChanges.remove(motionState); } + _pendingAdds.remove(entity); } void PhysicalEntitySimulation::changeEntityInternal(EntityItem* entity) { From 8c3a57566bb83ed64aed6257618dd28797392e22 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 7 May 2015 16:00:30 -0700 Subject: [PATCH 76/89] fix name of settings key for max octree pps --- libraries/octree/src/OctreeQuery.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index 6ca55fc4cc..5f62318338 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -16,7 +16,7 @@ #include "OctreeConstants.h" #include "OctreeQuery.h" -Setting::Handle maxOctreePacketsPerSecond("maxOctreePPS", DEFAULT_MAX_OCTREE_PPS); +Setting::Handle maxOctreePacketsPerSecond("maxOctreePPSSpin", DEFAULT_MAX_OCTREE_PPS); OctreeQuery::OctreeQuery() { _maxOctreePPS = maxOctreePacketsPerSecond.get(); From c1e3500f3ccd5d6165b53b1cdabf8b83261d52bb Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 7 May 2015 16:01:08 -0700 Subject: [PATCH 77/89] voxelDetailsForCode returns a ratio, cubeinfrustrum takes meters --- interface/src/Application.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8d660848f2..61ba836d4a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2644,7 +2644,10 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node if (rootCode) { VoxelPositionSize rootDetails; voxelDetailsForCode(rootCode, rootDetails); - AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); + AACube serverBounds(glm::vec3(rootDetails.x * TREE_SCALE, + rootDetails.y * TREE_SCALE, + rootDetails.z * TREE_SCALE), + rootDetails.s * TREE_SCALE); ViewFrustum::location serverFrustumLocation = _viewFrustum.cubeInFrustum(serverBounds); @@ -2685,7 +2688,6 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node // only send to the NodeTypes that are serverType if (node->getActiveSocket() && node->getType() == serverType) { - // get the server bounds for this server QUuid nodeUUID = node->getUUID(); @@ -2707,7 +2709,12 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node if (rootCode) { VoxelPositionSize rootDetails; voxelDetailsForCode(rootCode, rootDetails); - AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); + AACube serverBounds(glm::vec3(rootDetails.x * TREE_SCALE, + rootDetails.y * TREE_SCALE, + rootDetails.z * TREE_SCALE), + rootDetails.s * TREE_SCALE); + + ViewFrustum::location serverFrustumLocation = _viewFrustum.cubeInFrustum(serverBounds); if (serverFrustumLocation != ViewFrustum::OUTSIDE) { @@ -2753,7 +2760,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node } // set up the packet for sending... unsigned char* endOfQueryPacket = queryPacket; - + // insert packet type/version and node UUID endOfQueryPacket += populatePacketHeader(reinterpret_cast(endOfQueryPacket), packetType); From 8db8e56af02abfbe376bcdbd05997aa6e9b6bb72 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 7 May 2015 16:41:52 -0700 Subject: [PATCH 78/89] Merge branch 'master' of https://github.com/highfidelity/hifi into objReader-tweak --- libraries/fbx/src/OBJReader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 186c7b03e8..c26dcacd4c 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -484,7 +484,7 @@ FBXGeometry OBJReader::readOBJ(QIODevice* device, const QVariantHash& mapping, Q meshPart._material->setShininess(material->shininess); meshPart._material->setOpacity(material->opacity); } - qCDebug(modelformat) << "OBJ Reader part:" << meshPartCount << "name:" << leadFace.groupName << "material:" << groupMaterialName << "diffuse:" << meshPart._material->getDiffuse() << " texture:" << meshPart.diffuseTexture.filename << "faces:" << faceGroup.count() << "triangle indices will start with:" << mesh.vertices.count(); + // qCDebug(modelformat) << "OBJ Reader part:" << meshPartCount << "name:" << leadFace.groupName << "material:" << groupMaterialName << "diffuse:" << meshPart._material->getDiffuse() << "faces:" << faceGroup.count() << "triangle indices will start with:" << mesh.vertices.count(); foreach(OBJFace face, faceGroup) { glm::vec3 v0 = vertices[face.vertexIndices[0]]; glm::vec3 v1 = vertices[face.vertexIndices[1]]; @@ -529,7 +529,7 @@ FBXGeometry OBJReader::readOBJ(QIODevice* device, const QVariantHash& mapping, Q mesh.meshExtents.addPoint(vertex); geometry.meshExtents.addPoint(vertex); } - fbxDebugDump(geometry); + // fbxDebugDump(geometry); } catch(const std::exception& e) { qCDebug(modelformat) << "OBJ reader fail: " << e.what(); } From ce5295a55fac635551c13204bbae8708d2dd32cb Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 7 May 2015 17:06:15 -0700 Subject: [PATCH 79/89] THese is not final but we have a basic working framework so let's try to share --- interface/src/Application.cpp | 6 ------ .../src/EntityTreeRenderer.cpp | 5 ++++- libraries/gpu/src/gpu/GLBackendTexture.cpp | 4 +--- libraries/model/src/model/Material.h | 1 + libraries/model/src/model/Skybox.cpp | 6 +++--- libraries/model/src/model/Skybox.slf | 7 ++++--- libraries/model/src/model/TextureStorage.cpp | 13 ++++++------- libraries/model/src/model/TextureStorage.h | 18 +++++++++++++----- libraries/render-utils/src/TextureCache.cpp | 2 +- 9 files changed, 33 insertions(+), 29 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2578c498a9..cc99181fe1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3212,12 +3212,6 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs } else if (skyStage->getBackgroundMode() == model::SunSkyStage::SKY_BOX) { auto skybox = skyStage->getSkybox(); if (skybox) { - if (!skybox->getCubemap()) { - auto texture = DependencyManager::get()-> - getTexture(QUrl("https://hifi-public.s3.amazonaws.com/ryan/CloudyDay.png"), CUBE_TEXTURE); - skybox->setCubemap(texture->getGPUTexture()); - } - gpu::Batch batch; model::Skybox::render(batch, _viewFrustum, *skybox); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 0fb9296b64..84f12fca2d 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include "EntityTreeRenderer.h" @@ -455,7 +456,9 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, if (_bestZone->getSkyboxProperties().getURL().isEmpty()) { stage->getSkybox()->clearCubemap(); } else { - stage->getSkybox()->clearCubemap(); // NOTE: this should be changed to do something to set the cubemap + auto cubeMap = DependencyManager::get()->getTexture(_bestZone->getSkyboxProperties().getURL(), CUBE_TEXTURE); + + stage->getSkybox()->setCubemap(cubeMap->getGPUTexture()); // NOTE: this should be changed to do something to set the cubemap } stage->setBackgroundMode(model::SunSkyStage::SKY_BOX); } diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index df275e16ad..69f2b33d1b 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -370,11 +370,9 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { glBindTexture(GL_TEXTURE_CUBE_MAP, object->_texture); const int NUM_FACES = 6; const GLenum FACE_LAYOUT[] = { - // GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, - GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_X, + GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z }; - if (needUpdate) { if (texture.isStoredMipAvailable(0)) { Texture::PixelsPointer mip = texture.accessStoredMip(0); diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index cd4c6d0373..ea0ab808e9 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -41,6 +41,7 @@ public: NUM_MAPS, }; typedef std::map TextureMap; + typedef std::bitset MapFlags; enum FlagBit { DIFFUSE_BIT = 0, diff --git a/libraries/model/src/model/Skybox.cpp b/libraries/model/src/model/Skybox.cpp index c163f8c069..c01d07edfa 100755 --- a/libraries/model/src/model/Skybox.cpp +++ b/libraries/model/src/model/Skybox.cpp @@ -20,8 +20,8 @@ using namespace model; Skybox::Skybox() { - -/* _cubemap.reset( gpu::Texture::createCube(gpu::Element::COLOR_RGBA_32, 1)); +/* + _cubemap.reset( gpu::Texture::createCube(gpu::Element::COLOR_RGBA_32, 1)); unsigned char texels[] = { 255, 0, 0, 255, 0, 255, 255, 255, @@ -30,7 +30,7 @@ Skybox::Skybox() { 0, 255, 0, 255, 255, 0, 255, 255, }; - _cubemap->assignStoredMip(0, gpu::Element::COLOR_RGBA_32, sizeof(texels), texels); */ + _cubemap->assignStoredMip(0, gpu::Element::COLOR_RGBA_32, sizeof(texels), texels);*/ } void Skybox::setColor(const Color& color) { diff --git a/libraries/model/src/model/Skybox.slf b/libraries/model/src/model/Skybox.slf index 452b9daebe..03f7a5ef8a 100755 --- a/libraries/model/src/model/Skybox.slf +++ b/libraries/model/src/model/Skybox.slf @@ -18,7 +18,8 @@ varying vec3 color; void main(void) { - vec4 texel = textureCube(cubeMap, normalize(normal)); - gl_FragData[0] = texel; - // gl_FragData[0] = vec4(normal, 1.0); + vec3 coord = normalize(normal); + vec4 texel = textureCube(cubeMap, coord); + // gl_FragData[0] = vec4(texel.xyz * color, texel.w); + gl_FragData[0] = vec4(texel.xyz, 1.0); } diff --git a/libraries/model/src/model/TextureStorage.cpp b/libraries/model/src/model/TextureStorage.cpp index cc01941424..499054c34b 100755 --- a/libraries/model/src/model/TextureStorage.cpp +++ b/libraries/model/src/model/TextureStorage.cpp @@ -14,16 +14,15 @@ using namespace model; using namespace gpu; // TextureStorage -TextureStorage::TextureStorage(const QUrl& url, Texture::Type type ) : Texture::Storage(), - _url(url), - _type(type) { - init(); -} +TextureStorage::TextureStorage() : Texture::Storage(), + _gpuTexture(Texture::createFromStorage(this)) +{} TextureStorage::~TextureStorage() { } -void TextureStorage::init() { - _gpuTexture = TexturePointer(Texture::createFromStorage(this)); +void TextureStorage::reset(const QUrl& url, const TextureUsage& usage) { + _url = url; + _usage = usage; } diff --git a/libraries/model/src/model/TextureStorage.h b/libraries/model/src/model/TextureStorage.h index ec56438bf3..2b19a6cc1d 100755 --- a/libraries/model/src/model/TextureStorage.h +++ b/libraries/model/src/model/TextureStorage.h @@ -21,24 +21,32 @@ namespace model { typedef glm::vec3 Color; +class TextureUsage { +public: + gpu::Texture::Type _type{ gpu::Texture::TEX_2D }; + Material::MapFlags _materialUsage{ Material::DIFFUSE_MAP }; + + int _environmentUsage = 0; +}; + // TextureStorage is a specialized version of the gpu::Texture::Storage // It provides the mechanism to create a texture from a Url and the intended usage // that guides the internal format used class TextureStorage : public gpu::Texture::Storage { public: - TextureStorage(const QUrl& url, gpu::Texture::Type type = gpu::Texture::TEX_2D); + TextureStorage(); ~TextureStorage(); const QUrl& getUrl() const { return _url; } - const gpu::Texture::Type getType() const { return _type; } + const gpu::Texture::Type getType() const { return _usage._type; } const gpu::TexturePointer& getGPUTexture() const { return _gpuTexture; } + void reset(const QUrl& url, const TextureUsage& usage); + protected: gpu::TexturePointer _gpuTexture; + TextureUsage _usage; QUrl _url; - gpu::Texture::Type _type; - - void init(); }; typedef std::shared_ptr< TextureStorage > TextureStoragePointer; diff --git a/libraries/render-utils/src/TextureCache.cpp b/libraries/render-utils/src/TextureCache.cpp index 754ceb5d7e..c88050f7fb 100644 --- a/libraries/render-utils/src/TextureCache.cpp +++ b/libraries/render-utils/src/TextureCache.cpp @@ -525,7 +525,7 @@ void NetworkTexture::setImage(const QImage& image, bool translucent, const QColo if (_type == CUBE_TEXTURE) { if (_height >= (6 * _width)) { - _gpuTexture = gpu::TexturePointer(gpu::Texture::createCube(formatGPU, image.width(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT, gpu::Sampler::WRAP_CLAMP))); + _gpuTexture = gpu::TexturePointer(gpu::Texture::createCube(formatGPU, image.width(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP))); _gpuTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); _gpuTexture->autoGenerateMips(-1); } From deb303838d8e0e6fbbdfd5198c7db12e9e1cce3e Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 7 May 2015 17:15:45 -0700 Subject: [PATCH 80/89] Cleaning code --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 4 ++-- libraries/model/src/model/Skybox.cpp | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 84f12fca2d..b268ba6031 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -456,9 +456,9 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, if (_bestZone->getSkyboxProperties().getURL().isEmpty()) { stage->getSkybox()->clearCubemap(); } else { + // Update the Texture of the Skybox with the one pointed by this zone auto cubeMap = DependencyManager::get()->getTexture(_bestZone->getSkyboxProperties().getURL(), CUBE_TEXTURE); - - stage->getSkybox()->setCubemap(cubeMap->getGPUTexture()); // NOTE: this should be changed to do something to set the cubemap + stage->getSkybox()->setCubemap(cubeMap->getGPUTexture()); } stage->setBackgroundMode(model::SunSkyStage::SKY_BOX); } diff --git a/libraries/model/src/model/Skybox.cpp b/libraries/model/src/model/Skybox.cpp index c01d07edfa..00a64c9606 100755 --- a/libraries/model/src/model/Skybox.cpp +++ b/libraries/model/src/model/Skybox.cpp @@ -20,7 +20,8 @@ using namespace model; Skybox::Skybox() { -/* + +/* // PLease create a default engineer skybox _cubemap.reset( gpu::Texture::createCube(gpu::Element::COLOR_RGBA_32, 1)); unsigned char texels[] = { 255, 0, 0, 255, From e20df0e2bf67e30a284631ef22787b060352fd56 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 7 May 2015 18:28:49 -0700 Subject: [PATCH 81/89] Delete Leap and RealSense devices on shutdown Leaving them running prevents a clean shutdown on Windows when running Interface.exe from a command line: the interface.exe process stays alive preventing Interface from being run again from the command line without manually terminating the running process. --- interface/src/Application.cpp | 3 +++ interface/src/devices/DeviceTracker.cpp | 7 +++++++ interface/src/devices/DeviceTracker.h | 2 ++ interface/src/devices/Leapmotion.cpp | 5 +++++ interface/src/devices/Leapmotion.h | 1 + interface/src/devices/RealSense.cpp | 5 +++++ interface/src/devices/RealSense.h | 1 + 7 files changed, 24 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index cc99181fe1..1174fbf697 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -690,6 +690,9 @@ Application::~Application() { nodeThread->quit(); nodeThread->wait(); + Leapmotion::destroy(); + RealSense::destroy(); + qInstallMessageHandler(NULL); // NOTE: Do this as late as possible so we continue to get our log messages } diff --git a/interface/src/devices/DeviceTracker.cpp b/interface/src/devices/DeviceTracker.cpp index 265a77b362..aa0e68ff47 100644 --- a/interface/src/devices/DeviceTracker.cpp +++ b/interface/src/devices/DeviceTracker.cpp @@ -66,6 +66,13 @@ DeviceTracker::ID DeviceTracker::registerDevice(const Name& name, DeviceTracker* return deviceID; } +void DeviceTracker::destroyDevice(const Name& name) { + DeviceTracker::ID deviceID = getDeviceID(name); + if (deviceID != INVALID_DEVICE) { + delete Singleton::get()->_devicesVector[getDeviceID(name)]; + } +} + void DeviceTracker::updateAll() { //TODO C++11 for (auto deviceIt = Singleton::get()->_devicesVector.begin(); deviceIt != Singleton::get()->_devicesVector.end(); deviceIt++) { for (Vector::iterator deviceIt = Singleton::get()->_devicesVector.begin(); deviceIt != Singleton::get()->_devicesVector.end(); deviceIt++) { diff --git a/interface/src/devices/DeviceTracker.h b/interface/src/devices/DeviceTracker.h index 2e0f69b371..b28e22b06d 100644 --- a/interface/src/devices/DeviceTracker.h +++ b/interface/src/devices/DeviceTracker.h @@ -79,6 +79,8 @@ public: /// INVALID_DEVICE_NAME if the name is already taken static ID registerDevice(const Name& name, DeviceTracker* tracker); + static void destroyDevice(const Name& name); + // DeviceTracker interface virtual void update(); diff --git a/interface/src/devices/Leapmotion.cpp b/interface/src/devices/Leapmotion.cpp index 04cd51a484..cb99cf324d 100644 --- a/interface/src/devices/Leapmotion.cpp +++ b/interface/src/devices/Leapmotion.cpp @@ -50,6 +50,11 @@ void Leapmotion::init() { } } +// static +void Leapmotion::destroy() { + DeviceTracker::destroyDevice(NAME); +} + // static Leapmotion* Leapmotion::getInstance() { DeviceTracker* device = DeviceTracker::getDevice(NAME); diff --git a/interface/src/devices/Leapmotion.h b/interface/src/devices/Leapmotion.h index a0c75da38f..266b9beb87 100644 --- a/interface/src/devices/Leapmotion.h +++ b/interface/src/devices/Leapmotion.h @@ -26,6 +26,7 @@ public: static const Name NAME; static void init(); + static void destroy(); /// Leapmotion MotionTracker factory static Leapmotion* getInstance(); diff --git a/interface/src/devices/RealSense.cpp b/interface/src/devices/RealSense.cpp index 8e9cd85451..d9b1486f09 100644 --- a/interface/src/devices/RealSense.cpp +++ b/interface/src/devices/RealSense.cpp @@ -54,6 +54,11 @@ void RealSense::init() { } } +// static +void RealSense::destroy() { + DeviceTracker::destroyDevice(NAME); +} + // static RealSense* RealSense::getInstance() { DeviceTracker* device = DeviceTracker::getDevice(NAME); diff --git a/interface/src/devices/RealSense.h b/interface/src/devices/RealSense.h index 20111365d0..c958ab1e53 100644 --- a/interface/src/devices/RealSense.h +++ b/interface/src/devices/RealSense.h @@ -32,6 +32,7 @@ public: static const Name NAME; static void init(); + static void destroy(); /// RealSense MotionTracker factory static RealSense* getInstance(); From d3a977d3f8a9d08ee4d13ade4533b5be15ddeb54 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 7 May 2015 21:05:13 -0700 Subject: [PATCH 82/89] Fix velocity math error, add random color changes --- examples/harmonicOscillator.js | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/examples/harmonicOscillator.js b/examples/harmonicOscillator.js index 0ffbce8beb..653c2db939 100644 --- a/examples/harmonicOscillator.js +++ b/examples/harmonicOscillator.js @@ -16,8 +16,7 @@ var ball, disc; var time = 0.0; var range = 1.0; -var speed = 0.5; - +var omega = 2.0 * Math.PI / 32.0; var basePosition = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); @@ -25,35 +24,44 @@ ball = Entities.addEntity( { type: "Box", position: basePosition, dimensions: { x: 0.1, y: 0.1, z: 0.1 }, - color: { red: 255, green: 0, blue: 255 } + color: { red: 255, green: 0, blue: 255 }, + collisionsWillMove: false, + ignoreForCollisions: true }); disc = Entities.addEntity( { type: "Sphere", position: basePosition, - dimensions: { x: range, y: range / 20.0, z: range }, + dimensions: { x: range * 0.8, y: range / 20.0, z: range * 0.8}, color: { red: 128, green: 128, blue: 128 } }); +function randomColor() { + return { red: Math.random() * 255, green: Math.random() * 255, blue: Math.random() * 255 }; +} + function update(deltaTime) { - time += deltaTime * speed; + time += deltaTime; if (!ball.isKnownID) { ball = Entities.identifyEntity(ball); } - rotation = Quat.angleAxis(time/Math.PI * 180.0, { x: 0, y: 1, z: 0 }); + rotation = Quat.angleAxis(time * omega /Math.PI * 180.0, { x: 0, y: 1, z: 0 }); Entities.editEntity(ball, { - color: { red: 255 * (Math.sin(time)/2.0 + 0.5), - green: 255 - 255 * (Math.sin(time)/2.0 + 0.5), + color: { red: 255 * (Math.sin(time * omega)/2.0 + 0.5), + green: 255 - 255 * (Math.sin(time * omega)/2.0 + 0.5), blue: 0 }, - position: { x: basePosition.x + Math.sin(time) / 2.0 * range, + position: { x: basePosition.x + Math.sin(time * omega) / 2.0 * range, y: basePosition.y, - z: basePosition.z + Math.cos(time) / 2.0 * range }, - velocity: { x: Math.cos(time)/2.0 * range, + z: basePosition.z + Math.cos(time * omega) / 2.0 * range }, + velocity: { x: Math.cos(time * omega)/2.0 * range * omega, y: 0.0, - z: -Math.sin(time)/2.0 * range }, + z: -Math.sin(time * omega)/2.0 * range * omega}, rotation: rotation }); + if (Math.random() < 0.007) { + Entities.editEntity(disc, { color: randomColor() }); + } } function scriptEnding() { From 32dbbbdc8fa98cb5a6e4c7ecb603f59a0eceda6a Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 7 May 2015 21:44:09 -0700 Subject: [PATCH 83/89] normalize a vector that needed it. Correct rolloff of grab force --- examples/grab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/grab.js b/examples/grab.js index 5d2ae13cde..312d21dd43 100644 --- a/examples/grab.js +++ b/examples/grab.js @@ -179,7 +179,7 @@ function update(deltaTime) { if (distanceToTarget > CLOSE_ENOUGH) { // compute current velocity in the direction we want to move velocityTowardTarget = Vec3.dot(currentVelocity, Vec3.normalize(dPosition)); - velocityTowardTarget = Vec3.multiply(dPosition, velocityTowardTarget); + velocityTowardTarget = Vec3.multiply(Vec3.normalize(dPosition), velocityTowardTarget); // compute the speed we would like to be going toward the target position desiredVelocity = Vec3.multiply(dPosition, (1.0 / deltaTime) * SPRING_RATE); From 01e3c33bf1b88b85da70a28ecb6c8442537fb89d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 8 May 2015 16:13:04 +0200 Subject: [PATCH 84/89] Add some debug to edit.js --- examples/libraries/entitySelectionTool.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 70af987243..80ba4c0f56 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -203,7 +203,7 @@ SelectionManager = (function() { try { listeners[i](); } catch (e) { - print("got exception"); + print("EntitySelectionTool got exception: " = JSON.stringify(e)); } } }; From ada48bcb70647e035176bcb72036af6b382b63fd Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 8 May 2015 09:06:31 -0700 Subject: [PATCH 85/89] fix for glitchy physics updates --- libraries/physics/src/EntityMotionState.cpp | 148 +++++++++----------- 1 file changed, 70 insertions(+), 78 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index c897da3ef9..b5d14e4814 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -151,10 +151,10 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { _movingStepsWithoutSimulationOwner = 0; } - int ownershipClaimDelay = 50; // TODO -- how to pick this? based on meters from our characterController? + uint32_t ownershipClaimDelay = 50; // TODO -- how to pick this? based on meters from our characterController? if (_movingStepsWithoutSimulationOwner > ownershipClaimDelay) { - qDebug() << "Warning -- claiming something I saw moving." << getName(); + //qDebug() << "Warning -- claiming something I saw moving." << getName(); setShouldClaimSimulationOwnership(true); } @@ -178,7 +178,7 @@ void EntityMotionState::computeObjectShapeInfo(ShapeInfo& shapeInfo) { const int MAX_NUM_NON_MOVING_UPDATES = 5; bool EntityMotionState::doesNotNeedToSendUpdate() const { - return !_body->isActive() && _numNonMovingUpdates > MAX_NUM_NON_MOVING_UPDATES; + return !_body || (_body->isActive() && _numNonMovingUpdates > MAX_NUM_NON_MOVING_UPDATES); } bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { @@ -232,6 +232,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { _serverPosition += dt * _serverVelocity; } + // TODO: compensate for simulation offset here btTransform worldTrans = _body->getWorldTransform(); glm::vec3 position = bulletToGLM(worldTrans.getOrigin()); @@ -310,86 +311,60 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ return; // never update entities that are unknown } + bool active = _body->isActive(); + if (!active) { + if (_sentMoving) { + // make sure all derivatives are zero + glm::vec3 zero(0.0f); + _entity->setVelocity(zero); + _entity->setAngularVelocity(zero); + _entity->setAcceleration(zero); + } + + } else { + float gravityLength = glm::length(_entity->getGravity()); + float accVsGravity = glm::abs(glm::length(_measuredAcceleration) - gravityLength); + if (accVsGravity < ACCELERATION_EQUIVALENT_EPSILON_RATIO * gravityLength) { + // acceleration measured during the most recent simulation step was close to gravity. + if (getAccelerationNearlyGravityCount() < STEPS_TO_DECIDE_BALLISTIC) { + // only increment this if we haven't reached the threshold yet. this is to avoid + // overflowing the counter. + incrementAccelerationNearlyGravityCount(); + } + } else { + // acceleration wasn't similar to this entities gravity, so reset the went-ballistic counter + resetAccelerationNearlyGravityCount(); + } + + // if this entity has been accelerated at close to gravity for a certain number of simulation-steps, let + // the entity server's estimates include gravity. + if (getAccelerationNearlyGravityCount() >= STEPS_TO_DECIDE_BALLISTIC) { + _entity->setAcceleration(_entity->getGravity()); + } else { + _entity->setAcceleration(glm::vec3(0.0f)); + } + } + + // remember properties for local server prediction + _serverPosition = _entity->getPosition(); + _serverRotation = _entity->getRotation(); + _serverVelocity = _entity->getVelocity(); + _serverAcceleration = _entity->getAcceleration(); + _serverAngularVelocity = _entity->getAngularVelocity(); + + _sentMoving = _serverVelocity != glm::vec3(0.0f) || _serverAngularVelocity != glm::vec3(0.0f); + EntityItemProperties properties = _entity->getProperties(); - float gravityLength = glm::length(_entity->getGravity()); - float accVsGravity = glm::abs(glm::length(_measuredAcceleration) - gravityLength); - if (accVsGravity < ACCELERATION_EQUIVALENT_EPSILON_RATIO * gravityLength) { - // acceleration measured during the most recent simulation step was close to gravity. - if (getAccelerationNearlyGravityCount() < STEPS_TO_DECIDE_BALLISTIC) { - // only increment this if we haven't reached the threshold yet. this is to avoid - // overflowing the counter. - incrementAccelerationNearlyGravityCount(); - } - } else { - // acceleration wasn't similar to this entities gravity, so reset the went-ballistic counter - resetAccelerationNearlyGravityCount(); - } - - // if this entity has been accelerated at close to gravity for a certain number of simulation-steps, let - // the entity server's estimates include gravity. - if (getAccelerationNearlyGravityCount() >= STEPS_TO_DECIDE_BALLISTIC) { - _entity->setAcceleration(_entity->getGravity()); - } else { - _entity->setAcceleration(glm::vec3(0.0f)); - } - - btTransform worldTrans = _body->getWorldTransform(); - _serverPosition = bulletToGLM(worldTrans.getOrigin()); - properties.setPosition(_serverPosition + ObjectMotionState::getWorldOffset()); - - _serverRotation = bulletToGLM(worldTrans.getRotation()); + // explicitly set the properties that changed + properties.setPosition(_serverPosition); properties.setRotation(_serverRotation); - - bool zeroSpeed = true; - bool zeroSpin = true; - - if (_body->isActive()) { - _serverVelocity = bulletToGLM(_body->getLinearVelocity()); - _serverAngularVelocity = bulletToGLM(_body->getAngularVelocity()); - - // if the speeds are very small we zero them out - const float MINIMUM_EXTRAPOLATION_SPEED_SQUARED = 1.0e-4f; // 1cm/sec - zeroSpeed = (glm::length2(_serverVelocity) < MINIMUM_EXTRAPOLATION_SPEED_SQUARED); - if (zeroSpeed) { - _serverVelocity = glm::vec3(0.0f); - } - const float MINIMUM_EXTRAPOLATION_SPIN_SQUARED = 0.004f; // ~0.01 rotation/sec - zeroSpin = glm::length2(_serverAngularVelocity) < MINIMUM_EXTRAPOLATION_SPIN_SQUARED; - if (zeroSpin) { - _serverAngularVelocity = glm::vec3(0.0f); - } - - _sentMoving = ! (zeroSpeed && zeroSpin); - } else { - _serverVelocity = _serverAngularVelocity = glm::vec3(0.0f); - _sentMoving = false; - } properties.setVelocity(_serverVelocity); - _serverGravity = _entity->getGravity(); - properties.setGravity(_entity->getGravity()); - _serverAcceleration = _entity->getAcceleration(); properties.setAcceleration(_serverAcceleration); properties.setAngularVelocity(_serverAngularVelocity); - auto nodeList = DependencyManager::get(); - QUuid myNodeID = nodeList->getSessionUUID(); - QUuid simulatorID = _entity->getSimulatorID(); - - if (getShouldClaimSimulationOwnership()) { - properties.setSimulatorID(myNodeID); - setShouldClaimSimulationOwnership(false); - } else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { - // we are the simulator and the entity has stopped. give up "simulator" status - _entity->setSimulatorID(QUuid()); - properties.setSimulatorID(QUuid()); - } else if (simulatorID == myNodeID && !_body->isActive()) { - // it's not active. don't keep simulation ownership. - _entity->setSimulatorID(QUuid()); - properties.setSimulatorID(QUuid()); - } - - // RELIABLE_SEND_HACK: count number of updates for entities at rest so we can stop sending them after some limit. + // 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 { @@ -397,8 +372,6 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ } if (_numNonMovingUpdates <= 1) { // we only update lastEdited when we're sending new physics data - // (i.e. NOT when we just simulate the positions forward, nor when we resend non-moving data) - // NOTE: Andrew & Brad to discuss. Let's make sure we're using lastEdited, lastSimulated, and lastUpdated correctly quint64 lastSimulated = _entity->getLastSimulated(); _entity->setLastEdited(lastSimulated); properties.setLastEdited(lastSimulated); @@ -415,6 +388,25 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ properties.setLastEdited(_entity->getLastEdited()); } + auto nodeList = DependencyManager::get(); + QUuid myNodeID = nodeList->getSessionUUID(); + QUuid simulatorID = _entity->getSimulatorID(); + + if (getShouldClaimSimulationOwnership()) { + // we think we should own it, so we tell the server that we do, + // but we don't remember that we own it... + // instead we expect the sever to tell us later whose ownership it has accepted + properties.setSimulatorID(myNodeID); + setShouldClaimSimulationOwnership(false); + } else if (simulatorID == myNodeID + && !_sentMoving + && _numNonMovingUpdates == MAX_NUM_NON_MOVING_UPDATES) { + // we own it, the entity has stopped, and we're sending the last non-moving update + // --> give up ownership + _entity->setSimulatorID(QUuid()); + properties.setSimulatorID(QUuid()); + } + if (EntityItem::getSendPhysicsUpdates()) { EntityItemID id(_entity->getID()); EntityEditPacketSender* entityPacketSender = static_cast(packetSender); From 6d0ca40aae2ec2f8327f0dbcf26f322a2752a385 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 8 May 2015 18:21:42 +0200 Subject: [PATCH 86/89] Set pointer to nullptr after delete --- interface/src/devices/DeviceTracker.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/devices/DeviceTracker.cpp b/interface/src/devices/DeviceTracker.cpp index aa0e68ff47..2a956a42de 100644 --- a/interface/src/devices/DeviceTracker.cpp +++ b/interface/src/devices/DeviceTracker.cpp @@ -70,6 +70,7 @@ void DeviceTracker::destroyDevice(const Name& name) { DeviceTracker::ID deviceID = getDeviceID(name); if (deviceID != INVALID_DEVICE) { delete Singleton::get()->_devicesVector[getDeviceID(name)]; + Singleton::get()->_devicesVector[getDeviceID(name)] = nullptr; } } From de6a63c69ae8f778e0429aba15b823b885f76414 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 8 May 2015 09:49:58 -0700 Subject: [PATCH 87/89] add delete button to clear existing dice --- examples/dice.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/examples/dice.js b/examples/dice.js index ee48d59617..f313e606b8 100644 --- a/examples/dice.js +++ b/examples/dice.js @@ -32,7 +32,7 @@ var BUTTON_SIZE = 32; var PADDING = 3; var offButton = Overlays.addOverlay("image", { - x: screenSize.x / 2 - BUTTON_SIZE, + x: screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING, y: screenSize.y- (BUTTON_SIZE + PADDING), width: BUTTON_SIZE, height: BUTTON_SIZE, @@ -40,6 +40,17 @@ var offButton = Overlays.addOverlay("image", { color: { red: 255, green: 255, blue: 255}, alpha: 1 }); + +var deleteButton = Overlays.addOverlay("image", { + x: screenSize.x / 2 - BUTTON_SIZE, + y: screenSize.y- (BUTTON_SIZE + PADDING), + width: BUTTON_SIZE, + height: BUTTON_SIZE, + imageURL: HIFI_PUBLIC_BUCKET + "images/delete.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); + var diceButton = Overlays.addOverlay("image", { x: screenSize.x / 2 + PADDING, y: screenSize.y - (BUTTON_SIZE + PADDING), @@ -108,6 +119,8 @@ function mousePressEvent(event) { if (clickedOverlay == offButton) { deleteDice(); Script.stop(); + } else if (clickedOverlay == deleteButton) { + deleteDice(); } else if (clickedOverlay == diceButton) { var HOW_HARD = 2.0; var position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); @@ -120,6 +133,7 @@ function mousePressEvent(event) { function scriptEnding() { Overlays.deleteOverlay(offButton); Overlays.deleteOverlay(diceButton); + Overlays.deleteOverlay(deleteButton); } Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity); From e8f43c7f4bfe0e0959eb661d2360629603602a2b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 8 May 2015 10:03:24 -0700 Subject: [PATCH 88/89] set default atmosphere properties to match the default atmosphere --- .../entities/src/AtmospherePropertyGroup.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/AtmospherePropertyGroup.cpp b/libraries/entities/src/AtmospherePropertyGroup.cpp index c1210be24e..2e0a043749 100644 --- a/libraries/entities/src/AtmospherePropertyGroup.cpp +++ b/libraries/entities/src/AtmospherePropertyGroup.cpp @@ -16,12 +16,19 @@ #include "EntityItemPropertiesMacros.h" AtmospherePropertyGroup::AtmospherePropertyGroup() { - _center = glm::vec3(0.0f); - _innerRadius = 0.0f; - _outerRadius = 0.0f; - _mieScattering = 0.0f; - _rayleighScattering = 0.0f; - _scatteringWavelengths = glm::vec3(0.0f); + const glm::vec3 DEFAULT_CENTER = glm::vec3(0.0f, -1000.0f, 0.0f); + const float DEFAULT_INNER_RADIUS = 1000.0f; + const float DEFAULT_OUTER_RADIUS = 1025.0f; + const float DEFAULT_RAYLEIGH_SCATTERING = 0.0025f; + const float DEFAULT_MIE_SCATTERING = 0.0010f; + const glm::vec3 DEFAULT_SCATTERING_WAVELENGTHS = glm::vec3(0.650f, 0.570f, 0.475f); + + _center = DEFAULT_CENTER; + _innerRadius = DEFAULT_INNER_RADIUS; + _outerRadius = DEFAULT_OUTER_RADIUS; + _mieScattering = DEFAULT_MIE_SCATTERING; + _rayleighScattering = DEFAULT_RAYLEIGH_SCATTERING; + _scatteringWavelengths = DEFAULT_SCATTERING_WAVELENGTHS; _hasStars = true; } From d40e4b721876c3c6f691e655e87234d5d6138cf4 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 8 May 2015 14:05:32 -0700 Subject: [PATCH 89/89] don't apply changes to velocity unless needed --- examples/grab.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/grab.js b/examples/grab.js index 312d21dd43..df2042350e 100644 --- a/examples/grab.js +++ b/examples/grab.js @@ -193,12 +193,15 @@ function update(deltaTime) { // Add Damping newVelocity = Vec3.subtract(newVelocity, Vec3.multiply(newVelocity, DAMPING_RATE)); // Update entity - - //add damping to angular velocity: + } else { + newVelocity = entityProps.velocity; } if (shouldRotate) { angularVelocity = Vec3.subtract(angularVelocity, Vec3.multiply(angularVelocity, ANGULAR_DAMPING_RATE)); + } else { + angularVelocity = entityProps.angularVelocity; } + Entities.editEntity(grabbedEntity, { velocity: newVelocity, angularVelocity: angularVelocity