// // EntityItem.h // libraries/entities/src // // Created by Brad Hefta-Gaub on 12/4/13. // Copyright 2013 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #ifndef hifi_EntityItem_h #define hifi_EntityItem_h #include #include #include // for Animation, AnimationCache, and AnimationPointer classes #include // for EncodeBitstreamParams class #include // for OctreeElement::AppendState #include #include "EntityItemID.h" #include "EntityItemProperties.h" #include "EntityTypes.h" class EntityTreeElement; 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: DONT_ALLOW_INSTANTIATION // This class can not be instantiated directly EntityItem(const EntityItemID& entityItemID); EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); virtual ~EntityItem() { } // ID and EntityItemID related methods 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; } bool isNewlyCreated() const { return _newlyCreated; } bool isKnownID() const { return getID() != UNKNOWN_ENTITY_ID; } EntityItemID getEntityItemID() const { return EntityItemID(getID(), getCreatorTokenID(), getID() != UNKNOWN_ENTITY_ID); } // methods for getting/setting all properties of an entity virtual EntityItemProperties getProperties() const; /// returns true is something changed virtual bool setProperties(const EntityItemProperties& properties, bool forceCopy = false); /// override this in your derived class if you'd like to be informed when something about the state of the entity /// has changed. This will be called with properties change or when new data is loaded from a stream virtual void somethingChangedNotification() { } quint64 getLastUpdated() const { return _lastUpdated; } /// Last simulated time of this entity universal usecs /// Last edited time of this entity universal usecs quint64 getLastEdited() const { return _lastEdited; } void setLastEdited(quint64 lastEdited) { _lastEdited = _lastUpdated = lastEdited; } float getEditedAgo() const /// Elapsed seconds since this entity was last edited { return (float)(usecTimestampNow() - getLastEdited()) / (float)USECS_PER_SECOND; } // TODO: eventually only include properties changed since the params.lastViewFrustumSent time virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const; virtual OctreeElement::AppendState appendEntityData(OctreePacketData* packetData, EncodeBitstreamParams& params, EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData) const; virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData, EntityPropertyFlags& requestedProperties, EntityPropertyFlags& propertyFlags, EntityPropertyFlags& propertiesDidntFit, int& propertyCount, OctreeElement::AppendState& appendState) const { /* do nothing*/ }; static EntityItemID readEntityItemIDFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); virtual int readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData) { return 0; } virtual void render(RenderArgs* args) { } // by default entity items don't know how to render static int expectedBytes(); static bool encodeEntityEditMessageDetails(PacketType command, EntityItemID id, const EntityItemProperties& details, unsigned char* bufferOut, int sizeIn, int& sizeOut); static void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, size_t length, int clockSkew); virtual void update(const quint64& now); typedef enum SimulationState_t { Static, Mortal, Changing, Moving } SimulationState; virtual SimulationState getSimulationState() const; 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) glm::vec3 getPositionInMeters() const { return _position * (float) TREE_SCALE; } /// get position in meters void setPosition(const glm::vec3& value) { _position = value; } /// set position in domain scale units (0.0 - 1.0) void setPositionInMeters(const glm::vec3& value) /// set position in meter units (0.0 - TREE_SCALE) { setPosition(glm::clamp(value / (float) TREE_SCALE, 0.0f, 1.0f)); } static const glm::vec3 DEFAULT_DIMENSIONS; const glm::vec3& getDimensions() const { return _dimensions; } /// get dimensions in domain scale units (0.0 - 1.0) glm::vec3 getDimensionsInMeters() const { return _dimensions * (float) TREE_SCALE; } /// get dimensions in meters float getDistanceToBottomOfEntity() const; /// get the distance from the position of the entity to its "bottom" in y axis float getLargestDimension() const { return glm::length(_dimensions); } /// get the largest possible dimension /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately void setDimensions(const glm::vec3& value) { _dimensions = value; } /// set dimensions in meter units (0.0 - TREE_SCALE) this will also reset radius appropriately void setDimensionsInMeters(const glm::vec3& value) { setDimensions(value / (float) TREE_SCALE); } static const glm::quat DEFAULT_ROTATION; const glm::quat& getRotation() const { return _rotation; } void setRotation(const glm::quat& rotation) { _rotation = rotation; } static const float DEFAULT_GLOW_LEVEL; float getGlowLevel() const { return _glowLevel; } void setGlowLevel(float glowLevel) { _glowLevel = glowLevel; } static const float DEFAULT_MASS; float getMass() const { return _mass; } void setMass(float value) { _mass = value; } static const glm::vec3 DEFAULT_VELOCITY; static const glm::vec3 NO_VELOCITY; static const float EPSILON_VELOCITY_LENGTH; const glm::vec3 getVelocity() const { return _velocity; } /// velocity in domain scale units (0.0-1.0) per second glm::vec3 getVelocityInMeters() const { return _velocity * (float) TREE_SCALE; } /// get velocity in meters void setVelocity(const glm::vec3& value) { _velocity = value; } /// velocity in domain scale units (0.0-1.0) per second void setVelocityInMeters(const glm::vec3& value) { _velocity = value / (float) TREE_SCALE; } /// velocity in meters bool hasVelocity() const { return _velocity != NO_VELOCITY; } static const glm::vec3 DEFAULT_GRAVITY; static const glm::vec3 REGULAR_GRAVITY; static const glm::vec3 NO_GRAVITY; const glm::vec3& getGravity() const { return _gravity; } /// gravity in domain scale units (0.0-1.0) per second squared glm::vec3 getGravityInMeters() const { return _gravity * (float) TREE_SCALE; } /// get gravity in meters void setGravity(const glm::vec3& value) { _gravity = value; } /// gravity in domain scale units (0.0-1.0) per second squared void setGravityInMeters(const glm::vec3& value) { _gravity = value / (float) TREE_SCALE; } /// gravity in meters bool hasGravity() const { return _gravity != NO_GRAVITY; } // TODO: this should eventually be updated to support resting on collisions with other surfaces bool isRestingOnSurface() const; static const float DEFAULT_DAMPING; float getDamping() const { return _damping; } void setDamping(float value) { _damping = value; } // lifetime related properties. static const float IMMORTAL; /// special lifetime which means the entity lives for ever. default lifetime static const float DEFAULT_LIFETIME; float getLifetime() const { return _lifetime; } /// get the lifetime in seconds for the entity void setLifetime(float value) { _lifetime = value; } /// set the lifetime in seconds for the entity /// is this entity immortal, in that it has no lifetime set, and will exist until manually deleted bool isImmortal() const { return _lifetime == IMMORTAL; } /// is this entity mortal, in that it has a lifetime set, and will automatically be deleted when that lifetime expires bool isMortal() const { return _lifetime != IMMORTAL; } /// age of this entity in seconds float getAge() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; } bool lifetimeHasExpired() const; // position, size, and bounds related helpers float getSize() const; /// get maximum dimension in domain scale units (0.0 - 1.0) glm::vec3 getMinimumPoint() const; glm::vec3 getMaximumPoint() const; AACube getAACube() const { return AACube(getMinimumPoint(), getSize()); } /// AACube in domain scale units (0.0 - 1.0) static const QString DEFAULT_SCRIPT; const QString& getScript() const { return _script; } void setScript(const QString& value) { _script = value; } static const glm::vec3 DEFAULT_REGISTRATION_POINT; const glm::vec3& getRegistrationPoint() const { return _registrationPoint; } /// registration point as ratio of entity void setRegistrationPoint(const glm::vec3& value) { _registrationPoint = value; } /// registration point as ratio of entity static const glm::vec3 NO_ANGULAR_VELOCITY; static const glm::vec3 DEFAULT_ANGULAR_VELOCITY; const glm::vec3& getAngularVelocity() const { return _angularVelocity; } void setAngularVelocity(const glm::vec3& value) { _angularVelocity = value; } bool hasAngularVelocity() const { return _angularVelocity != NO_ANGULAR_VELOCITY; } static const float DEFAULT_ANGULAR_DAMPING; float getAngularDamping() const { return _angularDamping; } void setAngularDamping(float value) { _angularDamping = value; } static const bool DEFAULT_VISIBLE; bool getVisible() const { return _visible; } void setVisible(bool value) { _visible = value; } bool isVisible() const { return _visible; } bool isInvisible() const { return !_visible; } protected: virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init EntityTypes::EntityType _type; QUuid _id; uint32_t _creatorTokenID; bool _newlyCreated; quint64 _lastUpdated; quint64 _lastEdited; // this is the last official local or remote edit time quint64 _lastEditedFromRemote; // this is the last time we received and edit from the server quint64 _lastEditedFromRemoteInRemoteTime; // time in server time space the last time we received and edit from the server quint64 _created; glm::vec3 _position; glm::vec3 _dimensions; glm::quat _rotation; float _glowLevel; float _mass; glm::vec3 _velocity; glm::vec3 _gravity; float _damping; float _lifetime; QString _script; glm::vec3 _registrationPoint; glm::vec3 _angularVelocity; float _angularDamping; bool _visible; // NOTE: Radius support is obsolete, but these private helper functions are available for this class to // parse old data streams /// 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); /// set radius in meter units (0.0 - TREE_SCALE), this will also reset dimensions to be equal for each axis void setRadiusInMeters(float value) { float valueInTreeUnits = value / (float) TREE_SCALE; setRadius(valueInTreeUnits); } private: // TODO: We need to get rid of these users of getRadius()... but for now, we'll make them friends // so they can be the only ones accessing this method. friend EntityTreeElement; float getRadius() const; }; #endif // hifi_EntityItem_h