more work on virtual entities

This commit is contained in:
ZappoMan 2014-08-04 16:18:24 -07:00
parent 3a8c5018ee
commit 273853ef24
13 changed files with 1018 additions and 409 deletions

View file

@ -1170,7 +1170,7 @@ function Tooltip() {
text += "Model URL: " + properties.modelURL + "\n"
text += "Animation URL: " + properties.animationURL + "\n"
text += "Animation is playing: " + properties.animationIsPlaying + "\n"
if (properties.sittingPoints.length > 0) {
if (properties.sittingPoints && properties.sittingPoints.length > 0) {
text += properties.sittingPoints.length + " Sitting points: "
for (var i = 0; i < properties.sittingPoints.length; ++i) {
text += properties.sittingPoints[i].name + " "

View file

@ -83,8 +83,8 @@ const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(const EntityItem& en
Model* EntityTreeRenderer::getModel(const EntityItem& entityItem) {
Model* model = NULL;
#if 0 //def HIDE_SUBCLASS_METHODS
if (!entityItem.getModelURL().isEmpty()) {
#ifdef HIDE_SUBCLASS_METHODS
if (entityItem.isKnownID()) {
if (_knownEntityItemModels.find(entityItem.getID()) != _knownEntityItemModels.end()) {
model = _knownEntityItemModels[entityItem.getID()];
@ -136,8 +136,8 @@ Model* EntityTreeRenderer::getModel(const EntityItem& entityItem) {
_unknownEntityItemModels[entityItem.getCreatorTokenID()] = model;
}
}
#endif
}
#endif
return model;
}
@ -247,7 +247,7 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
float radius = entityItem->getRadius() * (float)TREE_SCALE;
float size = entityItem->getSize() * (float)TREE_SCALE;
#ifdef HIDE_SUBCLASS_METHODS
#if 0 //def HIDE_SUBCLASS_METHODS
bool drawAsModel = entityItem->hasModel();
#else
bool drawAsModel = false;
@ -256,7 +256,7 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
args->_itemsRendered++;
if (drawAsModel) {
#ifdef HIDE_SUBCLASS_METHODS
#if 0 //def HIDE_SUBCLASS_METHODS
glPushMatrix();
{
const float alpha = 1.0f;

View file

@ -29,15 +29,6 @@
#include "EntityItem.h"
#include "EntityTree.h"
EntityItem::EntityItem() {
qDebug() << "EntityItem::EntityItem()....";
_type = EntityTypes::Base;
_lastEdited = 0;
_lastUpdated = 0;
rgbColor noColor = { 0, 0, 0 };
init(glm::vec3(0,0,0), 0, noColor, NEW_ENTITY);
}
void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) {
_id = entityItemID.id;
_creatorTokenID = entityItemID.creatorTokenID;
@ -51,29 +42,6 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) {
_radius = 0;
_rotation = ENTITY_DEFAULT_ROTATION;
_shouldBeDeleted = false;
#ifdef HIDE_SUBCLASS_METHODS
rgbColor noColor = { 0, 0, 0 };
memcpy(_color, noColor, sizeof(_color));
_modelURL = ENTITY_DEFAULT_MODEL_URL;
// animation related
_animationURL = ENTITY_DEFAULT_ANIMATION_URL;
_animationIsPlaying = false;
_animationFrameIndex = 0.0f;
_animationFPS = ENTITY_DEFAULT_ANIMATION_FPS;
_glowLevel = 0.0f;
_jointMappingCompleted = false;
_lastAnimated = 0;
#endif
}
EntityItem::EntityItem(const EntityItemID& entityItemID) {
//qDebug() << "EntityItem::EntityItem(const EntityItemID& entityItemID)....";
_type = EntityTypes::Base;
initFromEntityItemID(entityItemID);
}
EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) {
@ -82,51 +50,12 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert
_lastEdited = 0;
_lastUpdated = 0;
initFromEntityItemID(entityItemID);
//qDebug() << "EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties).... _lastEdited=" << _lastEdited;
setProperties(properties, true); // force copy
//qDebug() << "EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties).... after setProperties() _lastEdited=" << _lastEdited;
}
EntityItem::~EntityItem() {
}
void EntityItem::init(glm::vec3 position, float radius, rgbColor color, uint32_t id) {
// TODO: is this what we want???
/*
if (id == NEW_ENTITY) {
_id = _nextID;
_nextID++;
} else {
_id = id;
}
*/
_id = id;
quint64 now = usecTimestampNow();
_lastEdited = now;
_lastUpdated = now;
_position = position;
_radius = radius;
_rotation = ENTITY_DEFAULT_ROTATION;
_shouldBeDeleted = false;
#ifdef HIDE_SUBCLASS_METHODS
memcpy(_color, color, sizeof(_color));
_modelURL = ENTITY_DEFAULT_MODEL_URL;
// animation related
_animationURL = ENTITY_DEFAULT_ANIMATION_URL;
_animationIsPlaying = false;
_animationFrameIndex = 0.0f;
_animationFPS = ENTITY_DEFAULT_ANIMATION_FPS;
_glowLevel = 0.0f;
_jointMappingCompleted = false;
_lastAnimated = now;
#endif
}
OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData) const {
@ -292,7 +221,7 @@ qDebug() << "EntityItem::appendEntityData() ... lastEdited=" << lastEdited;
// script would go here...
#ifdef HIDE_SUBCLASS_METHODS
#if 0 // def HIDE_SUBCLASS_METHODS
// PROP_COLOR
if (requestedProperties.getHasProperty(PROP_COLOR)) {
//qDebug() << "PROP_COLOR requested...";
@ -472,103 +401,6 @@ int EntityItem::expectedBytes() {
return expectedBytes;
}
int EntityItem::oldVersionReadEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) {
int bytesRead = 0;
if (bytesLeftToRead >= expectedBytes()) {
int clockSkew = args.sourceNode ? args.sourceNode->getClockSkewUsec() : 0;
const unsigned char* dataAt = data;
// id
memcpy(&_id, dataAt, sizeof(_id));
dataAt += sizeof(_id);
bytesRead += sizeof(_id);
// _lastUpdated
memcpy(&_lastUpdated, dataAt, sizeof(_lastUpdated));
dataAt += sizeof(_lastUpdated);
bytesRead += sizeof(_lastUpdated);
_lastUpdated -= clockSkew;
// _lastEdited
memcpy(&_lastEdited, dataAt, sizeof(_lastEdited));
dataAt += sizeof(_lastEdited);
bytesRead += sizeof(_lastEdited);
_lastEdited -= clockSkew;
// radius
memcpy(&_radius, dataAt, sizeof(_radius));
dataAt += sizeof(_radius);
bytesRead += sizeof(_radius);
// position
memcpy(&_position, dataAt, sizeof(_position));
dataAt += sizeof(_position);
bytesRead += sizeof(_position);
// color
#ifdef HIDE_SUBCLASS_METHODS
memcpy(_color, dataAt, sizeof(_color));
dataAt += sizeof(_color);
bytesRead += sizeof(_color);
#endif
// shouldBeDeleted
memcpy(&_shouldBeDeleted, dataAt, sizeof(_shouldBeDeleted));
dataAt += sizeof(_shouldBeDeleted);
bytesRead += sizeof(_shouldBeDeleted);
// modelURL
uint16_t modelURLLength;
memcpy(&modelURLLength, dataAt, sizeof(modelURLLength));
dataAt += sizeof(modelURLLength);
bytesRead += sizeof(modelURLLength);
QString modelURLString((const char*)dataAt);
#ifdef HIDE_SUBCLASS_METHODS
setModelURL(modelURLString);
#endif
dataAt += modelURLLength;
bytesRead += modelURLLength;
// rotation
int bytes = unpackOrientationQuatFromBytes(dataAt, _rotation);
dataAt += bytes;
bytesRead += bytes;
if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ANIMATION) {
// animationURL
uint16_t animationURLLength;
memcpy(&animationURLLength, dataAt, sizeof(animationURLLength));
dataAt += sizeof(animationURLLength);
bytesRead += sizeof(animationURLLength);
QString animationURLString((const char*)dataAt);
#ifdef HIDE_SUBCLASS_METHODS
setAnimationURL(animationURLString);
#endif
dataAt += animationURLLength;
bytesRead += animationURLLength;
#ifdef HIDE_SUBCLASS_METHODS
// animationIsPlaying
memcpy(&_animationIsPlaying, dataAt, sizeof(_animationIsPlaying));
dataAt += sizeof(_animationIsPlaying);
bytesRead += sizeof(_animationIsPlaying);
// animationFrameIndex
memcpy(&_animationFrameIndex, dataAt, sizeof(_animationFrameIndex));
dataAt += sizeof(_animationFrameIndex);
bytesRead += sizeof(_animationFrameIndex);
// animationFPS
memcpy(&_animationFPS, dataAt, sizeof(_animationFPS));
dataAt += sizeof(_animationFPS);
bytesRead += sizeof(_animationFPS);
#endif
}
}
return bytesRead;
}
EntityItemID EntityItem::readEntityItemIDFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args) {
@ -588,7 +420,8 @@ EntityItemID EntityItem::readEntityItemIDFromBuffer(const unsigned char* data, i
int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) {
if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU) {
return oldVersionReadEntityDataFromBuffer(data, bytesLeftToRead, args);
qDebug() << "EntityItem::readEntityDataFromBuffer()... ERROR CASE...args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU";
return 0;
}
// Header bytes
@ -725,7 +558,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
// script would go here...
#ifdef HIDE_SUBCLASS_METHODS
#if 0 //def HIDE_SUBCLASS_METHODS
// PROP_COLOR
if (propertyFlags.getHasProperty(PROP_COLOR)) {
rgbColor color;
@ -811,7 +644,7 @@ void EntityItem::debugDump() const {
qDebug(" position:%f,%f,%f", _position.x, _position.y, _position.z);
qDebug(" radius:%f", getRadius());
#ifdef HIDE_SUBCLASS_METHODS
#if 0 //def HIDE_SUBCLASS_METHODS
qDebug(" color:%d,%d,%d", _color[0], _color[1], _color[2]);
if (!getModelURL().isEmpty()) {
qDebug() << " modelURL:" << qPrintable(getModelURL());
@ -1027,7 +860,11 @@ qDebug() << "EntityItem::encodeEntityEditMessageDetails() ... lastEdited=" << la
// script would go here...
#if 0 // def HIDE_SUBCLASS_METHODS
//#if 0 // def HIDE_SUBCLASS_METHODS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// TODO: move these??? how to handle this for subclass properties???
// PROP_COLOR
if (requestedProperties.getHasProperty(PROP_COLOR)) {
//qDebug() << "PROP_COLOR requested...";
@ -1068,6 +905,8 @@ qDebug() << "EntityItem::encodeEntityEditMessageDetails() ... lastEdited=" << la
propertiesDidntFit -= PROP_MODEL_URL;
}
qDebug() << "EntityItem EntityItem::encodeEntityEditMessageDetails() model URL=" << properties.getModelURL();
// PROP_ANIMATION_URL
if (requestedProperties.getHasProperty(PROP_ANIMATION_URL)) {
//qDebug() << "PROP_ANIMATION_URL requested...";
@ -1148,7 +987,8 @@ qDebug() << "EntityItem::encodeEntityEditMessageDetails() ... lastEdited=" << la
propertiesDidntFit -= PROP_ANIMATION_PLAYING;
}
#endif //def HIDE_SUBCLASS_METHODS
//#endif //def HIDE_SUBCLASS_METHODS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}
if (propertyCount > 0) {
@ -1242,7 +1082,7 @@ void EntityItem::adjustEditPacketForClockSkew(unsigned char* editPacketBuffer, s
}
}
#ifdef HIDE_SUBCLASS_METHODS
#if 0 //def HIDE_SUBCLASS_METHODS
QMap<QString, AnimationPointer> EntityItem::_loadedAnimations; // TODO: improve cleanup by leveraging the AnimationPointer(s)
AnimationCache EntityItem::_animationCache;
@ -1327,7 +1167,7 @@ void EntityItem::update(const quint64& updateTime) {
quint64 now = usecTimestampNow();
// only advance the frame index if we're playing
#ifdef HIDE_SUBCLASS_METHODS
#if 0 //def HIDE_SUBCLASS_METHODS
if (getAnimationIsPlaying()) {
float deltaTime = (float)(now - _lastAnimated) / (float)USECS_PER_SECOND;
@ -1375,25 +1215,6 @@ EntityItemProperties EntityItem::getProperties() const {
properties._radiusChanged = false;
properties._rotationChanged = false;
properties._shouldBeDeletedChanged = false;
#if 0 //def HIDE_SUBCLASS_METHODS
properties._color = getXColor();
properties._modelURL = getModelURL();
properties._animationURL = getAnimationURL();
properties._animationIsPlaying = getAnimationIsPlaying();
properties._animationFrameIndex = getAnimationFrameIndex();
properties._animationFPS = getAnimationFPS();
properties._glowLevel = getGlowLevel();
properties._sittingPoints = getSittingPoints(); // sitting support
properties._colorChanged = false;
properties._modelURLChanged = false;
properties._animationURLChanged = false;
properties._animationIsPlayingChanged = false;
properties._animationFrameIndexChanged = false;
properties._animationFPSChanged = false;
properties._glowLevelChanged = false;
#endif
properties._defaultSettings = false;
@ -1422,44 +1243,6 @@ void EntityItem::setProperties(const EntityItemProperties& properties, bool forc
somethingChanged = true;
}
#if 0 // def HIDE_SUBCLASS_METHODS
if (properties._colorChanged || forceCopy) {
setColor(properties._color);
somethingChanged = true;
}
if (properties._modelURLChanged || forceCopy) {
setModelURL(properties._modelURL);
somethingChanged = true;
}
if (properties._animationURLChanged || forceCopy) {
setAnimationURL(properties._animationURL);
somethingChanged = true;
}
if (properties._animationIsPlayingChanged || forceCopy) {
setAnimationIsPlaying(properties._animationIsPlaying);
somethingChanged = true;
}
if (properties._animationFrameIndexChanged || forceCopy) {
setAnimationFrameIndex(properties._animationFrameIndex);
somethingChanged = true;
}
if (properties._animationFPSChanged || forceCopy) {
setAnimationFPS(properties._animationFPS);
somethingChanged = true;
}
if (properties._glowLevelChanged || forceCopy) {
setGlowLevel(properties._glowLevel);
somethingChanged = true;
}
#endif
if (somethingChanged) {
bool wantDebug = false;
if (wantDebug) {

View file

@ -12,8 +12,6 @@
#ifndef hifi_EntityItem_h
#define hifi_EntityItem_h
#define HIDE_SUBCLASS_METHODS 1
#include <stdint.h>
#include <glm/glm.hpp>
@ -33,8 +31,6 @@ class EntityTreeElementExtraEncodeData;
class EntityItem {
public:
EntityItem();
EntityItem(const EntityItemID& entityItemID);
EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
virtual ~EntityItem();
@ -50,15 +46,9 @@ public:
bool isKnownID() const { return getID() != UNKNOWN_ENTITY_ID; }
EntityItemID getEntityItemID() const { return EntityItemID(getID(), getCreatorTokenID(), getID() != UNKNOWN_ENTITY_ID); }
/*
// these methods allow you to create models, and later edit them.
static uint32_t getIDfromCreatorTokenID(uint32_t creatorTokenID);
static uint32_t getNextCreatorTokenID();
static void handleAddEntityResponse(const QByteArray& packet);
*/
// methods for getting/setting all properties of an entity
EntityItemProperties getProperties() const;
void setProperties(const EntityItemProperties& properties, bool forceCopy = false);
virtual EntityItemProperties getProperties() const;
virtual void setProperties(const EntityItemProperties& properties, bool forceCopy = false);
quint64 getLastUpdated() const { return _lastUpdated; } /// Last simulated time of this entity universal usecs
quint64 getLastEdited() const { return _lastEdited; } /// Last edited time of this entity universal usecs
@ -66,15 +56,14 @@ public:
float getEditedAgo() const /// Elapsed seconds since this entity was last edited
{ return (float)(usecTimestampNow() - _lastEdited) / (float)USECS_PER_SECOND; }
OctreeElement::AppendState appendEntityData(OctreePacketData* packetData, EncodeBitstreamParams& params,
virtual OctreeElement::AppendState appendEntityData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData) const;
static EntityItemID readEntityItemIDFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args);
int readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args);
virtual int readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args);
/// For reading models from pre V3 bitstreams
int oldVersionReadEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args);
static int expectedBytes();
static bool encodeEntityEditMessageDetails(PacketType command, EntityItemID id, const EntityItemProperties& details,
@ -108,54 +97,10 @@ public:
glm::vec3 getMaximumPoint() const { return _position + glm::vec3(_radius, _radius, _radius); }
AACube getAACube() const { return AACube(getMinimumPoint(), getSize()); } /// AACube in domain scale units (0.0 - 1.0)
// TODO: Move these to subclasses, or other appropriate abstraction
// getters/setters applicable to models and particles
#ifdef HIDE_SUBCLASS_METHODS
const rgbColor& getColor() const { return _color; }
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
bool hasModel() const { return !_modelURL.isEmpty(); }
const QString& getModelURL() const { return _modelURL; }
bool hasAnimation() const { return !_animationURL.isEmpty(); }
const QString& getAnimationURL() const { return _animationURL; }
float getGlowLevel() const { return _glowLevel; }
QVector<SittingPoint> getSittingPoints() const { return _sittingPoints; }
void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); }
void setColor(const xColor& value) {
_color[RED_INDEX] = value.red;
_color[GREEN_INDEX] = value.green;
_color[BLUE_INDEX] = value.blue;
}
// model related properties
void setModelURL(const QString& url) { _modelURL = url; }
void setAnimationURL(const QString& url) { _animationURL = url; }
void setAnimationFrameIndex(float value) { _animationFrameIndex = value; }
void setAnimationIsPlaying(bool value) { _animationIsPlaying = value; }
void setAnimationFPS(float value) { _animationFPS = value; }
void setGlowLevel(float glowLevel) { _glowLevel = glowLevel; }
void setSittingPoints(QVector<SittingPoint> sittingPoints) { _sittingPoints = sittingPoints; }
void mapJoints(const QStringList& modelJointNames);
QVector<glm::quat> getAnimationFrame();
bool jointsMapped() const { return _jointMappingCompleted; }
bool getAnimationIsPlaying() const { return _animationIsPlaying; }
float getAnimationFrameIndex() const { return _animationFrameIndex; }
float getAnimationFPS() const { return _animationFPS; }
#endif
static void cleanupLoadedAnimations();
protected:
void initFromEntityItemID(const EntityItemID& entityItemID);
virtual void init(glm::vec3 position, float radius, rgbColor color, uint32_t id = NEW_ENTITY);
/*
static quint32 _nextID;
static uint32_t _nextCreatorTokenID; /// used by the static interfaces for creator token ids
static std::map<uint32_t,uint32_t> _tokenIDsToIDs;
*/
virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init
quint32 _id;
EntityTypes::EntityType_t _type;
@ -168,43 +113,6 @@ protected:
float _radius;
glm::quat _rotation;
bool _shouldBeDeleted;
#ifdef HIDE_SUBCLASS_METHODS
rgbColor _color;
QString _modelURL;
QVector<SittingPoint> _sittingPoints;
float _glowLevel;
quint64 _lastAnimated;
QString _animationURL;
float _animationFrameIndex; // we keep this as a float and round to int only when we need the exact index
bool _animationIsPlaying;
float _animationFPS;
bool _jointMappingCompleted;
QVector<int> _jointMapping;
static Animation* getAnimation(const QString& url);
static QMap<QString, AnimationPointer> _loadedAnimations;
static AnimationCache _animationCache;
#endif
};
// our non-pure virtual subclass for now...
class ModelEntityItem : public EntityItem {
public:
ModelEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
EntityItem(entityItemID, properties) { _type = EntityTypes::Model; }
virtual void somePureVirtualFunction() { }; // allow this class to be constructed
};
class ParticleEntityItem : public EntityItem {
public:
ParticleEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
EntityItem(entityItemID, properties) { _type = EntityTypes::Particle; }
virtual void somePureVirtualFunction() { }; // allow this class to be constructed
};
class BoxEntityItem : public EntityItem {

View file

@ -34,7 +34,6 @@ EntityItemProperties::EntityItemProperties() :
_shouldBeDeletedChanged(false),
#if 0 //def HIDE_SUBCLASS_METHODS
_color(),
_modelURL(""),
_animationURL(""),
@ -50,7 +49,6 @@ EntityItemProperties::EntityItemProperties() :
_animationFrameIndexChanged(false),
_animationFPSChanged(false),
_glowLevelChanged(false),
#endif
_defaultSettings(true)
{
@ -64,54 +62,6 @@ void EntityItemProperties::debugDump() const {
qDebug() << " _radius=" << _radius;
}
uint16_t EntityItemProperties::getChangedBits() const {
uint16_t changedBits = 0;
if (_radiusChanged) {
changedBits += ENTITY_PACKET_CONTAINS_RADIUS;
}
if (_positionChanged) {
changedBits += ENTITY_PACKET_CONTAINS_POSITION;
}
if (_rotationChanged) {
changedBits += ENTITY_PACKET_CONTAINS_ROTATION;
}
if (_shouldBeDeletedChanged) {
changedBits += ENTITY_PACKET_CONTAINS_SHOULDDIE;
}
#if 0 //def HIDE_SUBCLASS_METHODS
if (_colorChanged) {
changedBits += ENTITY_PACKET_CONTAINS_COLOR;
}
if (_modelURLChanged) {
changedBits += ENTITY_PACKET_CONTAINS_MODEL_URL;
}
if (_animationURLChanged) {
changedBits += ENTITY_PACKET_CONTAINS_ANIMATION_URL;
}
if (_animationIsPlayingChanged) {
changedBits += ENTITY_PACKET_CONTAINS_ANIMATION_PLAYING;
}
if (_animationFrameIndexChanged) {
changedBits += ENTITY_PACKET_CONTAINS_ANIMATION_FRAME;
}
if (_animationFPSChanged) {
changedBits += ENTITY_PACKET_CONTAINS_ANIMATION_FPS;
}
#endif
return changedBits;
}
EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
EntityPropertyFlags changedProperties;
if (_radiusChanged) {
@ -130,7 +80,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
changedProperties += PROP_SHOULD_BE_DELETED;
}
#if 0 //def HIDE_SUBCLASS_METHODS
if (_colorChanged) {
changedProperties += PROP_COLOR;
}
@ -154,7 +103,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
if (_animationFPSChanged) {
changedProperties += PROP_ANIMATION_FPS;
}
#endif
return changedProperties;
}
@ -176,10 +124,12 @@ qDebug() << "EntityItemProperties::copyToScriptValue()... isKnownID=" << isKnown
properties.setProperty("rotation", rotation);
properties.setProperty("shouldBeDeleted", _shouldBeDeleted);
#if 0 // def HIDE_SUBCLASS_METHODS
QScriptValue color = xColorToScriptValue(engine, _color);
properties.setProperty("color", color);
properties.setProperty("modelURL", _modelURL);
//qDebug() << "EntityItemProperties::copyToScriptValue().... _modelURL=" << _modelURL;
properties.setProperty("animationURL", _animationURL);
properties.setProperty("animationIsPlaying", _animationIsPlaying);
properties.setProperty("animationFrameIndex", _animationFrameIndex);
@ -197,7 +147,6 @@ qDebug() << "EntityItemProperties::copyToScriptValue()... isKnownID=" << isKnown
}
sittingPoints.setProperty("length", _sittingPoints.size());
properties.setProperty("sittingPoints", sittingPoints);
#endif // HIDE_SUBCLASS_METHODS
return properties;
}
@ -267,7 +216,6 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
}
}
#if 0 //def HIDE_SUBCLASS_METHODS
QScriptValue color = object.property("color");
if (color.isValid()) {
QScriptValue red = color.property("red");
@ -296,6 +244,8 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
_modelURLChanged = true;
}
}
qDebug() << "EntityItemProperties::copyFromScriptValue().... _modelURL=" << _modelURL;
QScriptValue animationURL = object.property("animationURL");
if (animationURL.isValid()) {
@ -346,7 +296,6 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
_glowLevelChanged = true;
}
}
#endif
_lastEdited = usecTimestampNow();
}

View file

@ -79,6 +79,7 @@ typedef PropertyFlags<EntityPropertyList> EntityPropertyFlags;
/// all units for position, radius, etc are in meter units
class EntityItemProperties {
friend class EntityItem; // TODO: consider removing this friend relationship and have EntityItem use public methods
friend class ModelEntityItem; // TODO: consider removing this friend relationship and have EntityItem use public methods
public:
EntityItemProperties();
virtual ~EntityItemProperties() { };
@ -88,7 +89,6 @@ public:
// editing related features supported by all entities
quint64 getLastEdited() const { return _lastEdited; }
uint16_t getChangedBits() const;
EntityPropertyFlags getChangedProperties() const;
/// used by EntityScriptingInterface to return EntityItemProperties for unknown models
@ -138,7 +138,9 @@ public:
bool containsPositionChange() const { return _positionChanged; }
bool containsRadiusChange() const { return _radiusChanged; }
#ifdef HIDE_SUBCLASS_METHODS
// TODO: this need to be more generic. for now, we're going to have the properties class support these as
// named getter/setters, but we want to move them to generic types...
//#ifdef HIDE_SUBCLASS_METHODS
// properties we want to move to just models and particles
xColor getColor() const { return _color; }
const QString& getModelURL() const { return _modelURL; }
@ -156,7 +158,7 @@ public:
void setAnimationIsPlaying(bool value) { _animationIsPlaying = value; _animationIsPlayingChanged = true; }
void setAnimationFPS(float value) { _animationFPS = value; _animationFPSChanged = true; }
void setGlowLevel(float value) { _glowLevel = value; _glowLevelChanged = true; }
#endif
//#endif
private:
friend bool EntityTypes::decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes,
@ -178,7 +180,9 @@ private:
bool _rotationChanged;
bool _shouldBeDeletedChanged;
#ifdef HIDE_SUBCLASS_METHODS
// TODO: this need to be more generic. for now, we're going to have the properties class support these as
// named getter/setters, but we want to move them to generic types...
//#ifdef HIDE_SUBCLASS_METHODS
xColor _color;
QString _modelURL;
QString _animationURL;
@ -195,7 +199,7 @@ private:
bool _animationFrameIndexChanged;
bool _animationFPSChanged;
bool _glowLevelChanged;
#endif
//#endif
bool _defaultSettings;
};

View file

@ -17,6 +17,7 @@
#include "EntityItem.h"
#include "EntityItemProperties.h"
#include "EntityTypes.h"
#include "ModelEntityItem.h"
QHash<EntityTypes::EntityType_t, QString> EntityTypes::_typeNameHash;
@ -48,10 +49,6 @@ EntityItem* EntityTypes::constructEntityItem(EntityType_t entityType, const Enti
newEntityItem = new ModelEntityItem(entityID, properties);
break;
case Particle:
newEntityItem = new ParticleEntityItem(entityID, properties);
break;
case Box:
newEntityItem = new BoxEntityItem(entityID, properties);
break;
@ -123,7 +120,7 @@ EntityItem* EntityTypes::constructEntityItem(const unsigned char* data, int byte
EntityItemID tempEntityID;
EntityItemProperties tempProperties;
//qDebug() << "EntityTypes::constructEntityItem(data, bytesToRead).... NEW BITSTREAM!!! entityType=" << entityType;
qDebug() << "EntityTypes::constructEntityItem(data, bytesToRead).... NEW BITSTREAM!!! entityType=" << entityType;
return constructEntityItem(entityType, tempEntityID, tempProperties);
}
@ -141,7 +138,7 @@ bool EntityTypes::decodeEntityEditPacket(const unsigned char* data, int bytesToR
EntityItemID& entityID, EntityItemProperties& properties) {
bool valid = false;
bool wantDebug = false;
bool wantDebug = true;
if (wantDebug) {
qDebug() << "EntityItem EntityItem::decodeEntityEditPacket() bytesToRead=" << bytesToRead;
}
@ -283,7 +280,13 @@ qDebug() << "EntityItem::decodeEntityEditPacket() ... lastEdited=" << lastEdited
// script would go here...
#ifdef HIDE_SUBCLASS_METHODS
//#ifdef HIDE_SUBCLASS_METHODS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// TODO: this needs to be reconciled...
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// PROP_COLOR
if (propertyFlags.getHasProperty(PROP_COLOR)) {
xColor color;
@ -308,6 +311,10 @@ qDebug() << "EntityItem::decodeEntityEditPacket() ... lastEdited=" << lastEdited
properties.setModelURL(modelURLString);
}
if (wantDebug) {
qDebug() << "EntityItem EntityItem::decodeEntityEditPacket() model URL=" << properties.getModelURL();
}
// PROP_ANIMATION_URL
if (propertyFlags.getHasProperty(PROP_ANIMATION_URL)) {
// animationURL
@ -347,7 +354,8 @@ qDebug() << "EntityItem::decodeEntityEditPacket() ... lastEdited=" << lastEdited
processedBytes += sizeof(animationIsPlaying);
properties.setAnimationIsPlaying(animationIsPlaying);
}
#endif
//#endif
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const bool wantDebugging = false;
if (wantDebugging) {

View file

@ -27,7 +27,6 @@ public:
typedef enum EntityType {
Base,
Model,
Particle,
Box,
Sphere,
Plane,

View file

@ -0,0 +1,772 @@
//
// ModelEntityItem.cpp
// 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
//
#include <ByteCountCoding.h>
#include "EntityTree.h"
#include "EntityTreeElement.h"
#include "ModelEntityItem.h"
// our non-pure virtual subclass for now...
ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
EntityItem(entityItemID, properties)
{
qDebug() << "ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties)...";
_type = EntityTypes::Model;
qDebug() << "ModelEntityItem::ModelEntityItem() properties.getModelURL()=" << properties.getModelURL();
qDebug() << "ModelEntityItem::ModelEntityItem() calling setProperties()";
setProperties(properties);
qDebug() << "ModelEntityItem::ModelEntityItem() getModelURL()=" << getModelURL();
}
EntityItemProperties ModelEntityItem::getProperties() const {
qDebug() << "ModelEntityItem::getProperties()... <<<<<<<<<<<<<<<< <<<<<<<<<<<<<<<<<<<<<<<<<";
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
properties._color = getXColor();
properties._modelURL = getModelURL();
properties._animationURL = getAnimationURL();
properties._animationIsPlaying = getAnimationIsPlaying();
properties._animationFrameIndex = getAnimationFrameIndex();
properties._animationFPS = getAnimationFPS();
properties._glowLevel = getGlowLevel();
properties._sittingPoints = getSittingPoints(); // sitting support
properties._colorChanged = false;
properties._modelURLChanged = false;
properties._animationURLChanged = false;
properties._animationIsPlayingChanged = false;
properties._animationFrameIndexChanged = false;
properties._animationFPSChanged = false;
properties._glowLevelChanged = false;
qDebug() << "ModelEntityItem::getProperties() getModelURL()=" << getModelURL();
return properties;
}
void ModelEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) {
qDebug() << "ModelEntityItem::setProperties()...";
qDebug() << "ModelEntityItem::ModelEntityItem() properties.getModelURL()=" << properties.getModelURL();
bool somethingChanged = false;
EntityItem::setProperties(properties, forceCopy); // set the properties in our base class
if (properties._colorChanged || forceCopy) {
setColor(properties._color);
somethingChanged = true;
}
if (properties._modelURLChanged || forceCopy) {
setModelURL(properties._modelURL);
qDebug() << "ModelEntityItem::setProperties() getModelURL()=" << getModelURL() << " ---- SETTING!!! --------";
somethingChanged = true;
}
if (properties._animationURLChanged || forceCopy) {
setAnimationURL(properties._animationURL);
somethingChanged = true;
}
if (properties._animationIsPlayingChanged || forceCopy) {
setAnimationIsPlaying(properties._animationIsPlaying);
somethingChanged = true;
}
if (properties._animationFrameIndexChanged || forceCopy) {
setAnimationFrameIndex(properties._animationFrameIndex);
somethingChanged = true;
}
if (properties._animationFPSChanged || forceCopy) {
setAnimationFPS(properties._animationFPS);
somethingChanged = true;
}
if (properties._glowLevelChanged || forceCopy) {
setGlowLevel(properties._glowLevel);
somethingChanged = true;
}
if (somethingChanged) {
bool wantDebug = false;
if (wantDebug) {
uint64_t now = usecTimestampNow();
int elapsed = now - _lastEdited;
qDebug() << "ModelEntityItem::setProperties() AFTER update... edited AGO=" << elapsed <<
"now=" << now << " _lastEdited=" << _lastEdited;
}
setLastEdited(properties._lastEdited);
}
}
int ModelEntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) {
qDebug() << "ModelEntityItem::readEntityDataFromBuffer()... <<<<<<<<<<<<<<<< <<<<<<<<<<<<<<<<<<<<<<<<<";
if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU) {
return oldVersionReadEntityDataFromBuffer(data, bytesLeftToRead, args);
}
// Header bytes
// object ID [16 bytes]
// ByteCountCoded(type code) [~1 byte]
// last edited [8 bytes]
// ByteCountCoded(last_edited to last_updated delta) [~1-8 bytes]
// PropertyFlags<>( everything ) [1-2 bytes]
// ~27-35 bytes...
const int MINIMUM_HEADER_BYTES = 27; // TODO: this is not correct, we don't yet have 16 byte IDs
int bytesRead = 0;
if (bytesLeftToRead >= MINIMUM_HEADER_BYTES) {
int originalLength = bytesLeftToRead;
QByteArray originalDataBuffer((const char*)data, originalLength);
int clockSkew = args.sourceNode ? args.sourceNode->getClockSkewUsec() : 0;
const unsigned char* dataAt = data;
// id
QByteArray encodedID = originalDataBuffer.mid(bytesRead); // maximum possible size
ByteCountCoded<quint32> idCoder = encodedID;
encodedID = idCoder; // determine true length
dataAt += encodedID.size();
bytesRead += encodedID.size();
_id = idCoder;
_creatorTokenID = UNKNOWN_ENTITY_TOKEN; // if we know the id, then we don't care about the creator token
_newlyCreated = false;
// type
QByteArray encodedType = originalDataBuffer.mid(bytesRead); // maximum possible size
ByteCountCoded<quint32> typeCoder = encodedType;
encodedType = typeCoder; // determine true length
dataAt += encodedType.size();
bytesRead += encodedType.size();
quint32 type = typeCoder;
_type = (EntityTypes::EntityType_t)type;
// XXXBHG: is this a good place to handle the last edited time client vs server??
// If the edit time encoded in the packet is NEWER than our known edit time...
// then we WANT to over-write our local data.
// If the edit time encoded in the packet is OLDER than our known edit time...
// then we WANT to preserve our local data. (NOTE: what if I change color, and you change position?? last one wins!)
bool overwriteLocalData = true; // assume the new content overwrites our local data
quint64 lastEditedFromBuffer = 0;
// _lastEdited
memcpy(&lastEditedFromBuffer, dataAt, sizeof(lastEditedFromBuffer));
dataAt += sizeof(lastEditedFromBuffer);
bytesRead += sizeof(lastEditedFromBuffer);
lastEditedFromBuffer -= clockSkew;
// If we've changed our local tree more recently than the new data from this packet
// then we will not be changing our values, instead we just read and skip the data
if (_lastEdited > lastEditedFromBuffer) {
overwriteLocalData = false;
qDebug() << "IGNORING old data from server!!! **************** _lastEdited=" << _lastEdited
<< "lastEditedFromBuffer=" << lastEditedFromBuffer << "now=" << usecTimestampNow();
} else {
qDebug() << "USING NEW data from server!!! **************** OLD _lastEdited=" << _lastEdited
<< "lastEditedFromBuffer=" << lastEditedFromBuffer << "now=" << usecTimestampNow();
_lastEdited = lastEditedFromBuffer;
}
// last updated is stored as ByteCountCoded delta from lastEdited
QByteArray encodedUpdateDelta = originalDataBuffer.mid(bytesRead); // maximum possible size
ByteCountCoded<quint64> updateDeltaCoder = encodedUpdateDelta;
quint64 updateDelta = updateDeltaCoder;
if (overwriteLocalData) {
_lastUpdated = _lastEdited + updateDelta; // don't adjust for clock skew since we already did that for _lastEdited
}
encodedUpdateDelta = updateDeltaCoder; // determine true length
dataAt += encodedUpdateDelta.size();
bytesRead += encodedUpdateDelta.size();
// Property Flags
QByteArray encodedPropertyFlags = originalDataBuffer.mid(bytesRead); // maximum possible size
EntityPropertyFlags propertyFlags = encodedPropertyFlags;
dataAt += propertyFlags.getEncodedLength();
bytesRead += propertyFlags.getEncodedLength();
// PROP_POSITION
if (propertyFlags.getHasProperty(PROP_POSITION)) {
glm::vec3 positionFromBuffer;
memcpy(&positionFromBuffer, dataAt, sizeof(positionFromBuffer));
dataAt += sizeof(positionFromBuffer);
bytesRead += sizeof(positionFromBuffer);
if (overwriteLocalData) {
_position = positionFromBuffer;
}
}
// PROP_RADIUS
if (propertyFlags.getHasProperty(PROP_RADIUS)) {
float radiusFromBuffer;
memcpy(&radiusFromBuffer, dataAt, sizeof(radiusFromBuffer));
dataAt += sizeof(radiusFromBuffer);
bytesRead += sizeof(radiusFromBuffer);
if (overwriteLocalData) {
_radius = radiusFromBuffer;
}
}
// PROP_ROTATION
if (propertyFlags.getHasProperty(PROP_ROTATION)) {
glm::quat rotation;
int bytes = unpackOrientationQuatFromBytes(dataAt, rotation);
dataAt += bytes;
bytesRead += bytes;
if (overwriteLocalData) {
_rotation = rotation;
}
}
// PROP_SHOULD_BE_DELETED
if (propertyFlags.getHasProperty(PROP_SHOULD_BE_DELETED)) {
bool shouldBeDeleted;
memcpy(&shouldBeDeleted, dataAt, sizeof(shouldBeDeleted));
dataAt += sizeof(shouldBeDeleted);
bytesRead += sizeof(shouldBeDeleted);
if (overwriteLocalData) {
_shouldBeDeleted = shouldBeDeleted;
}
}
// PROP_SCRIPT
// script would go here...
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// TODO: only handle these subclass items here, use the base class for the rest...
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// PROP_COLOR
if (propertyFlags.getHasProperty(PROP_COLOR)) {
rgbColor color;
if (overwriteLocalData) {
memcpy(_color, dataAt, sizeof(_color));
}
dataAt += sizeof(color);
bytesRead += sizeof(color);
}
// PROP_MODEL_URL
if (propertyFlags.getHasProperty(PROP_MODEL_URL)) {
// TODO: fix to new format...
uint16_t modelURLLength;
memcpy(&modelURLLength, dataAt, sizeof(modelURLLength));
dataAt += sizeof(modelURLLength);
bytesRead += sizeof(modelURLLength);
QString modelURLString((const char*)dataAt);
dataAt += modelURLLength;
bytesRead += modelURLLength;
if (overwriteLocalData) {
setModelURL(modelURLString);
}
}
qDebug() << "ModelEntityItem::readEntityDataFromBuffer()... modelURL=" << getModelURL();
// PROP_ANIMATION_URL
if (propertyFlags.getHasProperty(PROP_ANIMATION_URL)) {
// animationURL
uint16_t animationURLLength;
memcpy(&animationURLLength, dataAt, sizeof(animationURLLength));
dataAt += sizeof(animationURLLength);
bytesRead += sizeof(animationURLLength);
QString animationURLString((const char*)dataAt);
dataAt += animationURLLength;
bytesRead += animationURLLength;
if (overwriteLocalData) {
setAnimationURL(animationURLString);
}
}
// PROP_ANIMATION_FPS
if (propertyFlags.getHasProperty(PROP_ANIMATION_FPS)) {
float animationFPS;
memcpy(&animationFPS, dataAt, sizeof(animationFPS));
dataAt += sizeof(animationFPS);
bytesRead += sizeof(animationFPS);
if (overwriteLocalData) {
_animationFPS = animationFPS;
}
}
// PROP_ANIMATION_FRAME_INDEX
if (propertyFlags.getHasProperty(PROP_ANIMATION_FRAME_INDEX)) {
float animationFrameIndex;
memcpy(&animationFrameIndex, dataAt, sizeof(animationFrameIndex));
dataAt += sizeof(animationFrameIndex);
bytesRead += sizeof(animationFrameIndex);
if (overwriteLocalData) {
_animationFrameIndex = animationFrameIndex;
}
}
// PROP_ANIMATION_PLAYING
if (propertyFlags.getHasProperty(PROP_ANIMATION_PLAYING)) {
bool animationIsPlaying;
memcpy(&animationIsPlaying, dataAt, sizeof(animationIsPlaying));
dataAt += sizeof(animationIsPlaying);
bytesRead += sizeof(animationIsPlaying);
if (overwriteLocalData) {
_animationIsPlaying = animationIsPlaying;
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}
return bytesRead;
}
int ModelEntityItem::oldVersionReadEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) {
int bytesRead = 0;
if (bytesLeftToRead >= expectedBytes()) {
int clockSkew = args.sourceNode ? args.sourceNode->getClockSkewUsec() : 0;
const unsigned char* dataAt = data;
// id
memcpy(&_id, dataAt, sizeof(_id));
dataAt += sizeof(_id);
bytesRead += sizeof(_id);
// _lastUpdated
memcpy(&_lastUpdated, dataAt, sizeof(_lastUpdated));
dataAt += sizeof(_lastUpdated);
bytesRead += sizeof(_lastUpdated);
_lastUpdated -= clockSkew;
// _lastEdited
memcpy(&_lastEdited, dataAt, sizeof(_lastEdited));
dataAt += sizeof(_lastEdited);
bytesRead += sizeof(_lastEdited);
_lastEdited -= clockSkew;
// radius
memcpy(&_radius, dataAt, sizeof(_radius));
dataAt += sizeof(_radius);
bytesRead += sizeof(_radius);
// position
memcpy(&_position, dataAt, sizeof(_position));
dataAt += sizeof(_position);
bytesRead += sizeof(_position);
// color
memcpy(&_color, dataAt, sizeof(_color));
dataAt += sizeof(_color);
bytesRead += sizeof(_color);
// shouldBeDeleted
memcpy(&_shouldBeDeleted, dataAt, sizeof(_shouldBeDeleted));
dataAt += sizeof(_shouldBeDeleted);
bytesRead += sizeof(_shouldBeDeleted);
// modelURL
uint16_t modelURLLength;
memcpy(&modelURLLength, dataAt, sizeof(modelURLLength));
dataAt += sizeof(modelURLLength);
bytesRead += sizeof(modelURLLength);
QString modelURLString((const char*)dataAt);
setModelURL(modelURLString);
dataAt += modelURLLength;
bytesRead += modelURLLength;
// rotation
int bytes = unpackOrientationQuatFromBytes(dataAt, _rotation);
dataAt += bytes;
bytesRead += bytes;
if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ANIMATION) {
// animationURL
uint16_t animationURLLength;
memcpy(&animationURLLength, dataAt, sizeof(animationURLLength));
dataAt += sizeof(animationURLLength);
bytesRead += sizeof(animationURLLength);
QString animationURLString((const char*)dataAt);
setAnimationURL(animationURLString);
dataAt += animationURLLength;
bytesRead += animationURLLength;
// animationIsPlaying
memcpy(&_animationIsPlaying, dataAt, sizeof(_animationIsPlaying));
dataAt += sizeof(_animationIsPlaying);
bytesRead += sizeof(_animationIsPlaying);
// animationFrameIndex
memcpy(&_animationFrameIndex, dataAt, sizeof(_animationFrameIndex));
dataAt += sizeof(_animationFrameIndex);
bytesRead += sizeof(_animationFrameIndex);
// animationFPS
memcpy(&_animationFPS, dataAt, sizeof(_animationFPS));
dataAt += sizeof(_animationFPS);
bytesRead += sizeof(_animationFPS);
}
}
return bytesRead;
}
OctreeElement::AppendState ModelEntityItem::appendEntityData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData) const {
qDebug() << "ModelEntityItem::appendEntityData()... ********************************************";
// ALL this fits...
// object ID [16 bytes]
// ByteCountCoded(type code) [~1 byte]
// last edited [8 bytes]
// ByteCountCoded(last_edited to last_updated delta) [~1-8 bytes]
// PropertyFlags<>( everything ) [1-2 bytes]
// ~27-35 bytes...
OctreeElement::AppendState appendState = OctreeElement::COMPLETED; // assume the best
// encode our ID as a byte count coded byte stream
ByteCountCoded<quint32> idCoder = getID();
QByteArray encodedID = idCoder;
// encode our type as a byte count coded byte stream
ByteCountCoded<quint32> typeCoder = getType();
QByteArray encodedType = typeCoder;
quint64 updateDelta = getLastUpdated() <= getLastEdited() ? 0 : getLastUpdated() - getLastEdited();
ByteCountCoded<quint64> updateDeltaCoder = updateDelta;
QByteArray encodedUpdateDelta = updateDeltaCoder;
EntityPropertyFlags propertyFlags(PROP_LAST_ITEM);
EntityPropertyFlags requestedProperties;
requestedProperties += PROP_POSITION;
requestedProperties += PROP_RADIUS;
requestedProperties += PROP_MODEL_URL;
requestedProperties += PROP_ROTATION;
requestedProperties += PROP_COLOR;
requestedProperties += PROP_ANIMATION_URL;
requestedProperties += PROP_ANIMATION_FPS;
requestedProperties += PROP_ANIMATION_FRAME_INDEX;
requestedProperties += PROP_ANIMATION_PLAYING;
requestedProperties += PROP_SHOULD_BE_DELETED;
EntityPropertyFlags propertiesDidntFit = requestedProperties;
// If we are being called for a subsequent pass at appendEntityData() that failed to completely encode this item,
// then our modelTreeElementExtraEncodeData should include data about which properties we need to append.
if (modelTreeElementExtraEncodeData && modelTreeElementExtraEncodeData->includedItems.contains(getEntityItemID())) {
requestedProperties = modelTreeElementExtraEncodeData->includedItems.value(getEntityItemID());
}
//qDebug() << "requestedProperties=";
//requestedProperties.debugDumpBits();
LevelDetails modelLevel = packetData->startLevel();
bool successIDFits = packetData->appendValue(encodedID);
bool successTypeFits = packetData->appendValue(encodedType);
quint64 lastEdited = getLastEdited();
qDebug() << "ModelEntityItem::appendEntityData() ... lastEdited=" << lastEdited;
bool successLastEditedFits = packetData->appendValue(lastEdited);
bool successLastUpdatedFits = packetData->appendValue(encodedUpdateDelta);
int propertyFlagsOffset = packetData->getUncompressedByteOffset();
QByteArray encodedPropertyFlags = propertyFlags;
int oldPropertyFlagsLength = encodedPropertyFlags.length();
bool successPropertyFlagsFits = packetData->appendValue(encodedPropertyFlags);
int propertyCount = 0;
bool headerFits = successIDFits && successTypeFits && successLastEditedFits
&& successLastUpdatedFits && successPropertyFlagsFits;
int startOfEntityItemData = packetData->getUncompressedByteOffset();
if (headerFits) {
bool successPropertyFits;
propertyFlags -= PROP_LAST_ITEM; // clear the last item for now, we may or may not set it as the actual item
// These items would go here once supported....
// PROP_PAGED_PROPERTY,
// PROP_CUSTOM_PROPERTIES_INCLUDED,
// PROP_VISIBLE,
// PROP_POSITION
if (requestedProperties.getHasProperty(PROP_POSITION)) {
//qDebug() << "PROP_POSITION requested...";
LevelDetails propertyLevel = packetData->startLevel();
successPropertyFits = packetData->appendPosition(getPosition());
if (successPropertyFits) {
propertyFlags |= PROP_POSITION;
propertiesDidntFit -= PROP_POSITION;
propertyCount++;
packetData->endLevel(propertyLevel);
} else {
//qDebug() << "PROP_POSITION didn't fit...";
packetData->discardLevel(propertyLevel);
appendState = OctreeElement::PARTIAL;
}
} else {
//qDebug() << "PROP_POSITION NOT requested...";
propertiesDidntFit -= PROP_POSITION;
}
// PROP_RADIUS
if (requestedProperties.getHasProperty(PROP_RADIUS)) {
//qDebug() << "PROP_RADIUS requested...";
LevelDetails propertyLevel = packetData->startLevel();
successPropertyFits = packetData->appendValue(getRadius());
if (successPropertyFits) {
propertyFlags |= PROP_RADIUS;
propertiesDidntFit -= PROP_RADIUS;
propertyCount++;
packetData->endLevel(propertyLevel);
} else {
//qDebug() << "PROP_RADIUS didn't fit...";
packetData->discardLevel(propertyLevel);
appendState = OctreeElement::PARTIAL;
}
} else {
//qDebug() << "PROP_RADIUS NOT requested...";
propertiesDidntFit -= PROP_RADIUS;
}
// PROP_ROTATION
if (requestedProperties.getHasProperty(PROP_ROTATION)) {
//qDebug() << "PROP_ROTATION requested...";
LevelDetails propertyLevel = packetData->startLevel();
successPropertyFits = packetData->appendValue(getRotation());
if (successPropertyFits) {
propertyFlags |= PROP_ROTATION;
propertiesDidntFit -= PROP_ROTATION;
propertyCount++;
packetData->endLevel(propertyLevel);
} else {
//qDebug() << "PROP_ROTATION didn't fit...";
packetData->discardLevel(propertyLevel);
appendState = OctreeElement::PARTIAL;
}
} else {
//qDebug() << "PROP_ROTATION NOT requested...";
propertiesDidntFit -= PROP_ROTATION;
}
// PROP_SHOULD_BE_DELETED
if (requestedProperties.getHasProperty(PROP_SHOULD_BE_DELETED)) {
//qDebug() << "PROP_SHOULD_BE_DELETED requested...";
LevelDetails propertyLevel = packetData->startLevel();
successPropertyFits = packetData->appendValue(getShouldBeDeleted());
if (successPropertyFits) {
propertyFlags |= PROP_SHOULD_BE_DELETED;
propertiesDidntFit -= PROP_SHOULD_BE_DELETED;
propertyCount++;
packetData->endLevel(propertyLevel);
} else {
//qDebug() << "PROP_SHOULD_BE_DELETED didn't fit...";
packetData->discardLevel(propertyLevel);
appendState = OctreeElement::PARTIAL;
}
} else {
//qDebug() << "PROP_SHOULD_BE_DELETED NOT requested...";
propertiesDidntFit -= PROP_SHOULD_BE_DELETED;
}
// PROP_SCRIPT
// script would go here...
// PROP_COLOR
if (requestedProperties.getHasProperty(PROP_COLOR)) {
//qDebug() << "PROP_COLOR requested...";
LevelDetails propertyLevel = packetData->startLevel();
successPropertyFits = packetData->appendColor(getColor());
if (successPropertyFits) {
propertyFlags |= PROP_COLOR;
propertiesDidntFit -= PROP_COLOR;
propertyCount++;
packetData->endLevel(propertyLevel);
} else {
//qDebug() << "PROP_COLOR didn't fit...";
packetData->discardLevel(propertyLevel);
appendState = OctreeElement::PARTIAL;
}
} else {
//qDebug() << "PROP_COLOR NOT requested...";
propertiesDidntFit -= PROP_COLOR;
}
// PROP_MODEL_URL
if (requestedProperties.getHasProperty(PROP_MODEL_URL)) {
//qDebug() << "PROP_MODEL_URL requested...";
LevelDetails propertyLevel = packetData->startLevel();
successPropertyFits = packetData->appendValue(getModelURL());
if (successPropertyFits) {
propertyFlags |= PROP_MODEL_URL;
propertiesDidntFit -= PROP_MODEL_URL;
propertyCount++;
packetData->endLevel(propertyLevel);
} else {
//qDebug() << "PROP_MODEL_URL didn't fit...";
packetData->discardLevel(propertyLevel);
appendState = OctreeElement::PARTIAL;
}
} else {
//qDebug() << "PROP_MODEL_URL NOT requested...";
propertiesDidntFit -= PROP_MODEL_URL;
}
qDebug() << "ModelEntityItem::appendEntityData()... modelURL=" << getModelURL();
// PROP_ANIMATION_URL
if (requestedProperties.getHasProperty(PROP_ANIMATION_URL)) {
//qDebug() << "PROP_ANIMATION_URL requested...";
LevelDetails propertyLevel = packetData->startLevel();
successPropertyFits = packetData->appendValue(getAnimationURL());
if (successPropertyFits) {
propertyFlags |= PROP_ANIMATION_URL;
propertiesDidntFit -= PROP_ANIMATION_URL;
propertyCount++;
packetData->endLevel(propertyLevel);
} else {
//qDebug() << "PROP_ANIMATION_URL didn't fit...";
packetData->discardLevel(propertyLevel);
appendState = OctreeElement::PARTIAL;
}
} else {
//qDebug() << "PROP_ANIMATION_URL NOT requested...";
propertiesDidntFit -= PROP_ANIMATION_URL;
}
// PROP_ANIMATION_FPS
if (requestedProperties.getHasProperty(PROP_ANIMATION_FPS)) {
//qDebug() << "PROP_ANIMATION_FPS requested...";
LevelDetails propertyLevel = packetData->startLevel();
successPropertyFits = packetData->appendValue(getAnimationFPS());
if (successPropertyFits) {
propertyFlags |= PROP_ANIMATION_FPS;
propertiesDidntFit -= PROP_ANIMATION_FPS;
propertyCount++;
packetData->endLevel(propertyLevel);
} else {
//qDebug() << "PROP_ANIMATION_FPS didn't fit...";
packetData->discardLevel(propertyLevel);
appendState = OctreeElement::PARTIAL;
}
} else {
//qDebug() << "PROP_ANIMATION_FPS NOT requested...";
propertiesDidntFit -= PROP_ANIMATION_FPS;
}
// PROP_ANIMATION_FRAME_INDEX
if (requestedProperties.getHasProperty(PROP_ANIMATION_FRAME_INDEX)) {
//qDebug() << "PROP_ANIMATION_FRAME_INDEX requested...";
LevelDetails propertyLevel = packetData->startLevel();
successPropertyFits = packetData->appendValue(getAnimationFrameIndex());
if (successPropertyFits) {
propertyFlags |= PROP_ANIMATION_FRAME_INDEX;
propertiesDidntFit -= PROP_ANIMATION_FRAME_INDEX;
propertyCount++;
packetData->endLevel(propertyLevel);
} else {
//qDebug() << "PROP_ANIMATION_FRAME_INDEX didn't fit...";
packetData->discardLevel(propertyLevel);
appendState = OctreeElement::PARTIAL;
}
} else {
//qDebug() << "PROP_ANIMATION_FRAME_INDEX NOT requested...";
propertiesDidntFit -= PROP_ANIMATION_FRAME_INDEX;
}
// PROP_ANIMATION_PLAYING
if (requestedProperties.getHasProperty(PROP_ANIMATION_PLAYING)) {
//qDebug() << "PROP_ANIMATION_PLAYING requested...";
LevelDetails propertyLevel = packetData->startLevel();
successPropertyFits = packetData->appendValue(getAnimationIsPlaying());
if (successPropertyFits) {
propertyFlags |= PROP_ANIMATION_PLAYING;
propertiesDidntFit -= PROP_ANIMATION_PLAYING;
propertyCount++;
packetData->endLevel(propertyLevel);
} else {
//qDebug() << "PROP_ANIMATION_PLAYING didn't fit...";
packetData->discardLevel(propertyLevel);
appendState = OctreeElement::PARTIAL;
}
} else {
//qDebug() << "PROP_ANIMATION_PLAYING NOT requested...";
propertiesDidntFit -= PROP_ANIMATION_PLAYING;
}
}
if (propertyCount > 0) {
int endOfEntityItemData = packetData->getUncompressedByteOffset();
encodedPropertyFlags = propertyFlags;
int newPropertyFlagsLength = encodedPropertyFlags.length();
packetData->updatePriorBytes(propertyFlagsOffset,
(const unsigned char*)encodedPropertyFlags.constData(), encodedPropertyFlags.length());
// if the size of the PropertyFlags shrunk, we need to shift everything down to front of packet.
if (newPropertyFlagsLength < oldPropertyFlagsLength) {
int oldSize = packetData->getUncompressedSize();
const unsigned char* modelItemData = packetData->getUncompressedData(propertyFlagsOffset + oldPropertyFlagsLength);
int modelItemDataLength = endOfEntityItemData - startOfEntityItemData;
int newEntityItemDataStart = propertyFlagsOffset + newPropertyFlagsLength;
packetData->updatePriorBytes(newEntityItemDataStart, modelItemData, modelItemDataLength);
int newSize = oldSize - (oldPropertyFlagsLength - newPropertyFlagsLength);
packetData->setUncompressedSize(newSize);
} else {
assert(newPropertyFlagsLength == oldPropertyFlagsLength); // should not have grown
}
packetData->endLevel(modelLevel);
} else {
packetData->discardLevel(modelLevel);
appendState = OctreeElement::NONE; // if we got here, then we didn't include the item
}
//qDebug() << "propertyFlags=";
//propertyFlags.debugDumpBits();
//qDebug() << "propertiesDidntFit=";
//propertiesDidntFit.debugDumpBits();
// If any part of the model items didn't fit, then the element is considered partial
if (appendState != OctreeElement::COMPLETED) {
// add this item into our list for the next appendElementData() pass
modelTreeElementExtraEncodeData->includedItems.insert(getEntityItemID(), propertiesDidntFit);
}
return appendState;
}

View file

@ -0,0 +1,94 @@
//
// ModelEntityItem.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_ModelEntityItem_h
#define hifi_ModelEntityItem_h
#include "EntityItem.h"
// our non-pure virtual subclass for now...
class ModelEntityItem : public EntityItem {
public:
ModelEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
virtual void somePureVirtualFunction() { }; // allow this class to be constructed
// methods for getting/setting all properties of an entity
virtual EntityItemProperties getProperties() const;
virtual void setProperties(const EntityItemProperties& properties, bool forceCopy = false);
virtual OctreeElement::AppendState appendEntityData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData) const;
virtual int readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args);
/// For reading models from pre V3 bitstreams
int oldVersionReadEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args);
// TODO: Move these to subclasses, or other appropriate abstraction
// getters/setters applicable to models and particles
const rgbColor& getColor() const { return _color; }
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
bool hasModel() const { return !_modelURL.isEmpty(); }
const QString& getModelURL() const { return _modelURL; }
bool hasAnimation() const { return !_animationURL.isEmpty(); }
const QString& getAnimationURL() const { return _animationURL; }
float getGlowLevel() const { return _glowLevel; }
QVector<SittingPoint> getSittingPoints() const { return _sittingPoints; }
void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); }
void setColor(const xColor& value) {
_color[RED_INDEX] = value.red;
_color[GREEN_INDEX] = value.green;
_color[BLUE_INDEX] = value.blue;
}
// model related properties
void setModelURL(const QString& url) { _modelURL = url; }
void setAnimationURL(const QString& url) { _animationURL = url; }
void setAnimationFrameIndex(float value) { _animationFrameIndex = value; }
void setAnimationIsPlaying(bool value) { _animationIsPlaying = value; }
void setAnimationFPS(float value) { _animationFPS = value; }
void setGlowLevel(float glowLevel) { _glowLevel = glowLevel; }
void setSittingPoints(QVector<SittingPoint> sittingPoints) { _sittingPoints = sittingPoints; }
void mapJoints(const QStringList& modelJointNames);
QVector<glm::quat> getAnimationFrame();
bool jointsMapped() const { return _jointMappingCompleted; }
bool getAnimationIsPlaying() const { return _animationIsPlaying; }
float getAnimationFrameIndex() const { return _animationFrameIndex; }
float getAnimationFPS() const { return _animationFPS; }
protected:
rgbColor _color;
QString _modelURL;
QVector<SittingPoint> _sittingPoints;
float _glowLevel;
quint64 _lastAnimated;
QString _animationURL;
float _animationFrameIndex; // we keep this as a float and round to int only when we need the exact index
bool _animationIsPlaying;
float _animationFPS;
bool _jointMappingCompleted;
QVector<int> _jointMapping;
static Animation* getAnimation(const QString& url);
static QMap<QString, AnimationPointer> _loadedAnimations;
static AnimationCache _animationCache;
};
#endif // hifi_ModelEntityItem_h

View file

@ -1,6 +1,85 @@
Base properties...
* type
* position
* size/radius/bounds?? maybe correct is x,y,z scales
* rotation
* script
should these be included for all entities? Light, Models, planes, etc?
* velocity
* gravity
* damping
* rotational velocity? - wouldn't that be cool to be automatic with no edits
* rotational damping?? - can you slow a quat rotation by simply multiplying it by a fraction?
* color??
Primitive Object Properties:
* color?
* texture?
Model properties:
void setModelURL(const QString& url)
void setAnimationURL(const QString& url)
void setAnimationFrameIndex(float value)
void setAnimationIsPlaying(bool value)
void setAnimationFPS(float value)
void setGlowLevel(float glowLevel)
void setSittingPoints(QVector<SittingPoint> sittingPoints) ??? - should this just be a string property???
// Things to do with entities...
//
// TODO:
// 0) handle subclass properties?
We use properties for addEntity(id, props) -
the result should be that the properties are not really understood by the tree, or element, but should be
storable, passable, and reusable by the subclass entity... so "setProperties()" should be virtual and handle
storage of any items contained in the properties
getProperties() examples:
Application::exportModels()
EntityScriptingInterface::getEntityProperties()
EntityScriptingInterface::findRayIntersection/Blocking/Worker()
setProperties() examples:
EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); /// ??????
UpdateEntityOperator - this seems like it should be able to be virtual and work well.
EntityTreeElement::addOrUpdateEntity() -- same use case as UpdateEntityOperator...
basic properties features use getter/setter....
all others use:
set('propertyName', value)... but... we need to know the type of value
setStringProperty('name', const QString& value);
QString getStringProperty('name');
setFloatProperty('name', float value);
float getFloatProperty('name');
what about editing?
EntityItem::encodeEntityEditMessageDetails() -- this could be a member of EntityItemProperties, or EntityTypes?...
EntityTypes::decodeEntityEditPacket() -- this could be a member of EntityItemProperties...??
//
// 1) consider moving type to front of buffers to make construction easier
// 2) EntityTree::update()/EntityTreeElement::update()... for animations and velocity changes...
@ -36,7 +115,7 @@
// 12b) Use the delete message instead of shouldDelete property
// 13) add user properties (support sitpoints)
// 14) implement "Light" entity
// 14) implement "Light" entity, "Fire" entity?
@ -55,12 +134,18 @@
22a) void ModelItemProperties::copyFromNewModelItem(const ModelItem& modelItem); // XXX ??? Do we need this????
22b) Local Entities Overlay - from Local Models Overlay
22c) void ModelTree::sendModels(ModelEditPacketSender* packetSender, float x, float y, float z)....
22d) void ModelTree::findModelsInCube(const AACube& cube, QVector<ModelItem*>& foundModels)...
22e) void ModelTreeElement::getModelsInside(const AACube& box, QVector<ModelItem*>& foundModels)...
DONE -- 22d) void ModelTree::findModelsInCube(const AACube& cube, QVector<ModelItem*>& foundModels)...
DONE -- 22e) void ModelTreeElement::getModelsInside(const AACube& box, QVector<ModelItem*>& foundModels)...
// 23) xColor vs rbgColor????
// 24) get rid of EntityItem::expectedBytes()...
===============

View file

@ -219,6 +219,10 @@ bool OctreePacketData::appendColor(const nodeColor& color) {
return appendColor(color[RED_INDEX], color[GREEN_INDEX], color[BLUE_INDEX]);
}
bool OctreePacketData::appendColor(const xColor& color) {
return appendColor(color.red, color.green, color.blue);
}
bool OctreePacketData::appendColor(const rgbColor& color) {
return appendColor(color[RED_INDEX], color[GREEN_INDEX], color[BLUE_INDEX]);
}

View file

@ -115,6 +115,9 @@ public:
/// appends a color to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendColor(const nodeColor& color);
/// appends a color to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendColor(const xColor& color);
/// appends a color to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendColor(const rgbColor& color);