diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index d0fafa06b1..98dda6f33f 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -90,6 +90,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) { _lastEditedFromRemoteInRemoteTime = 0; _lastUpdated = 0; _created = 0; + _updateFlags = 0; _changedOnServer = 0; initFromEntityItemID(entityItemID); _simulationState = EntityItem::Static; @@ -102,6 +103,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert _lastEditedFromRemoteInRemoteTime = 0; _lastUpdated = 0; _created = properties.getCreated(); + _updateFlags = 0; _changedOnServer = 0; initFromEntityItemID(entityItemID); setProperties(properties, true); // force copy @@ -465,7 +467,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef dataAt += propertyFlags.getEncodedLength(); bytesRead += propertyFlags.getEncodedLength(); - READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, _position); + READ_ENTITY_PROPERTY_SETTER(PROP_POSITION, glm::vec3, updatePosition); // Old bitstreams had PROP_RADIUS, new bitstreams have PROP_DIMENSIONS if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_DIMENSIONS) { @@ -484,7 +486,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef } } else { - READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, _dimensions); + READ_ENTITY_PROPERTY_SETTER(PROP_DIMENSIONS, glm::vec3, setDimensions); if (wantDebug) { qDebug() << " readEntityDataFromBuffer() NEW FORMAT... look for PROP_DIMENSIONS"; } @@ -494,19 +496,19 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef qDebug() << " readEntityDataFromBuffer() _dimensions:" << getDimensionsInMeters() << " in meters"; } - READ_ENTITY_PROPERTY_QUAT(PROP_ROTATION, _rotation); - READ_ENTITY_PROPERTY(PROP_MASS, float, _mass); - READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, _velocity); - READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, _gravity); + READ_ENTITY_PROPERTY_QUAT_SETTER(PROP_ROTATION, updateRotation); + READ_ENTITY_PROPERTY_SETTER(PROP_MASS, float, updateMass); + READ_ENTITY_PROPERTY_SETTER(PROP_VELOCITY, glm::vec3, updateVelocity); + READ_ENTITY_PROPERTY_SETTER(PROP_GRAVITY, glm::vec3, updateGravity); READ_ENTITY_PROPERTY(PROP_DAMPING, float, _damping); - READ_ENTITY_PROPERTY(PROP_LIFETIME, float, _lifetime); + READ_ENTITY_PROPERTY_SETTER(PROP_LIFETIME, float, updateLifetime); READ_ENTITY_PROPERTY_STRING(PROP_SCRIPT,setScript); READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, _registrationPoint); - READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, _angularVelocity); + READ_ENTITY_PROPERTY_SETTER(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity); READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, _angularDamping); READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, _visible); - READ_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, bool, _ignoreForCollisions); - READ_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, bool, _collisionsWillMove); + READ_ENTITY_PROPERTY_SETTER(PROP_IGNORE_FOR_COLLISIONS, bool, updateIgnoreForCollisions); + READ_ENTITY_PROPERTY_SETTER(PROP_COLLISIONS_WILL_MOVE, bool, updateCollisionsWillMove); READ_ENTITY_PROPERTY(PROP_LOCKED, bool, _locked); READ_ENTITY_PROPERTY_STRING(PROP_USER_DATA,setUserData); @@ -731,11 +733,6 @@ bool EntityItem::lifetimeHasExpired() const { return isMortal() && (getAge() > getLifetime()); } - -void EntityItem::copyChangedProperties(const EntityItem& other) { - *this = other; -} - EntityItemProperties EntityItem::getProperties() const { EntityItemProperties properties; properties._id = getID(); @@ -947,4 +944,111 @@ void EntityItem::recalculateCollisionShape() { _collisionShape.setScale(entityAACube.getScale()); } +void EntityItem::updatePosition(const glm::vec3& value) { + if (_position != value) { + _position = value; + recalculateCollisionShape(); + _updateFlags |= EntityItem::UPDATE_POSITION; + } +} + +void EntityItem::updatePositionInMeters(const glm::vec3& value) { + glm::vec3 position = glm::clamp(value / (float) TREE_SCALE, 0.0f, 1.0f); + if (_position != position) { + _position = position; + recalculateCollisionShape(); + _updateFlags |= EntityItem::UPDATE_POSITION; + } +} + +void EntityItem::updateDimensions(const glm::vec3& value) { + if (_dimensions != value) { + _dimensions = value; + recalculateCollisionShape(); + _updateFlags |= EntityItem::UPDATE_SHAPE; + } +} + +void EntityItem::updateDimensionsInMeters(const glm::vec3& value) { + glm::vec3 dimensions = value / (float) TREE_SCALE; + if (_dimensions != dimensions) { + _dimensions = dimensions; + recalculateCollisionShape(); + _updateFlags |= EntityItem::UPDATE_SHAPE; + } +} + +void EntityItem::updateRotation(const glm::quat& rotation) { + if (_rotation != rotation) { + _rotation = rotation; + recalculateCollisionShape(); + _updateFlags |= EntityItem::UPDATE_POSITION; + } +} + +void EntityItem::updateMass(float value) { + if (_mass != value) { + _mass = value; + _updateFlags |= EntityItem::UPDATE_MASS; + } +} + +void EntityItem::updateVelocity(const glm::vec3& value) { + if (_velocity != value) { + _velocity = value; + _updateFlags |= EntityItem::UPDATE_VELOCITY; + } +} + +void EntityItem::updateVelocityInMeters(const glm::vec3& value) { + glm::vec3 velocity = value / (float) TREE_SCALE; + if (_velocity != velocity) { + _velocity = velocity; + _updateFlags |= EntityItem::UPDATE_VELOCITY; + } +} + +void EntityItem::updateGravity(const glm::vec3& value) { + if (_gravity != value) { + _gravity = value; + _updateFlags |= EntityItem::UPDATE_VELOCITY; + } +} + +void EntityItem::updateGravityInMeters(const glm::vec3& value) { + glm::vec3 gravity = value / (float) TREE_SCALE; + if (_gravity != gravity) { + _gravity = gravity; + _updateFlags |= EntityItem::UPDATE_VELOCITY; + } +} + +void EntityItem::updateAngularVelocity(const glm::vec3& value) { + if (_angularVelocity != value) { + _angularVelocity = value; + _updateFlags |= EntityItem::UPDATE_VELOCITY; + } +} + +void EntityItem::updateIgnoreForCollisions(bool value) { + if (_ignoreForCollisions != value) { + _ignoreForCollisions = value; + _updateFlags |= EntityItem::UPDATE_COLLISION_GROUP; + } +} + +void EntityItem::updateCollisionsWillMove(bool value) { + if (_collisionsWillMove != value) { + _collisionsWillMove = value; + _updateFlags |= EntityItem::UPDATE_MOTION_TYPE; + } +} + +void EntityItem::updateLifetime(float value) { + if (_lifetime != value) { + _lifetime = value; + _updateFlags |= EntityItem::UPDATE_LIFETIME; + } +} + diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index d57f547cc5..3f63c96c4e 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -35,13 +35,23 @@ class EntityTreeElementExtraEncodeData; #define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0; #define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() { }; - /// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available /// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate /// one directly, instead you must only construct one of it's derived classes with additional features. 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, + }; + DONT_ALLOW_INSTANTIATION // This class can not be instantiated directly EntityItem(const EntityItemID& entityItemID); @@ -125,9 +135,6 @@ public: virtual void debugDump() const; - // similar to assignment/copy, but it handles keeping lifetime accurate - void copyChangedProperties(const EntityItem& other); - // attributes applicable to all entity types EntityTypes::EntityType getType() const { return _type; } const glm::vec3& getPosition() const { return _position; } /// get position in domain scale units (0.0 - 1.0) @@ -266,6 +273,30 @@ public: virtual const Shape& getCollisionShapeInMeters() const { return _collisionShape; } virtual bool contains(const glm::vec3& point) const { return getAABox().contains(point); } + // updateFoo() methods to be used when changes need to be accumulated in the _updateFlags + void updatePosition(const glm::vec3& value); + void updatePositionInMeters(const glm::vec3& value); + void updateDimensions(const glm::vec3& value); + void updateDimensionsInMeters(const glm::vec3& value); + void updateRotation(const glm::quat& rotation); + void updateMass(float value); + void updateVelocity(const glm::vec3& value); + void updateVelocityInMeters(const glm::vec3& value); + void updateGravity(const glm::vec3& value); + void updateGravityInMeters(const glm::vec3& value); + void updateAngularVelocity(const glm::vec3& value); + void updateIgnoreForCollisions(bool value); + void updateCollisionsWillMove(bool value); + void updateLifetime(float 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: @@ -314,6 +345,10 @@ protected: AACubeShape _collisionShape; SimulationState _simulationState; // only set by EntityTree + + // UpdateFlags are set whenever a property changes that requires the change to be communicated to other + // data structures. It is the responsibility of the EntityTree to relay changes entity and clear flags. + uint32_t _updateFlags; }; diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index 8ad444a975..3288e56a3d 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -63,6 +63,17 @@ } \ } +#define READ_ENTITY_PROPERTY_QUAT_SETTER(P,M) \ + if (propertyFlags.getHasProperty(P)) { \ + glm::quat fromBuffer; \ + int bytes = unpackOrientationQuatFromBytes(dataAt, fromBuffer); \ + dataAt += bytes; \ + bytesRead += bytes; \ + if (overwriteLocalData) { \ + M(fromBuffer); \ + } \ + } + #define READ_ENTITY_PROPERTY_STRING(P,O) \ if (propertyFlags.getHasProperty(P)) { \ uint16_t length; \ diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index a0b2d6f9c3..b25b153f44 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -657,12 +657,13 @@ void EntityTree::updateChangedEntities(quint64 now, QSet& entities foreach (EntityItem* thisEntity, _changedEntities) { // check to see if the lifetime has expired, for immortal entities this is always false if (thisEntity->lifetimeHasExpired()) { - qDebug() << "Lifetime has expired for thisEntity:" << thisEntity->getEntityItemID(); + qDebug() << "Lifetime has expired for entity:" << thisEntity->getEntityItemID(); entitiesToDelete << thisEntity->getEntityItemID(); clearEntityState(thisEntity); } else { updateEntityState(thisEntity); } + thisEntity->clearUpdateFlags(); } _changedEntities.clear(); } diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 7d4d95bf94..2c189846eb 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -739,8 +739,9 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int EntityTreeElement* currentContainingElement = _myTree->getContainingElement(entityItemID); bytesForThisEntity = entityItem->readEntityDataFromBuffer(dataAt, bytesLeftToRead, args); - // TODO: Andrew to only set changed if something has actually changed - _myTree->entityChanged(entityItem); + if (entityItem->getUpdateFlags()) { + _myTree->entityChanged(entityItem); + } bool bestFitAfter = bestFitEntityBounds(entityItem); if (bestFitBefore != bestFitAfter) {