working on addressing issues with sibling cells and server clock skew causing some properties to be ignored

This commit is contained in:
ZappoMan 2014-09-01 21:48:03 -07:00
parent 1fa587b88a
commit b244e78af4
13 changed files with 923 additions and 137 deletions

View file

@ -61,9 +61,9 @@ bool BoxEntityItem::setProperties(const EntityItemProperties& properties, bool f
bool wantDebug = false;
if (wantDebug) {
uint64_t now = usecTimestampNow();
int elapsed = now - _lastEdited;
int elapsed = now - getLastEdited();
qDebug() << "BoxEntityItem::setProperties() AFTER update... edited AGO=" << elapsed <<
"now=" << now << " _lastEdited=" << _lastEdited;
"now=" << now << " getLastEdited()=" << getLastEdited();
}
setLastEdited(properties._lastEdited);
}

View file

@ -42,7 +42,9 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) {
// init values with defaults before calling setProperties
//uint64_t now = usecTimestampNow();
_lastEdited = 0;
_lastEditedRemote = 0;
_lastEditedLocal = 0;
//_lastEdited = 0;
_lastUpdated = 0;
_created = 0; // TODO: when do we actually want to make this "now"
@ -60,7 +62,9 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) {
EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) {
_type = EntityTypes::Unknown;
_lastEdited = 0;
_lastEditedRemote = 0;
_lastEditedLocal = 0;
//_lastEdited = 0;
_lastUpdated = 0;
_created = properties.getCreated();
initFromEntityItemID(entityItemID);
@ -84,7 +88,16 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param
}
OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData) const {
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData) const {
const bool wantDebug = false;
if (wantDebug) {
qDebug() << "EntityItem::appendEntityData()....";
qDebug() << " entity=" << this;
qDebug() << " entityItemID=" << getEntityItemID();
}
// ALL this fits...
// object ID [16 bytes]
@ -111,9 +124,42 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
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());
// then our entityTreeElementExtraEncodeData should include data about which properties we need to append.
if (entityTreeElementExtraEncodeData && wantDebug) {
qDebug() << " entityTreeElementExtraEncodeData INCLUDED";
}
if (entityTreeElementExtraEncodeData && entityTreeElementExtraEncodeData->entities.contains(getEntityItemID())) {
requestedProperties = entityTreeElementExtraEncodeData->entities.value(getEntityItemID());
if (wantDebug) {
qDebug() << " entityTreeElementExtraEncodeData INCLUDED -AND- this entity is included";
qDebug() << " --- requestedProperties ---";
qDebug() << " PROP_MODEL_URL: " << requestedProperties.getHasProperty(PROP_MODEL_URL)<< " entity ID:" << getEntityItemID();
qDebug() << " --- all requestedProperties ---";
#define DEBUG_REQUESTED_PROPERTY(x) if (requestedProperties.getHasProperty(x)) { qDebug() << " " #x; }
DEBUG_REQUESTED_PROPERTY(PROP_MODEL_URL);
DEBUG_REQUESTED_PROPERTY(PROP_PAGED_PROPERTY)
DEBUG_REQUESTED_PROPERTY(PROP_CUSTOM_PROPERTIES_INCLUDED);
DEBUG_REQUESTED_PROPERTY(PROP_POSITION);
DEBUG_REQUESTED_PROPERTY(PROP_RADIUS);
DEBUG_REQUESTED_PROPERTY(PROP_ROTATION);
DEBUG_REQUESTED_PROPERTY(PROP_MASS);
DEBUG_REQUESTED_PROPERTY(PROP_VELOCITY);
DEBUG_REQUESTED_PROPERTY(PROP_GRAVITY);
DEBUG_REQUESTED_PROPERTY(PROP_DAMPING);
DEBUG_REQUESTED_PROPERTY(PROP_LIFETIME);
DEBUG_REQUESTED_PROPERTY(PROP_SCRIPT);
DEBUG_REQUESTED_PROPERTY(PROP_COLOR);
DEBUG_REQUESTED_PROPERTY(PROP_ANIMATION_URL);
DEBUG_REQUESTED_PROPERTY(PROP_ANIMATION_FPS);
DEBUG_REQUESTED_PROPERTY(PROP_ANIMATION_FRAME_INDEX);
DEBUG_REQUESTED_PROPERTY(PROP_ANIMATION_PLAYING);
}
}
LevelDetails modelLevel = packetData->startLevel();
@ -320,16 +366,40 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
propertiesDidntFit -= PROP_SCRIPT;
}
appendSubclassData(packetData, params, modelTreeElementExtraEncodeData,
appendSubclassData(packetData, params, entityTreeElementExtraEncodeData,
requestedProperties,
propertyFlags,
propertiesDidntFit,
propertyCount,
appendState);
}
#define DEBUG_PROPERTY(y, x) if (y.getHasProperty(x)) { qDebug() << " " #x; }
if (propertyCount > 0) {
int endOfEntityItemData = packetData->getUncompressedByteOffset();
qDebug() << "Entity Properties THIS ROUND... entityID:" << getEntityItemID();
DEBUG_PROPERTY(propertyFlags, PROP_MODEL_URL);
DEBUG_PROPERTY(propertyFlags, PROP_PAGED_PROPERTY)
DEBUG_PROPERTY(propertyFlags, PROP_CUSTOM_PROPERTIES_INCLUDED);
DEBUG_PROPERTY(propertyFlags, PROP_POSITION);
DEBUG_PROPERTY(propertyFlags, PROP_RADIUS);
DEBUG_PROPERTY(propertyFlags, PROP_ROTATION);
DEBUG_PROPERTY(propertyFlags, PROP_MASS);
DEBUG_PROPERTY(propertyFlags, PROP_VELOCITY);
DEBUG_PROPERTY(propertyFlags, PROP_GRAVITY);
DEBUG_PROPERTY(propertyFlags, PROP_DAMPING);
DEBUG_PROPERTY(propertyFlags, PROP_LIFETIME);
DEBUG_PROPERTY(propertyFlags, PROP_SCRIPT);
DEBUG_PROPERTY(propertyFlags, PROP_COLOR);
DEBUG_PROPERTY(propertyFlags, PROP_ANIMATION_URL);
DEBUG_PROPERTY(propertyFlags, PROP_ANIMATION_FPS);
DEBUG_PROPERTY(propertyFlags, PROP_ANIMATION_FRAME_INDEX);
DEBUG_PROPERTY(propertyFlags, PROP_ANIMATION_PLAYING);
encodedPropertyFlags = propertyFlags;
int newPropertyFlagsLength = encodedPropertyFlags.length();
@ -338,6 +408,9 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
// if the size of the PropertyFlags shrunk, we need to shift everything down to front of packet.
if (newPropertyFlagsLength < oldPropertyFlagsLength) {
qDebug() << "PACKET SHIFTING!!! <<<<<<<<<<<<<<<< ";
int oldSize = packetData->getUncompressedSize();
const unsigned char* modelItemData = packetData->getUncompressedData(propertyFlagsOffset + oldPropertyFlagsLength);
int modelItemDataLength = endOfEntityItemData - startOfEntityItemData;
@ -359,7 +432,32 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
// 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);
qDebug() << "Entity Partially encoded... entityID:" << getEntityItemID();
#define DEBUG_PROPERTY(y, x) if (y.getHasProperty(x)) { qDebug() << " " #x; }
DEBUG_PROPERTY(propertiesDidntFit, PROP_MODEL_URL);
DEBUG_PROPERTY(propertiesDidntFit, PROP_PAGED_PROPERTY)
DEBUG_PROPERTY(propertiesDidntFit, PROP_CUSTOM_PROPERTIES_INCLUDED);
DEBUG_PROPERTY(propertiesDidntFit, PROP_POSITION);
DEBUG_PROPERTY(propertiesDidntFit, PROP_RADIUS);
DEBUG_PROPERTY(propertiesDidntFit, PROP_ROTATION);
DEBUG_PROPERTY(propertiesDidntFit, PROP_MASS);
DEBUG_PROPERTY(propertiesDidntFit, PROP_VELOCITY);
DEBUG_PROPERTY(propertiesDidntFit, PROP_GRAVITY);
DEBUG_PROPERTY(propertiesDidntFit, PROP_DAMPING);
DEBUG_PROPERTY(propertiesDidntFit, PROP_LIFETIME);
DEBUG_PROPERTY(propertiesDidntFit, PROP_SCRIPT);
DEBUG_PROPERTY(propertiesDidntFit, PROP_COLOR);
DEBUG_PROPERTY(propertiesDidntFit, PROP_ANIMATION_URL);
DEBUG_PROPERTY(propertiesDidntFit, PROP_ANIMATION_FPS);
DEBUG_PROPERTY(propertiesDidntFit, PROP_ANIMATION_FRAME_INDEX);
DEBUG_PROPERTY(propertiesDidntFit, PROP_ANIMATION_PLAYING);
entityTreeElementExtraEncodeData->entities.insert(getEntityItemID(), propertiesDidntFit);
} else {
qDebug() << "Entity COMPLETED... entityID:" << getEntityItemID();
}
return appendState;
@ -448,34 +546,42 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
}
quint64 lastEditedFromBuffer = 0;
quint64 lastEditedFromBufferAdjusted = 0;
// TODO: we could make this encoded as a delta from _created
// _lastEdited
memcpy(&lastEditedFromBuffer, dataAt, sizeof(lastEditedFromBuffer));
dataAt += sizeof(lastEditedFromBuffer);
bytesRead += sizeof(lastEditedFromBuffer);
lastEditedFromBuffer -= clockSkew;
qDebug() << "data from server **************** ";
qDebug() << " entityItemID=" << getEntityItemID();
qDebug() << " now=" << usecTimestampNow();
qDebug() << " getLastEdited();=" << getLastEdited();
qDebug() << " _lastEditedRemote=" << _lastEditedRemote;
qDebug() << " _lastEditedLocal=" << _lastEditedLocal;
qDebug() << " lastEditedFromBuffer=" << lastEditedFromBuffer << " (BEFORE clockskew adjust)";
qDebug() << " clockSkew=" << clockSkew;
lastEditedFromBufferAdjusted = lastEditedFromBuffer - clockSkew;
qDebug() << " lastEditedFromBufferAdjusted=" << lastEditedFromBufferAdjusted << " (AFTER clockskew adjust)";
// 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) {
if (_lastEditedLocal > lastEditedFromBufferAdjusted) {
overwriteLocalData = false;
if (wantDebug) {
qDebug() << "IGNORING old data from server!!! **************** _lastEdited=" << _lastEdited
<< "lastEditedFromBuffer=" << lastEditedFromBuffer << "now=" << usecTimestampNow();
if (true || wantDebug) {
qDebug() << "IGNORING old data from server!!! ****************";
}
} else {
if (wantDebug) {
qDebug() << "USING NEW data from server!!! **************** OLD _lastEdited=" << _lastEdited
<< "lastEditedFromBuffer=" << lastEditedFromBuffer << "now=" << usecTimestampNow();
if (true || wantDebug) {
qDebug() << "USING NEW data from server!!! ****************";
}
_lastEdited = lastEditedFromBuffer;
_lastEditedRemote = lastEditedFromBuffer;
_lastEditedRemoteClockSkew = clockSkew;
somethingChangedNotification(); // notify derived classes that something has changed
}
// last updated is stored as ByteCountCoded delta from lastEdited
@ -483,7 +589,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
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
_lastUpdated = lastEditedFromBufferAdjusted + updateDelta; // don't adjust for clock skew since we already did that for _lastEdited
}
encodedUpdateDelta = updateDeltaCoder; // determine true length
dataAt += encodedUpdateDelta.size();
@ -865,9 +971,9 @@ bool EntityItem::setProperties(const EntityItemProperties& properties, bool forc
bool wantDebug = false;
if (wantDebug) {
uint64_t now = usecTimestampNow();
int elapsed = now - _lastEdited;
int elapsed = now - getLastEdited();
qDebug() << "EntityItem::setProperties() AFTER update... edited AGO=" << elapsed <<
"now=" << now << " _lastEdited=" << _lastEdited;
"now=" << now << " getLastEdited()=" << getLastEdited();
}
setLastEdited(properties._lastEdited);
}

View file

@ -62,19 +62,21 @@ public:
virtual void somethingChangedNotification() { }
quint64 getLastUpdated() const { return _lastUpdated; } /// Last simulated time of this entity universal usecs
quint64 getLastEdited() const { return _lastEdited; } /// Last edited time of this entity universal usecs
void setLastEdited(quint64 lastEdited) { _lastEdited = lastEdited; _lastUpdated = lastEdited; }
/// Last edited time of this entity universal usecs
quint64 getLastEdited() const { return std::max((_lastEditedRemote - _lastEditedRemoteClockSkew), _lastEditedLocal); }
void setLastEdited(quint64 lastEdited) { _lastEditedLocal = lastEdited; _lastEditedLocal = lastEdited; }
float getEditedAgo() const /// Elapsed seconds since this entity was last edited
{ return (float)(usecTimestampNow() - _lastEdited) / (float)USECS_PER_SECOND; }
{ return (float)(usecTimestampNow() - getLastEdited()) / (float)USECS_PER_SECOND; }
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const;
virtual OctreeElement::AppendState appendEntityData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData) const;
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData) const;
virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
@ -188,7 +190,10 @@ protected:
uint32_t _creatorTokenID;
bool _newlyCreated;
quint64 _lastUpdated;
quint64 _lastEdited;
//quint64 _lastEdited;
quint64 _lastEditedLocal;
quint64 _lastEditedRemote;
quint64 _lastEditedRemoteClockSkew;
quint64 _created;
glm::vec3 _position;

View file

@ -62,6 +62,11 @@ public:
const unsigned char* editData, int maxLength, const SharedNodePointer& senderNode);
virtual bool rootElementHasData() const { return true; }
// the root at least needs to store the number of entities in the packet/buffer
virtual int minimumRequiredRootDataBytes() const { return sizeof(uint16_t); }
virtual bool suppressEmptySubtrees() const { return false; }
virtual bool versionHasSVOfileBreaks(PacketVersion thisVersion) const
{ return thisVersion >= VERSION_ENTITIES_HAS_FILE_BREAKS; }

View file

@ -50,6 +50,246 @@ EntityTreeElement* EntityTreeElement::addChildAtIndex(int index) {
return newElement;
}
void EntityTreeElement::debugExtraEncodeData(EncodeBitstreamParams& params) const {
qDebug() << "EntityTreeElement::debugExtraEncodeData()... ";
qDebug() << " element:" << getAACube();
OctreeElementExtraEncodeData* extraEncodeData = params.extraEncodeData;
assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes
if (extraEncodeData->contains(this)) {
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData
= static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this));
qDebug() << " encode data:" << entityTreeElementExtraEncodeData;
} else {
qDebug() << " encode data: MISSING!!";
}
}
void EntityTreeElement::initializeExtraEncodeData(EncodeBitstreamParams& params) const {
OctreeElementExtraEncodeData* extraEncodeData = params.extraEncodeData;
assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes
// Check to see if this element yet has encode data... if it doesn't create it
if (!extraEncodeData->contains(this)) {
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData = new EntityTreeElementExtraEncodeData();
qDebug() << "EntityTreeElement::initializeExtraEncodeData()... ";
qDebug() << " element:" << getAACube();
entityTreeElementExtraEncodeData->elementCompleted = (_entityItems->size() == 0);
qDebug() << " elementCompleted:" << entityTreeElementExtraEncodeData->elementCompleted << "[ _entityItems->size()=" << _entityItems->size() <<" ]";
qDebug() << " --- initialize this element's child element state ---";
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
EntityTreeElement* child = getChildAtIndex(i);
if (!child) {
entityTreeElementExtraEncodeData->childCompleted[i] = true; // if no child exists, it is completed
qDebug() << " childCompleted[" << i <<"]= true -- completed";
} else {
if (child->hasEntities()) {
qDebug() << " childCompleted[" << i <<"] " << child->getAACube() << "= false -- HAS ENTITIES NEEDS ENCODING";
} else {
entityTreeElementExtraEncodeData->childCompleted[i] = true; // if the child doesn't have enities, it is completed
qDebug() << " childCompleted[" << i <<"] " << child->getAACube() << "= true -- doesn't have entities";
}
}
}
qDebug() << " --- initialize this element's entities state ---";
for (uint16_t i = 0; i < _entityItems->size(); i++) {
EntityItem* entity = (*_entityItems)[i];
entityTreeElementExtraEncodeData->entities.insert(entity->getEntityItemID(), entity->getEntityProperties(params));
}
// TODO: some of these inserts might be redundant!!!
qDebug() << " ADDING encode data (" << __LINE__ << ") for element " << getAACube() << " data=" << entityTreeElementExtraEncodeData;
extraEncodeData->insert(this, entityTreeElementExtraEncodeData);
}
}
bool EntityTreeElement::shouldIncludeChild(int childIndex, EncodeBitstreamParams& params) const {
OctreeElementExtraEncodeData* extraEncodeData = params.extraEncodeData;
assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes
if (extraEncodeData->contains(this)) {
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData
= static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this));
bool childCompleted = entityTreeElementExtraEncodeData->childCompleted[childIndex];
// If we haven't completely sent the child yet, then we should include it
return !childCompleted;
}
// I'm not sure this should ever happen, since we should have the extra encode data if we're considering
// the child data for this element
assert(false);
return false;
}
bool EntityTreeElement::shouldRecurseSubtree(OctreeElement* parent, EncodeBitstreamParams& params, OctreeElementBag* bag) const {
qDebug() << "EntityTreeElement::shouldRecurseSubtree()... ????????????????????????";
qDebug() << " element:" << getAACube();
OctreeElementExtraEncodeData* extraEncodeData = params.extraEncodeData;
assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes
if (extraEncodeData->contains(this)) {
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData
= static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this));
qDebug() << " this element encode data:" << entityTreeElementExtraEncodeData;
} else {
qDebug() << " this element encode data: MISSING!!!";
}
qDebug() << " parent:" << parent->getAACube();
if (extraEncodeData->contains(parent)) {
EntityTreeElementExtraEncodeData* parentExtraEncodeData
= static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(parent));
qDebug() << " parent encode data:" << parentExtraEncodeData;
} else {
qDebug() << " parent encode data: MISSING!!!";
}
return true;
}
void EntityTreeElement::updateEncodedData(int childIndex, AppendState childAppendState, EncodeBitstreamParams& params) const {
OctreeElementExtraEncodeData* extraEncodeData = params.extraEncodeData;
assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes
qDebug() << "EntityTreeElement::updateEncodedData()... ";
qDebug() << " element:" << getAACube();
qDebug() << " child:" << childIndex << getChildAtIndex(childIndex)->getAACube();
switch(childAppendState) {
case OctreeElement::NONE:
qDebug() << " childAppendState: NONE";
break;
case OctreeElement::PARTIAL:
qDebug() << " childAppendState: PARTIAL";
break;
case OctreeElement::COMPLETED:
qDebug() << " childAppendState: COMPLETED";
break;
}
if (extraEncodeData->contains(this)) {
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData
= static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this));
if (childAppendState == OctreeElement::COMPLETED) {
entityTreeElementExtraEncodeData->childCompleted[childIndex] = true;
qDebug() << " SETTING childCompleted[" << childIndex << "] = true - " << getChildAtIndex(childIndex)->getAACube();
}
qDebug() << " encode data:" << entityTreeElementExtraEncodeData;
} else {
assert(false); // this shouldn't happen!
}
}
void EntityTreeElement::elementEncodeComplete(EncodeBitstreamParams& params, OctreeElementBag* bag) const {
const bool wantDebug = true;
OctreeElementExtraEncodeData* extraEncodeData = params.extraEncodeData;
assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes
assert(extraEncodeData->contains(this));
EntityTreeElementExtraEncodeData* thisExtraEncodeData
= static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this));
// Note: this will be called when OUR element has finished running through encodeTreeBitstreamRecursion()
// which means, it's possible that our parent element hasn't finished encoding OUR data... so
// in this case, our children may be complete, and we should clean up their encode data...
// but not necessarily cleanup our own encode data...
//
// If we're really complete here's what must be true...
// 1) out own data must be complete
// 2) the data for all our immediate children must be complete.
// However, the following might also be the case...
// 1) it's ok for our child trees to not yet be fully encoded/complete...
// SO LONG AS... the our child's node is in the bag ready for encoding
if (wantDebug) {
qDebug() << "------------------------------------------------------------------------------------";
qDebug() << "EntityTreeElement::elementEncodeComplete()...";
qDebug() << " element=" << getAACube();
qDebug() << " encode data (this):" << thisExtraEncodeData;
if (!thisExtraEncodeData->elementCompleted) {
qDebug() << " ******* PROBABLY OK ---- WARNING ********* this element was not complete!!";
qDebug() << " we really only care that our data is complete when we attempt to check our parent...";
}
}
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
EntityTreeElement* childElement = getChildAtIndex(i);
if (childElement) {
bool isThisChildReallyComplete = thisExtraEncodeData->childCompleted[i];
// why would this ever fail???
// If we've encoding this element before... but we're coming back a second time in an attempt to
// encoud our parent... this might happen.
if (extraEncodeData->contains(childElement)) {
EntityTreeElementExtraEncodeData* childExtraEncodeData
= static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(childElement));
// If the child element is not complete, then it should be in the bag for re-encoding
if (!thisExtraEncodeData->childCompleted[i]) {
if (bag->contains(childElement)) {
qDebug() << " GOOD this element's child["<< i << "] " << childElement->getAACube() << " was not complete, but it's in the bag!!";
} else {
qDebug() << " ******* WARNING ********* this element's child["<< i << "] " << childElement->getAACube() << " was not complete, AND IT'S NOT IN THE BAG!!";
}
}
if (wantDebug) {
qDebug() << " child[" << i <<"] has extra data";
qDebug() << " child:" << childElement->getAACube();
qDebug() << " encode data (child):" << childExtraEncodeData;
// If we're completing THIS element then ALL of our child elements must have been able to add their element data
if (childExtraEncodeData->elementCompleted) {
qDebug() << " GOOD this element's child["<< i << "] " << childElement->getAACube() << " element data was complete!!";
} else {
qDebug() << " ******* WARNING ********* this element's child["<< i << "] " << childElement->getAACube() << " element data was NOT COMPLETE!!";
}
}
for (int ii = 0; ii < NUMBER_OF_CHILDREN; ii++) {
if (!childExtraEncodeData->childCompleted[ii]) {
OctreeElement* grandChild = childElement->getChildAtIndex(ii);
if (bag->contains(childElement)) {
qDebug() << " GOOD this element's child["<< i << "]'s child["<< ii << "] " << grandChild->getAACube()
<< " was not complete, but the child " << childElement->getAACube() << " is in the bag!!";
} else {
qDebug() << " ******* WARNING ********* this element's child["<< i << "]'s child["<< ii << "] " << grandChild->getAACube()
<< " was not complete, AND THE CHILD " << childElement->getAACube() << " IS NOT IN THE BAG!!";
}
isThisChildReallyComplete = false;
}
}
if (isThisChildReallyComplete) {
/*
qDebug() << " REMOVE CHILD EXTRA DATA....";
qDebug() << " DELETING -- CHILD EXTRA DATA....";
qDebug() << " REMOVING encode data (" << __LINE__ << ") for element " << childElement->getAACube() << " data=" << childExtraEncodeData;
extraEncodeData->remove(childElement);
delete childExtraEncodeData;
*/
}
} else {
qDebug() << " ******* WARNING ********* this element's child["<< i << "] " << childElement->getAACube() << " didn't have extra encode data ------ UNEXPECTED!!!!!";
}
}
}
qDebug() << "------------------------------------------------------------------------------------";
}
OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData* packetData,
EncodeBitstreamParams& params) const {
@ -61,6 +301,7 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
qDebug() << " START OF ELEMENT packetData->uncompressed size:" << packetData->getUncompressedSize();
qDebug() << " params.lastViewFrustumSent=" << params.lastViewFrustumSent;
}
OctreeElement::AppendState appendElementState = OctreeElement::COMPLETED; // assume the best...
// first, check the params.extraEncodeData to see if there's any partial re-encode data for this element
@ -73,9 +314,42 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
} else {
// if there wasn't one already, then create one
entityTreeElementExtraEncodeData = new EntityTreeElementExtraEncodeData();
qDebug() << "EntityTreeElement::appendElementData()... ENCODE DATA MISSING, SETTING IT UP NOW ";
qDebug() << " element:" << getAACube();
entityTreeElementExtraEncodeData->elementCompleted = (_entityItems->size() == 0);
qDebug() << " elementCompleted:" << entityTreeElementExtraEncodeData->elementCompleted << "[ _entityItems->size()=" << _entityItems->size() <<" ]";
qDebug() << " --- initialize child elements state ---";
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
EntityTreeElement* child = getChildAtIndex(i);
if (!child) {
entityTreeElementExtraEncodeData->childCompleted[i] = true; // if no child exists, it is completed
qDebug() << " childCompleted[" << i <<"]= true -- completed";
} else {
if (child->hasEntities()) {
qDebug() << " childCompleted[" << i <<"] " << child->getAACube() << "= false -- HAS ENTITIES NEEDS ENCODING";
} else {
entityTreeElementExtraEncodeData->childCompleted[i] = true; // if the child doesn't have enities, it is completed
qDebug() << " childCompleted[" << i <<"] " << child->getAACube() << "= true -- doesn't have entities";
}
}
}
qDebug() << " --- initialize this element's entities state ---";
for (uint16_t i = 0; i < _entityItems->size(); i++) {
EntityItem* entity = (*_entityItems)[i];
entityTreeElementExtraEncodeData->entities.insert(entity->getEntityItemID(), entity->getEntityProperties(params));
}
}
//assert(extraEncodeData);
//assert(extraEncodeData->contains(this));
//entityTreeElementExtraEncodeData = static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this));
LevelDetails elementLevel = packetData->startLevel();
if (wantDebug) {
qDebug() << "------------- elementLevel = packetData->startLevel() -------------";
}
// write our entities out... first determine which of the entities are in view based on our params
uint16_t numberOfEntities = 0;
@ -86,50 +360,56 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
qDebug() << "EntityTreeElement::appendElementData() _entityItems->size()=" << _entityItems->size();
}
for (uint16_t i = 0; i < _entityItems->size(); i++) {
EntityItem* entity = (*_entityItems)[i];
bool includeThisEntity = true;
// It's possible that our element has been previous completed. In this case we'll simply not include any of our
// entities for encoding. This is needed because we encode the element data at the "parent" level, and so we
// need to handle the case where our sibling elements need encoding but we don't.
if (!entityTreeElementExtraEncodeData->elementCompleted) {
for (uint16_t i = 0; i < _entityItems->size(); i++) {
EntityItem* entity = (*_entityItems)[i];
bool includeThisEntity = true;
if (wantDebug) {
qDebug() << "params.forceSendScene=" << params.forceSendScene;
qDebug() << "entity->getLastEdited()=" << entity->getLastEdited();
qDebug() << "entity->getLastEdited() > params.lastViewFrustumSent="
<< (entity->getLastEdited() > params.lastViewFrustumSent);
}
if (!params.forceSendScene && entity->getLastEdited() < params.lastViewFrustumSent) {
if (wantDebug) {
qDebug() << "NOT forceSendScene, and not changed since last sent SUPPRESSING this ENTITY"
<< entity->getEntityItemID();
if (false && wantDebug) {
qDebug() << "params.forceSendScene=" << params.forceSendScene;
qDebug() << "entity->getLastEdited()=" << entity->getLastEdited();
qDebug() << "entity->getLastEdited() > params.lastViewFrustumSent="
<< (entity->getLastEdited() > params.lastViewFrustumSent);
}
includeThisEntity = false;
}
if (hadElementExtraData) {
includeThisEntity = includeThisEntity &&
entityTreeElementExtraEncodeData->includedItems.contains(entity->getEntityItemID());
if (wantDebug) {
qDebug() << " hadElementExtraData=" << hadElementExtraData;
qDebug() << " entity[" << i <<"].entityItemID=" << entity->getEntityItemID();
qDebug() << " entity[" << i <<"].includeThisEntity=" << includeThisEntity;
if (!params.forceSendScene && entity->getLastEdited() < params.lastViewFrustumSent) {
if (false && wantDebug) {
qDebug() << "NOT forceSendScene, and not changed since last sent SUPPRESSING this ENTITY"
<< entity->getEntityItemID();
}
includeThisEntity = false;
}
}
if (includeThisEntity && params.viewFrustum) {
AACube entityCube = entity->getAACube();
entityCube.scale(TREE_SCALE);
if (params.viewFrustum->cubeInFrustum(entityCube) == ViewFrustum::OUTSIDE) {
includeThisEntity = false; // out of view, don't include it
if (hadElementExtraData) {
includeThisEntity = includeThisEntity &&
entityTreeElementExtraEncodeData->entities.contains(entity->getEntityItemID());
if (wantDebug) {
qDebug() << " entity[" << i <<"] cubeInFrustum(entityCube) == ViewFrustum::OUTSIDE "
"includeThisEntity=" << includeThisEntity;
if (includeThisEntity) {
qDebug() << " entity[" << i <<"].entityItemID=" << entity->getEntityItemID();
qDebug() << " entity[" << i <<"].includeThisEntity=" << includeThisEntity;
}
}
}
}
if (includeThisEntity) {
indexesOfEntitiesToInclude << i;
numberOfEntities++;
if (includeThisEntity && params.viewFrustum) {
AACube entityCube = entity->getAACube();
entityCube.scale(TREE_SCALE);
if (params.viewFrustum->cubeInFrustum(entityCube) == ViewFrustum::OUTSIDE) {
includeThisEntity = false; // out of view, don't include it
if (wantDebug) {
qDebug() << " entity[" << i <<"] cubeInFrustum(entityCube) == ViewFrustum::OUTSIDE "
"includeThisEntity=" << includeThisEntity;
}
}
}
if (includeThisEntity) {
indexesOfEntitiesToInclude << i;
numberOfEntities++;
}
}
}
@ -173,13 +453,25 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
qDebug() << "--- AFTER entity ---";
qDebug() << " packetData->getUncompressedSize=" << packetData->getUncompressedSize() << "line:" << __LINE__;
qDebug() << " packetData->getReservedBytes=" << packetData->getReservedBytes();
switch(appendEntityState) {
case OctreeElement::NONE:
qDebug() << " indexesOfEntitiesToInclude.... entity[" << i <<"] DIDN'T FIT!!!";
break;
case OctreeElement::PARTIAL:
qDebug() << " indexesOfEntitiesToInclude.... entity[" << i <<"] PARTIAL FIT!!!";
break;
case OctreeElement::COMPLETED:
qDebug() << " indexesOfEntitiesToInclude.... entity[" << i <<"] IT ALL FIT!!!";
break;
}
}
// If none of this entity data was able to be appended, then discard it
// and don't include it in our entity count
if (appendEntityState == OctreeElement::NONE) {
if (wantDebug) {
qDebug() << " indexesOfEntitiesToInclude.... entity[" << i <<"] DIDN'T FIT!!!";
qDebug() << " calling discardLevel(entityLevel)...";
}
packetData->discardLevel(entityLevel);
} else {
@ -188,33 +480,31 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
packetData->endLevel(entityLevel);
actualNumberOfEntities++;
if (wantDebug) {
qDebug() << " indexesOfEntitiesToInclude.... entity[" << i <<"] ALL OR SOME FIT!!!";
qDebug() << " calling endLevel(entityLevel)...";
}
}
// If the entity item got completely appended, then we can remove it from the extra encode data
if (appendEntityState == OctreeElement::COMPLETED) {
entityTreeElementExtraEncodeData->includedItems.remove(entity->getEntityItemID());
if (wantDebug) {
qDebug() << " indexesOfEntitiesToInclude.... entity[" << i <<"] IT ALL FIT!!!";
}
} else {
if (wantDebug) {
if (appendEntityState == OctreeElement::NONE) {
qDebug() << " indexesOfEntitiesToInclude.... entity[" << i <<"] DIDN'T FIT!!!";
} else {
qDebug() << " indexesOfEntitiesToInclude.... entity[" << i <<"] PARTIAL FIT!!!";
}
qDebug() << " since entity fit, removing it from entities...";
}
entityTreeElementExtraEncodeData->entities.remove(entity->getEntityItemID());
}
// If any part of the entity items didn't fit, then the element is considered partial
// NOTE: if the entity item didn't fit or only partially fit, then the entity item should have
// added itself to the extra encode data.
if (appendEntityState != OctreeElement::COMPLETED) {
if (wantDebug) {
qDebug() << " entity not complete, element must be partial!!!!";
}
appendElementState = OctreeElement::PARTIAL;
}
}
} else {
// we we couldn't add the entity count, then we couldn't add anything for this element and we're in a NONE state
appendElementState = OctreeElement::NONE;
}
if (wantDebug) {
@ -222,30 +512,121 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
qDebug() << " actualNumberOfEntities=" << actualNumberOfEntities;
qDebug() << " numberOfEntities=" << numberOfEntities;
qDebug() << " appendElementState=" << appendElementState;
switch(appendElementState) {
case OctreeElement::NONE:
qDebug() << " OctreeElement::NONE";
break;
case OctreeElement::PARTIAL:
qDebug() << " OctreeElement::PARTIAL";
break;
case OctreeElement::COMPLETED:
qDebug() << " OctreeElement::COMPLETED";
break;
}
}
// If we were provided with extraEncodeData, and we allocated and/or got entityTreeElementExtraEncodeData
// then we need to do some additional processing, namely make sure our extraEncodeData is up to date for
// this octree element.
if (extraEncodeData && entityTreeElementExtraEncodeData) {
if (wantDebug) {
qDebug() << " handling extra encode data....";
}
// If after processing we have some includedItems left in it, then make sure we re-add it back to our map
if (entityTreeElementExtraEncodeData->includedItems.size()) {
// After processing, if we are PARTIAL or COMPLETED then we need to re-include our extra data.
// Only our patent can remove our extra data in these cases and only after it knows that all of it's
// children have been encoded.
// If we weren't able to encode ANY data about ourselves, then we go ahead and remove our element data
// since that will signal that the entire element needs to be encoded on the next attempt
if (appendElementState == OctreeElement::NONE) {
if (!entityTreeElementExtraEncodeData->elementCompleted && entityTreeElementExtraEncodeData->entities.size() == 0) {
/*
if (wantDebug) {
qDebug() << " REMOVING OUR EXTRA DATA BECAUSE NOTHING FIT AND WE HAD NO PREVIOUS DATA....";
qDebug() << " for element:" << getAACube();
qDebug() << " elementCompleted=" << entityTreeElementExtraEncodeData->elementCompleted;
qDebug() << " entities.size()=" << entityTreeElementExtraEncodeData->entities.size();
qDebug() << " appendElementState=";
switch(appendElementState) {
case OctreeElement::NONE:
qDebug() << " OctreeElement::NONE";
break;
case OctreeElement::PARTIAL:
qDebug() << " OctreeElement::PARTIAL";
break;
case OctreeElement::COMPLETED:
qDebug() << " OctreeElement::COMPLETED";
break;
}
}
qDebug() << " --------- DO WE REALLY WANT TO DO THIS?????????????? --------------------";
qDebug() << " REMOVING encode data (" << __LINE__ << ") for element " << getAACube() << " data=" << entityTreeElementExtraEncodeData;
extraEncodeData->remove(this);
delete entityTreeElementExtraEncodeData;
*/
} else {
// TODO: some of these inserts might be redundant!!!
qDebug() << " ADDING encode data (" << __LINE__ << ") for element " << getAACube() << " data=" << entityTreeElementExtraEncodeData;
extraEncodeData->insert(this, entityTreeElementExtraEncodeData);
if (wantDebug) {
qDebug() << " RE INSERT OUR EXTRA DATA.... NOTHING FIT... BUT WE PREVIOUSLY STORED SOMETHING...";
qDebug() << " for element:" << getAACube();
qDebug() << " elementCompleted=" << entityTreeElementExtraEncodeData->elementCompleted;
qDebug() << " entities.size()=" << entityTreeElementExtraEncodeData->entities.size();
qDebug() << " appendElementState=";
switch(appendElementState) {
case OctreeElement::NONE:
qDebug() << " OctreeElement::NONE";
break;
case OctreeElement::PARTIAL:
qDebug() << " OctreeElement::PARTIAL";
break;
case OctreeElement::COMPLETED:
qDebug() << " OctreeElement::COMPLETED";
break;
}
}
}
} else {
// If we weren't previously completed, check to see if we are
if (!entityTreeElementExtraEncodeData->elementCompleted) {
// If all of our items have been encoded, then we are complete as an element.
if (entityTreeElementExtraEncodeData->entities.size() == 0) {
if (wantDebug) {
qDebug() << " since our entities.size() is 0 --- we are assuming we're done <<<<<<<<<<<<<<<<<<";
}
entityTreeElementExtraEncodeData->elementCompleted = true;
}
}
// TODO: some of these inserts might be redundant!!!
qDebug() << " ADDING encode data (" << __LINE__ << ") for element " << getAACube() << " data=" << entityTreeElementExtraEncodeData;
extraEncodeData->insert(this, entityTreeElementExtraEncodeData);
if (wantDebug) {
qDebug() << " RE INSERT OUR EXTRA DATA....";
qDebug() << " for element:" << getAACube();
qDebug() << " elementCompleted=" << entityTreeElementExtraEncodeData->elementCompleted;
qDebug() << " entities.size()=" << entityTreeElementExtraEncodeData->entities.size();
qDebug() << " appendElementState=";
switch(appendElementState) {
case OctreeElement::NONE:
qDebug() << " OctreeElement::NONE";
break;
case OctreeElement::PARTIAL:
qDebug() << " OctreeElement::PARTIAL";
break;
case OctreeElement::COMPLETED:
qDebug() << " OctreeElement::COMPLETED";
break;
}
}
} else {
// otherwise, clean things up...
extraEncodeData->remove(this);
delete entityTreeElementExtraEncodeData;
if (wantDebug) {
qDebug() << " REMOVE OUR EXTRA DATA....";
}
}
}
@ -288,6 +669,18 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
if (wantDebug) {
qDebug() << "END OF ELEMENT packetData->uncompressed size:" << packetData->getUncompressedSize();
qDebug() << "RETURNING appendElementState=";
switch(appendElementState) {
case OctreeElement::NONE:
qDebug() << " OctreeElement::NONE";
break;
case OctreeElement::PARTIAL:
qDebug() << " OctreeElement::PARTIAL";
break;
case OctreeElement::COMPLETED:
qDebug() << " OctreeElement::COMPLETED";
break;
}
}
return appendElementState;

View file

@ -38,9 +38,28 @@ public:
class EntityTreeElementExtraEncodeData {
public:
QMap<EntityItemID, EntityPropertyFlags> includedItems;
EntityTreeElementExtraEncodeData() :
elementCompleted(false),
entities() {
memset(childCompleted, 0, sizeof(childCompleted));
}
bool elementCompleted;
bool childCompleted[NUMBER_OF_CHILDREN];
QMap<EntityItemID, EntityPropertyFlags> entities;
};
inline QDebug operator<<(QDebug debug, const EntityTreeElementExtraEncodeData* data) {
debug << "{";
debug << " elementCompleted: " << data->elementCompleted << ", ";
debug << " childCompleted[]: ";
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
debug << " " << i << ":" << data->childCompleted[i] << ", ";
}
debug << " entities.size: " << data->entities.size() << "}";
return debug;
}
class SendModelsOperationArgs {
public:
glm::vec3 root;
@ -59,7 +78,7 @@ public:
virtual ~EntityTreeElement();
// type safe versions of OctreeElement methods
EntityTreeElement* getChildAtIndex(int index) { return (EntityTreeElement*)OctreeElement::getChildAtIndex(index); }
EntityTreeElement* getChildAtIndex(int index) const { return (EntityTreeElement*)OctreeElement::getChildAtIndex(index); }
// methods you can and should override to implement your tree functionality
@ -88,6 +107,14 @@ public:
/// Override to indicate that this element requires a split before editing lower elements in the octree
virtual bool requiresSplit() const { return false; }
virtual void debugExtraEncodeData(EncodeBitstreamParams& params) const;
virtual void initializeExtraEncodeData(EncodeBitstreamParams& params) const;
virtual bool shouldIncludeChild(int childIndex, EncodeBitstreamParams& params) const;
virtual bool shouldRecurseSubtree(OctreeElement* parent, EncodeBitstreamParams& params, OctreeElementBag* bag) const;
virtual void updateEncodedData(int childIndex, AppendState childAppendState, EncodeBitstreamParams& params) const;
virtual void elementEncodeComplete(EncodeBitstreamParams& params, OctreeElementBag* bag) const;
/// Override to serialize the state of this element. This is used for persistance and for transmission across the network.
virtual OctreeElement::AppendState appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const;

View file

@ -93,9 +93,9 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties, bool
bool wantDebug = false;
if (wantDebug) {
uint64_t now = usecTimestampNow();
int elapsed = now - _lastEdited;
int elapsed = now - getLastEdited();
qDebug() << "ModelEntityItem::setProperties() AFTER update... edited AGO=" << elapsed <<
"now=" << now << " _lastEdited=" << _lastEdited;
"now=" << now << " getLastEdited()=" << getLastEdited();
}
setLastEdited(properties._lastEdited);
}
@ -141,8 +141,14 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
QString modelURLString((const char*)dataAt);
dataAt += modelURLLength;
bytesRead += modelURLLength;
qDebug() << "ModelEntityItem::readEntitySubclassDataFromBuffer().... EntityID: " << getEntityItemID() << " --- PROP_MODEL_URL:" << modelURLString;
if (overwriteLocalData) {
setModelURL(modelURLString);
qDebug() << " setModelURL(modelURLString)=" << getModelURL();
} else {
qDebug() << " WARNING >>>>>>>>>>> IGNORING NEW DATA!!!! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<";
}
}
@ -223,11 +229,11 @@ int ModelEntityItem::oldVersionReadEntityDataFromBuffer(const unsigned char* dat
_lastUpdated -= clockSkew;
// _lastEdited
memcpy(&_lastEdited, dataAt, sizeof(_lastEdited));
dataAt += sizeof(_lastEdited);
bytesRead += sizeof(_lastEdited);
_lastEdited -= clockSkew;
_created = _lastEdited; // NOTE: old models didn't have age or created time, assume their last edit was a create
memcpy(&_lastEditedRemote, dataAt, sizeof(_lastEditedRemote));
dataAt += sizeof(_lastEditedRemote);
bytesRead += sizeof(_lastEditedRemote);
_lastEditedRemote -= clockSkew;
_created = _lastEditedRemote; // NOTE: old models didn't have age or created time, assume their last edit was a create
QString ageAsString = formatSecondsElapsed(getAge());
qDebug() << "Loading old model file, _created = _lastEdited =" << _created
@ -320,7 +326,7 @@ EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams&
void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
@ -350,6 +356,9 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
LevelDetails propertyLevel = packetData->startLevel();
successPropertyFits = packetData->appendValue(getModelURL());
if (successPropertyFits) {
qDebug() << "ModelEntityItem::appendSubclassData().... EntityID: " << getEntityItemID() << " --- PROP_MODEL_URL:" << getModelURL();
propertyFlags |= PROP_MODEL_URL;
propertiesDidntFit -= PROP_MODEL_URL;
propertyCount++;

View file

@ -30,7 +30,7 @@ public:
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const;
virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,

View file

@ -58,9 +58,9 @@ bool SphereEntityItem::setProperties(const EntityItemProperties& properties, boo
bool wantDebug = false;
if (wantDebug) {
uint64_t now = usecTimestampNow();
int elapsed = now - _lastEdited;
int elapsed = now - getLastEdited();
qDebug() << "SphereEntityItem::setProperties() AFTER update... edited AGO=" << elapsed <<
"now=" << now << " _lastEdited=" << _lastEdited;
"now=" << now << " getLastEdited()=" << getLastEdited();
}
setLastEdited(properties.getLastEdited());
}

View file

@ -1,7 +1,41 @@
// REQUIRED:
2) Test file save load for case where two siblings have more than MTU amount of data. I wonder if the fact that file save
doesn't include the extra exists bits will break something.
http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/Feisar_Ship.FBX#1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/newInvader16x16-large-purple.svo#1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
-123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1) clock skew sometimes causes properties to get reject when sent from the server...
-- this appears to be related to clock skew!!!
-- need to determine "when to deleted extra data" --
When encoding ----
if the parent node gets pulled from the bag first... things go ok
if the child node gets pulled first --
and it encodes the grandchildren ---
THEN -- it seems like things break:
1) the parent node will encode the children -- OK
2) then will attempt to recurse into the children..
7) some jutter with moving entities
-- I think this might only happen with lots of models in an element or in view
@ -14,20 +48,27 @@
- does the same pruning/reallocating issue as the old UpdateEntityOperator
- doesn't used clamped boxes for best fit tests... so could be problematic
-- crash on shutdown while animating...
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 io.highfidelity.Interface 0x000000010cf99a6a EntityTree::updateChangingEntities(unsigned long long, QSet<EntityItemID>&) + 202
1 io.highfidelity.Interface 0x000000010cf998a6 EntityTree::update() + 70
2 io.highfidelity.Interface 0x000000010cb64a3e EntityTreeRenderer::update() + 62
3 io.highfidelity.Interface 0x000000010c9eb6ec Application::update(float) + 796
4 io.highfidelity.Interface 0x000000010c9f5e26 Application::idle() + 550
5 io.highfidelity.Interface 0x000000010c99f567 Application::qt_static_metacall(QObject*, QMetaObject::Call, int, void**) + 1655
6 QtCore 0x0000000112474a30 QMetaObject::activate(QObject*, int, int, void**) + 2640
7 QtCore 0x000000011246d5c1 QObject::event(QEvent*) + 49
// NICE TO HAVE:
1) clean up Octree::encodeTreeBitstreamRecursion() --
It would be nice to clean up this function to be shorter...
1015-1158 - helper functions "exit early helpers"
1200-1245 - helper function "sorted children"
1248-1376 - helper function "visible children" -
this handles LOD, occlusion, in view/was in view for child elements
NOTE: this information could be cached for secondary passes of the element
in the same scene encode since they shouldn't change in same scene encode
11) quickly do some edits... then change domains... watch the entities continue to exist in new domain and move around.
-- verify this happens in old code, if so... move to "nice to have"
-- maybe this relates to having incoming packets waiting in the processing queue... they should be discarded on switching domains?
Z) Consider using client side "on the fly" billboard of entites to handle LOD
-- have routine to shoot views of an entity for 6 faces
-- store those images in the entity on the client
@ -102,9 +143,17 @@
10 libsystem_pthread.dylib 0x00007fff8bb9afc9 thread_start + 13
11) quickly do some edits... then change domains... watch the entities continue to exist in new domain and move around.
-- verify this happens in old code, if so... move to "nice to have"
-- crash on shutdown while animating...???
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 io.highfidelity.Interface 0x000000010cf99a6a EntityTree::updateChangingEntities(unsigned long long, QSet<EntityItemID>&) + 202
1 io.highfidelity.Interface 0x000000010cf998a6 EntityTree::update() + 70
2 io.highfidelity.Interface 0x000000010cb64a3e EntityTreeRenderer::update() + 62
3 io.highfidelity.Interface 0x000000010c9eb6ec Application::update(float) + 796
4 io.highfidelity.Interface 0x000000010c9f5e26 Application::idle() + 550
5 io.highfidelity.Interface 0x000000010c99f567 Application::qt_static_metacall(QObject*, QMetaObject::Call, int, void**) + 1655
6 QtCore 0x0000000112474a30 QMetaObject::activate(QObject*, int, int, void**) + 2640
7 QtCore 0x000000011246d5c1 QObject::event(QEvent*) + 49
===============
@ -237,6 +286,7 @@
// SOLVED -- 52) Look into why non-changed octree cells are being resent when editing an entity --
// this is probably because we're marking the trees as dirty -- but we probably can not send entitys that haven't changed
// Solution -- suppress sending of entities that haven't been edited since the last view frustum sent
// SOLVED -- 53) Test sibling cells

View file

@ -952,6 +952,7 @@ int Octree::encodeTreeBitstream(OctreeElement* element,
// If the octalcode couldn't fit, then we can return, because no nodes below us will fit...
if (!roomForOctalCode) {
bag.insert(element);
qDebug() << "params.stopReason = EncodeBitstreamParams::DIDNT_FIT --- line:" << __LINE__;
params.stopReason = EncodeBitstreamParams::DIDNT_FIT;
return bytesWritten;
}
@ -977,9 +978,11 @@ int Octree::encodeTreeBitstream(OctreeElement* element,
// if includeColor and childBytesWritten == 2, then it can only mean that the lower level trees don't exist or for some
// reason couldn't be written... so reset them here... This isn't true for the non-color included case
if (params.includeColor && childBytesWritten == 2) {
childBytesWritten = 0;
//params.stopReason = EncodeBitstreamParams::UNKNOWN; // possibly should be DIDNT_FIT...
if (suppressEmptySubtrees()) {
if (params.includeColor && childBytesWritten == 2) {
childBytesWritten = 0;
//params.stopReason = EncodeBitstreamParams::UNKNOWN; // possibly should be DIDNT_FIT...
}
}
// if we wrote child bytes, then return our result of all bytes written
@ -1010,6 +1013,15 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
// The append state of this level/element.
OctreeElement::AppendState elementAppendState = OctreeElement::COMPLETED; // assume the best
if (element != _rootElement) {
qDebug() << "TOP OF Octree::encodeTreeBitstreamRecursion().... elementAppendState = OctreeElement::COMPLETED ----";
if (element) {
qDebug() << " element=" << element->getAACube();
element->debugExtraEncodeData(params);
} else {
qDebug() << " element=NULL";
}
}
// How many bytes have we written so far at this level;
int bytesAtThisLevel = 0;
@ -1018,6 +1030,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
if (!element) {
qDebug("WARNING! encodeTreeBitstreamRecursion() called with element=NULL");
params.stopReason = EncodeBitstreamParams::NULL_NODE;
qDebug() << "encodeTreeBitstreamRecursion() --- returning from line: " << __LINE__;
return bytesAtThisLevel;
}
@ -1029,6 +1042,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
// If we've reached our max Search Level, then stop searching.
if (currentEncodeLevel >= params.maxEncodeLevel) {
params.stopReason = EncodeBitstreamParams::TOO_DEEP;
qDebug() << "encodeTreeBitstreamRecursion() --- returning from line: " << __LINE__;
return bytesAtThisLevel;
}
@ -1038,6 +1052,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
// but once we're in our own jurisdiction, then we need to make sure we're not below it.
if (JurisdictionMap::BELOW == params.jurisdictionMap->isMyJurisdiction(element->getOctalCode(), CHECK_NODE_ONLY)) {
params.stopReason = EncodeBitstreamParams::OUT_OF_JURISDICTION;
qDebug() << "encodeTreeBitstreamRecursion() --- returning from line: " << __LINE__;
return bytesAtThisLevel;
}
}
@ -1056,6 +1071,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
params.stats->skippedDistance(element);
}
params.stopReason = EncodeBitstreamParams::LOD_SKIP;
qDebug() << "encodeTreeBitstreamRecursion() --- returning from line: " << __LINE__;
return bytesAtThisLevel;
}
@ -1074,6 +1090,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
params.stats->skippedOutOfView(element);
}
params.stopReason = EncodeBitstreamParams::OUT_OF_VIEW;
qDebug() << "encodeTreeBitstreamRecursion() --- returning from line: " << __LINE__;
return bytesAtThisLevel;
}
@ -1114,6 +1131,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
params.stats->skippedWasInView(element);
}
params.stopReason = EncodeBitstreamParams::WAS_IN_VIEW;
qDebug() << "encodeTreeBitstreamRecursion() --- returning from line: " << __LINE__;
return bytesAtThisLevel;
}
@ -1125,6 +1143,9 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
params.stats->skippedNoChange(element);
}
params.stopReason = EncodeBitstreamParams::NO_CHANGE;
if (element != _rootElement) {
qDebug() << "encodeTreeBitstreamRecursion() --- returning from line: " << __LINE__;
}
return bytesAtThisLevel;
}
@ -1145,6 +1166,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
params.stats->skippedOccluded(element);
}
params.stopReason = EncodeBitstreamParams::OCCLUDED;
qDebug() << "encodeTreeBitstreamRecursion() --- returning from line: " << __LINE__;
return bytesAtThisLevel;
}
} else {
@ -1171,14 +1193,30 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
int requiredBytes = sizeof(childrenDataBits) + sizeof(childrenExistInPacketBits);
if (params.includeExistsBits) {
requiredBytes += sizeof(childrenExistInTreeBits);
}
}
// If this datatype allows root elements to include data, and this is the root, then ask the tree for the
// minimum bytes needed for root data and reserve those also
if (element == _rootElement && rootElementHasData()) {
requiredBytes += minimumRequiredRootDataBytes();
if (wantDebug) {
qDebug() << "Reserving at least " << minimumRequiredRootDataBytes() << " additional bytes for root data <<<<<<<<<<";
}
}
if (wantDebug) {
qDebug() << "Reserving total of " << requiredBytes <<" bytes for this elements data <<<<<<<<<<<<<<";
}
bool continueThisLevel = packetData->reserveBytes(requiredBytes);
// If we can't reserve our minimum bytes then we can discard this level and return as if none of this level fits
if (!continueThisLevel) {
qDebug() << " .....COULDN'T RESERVE MINIMUM BYTES.....";
packetData->discardLevel(thisLevelKey);
qDebug() << "params.stopReason = EncodeBitstreamParams::DIDNT_FIT --- line:" << __LINE__;
params.stopReason = EncodeBitstreamParams::DIDNT_FIT;
bag.insert(element);
qDebug() << "encodeTreeBitstreamRecursion() --- returning from line: " << __LINE__;
return bytesAtThisLevel;
}
@ -1361,29 +1399,41 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
}
}
// NOTE: the childrenDataBits is really more generically the childDataBits and it indicates
// that there is an array of child element data included in this packet. We wil write this bit mask
// but we may come back later and update the bits that are actually included
// NOTE: the childrenDataBits indicates that there is an array of child element data included in this packet.
// We wil write this bit mask but we may come back later and update the bits that are actually included
packetData->releaseReservedBytes(sizeof(childrenDataBits));
continueThisLevel = packetData->appendBitMask(childrenDataBits);
// we know the last thing we wrote to the packet was our childrenDataBits. Let's remember where that was!
int childDataBitsPlaceHolder = packetData->getUncompressedByteOffset(sizeof(childrenDataBits));
unsigned char actualChildrenDataBits = 0;
if (continueThisLevel) {
bytesAtThisLevel += sizeof(childrenDataBits); // keep track of byte count
if (params.stats) {
params.stats->colorBitsWritten();
}
assert(continueThisLevel); // since we used reserved bits, this really shouldn't fail
bytesAtThisLevel += sizeof(childrenDataBits); // keep track of byte count
if (params.stats) {
params.stats->colorBitsWritten(); // really data bits not just color bits
}
// write the child element data...
if (continueThisLevel && params.includeColor) {
// NOW might be a good time to give our tree subclass and this element a chance to set up and check any extra encode data
element->initializeExtraEncodeData(params);
// write the child element data... NOTE: includeColor means include element data
// NOTE: the format of the bitstream is generally this:
// [octalcode]
// [bitmask for existence of child data]
// N x [child data]
// [bitmask for existence of child elements in tree]
// [bitmask for existence of child elements in buffer]
// N x [ ... tree for children ...]
//
// This section of the code, is writing the "N x [child data]" portion of this bitstream
if (params.includeColor) {
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
if (oneAtBit(childrenDataBits, i)) {
OctreeElement* childElement = element->getChildAtIndex(i);
if (childElement) {
// the childrenDataBits were set up by the in view/LOD logic, it may contain children that we've already
// processed and sent the data bits for. Let our tree subclass determine if it really wants to send the
// data for this child at this point
if (childElement && element->shouldIncludeChild(i, params)) {
int bytesBeforeChild = packetData->getUncompressedSize();
@ -1394,7 +1444,11 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
// to be completed.
LevelDetails childDataLevelKey = packetData->startLevel();
qDebug() << "Octree::encodeTreeBitstreamRecursion().... calling childElement->appendElementData()... child:" << childElement->getAACube();
OctreeElement::AppendState childAppendState = childElement->appendElementData(packetData, params);
// allow our tree subclass to do any additional bookkeeping it needs to do with encoded data state
element->updateEncodedData(i, childAppendState, params);
// Continue this level so long as some part of this child element was appended.
bool childFit = (childAppendState != OctreeElement::NONE);
@ -1405,15 +1459,27 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
actualChildrenDataBits += (1 << (7 - i));
continueThisLevel = packetData->endLevel(childDataLevelKey);
} else {
if (wantDebug) {
qDebug() << "(childAppendState == OctreeElement::NONE) ... consider this element PARTIAL *************************************************";
qDebug() << " childElement=" << childElement->getAACube();
}
packetData->discardLevel(childDataLevelKey);
elementAppendState = OctreeElement::PARTIAL;
params.stopReason = EncodeBitstreamParams::DIDNT_FIT;
qDebug() << "Octree::encodeTreeBitstreamRecursion().... at least one child didn't fit elementAppendState = OctreeElement::PARTIAL ----";
qDebug() << "params.stopReason = EncodeBitstreamParams::DIDNT_FIT --- line:" << __LINE__;
}
// If this child was partially appended, then consider this element to be partially appended
if (childAppendState == OctreeElement::PARTIAL) {
if (wantDebug) {
qDebug() << "(childAppendState == OctreeElement::PARTIAL) ... consider this element PARTIAL";
qDebug() << " childElement=" << childElement->getAACube();
}
elementAppendState = OctreeElement::PARTIAL;
params.stopReason = EncodeBitstreamParams::DIDNT_FIT;
qDebug() << "Octree::encodeTreeBitstreamRecursion().... at least one child WAS PARTIAL elementAppendState = OctreeElement::PARTIAL ----";
qDebug() << "params.stopReason = EncodeBitstreamParams::DIDNT_FIT --- line:" << __LINE__;
}
int bytesAfterChild = packetData->getUncompressedSize();
@ -1424,14 +1490,35 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
if (params.stats && (childAppendState != OctreeElement::NONE)) {
params.stats->colorSent(childElement);
}
} else {
qDebug() << "Octree::encodeTreeBitstreamRecursion().... DIDN'T ATTEMPT TO appendElementData() for child[" << i << "]";
if (childElement) {
qDebug() << " childElement=" << childElement->getAACube();
} else {
qDebug() << " childElement=NULL";
}
}
}
}
}
if (!continueThisLevel) {
qDebug() << "******* WARNING UNEXPECTED CASE ***********************************************************";
qDebug() << "reached end of child element data loop with continueThisLevel=FALSE....";
qDebug() << "This is not expected!!!!";
qDebug() << "*******************************************************************************************";
}
if (actualChildrenDataBits != childrenDataBits) {
// repair the child data mask
continueThisLevel = packetData->updatePriorBitMask(childDataBitsPlaceHolder, actualChildrenDataBits);
if (!continueThisLevel) {
qDebug() << "******* WARNING UNEXPECTED CASE ***********************************************************";
qDebug() << "Failed to update childDataBitsPlaceHolder -- continueThisLevel=FALSE....";
qDebug() << "This is not expected!!!!";
qDebug() << "*******************************************************************************************";
}
}
// if the caller wants to include childExistsBits, then include them even if not in view, put them before the
@ -1444,6 +1531,11 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
if (params.stats) {
params.stats->existsBitsWritten();
}
} else {
qDebug() << "******* WARNING UNEXPECTED CASE ***********************************************************";
qDebug() << "Failed to append childrenExistInTreeBits -- continueThisLevel=FALSE....";
qDebug() << "This is not expected!!!!";
qDebug() << "*******************************************************************************************";
}
}
@ -1456,12 +1548,28 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
if (params.stats) {
params.stats->existsInPacketBitsWritten();
}
} else {
qDebug() << "******* WARNING UNEXPECTED CASE ***********************************************************";
qDebug() << "Failed to append childrenExistInPacketBits -- continueThisLevel=FALSE....";
qDebug() << "This is not expected!!!!";
qDebug() << "*******************************************************************************************";
}
}
// We only need to keep digging, if there is at least one child that is inView, and not a leaf.
keepDiggingDeeper = (inViewNotLeafCount > 0);
//
// NOTE: the format of the bitstream is generally this:
// [octalcode]
// [bitmask for existence of child data]
// N x [child data]
// [bitmask for existence of child elements in tree]
// [bitmask for existence of child elements in buffer]
// N x [ ... tree for children ...]
//
// This section of the code, is writing the "N x [ ... tree for children ...]" portion of this bitstream
//
if (continueThisLevel && keepDiggingDeeper) {
// at this point, we need to iterate the children who are in view, even if not colored
@ -1505,8 +1613,10 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
// recursing, by returning TRUE in recurseChildrenWithData().
if (recurseChildrenWithData() || !params.viewFrustum || !oneAtBit(childrenDataBits, originalIndex)) {
childTreeBytesOut = encodeTreeBitstreamRecursion(childElement, packetData, bag, params,
thisLevel, nodeLocationThisView);
if (childElement->shouldRecurseSubtree(element, params, &bag)) {
childTreeBytesOut = encodeTreeBitstreamRecursion(childElement, packetData, bag, params,
thisLevel, nodeLocationThisView);
}
}
// remember this for reshuffling
@ -1552,6 +1662,12 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
// repair the child exists mask
continueThisLevel = packetData->updatePriorBitMask(childExistsPlaceHolder, childrenExistInPacketBits);
if (!continueThisLevel) {
qDebug() << "******* WARNING UNEXPECTED CASE ***********************************************************";
qDebug() << "Failed to update childExistsPlaceHolder -- continueThisLevel=FALSE....";
qDebug() << "This is not expected!!!!";
qDebug() << "*******************************************************************************************";
}
// If this is the last of the child exists bits, then we're actually be rolling out the entire tree
if (params.stats && childrenExistInPacketBits == 0) {
@ -1559,7 +1675,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
}
if (!continueThisLevel) {
if (wantDebug) {
if (true || wantDebug) {
qDebug() << " WARNING line:" << __LINE__;
qDebug() << " breaking the child recursion loop with continueThisLevel=false!!!";
qDebug() << " AFTER attempting to updatePriorBitMask() for empty sub tree....";
@ -1594,6 +1710,12 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
// now that all slices are back in the correct order, copy them to the correct output buffer
continueThisLevel = packetData->updatePriorBytes(firstRecursiveSliceOffset, &tempReshuffleBuffer[0], allSlicesSize);
if (!continueThisLevel) {
qDebug() << "******* WARNING UNEXPECTED CASE ***********************************************************";
qDebug() << "Failed to update recursive slice!!! -- continueThisLevel=FALSE....";
qDebug() << "This is not expected!!!!";
qDebug() << "*******************************************************************************************";
}
}
} // end keepDiggingDeeper
@ -1603,6 +1725,10 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
int bytesBeforeChild = packetData->getUncompressedSize();
// release the bytes we reserved...
qDebug() << "RELEASING previously reserved " << minimumRequiredRootDataBytes() << " bytes for root -- line:" << __LINE__;
packetData->releaseReservedBytes(minimumRequiredRootDataBytes());
LevelDetails rootDataLevelKey = packetData->startLevel();
OctreeElement::AppendState rootAppendState = element->appendElementData(packetData, params);
bool partOfRootFit = (rootAppendState != OctreeElement::NONE);
@ -1620,6 +1746,8 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
if (!allOfRootFit) {
elementAppendState = OctreeElement::PARTIAL;
params.stopReason = EncodeBitstreamParams::DIDNT_FIT;
qDebug() << "Octree::encodeTreeBitstreamRecursion().... ROOT DATA WAS PARTIAL OR DIDN'T FIT elementAppendState = OctreeElement::PARTIAL ----";
qDebug() << "params.stopReason = EncodeBitstreamParams::DIDNT_FIT --- line:" << __LINE__;
}
// do we really ever NOT want to continue this level???
@ -1634,6 +1762,14 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
params.stats->colorSent(element);
}
}
if (!continueThisLevel) {
qDebug() << "******* WARNING UNEXPECTED CASE ***********************************************************";
qDebug() << "Something failed in packing ROOT data -- continueThisLevel=FALSE....";
qDebug() << "This is not expected!!!!";
qDebug() << "*******************************************************************************************";
}
}
// if we were unable to fit this level in our packet, then rewind and add it to the element bag for
@ -1642,12 +1778,22 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
continueThisLevel = packetData->endLevel(thisLevelKey);
} else {
packetData->discardLevel(thisLevelKey);
qDebug() << "******* WARNING UNEXPECTED CASE ***********************************************************";
qDebug() << "Something failed in attempting to pack this element -- continueThisLevel=FALSE....";
qDebug() << "This is not expected!!!!";
qDebug() << "*******************************************************************************************";
}
// This happens if the element could not be written at all. In the case of Octree's that support partial
// element data, continueThisLevel will be true. So this only happens if the full element needs to be
// added back to the element bag.
if (!continueThisLevel) {
qDebug() << "******* WARNING UNEXPECTED CASE ***********************************************************";
qDebug() << "Something failed in attempting to pack this element -- continueThisLevel=FALSE....";
qDebug() << "IS THIS EVER EXPECTED????";
qDebug() << " calling bag.insert(element);.....";
qDebug() << "*******************************************************************************************";
bag.insert(element);
// don't need to check element here, because we can't get here with no element
@ -1656,6 +1802,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
}
params.stopReason = EncodeBitstreamParams::DIDNT_FIT;
qDebug() << "params.stopReason = EncodeBitstreamParams::DIDNT_FIT --- line:" << __LINE__;
bytesAtThisLevel = 0; // didn't fit
} else {
@ -1665,10 +1812,31 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
// and assume that the appendElementData() has stored any required state data
// in the params extraEncodeData
if (elementAppendState == OctreeElement::PARTIAL) {
if (true || wantDebug) {
qDebug() << "(elementAppendState == OctreeElement::PARTIAL) ...";
qDebug() << " RE INSERT THIS(parent) element into bag";
qDebug() << " element:" << element->getAACube();
}
bag.insert(element);
}
}
// If our element is completed let the element know so it can do any cleanup it of extra wants
if (elementAppendState == OctreeElement::COMPLETED) {
if (true || wantDebug) {
qDebug() << "*********************************************************************************************************";
qDebug() << "(elementAppendState == OctreeElement::COMPLETED)";
qDebug() << " calling element->elementEncodeComplete(params)";
qDebug() << " element=" << element->getAACube();
}
element->elementEncodeComplete(params, &bag);
if (true || wantDebug) {
qDebug() << "*********************************************************************************************************";
}
}
qDebug() << "encodeTreeBitstreamRecursion() --- returning from line: " << __LINE__;
return bytesAtThisLevel;
}
@ -1855,11 +2023,18 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElement* element) {
params.extraEncodeData = &extraEncodeData;
while (!elementBag.isEmpty()) {
qDebug() << "WRITING SVO ---- START LOOP ---------------";
OctreeElement* subTree = elementBag.extract();
qDebug() << "WRITING SVO subTree=" << subTree->getAACube();
lockForRead(); // do tree locking down here so that we have shorter slices and less thread contention
bytesWritten = encodeTreeBitstream(subTree, &packetData, elementBag, params);
unlock();
qDebug() << "WRITING SVO subTree=" << subTree->getAACube() << " bytesWritten=" << bytesWritten;
qDebug() << "WRITING SVO subTree=" << subTree->getAACube() << " params.stopReason=" << params.getStopReason();
qDebug() << "WRITING SVO subTree=" << subTree->getAACube() << " packetData.hasContent()=" << packetData.hasContent();
// if the subTree couldn't fit, and so we should reset the packet and reinsert the element in our bag and try again
if (bytesWritten == 0 && (params.stopReason == EncodeBitstreamParams::DIDNT_FIT)) {
if (packetData.hasContent()) {
@ -1870,13 +2045,16 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElement* element) {
file.write((const char*)&bufferSize, sizeof(bufferSize));
}
file.write((const char*)packetData.getFinalizedData(), packetData.getFinalizedSize());
qDebug() << "WRITING SVO actually writing to the file bufferSize:" << packetData.getFinalizedSize();
lastPacketWritten = true;
}
packetData.reset(); // is there a better way to do this? could we fit more?
qDebug() << "WRITING SVO INSERT SUBTREE FOR ANOTHER GO ... subTree=" << subTree->getAACube();
elementBag.insert(subTree);
} else {
lastPacketWritten = false;
}
qDebug() << "WRITING SVO ---- END LOOP ---------------";
}
if (!lastPacketWritten) {
@ -1887,8 +2065,10 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElement* element) {
file.write((const char*)&bufferSize, sizeof(bufferSize));
}
file.write((const char*)packetData.getFinalizedData(), packetData.getFinalizedSize());
qDebug() << "WRITING SVO actually writing to the file bufferSize:" << packetData.getFinalizedSize();
}
}
qDebug() << "WRITING SVO CLOSING FILE";
file.close();
}

View file

@ -233,6 +233,8 @@ public:
virtual bool recurseChildrenWithData() const { return true; }
virtual bool rootElementHasData() const { return false; }
virtual int minimumRequiredRootDataBytes() const { return 0; }
virtual bool suppressEmptySubtrees() const { return true; }
/// some versions of the SVO file will include breaks with buffer lengths between each buffer chunk in the SVO
/// file. If the Octree subclass expects this for this particular version of the file, it should override this

View file

@ -28,6 +28,7 @@
class EncodeBitstreamParams;
class Octree;
class OctreeElement;
class OctreeElementBag;
class OctreeElementDeleteHook;
class OctreePacketData;
class ReadBitstreamToTreeParams;
@ -90,6 +91,14 @@ public:
/// The state of the call to appendElementData
typedef enum { COMPLETED, PARTIAL, NONE } AppendState;
virtual void debugExtraEncodeData(EncodeBitstreamParams& params) const { }
virtual void initializeExtraEncodeData(EncodeBitstreamParams& params) const { }
virtual bool shouldIncludeChild(int childIndex, EncodeBitstreamParams& params) const { return true; }
virtual bool shouldRecurseSubtree(OctreeElement* parent, EncodeBitstreamParams& params, OctreeElementBag* bag) const { return true; }
virtual void updateEncodedData(int childIndex, AppendState childAppendState, EncodeBitstreamParams& params) const { }
virtual void elementEncodeComplete(EncodeBitstreamParams& params, OctreeElementBag* bag) const { }
/// Override to serialize the state of this element. This is used for persistance and for transmission across the network.
virtual AppendState appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const
{ return COMPLETED; }