mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 11:45:36 +02:00
splitting up a bunch of Entity classes into different files
This commit is contained in:
parent
5869039bf3
commit
1125cb183e
10 changed files with 1055 additions and 611 deletions
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
32
libraries/entities/src/EntityItemID.cpp
Normal file
32
libraries/entities/src/EntityItemID.cpp
Normal 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();
|
||||
}
|
||||
|
||||
|
||||
|
82
libraries/entities/src/EntityItemID.h
Normal file
82
libraries/entities/src/EntityItemID.h
Normal 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
|
360
libraries/entities/src/EntityItemProperties.cpp
Normal file
360
libraries/entities/src/EntityItemProperties.cpp
Normal 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);
|
||||
}
|
187
libraries/entities/src/EntityItemProperties.h
Normal file
187
libraries/entities/src/EntityItemProperties.h
Normal 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
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
311
libraries/entities/src/EntityTypes.cpp
Normal file
311
libraries/entities/src/EntityTypes.cpp
Normal 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
|
||||
|
||||
|
50
libraries/entities/src/EntityTypes.h
Normal file
50
libraries/entities/src/EntityTypes.h
Normal 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
|
Loading…
Reference in a new issue