mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 14:29:03 +02:00
Merge pull request #3356 from ZappoMan/fixingOctreeSave
voxel file corruption fixes
This commit is contained in:
commit
39ffd3dadd
14 changed files with 315 additions and 67 deletions
|
@ -467,7 +467,7 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char
|
||||||
if (existingEntity) {
|
if (existingEntity) {
|
||||||
updateEntity(entityItemID, properties);
|
updateEntity(entityItemID, properties);
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "User attempted to edit an unknown entity.";
|
qDebug() << "User attempted to edit an unknown entity. ID:" << entityItemID;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// this is a new entity... assign a new entityID
|
// this is a new entity... assign a new entityID
|
||||||
|
|
|
@ -67,7 +67,8 @@ public:
|
||||||
virtual int minimumRequiredRootDataBytes() const { return sizeof(uint16_t); }
|
virtual int minimumRequiredRootDataBytes() const { return sizeof(uint16_t); }
|
||||||
virtual bool suppressEmptySubtrees() const { return false; }
|
virtual bool suppressEmptySubtrees() const { return false; }
|
||||||
virtual void releaseSceneEncodeData(OctreeElementExtraEncodeData* extraEncodeData) const;
|
virtual void releaseSceneEncodeData(OctreeElementExtraEncodeData* extraEncodeData) const;
|
||||||
|
virtual bool mustIncludeAllChildData() const { return false; }
|
||||||
|
|
||||||
virtual bool versionHasSVOfileBreaks(PacketVersion thisVersion) const
|
virtual bool versionHasSVOfileBreaks(PacketVersion thisVersion) const
|
||||||
{ return thisVersion >= VERSION_ENTITIES_HAS_FILE_BREAKS; }
|
{ return thisVersion >= VERSION_ENTITIES_HAS_FILE_BREAKS; }
|
||||||
|
|
||||||
|
@ -126,7 +127,7 @@ public:
|
||||||
void setContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element);
|
void setContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element);
|
||||||
void resetContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element);
|
void resetContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element);
|
||||||
void debugDumpMap();
|
void debugDumpMap();
|
||||||
void dumpTree();
|
virtual void dumpTree();
|
||||||
|
|
||||||
void sendEntities(EntityEditPacketSender* packetSender, EntityTree* localTree, float x, float y, float z);
|
void sendEntities(EntityEditPacketSender* packetSender, EntityTree* localTree, float x, float y, float z);
|
||||||
|
|
||||||
|
|
|
@ -721,9 +721,17 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int
|
||||||
if (bytesLeftToRead >= (int)(numberOfEntities * expectedBytesPerEntity)) {
|
if (bytesLeftToRead >= (int)(numberOfEntities * expectedBytesPerEntity)) {
|
||||||
for (uint16_t i = 0; i < numberOfEntities; i++) {
|
for (uint16_t i = 0; i < numberOfEntities; i++) {
|
||||||
int bytesForThisEntity = 0;
|
int bytesForThisEntity = 0;
|
||||||
EntityItemID entityItemID = EntityItemID::readEntityItemIDFromBuffer(dataAt, bytesLeftToRead);
|
EntityItemID entityItemID;
|
||||||
EntityItem* entityItem = _myTree->findEntityByEntityItemID(entityItemID);
|
EntityItem* entityItem = NULL;
|
||||||
bool newEntity = false;
|
bool newEntity = false;
|
||||||
|
|
||||||
|
// Old model files don't have UUIDs in them. So we don't want to try to read those IDs from the stream.
|
||||||
|
// Since this can only happen on loading an old file, we can safely treat these as new entity cases,
|
||||||
|
// which will correctly handle the case of creating models and letting them parse the old format.
|
||||||
|
if (args.bitstreamVersion >= VERSION_ENTITIES_SUPPORT_SPLIT_MTU) {
|
||||||
|
entityItemID = EntityItemID::readEntityItemIDFromBuffer(dataAt, bytesLeftToRead);
|
||||||
|
entityItem = _myTree->findEntityByEntityItemID(entityItemID);
|
||||||
|
}
|
||||||
|
|
||||||
// If the item already exists in our tree, we want do the following...
|
// If the item already exists in our tree, we want do the following...
|
||||||
// 1) allow the existing item to read from the databuffer
|
// 1) allow the existing item to read from the databuffer
|
||||||
|
@ -758,6 +766,7 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int
|
||||||
if (entityItem) {
|
if (entityItem) {
|
||||||
bytesForThisEntity = entityItem->readEntityDataFromBuffer(dataAt, bytesLeftToRead, args);
|
bytesForThisEntity = entityItem->readEntityDataFromBuffer(dataAt, bytesLeftToRead, args);
|
||||||
addEntityItem(entityItem); // add this new entity to this elements entities
|
addEntityItem(entityItem); // add this new entity to this elements entities
|
||||||
|
entityItemID = entityItem->getEntityItemID();
|
||||||
_myTree->setContainingElement(entityItemID, this);
|
_myTree->setContainingElement(entityItemID, this);
|
||||||
newEntity = true;
|
newEntity = true;
|
||||||
EntityItem::SimulationState newState = entityItem->getSimulationState();
|
EntityItem::SimulationState newState = entityItem->getSimulationState();
|
||||||
|
|
|
@ -65,7 +65,9 @@ bool EntityTypes::registerEntityType(EntityType entityType, const char* name, En
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityItem* EntityTypes::constructEntityItem(EntityType entityType, const EntityItemID& entityID, const EntityItemProperties& properties) {
|
EntityItem* EntityTypes::constructEntityItem(EntityType entityType, const EntityItemID& entityID,
|
||||||
|
const EntityItemProperties& properties) {
|
||||||
|
|
||||||
EntityItem* newEntityItem = NULL;
|
EntityItem* newEntityItem = NULL;
|
||||||
EntityTypeFactory factory = NULL;
|
EntityTypeFactory factory = NULL;
|
||||||
if (entityType >= 0 && entityType <= LAST) {
|
if (entityType >= 0 && entityType <= LAST) {
|
||||||
|
|
|
@ -165,7 +165,8 @@ int ModelEntityItem::oldVersionReadEntityDataFromBuffer(const unsigned char* dat
|
||||||
|
|
||||||
QString ageAsString = formatSecondsElapsed(getAge());
|
QString ageAsString = formatSecondsElapsed(getAge());
|
||||||
qDebug() << "Loading old model file, _created = _lastEdited =" << _created
|
qDebug() << "Loading old model file, _created = _lastEdited =" << _created
|
||||||
<< " age=" << getAge() << "seconds - " << ageAsString;
|
<< " age=" << getAge() << "seconds - " << ageAsString
|
||||||
|
<< "old ID=" << oldID << "new ID=" << _id;
|
||||||
|
|
||||||
// radius
|
// radius
|
||||||
memcpy(&_radius, dataAt, sizeof(_radius));
|
memcpy(&_radius, dataAt, sizeof(_radius));
|
||||||
|
|
|
@ -2053,19 +2053,64 @@ FBXGeometry readSVO(const QByteArray& model) {
|
||||||
mesh.parts.append(part);
|
mesh.parts.append(part);
|
||||||
|
|
||||||
VoxelTree tree;
|
VoxelTree tree;
|
||||||
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS);
|
|
||||||
|
|
||||||
unsigned char* dataAt = (unsigned char*)model.data();
|
unsigned char* dataAt = (unsigned char*)model.data();
|
||||||
size_t dataSize = model.size();
|
size_t dataSize = model.size();
|
||||||
|
|
||||||
if (tree.getWantSVOfileVersions()) {
|
PacketVersion gotVersion = 0;
|
||||||
|
|
||||||
|
// NOTE: SPECIAL CASE for old voxel svo files. The old voxel SVO files didn't have header
|
||||||
|
// details. They started with the the octalcode for the root. Which was always 00 which matches PacketTypeUnknown
|
||||||
|
unsigned char* firstByteAt = (unsigned char*)model.data();
|
||||||
|
unsigned char firstByteValue = *firstByteAt;
|
||||||
|
if (tree.expectedDataPacketType() == PacketTypeVoxelData && firstByteValue == 0) {
|
||||||
|
qDebug() << "Detected OLD Voxels format.";
|
||||||
|
gotVersion = 0;
|
||||||
|
} else if (tree.getWantSVOfileVersions()) {
|
||||||
// skip the type/version
|
// skip the type/version
|
||||||
dataAt += sizeof(PacketType);
|
dataAt += sizeof(PacketType);
|
||||||
dataSize -= sizeof(PacketType);
|
dataSize -= sizeof(PacketType);
|
||||||
|
|
||||||
|
gotVersion = *dataAt;
|
||||||
dataAt += sizeof(PacketVersion);
|
dataAt += sizeof(PacketVersion);
|
||||||
dataSize -= sizeof(PacketVersion);
|
dataSize -= sizeof(PacketVersion);
|
||||||
}
|
}
|
||||||
tree.readBitstreamToTree(dataAt, dataSize, args);
|
bool hasBufferBreaks = tree.versionHasSVOfileBreaks(gotVersion);
|
||||||
|
|
||||||
|
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0,
|
||||||
|
SharedNodePointer(), false, gotVersion);
|
||||||
|
|
||||||
|
if (!hasBufferBreaks) {
|
||||||
|
tree.readBitstreamToTree(dataAt, dataSize, args);
|
||||||
|
} else {
|
||||||
|
const unsigned long MAX_CHUNK_LENGTH = MAX_OCTREE_PACKET_SIZE * 2;
|
||||||
|
while (dataSize > 0) {
|
||||||
|
quint16 chunkLength = 0;
|
||||||
|
|
||||||
|
chunkLength = *dataAt;
|
||||||
|
dataAt += sizeof(chunkLength);
|
||||||
|
dataSize -= sizeof(chunkLength);
|
||||||
|
|
||||||
|
if (chunkLength > dataSize) {
|
||||||
|
qDebug() << "UNEXPECTED chunk size of:" << chunkLength
|
||||||
|
<< "greater than remaining length:" << dataSize;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chunkLength > MAX_CHUNK_LENGTH) {
|
||||||
|
qDebug() << "UNEXPECTED chunk size of:" << chunkLength
|
||||||
|
<< "greater than MAX_CHUNK_LENGTH:" << MAX_CHUNK_LENGTH;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0,
|
||||||
|
SharedNodePointer(), false, gotVersion);
|
||||||
|
|
||||||
|
tree.readBitstreamToTree(dataAt, chunkLength, args);
|
||||||
|
dataAt += chunkLength;
|
||||||
|
dataSize -= chunkLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
tree.recurseTreeWithOperation(addMeshVoxelsOperation, &mesh);
|
tree.recurseTreeWithOperation(addMeshVoxelsOperation, &mesh);
|
||||||
|
|
||||||
geometry.meshes.append(mesh);
|
geometry.meshes.append(mesh);
|
||||||
|
|
|
@ -83,11 +83,75 @@ PacketVersion versionForPacketType(PacketType type) {
|
||||||
return 1;
|
return 1;
|
||||||
case PacketTypeMetavoxelData:
|
case PacketTypeMetavoxelData:
|
||||||
return 3;
|
return 3;
|
||||||
|
case PacketTypeVoxelData:
|
||||||
|
return VERSION_VOXELS_HAS_FILE_BREAKS;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define PACKET_TYPE_NAME_LOOKUP(x) case x: return QString(#x);
|
||||||
|
|
||||||
|
QString nameForPacketType(PacketType type) {
|
||||||
|
switch (type) {
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeUnknown);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeStunResponse);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeDomainList);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypePing);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypePingReply);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeKillAvatar);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeAvatarData);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeInjectAudio);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeMixedAudio);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeMicrophoneAudioNoEcho);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeMicrophoneAudioWithEcho);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeBulkAvatarData);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeSilentAudioFrame);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeEnvironmentData);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeDomainListRequest);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeRequestAssignment);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeCreateAssignment);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeDomainOAuthRequest);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeMuteEnvironment);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeAudioStreamStats);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeDataServerConfirm);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeVoxelQuery);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeVoxelData);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeVoxelSet);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeVoxelSetDestructive);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeVoxelErase);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeOctreeStats);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeJurisdiction);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeJurisdictionRequest);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeParticleQuery);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeParticleData);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeParticleAddOrEdit);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeParticleErase);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeParticleAddResponse);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeMetavoxelData);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeAvatarIdentity);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeAvatarBillboard);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeDomainConnectRequest);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeDomainServerRequireDTLS);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeNodeJsonStats);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityQuery);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityData);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityAddOrEdit);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityErase);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityAddResponse);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeOctreeDataNack);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeVoxelEditNack);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeParticleEditNack);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityEditNack);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeSignedTransactionPayment);
|
||||||
|
default:
|
||||||
|
return QString("Type: ") + QString::number((int)type);
|
||||||
|
}
|
||||||
|
return QString("unexpected");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
QByteArray byteArrayWithPopulatedHeader(PacketType type, const QUuid& connectionUUID) {
|
QByteArray byteArrayWithPopulatedHeader(PacketType type, const QUuid& connectionUUID) {
|
||||||
QByteArray freshByteArray(MAX_PACKET_HEADER_BYTES, 0);
|
QByteArray freshByteArray(MAX_PACKET_HEADER_BYTES, 0);
|
||||||
freshByteArray.resize(populatePacketHeader(freshByteArray, type, connectionUUID));
|
freshByteArray.resize(populatePacketHeader(freshByteArray, type, connectionUUID));
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#include "UUID.h"
|
#include "UUID.h"
|
||||||
|
|
||||||
// NOTE: if adding a new packet type, you can replace one marked usable or add at the end
|
// NOTE: if adding a new packet type, you can replace one marked usable or add at the end
|
||||||
|
// NOTE: if you want the name of the packet type to be available for debugging or logging, update nameForPacketType() as well
|
||||||
enum PacketType {
|
enum PacketType {
|
||||||
PacketTypeUnknown,
|
PacketTypeUnknown,
|
||||||
PacketTypeStunResponse,
|
PacketTypeStunResponse,
|
||||||
|
@ -87,6 +87,7 @@ const int NUM_STATIC_HEADER_BYTES = sizeof(PacketVersion) + NUM_BYTES_RFC4122_UU
|
||||||
const int MAX_PACKET_HEADER_BYTES = sizeof(PacketType) + NUM_BYTES_MD5_HASH + NUM_STATIC_HEADER_BYTES;
|
const int MAX_PACKET_HEADER_BYTES = sizeof(PacketType) + NUM_BYTES_MD5_HASH + NUM_STATIC_HEADER_BYTES;
|
||||||
|
|
||||||
PacketVersion versionForPacketType(PacketType type);
|
PacketVersion versionForPacketType(PacketType type);
|
||||||
|
QString nameForPacketType(PacketType type);
|
||||||
|
|
||||||
const QUuid nullUUID = QUuid();
|
const QUuid nullUUID = QUuid();
|
||||||
|
|
||||||
|
@ -116,5 +117,6 @@ const PacketVersion VERSION_ENTITIES_HAVE_ANIMATION = 1;
|
||||||
const PacketVersion VERSION_ROOT_ELEMENT_HAS_DATA = 2;
|
const PacketVersion VERSION_ROOT_ELEMENT_HAS_DATA = 2;
|
||||||
const PacketVersion VERSION_ENTITIES_SUPPORT_SPLIT_MTU = 3;
|
const PacketVersion VERSION_ENTITIES_SUPPORT_SPLIT_MTU = 3;
|
||||||
const PacketVersion VERSION_ENTITIES_HAS_FILE_BREAKS = VERSION_ENTITIES_SUPPORT_SPLIT_MTU;
|
const PacketVersion VERSION_ENTITIES_HAS_FILE_BREAKS = VERSION_ENTITIES_SUPPORT_SPLIT_MTU;
|
||||||
|
const PacketVersion VERSION_VOXELS_HAS_FILE_BREAKS = 1;
|
||||||
|
|
||||||
#endif // hifi_PacketHeaders_h
|
#endif // hifi_PacketHeaders_h
|
||||||
|
|
|
@ -233,15 +233,31 @@ OctreeElement* Octree::createMissingElement(OctreeElement* lastParentElement, co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int Octree::readElementData(OctreeElement* destinationElement, const unsigned char* nodeData, int bytesLeftToRead,
|
int Octree::readElementData(OctreeElement* destinationElement, const unsigned char* nodeData, int bytesAvailable,
|
||||||
ReadBitstreamToTreeParams& args) {
|
ReadBitstreamToTreeParams& args) {
|
||||||
|
|
||||||
|
int bytesLeftToRead = bytesAvailable;
|
||||||
|
int bytesRead = 0;
|
||||||
|
|
||||||
// give this destination element the child mask from the packet
|
// give this destination element the child mask from the packet
|
||||||
const unsigned char ALL_CHILDREN_ASSUMED_TO_EXIST = 0xFF;
|
const unsigned char ALL_CHILDREN_ASSUMED_TO_EXIST = 0xFF;
|
||||||
|
|
||||||
|
if (bytesLeftToRead < sizeof(unsigned char)) {
|
||||||
|
qDebug() << "UNEXPECTED: readElementData() only had " << bytesLeftToRead << " bytes. Not enough for meaningful data.";
|
||||||
|
return bytesAvailable; // assume we read the entire buffer...
|
||||||
|
}
|
||||||
|
|
||||||
|
if (destinationElement->getScale() < SCALE_AT_DANGEROUSLY_DEEP_RECURSION) {
|
||||||
|
qDebug() << "UNEXPECTED: readElementData() destination element is unreasonably small ["
|
||||||
|
<< destinationElement->getScale() * (float)TREE_SCALE << " meters] "
|
||||||
|
<< " Discarding " << bytesAvailable << " remaining bytes.";
|
||||||
|
return bytesAvailable; // assume we read the entire buffer...
|
||||||
|
}
|
||||||
|
|
||||||
unsigned char colorInPacketMask = *nodeData;
|
unsigned char colorInPacketMask = *nodeData;
|
||||||
|
bytesRead += sizeof(colorInPacketMask);
|
||||||
|
bytesLeftToRead -= sizeof(colorInPacketMask);
|
||||||
|
|
||||||
// instantiate variable for bytes already read
|
|
||||||
int bytesRead = sizeof(colorInPacketMask);
|
|
||||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||||
// check the colors mask to see if we have a child to color in
|
// check the colors mask to see if we have a child to color in
|
||||||
if (oneAtBit(colorInPacketMask, i)) {
|
if (oneAtBit(colorInPacketMask, i)) {
|
||||||
|
@ -256,9 +272,13 @@ int Octree::readElementData(OctreeElement* destinationElement, const unsigned ch
|
||||||
OctreeElement* childElementAt = destinationElement->getChildAtIndex(i);
|
OctreeElement* childElementAt = destinationElement->getChildAtIndex(i);
|
||||||
bool nodeIsDirty = false;
|
bool nodeIsDirty = false;
|
||||||
if (childElementAt) {
|
if (childElementAt) {
|
||||||
bytesRead += childElementAt->readElementDataFromBuffer(nodeData + bytesRead, bytesLeftToRead, args);
|
|
||||||
|
int childElementDataRead = childElementAt->readElementDataFromBuffer(nodeData + bytesRead, bytesLeftToRead, args);
|
||||||
childElementAt->setSourceUUID(args.sourceUUID);
|
childElementAt->setSourceUUID(args.sourceUUID);
|
||||||
|
|
||||||
|
bytesRead += childElementDataRead;
|
||||||
|
bytesLeftToRead -= childElementDataRead;
|
||||||
|
|
||||||
// if we had a local version of the element already, it's possible that we have it already but
|
// if we had a local version of the element already, it's possible that we have it already but
|
||||||
// with the same color data, so this won't count as a change. To address this we check the following
|
// with the same color data, so this won't count as a change. To address this we check the following
|
||||||
if (!childElementAt->isDirty() && childElementAt->getShouldRender() && !childElementAt->isRendered()) {
|
if (!childElementAt->isDirty() && childElementAt->getShouldRender() && !childElementAt->isRendered()) {
|
||||||
|
@ -273,17 +293,28 @@ int Octree::readElementData(OctreeElement* destinationElement, const unsigned ch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// give this destination element the child mask from the packet
|
unsigned char childrenInTreeMask = ALL_CHILDREN_ASSUMED_TO_EXIST;
|
||||||
unsigned char childrenInTreeMask = args.includeExistsBits ? *(nodeData + bytesRead) : ALL_CHILDREN_ASSUMED_TO_EXIST;
|
unsigned char childInBufferMask = 0;
|
||||||
unsigned char childMask = *(nodeData + bytesRead + (args.includeExistsBits ? sizeof(childrenInTreeMask) : 0));
|
int bytesForMasks = args.includeExistsBits ? sizeof(childrenInTreeMask) + sizeof(childInBufferMask)
|
||||||
|
: sizeof(childInBufferMask);
|
||||||
|
|
||||||
|
if (bytesLeftToRead < bytesForMasks) {
|
||||||
|
qDebug() << "UNEXPECTED: readElementDataFromBuffer() only had " << bytesLeftToRead << " bytes before masks. "
|
||||||
|
"Not enough for meaningful data.";
|
||||||
|
return bytesAvailable; // assume we read the entire buffer...
|
||||||
|
}
|
||||||
|
|
||||||
|
childrenInTreeMask = args.includeExistsBits ? *(nodeData + bytesRead) : ALL_CHILDREN_ASSUMED_TO_EXIST;
|
||||||
|
childInBufferMask = *(nodeData + bytesRead + (args.includeExistsBits ? sizeof(childrenInTreeMask) : 0));
|
||||||
|
|
||||||
int childIndex = 0;
|
int childIndex = 0;
|
||||||
bytesRead += args.includeExistsBits ? sizeof(childrenInTreeMask) + sizeof(childMask) : sizeof(childMask);
|
bytesRead += bytesForMasks;
|
||||||
|
bytesLeftToRead -= bytesForMasks;
|
||||||
|
|
||||||
while (bytesLeftToRead - bytesRead > 0 && childIndex < NUMBER_OF_CHILDREN) {
|
while (bytesLeftToRead > 0 && childIndex < NUMBER_OF_CHILDREN) {
|
||||||
// check the exists mask to see if we have a child to traverse into
|
// check the exists mask to see if we have a child to traverse into
|
||||||
|
|
||||||
if (oneAtBit(childMask, childIndex)) {
|
if (oneAtBit(childInBufferMask, childIndex)) {
|
||||||
if (!destinationElement->getChildAtIndex(childIndex)) {
|
if (!destinationElement->getChildAtIndex(childIndex)) {
|
||||||
// add a child at that index, if it doesn't exist
|
// add a child at that index, if it doesn't exist
|
||||||
destinationElement->addChildAtIndex(childIndex);
|
destinationElement->addChildAtIndex(childIndex);
|
||||||
|
@ -294,8 +325,11 @@ int Octree::readElementData(OctreeElement* destinationElement, const unsigned ch
|
||||||
}
|
}
|
||||||
|
|
||||||
// tell the child to read the subsequent data
|
// tell the child to read the subsequent data
|
||||||
bytesRead += readElementData(destinationElement->getChildAtIndex(childIndex),
|
int lowerLevelBytes = readElementData(destinationElement->getChildAtIndex(childIndex),
|
||||||
nodeData + bytesRead, bytesLeftToRead - bytesRead, args);
|
nodeData + bytesRead, bytesLeftToRead, args);
|
||||||
|
|
||||||
|
bytesRead += lowerLevelBytes;
|
||||||
|
bytesLeftToRead -= lowerLevelBytes;
|
||||||
}
|
}
|
||||||
childIndex++;
|
childIndex++;
|
||||||
}
|
}
|
||||||
|
@ -314,7 +348,9 @@ int Octree::readElementData(OctreeElement* destinationElement, const unsigned ch
|
||||||
// if this is the root, and there is more data to read, allow it to read it's element data...
|
// if this is the root, and there is more data to read, allow it to read it's element data...
|
||||||
if (destinationElement == _rootElement && rootElementHasData() && (bytesLeftToRead - bytesRead) > 0) {
|
if (destinationElement == _rootElement && rootElementHasData() && (bytesLeftToRead - bytesRead) > 0) {
|
||||||
// tell the element to read the subsequent data
|
// tell the element to read the subsequent data
|
||||||
bytesRead += _rootElement->readElementDataFromBuffer(nodeData + bytesRead, bytesLeftToRead - bytesRead, args);
|
int rootDataSize = _rootElement->readElementDataFromBuffer(nodeData + bytesRead, bytesLeftToRead - bytesRead, args);
|
||||||
|
bytesRead += rootDataSize;
|
||||||
|
bytesLeftToRead -= rootDataSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytesRead;
|
return bytesRead;
|
||||||
|
@ -322,7 +358,6 @@ int Octree::readElementData(OctreeElement* destinationElement, const unsigned ch
|
||||||
|
|
||||||
void Octree::readBitstreamToTree(const unsigned char * bitstream, unsigned long int bufferSizeBytes,
|
void Octree::readBitstreamToTree(const unsigned char * bitstream, unsigned long int bufferSizeBytes,
|
||||||
ReadBitstreamToTreeParams& args) {
|
ReadBitstreamToTreeParams& args) {
|
||||||
|
|
||||||
int bytesRead = 0;
|
int bytesRead = 0;
|
||||||
const unsigned char* bitstreamAt = bitstream;
|
const unsigned char* bitstreamAt = bitstream;
|
||||||
|
|
||||||
|
@ -337,9 +372,18 @@ void Octree::readBitstreamToTree(const unsigned char * bitstream, unsigned long
|
||||||
|
|
||||||
while (bitstreamAt < bitstream + bufferSizeBytes) {
|
while (bitstreamAt < bitstream + bufferSizeBytes) {
|
||||||
OctreeElement* bitstreamRootElement = nodeForOctalCode(args.destinationElement, (unsigned char *)bitstreamAt, NULL);
|
OctreeElement* bitstreamRootElement = nodeForOctalCode(args.destinationElement, (unsigned char *)bitstreamAt, NULL);
|
||||||
if (*bitstreamAt != *bitstreamRootElement->getOctalCode()) {
|
|
||||||
// if the octal code returned is not on the same level as
|
int numberOfThreeBitSectionsInStream = numberOfThreeBitSectionsInCode(bitstreamAt, bufferSizeBytes);
|
||||||
// the code being searched for, we have OctreeElements to create
|
|
||||||
|
if (numberOfThreeBitSectionsInStream == OVERFLOWED_OCTCODE_BUFFER) {
|
||||||
|
qDebug() << "UNEXPECTED: parsing of the octal code would overflow the buffer. This buffer is corrupt. Returning.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int numberOfThreeBitSectionsFromNode = numberOfThreeBitSectionsInCode(bitstreamRootElement->getOctalCode());
|
||||||
|
|
||||||
|
// if the octal code returned is not on the same level as the code being searched for, we have OctreeElements to create
|
||||||
|
if (numberOfThreeBitSectionsInStream != numberOfThreeBitSectionsFromNode) {
|
||||||
|
|
||||||
// Note: we need to create this element relative to root, because we're assuming that the bitstream for the initial
|
// Note: we need to create this element relative to root, because we're assuming that the bitstream for the initial
|
||||||
// octal code is always relative to root!
|
// octal code is always relative to root!
|
||||||
|
@ -349,16 +393,18 @@ void Octree::readBitstreamToTree(const unsigned char * bitstream, unsigned long
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int octalCodeBytes = bytesRequiredForCodeLength(*bitstreamAt);
|
int octalCodeBytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInStream);
|
||||||
|
|
||||||
int theseBytesRead = 0;
|
int theseBytesRead = 0;
|
||||||
theseBytesRead += octalCodeBytes;
|
theseBytesRead += octalCodeBytes;
|
||||||
theseBytesRead += readElementData(bitstreamRootElement, bitstreamAt + octalCodeBytes,
|
int lowerLevelBytes = readElementData(bitstreamRootElement, bitstreamAt + octalCodeBytes,
|
||||||
bufferSizeBytes - (bytesRead + octalCodeBytes), args);
|
bufferSizeBytes - (bytesRead + octalCodeBytes), args);
|
||||||
|
|
||||||
|
theseBytesRead += lowerLevelBytes;
|
||||||
|
|
||||||
// skip bitstream to new startPoint
|
// skip bitstream to new startPoint
|
||||||
bitstreamAt += theseBytesRead;
|
bitstreamAt += theseBytesRead;
|
||||||
bytesRead += theseBytesRead;
|
bytesRead += theseBytesRead;
|
||||||
|
|
||||||
if (args.wantImportProgress) {
|
if (args.wantImportProgress) {
|
||||||
emit importProgress((100 * (bitstreamAt - bitstream)) / bufferSizeBytes);
|
emit importProgress((100 * (bitstreamAt - bitstream)) / bufferSizeBytes);
|
||||||
|
@ -1004,7 +1050,7 @@ int Octree::encodeTreeBitstream(OctreeElement* element,
|
||||||
params.stopReason = EncodeBitstreamParams::DIDNT_FIT;
|
params.stopReason = EncodeBitstreamParams::DIDNT_FIT;
|
||||||
return bytesWritten;
|
return bytesWritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytesWritten += codeLength; // keep track of byte count
|
bytesWritten += codeLength; // keep track of byte count
|
||||||
|
|
||||||
int currentEncodeLevel = 0;
|
int currentEncodeLevel = 0;
|
||||||
|
@ -1421,6 +1467,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
|
||||||
// We wil write this bit mask but we may come back later and update the bits that are actually included
|
// We wil write this bit mask but we may come back later and update the bits that are actually included
|
||||||
packetData->releaseReservedBytes(sizeof(childrenDataBits));
|
packetData->releaseReservedBytes(sizeof(childrenDataBits));
|
||||||
continueThisLevel = packetData->appendBitMask(childrenDataBits);
|
continueThisLevel = packetData->appendBitMask(childrenDataBits);
|
||||||
|
|
||||||
int childDataBitsPlaceHolder = packetData->getUncompressedByteOffset(sizeof(childrenDataBits));
|
int childDataBitsPlaceHolder = packetData->getUncompressedByteOffset(sizeof(childrenDataBits));
|
||||||
unsigned char actualChildrenDataBits = 0;
|
unsigned char actualChildrenDataBits = 0;
|
||||||
|
|
||||||
|
@ -1470,6 +1517,13 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
|
||||||
// Continue this level so long as some part of this child element was appended.
|
// Continue this level so long as some part of this child element was appended.
|
||||||
bool childFit = (childAppendState != OctreeElement::NONE);
|
bool childFit = (childAppendState != OctreeElement::NONE);
|
||||||
|
|
||||||
|
// some datatypes (like Voxels) assume that all child data will fit, if it doesn't fit
|
||||||
|
// the data type wants to bail on this element level completely
|
||||||
|
if (!childFit && mustIncludeAllChildData()) {
|
||||||
|
continueThisLevel = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// If the child was partially or fully appended, then mark the actualChildrenDataBits as including
|
// If the child was partially or fully appended, then mark the actualChildrenDataBits as including
|
||||||
// this child data
|
// this child data
|
||||||
if (childFit) {
|
if (childFit) {
|
||||||
|
@ -1500,15 +1554,14 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!continueThisLevel) {
|
if (!mustIncludeAllChildData() && !continueThisLevel) {
|
||||||
qDebug() << "WARNING UNEXPECTED CASE: reached end of child element data loop with continueThisLevel=FALSE";
|
qDebug() << "WARNING UNEXPECTED CASE: reached end of child element data loop with continueThisLevel=FALSE";
|
||||||
qDebug() << "This is not expected!!!! -- continueThisLevel=FALSE....";
|
qDebug() << "This is not expected!!!! -- continueThisLevel=FALSE....";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actualChildrenDataBits != childrenDataBits) {
|
if (continueThisLevel && actualChildrenDataBits != childrenDataBits) {
|
||||||
// repair the child data mask
|
// repair the child data mask
|
||||||
continueThisLevel = packetData->updatePriorBitMask(childDataBitsPlaceHolder, actualChildrenDataBits);
|
continueThisLevel = packetData->updatePriorBitMask(childDataBitsPlaceHolder, actualChildrenDataBits);
|
||||||
|
|
||||||
if (!continueThisLevel) {
|
if (!continueThisLevel) {
|
||||||
qDebug() << "WARNING UNEXPECTED CASE: Failed to update childDataBitsPlaceHolder";
|
qDebug() << "WARNING UNEXPECTED CASE: Failed to update childDataBitsPlaceHolder";
|
||||||
qDebug() << "This is not expected!!!! -- continueThisLevel=FALSE....";
|
qDebug() << "This is not expected!!!! -- continueThisLevel=FALSE....";
|
||||||
|
@ -1764,17 +1817,22 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
|
||||||
continueThisLevel = packetData->endLevel(thisLevelKey);
|
continueThisLevel = packetData->endLevel(thisLevelKey);
|
||||||
} else {
|
} else {
|
||||||
packetData->discardLevel(thisLevelKey);
|
packetData->discardLevel(thisLevelKey);
|
||||||
qDebug() << "WARNING UNEXPECTED CASE: Something failed in attempting to pack this element";
|
|
||||||
qDebug() << "This is not expected!!!! -- continueThisLevel=FALSE....";
|
if (!mustIncludeAllChildData()) {
|
||||||
|
qDebug() << "WARNING UNEXPECTED CASE: Something failed in attempting to pack this element";
|
||||||
|
qDebug() << "This is not expected!!!! -- continueThisLevel=FALSE....";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This happens if the element could not be written at all. In the case of Octree's that support partial
|
// 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
|
// element data, continueThisLevel will be true. So this only happens if the full element needs to be
|
||||||
// added back to the element bag.
|
// added back to the element bag.
|
||||||
if (!continueThisLevel) {
|
if (!continueThisLevel) {
|
||||||
qDebug() << "WARNING UNEXPECTED CASE - Something failed in attempting to pack this element";
|
if (!mustIncludeAllChildData()) {
|
||||||
qDebug() << "IS THIS EVER EXPECTED???? -- continueThisLevel=FALSE...." ;
|
qDebug() << "WARNING UNEXPECTED CASE - Something failed in attempting to pack this element.";
|
||||||
qDebug() << " calling bag.insert(element);.....";
|
qDebug() << " If the datatype requires all child data, then this might happen. Otherwise" ;
|
||||||
|
qDebug() << " this is an unexpected case and we should research a potential logic error." ;
|
||||||
|
}
|
||||||
|
|
||||||
bag.insert(element);
|
bag.insert(element);
|
||||||
|
|
||||||
|
@ -1826,6 +1884,10 @@ bool Octree::readFromSVOFile(const char* fileName) {
|
||||||
|
|
||||||
bool wantImportProgress = true;
|
bool wantImportProgress = true;
|
||||||
|
|
||||||
|
PacketType expectedType = expectedDataPacketType();
|
||||||
|
PacketVersion expectedVersion = versionForPacketType(expectedType);
|
||||||
|
bool hasBufferBreaks = versionHasSVOfileBreaks(expectedVersion);
|
||||||
|
|
||||||
// before reading the file, check to see if this version of the Octree supports file versions
|
// before reading the file, check to see if this version of the Octree supports file versions
|
||||||
if (getWantSVOfileVersions()) {
|
if (getWantSVOfileVersions()) {
|
||||||
|
|
||||||
|
@ -1840,15 +1902,26 @@ bool Octree::readFromSVOFile(const char* fileName) {
|
||||||
unsigned long dataLength = HEADER_LENGTH;
|
unsigned long dataLength = HEADER_LENGTH;
|
||||||
|
|
||||||
// if so, read the first byte of the file and see if it matches the expected version code
|
// if so, read the first byte of the file and see if it matches the expected version code
|
||||||
PacketType expectedType = expectedDataPacketType();
|
|
||||||
|
|
||||||
PacketType gotType;
|
PacketType gotType;
|
||||||
memcpy(&gotType, dataAt, sizeof(gotType));
|
memcpy(&gotType, dataAt, sizeof(gotType));
|
||||||
|
|
||||||
|
dataAt += sizeof(expectedType);
|
||||||
|
dataLength -= sizeof(expectedType);
|
||||||
|
gotVersion = *dataAt;
|
||||||
|
|
||||||
|
// NOTE: SPECIAL CASE for old voxel svo files. The old voxel SVO files didn't have header
|
||||||
|
// details. They started with the the octalcode for the root. Which was always 00 which matches PacketTypeUnknown
|
||||||
|
unsigned char* firstByteAt = (unsigned char*)&fileHeader;
|
||||||
|
unsigned char firstByteValue = *firstByteAt;
|
||||||
|
if (expectedType == PacketTypeVoxelData && firstByteValue == 0) {
|
||||||
|
gotType = PacketTypeVoxelData;
|
||||||
|
gotVersion = 0;
|
||||||
|
qDebug() << "Detected OLD Voxels format.";
|
||||||
|
headerLength = 0; // old format files don't have headers
|
||||||
|
file.seekg( 0, std::ios::beg ); // rewind to the beginning so old logic will work
|
||||||
|
}
|
||||||
|
|
||||||
if (gotType == expectedType) {
|
if (gotType == expectedType) {
|
||||||
dataAt += sizeof(expectedType);
|
|
||||||
dataLength -= sizeof(expectedType);
|
|
||||||
gotVersion = *dataAt;
|
|
||||||
if (canProcessVersion(gotVersion)) {
|
if (canProcessVersion(gotVersion)) {
|
||||||
dataAt += sizeof(gotVersion);
|
dataAt += sizeof(gotVersion);
|
||||||
dataLength -= sizeof(gotVersion);
|
dataLength -= sizeof(gotVersion);
|
||||||
|
@ -1857,25 +1930,25 @@ bool Octree::readFromSVOFile(const char* fileName) {
|
||||||
versionForPacketType(expectedDataPacketType()), gotVersion);
|
versionForPacketType(expectedDataPacketType()), gotVersion);
|
||||||
|
|
||||||
hasBufferBreaks = versionHasSVOfileBreaks(gotVersion);
|
hasBufferBreaks = versionHasSVOfileBreaks(gotVersion);
|
||||||
if (hasBufferBreaks) {
|
|
||||||
qDebug() << " this version includes buffer breaks";
|
|
||||||
} else {
|
|
||||||
qDebug() << " this version does not include buffer breaks";
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
qDebug("SVO file version mismatch. Expected: %d Got: %d",
|
qDebug("SVO file version mismatch. Expected: %d Got: %d",
|
||||||
versionForPacketType(expectedDataPacketType()), gotVersion);
|
versionForPacketType(expectedDataPacketType()), gotVersion);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qDebug("SVO file type mismatch. Expected: %c Got: %c", expectedType, gotType);
|
qDebug() << "SVO file type mismatch. Expected: " << nameForPacketType(expectedType)
|
||||||
|
<< " Got: " << nameForPacketType(gotType);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
qDebug() << " NOTE: this file type does not include type and version information.";
|
qDebug() << " NOTE: this file type does not include type and version information.";
|
||||||
fileOk = true; // assume the file is ok
|
fileOk = true; // assume the file is ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasBufferBreaks) {
|
||||||
|
qDebug() << " this version includes buffer breaks";
|
||||||
|
} else {
|
||||||
|
qDebug() << " this version does not include buffer breaks";
|
||||||
|
}
|
||||||
|
|
||||||
if (fileOk) {
|
if (fileOk) {
|
||||||
|
|
||||||
|
@ -1906,7 +1979,6 @@ bool Octree::readFromSVOFile(const char* fileName) {
|
||||||
quint16 chunkLength = 0;
|
quint16 chunkLength = 0;
|
||||||
|
|
||||||
file.read((char*)&chunkLength, sizeof(chunkLength)); // read the chunk size from the file
|
file.read((char*)&chunkLength, sizeof(chunkLength)); // read the chunk size from the file
|
||||||
|
|
||||||
remainingLength -= sizeof(chunkLength);
|
remainingLength -= sizeof(chunkLength);
|
||||||
|
|
||||||
if (chunkLength > remainingLength) {
|
if (chunkLength > remainingLength) {
|
||||||
|
@ -1942,6 +2014,7 @@ bool Octree::readFromSVOFile(const char* fileName) {
|
||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
return fileOk;
|
return fileOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1951,25 +2024,25 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElement* element) {
|
||||||
if(file.is_open()) {
|
if(file.is_open()) {
|
||||||
qDebug("Saving to file %s...", fileName);
|
qDebug("Saving to file %s...", fileName);
|
||||||
|
|
||||||
bool hasBufferBreaks = false;
|
PacketType expectedType = expectedDataPacketType();
|
||||||
|
PacketVersion expectedVersion = versionForPacketType(expectedType);
|
||||||
|
bool hasBufferBreaks = versionHasSVOfileBreaks(expectedVersion);
|
||||||
|
|
||||||
// before reading the file, check to see if this version of the Octree supports file versions
|
// before reading the file, check to see if this version of the Octree supports file versions
|
||||||
if (getWantSVOfileVersions()) {
|
if (getWantSVOfileVersions()) {
|
||||||
// if so, read the first byte of the file and see if it matches the expected version code
|
// if so, read the first byte of the file and see if it matches the expected version code
|
||||||
PacketType expectedType = expectedDataPacketType();
|
|
||||||
PacketVersion expectedVersion = versionForPacketType(expectedType);
|
|
||||||
file.write(reinterpret_cast<char*>(&expectedType), sizeof(expectedType));
|
file.write(reinterpret_cast<char*>(&expectedType), sizeof(expectedType));
|
||||||
file.write(&expectedVersion, sizeof(expectedVersion));
|
file.write(&expectedVersion, sizeof(expectedVersion));
|
||||||
|
qDebug() << "SVO file type: " << nameForPacketType(expectedType) << " version: " << (int)expectedVersion;
|
||||||
qDebug("SVO file type: %c version: %d", expectedType, expectedVersion);
|
|
||||||
|
|
||||||
hasBufferBreaks = versionHasSVOfileBreaks(expectedVersion);
|
hasBufferBreaks = versionHasSVOfileBreaks(expectedVersion);
|
||||||
if (hasBufferBreaks) {
|
|
||||||
qDebug() << " this version includes buffer breaks";
|
|
||||||
} else {
|
|
||||||
qDebug() << " this version does not include buffer breaks";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (hasBufferBreaks) {
|
||||||
|
qDebug() << " this version includes buffer breaks";
|
||||||
|
} else {
|
||||||
|
qDebug() << " this version does not include buffer breaks";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
OctreeElementBag elementBag;
|
OctreeElementBag elementBag;
|
||||||
OctreeElementExtraEncodeData extraEncodeData;
|
OctreeElementExtraEncodeData extraEncodeData;
|
||||||
|
|
|
@ -238,6 +238,7 @@ public:
|
||||||
virtual int minimumRequiredRootDataBytes() const { return 0; }
|
virtual int minimumRequiredRootDataBytes() const { return 0; }
|
||||||
virtual bool suppressEmptySubtrees() const { return true; }
|
virtual bool suppressEmptySubtrees() const { return true; }
|
||||||
virtual void releaseSceneEncodeData(OctreeElementExtraEncodeData* extraEncodeData) const { }
|
virtual void releaseSceneEncodeData(OctreeElementExtraEncodeData* extraEncodeData) const { }
|
||||||
|
virtual bool mustIncludeAllChildData() const { return true; }
|
||||||
|
|
||||||
/// some versions of the SVO file will include breaks with buffer lengths between each buffer chunk in the SVO
|
/// 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
|
/// file. If the Octree subclass expects this for this particular version of the file, it should override this
|
||||||
|
@ -352,6 +353,7 @@ public:
|
||||||
bool getIsClient() const { return !_isServer; } /// Is this a client based tree. Allows guards for certain operations
|
bool getIsClient() const { return !_isServer; } /// Is this a client based tree. Allows guards for certain operations
|
||||||
void setIsClient(bool isClient) { _isServer = !isClient; }
|
void setIsClient(bool isClient) { _isServer = !isClient; }
|
||||||
|
|
||||||
|
virtual void dumpTree() { };
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void importSize(float x, float y, float z);
|
void importSize(float x, float y, float z);
|
||||||
|
|
|
@ -37,6 +37,8 @@ const float VIEW_FRUSTUM_FOV_OVERSEND = 60.0f;
|
||||||
// These are guards to prevent our voxel tree recursive routines from spinning out of control
|
// These are guards to prevent our voxel tree recursive routines from spinning out of control
|
||||||
const int UNREASONABLY_DEEP_RECURSION = 20; // use this for something that you want to be shallow, but not spin out
|
const int UNREASONABLY_DEEP_RECURSION = 20; // use this for something that you want to be shallow, but not spin out
|
||||||
const int DANGEROUSLY_DEEP_RECURSION = 200; // use this for something that needs to go deeper
|
const int DANGEROUSLY_DEEP_RECURSION = 200; // use this for something that needs to go deeper
|
||||||
|
const float SCALE_AT_UNREASONABLY_DEEP_RECURSION = (1.0f / powf(2.0f, UNREASONABLY_DEEP_RECURSION));
|
||||||
|
const float SCALE_AT_DANGEROUSLY_DEEP_RECURSION = (1.0f / powf(2.0f, DANGEROUSLY_DEEP_RECURSION));
|
||||||
|
|
||||||
const int DEFAULT_MAX_OCTREE_PPS = 600; // the default maximum PPS we think any octree based server should send to a client
|
const int DEFAULT_MAX_OCTREE_PPS = 600; // the default maximum PPS we think any octree based server should send to a client
|
||||||
|
|
||||||
|
|
|
@ -11,11 +11,10 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include <QtCore/QDebug>
|
#include <QDebug>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QRgb>
|
#include <QRgb>
|
||||||
|
|
||||||
|
|
||||||
#include "VoxelTree.h"
|
#include "VoxelTree.h"
|
||||||
#include "Tags.h"
|
#include "Tags.h"
|
||||||
|
|
||||||
|
@ -567,3 +566,26 @@ int VoxelTree::processEditPacketData(PacketType packetType, const unsigned char*
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class VoxelTreeDebugOperator : public RecurseOctreeOperator {
|
||||||
|
public:
|
||||||
|
virtual bool preRecursion(OctreeElement* element);
|
||||||
|
virtual bool postRecursion(OctreeElement* element) { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
bool VoxelTreeDebugOperator::preRecursion(OctreeElement* element) {
|
||||||
|
VoxelTreeElement* treeElement = static_cast<VoxelTreeElement*>(element);
|
||||||
|
qDebug() << "VoxelTreeElement [" << treeElement << ":" << treeElement->getAACube() << "]";
|
||||||
|
qDebug() << " isLeaf:" << treeElement->isLeaf();
|
||||||
|
qDebug() << " color:" << treeElement->getColor()[0] << ", "
|
||||||
|
<< treeElement->getColor()[1] << ", "
|
||||||
|
<< treeElement->getColor()[2];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelTree::dumpTree() {
|
||||||
|
// First, look for the existing entity in the tree..
|
||||||
|
VoxelTreeDebugOperator theOperator;
|
||||||
|
recurseTreeWithOperator(&theOperator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,12 +51,30 @@ public:
|
||||||
|
|
||||||
void readCodeColorBufferToTree(const unsigned char* codeColorBuffer, bool destructive = false);
|
void readCodeColorBufferToTree(const unsigned char* codeColorBuffer, bool destructive = false);
|
||||||
|
|
||||||
|
|
||||||
|
virtual bool getWantSVOfileVersions() const { return true; }
|
||||||
|
virtual bool canProcessVersion(PacketVersion thisVersion) const {
|
||||||
|
return thisVersion == 0 || thisVersion == versionForPacketType(expectedDataPacketType()); }
|
||||||
|
virtual PacketVersion expectedVersion() const { return versionForPacketType(expectedDataPacketType()); }
|
||||||
|
|
||||||
virtual PacketType expectedDataPacketType() const { return PacketTypeVoxelData; }
|
virtual PacketType expectedDataPacketType() const { return PacketTypeVoxelData; }
|
||||||
virtual bool handlesEditPacketType(PacketType packetType) const;
|
virtual bool handlesEditPacketType(PacketType packetType) const;
|
||||||
virtual int processEditPacketData(PacketType packetType, const unsigned char* packetData, int packetLength,
|
virtual int processEditPacketData(PacketType packetType, const unsigned char* packetData, int packetLength,
|
||||||
const unsigned char* editData, int maxLength, const SharedNodePointer& node);
|
const unsigned char* editData, int maxLength, const SharedNodePointer& node);
|
||||||
virtual bool recurseChildrenWithData() const { return false; }
|
virtual bool recurseChildrenWithData() const { return false; }
|
||||||
|
|
||||||
|
/// 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
|
||||||
|
/// method and return true.
|
||||||
|
virtual bool versionHasSVOfileBreaks(PacketVersion thisVersion) const {
|
||||||
|
if (thisVersion == 0) {
|
||||||
|
return false; // old versions didn't have buffer breaks
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void dumpTree();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// helper functions for nudgeSubTree
|
// helper functions for nudgeSubTree
|
||||||
void recurseNodeForNudge(VoxelTreeElement* element, RecurseOctreeOperation operation, void* extraData);
|
void recurseNodeForNudge(VoxelTreeElement* element, RecurseOctreeOperation operation, void* extraData);
|
||||||
|
|
|
@ -73,6 +73,13 @@ OctreeElement::AppendState VoxelTreeElement::appendElementData(OctreePacketData*
|
||||||
int VoxelTreeElement::readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
int VoxelTreeElement::readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||||
ReadBitstreamToTreeParams& args) {
|
ReadBitstreamToTreeParams& args) {
|
||||||
const int BYTES_PER_COLOR = 3;
|
const int BYTES_PER_COLOR = 3;
|
||||||
|
|
||||||
|
if (bytesLeftToRead < BYTES_PER_COLOR) {
|
||||||
|
qDebug() << "UNEXPECTED: readElementDataFromBuffer() only had " << bytesLeftToRead << " bytes. "
|
||||||
|
"Not enough for meaningful data.";
|
||||||
|
return bytesLeftToRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// pull the color for this child
|
// pull the color for this child
|
||||||
nodeColor newColor = { 128, 128, 128, 1};
|
nodeColor newColor = { 128, 128, 128, 1};
|
||||||
|
|
Loading…
Reference in a new issue