splitting up a bunch of Entity classes into different files

This commit is contained in:
ZappoMan 2014-07-16 09:25:54 -07:00
parent 5869039bf3
commit 1125cb183e
10 changed files with 1055 additions and 611 deletions

View file

@ -29,74 +29,6 @@
#include "EntityItem.h"
#include "EntityTree.h"
QHash<EntityTypes::EntityType_t, QString> EntityTypes::_typeNameHash;
const QString UNKNOWN_EntityType_t_NAME = "Unknown";
const QString& EntityTypes::getEntityTypeName(EntityType_t entityType) {
QHash<EntityType_t, QString>::iterator matchedTypeName = _typeNameHash.find(entityType);
return matchedTypeName != _typeNameHash.end() ? matchedTypeName.value() : UNKNOWN_EntityType_t_NAME;
}
bool EntityTypes::registerEntityType(EntityType_t entityType, const QString& name) {
_typeNameHash.insert(entityType, name);
return true;
}
EntityItem* EntityTypes::constructEntityItem(EntityType_t entityType, const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItem* newEntityItem = NULL;
// switch statement for now, needs to support registration of constructor
switch (entityType) {
// Base, // ??? not supported?
case Model:
newEntityItem = new ModelEntityItem(entityID, properties);
break;
case Particle:
newEntityItem = new ParticleEntityItem(entityID, properties);
break;
case Box:
newEntityItem = new BoxEntityItem(entityID, properties);
break;
case Sphere:
newEntityItem = new SphereEntityItem(entityID, properties);
break;
case Plane:
newEntityItem = new PlaneEntityItem(entityID, properties);
break;
case Cylinder:
newEntityItem = new CylinderEntityItem(entityID, properties);
break;
case Pyramid:
newEntityItem = new PyramidEntityItem(entityID, properties);
break;
default:
newEntityItem = new ModelEntityItem(entityID, properties);
break;
}
return newEntityItem;
}
EntityItem* EntityTypes::constructEntityItem(const unsigned char* data, int bytesToRead) {
return NULL; // TODO Implement this for real!
}
bool EntityTypes::decodEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes,
const EntityItemID& entityID, const EntityItemProperties& properties) {
bool valid = false;
return valid;
}
bool registered = EntityTypes::registerEntityType(EntityTypes::Base, "Base")
&& EntityTypes::registerEntityType(EntityTypes::Model, "Model"); // TODO: move this to model subclass
uint32_t EntityItem::_nextID = 0;
// for locally created models
@ -827,241 +759,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
return bytesRead;
}
EntityItem* EntityItem::fromEditPacket(const unsigned char* data, int length, int& processedBytes, EntityTree* tree, bool& valid) {
EntityItem* result = NULL;
bool wantDebug = false;
if (wantDebug) {
qDebug() << "EntityItem EntityItem::fromEditPacket() length=" << length;
}
const unsigned char* dataAt = data;
processedBytes = 0;
// the first part of the data is an octcode, this is a required element of the edit packet format, but we don't
// actually use it, we do need to skip it and read to the actual data we care about.
int octets = numberOfThreeBitSectionsInCode(data);
int lengthOfOctcode = bytesRequiredForCodeLength(octets);
if (wantDebug) {
qDebug() << "EntityItem EntityItem::fromEditPacket() lengthOfOctcode=" << lengthOfOctcode;
}
// we don't actually do anything with this octcode...
dataAt += lengthOfOctcode;
processedBytes += lengthOfOctcode;
// Edit packets have a last edited time stamp immediately following the octcode.
// NOTE: the edit times have been set by the editor to match out clock, so we don't need to adjust
// these times for clock skew at this point.
quint64 lastEdited;
memcpy(&lastEdited, dataAt, sizeof(lastEdited));
dataAt += sizeof(lastEdited);
processedBytes += sizeof(lastEdited);
// encoded id
QByteArray encodedID((const char*)dataAt, (length - processedBytes));
ByteCountCoded<quint32> idCoder = encodedID;
quint32 editID = idCoder;
encodedID = idCoder; // determine true length
dataAt += encodedID.size();
processedBytes += encodedID.size();
if (wantDebug) {
qDebug() << "EntityItem EntityItem::fromEditPacket() editID=" << editID;
}
bool isNewEntityItem = (editID == NEW_ENTITY);
if (isNewEntityItem) {
// If this is a NEW_ENTITY, then we assume that there's an additional uint32_t creatorToken, that
// we want to send back to the creator as an map to the actual id
QByteArray encodedToken((const char*)dataAt, (length - processedBytes));
ByteCountCoded<quint32> tokenCoder = encodedToken;
quint32 creatorTokenID = tokenCoder;
encodedToken = tokenCoder; // determine true length
dataAt += encodedToken.size();
processedBytes += encodedToken.size();
//newEntityItem.setCreatorTokenID(creatorTokenID);
//newEntityItem._newlyCreated = true;
valid = true;
} else {
// look up the existing entityItem
const EntityItem* existingEntityItem = tree->findEntityByID(editID, true);
// copy existing properties before over-writing with new properties
if (existingEntityItem) {
// TODO: how do we want to handle these edits to existing packets???
//newEntityItem = *existingEntityItem;
valid = true;
} else {
// the user attempted to edit a entityItem that doesn't exist
qDebug() << "user attempted to edit a entityItem that doesn't exist... editID=" << editID;
tree->debugDumpMap();
valid = false;
// NOTE: Even though we know item is not valid, we still need to parse the rest
// of the edit packet so that we don't end up out of sync on our bitstream
// fall through....
}
//newEntityItem._id = editID;
//newEntityItem._newlyCreated = false;
}
// Entity Type...
QByteArray encodedType((const char*)dataAt, (length - processedBytes));
ByteCountCoded<quint32> typeCoder = encodedType;
quint32 entityTypeCode = typeCoder;
EntityTypes::EntityType_t entityType = (EntityTypes::EntityType_t)entityTypeCode;
encodedType = typeCoder; // determine true length
dataAt += encodedType.size();
processedBytes += encodedType.size();
// Update Delta - when was this item updated relative to last edit... this really should be 0
// TODO: Should we get rid of this in this in edit packets, since this has to always be 0?
// last updated is stored as ByteCountCoded delta from lastEdited
QByteArray encodedUpdateDelta((const char*)dataAt, (length - processedBytes));
ByteCountCoded<quint64> updateDeltaCoder = encodedUpdateDelta;
quint64 updateDelta = updateDeltaCoder;
quint64 lastUpdated = lastEdited + updateDelta; // don't adjust for clock skew since we already did that for lastEdited
encodedUpdateDelta = updateDeltaCoder; // determine true length
dataAt += encodedUpdateDelta.size();
processedBytes += encodedUpdateDelta.size();
// Property Flags...
QByteArray encodedPropertyFlags((const char*)dataAt, (length - processedBytes));
EntityPropertyFlags propertyFlags = encodedPropertyFlags;
dataAt += propertyFlags.getEncodedLength();
processedBytes += propertyFlags.getEncodedLength();
/****
// All of the remaining items are optional, and may or may not be included based on their included values in the
// properties included bits
uint16_t packetContainsBits = 0;
if (!isNewEntityItem) {
memcpy(&packetContainsBits, dataAt, sizeof(packetContainsBits));
dataAt += sizeof(packetContainsBits);
processedBytes += sizeof(packetContainsBits);
// only applies to editing of existing models
if (!packetContainsBits) {
//qDebug() << "edit packet didn't contain any information ignore it...";
valid = false;
//return newEntityItem;
return NULL;
}
}
// position
if (isNewEntityItem || ((packetContainsBits & ENTITY_PACKET_CONTAINS_POSITION) == ENTITY_PACKET_CONTAINS_POSITION)) {
memcpy(&newEntityItem._position, dataAt, sizeof(newEntityItem._position));
dataAt += sizeof(newEntityItem._position);
processedBytes += sizeof(newEntityItem._position);
}
// radius
if (isNewEntityItem || ((packetContainsBits & ENTITY_PACKET_CONTAINS_RADIUS) == ENTITY_PACKET_CONTAINS_RADIUS)) {
memcpy(&newEntityItem._radius, dataAt, sizeof(newEntityItem._radius));
dataAt += sizeof(newEntityItem._radius);
processedBytes += sizeof(newEntityItem._radius);
}
// rotation
if (isNewEntityItem || ((packetContainsBits &
ENTITY_PACKET_CONTAINS_ROTATION) == ENTITY_PACKET_CONTAINS_ROTATION)) {
int bytes = unpackOrientationQuatFromBytes(dataAt, newEntityItem._rotation);
dataAt += bytes;
processedBytes += bytes;
}
// shouldBeDeleted
if (isNewEntityItem || ((packetContainsBits & ENTITY_PACKET_CONTAINS_SHOULDDIE) == ENTITY_PACKET_CONTAINS_SHOULDDIE)) {
memcpy(&newEntityItem._shouldBeDeleted, dataAt, sizeof(newEntityItem._shouldBeDeleted));
dataAt += sizeof(newEntityItem._shouldBeDeleted);
processedBytes += sizeof(newEntityItem._shouldBeDeleted);
}
#ifdef HIDE_SUBCLASS_METHODS
// color
if (isNewEntityItem || ((packetContainsBits & ENTITY_PACKET_CONTAINS_COLOR) == ENTITY_PACKET_CONTAINS_COLOR)) {
memcpy(newEntityItem._color, dataAt, sizeof(newEntityItem._color));
dataAt += sizeof(newEntityItem._color);
processedBytes += sizeof(newEntityItem._color);
}
// modelURL
if (isNewEntityItem || ((packetContainsBits & ENTITY_PACKET_CONTAINS_MODEL_URL) == ENTITY_PACKET_CONTAINS_MODEL_URL)) {
uint16_t modelURLLength;
memcpy(&modelURLLength, dataAt, sizeof(modelURLLength));
dataAt += sizeof(modelURLLength);
processedBytes += sizeof(modelURLLength);
QString tempString((const char*)dataAt);
newEntityItem._modelURL = tempString;
dataAt += modelURLLength;
processedBytes += modelURLLength;
}
// animationURL
if (isNewEntityItem || ((packetContainsBits & ENTITY_PACKET_CONTAINS_ANIMATION_URL) == ENTITY_PACKET_CONTAINS_ANIMATION_URL)) {
uint16_t animationURLLength;
memcpy(&animationURLLength, dataAt, sizeof(animationURLLength));
dataAt += sizeof(animationURLLength);
processedBytes += sizeof(animationURLLength);
QString tempString((const char*)dataAt);
newEntityItem._animationURL = tempString;
dataAt += animationURLLength;
processedBytes += animationURLLength;
}
// animationIsPlaying
if (isNewEntityItem || ((packetContainsBits &
ENTITY_PACKET_CONTAINS_ANIMATION_PLAYING) == ENTITY_PACKET_CONTAINS_ANIMATION_PLAYING)) {
memcpy(&newEntityItem._animationIsPlaying, dataAt, sizeof(newEntityItem._animationIsPlaying));
dataAt += sizeof(newEntityItem._animationIsPlaying);
processedBytes += sizeof(newEntityItem._animationIsPlaying);
}
// animationFrameIndex
if (isNewEntityItem || ((packetContainsBits &
ENTITY_PACKET_CONTAINS_ANIMATION_FRAME) == ENTITY_PACKET_CONTAINS_ANIMATION_FRAME)) {
memcpy(&newEntityItem._animationFrameIndex, dataAt, sizeof(newEntityItem._animationFrameIndex));
dataAt += sizeof(newEntityItem._animationFrameIndex);
processedBytes += sizeof(newEntityItem._animationFrameIndex);
}
// animationFPS
if (isNewEntityItem || ((packetContainsBits &
ENTITY_PACKET_CONTAINS_ANIMATION_FPS) == ENTITY_PACKET_CONTAINS_ANIMATION_FPS)) {
memcpy(&newEntityItem._animationFPS, dataAt, sizeof(newEntityItem._animationFPS));
dataAt += sizeof(newEntityItem._animationFPS);
processedBytes += sizeof(newEntityItem._animationFPS);
}
#endif
***/
const bool wantDebugging = false;
if (wantDebugging) {
qDebug("EntityItem::fromEditPacket()...");
qDebug() << " EntityItem id in packet:" << editID;
//newEntityItem.debugDump();
}
// TODO: need to make this actually return something...
return result;
}
void EntityItem::debugDump() const {
qDebug() << "EntityItem id:" << getEntityItemID();
qDebug(" edited ago:%f", getEditedAgo());
@ -1081,9 +778,6 @@ void EntityItem::debugDump() const {
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
@ -1614,6 +1308,8 @@ EntityItemProperties EntityItem::getProperties() const {
properties._id = getID();
properties._idSet = true;
properties._type = getType();
properties._position = getPosition() * (float) TREE_SCALE;
properties._radius = getRadius() * (float) TREE_SCALE;
properties._rotation = getRotation();
@ -1726,6 +1422,7 @@ EntityItemProperties::EntityItemProperties() :
_id(UNKNOWN_ENTITY_ID),
_idSet(false),
_lastEdited(usecTimestampNow()),
_type(EntityTypes::Base),
_position(0),
_radius(ENTITY_DEFAULT_RADIUS),
@ -1908,6 +1605,13 @@ qDebug() << "EntityItemProperties::copyToScriptValue()... isKnownID=" << isKnown
void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
QScriptValue typeScriptValue = object.property("type");
if (typeScriptValue.isValid()) {
QString typeName;
typeName = typeScriptValue.toVariant().toString();
_type = EntityTypes::getEntityTypeFromName(typeName);
}
QScriptValue position = object.property("position");
if (position.isValid()) {
QScriptValue x = position.property("x");
@ -2055,22 +1759,3 @@ QScriptValue EntityItemPropertiesToScriptValue(QScriptEngine* engine, const Enti
void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemProperties& properties) {
properties.copyFromScriptValue(object);
}
QScriptValue EntityItemIDtoScriptValue(QScriptEngine* engine, const EntityItemID& id) {
QScriptValue obj = engine->newObject();
obj.setProperty("id", id.id);
obj.setProperty("creatorTokenID", id.creatorTokenID);
obj.setProperty("isKnownID", id.isKnownID);
qDebug() << "EntityItemIDtoScriptValue()... isKnownID=" << id.isKnownID << "id=" << id.id << "creatorTokenID=" << id.creatorTokenID;
return obj;
}
void EntityItemIDfromScriptValue(const QScriptValue &object, EntityItemID& id) {
id.id = object.property("id").toVariant().toUInt();
id.creatorTokenID = object.property("creatorTokenID").toVariant().toUInt();
id.isKnownID = object.property("isKnownID").toVariant().toBool();
}

View file

@ -1,6 +1,6 @@
//
// EntityItem.h
// libraries/models/src
// libraries/entities/src
//
// Created by Brad Hefta-Gaub on 12/4/13.
// Copyright 2013 High Fidelity, Inc.
@ -18,266 +18,16 @@
#include <glm/glm.hpp>
#include <QtScript/QScriptEngine>
#include <QtCore/QObject>
#include <AnimationCache.h>
#include <CollisionInfo.h>
#include <AnimationCache.h> // for Animation, AnimationCache, and AnimationPointer classes
#include <Octree.h> // for EncodeBitstreamParams class
#include <OctreeElement.h> // for OctreeElement::AppendState
#include <OctreePacketData.h>
#include <PropertyFlags.h>
#include <SharedUtil.h>
#include <FBXReader.h>
#include "EntityItemID.h"
#include "EntityItemProperties.h"
#include "EntityTypes.h"
class EntityItem;
class EntityItemID;
class EntityEditPacketSender;
class EntityItemProperties;
class EntitysScriptingInterface;
class EntityTree;
class EntityTreeElementExtraEncodeData;
class ScriptEngine;
class VoxelEditPacketSender;
class VoxelsScriptingInterface;
struct VoxelDetail;
const uint32_t NEW_ENTITY = 0xFFFFFFFF;
const uint32_t UNKNOWN_ENTITY_TOKEN = 0xFFFFFFFF;
const uint32_t UNKNOWN_ENTITY_ID = 0xFFFFFFFF;
const uint16_t ENTITY_PACKET_CONTAINS_RADIUS = 1;
const uint16_t ENTITY_PACKET_CONTAINS_POSITION = 2;
const uint16_t ENTITY_PACKET_CONTAINS_COLOR = 4;
const uint16_t ENTITY_PACKET_CONTAINS_SHOULDDIE = 8;
const uint16_t ENTITY_PACKET_CONTAINS_MODEL_URL = 16;
const uint16_t ENTITY_PACKET_CONTAINS_ROTATION = 32;
const uint16_t ENTITY_PACKET_CONTAINS_ANIMATION_URL = 64;
const uint16_t ENTITY_PACKET_CONTAINS_ANIMATION_PLAYING = 128;
const uint16_t ENTITY_PACKET_CONTAINS_ANIMATION_FRAME = 256;
const uint16_t ENTITY_PACKET_CONTAINS_ANIMATION_FPS = 512;
const float ENTITY_DEFAULT_RADIUS = 0.1f / TREE_SCALE;
const float ENTITY_MINIMUM_ELEMENT_SIZE = (1.0f / 100000.0f) / TREE_SCALE; // smallest size container
const QString ENTITY_DEFAULT_MODEL_URL("");
const glm::quat ENTITY_DEFAULT_ROTATION;
const QString ENTITY_DEFAULT_ANIMATION_URL("");
const float ENTITY_DEFAULT_ANIMATION_FPS = 30.0f;
// PropertyFlags support
class EntityTypes {
public:
typedef enum EntityType {
Base,
Model,
Particle,
Box,
Sphere,
Plane,
Cylinder,
Pyramid
} EntityType_t;
static const QString& getEntityTypeName(EntityType_t entityType);
static bool registerEntityType(EntityType_t entityType, const QString& name);
static EntityItem* constructEntityItem(EntityType_t entityType, const EntityItemID& entityID, const EntityItemProperties& properties);
static EntityItem* constructEntityItem(const unsigned char* data, int bytesToRead);
static bool decodEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes,
const EntityItemID& entityID, const EntityItemProperties& properties);
private:
static QHash<EntityType_t, QString> _typeNameHash;
};
// PropertyFlags support
enum EntityPropertyList {
PROP_PAGED_PROPERTY,
PROP_CUSTOM_PROPERTIES_INCLUDED,
PROP_VISIBLE,
PROP_POSITION,
PROP_RADIUS,
PROP_ROTATION,
PROP_SCRIPT,
PROP_MODEL_URL,
PROP_COLOR,
PROP_ANIMATION_URL,
PROP_ANIMATION_FPS,
PROP_ANIMATION_FRAME_INDEX,
PROP_ANIMATION_PLAYING,
PROP_SHOULD_BE_DELETED,
PROP_LAST_ITEM = PROP_SHOULD_BE_DELETED
};
typedef PropertyFlags<EntityPropertyList> EntityPropertyFlags;
/// A collection of properties of an entity item used in the scripting API. Translates between the actual properties of an
/// entity and a JavaScript style hash/QScriptValue storing a set of properties. Used in scripting to set/get the complete
/// set of entity item properties via JavaScript hashes/QScriptValues
/// 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
public:
EntityItemProperties();
virtual ~EntityItemProperties() { };
virtual QScriptValue copyToScriptValue(QScriptEngine* engine) const;
virtual void copyFromScriptValue(const QScriptValue& object);
// 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
void setIsUnknownID() { _id = UNKNOWN_ENTITY_ID; _idSet = true; }
glm::vec3 getMinimumPointMeters() const { return _position - glm::vec3(_radius, _radius, _radius); }
glm::vec3 getMaximumPointMeters() const { return _position + glm::vec3(_radius, _radius, _radius); }
AACube getAACubeMeters() const { return AACube(getMinimumPointMeters(), getMaxDimension()); } /// AACube in meter units
glm::vec3 getMinimumPointTreeUnits() const { return getMinimumPointMeters() / (float)TREE_SCALE; }
glm::vec3 getMaximumPointTreeUnits() const { return getMaximumPointMeters() / (float)TREE_SCALE; }
AACube getAACubeTreeUnits() const { return AACube(getMinimumPointMeters()/(float)TREE_SCALE, getMaxDimension()/(float)TREE_SCALE); } /// AACube in domain scale units (0.0 - 1.0)
void debugDump() const;
// properties of all entities
EntityTypes::EntityType_t getType() const { return _type; }
const glm::vec3& getPosition() const { return _position; }
float getRadius() const { return _radius; }
float getMaxDimension() const { return _radius * 2.0f; }
glm::vec3 getDimensions() const { return glm::vec3(_radius, _radius, _radius) * 2.0f; }
const glm::quat& getRotation() const { return _rotation; }
bool getShouldBeDeleted() const { return _shouldBeDeleted; }
/// set position in meter units
void setPosition(const glm::vec3& value) { _position = value; _positionChanged = true; }
void setRadius(float value) { _radius = value; _radiusChanged = true; }
void setShouldBeDeleted(bool shouldBeDeleted) { _shouldBeDeleted = shouldBeDeleted; _shouldBeDeletedChanged = true; }
// NOTE: how do we handle _defaultSettings???
bool containsBoundsProperties() const { return (_positionChanged || _radiusChanged); }
#if 0 // def HIDE_SUBCLASS_METHODS
// properties we want to move to just models and particles
xColor getColor() const { return _color; }
const QString& getModelURL() const { return _modelURL; }
const QString& getAnimationURL() const { return _animationURL; }
float getAnimationFrameIndex() const { return _animationFrameIndex; }
bool getAnimationIsPlaying() const { return _animationIsPlaying; }
float getAnimationFPS() const { return _animationFPS; }
float getGlowLevel() const { return _glowLevel; }
// model related properties
void setColor(const xColor& value) { _color = value; _colorChanged = true; }
void setModelURL(const QString& url) { _modelURL = url; _modelURLChanged = true; }
void setRotation(const glm::quat& rotation) { _rotation = rotation; _rotationChanged = true; }
void setAnimationURL(const QString& url) { _animationURL = url; _animationURLChanged = true; }
void setAnimationFrameIndex(float value) { _animationFrameIndex = value; _animationFrameIndexChanged = true; }
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
private:
quint32 _id;
bool _idSet;
quint64 _lastEdited;
EntityTypes::EntityType_t _type;
glm::vec3 _position;
float _radius;
glm::quat _rotation;
bool _shouldBeDeleted;
bool _positionChanged;
bool _radiusChanged;
bool _rotationChanged;
bool _shouldBeDeletedChanged;
#if 0 // def HIDE_SUBCLASS_METHODS
xColor _color;
QString _modelURL;
QString _animationURL;
bool _animationIsPlaying;
float _animationFrameIndex;
float _animationFPS;
float _glowLevel;
QVector<SittingPoint> _sittingPoints;
bool _colorChanged;
bool _modelURLChanged;
bool _animationURLChanged;
bool _animationIsPlayingChanged;
bool _animationFrameIndexChanged;
bool _animationFPSChanged;
bool _glowLevelChanged;
#endif
bool _defaultSettings;
};
Q_DECLARE_METATYPE(EntityItemProperties);
QScriptValue EntityItemPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties);
void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemProperties& properties);
/// Abstract ID for editing model items. Used in EntityItem JS API - When models are created in the JS api, they are given a
/// local creatorTokenID, the actual id for the model is not known until the server responds to the creator with the
/// correct mapping. This class works with the scripting API an allows the developer to edit models they created.
class EntityItemID {
public:
EntityItemID() :
id(NEW_ENTITY), creatorTokenID(UNKNOWN_ENTITY_TOKEN), isKnownID(false) {
//qDebug() << "EntityItemID::EntityItemID()... isKnownID=" << isKnownID << "id=" << id << "creatorTokenID=" << creatorTokenID;
};
EntityItemID(uint32_t id, uint32_t creatorTokenID, bool isKnownID) :
id(id), creatorTokenID(creatorTokenID), isKnownID(isKnownID) {
//qDebug() << "EntityItemID::EntityItemID(uint32_t id, uint32_t creatorTokenID, bool isKnownID)... isKnownID=" << isKnownID << "id=" << id << "creatorTokenID=" << creatorTokenID;
};
EntityItemID(uint32_t id) :
id(id), creatorTokenID(UNKNOWN_ENTITY_TOKEN), isKnownID(true) {
//qDebug() << "EntityItemID::EntityItemID(uint32_t id)... isKnownID=" << isKnownID << "id=" << id << "creatorTokenID=" << creatorTokenID;
};
uint32_t id;
uint32_t creatorTokenID;
bool isKnownID;
};
inline bool operator<(const EntityItemID& a, const EntityItemID& b) {
return (a.id == b.id) ? (a.creatorTokenID < b.creatorTokenID) : (a.id < b.id);
}
inline bool operator==(const EntityItemID& a, const EntityItemID& b) {
if (a.id == UNKNOWN_ENTITY_ID && b.id == UNKNOWN_ENTITY_ID) {
return a.creatorTokenID == b.creatorTokenID;
}
return a.id == b.id;
}
inline uint qHash(const EntityItemID& a, uint seed) {
qint64 temp;
if (a.id == UNKNOWN_ENTITY_ID) {
temp = -a.creatorTokenID;
} else {
temp = a.id;
}
return qHash(temp, seed);
}
inline QDebug operator<<(QDebug debug, const EntityItemID& id) {
debug << "[ id:" << id.id << ", creatorTokenID:" << id.creatorTokenID << ", isKnownID:" << id.isKnownID << "]";
return debug;
}
Q_DECLARE_METATYPE(EntityItemID);
Q_DECLARE_METATYPE(QVector<EntityItemID>);
QScriptValue EntityItemIDtoScriptValue(QScriptEngine* engine, const EntityItemID& properties);
void EntityItemIDfromScriptValue(const QScriptValue &object, EntityItemID& properties);
/// EntityItem class - this is the actual model item class.
class EntityItem {
@ -287,9 +37,6 @@ public:
EntityItem(const EntityItemID& entityItemID);
EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
/// creates an NEW model from an model add or edit message data buffer
static EntityItem* fromEditPacket(const unsigned char* data, int length, int& processedBytes, EntityTree* tree, bool& valid);
virtual ~EntityItem();
virtual void somePureVirtualFunction() = 0;
@ -444,7 +191,7 @@ protected:
class ModelEntityItem : public EntityItem {
public:
ModelEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
EntityItem(entityItemID, properties) { };
EntityItem(entityItemID, properties) { _type = EntityTypes::Model; }
virtual void somePureVirtualFunction() { }; // allow this class to be constructed
};
@ -452,7 +199,7 @@ public:
class ParticleEntityItem : public EntityItem {
public:
ParticleEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
EntityItem(entityItemID, properties) { };
EntityItem(entityItemID, properties) { _type = EntityTypes::Particle; }
virtual void somePureVirtualFunction() { }; // allow this class to be constructed
};
@ -460,7 +207,7 @@ public:
class BoxEntityItem : public EntityItem {
public:
BoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
EntityItem(entityItemID, properties) { };
EntityItem(entityItemID, properties) { _type = EntityTypes::Box; }
virtual void somePureVirtualFunction() { }; // allow this class to be constructed
};
@ -468,7 +215,7 @@ public:
class SphereEntityItem : public EntityItem {
public:
SphereEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
EntityItem(entityItemID, properties) { };
EntityItem(entityItemID, properties) { _type = EntityTypes::Sphere; }
virtual void somePureVirtualFunction() { }; // allow this class to be constructed
};
@ -476,7 +223,7 @@ public:
class PlaneEntityItem : public EntityItem {
public:
PlaneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
EntityItem(entityItemID, properties) { };
EntityItem(entityItemID, properties) { _type = EntityTypes::Plane; }
virtual void somePureVirtualFunction() { }; // allow this class to be constructed
};
@ -484,7 +231,7 @@ public:
class CylinderEntityItem : public EntityItem {
public:
CylinderEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
EntityItem(entityItemID, properties) { };
EntityItem(entityItemID, properties) { _type = EntityTypes::Cylinder; }
virtual void somePureVirtualFunction() { }; // allow this class to be constructed
};
@ -492,7 +239,7 @@ public:
class PyramidEntityItem : public EntityItem {
public:
PyramidEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
EntityItem(entityItemID, properties) { };
EntityItem(entityItemID, properties) { _type = EntityTypes::Pyramid; }
virtual void somePureVirtualFunction() { }; // allow this class to be constructed
};

View file

@ -0,0 +1,32 @@
//
// EntityItemID.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 <QtCore/QObject>
#include <QDebug>
#include "EntityItemID.h"
QScriptValue EntityItemIDtoScriptValue(QScriptEngine* engine, const EntityItemID& id) {
QScriptValue obj = engine->newObject();
obj.setProperty("id", id.id);
obj.setProperty("creatorTokenID", id.creatorTokenID);
obj.setProperty("isKnownID", id.isKnownID);
return obj;
}
void EntityItemIDfromScriptValue(const QScriptValue &object, EntityItemID& id) {
id.id = object.property("id").toVariant().toUInt();
id.creatorTokenID = object.property("creatorTokenID").toVariant().toUInt();
id.isKnownID = object.property("isKnownID").toVariant().toBool();
}

View file

@ -0,0 +1,82 @@
//
// EntityItemID.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_EntityItemID_h
#define hifi_EntityItemID_h
#include <stdint.h>
#include <QtScript/QScriptEngine>
#include <QtCore/QObject>
const uint32_t NEW_ENTITY = 0xFFFFFFFF;
const uint32_t UNKNOWN_ENTITY_TOKEN = 0xFFFFFFFF;
const uint32_t UNKNOWN_ENTITY_ID = 0xFFFFFFFF;
/// Abstract ID for editing model items. Used in EntityItem JS API - When models are created in the JS api, they are given a
/// local creatorTokenID, the actual id for the model is not known until the server responds to the creator with the
/// correct mapping. This class works with the scripting API an allows the developer to edit models they created.
class EntityItemID {
public:
EntityItemID() :
id(NEW_ENTITY), creatorTokenID(UNKNOWN_ENTITY_TOKEN), isKnownID(false) {
//qDebug() << "EntityItemID::EntityItemID()... isKnownID=" << isKnownID << "id=" << id << "creatorTokenID=" << creatorTokenID;
};
EntityItemID(uint32_t id, uint32_t creatorTokenID, bool isKnownID) :
id(id), creatorTokenID(creatorTokenID), isKnownID(isKnownID) {
//qDebug() << "EntityItemID::EntityItemID(uint32_t id, uint32_t creatorTokenID, bool isKnownID)... isKnownID=" << isKnownID << "id=" << id << "creatorTokenID=" << creatorTokenID;
};
EntityItemID(uint32_t id) :
id(id), creatorTokenID(UNKNOWN_ENTITY_TOKEN), isKnownID(true) {
//qDebug() << "EntityItemID::EntityItemID(uint32_t id)... isKnownID=" << isKnownID << "id=" << id << "creatorTokenID=" << creatorTokenID;
};
uint32_t id;
uint32_t creatorTokenID;
bool isKnownID;
};
inline bool operator<(const EntityItemID& a, const EntityItemID& b) {
return (a.id == b.id) ? (a.creatorTokenID < b.creatorTokenID) : (a.id < b.id);
}
inline bool operator==(const EntityItemID& a, const EntityItemID& b) {
if (a.id == UNKNOWN_ENTITY_ID && b.id == UNKNOWN_ENTITY_ID) {
return a.creatorTokenID == b.creatorTokenID;
}
return a.id == b.id;
}
inline uint qHash(const EntityItemID& a, uint seed) {
qint64 temp;
if (a.id == UNKNOWN_ENTITY_ID) {
temp = -a.creatorTokenID;
} else {
temp = a.id;
}
return qHash(temp, seed);
}
inline QDebug operator<<(QDebug debug, const EntityItemID& id) {
debug << "[ id:" << id.id << ", creatorTokenID:" << id.creatorTokenID << ", isKnownID:" << id.isKnownID << "]";
return debug;
}
Q_DECLARE_METATYPE(EntityItemID);
Q_DECLARE_METATYPE(QVector<EntityItemID>);
QScriptValue EntityItemIDtoScriptValue(QScriptEngine* engine, const EntityItemID& properties);
void EntityItemIDfromScriptValue(const QScriptValue &object, EntityItemID& properties);
#endif // hifi_EntityItemID_h

View file

@ -0,0 +1,360 @@
//
// EntityItemProperties.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 <QDebug>
#include <QObject>
#include <RegisteredMetaTypes.h>
#include "EntityItemProperties.h"
EntityItemProperties::EntityItemProperties() :
_id(UNKNOWN_ENTITY_ID),
_idSet(false),
_lastEdited(usecTimestampNow()),
_type(EntityTypes::Base),
_position(0),
_radius(ENTITY_DEFAULT_RADIUS),
_rotation(ENTITY_DEFAULT_ROTATION),
_shouldBeDeleted(false),
_positionChanged(false),
_radiusChanged(false),
_rotationChanged(false),
_shouldBeDeletedChanged(false),
#if 0 //def HIDE_SUBCLASS_METHODS
_color(),
_modelURL(""),
_animationURL(""),
_animationIsPlaying(false),
_animationFrameIndex(0.0),
_animationFPS(ENTITY_DEFAULT_ANIMATION_FPS),
_glowLevel(0.0f),
_colorChanged(false),
_modelURLChanged(false),
_animationURLChanged(false),
_animationIsPlayingChanged(false),
_animationFrameIndexChanged(false),
_animationFPSChanged(false),
_glowLevelChanged(false),
#endif
_defaultSettings(true)
{
}
void EntityItemProperties::debugDump() const {
qDebug() << "EntityItemProperties...";
qDebug() << " _id=" << _id;
qDebug() << " _idSet=" << _idSet;
qDebug() << " _position=" << _position.x << "," << _position.y << "," << _position.z;
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) {
changedProperties += PROP_RADIUS;
}
if (_positionChanged) {
changedProperties += PROP_POSITION;
}
if (_rotationChanged) {
changedProperties += PROP_ROTATION;
}
if (_shouldBeDeletedChanged) {
changedProperties += PROP_SHOULD_BE_DELETED;
}
#if 0 //def HIDE_SUBCLASS_METHODS
if (_colorChanged) {
changedProperties += PROP_COLOR;
}
if (_modelURLChanged) {
changedProperties += PROP_MODEL_URL;
}
if (_animationURLChanged) {
changedProperties += PROP_ANIMATION_URL;
}
if (_animationIsPlayingChanged) {
changedProperties += PROP_ANIMATION_PLAYING;
}
if (_animationFrameIndexChanged) {
changedProperties += PROP_ANIMATION_FRAME_INDEX;
}
if (_animationFPSChanged) {
changedProperties += PROP_ANIMATION_FPS;
}
#endif
return changedProperties;
}
QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) const {
QScriptValue properties = engine->newObject();
if (_idSet) {
properties.setProperty("id", _id);
bool isKnownID = (_id != UNKNOWN_ENTITY_ID);
properties.setProperty("isKnownID", isKnownID);
qDebug() << "EntityItemProperties::copyToScriptValue()... isKnownID=" << isKnownID << "id=" << _id;
}
QScriptValue position = vec3toScriptValue(engine, _position);
properties.setProperty("position", position);
properties.setProperty("radius", _radius);
QScriptValue rotation = quatToScriptValue(engine, _rotation);
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);
properties.setProperty("animationURL", _animationURL);
properties.setProperty("animationIsPlaying", _animationIsPlaying);
properties.setProperty("animationFrameIndex", _animationFrameIndex);
properties.setProperty("animationFPS", _animationFPS);
properties.setProperty("glowLevel", _glowLevel);
// Sitting properties support
QScriptValue sittingPoints = engine->newObject();
for (int i = 0; i < _sittingPoints.size(); ++i) {
QScriptValue sittingPoint = engine->newObject();
sittingPoint.setProperty("name", _sittingPoints[i].name);
sittingPoint.setProperty("position", vec3toScriptValue(engine, _sittingPoints[i].position));
sittingPoint.setProperty("rotation", quatToScriptValue(engine, _sittingPoints[i].rotation));
sittingPoints.setProperty(i, sittingPoint);
}
sittingPoints.setProperty("length", _sittingPoints.size());
properties.setProperty("sittingPoints", sittingPoints);
#endif // HIDE_SUBCLASS_METHODS
return properties;
}
void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
QScriptValue typeScriptValue = object.property("type");
if (typeScriptValue.isValid()) {
QString typeName;
typeName = typeScriptValue.toVariant().toString();
_type = EntityTypes::getEntityTypeFromName(typeName);
}
QScriptValue position = object.property("position");
if (position.isValid()) {
QScriptValue x = position.property("x");
QScriptValue y = position.property("y");
QScriptValue z = position.property("z");
if (x.isValid() && y.isValid() && z.isValid()) {
glm::vec3 newPosition;
newPosition.x = x.toVariant().toFloat();
newPosition.y = y.toVariant().toFloat();
newPosition.z = z.toVariant().toFloat();
if (_defaultSettings || newPosition != _position) {
_position = newPosition;
_positionChanged = true;
}
}
}
QScriptValue radius = object.property("radius");
if (radius.isValid()) {
float newRadius;
newRadius = radius.toVariant().toFloat();
if (_defaultSettings || newRadius != _radius) {
_radius = newRadius;
_radiusChanged = true;
}
}
QScriptValue rotation = object.property("rotation");
if (rotation.isValid()) {
QScriptValue x = rotation.property("x");
QScriptValue y = rotation.property("y");
QScriptValue z = rotation.property("z");
QScriptValue w = rotation.property("w");
if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) {
glm::quat newRotation;
newRotation.x = x.toVariant().toFloat();
newRotation.y = y.toVariant().toFloat();
newRotation.z = z.toVariant().toFloat();
newRotation.w = w.toVariant().toFloat();
if (_defaultSettings || newRotation != _rotation) {
_rotation = newRotation;
_rotationChanged = true;
}
}
}
QScriptValue shouldBeDeleted = object.property("shouldBeDeleted");
if (shouldBeDeleted.isValid()) {
bool newShouldBeDeleted;
newShouldBeDeleted = shouldBeDeleted.toVariant().toBool();
if (_defaultSettings || newShouldBeDeleted != _shouldBeDeleted) {
_shouldBeDeleted = newShouldBeDeleted;
_shouldBeDeletedChanged = true;
}
}
#if 0 //def HIDE_SUBCLASS_METHODS
QScriptValue color = object.property("color");
if (color.isValid()) {
QScriptValue red = color.property("red");
QScriptValue green = color.property("green");
QScriptValue blue = color.property("blue");
if (red.isValid() && green.isValid() && blue.isValid()) {
xColor newColor;
newColor.red = red.toVariant().toInt();
newColor.green = green.toVariant().toInt();
newColor.blue = blue.toVariant().toInt();
if (_defaultSettings || (newColor.red != _color.red ||
newColor.green != _color.green ||
newColor.blue != _color.blue)) {
_color = newColor;
_colorChanged = true;
}
}
}
QScriptValue modelURL = object.property("modelURL");
if (modelURL.isValid()) {
QString newModelURL;
newModelURL = modelURL.toVariant().toString();
if (_defaultSettings || newModelURL != _modelURL) {
_modelURL = newModelURL;
_modelURLChanged = true;
}
}
QScriptValue animationURL = object.property("animationURL");
if (animationURL.isValid()) {
QString newAnimationURL;
newAnimationURL = animationURL.toVariant().toString();
if (_defaultSettings || newAnimationURL != _animationURL) {
_animationURL = newAnimationURL;
_animationURLChanged = true;
}
}
QScriptValue animationIsPlaying = object.property("animationIsPlaying");
if (animationIsPlaying.isValid()) {
bool newIsAnimationPlaying;
newIsAnimationPlaying = animationIsPlaying.toVariant().toBool();
if (_defaultSettings || newIsAnimationPlaying != _animationIsPlaying) {
_animationIsPlaying = newIsAnimationPlaying;
_animationIsPlayingChanged = true;
}
}
QScriptValue animationFrameIndex = object.property("animationFrameIndex");
if (animationFrameIndex.isValid()) {
float newFrameIndex;
newFrameIndex = animationFrameIndex.toVariant().toFloat();
if (_defaultSettings || newFrameIndex != _animationFrameIndex) {
_animationFrameIndex = newFrameIndex;
_animationFrameIndexChanged = true;
}
}
QScriptValue animationFPS = object.property("animationFPS");
if (animationFPS.isValid()) {
float newFPS;
newFPS = animationFPS.toVariant().toFloat();
if (_defaultSettings || newFPS != _animationFPS) {
_animationFPS = newFPS;
_animationFPSChanged = true;
}
}
QScriptValue glowLevel = object.property("glowLevel");
if (glowLevel.isValid()) {
float newGlowLevel;
newGlowLevel = glowLevel.toVariant().toFloat();
if (_defaultSettings || newGlowLevel != _glowLevel) {
_glowLevel = newGlowLevel;
_glowLevelChanged = true;
}
}
#endif
_lastEdited = usecTimestampNow();
}
QScriptValue EntityItemPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties) {
return properties.copyToScriptValue(engine);
}
void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemProperties& properties) {
properties.copyFromScriptValue(object);
}

View file

@ -0,0 +1,187 @@
//
// EntityItemProperties.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_EntityItemProperties_h
#define hifi_EntityItemProperties_h
#define HIDE_SUBCLASS_METHODS 1
#include <stdint.h>
#include <glm/glm.hpp>
#include <QtScript/QScriptEngine>
#include <QtCore/QObject>
#include <QVector>
#include <QString>
#include <AACube.h>
#include <FBXReader.h> // for SittingPoint
#include <PropertyFlags.h>
#include <OctreeConstants.h>
#include "EntityItemID.h"
#include "EntityTypes.h"
const uint16_t ENTITY_PACKET_CONTAINS_RADIUS = 1;
const uint16_t ENTITY_PACKET_CONTAINS_POSITION = 2;
const uint16_t ENTITY_PACKET_CONTAINS_COLOR = 4;
const uint16_t ENTITY_PACKET_CONTAINS_SHOULDDIE = 8;
const uint16_t ENTITY_PACKET_CONTAINS_MODEL_URL = 16;
const uint16_t ENTITY_PACKET_CONTAINS_ROTATION = 32;
const uint16_t ENTITY_PACKET_CONTAINS_ANIMATION_URL = 64;
const uint16_t ENTITY_PACKET_CONTAINS_ANIMATION_PLAYING = 128;
const uint16_t ENTITY_PACKET_CONTAINS_ANIMATION_FRAME = 256;
const uint16_t ENTITY_PACKET_CONTAINS_ANIMATION_FPS = 512;
const float ENTITY_DEFAULT_RADIUS = 0.1f / TREE_SCALE;
const float ENTITY_MINIMUM_ELEMENT_SIZE = (1.0f / 100000.0f) / TREE_SCALE; // smallest size container
const QString ENTITY_DEFAULT_MODEL_URL("");
const glm::quat ENTITY_DEFAULT_ROTATION;
const QString ENTITY_DEFAULT_ANIMATION_URL("");
const float ENTITY_DEFAULT_ANIMATION_FPS = 30.0f;
// PropertyFlags support
enum EntityPropertyList {
PROP_PAGED_PROPERTY,
PROP_CUSTOM_PROPERTIES_INCLUDED,
PROP_VISIBLE,
PROP_POSITION,
PROP_RADIUS,
PROP_ROTATION,
PROP_SCRIPT,
PROP_MODEL_URL,
PROP_COLOR,
PROP_ANIMATION_URL,
PROP_ANIMATION_FPS,
PROP_ANIMATION_FRAME_INDEX,
PROP_ANIMATION_PLAYING,
PROP_SHOULD_BE_DELETED,
PROP_LAST_ITEM = PROP_SHOULD_BE_DELETED
};
typedef PropertyFlags<EntityPropertyList> EntityPropertyFlags;
/// A collection of properties of an entity item used in the scripting API. Translates between the actual properties of an
/// entity and a JavaScript style hash/QScriptValue storing a set of properties. Used in scripting to set/get the complete
/// set of entity item properties via JavaScript hashes/QScriptValues
/// 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
public:
EntityItemProperties();
virtual ~EntityItemProperties() { };
virtual QScriptValue copyToScriptValue(QScriptEngine* engine) const;
virtual void copyFromScriptValue(const QScriptValue& object);
// 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
void setIsUnknownID() { _id = UNKNOWN_ENTITY_ID; _idSet = true; }
glm::vec3 getMinimumPointMeters() const { return _position - glm::vec3(_radius, _radius, _radius); }
glm::vec3 getMaximumPointMeters() const { return _position + glm::vec3(_radius, _radius, _radius); }
AACube getAACubeMeters() const { return AACube(getMinimumPointMeters(), getMaxDimension()); } /// AACube in meter units
glm::vec3 getMinimumPointTreeUnits() const { return getMinimumPointMeters() / (float)TREE_SCALE; }
glm::vec3 getMaximumPointTreeUnits() const { return getMaximumPointMeters() / (float)TREE_SCALE; }
AACube getAACubeTreeUnits() const { return AACube(getMinimumPointMeters()/(float)TREE_SCALE, getMaxDimension()/(float)TREE_SCALE); } /// AACube in domain scale units (0.0 - 1.0)
void debugDump() const;
// properties of all entities
EntityTypes::EntityType_t getType() const { return _type; }
const glm::vec3& getPosition() const { return _position; }
float getRadius() const { return _radius; }
float getMaxDimension() const { return _radius * 2.0f; }
glm::vec3 getDimensions() const { return glm::vec3(_radius, _radius, _radius) * 2.0f; }
const glm::quat& getRotation() const { return _rotation; }
bool getShouldBeDeleted() const { return _shouldBeDeleted; }
void setType(EntityTypes::EntityType_t type) { _type = type; }
/// set position in meter units
void setPosition(const glm::vec3& value) { _position = value; _positionChanged = true; }
void setRadius(float value) { _radius = value; _radiusChanged = true; }
void setRotation(const glm::quat& rotation) { _rotation = rotation; _rotationChanged = true; }
void setShouldBeDeleted(bool shouldBeDeleted) { _shouldBeDeleted = shouldBeDeleted; _shouldBeDeletedChanged = true; }
// NOTE: how do we handle _defaultSettings???
bool containsBoundsProperties() const { return (_positionChanged || _radiusChanged); }
#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; }
const QString& getAnimationURL() const { return _animationURL; }
float getAnimationFrameIndex() const { return _animationFrameIndex; }
bool getAnimationIsPlaying() const { return _animationIsPlaying; }
float getAnimationFPS() const { return _animationFPS; }
float getGlowLevel() const { return _glowLevel; }
// model related properties
void setColor(const xColor& value) { _color = value; _colorChanged = true; }
void setModelURL(const QString& url) { _modelURL = url; _modelURLChanged = true; }
void setAnimationURL(const QString& url) { _animationURL = url; _animationURLChanged = true; }
void setAnimationFrameIndex(float value) { _animationFrameIndex = value; _animationFrameIndexChanged = true; }
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
private:
quint32 _id;
bool _idSet;
quint64 _lastEdited;
EntityTypes::EntityType_t _type;
glm::vec3 _position;
float _radius;
glm::quat _rotation;
bool _shouldBeDeleted;
bool _positionChanged;
bool _radiusChanged;
bool _rotationChanged;
bool _shouldBeDeletedChanged;
#ifdef HIDE_SUBCLASS_METHODS
xColor _color;
QString _modelURL;
QString _animationURL;
bool _animationIsPlaying;
float _animationFrameIndex;
float _animationFPS;
float _glowLevel;
QVector<SittingPoint> _sittingPoints;
bool _colorChanged;
bool _modelURLChanged;
bool _animationURLChanged;
bool _animationIsPlayingChanged;
bool _animationFrameIndexChanged;
bool _animationFPSChanged;
bool _glowLevelChanged;
#endif
bool _defaultSettings;
};
Q_DECLARE_METATYPE(EntityItemProperties);
QScriptValue EntityItemPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties);
void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemProperties& properties);
#endif // hifi_EntityItemProperties_h

View file

@ -8,6 +8,8 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// TODO: How will we handle collision callbacks with Entities
//
#ifndef hifi_EntityScriptingInterface_h
#define hifi_EntityScriptingInterface_h
@ -21,6 +23,10 @@
#include "EntityEditPacketSender.h"
class EntityTree;
class RayToEntityIntersectionResult {
public:
RayToEntityIntersectionResult();
@ -91,10 +97,6 @@ public slots:
Q_INVOKABLE void dumpTree() const;
signals:
void modelCollisionWithVoxel(const EntityItemID& entityID, const VoxelDetail& voxel, const CollisionInfo& collision);
void modelCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const CollisionInfo& collision);
private:
void queueEntityMessage(PacketType packetType, EntityItemID entityID, const EntityItemProperties& properties);

View file

@ -797,7 +797,7 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char
EntityItemID entityItemID;
EntityItemProperties properties;
bool validEditPacket = EntityTypes::decodEntityEditPacket(editData, maxLength,
bool validEditPacket = EntityTypes::decodeEntityEditPacket(editData, maxLength,
processedBytes, entityItemID, properties);
// If we got a valid edit packet, then it could be a new entity or it could be an update to
@ -816,20 +816,8 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char
}
}
}
#if 0 ////// OLD CODE...
bool isValid = false;
EntityItem* newEntity = NULL; // EntityItem::fromEditPacket(editData, maxLength, processedBytes, this, isValid);
if (isValid) {
storeEntity(newEntity, senderNode);
if (newEntity.isNewlyCreated()) {
notifyNewlyCreatedEntity(newEntity, senderNode);
}
}
#endif
} break;
break;
}
default:
processedBytes = 0;

View file

@ -0,0 +1,311 @@
//
// EntityTypes.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 <QtCore/QObject>
#include <ByteCountCoding.h>
#include "EntityItem.h"
#include "EntityItemProperties.h"
#include "EntityTypes.h"
QHash<EntityTypes::EntityType_t, QString> EntityTypes::_typeNameHash;
const QString UNKNOWN_EntityType_t_NAME = "Unknown";
const QString& EntityTypes::getEntityTypeName(EntityType_t entityType) {
QHash<EntityType_t, QString>::iterator matchedTypeName = _typeNameHash.find(entityType);
return matchedTypeName != _typeNameHash.end() ? matchedTypeName.value() : UNKNOWN_EntityType_t_NAME;
}
bool EntityTypes::registerEntityType(EntityType_t entityType, const QString& name) {
_typeNameHash.insert(entityType, name);
return true;
}
EntityTypes::EntityType_t EntityTypes::getEntityTypeFromName(const QString& name) {
return Base; // TODO: support registration
}
EntityItem* EntityTypes::constructEntityItem(EntityType_t entityType, const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItem* newEntityItem = NULL;
// switch statement for now, needs to support registration of constructor
switch (entityType) {
// Base, // ??? not supported?
case Model:
newEntityItem = new ModelEntityItem(entityID, properties);
break;
case Particle:
newEntityItem = new ParticleEntityItem(entityID, properties);
break;
case Box:
newEntityItem = new BoxEntityItem(entityID, properties);
break;
case Sphere:
newEntityItem = new SphereEntityItem(entityID, properties);
break;
case Plane:
newEntityItem = new PlaneEntityItem(entityID, properties);
break;
case Cylinder:
newEntityItem = new CylinderEntityItem(entityID, properties);
break;
case Pyramid:
newEntityItem = new PyramidEntityItem(entityID, properties);
break;
default:
newEntityItem = new ModelEntityItem(entityID, properties);
break;
}
return newEntityItem;
}
EntityItem* EntityTypes::constructEntityItem(const unsigned char* data, int bytesToRead) {
return NULL; // TODO Implement this for real!
}
// TODO:
// how to handle lastEdited?
// how to handle lastUpdated?
// consider handling case where no properties are included... we should just ignore this packet...
bool EntityTypes::decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes,
EntityItemID& entityID, EntityItemProperties& properties) {
bool valid = false;
bool wantDebug = false;
if (wantDebug) {
qDebug() << "EntityItem EntityItem::decodeEntityEditPacket() bytesToRead=" << bytesToRead;
}
const unsigned char* dataAt = data;
processedBytes = 0;
// the first part of the data is an octcode, this is a required element of the edit packet format, but we don't
// actually use it, we do need to skip it and read to the actual data we care about.
int octets = numberOfThreeBitSectionsInCode(data);
int bytesToReadOfOctcode = bytesRequiredForCodeLength(octets);
if (wantDebug) {
qDebug() << "EntityItem EntityItem::decodeEntityEditPacket() bytesToReadOfOctcode=" << bytesToReadOfOctcode;
}
// we don't actually do anything with this octcode...
dataAt += bytesToReadOfOctcode;
processedBytes += bytesToReadOfOctcode;
// Edit packets have a last edited time stamp immediately following the octcode.
// NOTE: the edit times have been set by the editor to match out clock, so we don't need to adjust
// these times for clock skew at this point.
quint64 lastEdited;
memcpy(&lastEdited, dataAt, sizeof(lastEdited));
dataAt += sizeof(lastEdited);
processedBytes += sizeof(lastEdited);
// encoded id
QByteArray encodedID((const char*)dataAt, (bytesToRead - processedBytes));
ByteCountCoded<quint32> idCoder = encodedID;
quint32 editID = idCoder;
encodedID = idCoder; // determine true bytesToRead
dataAt += encodedID.size();
processedBytes += encodedID.size();
if (wantDebug) {
qDebug() << "EntityItem EntityItem::decodeEntityEditPacket() editID=" << editID;
}
bool isNewEntityItem = (editID == NEW_ENTITY);
if (isNewEntityItem) {
// If this is a NEW_ENTITY, then we assume that there's an additional uint32_t creatorToken, that
// we want to send back to the creator as an map to the actual id
QByteArray encodedToken((const char*)dataAt, (bytesToRead - processedBytes));
ByteCountCoded<quint32> tokenCoder = encodedToken;
quint32 creatorTokenID = tokenCoder;
encodedToken = tokenCoder; // determine true bytesToRead
dataAt += encodedToken.size();
processedBytes += encodedToken.size();
//newEntityItem.setCreatorTokenID(creatorTokenID);
//newEntityItem._newlyCreated = true;
entityID.id = NEW_ENTITY;
entityID.creatorTokenID = creatorTokenID;
entityID.isKnownID = false;
valid = true;
} else {
entityID.id = editID;
entityID.creatorTokenID = UNKNOWN_ENTITY_TOKEN;
entityID.isKnownID = true;
valid = true;
}
// Entity Type...
QByteArray encodedType((const char*)dataAt, (bytesToRead - processedBytes));
ByteCountCoded<quint32> typeCoder = encodedType;
quint32 entityTypeCode = typeCoder;
properties.setType((EntityTypes::EntityType_t)entityTypeCode);
encodedType = typeCoder; // determine true bytesToRead
dataAt += encodedType.size();
processedBytes += encodedType.size();
// Update Delta - when was this item updated relative to last edit... this really should be 0
// TODO: Should we get rid of this in this in edit packets, since this has to always be 0?
// TODO: do properties need to handle lastupdated???
// last updated is stored as ByteCountCoded delta from lastEdited
QByteArray encodedUpdateDelta((const char*)dataAt, (bytesToRead - processedBytes));
ByteCountCoded<quint64> updateDeltaCoder = encodedUpdateDelta;
quint64 updateDelta = updateDeltaCoder;
quint64 lastUpdated = lastEdited + updateDelta; // don't adjust for clock skew since we already did that for lastEdited
encodedUpdateDelta = updateDeltaCoder; // determine true bytesToRead
dataAt += encodedUpdateDelta.size();
processedBytes += encodedUpdateDelta.size();
// Property Flags...
QByteArray encodedPropertyFlags((const char*)dataAt, (bytesToRead - processedBytes));
EntityPropertyFlags propertyFlags = encodedPropertyFlags;
dataAt += propertyFlags.getEncodedLength();
processedBytes += propertyFlags.getEncodedLength();
// PROP_POSITION
if (propertyFlags.getHasProperty(PROP_POSITION)) {
glm::vec3 position;
memcpy(&position, dataAt, sizeof(position));
dataAt += sizeof(position);
processedBytes += sizeof(position);
properties.setPosition(position);
}
// PROP_RADIUS
if (propertyFlags.getHasProperty(PROP_RADIUS)) {
float radius;
memcpy(&radius, dataAt, sizeof(radius));
dataAt += sizeof(radius);
processedBytes += sizeof(radius);
properties.setRadius(radius);
}
// PROP_ROTATION
if (propertyFlags.getHasProperty(PROP_ROTATION)) {
glm::quat rotation;
int bytes = unpackOrientationQuatFromBytes(dataAt, rotation);
dataAt += bytes;
processedBytes += bytes;
properties.setRotation(rotation);
}
// PROP_SHOULD_BE_DELETED
if (propertyFlags.getHasProperty(PROP_SHOULD_BE_DELETED)) {
bool shouldBeDeleted;
memcpy(&shouldBeDeleted, dataAt, sizeof(shouldBeDeleted));
dataAt += sizeof(shouldBeDeleted);
processedBytes += sizeof(shouldBeDeleted);
properties.setShouldBeDeleted(shouldBeDeleted);
}
// PROP_SCRIPT
// script would go here...
#ifdef HIDE_SUBCLASS_METHODS
// PROP_COLOR
if (propertyFlags.getHasProperty(PROP_COLOR)) {
xColor color;
memcpy(&color, dataAt, sizeof(color));
dataAt += sizeof(color);
processedBytes += sizeof(color);
properties.setColor(color);
}
// PROP_MODEL_URL
if (propertyFlags.getHasProperty(PROP_MODEL_URL)) {
// TODO: fix to new format...
uint16_t modelURLbytesToRead;
memcpy(&modelURLbytesToRead, dataAt, sizeof(modelURLbytesToRead));
dataAt += sizeof(modelURLbytesToRead);
processedBytes += sizeof(modelURLbytesToRead);
QString modelURLString((const char*)dataAt);
dataAt += modelURLbytesToRead;
processedBytes += modelURLbytesToRead;
properties.setModelURL(modelURLString);
}
// PROP_ANIMATION_URL
if (propertyFlags.getHasProperty(PROP_ANIMATION_URL)) {
// animationURL
uint16_t animationURLbytesToRead;
memcpy(&animationURLbytesToRead, dataAt, sizeof(animationURLbytesToRead));
dataAt += sizeof(animationURLbytesToRead);
processedBytes += sizeof(animationURLbytesToRead);
QString animationURLString((const char*)dataAt);
dataAt += animationURLbytesToRead;
processedBytes += animationURLbytesToRead;
properties.setAnimationURL(animationURLString);
}
// PROP_ANIMATION_FPS
if (propertyFlags.getHasProperty(PROP_ANIMATION_FPS)) {
float animationFPS;
memcpy(&animationFPS, dataAt, sizeof(animationFPS));
dataAt += sizeof(animationFPS);
processedBytes += sizeof(animationFPS);
properties.setAnimationFPS(animationFPS);
}
// PROP_ANIMATION_FRAME_INDEX
if (propertyFlags.getHasProperty(PROP_ANIMATION_FRAME_INDEX)) {
float animationFrameIndex; // we keep this as a float and round to int only when we need the exact index
memcpy(&animationFrameIndex, dataAt, sizeof(animationFrameIndex));
dataAt += sizeof(animationFrameIndex);
processedBytes += sizeof(animationFrameIndex);
properties.setAnimationFrameIndex(animationFrameIndex);
}
// PROP_ANIMATION_PLAYING
if (propertyFlags.getHasProperty(PROP_ANIMATION_PLAYING)) {
bool animationIsPlaying;
memcpy(&animationIsPlaying, dataAt, sizeof(animationIsPlaying));
dataAt += sizeof(animationIsPlaying);
processedBytes += sizeof(animationIsPlaying);
properties.setAnimationIsPlaying(animationIsPlaying);
}
#endif
const bool wantDebugging = false;
if (wantDebugging) {
qDebug("EntityItem::fromEditPacket()...");
qDebug() << " EntityItem id in packet:" << editID;
//newEntityItem.debugDump();
}
return valid;
}
bool registered = EntityTypes::registerEntityType(EntityTypes::Base, "Base")
&& EntityTypes::registerEntityType(EntityTypes::Model, "Model"); // TODO: move this to model subclass

View file

@ -0,0 +1,50 @@
//
// EntityTypes.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_EntityTypes_h
#define hifi_EntityTypes_h
#include <stdint.h>
#include <QHash>
#include <QString>
class EntityItem;
class EntityItemID;
class EntityItemProperties;
class EntityTypes {
public:
typedef enum EntityType {
Base,
Model,
Particle,
Box,
Sphere,
Plane,
Cylinder,
Pyramid
} EntityType_t;
static const QString& getEntityTypeName(EntityType_t entityType);
static bool registerEntityType(EntityType_t entityType, const QString& name);
static EntityTypes::EntityType_t getEntityTypeFromName(const QString& name);
static EntityItem* constructEntityItem(EntityType_t entityType, const EntityItemID& entityID, const EntityItemProperties& properties);
static EntityItem* constructEntityItem(const unsigned char* data, int bytesToRead);
static bool decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes,
EntityItemID& entityID, EntityItemProperties& properties);
private:
static QHash<EntityType_t, QString> _typeNameHash;
};
#endif // hifi_EntityTypes_h