mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
more work on virtual entities
This commit is contained in:
parent
3a8c5018ee
commit
273853ef24
13 changed files with 1018 additions and 409 deletions
|
@ -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 + " "
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -27,7 +27,6 @@ public:
|
|||
typedef enum EntityType {
|
||||
Base,
|
||||
Model,
|
||||
Particle,
|
||||
Box,
|
||||
Sphere,
|
||||
Plane,
|
||||
|
|
772
libraries/entities/src/ModelEntityItem.cpp
Normal file
772
libraries/entities/src/ModelEntityItem.cpp
Normal 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;
|
||||
}
|
94
libraries/entities/src/ModelEntityItem.h
Normal file
94
libraries/entities/src/ModelEntityItem.h
Normal 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
|
|
@ -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()...
|
||||
|
||||
|
||||
|
||||
|
||||
===============
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue