From ec1f11c1a896d47d74f9514c7df34d3c471d9e59 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 24 Nov 2014 11:21:40 -0800 Subject: [PATCH] route more entity updates into physics engine --- .../entities/src/EntityCollisionSystem.cpp | 4 +- libraries/entities/src/EntityItem.cpp | 47 +++--- libraries/entities/src/EntityItem.h | 33 ++-- libraries/entities/src/EntityMotionState.cpp | 51 ++++-- libraries/entities/src/EntityMotionState.h | 14 +- libraries/entities/src/EntityTree.cpp | 71 +++++---- libraries/entities/src/EntityTree.h | 6 +- libraries/entities/src/EntityTreeElement.cpp | 14 +- .../entities/src/UpdateEntityOperator.cpp | 15 +- libraries/physics/src/CustomMotionState.cpp | 6 + libraries/physics/src/CustomMotionState.h | 2 + libraries/physics/src/PhysicsEngine.cpp | 148 +++++++++++++----- libraries/physics/src/PhysicsEngine.h | 26 ++- 13 files changed, 290 insertions(+), 147 deletions(-) diff --git a/libraries/entities/src/EntityCollisionSystem.cpp b/libraries/entities/src/EntityCollisionSystem.cpp index 903cd430de..448a39de78 100644 --- a/libraries/entities/src/EntityCollisionSystem.cpp +++ b/libraries/entities/src/EntityCollisionSystem.cpp @@ -50,7 +50,9 @@ void EntityCollisionSystem::update() { if (_entities->tryLockForRead()) { QList& movingEntities = _entities->getMovingEntities(); foreach (EntityItem* entity, movingEntities) { - checkEntity(entity); + if (!entity->getMotionState()) { + checkEntity(entity); + } } _entities->unlock(); } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index e610ed4c2f..f07ce3ca16 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -91,9 +91,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) { _lastEditedFromRemoteInRemoteTime = 0; _lastUpdated = 0; _created = 0; -#ifdef USE_BULLET_PHYSICS _motionState = NULL; -#endif // USE_BULLET_PHYSICS _updateFlags = 0; _changedOnServer = 0; initFromEntityItemID(entityItemID); @@ -107,9 +105,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert _lastEditedFromRemoteInRemoteTime = 0; _lastUpdated = 0; _created = properties.getCreated(); -#ifdef USE_BULLET_PHYSICS _motionState = NULL; -#endif // USE_BULLET_PHYSICS _updateFlags = 0; _changedOnServer = 0; initFromEntityItemID(entityItemID); @@ -118,11 +114,9 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert } EntityItem::~EntityItem() { -#ifdef USE_BULLET_PHYSICS // Make sure the EntityItem has been removed from the physics engine AND // that its _motionState has been destroyed BEFORE you get here. assert(_motionState == NULL); -#endif // USE_BULLET_PHYSICS } EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& params) const { @@ -519,7 +513,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY_SETTER(PROP_GRAVITY, glm::vec3, updateGravity); READ_ENTITY_PROPERTY(PROP_DAMPING, float, _damping); READ_ENTITY_PROPERTY_SETTER(PROP_LIFETIME, float, updateLifetime); - READ_ENTITY_PROPERTY_STRING(PROP_SCRIPT,setScript); + READ_ENTITY_PROPERTY_STRING(PROP_SCRIPT, updateScript); READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, _registrationPoint); READ_ENTITY_PROPERTY_SETTER(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity); READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, _angularDamping); @@ -797,23 +791,23 @@ bool EntityItem::setProperties(const EntityItemProperties& properties, bool forc } } - SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, setPositionInMeters); // this will call recalculate collision shape if needed - SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, setDimensionsInMeters); // NOTE: radius is obsolete - SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, setRotation); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(mass, setMass); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocity, setVelocityInMeters); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(gravity, setGravityInMeters); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, updatePositionInMeters); // this will call recalculate collision shape if needed + SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, updateDimensionsInMeters); // NOTE: radius is obsolete + SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, updateRotation); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(mass, updateMass); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocity, updateVelocityInMeters); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(gravity, updateGravityInMeters); SET_ENTITY_PROPERTY_FROM_PROPERTIES(damping, setDamping); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, setLifetime); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, setScript); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, updateLifetime); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, updateScript); SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, setRegistrationPoint); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularVelocity, setAngularVelocity); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularVelocity, updateAngularVelocity); SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularDamping, setAngularDamping); SET_ENTITY_PROPERTY_FROM_PROPERTIES(glowLevel, setGlowLevel); SET_ENTITY_PROPERTY_FROM_PROPERTIES(localRenderAlpha, setLocalRenderAlpha); SET_ENTITY_PROPERTY_FROM_PROPERTIES(visible, setVisible); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignoreForCollisions, setIgnoreForCollisions); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, setCollisionsWillMove); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignoreForCollisions, updateIgnoreForCollisions); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, updateCollisionsWillMove); SET_ENTITY_PROPERTY_FROM_PROPERTIES(locked, setLocked); SET_ENTITY_PROPERTY_FROM_PROPERTIES(userData, setUserData); @@ -985,7 +979,7 @@ void EntityItem::updateDimensions(const glm::vec3& value) { if (_dimensions != value) { _dimensions = value; recalculateCollisionShape(); - _updateFlags |= EntityItem::UPDATE_SHAPE; + _updateFlags |= (EntityItem::UPDATE_SHAPE | EntityItem::UPDATE_MASS); } } @@ -994,7 +988,7 @@ void EntityItem::updateDimensionsInMeters(const glm::vec3& value) { if (_dimensions != dimensions) { _dimensions = dimensions; recalculateCollisionShape(); - _updateFlags |= EntityItem::UPDATE_SHAPE; + _updateFlags |= (EntityItem::UPDATE_SHAPE | EntityItem::UPDATE_MASS); } } @@ -1031,7 +1025,7 @@ void EntityItem::updateVelocityInMeters(const glm::vec3& value) { void EntityItem::updateGravity(const glm::vec3& value) { if (_gravity != value) { _gravity = value; - _updateFlags |= EntityItem::UPDATE_VELOCITY; + _updateFlags |= EntityItem::UPDATE_GRAVITY; } } @@ -1039,7 +1033,7 @@ void EntityItem::updateGravityInMeters(const glm::vec3& value) { glm::vec3 gravity = value / (float) TREE_SCALE; if (_gravity != gravity) { _gravity = gravity; - _updateFlags |= EntityItem::UPDATE_VELOCITY; + _updateFlags |= EntityItem::UPDATE_GRAVITY; } } @@ -1071,12 +1065,17 @@ void EntityItem::updateLifetime(float value) { } } -#ifdef USE_BULLET_PHYSICS +void EntityItem::updateScript(const QString& value) { + if (_script != value) { + _script = value; + _updateFlags |= EntityItem::UPDATE_SCRIPT; + } +} + void EntityItem::destroyMotionState() { if (_motionState) { delete _motionState; _motionState = NULL; } } -#endif // USE_BULLET_PHYSICS diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 3c84fd193d..a32bd111d0 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -22,6 +22,7 @@ #include // for EncodeBitstreamParams class #include // for OctreeElement::AppendState #include +#include #include #include "EntityItemID.h" @@ -35,9 +36,7 @@ class EntityTreeElementExtraEncodeData; #define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0; #define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() { }; -#ifdef USE_BULLET_PHYSICS class EntityMotionState; -#endif // USE_BULLET_PHYSICS /// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available /// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate @@ -46,14 +45,21 @@ class EntityItem { public: enum EntityUpdateFlags { - UPDATE_POSITION = 0x0001, - UPDATE_VELOCITY = 0x0002, - UPDATE_MASS = 0x0004, - UPDATE_COLLISION_GROUP = 0x0008, - UPDATE_MOTION_TYPE = 0x0010, - UPDATE_SHAPE = 0x0020, - UPDATE_LIFETIME = 0x0040 - //UPDATE_APPEARANCE = 0x8000, + // flags for things that need to be relayed to physics engine + UPDATE_POSITION = PHYSICS_UPDATE_POSITION, //0x0001, + UPDATE_VELOCITY = PHYSICS_UPDATE_VELOCITY, //0x0002, + UPDATE_GRAVITY = PHYSICS_UPDATE_GRAVITY, //0x0004, + UPDATE_MASS = PHYSICS_UPDATE_MASS, //0x0008, + UPDATE_COLLISION_GROUP = PHYSICS_UPDATE_COLLISION_GROUP, //0x0010, + UPDATE_MOTION_TYPE = PHYSICS_UPDATE_MOTION_TYPE, //0x0020, + UPDATE_SHAPE = PHYSICS_UPDATE_SHAPE, //0x0040, + //... + // add new flags here in the middle + //... + // non-physics stuff + UPDATE_SCRIPT = 0x2000, + UPDATE_LIFETIME = 0x4000, + UPDATE_APPEARANCE = 0x8000 }; DONT_ALLOW_INSTANTIATION // This class can not be instantiated directly @@ -292,19 +298,18 @@ public: void updateIgnoreForCollisions(bool value); void updateCollisionsWillMove(bool value); void updateLifetime(float value); + void updateScript(const QString& value); uint32_t getUpdateFlags() const { return _updateFlags; } - void clearUpdateFlags() { _updateFlags = 0; } -#ifdef USE_BULLET_PHYSICS EntityMotionState* getMotionState() const { return _motionState; } virtual EntityMotionState* createMotionState() { return NULL; } void destroyMotionState(); -#endif // USE_BULLET_PHYSICS SimulationState getSimulationState() const { return _simulationState; } protected: friend class EntityTree; + void clearUpdateFlags() { _updateFlags = 0; } void setSimulationState(SimulationState state) { _simulationState = state; } virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init @@ -348,9 +353,7 @@ protected: void setRadius(float value); AACubeShape _collisionShape; -#ifdef USE_BULLET_PHYSICS EntityMotionState* _motionState; -#endif // USE_BULLET_PHYSICS SimulationState _simulationState; // only set by EntityTree // UpdateFlags are set whenever a property changes that requires the change to be communicated to other diff --git a/libraries/entities/src/EntityMotionState.cpp b/libraries/entities/src/EntityMotionState.cpp index be15f1cfe9..b27e372902 100644 --- a/libraries/entities/src/EntityMotionState.cpp +++ b/libraries/entities/src/EntityMotionState.cpp @@ -11,6 +11,7 @@ #ifdef USE_BULLET_PHYSICS #include +#endif // USE_BULLET_PHYSICS #include "EntityItem.h" #include "EntityMotionState.h" @@ -41,9 +42,10 @@ MotionType EntityMotionState::getMotionType() const { // HACK: According to EntityTree the meaning of "static" is "not moving" whereas // to Bullet it means "can't move". For demo purposes we temporarily interpret // Entity::weightless to mean Bullet::static. - return _entity->hasGravity() ? MOTION_TYPE_DYNAMIC : MOTION_TYPE_STATIC; + return _entity->getCollisionsWillMove() ? MOTION_TYPE_DYNAMIC : MOTION_TYPE_STATIC; } +#ifdef USE_BULLET_PHYSICS // This callback is invoked by the physics simulation in two cases: // (1) when the RigidBody is first added to the world // (irregardless of MotionType: STATIC, DYNAMIC, or KINEMATIC) @@ -64,34 +66,54 @@ void EntityMotionState::getWorldTransform (btTransform &worldTrans) const { // This callback is invoked by the physics simulation at the end of each simulation frame... // iff the corresponding RigidBody is DYNAMIC and has moved. void EntityMotionState::setWorldTransform (const btTransform &worldTrans) { - glm::vec3 pos; - bulletToGLM(worldTrans.getOrigin(), pos); - _entity->setPositionInMeters(pos + _cachedWorldOffset); + uint32_t updateFlags = _entity->getUpdateFlags(); + if (! (updateFlags & PHYSICS_UPDATE_POSITION)) { + glm::vec3 pos; + bulletToGLM(worldTrans.getOrigin(), pos); + _entity->setPositionInMeters(pos + _cachedWorldOffset); + + glm::quat rot; + bulletToGLM(worldTrans.getRotation(), rot); + _entity->setRotation(rot); + } - glm::quat rot; - bulletToGLM(worldTrans.getRotation(), rot); - _entity->setRotation(rot); - - glm::vec3 v; - getVelocity(v); - _entity->setVelocityInMeters(v); - getAngularVelocity(v); - _entity->setAngularVelocity(v); + if (! (updateFlags & PHYSICS_UPDATE_VELOCITY)) { + glm::vec3 v; + getVelocity(v); + _entity->setVelocityInMeters(v); + getAngularVelocity(v); + _entity->setAngularVelocity(v); + } } +#endif // USE_BULLET_PHYSICS void EntityMotionState::applyVelocities() const { +#ifdef USE_BULLET_PHYSICS if (_body) { setVelocity(_entity->getVelocityInMeters()); setAngularVelocity(_entity->getAngularVelocity()); + _body->setActivationState(ACTIVE_TAG); } +#endif // USE_BULLET_PHYSICS +} + +void EntityMotionState::applyGravity() const { +#ifdef USE_BULLET_PHYSICS + if (_body) { + setGravity(_entity->getGravityInMeters()); + _body->setActivationState(ACTIVE_TAG); + } +#endif // USE_BULLET_PHYSICS } void EntityMotionState::computeShapeInfo(ShapeInfo& info) { +#ifdef USE_BULLET_PHYSICS // HACK: for now we make everything a box. - glm::vec3 halfExtents = _entity->getDimensionsInMeters(); + glm::vec3 halfExtents = 0.5f * _entity->getDimensionsInMeters(); btVector3 bulletHalfExtents; glmToBullet(halfExtents, bulletHalfExtents); info.setBox(bulletHalfExtents); +#endif // USE_BULLET_PHYSICS } void EntityMotionState::getBoundingCubes(AACube& oldCube, AACube& newCube) { @@ -100,4 +122,3 @@ void EntityMotionState::getBoundingCubes(AACube& oldCube, AACube& newCube) { _oldBoundingCube = newCube; } -#endif // USE_BULLET_PHYSICS diff --git a/libraries/entities/src/EntityMotionState.h b/libraries/entities/src/EntityMotionState.h index 3b69abcd9d..ace42613dd 100644 --- a/libraries/entities/src/EntityMotionState.h +++ b/libraries/entities/src/EntityMotionState.h @@ -12,10 +12,16 @@ #ifndef hifi_EntityMotionState_h #define hifi_EntityMotionState_h -#ifdef USE_BULLET_PHYSICS - #include +#ifdef USE_BULLET_PHYSICS #include +#else // USE_BULLET_PHYSICS +// CustomMotionState stubbery +class CustomMotionState { +public: + bool _foo; +}; +#endif // USE_BULLET_PHYSICS class EntityItem; @@ -29,9 +35,12 @@ public: MotionType getMotionType() const; +#ifdef USE_BULLET_PHYSICS void getWorldTransform (btTransform &worldTrans) const; void setWorldTransform (const btTransform &worldTrans); +#endif // USE_BULLET_PHYSICS void applyVelocities() const; + void applyGravity() const; void computeShapeInfo(ShapeInfo& info); @@ -42,5 +51,4 @@ protected: AACube _oldBoundingCube; }; -#endif // USE_BULLET_PHYSICS #endif // hifi_EntityMotionState_h diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 2e697eebbb..9dbedf331f 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -77,12 +77,13 @@ EntityItem* EntityTree::getOrCreateEntityItem(const EntityItemID& entityID, cons } /// Adds a new entity item to the tree -void EntityTree::addEntityItem(EntityItem* entity) { +void EntityTree::addEntityInternal(EntityItem* entity) { // You should not call this on existing entities that are already part of the tree! Call updateEntity() EntityItemID entityID = entity->getEntityItemID(); EntityTreeElement* containingElement = getContainingElement(entityID); if (containingElement) { - qDebug() << "UNEXPECTED!!!! don't call addEntityItem() on existing EntityItems. entityID=" << entityID; + // should probably assert here + qDebug() << "UNEXPECTED!!!! don't call addEntityInternal() on existing EntityItems. entityID=" << entityID; return; } @@ -90,17 +91,39 @@ void EntityTree::addEntityItem(EntityItem* entity) { AddEntityOperator theOperator(this, entity); recurseTreeWithOperator(&theOperator); - updateEntityState(entity); + emitAddingEntity(entity); +} +void EntityTree::emitAddingEntity(EntityItem* entity) { + // add entity to proper internal lists + EntityItem::SimulationState newState = entity->computeSimulationState(); + switch (newState) { + case EntityItem::Moving: + _movingEntities.push_back(entity); + break; + + case EntityItem::Mortal: + _mortalEntities.push_back(entity); + break; + + default: + break; + } + entity->setSimulationState(newState); + entity->clearUpdateFlags(); + + // add entity to physics engine if (_physicsEngine && !entity->getMotionState()) { addEntityToPhysicsEngine(entity); } _isDirty = true; + + // finally emit the signal + emit addingEntity(entity->getEntityItemID()); } bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties) { - // You should not call this on existing entities that are already part of the tree! Call updateEntity() EntityTreeElement* containingElement = getContainingElement(entityID); if (!containingElement) { qDebug() << "UNEXPECTED!!!! EntityTree::updateEntity() entityID doesn't exist!!! entityID=" << entityID; @@ -127,20 +150,9 @@ bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProp } } } else { - // check to see if we need to simulate this entity... - QString entityScriptBefore = existingEntity->getScript(); - UpdateEntityOperator theOperator(this, containingElement, existingEntity, properties); recurseTreeWithOperator(&theOperator); _isDirty = true; - - updateEntityState(existingEntity); - - QString entityScriptAfter = existingEntity->getScript(); - if (entityScriptBefore != entityScriptAfter) { - emitEntityScriptChanging(entityID); // the entity script has changed - } - } containingElement = getContainingElement(entityID); @@ -177,8 +189,7 @@ EntityItem* EntityTree::addEntity(const EntityItemID& entityID, const EntityItem if (result) { // this does the actual adding of the entity - addEntityItem(result); - emitAddingEntity(entityID); + addEntityInternal(result); } return result; } @@ -204,14 +215,6 @@ void EntityTree::setPhysicsEngine(PhysicsEngine* engine) { _physicsEngine = engine; } -void EntityTree::emitAddingEntity(const EntityItemID& entityItemID) { - emit addingEntity(entityItemID); -} - -void EntityTree::emitEntityScriptChanging(const EntityItemID& entityItemID) { - emit entityScriptChanging(entityItemID); -} - void EntityTree::deleteEntity(const EntityItemID& entityID) { emit deletingEntity(entityID); @@ -619,13 +622,6 @@ void EntityTree::updateEntityState(EntityItem* entity) { break; } entity->setSimulationState(newState); - - if (_physicsEngine) { - EntityMotionState* motionState = entity->getMotionState(); - if (motionState) { - _physicsEngine->updateEntityMotionType(motionState); - } - } } } @@ -701,8 +697,15 @@ void EntityTree::updateChangedEntities(quint64 now, QSet& entities entitiesToDelete << thisEntity->getEntityItemID(); clearEntityState(thisEntity); } else { - // TODO: Andrew to push changes to physics engine (when we know how to sort the changes) + uint32_t flags = thisEntity->getUpdateFlags(); + if (flags & EntityItem::UPDATE_SCRIPT) { + emit entityScriptChanging(thisEntity->getEntityItemID()); + } + updateEntityState(thisEntity); + if (_physicsEngine && thisEntity->getMotionState()) { + _physicsEngine->updateEntity(thisEntity->getMotionState(), flags); + } } thisEntity->clearUpdateFlags(); } @@ -742,7 +745,7 @@ void EntityTree::updateMovingEntities(quint64 now, QSet& entitiesT qDebug() << "Entity " << thisEntity->getEntityItemID() << " moved out of domain bounds."; entitiesToDelete << thisEntity->getEntityItemID(); clearEntityState(thisEntity); - } else { + } else if (newCube != oldCube) { moveOperator.addEntityToMoveList(thisEntity, oldCube, newCube); updateEntityState(thisEntity); } diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 2323a1b612..1ef9b7e144 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -79,7 +79,8 @@ public: // The newer API... EntityItem* getOrCreateEntityItem(const EntityItemID& entityID, const EntityItemProperties& properties); - void addEntityItem(EntityItem* entityItem); + void addEntityInternal(EntityItem* entityItem); + void emitAddingEntity(EntityItem* entityItem); EntityItem* addEntity(const EntityItemID& entityID, const EntityItemProperties& properties); bool updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties); @@ -147,9 +148,6 @@ public: void trackDeletedEntity(const EntityItemID& entityID); - void emitAddingEntity(const EntityItemID& entityItemID); - void emitEntityScriptChanging(const EntityItemID& entityItemID); - QList& getMovingEntities() { return _movingEntities; } void setPhysicsEngine(PhysicsEngine* engine); diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index e94fb1718f..9d3e46400c 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -742,12 +742,13 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int // TODO: Do we need to also do this? // 3) remember the old cube for the entity so we can mark it as dirty if (entityItem) { - QString entityScriptBefore = entityItem->getScript(); + uint32_t oldFlags = entityItem->getUpdateFlags(); bool bestFitBefore = bestFitEntityBounds(entityItem); EntityTreeElement* currentContainingElement = _myTree->getContainingElement(entityItemID); bytesForThisEntity = entityItem->readEntityDataFromBuffer(dataAt, bytesLeftToRead, args); - if (entityItem->getUpdateFlags()) { + if (!oldFlags && entityItem->getUpdateFlags()) { + // this entity is not yet on the changed list and needs to be added _myTree->entityChanged(entityItem); } bool bestFitAfter = bestFitEntityBounds(entityItem); @@ -763,21 +764,14 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int } } } - - QString entityScriptAfter = entityItem->getScript(); - if (entityScriptBefore != entityScriptAfter) { - _myTree->emitEntityScriptChanging(entityItemID); // the entity script has changed - } - } else { entityItem = EntityTypes::constructEntityItem(dataAt, bytesLeftToRead, args); if (entityItem) { bytesForThisEntity = entityItem->readEntityDataFromBuffer(dataAt, bytesLeftToRead, args); addEntityItem(entityItem); // add this new entity to this elements entities + _myTree->emitAddingEntity(entityItem); entityItemID = entityItem->getEntityItemID(); _myTree->setContainingElement(entityItemID, this); - _myTree->updateEntityState(entityItem); - _myTree->emitAddingEntity(entityItemID); // we just added an entity } } // Move the buffer forward to read more entities diff --git a/libraries/entities/src/UpdateEntityOperator.cpp b/libraries/entities/src/UpdateEntityOperator.cpp index 9cee11d73c..0f51d76162 100644 --- a/libraries/entities/src/UpdateEntityOperator.cpp +++ b/libraries/entities/src/UpdateEntityOperator.cpp @@ -299,14 +299,25 @@ bool UpdateEntityOperator::preRecursion(OctreeElement* element) { } // set the entity properties and mark our element as changed. - _existingEntity->setProperties(_properties); + uint32_t oldUpdateFlags = _existingEntity->getUpdateFlags(); + bool somethingChanged = _existingEntity->setProperties(_properties); + uint32_t newUpdateFlags = _existingEntity->getUpdateFlags(); + if (somethingChanged && !oldUpdateFlags && _existingEntity->getUpdateFlags()) { + // this entity hasn't yet been added to changed list + _tree->entityChanged(_existingEntity); + } if (_wantDebug) { qDebug() << " *** set properties ***"; } } else { // otherwise, this is an add case. entityTreeElement->addEntityItem(_existingEntity); - _existingEntity->setProperties(_properties); // still need to update the properties! + uint32_t oldUpdateFlags = _existingEntity->getUpdateFlags(); + bool somethingChanged = _existingEntity->setProperties(_properties); // still need to update the properties! + if (somethingChanged && !oldUpdateFlags && _existingEntity->getUpdateFlags()) { + // this entity hasn't yet been added to changed list + _tree->entityChanged(_existingEntity); + } _tree->setContainingElement(_entityItemID, entityTreeElement); if (_wantDebug) { qDebug() << " *** ADDING ENTITY to ELEMENT and MAP and SETTING PROPERTIES ***"; diff --git a/libraries/physics/src/CustomMotionState.cpp b/libraries/physics/src/CustomMotionState.cpp index 743ed26614..20bd1aac69 100644 --- a/libraries/physics/src/CustomMotionState.cpp +++ b/libraries/physics/src/CustomMotionState.cpp @@ -72,6 +72,12 @@ void CustomMotionState::setAngularVelocity(const glm::vec3& velocity) const { _body->setAngularVelocity(v); } +void CustomMotionState::setGravity(const glm::vec3& gravity) const { + btVector3 g; + glmToBullet(gravity, g); + _body->setGravity(g); +} + void CustomMotionState::getVelocity(glm::vec3& velocityOut) const { bulletToGLM(_body->getLinearVelocity(), velocityOut); } diff --git a/libraries/physics/src/CustomMotionState.h b/libraries/physics/src/CustomMotionState.h index 7801625e09..d78aa66dfd 100644 --- a/libraries/physics/src/CustomMotionState.h +++ b/libraries/physics/src/CustomMotionState.h @@ -35,6 +35,7 @@ public: //virtual void setWorldTransform (const btTransform &worldTrans); virtual void applyVelocities() const = 0; + virtual void applyGravity() const = 0; virtual void computeShapeInfo(ShapeInfo& info) = 0; @@ -49,6 +50,7 @@ public: void setVelocity(const glm::vec3& velocity) const; void setAngularVelocity(const glm::vec3& velocity) const; + void setGravity(const glm::vec3& gravity) const; void getVelocity(glm::vec3& velocityOut) const; void getAngularVelocity(glm::vec3& angularVelocityOut) const; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 94d92f19f8..2e44d27f13 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -32,7 +32,7 @@ void PhysicsEngine::init() { // NOTE: we don't care about memory leaking groundShape and groundObject --> // they'll exist until the executable exits. const float halfSide = 200.0f; - const float halfHeight = 10.0f; + const float halfHeight = 1.0f; btCollisionShape* groundShape = new btBoxShape(btVector3(halfSide, halfHeight, halfSide)); btTransform groundTransform; @@ -40,6 +40,7 @@ void PhysicsEngine::init() { groundTransform.setOrigin(btVector3(halfSide, -halfHeight, halfSide)); btCollisionObject* groundObject = new btCollisionObject(); + groundObject->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT); groundObject->setCollisionShape(groundShape); groundObject->setWorldTransform(groundTransform); _dynamicsWorld->addCollisionObject(groundObject); @@ -131,7 +132,7 @@ bool PhysicsEngine::addEntity(CustomMotionState* motionState) { btVector3 inertia(0.0f, 0.0f, 0.0f); float mass = 0.0f; btRigidBody* body = NULL; - switch(motionState->_motionType) { + switch(motionState->getMotionType()) { case MOTION_TYPE_KINEMATIC: { body = new btRigidBody(mass, motionState, shape, inertia); body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); @@ -147,6 +148,7 @@ bool PhysicsEngine::addEntity(CustomMotionState* motionState) { body->updateInertiaTensor(); motionState->_body = body; motionState->applyVelocities(); + motionState->applyGravity(); break; } case MOTION_TYPE_STATIC: @@ -158,6 +160,8 @@ bool PhysicsEngine::addEntity(CustomMotionState* motionState) { break; } } + // wtf? + body->setFlags(BT_DISABLE_WORLD_GRAVITY); body->setRestitution(motionState->_restitution); body->setFriction(motionState->_friction); _dynamicsWorld->addRigidBody(body); @@ -182,60 +186,132 @@ bool PhysicsEngine::removeEntity(CustomMotionState* motionState) { return false; } -bool PhysicsEngine::updateEntityMotionType(CustomMotionState* motionState) { +bool PhysicsEngine::updateEntity(CustomMotionState* motionState, uint32_t flags) { btRigidBody* body = motionState->_body; if (!body) { return false; } - + + if (flags & PHYSICS_UPDATE_HARD) { + // a hard update requires the body be pulled out of physics engine, changed, then reinserted + updateEntityHard(body, motionState, flags); + } else if (flags & PHYSICS_UPDATE_EASY) { + // an easy update does not require that the body be pulled out of physics engine + updateEntityEasy(body, motionState, flags); + } + return true; +} + +// private +void PhysicsEngine::updateEntityHard(btRigidBody* body, CustomMotionState* motionState, uint32_t flags) { + MotionType newType = motionState->getMotionType(); MotionType oldType = MOTION_TYPE_DYNAMIC; if (body->isStaticObject()) { oldType = MOTION_TYPE_STATIC; } else if (body->isKinematicObject()) { oldType = MOTION_TYPE_KINEMATIC; } - MotionType newType = motionState->getMotionType(); - if (oldType != newType) { - // pull body out of physics engine - _dynamicsWorld->removeRigidBody(body); - // update various properties and flags - switch (newType) { - case MOTION_TYPE_KINEMATIC: { - body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); - body->setActivationState(DISABLE_DEACTIVATION); - body->updateInertiaTensor(); - break; - } - case MOTION_TYPE_DYNAMIC: { + // pull body out of physics engine + _dynamicsWorld->removeRigidBody(body); + + if (flags & PHYSICS_UPDATE_SHAPE) { + btCollisionShape* oldShape = body->getCollisionShape(); + ShapeInfo info; + motionState->computeShapeInfo(info); + btCollisionShape* newShape = _shapeManager.getShape(info); + if (newShape != oldShape) { + body->setCollisionShape(newShape); + _shapeManager.releaseShape(oldShape); + } else { + // whoops, shape hasn't changed after all so we must release the reference + // that was created when looking it up + _shapeManager.releaseShape(newShape); + } + // MASS bit should be set whenever SHAPE is set + assert(flags & PHYSICS_UPDATE_MASS); + } + bool easyUpdate = flags & PHYSICS_UPDATE_EASY; + if (easyUpdate) { + updateEntityEasy(body, motionState, flags); + } + + // update the motion parameters + switch (newType) { + case MOTION_TYPE_KINEMATIC: { + int collisionFlags = body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT; + collisionFlags &= ~(btCollisionObject::CF_STATIC_OBJECT); + body->setCollisionFlags(collisionFlags); + body->forceActivationState(DISABLE_DEACTIVATION); + + body->setMassProps(0.0f, btVector3(0.0f, 0.0f, 0.0f)); + body->updateInertiaTensor(); + break; + } + case MOTION_TYPE_DYNAMIC: { + int collisionFlags = body->getCollisionFlags() & ~(btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT); + body->setCollisionFlags(collisionFlags); + if (! (flags & PHYSICS_UPDATE_MASS)) { + // always update mass properties when going dynamic (unless it's already been done) btVector3 inertia(0.0f, 0.0f, 0.0f); float mass = motionState->getMass(); body->getCollisionShape()->calculateLocalInertia(mass, inertia); + body->setMassProps(mass, inertia); body->updateInertiaTensor(); - motionState->applyVelocities(); - break; - } - default: { - // MOTION_TYPE_STATIC - body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT); - body->updateInertiaTensor(); - break; } + bool forceActivation = true; + body->activate(forceActivation); + break; } + default: { + // MOTION_TYPE_STATIC + int collisionFlags = body->getCollisionFlags() | btCollisionObject::CF_STATIC_OBJECT; + collisionFlags &= ~(btCollisionObject::CF_KINEMATIC_OBJECT); + body->setCollisionFlags(collisionFlags); + body->forceActivationState(DISABLE_SIMULATION); - // reinsert body into physics engine - body->setRestitution(motionState->_restitution); - body->setFriction(motionState->_friction); - _dynamicsWorld->addRigidBody(body); - return true; + body->setMassProps(0.0f, btVector3(0.0f, 0.0f, 0.0f)); + body->updateInertiaTensor(); + + body->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f)); + body->setAngularVelocity(btVector3(0.0f, 0.0f, 0.0f)); + break; + } } - return false; + + // reinsert body into physics engine + _dynamicsWorld->addRigidBody(body); + + body->activate(); } -bool PhysicsEngine::updateEntityMassProperties(CustomMotionState* motionState, float mass, const glm::vec3& inertiaEigenValues) { - // TODO: implement this - assert(motionState); - return false; -} +// private +void PhysicsEngine::updateEntityEasy(btRigidBody* body, CustomMotionState* motionState, uint32_t flags) { + if (flags & PHYSICS_UPDATE_POSITION) { + btTransform transform; + motionState->getWorldTransform(transform); + body->setWorldTransform(transform); + } + if (flags & PHYSICS_UPDATE_VELOCITY) { + motionState->applyVelocities(); + motionState->applyGravity(); + } + body->setRestitution(motionState->_restitution); + body->setFriction(motionState->_friction); + + if (flags & PHYSICS_UPDATE_MASS) { + float mass = motionState->getMass(); + btVector3 inertia(0.0f, 0.0f, 0.0f); + body->getCollisionShape()->calculateLocalInertia(mass, inertia); + body->setMassProps(mass, inertia); + body->updateInertiaTensor(); + } + body->activate(); + + btVector3 v = body->getLinearVelocity(); + btVector3 g = body->getGravity(); + + // TODO: support collision groups +}; #endif // USE_BULLET_PHYSICS diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 222860e575..4daca423ad 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -12,6 +12,24 @@ #ifndef hifi_PhysicsEngine_h #define hifi_PhysicsEngine_h +enum PhysicsUpdateFlag { + PHYSICS_UPDATE_POSITION = 0x0001, + PHYSICS_UPDATE_VELOCITY = 0x0002, + PHYSICS_UPDATE_GRAVITY = 0x0004, + PHYSICS_UPDATE_MASS = 0x0008, + PHYSICS_UPDATE_COLLISION_GROUP = 0x0010, + PHYSICS_UPDATE_MOTION_TYPE = 0x0020, + PHYSICS_UPDATE_SHAPE = 0x0040 +}; + +typedef unsigned int uint32_t; + +// The update flags trigger two varieties of updates: "hard" which require the body to be pulled +// and re-added to the physics engine and "easy" which just updates the body properties. +const uint32_t PHYSICS_UPDATE_HARD = PHYSICS_UPDATE_MOTION_TYPE | PHYSICS_UPDATE_SHAPE; +const uint32_t PHYSICS_UPDATE_EASY = PHYSICS_UPDATE_POSITION | PHYSICS_UPDATE_VELOCITY | + PHYSICS_UPDATE_GRAVITY PHYSICS_UPDATE_MASS | PHYSICS_UPDATE_COLLISION_GROUP; + #ifdef USE_BULLET_PHYSICS #include @@ -68,12 +86,14 @@ public: bool removeEntity(CustomMotionState* motionState); /// \param motionState pointer to Entity's MotionState + /// \param flags set of bits indicating what categories of properties need to be updated /// \return true if entity updated - bool updateEntityMotionType(CustomMotionState* motionState); - - bool updateEntityMassProperties(CustomMotionState* motionState, float mass, const glm::vec3& inertiaEigenValues); + bool updateEntity(CustomMotionState* motionState, uint32_t flags); protected: + void updateEntityHard(btRigidBody* body, CustomMotionState* motionState, uint32_t flags); + void updateEntityEasy(btRigidBody* body, CustomMotionState* motionState, uint32_t flags); + btClock _clock; btDefaultCollisionConfiguration* _collisionConfig; btCollisionDispatcher* _collisionDispatcher;