mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 14:58:03 +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 "EntityItem.h"
|
||||||
#include "EntityTree.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;
|
uint32_t EntityItem::_nextID = 0;
|
||||||
|
|
||||||
// for locally created models
|
// for locally created models
|
||||||
|
@ -827,241 +759,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
||||||
return bytesRead;
|
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 {
|
void EntityItem::debugDump() const {
|
||||||
qDebug() << "EntityItem id:" << getEntityItemID();
|
qDebug() << "EntityItem id:" << getEntityItemID();
|
||||||
qDebug(" edited ago:%f", getEditedAgo());
|
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._id = getID();
|
||||||
properties._idSet = true;
|
properties._idSet = true;
|
||||||
|
|
||||||
|
properties._type = getType();
|
||||||
|
|
||||||
properties._position = getPosition() * (float) TREE_SCALE;
|
properties._position = getPosition() * (float) TREE_SCALE;
|
||||||
properties._radius = getRadius() * (float) TREE_SCALE;
|
properties._radius = getRadius() * (float) TREE_SCALE;
|
||||||
properties._rotation = getRotation();
|
properties._rotation = getRotation();
|
||||||
|
@ -1726,6 +1422,7 @@ EntityItemProperties::EntityItemProperties() :
|
||||||
_id(UNKNOWN_ENTITY_ID),
|
_id(UNKNOWN_ENTITY_ID),
|
||||||
_idSet(false),
|
_idSet(false),
|
||||||
_lastEdited(usecTimestampNow()),
|
_lastEdited(usecTimestampNow()),
|
||||||
|
_type(EntityTypes::Base),
|
||||||
|
|
||||||
_position(0),
|
_position(0),
|
||||||
_radius(ENTITY_DEFAULT_RADIUS),
|
_radius(ENTITY_DEFAULT_RADIUS),
|
||||||
|
@ -1908,6 +1605,13 @@ qDebug() << "EntityItemProperties::copyToScriptValue()... isKnownID=" << isKnown
|
||||||
|
|
||||||
void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
|
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");
|
QScriptValue position = object.property("position");
|
||||||
if (position.isValid()) {
|
if (position.isValid()) {
|
||||||
QScriptValue x = position.property("x");
|
QScriptValue x = position.property("x");
|
||||||
|
@ -2055,22 +1759,3 @@ QScriptValue EntityItemPropertiesToScriptValue(QScriptEngine* engine, const Enti
|
||||||
void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemProperties& properties) {
|
void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemProperties& properties) {
|
||||||
properties.copyFromScriptValue(object);
|
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
|
// EntityItem.h
|
||||||
// libraries/models/src
|
// libraries/entities/src
|
||||||
//
|
//
|
||||||
// Created by Brad Hefta-Gaub on 12/4/13.
|
// Created by Brad Hefta-Gaub on 12/4/13.
|
||||||
// Copyright 2013 High Fidelity, Inc.
|
// Copyright 2013 High Fidelity, Inc.
|
||||||
|
@ -18,266 +18,16 @@
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
#include <QtScript/QScriptEngine>
|
#include <AnimationCache.h> // for Animation, AnimationCache, and AnimationPointer classes
|
||||||
#include <QtCore/QObject>
|
#include <Octree.h> // for EncodeBitstreamParams class
|
||||||
|
#include <OctreeElement.h> // for OctreeElement::AppendState
|
||||||
#include <AnimationCache.h>
|
|
||||||
#include <CollisionInfo.h>
|
|
||||||
#include <OctreePacketData.h>
|
#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 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.
|
/// EntityItem class - this is the actual model item class.
|
||||||
class EntityItem {
|
class EntityItem {
|
||||||
|
@ -287,9 +37,6 @@ public:
|
||||||
EntityItem(const EntityItemID& entityItemID);
|
EntityItem(const EntityItemID& entityItemID);
|
||||||
EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
|
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 ~EntityItem();
|
||||||
|
|
||||||
virtual void somePureVirtualFunction() = 0;
|
virtual void somePureVirtualFunction() = 0;
|
||||||
|
@ -444,7 +191,7 @@ protected:
|
||||||
class ModelEntityItem : public EntityItem {
|
class ModelEntityItem : public EntityItem {
|
||||||
public:
|
public:
|
||||||
ModelEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
|
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
|
virtual void somePureVirtualFunction() { }; // allow this class to be constructed
|
||||||
};
|
};
|
||||||
|
@ -452,7 +199,7 @@ public:
|
||||||
class ParticleEntityItem : public EntityItem {
|
class ParticleEntityItem : public EntityItem {
|
||||||
public:
|
public:
|
||||||
ParticleEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
|
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
|
virtual void somePureVirtualFunction() { }; // allow this class to be constructed
|
||||||
};
|
};
|
||||||
|
@ -460,7 +207,7 @@ public:
|
||||||
class BoxEntityItem : public EntityItem {
|
class BoxEntityItem : public EntityItem {
|
||||||
public:
|
public:
|
||||||
BoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
|
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
|
virtual void somePureVirtualFunction() { }; // allow this class to be constructed
|
||||||
};
|
};
|
||||||
|
@ -468,7 +215,7 @@ public:
|
||||||
class SphereEntityItem : public EntityItem {
|
class SphereEntityItem : public EntityItem {
|
||||||
public:
|
public:
|
||||||
SphereEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
|
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
|
virtual void somePureVirtualFunction() { }; // allow this class to be constructed
|
||||||
};
|
};
|
||||||
|
@ -476,7 +223,7 @@ public:
|
||||||
class PlaneEntityItem : public EntityItem {
|
class PlaneEntityItem : public EntityItem {
|
||||||
public:
|
public:
|
||||||
PlaneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
|
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
|
virtual void somePureVirtualFunction() { }; // allow this class to be constructed
|
||||||
};
|
};
|
||||||
|
@ -484,7 +231,7 @@ public:
|
||||||
class CylinderEntityItem : public EntityItem {
|
class CylinderEntityItem : public EntityItem {
|
||||||
public:
|
public:
|
||||||
CylinderEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
|
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
|
virtual void somePureVirtualFunction() { }; // allow this class to be constructed
|
||||||
};
|
};
|
||||||
|
@ -492,7 +239,7 @@ public:
|
||||||
class PyramidEntityItem : public EntityItem {
|
class PyramidEntityItem : public EntityItem {
|
||||||
public:
|
public:
|
||||||
PyramidEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
|
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
|
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.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// 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
|
#ifndef hifi_EntityScriptingInterface_h
|
||||||
#define hifi_EntityScriptingInterface_h
|
#define hifi_EntityScriptingInterface_h
|
||||||
|
@ -21,6 +23,10 @@
|
||||||
|
|
||||||
#include "EntityEditPacketSender.h"
|
#include "EntityEditPacketSender.h"
|
||||||
|
|
||||||
|
|
||||||
|
class EntityTree;
|
||||||
|
|
||||||
|
|
||||||
class RayToEntityIntersectionResult {
|
class RayToEntityIntersectionResult {
|
||||||
public:
|
public:
|
||||||
RayToEntityIntersectionResult();
|
RayToEntityIntersectionResult();
|
||||||
|
@ -91,10 +97,6 @@ public slots:
|
||||||
|
|
||||||
Q_INVOKABLE void dumpTree() const;
|
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:
|
private:
|
||||||
void queueEntityMessage(PacketType packetType, EntityItemID entityID, const EntityItemProperties& properties);
|
void queueEntityMessage(PacketType packetType, EntityItemID entityID, const EntityItemProperties& properties);
|
||||||
|
|
||||||
|
|
|
@ -797,7 +797,7 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char
|
||||||
EntityItemID entityItemID;
|
EntityItemID entityItemID;
|
||||||
EntityItemProperties properties;
|
EntityItemProperties properties;
|
||||||
|
|
||||||
bool validEditPacket = EntityTypes::decodEntityEditPacket(editData, maxLength,
|
bool validEditPacket = EntityTypes::decodeEntityEditPacket(editData, maxLength,
|
||||||
processedBytes, entityItemID, properties);
|
processedBytes, entityItemID, properties);
|
||||||
|
|
||||||
// If we got a valid edit packet, then it could be a new entity or it could be an update to
|
// 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
#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;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
processedBytes = 0;
|
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