mirror of
https://github.com/Armored-Dragon/overte.git
synced 2025-03-11 16:13:16 +01:00
registration of multiple entity types: Model and Box
This commit is contained in:
parent
273853ef24
commit
e9db4fd120
13 changed files with 644 additions and 37 deletions
|
@ -903,12 +903,13 @@ function controller(wichSide) {
|
|||
MyAvatar.detachOne(attachments[attachmentIndex].modelURL, attachments[attachmentIndex].jointName);
|
||||
|
||||
newProperties = {
|
||||
position: Vec3.sum(MyAvatar.getJointPosition(attachments[attachmentIndex].jointName),
|
||||
Vec3.multiplyQbyV(MyAvatar.getJointCombinedRotation(attachments[attachmentIndex].jointName), attachments[attachmentIndex].translation)),
|
||||
rotation: Quat.multiply(MyAvatar.getJointCombinedRotation(attachments[attachmentIndex].jointName),
|
||||
attachments[attachmentIndex].rotation),
|
||||
radius: attachments[attachmentIndex].scale / 2.0,
|
||||
modelURL: attachments[attachmentIndex].modelURL
|
||||
type: "Model",
|
||||
position: Vec3.sum(MyAvatar.getJointPosition(attachments[attachmentIndex].jointName),
|
||||
Vec3.multiplyQbyV(MyAvatar.getJointCombinedRotation(attachments[attachmentIndex].jointName), attachments[attachmentIndex].translation)),
|
||||
rotation: Quat.multiply(MyAvatar.getJointCombinedRotation(attachments[attachmentIndex].jointName),
|
||||
attachments[attachmentIndex].rotation),
|
||||
radius: attachments[attachmentIndex].scale / 2.0,
|
||||
modelURL: attachments[attachmentIndex].modelURL
|
||||
};
|
||||
|
||||
print(">>>>> CALLING >>>>> newModel = Entities.addEntity(newProperties);");
|
||||
|
@ -1208,7 +1209,9 @@ function mousePressEvent(event) {
|
|||
|
||||
if (position.x > 0 && position.y > 0 && position.z > 0) {
|
||||
print(">>>>> CALLING >>>>> Entities.addEntity(newProperties);");
|
||||
Entities.addEntity({ position: position,
|
||||
Entities.addEntity({
|
||||
type: "Model",
|
||||
position: position,
|
||||
radius: radiusDefault,
|
||||
modelURL: url
|
||||
});
|
||||
|
@ -1226,7 +1229,9 @@ print(">>>>> CALLING >>>>> Entities.addEntity(newProperties);");
|
|||
|
||||
if (position.x > 0 && position.y > 0 && position.z > 0) {
|
||||
print(">>>>> CALLING >>>>> Entities.addEntity(newProperties);");
|
||||
Entities.addEntity({ position: position,
|
||||
Entities.addEntity({
|
||||
type: "Model",
|
||||
position: position,
|
||||
radius: radiusDefault,
|
||||
modelURL: url
|
||||
});
|
||||
|
|
|
@ -374,7 +374,16 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
|
|||
#endif
|
||||
} else {
|
||||
//glColor3ub(entityItem->getColor()[RED_INDEX],entityItem->getColor()[GREEN_INDEX],entityItem.getColor()[BLUE_INDEX]);
|
||||
glColor3f(1.0f, 0.0f, 0.0f);
|
||||
|
||||
EntityTypes::EntityType_t type = entityItem->getType();
|
||||
|
||||
//qDebug() << "rendering type=" << type;
|
||||
|
||||
if (type == EntityTypes::Model) {
|
||||
glColor3f(1.0f, 0.0f, 0.0f);
|
||||
} else {
|
||||
glColor3f(0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glutSolidSphere(radius, 15, 15);
|
||||
|
|
476
libraries/entities/src/BoxEntityItem.cpp
Normal file
476
libraries/entities/src/BoxEntityItem.cpp
Normal file
|
@ -0,0 +1,476 @@
|
|||
//
|
||||
// BoxEntityItem.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 <ByteCountCoding.h>
|
||||
|
||||
#include "EntityTree.h"
|
||||
#include "EntityTreeElement.h"
|
||||
#include "BoxEntityItem.h"
|
||||
|
||||
|
||||
//static bool registerBox = EntityTypes::registerEntityType(EntityTypes::Box, "Box", BoxEntityItem::factory);
|
||||
|
||||
|
||||
EntityItem* BoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
qDebug() << "BoxEntityItem::factory(const EntityItemID& entityItemID, const EntityItemProperties& properties)...";
|
||||
return new BoxEntityItem(entityID, properties);
|
||||
}
|
||||
|
||||
// our non-pure virtual subclass for now...
|
||||
BoxEntityItem::BoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
|
||||
EntityItem(entityItemID, properties)
|
||||
{
|
||||
qDebug() << "BoxEntityItem::BoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties)...";
|
||||
_type = EntityTypes::Box;
|
||||
|
||||
qDebug() << "BoxEntityItem::BoxEntityItem() properties.getModelURL()=" << properties.getModelURL();
|
||||
|
||||
qDebug() << "BoxEntityItem::BoxEntityItem() calling setProperties()";
|
||||
setProperties(properties);
|
||||
|
||||
|
||||
}
|
||||
|
||||
EntityItemProperties BoxEntityItem::getProperties() const {
|
||||
qDebug() << "BoxEntityItem::getProperties()... <<<<<<<<<<<<<<<< <<<<<<<<<<<<<<<<<<<<<<<<<";
|
||||
|
||||
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
|
||||
|
||||
properties._color = getXColor();
|
||||
properties._colorChanged = false;
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
void BoxEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) {
|
||||
qDebug() << "BoxEntityItem::setProperties()...";
|
||||
qDebug() << "BoxEntityItem::BoxEntityItem() properties.getModelURL()=" << properties.getModelURL();
|
||||
bool somethingChanged = false;
|
||||
|
||||
EntityItem::setProperties(properties, forceCopy); // set the properties in our base class
|
||||
|
||||
if (properties._colorChanged || forceCopy) {
|
||||
setColor(properties._color);
|
||||
somethingChanged = true;
|
||||
}
|
||||
|
||||
if (somethingChanged) {
|
||||
bool wantDebug = false;
|
||||
if (wantDebug) {
|
||||
uint64_t now = usecTimestampNow();
|
||||
int elapsed = now - _lastEdited;
|
||||
qDebug() << "BoxEntityItem::setProperties() AFTER update... edited AGO=" << elapsed <<
|
||||
"now=" << now << " _lastEdited=" << _lastEdited;
|
||||
}
|
||||
setLastEdited(properties._lastEdited);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int BoxEntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) {
|
||||
|
||||
|
||||
qDebug() << "BoxEntityItem::readEntityDataFromBuffer()... <<<<<<<<<<<<<<<< <<<<<<<<<<<<<<<<<<<<<<<<<";
|
||||
|
||||
// Header bytes
|
||||
// object ID [16 bytes]
|
||||
// ByteCountCoded(type code) [~1 byte]
|
||||
// last edited [8 bytes]
|
||||
// ByteCountCoded(last_edited to last_updated delta) [~1-8 bytes]
|
||||
// PropertyFlags<>( everything ) [1-2 bytes]
|
||||
// ~27-35 bytes...
|
||||
const int MINIMUM_HEADER_BYTES = 27; // TODO: this is not correct, we don't yet have 16 byte IDs
|
||||
|
||||
int bytesRead = 0;
|
||||
if (bytesLeftToRead >= MINIMUM_HEADER_BYTES) {
|
||||
|
||||
int originalLength = bytesLeftToRead;
|
||||
QByteArray originalDataBuffer((const char*)data, originalLength);
|
||||
|
||||
int clockSkew = args.sourceNode ? args.sourceNode->getClockSkewUsec() : 0;
|
||||
|
||||
const unsigned char* dataAt = data;
|
||||
|
||||
// id
|
||||
QByteArray encodedID = originalDataBuffer.mid(bytesRead); // maximum possible size
|
||||
ByteCountCoded<quint32> idCoder = encodedID;
|
||||
encodedID = idCoder; // determine true length
|
||||
dataAt += encodedID.size();
|
||||
bytesRead += encodedID.size();
|
||||
_id = idCoder;
|
||||
_creatorTokenID = UNKNOWN_ENTITY_TOKEN; // if we know the id, then we don't care about the creator token
|
||||
_newlyCreated = false;
|
||||
|
||||
// type
|
||||
QByteArray encodedType = originalDataBuffer.mid(bytesRead); // maximum possible size
|
||||
ByteCountCoded<quint32> typeCoder = encodedType;
|
||||
encodedType = typeCoder; // determine true length
|
||||
dataAt += encodedType.size();
|
||||
bytesRead += encodedType.size();
|
||||
quint32 type = typeCoder;
|
||||
_type = (EntityTypes::EntityType_t)type;
|
||||
|
||||
// XXXBHG: is this a good place to handle the last edited time client vs server??
|
||||
|
||||
// If the edit time encoded in the packet is NEWER than our known edit time...
|
||||
// then we WANT to over-write our local data.
|
||||
// If the edit time encoded in the packet is OLDER than our known edit time...
|
||||
// then we WANT to preserve our local data. (NOTE: what if I change color, and you change position?? last one wins!)
|
||||
|
||||
bool overwriteLocalData = true; // assume the new content overwrites our local data
|
||||
|
||||
quint64 lastEditedFromBuffer = 0;
|
||||
|
||||
// _lastEdited
|
||||
memcpy(&lastEditedFromBuffer, dataAt, sizeof(lastEditedFromBuffer));
|
||||
dataAt += sizeof(lastEditedFromBuffer);
|
||||
bytesRead += sizeof(lastEditedFromBuffer);
|
||||
lastEditedFromBuffer -= clockSkew;
|
||||
|
||||
// If we've changed our local tree more recently than the new data from this packet
|
||||
// then we will not be changing our values, instead we just read and skip the data
|
||||
if (_lastEdited > lastEditedFromBuffer) {
|
||||
overwriteLocalData = false;
|
||||
qDebug() << "IGNORING old data from server!!! **************** _lastEdited=" << _lastEdited
|
||||
<< "lastEditedFromBuffer=" << lastEditedFromBuffer << "now=" << usecTimestampNow();
|
||||
} else {
|
||||
|
||||
qDebug() << "USING NEW data from server!!! **************** OLD _lastEdited=" << _lastEdited
|
||||
<< "lastEditedFromBuffer=" << lastEditedFromBuffer << "now=" << usecTimestampNow();
|
||||
|
||||
_lastEdited = lastEditedFromBuffer;
|
||||
}
|
||||
|
||||
// last updated is stored as ByteCountCoded delta from lastEdited
|
||||
QByteArray encodedUpdateDelta = originalDataBuffer.mid(bytesRead); // maximum possible size
|
||||
ByteCountCoded<quint64> updateDeltaCoder = encodedUpdateDelta;
|
||||
quint64 updateDelta = updateDeltaCoder;
|
||||
if (overwriteLocalData) {
|
||||
_lastUpdated = _lastEdited + updateDelta; // don't adjust for clock skew since we already did that for _lastEdited
|
||||
}
|
||||
encodedUpdateDelta = updateDeltaCoder; // determine true length
|
||||
dataAt += encodedUpdateDelta.size();
|
||||
bytesRead += encodedUpdateDelta.size();
|
||||
|
||||
// Property Flags
|
||||
QByteArray encodedPropertyFlags = originalDataBuffer.mid(bytesRead); // maximum possible size
|
||||
EntityPropertyFlags propertyFlags = encodedPropertyFlags;
|
||||
dataAt += propertyFlags.getEncodedLength();
|
||||
bytesRead += propertyFlags.getEncodedLength();
|
||||
|
||||
// PROP_POSITION
|
||||
if (propertyFlags.getHasProperty(PROP_POSITION)) {
|
||||
glm::vec3 positionFromBuffer;
|
||||
memcpy(&positionFromBuffer, dataAt, sizeof(positionFromBuffer));
|
||||
dataAt += sizeof(positionFromBuffer);
|
||||
bytesRead += sizeof(positionFromBuffer);
|
||||
if (overwriteLocalData) {
|
||||
_position = positionFromBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
// PROP_RADIUS
|
||||
if (propertyFlags.getHasProperty(PROP_RADIUS)) {
|
||||
float radiusFromBuffer;
|
||||
memcpy(&radiusFromBuffer, dataAt, sizeof(radiusFromBuffer));
|
||||
dataAt += sizeof(radiusFromBuffer);
|
||||
bytesRead += sizeof(radiusFromBuffer);
|
||||
if (overwriteLocalData) {
|
||||
_radius = radiusFromBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
// PROP_ROTATION
|
||||
if (propertyFlags.getHasProperty(PROP_ROTATION)) {
|
||||
glm::quat rotation;
|
||||
int bytes = unpackOrientationQuatFromBytes(dataAt, rotation);
|
||||
dataAt += bytes;
|
||||
bytesRead += bytes;
|
||||
if (overwriteLocalData) {
|
||||
_rotation = rotation;
|
||||
}
|
||||
}
|
||||
|
||||
// PROP_SHOULD_BE_DELETED
|
||||
if (propertyFlags.getHasProperty(PROP_SHOULD_BE_DELETED)) {
|
||||
bool shouldBeDeleted;
|
||||
memcpy(&shouldBeDeleted, dataAt, sizeof(shouldBeDeleted));
|
||||
dataAt += sizeof(shouldBeDeleted);
|
||||
bytesRead += sizeof(shouldBeDeleted);
|
||||
if (overwriteLocalData) {
|
||||
_shouldBeDeleted = shouldBeDeleted;
|
||||
}
|
||||
}
|
||||
|
||||
// PROP_SCRIPT
|
||||
// script would go here...
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TODO: only handle these subclass items here, use the base class for the rest...
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// PROP_COLOR
|
||||
if (propertyFlags.getHasProperty(PROP_COLOR)) {
|
||||
rgbColor color;
|
||||
if (overwriteLocalData) {
|
||||
memcpy(_color, dataAt, sizeof(_color));
|
||||
}
|
||||
dataAt += sizeof(color);
|
||||
bytesRead += sizeof(color);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
|
||||
OctreeElement::AppendState BoxEntityItem::appendEntityData(OctreePacketData* packetData, EncodeBitstreamParams& params,
|
||||
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData) const {
|
||||
|
||||
|
||||
|
||||
qDebug() << "BoxEntityItem::appendEntityData()... ********************************************";
|
||||
|
||||
// ALL this fits...
|
||||
// object ID [16 bytes]
|
||||
// ByteCountCoded(type code) [~1 byte]
|
||||
// last edited [8 bytes]
|
||||
// ByteCountCoded(last_edited to last_updated delta) [~1-8 bytes]
|
||||
// PropertyFlags<>( everything ) [1-2 bytes]
|
||||
// ~27-35 bytes...
|
||||
|
||||
OctreeElement::AppendState appendState = OctreeElement::COMPLETED; // assume the best
|
||||
|
||||
// encode our ID as a byte count coded byte stream
|
||||
ByteCountCoded<quint32> idCoder = getID();
|
||||
QByteArray encodedID = idCoder;
|
||||
|
||||
// encode our type as a byte count coded byte stream
|
||||
|
||||
EntityTypes::EntityType_t type = getType();
|
||||
qDebug() << "BoxEntityItem::appendEntityData()... type=" << type;
|
||||
|
||||
|
||||
ByteCountCoded<quint32> typeCoder = type;
|
||||
QByteArray encodedType = typeCoder;
|
||||
|
||||
quint64 updateDelta = getLastUpdated() <= getLastEdited() ? 0 : getLastUpdated() - getLastEdited();
|
||||
ByteCountCoded<quint64> updateDeltaCoder = updateDelta;
|
||||
QByteArray encodedUpdateDelta = updateDeltaCoder;
|
||||
EntityPropertyFlags propertyFlags(PROP_LAST_ITEM);
|
||||
EntityPropertyFlags requestedProperties;
|
||||
|
||||
requestedProperties += PROP_POSITION;
|
||||
requestedProperties += PROP_RADIUS;
|
||||
requestedProperties += PROP_ROTATION;
|
||||
requestedProperties += PROP_COLOR;
|
||||
requestedProperties += PROP_SHOULD_BE_DELETED;
|
||||
|
||||
EntityPropertyFlags propertiesDidntFit = requestedProperties;
|
||||
|
||||
// If we are being called for a subsequent pass at appendEntityData() that failed to completely encode this item,
|
||||
// then our modelTreeElementExtraEncodeData should include data about which properties we need to append.
|
||||
if (modelTreeElementExtraEncodeData && modelTreeElementExtraEncodeData->includedItems.contains(getEntityItemID())) {
|
||||
requestedProperties = modelTreeElementExtraEncodeData->includedItems.value(getEntityItemID());
|
||||
}
|
||||
|
||||
//qDebug() << "requestedProperties=";
|
||||
//requestedProperties.debugDumpBits();
|
||||
|
||||
LevelDetails modelLevel = packetData->startLevel();
|
||||
|
||||
bool successIDFits = packetData->appendValue(encodedID);
|
||||
bool successTypeFits = packetData->appendValue(encodedType);
|
||||
|
||||
quint64 lastEdited = getLastEdited();
|
||||
qDebug() << "BoxEntityItem::appendEntityData() ... lastEdited=" << lastEdited;
|
||||
|
||||
bool successLastEditedFits = packetData->appendValue(lastEdited);
|
||||
bool successLastUpdatedFits = packetData->appendValue(encodedUpdateDelta);
|
||||
|
||||
int propertyFlagsOffset = packetData->getUncompressedByteOffset();
|
||||
QByteArray encodedPropertyFlags = propertyFlags;
|
||||
int oldPropertyFlagsLength = encodedPropertyFlags.length();
|
||||
bool successPropertyFlagsFits = packetData->appendValue(encodedPropertyFlags);
|
||||
int propertyCount = 0;
|
||||
|
||||
bool headerFits = successIDFits && successTypeFits && successLastEditedFits
|
||||
&& successLastUpdatedFits && successPropertyFlagsFits;
|
||||
|
||||
int startOfEntityItemData = packetData->getUncompressedByteOffset();
|
||||
|
||||
if (headerFits) {
|
||||
bool successPropertyFits;
|
||||
|
||||
propertyFlags -= PROP_LAST_ITEM; // clear the last item for now, we may or may not set it as the actual item
|
||||
|
||||
// These items would go here once supported....
|
||||
// PROP_PAGED_PROPERTY,
|
||||
// PROP_CUSTOM_PROPERTIES_INCLUDED,
|
||||
// PROP_VISIBLE,
|
||||
|
||||
// PROP_POSITION
|
||||
if (requestedProperties.getHasProperty(PROP_POSITION)) {
|
||||
//qDebug() << "PROP_POSITION requested...";
|
||||
LevelDetails propertyLevel = packetData->startLevel();
|
||||
successPropertyFits = packetData->appendPosition(getPosition());
|
||||
if (successPropertyFits) {
|
||||
propertyFlags |= PROP_POSITION;
|
||||
propertiesDidntFit -= PROP_POSITION;
|
||||
propertyCount++;
|
||||
packetData->endLevel(propertyLevel);
|
||||
} else {
|
||||
//qDebug() << "PROP_POSITION didn't fit...";
|
||||
packetData->discardLevel(propertyLevel);
|
||||
appendState = OctreeElement::PARTIAL;
|
||||
}
|
||||
} else {
|
||||
//qDebug() << "PROP_POSITION NOT requested...";
|
||||
propertiesDidntFit -= PROP_POSITION;
|
||||
}
|
||||
|
||||
// PROP_RADIUS
|
||||
if (requestedProperties.getHasProperty(PROP_RADIUS)) {
|
||||
//qDebug() << "PROP_RADIUS requested...";
|
||||
LevelDetails propertyLevel = packetData->startLevel();
|
||||
successPropertyFits = packetData->appendValue(getRadius());
|
||||
if (successPropertyFits) {
|
||||
propertyFlags |= PROP_RADIUS;
|
||||
propertiesDidntFit -= PROP_RADIUS;
|
||||
propertyCount++;
|
||||
packetData->endLevel(propertyLevel);
|
||||
} else {
|
||||
//qDebug() << "PROP_RADIUS didn't fit...";
|
||||
packetData->discardLevel(propertyLevel);
|
||||
appendState = OctreeElement::PARTIAL;
|
||||
}
|
||||
} else {
|
||||
//qDebug() << "PROP_RADIUS NOT requested...";
|
||||
propertiesDidntFit -= PROP_RADIUS;
|
||||
}
|
||||
|
||||
// PROP_ROTATION
|
||||
if (requestedProperties.getHasProperty(PROP_ROTATION)) {
|
||||
//qDebug() << "PROP_ROTATION requested...";
|
||||
LevelDetails propertyLevel = packetData->startLevel();
|
||||
successPropertyFits = packetData->appendValue(getRotation());
|
||||
if (successPropertyFits) {
|
||||
propertyFlags |= PROP_ROTATION;
|
||||
propertiesDidntFit -= PROP_ROTATION;
|
||||
propertyCount++;
|
||||
packetData->endLevel(propertyLevel);
|
||||
} else {
|
||||
//qDebug() << "PROP_ROTATION didn't fit...";
|
||||
packetData->discardLevel(propertyLevel);
|
||||
appendState = OctreeElement::PARTIAL;
|
||||
}
|
||||
} else {
|
||||
//qDebug() << "PROP_ROTATION NOT requested...";
|
||||
propertiesDidntFit -= PROP_ROTATION;
|
||||
}
|
||||
|
||||
// PROP_SHOULD_BE_DELETED
|
||||
if (requestedProperties.getHasProperty(PROP_SHOULD_BE_DELETED)) {
|
||||
//qDebug() << "PROP_SHOULD_BE_DELETED requested...";
|
||||
LevelDetails propertyLevel = packetData->startLevel();
|
||||
successPropertyFits = packetData->appendValue(getShouldBeDeleted());
|
||||
if (successPropertyFits) {
|
||||
propertyFlags |= PROP_SHOULD_BE_DELETED;
|
||||
propertiesDidntFit -= PROP_SHOULD_BE_DELETED;
|
||||
propertyCount++;
|
||||
packetData->endLevel(propertyLevel);
|
||||
} else {
|
||||
//qDebug() << "PROP_SHOULD_BE_DELETED didn't fit...";
|
||||
packetData->discardLevel(propertyLevel);
|
||||
appendState = OctreeElement::PARTIAL;
|
||||
}
|
||||
} else {
|
||||
//qDebug() << "PROP_SHOULD_BE_DELETED NOT requested...";
|
||||
propertiesDidntFit -= PROP_SHOULD_BE_DELETED;
|
||||
}
|
||||
|
||||
// PROP_SCRIPT
|
||||
// script would go here...
|
||||
|
||||
|
||||
// PROP_COLOR
|
||||
if (requestedProperties.getHasProperty(PROP_COLOR)) {
|
||||
//qDebug() << "PROP_COLOR requested...";
|
||||
LevelDetails propertyLevel = packetData->startLevel();
|
||||
successPropertyFits = packetData->appendColor(getColor());
|
||||
if (successPropertyFits) {
|
||||
propertyFlags |= PROP_COLOR;
|
||||
propertiesDidntFit -= PROP_COLOR;
|
||||
propertyCount++;
|
||||
packetData->endLevel(propertyLevel);
|
||||
} else {
|
||||
//qDebug() << "PROP_COLOR didn't fit...";
|
||||
packetData->discardLevel(propertyLevel);
|
||||
appendState = OctreeElement::PARTIAL;
|
||||
}
|
||||
} else {
|
||||
//qDebug() << "PROP_COLOR NOT requested...";
|
||||
propertiesDidntFit -= PROP_COLOR;
|
||||
}
|
||||
}
|
||||
if (propertyCount > 0) {
|
||||
int endOfEntityItemData = packetData->getUncompressedByteOffset();
|
||||
|
||||
encodedPropertyFlags = propertyFlags;
|
||||
int newPropertyFlagsLength = encodedPropertyFlags.length();
|
||||
packetData->updatePriorBytes(propertyFlagsOffset,
|
||||
(const unsigned char*)encodedPropertyFlags.constData(), encodedPropertyFlags.length());
|
||||
|
||||
// if the size of the PropertyFlags shrunk, we need to shift everything down to front of packet.
|
||||
if (newPropertyFlagsLength < oldPropertyFlagsLength) {
|
||||
int oldSize = packetData->getUncompressedSize();
|
||||
|
||||
const unsigned char* modelItemData = packetData->getUncompressedData(propertyFlagsOffset + oldPropertyFlagsLength);
|
||||
int modelItemDataLength = endOfEntityItemData - startOfEntityItemData;
|
||||
int newEntityItemDataStart = propertyFlagsOffset + newPropertyFlagsLength;
|
||||
packetData->updatePriorBytes(newEntityItemDataStart, modelItemData, modelItemDataLength);
|
||||
|
||||
int newSize = oldSize - (oldPropertyFlagsLength - newPropertyFlagsLength);
|
||||
packetData->setUncompressedSize(newSize);
|
||||
|
||||
} else {
|
||||
assert(newPropertyFlagsLength == oldPropertyFlagsLength); // should not have grown
|
||||
}
|
||||
|
||||
packetData->endLevel(modelLevel);
|
||||
} else {
|
||||
packetData->discardLevel(modelLevel);
|
||||
appendState = OctreeElement::NONE; // if we got here, then we didn't include the item
|
||||
}
|
||||
|
||||
//qDebug() << "propertyFlags=";
|
||||
//propertyFlags.debugDumpBits();
|
||||
|
||||
//qDebug() << "propertiesDidntFit=";
|
||||
//propertiesDidntFit.debugDumpBits();
|
||||
|
||||
// If any part of the model items didn't fit, then the element is considered partial
|
||||
if (appendState != OctreeElement::COMPLETED) {
|
||||
// add this item into our list for the next appendElementData() pass
|
||||
modelTreeElementExtraEncodeData->includedItems.insert(getEntityItemID(), propertiesDidntFit);
|
||||
}
|
||||
|
||||
return appendState;
|
||||
}
|
54
libraries/entities/src/BoxEntityItem.h
Normal file
54
libraries/entities/src/BoxEntityItem.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
//
|
||||
// BoxEntityItem.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_BoxEntityItem_h
|
||||
#define hifi_BoxEntityItem_h
|
||||
|
||||
#include "EntityItem.h"
|
||||
|
||||
class BoxEntityItem : public EntityItem {
|
||||
public:
|
||||
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
|
||||
BoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
|
||||
|
||||
virtual void somePureVirtualFunction() { }; // allow this class to be constructed
|
||||
|
||||
// methods for getting/setting all properties of an entity
|
||||
virtual EntityItemProperties getProperties() const;
|
||||
virtual void setProperties(const EntityItemProperties& properties, bool forceCopy = false);
|
||||
|
||||
virtual OctreeElement::AppendState appendEntityData(OctreePacketData* packetData, EncodeBitstreamParams& params,
|
||||
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData) const;
|
||||
|
||||
|
||||
virtual int readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args);
|
||||
|
||||
|
||||
// TODO: Move these to subclasses, or other appropriate abstraction
|
||||
// getters/setters applicable to models and particles
|
||||
|
||||
const rgbColor& getColor() const { return _color; }
|
||||
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
|
||||
|
||||
void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); }
|
||||
void setColor(const xColor& value) {
|
||||
_color[RED_INDEX] = value.red;
|
||||
_color[GREEN_INDEX] = value.green;
|
||||
_color[BLUE_INDEX] = value.blue;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
rgbColor _color;
|
||||
};
|
||||
|
||||
#endif // hifi_BoxEntityItem_h
|
|
@ -46,7 +46,7 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) {
|
|||
|
||||
EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) {
|
||||
//qDebug() << "EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties)....";
|
||||
_type = EntityTypes::Base;
|
||||
_type = EntityTypes::Unknown;
|
||||
_lastEdited = 0;
|
||||
_lastUpdated = 0;
|
||||
initFromEntityItemID(entityItemID);
|
||||
|
@ -712,6 +712,9 @@ bool EntityItem::encodeEntityEditMessageDetails(PacketType command, EntityItemID
|
|||
|
||||
// encode our type as a byte count coded byte stream
|
||||
ByteCountCoded<quint32> typeCoder = (quint32)properties.getType();
|
||||
|
||||
qDebug() << "(quint32)properties.getType()=" << (quint32)properties.getType();
|
||||
|
||||
QByteArray encodedType = typeCoder;
|
||||
|
||||
quint64 updateDelta = 0; // this is an edit so by definition, it's update is in sync
|
||||
|
|
|
@ -115,14 +115,6 @@ protected:
|
|||
bool _shouldBeDeleted;
|
||||
};
|
||||
|
||||
class BoxEntityItem : public EntityItem {
|
||||
public:
|
||||
BoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
|
||||
EntityItem(entityItemID, properties) { _type = EntityTypes::Box; }
|
||||
|
||||
virtual void somePureVirtualFunction() { }; // allow this class to be constructed
|
||||
};
|
||||
|
||||
class SphereEntityItem : public EntityItem {
|
||||
public:
|
||||
SphereEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
|
||||
|
|
|
@ -21,7 +21,7 @@ EntityItemProperties::EntityItemProperties() :
|
|||
_id(UNKNOWN_ENTITY_ID),
|
||||
_idSet(false),
|
||||
_lastEdited(0),
|
||||
_type(EntityTypes::Base),
|
||||
_type(EntityTypes::Unknown),
|
||||
|
||||
_position(0),
|
||||
_radius(ENTITY_DEFAULT_RADIUS),
|
||||
|
@ -157,7 +157,9 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
|
|||
if (typeScriptValue.isValid()) {
|
||||
QString typeName;
|
||||
typeName = typeScriptValue.toVariant().toString();
|
||||
qDebug() << "EntityItemProperties::copyFromScriptValue()... typeName=" << typeName;
|
||||
_type = EntityTypes::getEntityTypeFromName(typeName);
|
||||
qDebug() << "EntityItemProperties::copyFromScriptValue()... _type=" << _type;
|
||||
}
|
||||
|
||||
QScriptValue position = object.property("position");
|
||||
|
|
|
@ -80,6 +80,7 @@ typedef PropertyFlags<EntityPropertyList> EntityPropertyFlags;
|
|||
class EntityItemProperties {
|
||||
friend class EntityItem; // TODO: consider removing this friend relationship and have EntityItem use public methods
|
||||
friend class ModelEntityItem; // TODO: consider removing this friend relationship and have EntityItem use public methods
|
||||
friend class BoxEntityItem; // TODO: consider removing this friend relationship and have EntityItem use public methods
|
||||
public:
|
||||
EntityItemProperties();
|
||||
virtual ~EntityItemProperties() { };
|
||||
|
|
|
@ -17,34 +17,74 @@
|
|||
#include "EntityItem.h"
|
||||
#include "EntityItemProperties.h"
|
||||
#include "EntityTypes.h"
|
||||
|
||||
#include "BoxEntityItem.h"
|
||||
#include "ModelEntityItem.h"
|
||||
|
||||
QHash<EntityTypes::EntityType_t, QString> EntityTypes::_typeNameHash;
|
||||
|
||||
const QString UNKNOWN_EntityType_t_NAME = "Unknown";
|
||||
QMap<EntityTypes::EntityType_t, QString> EntityTypes::_typeNameHash;
|
||||
QMap<QString, EntityTypes::EntityType_t> EntityTypes::_nameTypeHash;
|
||||
QMap<EntityTypes::EntityType_t, EntityTypeFactory> EntityTypes::_typeFactoryHash;
|
||||
|
||||
const QString ENTITY_TYPE_NAME_UNKNOWN = "Unknown";
|
||||
|
||||
// Register Entity Types here...
|
||||
REGISTER_ENTITY_TYPE(Model)
|
||||
REGISTER_ENTITY_TYPE(Box)
|
||||
|
||||
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;
|
||||
QMap<EntityType_t, QString>::iterator matchedTypeName = _typeNameHash.find(entityType);
|
||||
return matchedTypeName != _typeNameHash.end() ? matchedTypeName.value() : ENTITY_TYPE_NAME_UNKNOWN;
|
||||
}
|
||||
|
||||
bool EntityTypes::registerEntityType(EntityType_t entityType, const QString& name) {
|
||||
_typeNameHash.insert(entityType, name);
|
||||
bool EntityTypes::registerEntityType(EntityType_t entityType, const char* name, EntityTypeFactory factoryMethod) {
|
||||
qDebug() << "EntityTypes::registerEntityType()";
|
||||
qDebug() << " entityType=" << entityType;
|
||||
qDebug() << " name=" << name;
|
||||
qDebug() << " factoryMethod=" << (void*)factoryMethod;
|
||||
|
||||
_typeNameHash[entityType] = name;
|
||||
_nameTypeHash[name] = entityType;
|
||||
_typeFactoryHash[entityType] = factoryMethod;
|
||||
return true;
|
||||
}
|
||||
|
||||
EntityTypes::EntityType_t EntityTypes::getEntityTypeFromName(const QString& name) {
|
||||
return Base; // TODO: support registration
|
||||
qDebug() << "EntityTypes::getEntityTypeFromName() name=" << name;
|
||||
|
||||
QMap<QString, EntityTypes::EntityType_t>::iterator matchedTypeName = _nameTypeHash.find(name);
|
||||
if (matchedTypeName != _nameTypeHash.end()) {
|
||||
qDebug() << "EntityTypes::getEntityTypeFromName() FOUND IT! type=" << matchedTypeName.value();
|
||||
return matchedTypeName.value();
|
||||
}
|
||||
qDebug() << "EntityTypes::getEntityTypeFromName() COULDN'T FIND TYPE!! name=" << name;
|
||||
return Unknown;
|
||||
}
|
||||
|
||||
EntityItem* EntityTypes::constructEntityItem(EntityType_t entityType, const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
|
||||
//qDebug() << "EntityTypes::constructEntityItem(EntityType_t entityType, const EntityItemID& entityID, const EntityItemProperties& properties)";
|
||||
qDebug() << "EntityTypes::constructEntityItem(EntityType_t entityType, const EntityItemID& entityID, const EntityItemProperties& properties)";
|
||||
qDebug() << " entityType=" << entityType;
|
||||
qDebug() << " entityID=" << entityID;
|
||||
//qDebug() << " properties=" << properties;
|
||||
|
||||
EntityItem* newEntityItem = NULL;
|
||||
|
||||
QMap<EntityTypes::EntityType_t, EntityTypeFactory>::iterator matchedType = _typeFactoryHash.find(entityType);
|
||||
if (matchedType != _typeFactoryHash.end()) {
|
||||
EntityTypeFactory factory = matchedType.value();
|
||||
|
||||
qDebug() << "ABOUT TO CALL FACTORY!!!!!";
|
||||
newEntityItem = factory(entityID, properties);
|
||||
qDebug() << "AFTER FACTORY!!!!!";
|
||||
} else {
|
||||
qDebug() << "UNABLE TO CALL FACTORY!!!!!";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
// switch statement for now, needs to support registration of constructor
|
||||
switch (entityType) {
|
||||
// Base, // ??? not supported?
|
||||
case Model:
|
||||
newEntityItem = new ModelEntityItem(entityID, properties);
|
||||
break;
|
||||
|
@ -73,6 +113,8 @@ EntityItem* EntityTypes::constructEntityItem(EntityType_t entityType, const Enti
|
|||
newEntityItem = new ModelEntityItem(entityID, properties);
|
||||
break;
|
||||
}
|
||||
|
||||
*/
|
||||
return newEntityItem;
|
||||
}
|
||||
|
||||
|
@ -368,7 +410,3 @@ qDebug() << "EntityItem::decodeEntityEditPacket() ... lastEdited=" << lastEdited
|
|||
}
|
||||
|
||||
|
||||
bool registered = EntityTypes::registerEntityType(EntityTypes::Base, "Base")
|
||||
&& EntityTypes::registerEntityType(EntityTypes::Model, "Model"); // TODO: move this to model subclass
|
||||
|
||||
|
||||
|
|
|
@ -22,10 +22,12 @@ class EntityItemID;
|
|||
class EntityItemProperties;
|
||||
class ReadBitstreamToTreeParams;
|
||||
|
||||
typedef EntityItem* (*EntityTypeFactory)(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
|
||||
class EntityTypes {
|
||||
public:
|
||||
typedef enum EntityType {
|
||||
Base,
|
||||
Unknown,
|
||||
Model,
|
||||
Box,
|
||||
Sphere,
|
||||
|
@ -35,7 +37,7 @@ public:
|
|||
} EntityType_t;
|
||||
|
||||
static const QString& getEntityTypeName(EntityType_t entityType);
|
||||
static bool registerEntityType(EntityType_t entityType, const QString& name);
|
||||
static bool registerEntityType(EntityType_t entityType, const char* name, EntityTypeFactory factoryMethod);
|
||||
static EntityTypes::EntityType_t getEntityTypeFromName(const QString& name);
|
||||
|
||||
static EntityItem* constructEntityItem(EntityType_t entityType, const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
|
@ -43,7 +45,17 @@ public:
|
|||
static bool decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes,
|
||||
EntityItemID& entityID, EntityItemProperties& properties);
|
||||
private:
|
||||
static QHash<EntityType_t, QString> _typeNameHash;
|
||||
static QMap<EntityType_t, QString> _typeNameHash;
|
||||
static QMap<QString, EntityTypes::EntityType_t> _nameTypeHash;
|
||||
static QMap<EntityType_t, EntityTypeFactory> _typeFactoryHash;
|
||||
};
|
||||
|
||||
|
||||
/// Macro for registering entity types. Make sure to add an element to the EntityType enum with your name, and your class should be
|
||||
/// named NameEntityItem and must of a static method called factory that takes an EnityItemID, and EntityItemProperties and return a newly
|
||||
/// constructed (heap allocated) instance of your type. e.g. The following prototype:
|
||||
// static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
#define REGISTER_ENTITY_TYPE(x) static bool x##Registration = EntityTypes::registerEntityType(EntityTypes::x, #x, x##EntityItem::factory);
|
||||
|
||||
|
||||
#endif // hifi_EntityTypes_h
|
||||
|
|
|
@ -15,6 +15,15 @@
|
|||
#include "EntityTreeElement.h"
|
||||
#include "ModelEntityItem.h"
|
||||
|
||||
|
||||
//EntityTypes::registerEntityType(EntityTypes::Model, "Model", ModelEntityItem::factory);
|
||||
|
||||
|
||||
EntityItem* ModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
qDebug() << "ModelEntityItem::factory(const EntityItemID& entityItemID, const EntityItemProperties& properties)...";
|
||||
return new ModelEntityItem(entityID, properties);
|
||||
}
|
||||
|
||||
// our non-pure virtual subclass for now...
|
||||
ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
|
||||
EntityItem(entityItemID, properties)
|
||||
|
|
|
@ -14,9 +14,10 @@
|
|||
|
||||
#include "EntityItem.h"
|
||||
|
||||
// our non-pure virtual subclass for now...
|
||||
class ModelEntityItem : public EntityItem {
|
||||
public:
|
||||
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
|
||||
ModelEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
|
||||
|
||||
virtual void somePureVirtualFunction() { }; // allow this class to be constructed
|
||||
|
|
|
@ -11,6 +11,7 @@ should these be included for all entities? Light, Models, planes, etc?
|
|||
* damping
|
||||
* rotational velocity? - wouldn't that be cool to be automatic with no edits
|
||||
* rotational damping?? - can you slow a quat rotation by simply multiplying it by a fraction?
|
||||
* glow level???
|
||||
|
||||
* color??
|
||||
|
||||
|
@ -73,7 +74,7 @@ Model properties:
|
|||
|
||||
|
||||
|
||||
what about editing?
|
||||
what about editing/edit messages...
|
||||
|
||||
EntityItem::encodeEntityEditMessageDetails() -- this could be a member of EntityItemProperties, or EntityTypes?...
|
||||
EntityTypes::decodeEntityEditPacket() -- this could be a member of EntityItemProperties...??
|
||||
|
@ -146,6 +147,10 @@ Model properties:
|
|||
// 24) get rid of EntityItem::expectedBytes()...
|
||||
|
||||
|
||||
// 25) consider moving the EntityTypes static Maps to be inside a singleton instance of EntityTypes to ensure initialization order
|
||||
// 26) Why can't we call REGISTER_ENTITY_TYPE() in BoxEntityType.cpp
|
||||
|
||||
|
||||
|
||||
|
||||
===============
|
||||
|
|
Loading…
Reference in a new issue