major pass on cleaning up voxel packets to have flags, sequence numbers, and flight time, add compression menu item

This commit is contained in:
ZappoMan 2013-11-26 17:26:54 -08:00
parent a60cf0f34e
commit 491512fbce
14 changed files with 246 additions and 220 deletions

View file

@ -43,6 +43,9 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) {
case PACKET_TYPE_SET_VOXEL_DESTRUCTIVE:
case PACKET_TYPE_ERASE_VOXEL:
return 1;
case PACKET_TYPE_VOXEL_DATA:
return 1;
default:
return 0;

View file

@ -20,7 +20,6 @@ const PACKET_TYPE PACKET_TYPE_PING = 'P';
const PACKET_TYPE PACKET_TYPE_PING_REPLY = 'R';
const PACKET_TYPE PACKET_TYPE_KILL_NODE = 'K';
const PACKET_TYPE PACKET_TYPE_HEAD_DATA = 'H';
const PACKET_TYPE PACKET_TYPE_Z_COMMAND = 'Z';
const PACKET_TYPE PACKET_TYPE_INJECT_AUDIO = 'I';
const PACKET_TYPE PACKET_TYPE_MIXED_AUDIO = 'A';
const PACKET_TYPE PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO = 'M';
@ -41,7 +40,6 @@ const PACKET_TYPE PACKET_TYPE_DATA_SERVER_SEND = 'u';
const PACKET_TYPE PACKET_TYPE_DATA_SERVER_CONFIRM = 'c';
const PACKET_TYPE PACKET_TYPE_VOXEL_QUERY = 'q';
const PACKET_TYPE PACKET_TYPE_VOXEL_DATA = 'V';
const PACKET_TYPE PACKET_TYPE_VOXEL_DATA_MONOCHROME = 'v';
const PACKET_TYPE PACKET_TYPE_VOXEL_STATS = '#';
const PACKET_TYPE PACKET_TYPE_VOXEL_JURISDICTION = 'J';
const PACKET_TYPE PACKET_TYPE_VOXEL_JURISDICTION_REQUEST = 'j';

View file

@ -23,6 +23,7 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) :
_viewFrustumChanging(false),
_viewFrustumJustStoppedChanging(true),
_currentPacketIsColor(true),
_currentPacketIsCompressed(false),
_voxelSendThread(NULL),
_lastClientBoundaryLevelAdjust(0),
_lastClientVoxelSizeScale(DEFAULT_VOXEL_SIZE_SCALE),
@ -34,6 +35,7 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) :
_lastVoxelPacket = new unsigned char[_voxelPacketAvailableBytes];
_lastVoxelPacketLength = 0;
_duplicatePacketCount = 0;
_sequenceNumber = 0;
resetVoxelPacket();
}
@ -96,12 +98,37 @@ void VoxelNodeData::resetVoxelPacket() {
// If we're moving, and the client asked for low res, then we force monochrome, otherwise, use
// the clients requested color state.
_currentPacketIsColor = (LOW_RES_MONO && getWantLowResMoving() && _viewFrustumChanging) ? false : getWantColor();
PACKET_TYPE voxelPacketType = _currentPacketIsColor ? PACKET_TYPE_VOXEL_DATA : PACKET_TYPE_VOXEL_DATA_MONOCHROME;
_currentPacketIsColor = getWantColor();
_currentPacketIsCompressed = getWantCompression();
VOXEL_PACKET_FLAGS flags = 0;
if (_currentPacketIsColor) {
setAtBit(flags,PACKET_IS_COLOR_BIT);
}
if (_currentPacketIsCompressed) {
setAtBit(flags,PACKET_IS_COMPRESSED_BIT);
}
int numBytesPacketHeader = populateTypeAndVersion(_voxelPacket, voxelPacketType);
int numBytesPacketHeader = populateTypeAndVersion(_voxelPacket, PACKET_TYPE_VOXEL_DATA);
_voxelPacketAt = _voxelPacket + numBytesPacketHeader;
_voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE - numBytesPacketHeader;
// pack in flags
VOXEL_PACKET_FLAGS* flagsAt = (VOXEL_PACKET_FLAGS*)_voxelPacketAt;
*flagsAt = flags;
_voxelPacketAt += sizeof(VOXEL_PACKET_FLAGS);
// pack in sequence number
VOXEL_PACKET_SEQUENCE* sequenceAt = (VOXEL_PACKET_SEQUENCE*)_voxelPacketAt;
*sequenceAt = _sequenceNumber;
_voxelPacketAt += sizeof(VOXEL_PACKET_SEQUENCE);
_sequenceNumber++;
// pack in timestamp
VOXEL_PACKET_SENT_TIME now = usecTimestampNow();
VOXEL_PACKET_SENT_TIME* timeAt = (VOXEL_PACKET_SENT_TIME*)_voxelPacketAt;
*timeAt = now;
_voxelPacketAt += sizeof(VOXEL_PACKET_SENT_TIME);
_voxelPacketAvailableBytes = MAX_VOXEL_PACKET_DATA_SIZE;
_voxelPacketWaiting = false;
}
@ -181,7 +208,6 @@ void VoxelNodeData::setViewSent(bool viewSent) {
}
}
void VoxelNodeData::updateLastKnownViewFrustum() {
bool frustumChanges = !_lastKnownViewFrustum.isVerySimilar(_currentViewFrustum);

View file

@ -11,7 +11,7 @@
#include <iostream>
#include <NodeData.h>
#include <VoxelPacket.h>
#include <VoxelPacketData.h>
#include <VoxelQuery.h>
#include <CoverageMap.h>
@ -39,36 +39,40 @@ public:
bool shouldSuppressDuplicatePacket();
int getAvailable() const { return _voxelPacketAvailableBytes; }
int getMaxSearchLevel() const { return _maxSearchLevel; };
void resetMaxSearchLevel() { _maxSearchLevel = 1; };
void incrementMaxSearchLevel() { _maxSearchLevel++; };
int getMaxSearchLevel() const { return _maxSearchLevel; }
void resetMaxSearchLevel() { _maxSearchLevel = 1; }
void incrementMaxSearchLevel() { _maxSearchLevel++; }
int getMaxLevelReached() const { return _maxLevelReachedInLastSearch; };
int getMaxLevelReached() const { return _maxLevelReachedInLastSearch; }
void setMaxLevelReached(int maxLevelReached) { _maxLevelReachedInLastSearch = maxLevelReached; }
VoxelNodeBag nodeBag;
CoverageMap map;
ViewFrustum& getCurrentViewFrustum() { return _currentViewFrustum; };
ViewFrustum& getLastKnownViewFrustum() { return _lastKnownViewFrustum; };
ViewFrustum& getCurrentViewFrustum() { return _currentViewFrustum; }
ViewFrustum& getLastKnownViewFrustum() { return _lastKnownViewFrustum; }
// These are not classic setters because they are calculating and maintaining state
// which is set asynchronously through the network receive
bool updateCurrentViewFrustum();
void updateLastKnownViewFrustum();
bool getViewSent() const { return _viewSent; };
bool getViewSent() const { return _viewSent; }
void setViewSent(bool viewSent);
bool getViewFrustumChanging() const { return _viewFrustumChanging; };
bool getViewFrustumJustStoppedChanging() const { return _viewFrustumJustStoppedChanging; };
bool getViewFrustumChanging() const { return _viewFrustumChanging; }
bool getViewFrustumJustStoppedChanging() const { return _viewFrustumJustStoppedChanging; }
bool moveShouldDump() const;
uint64_t getLastTimeBagEmpty() const { return _lastTimeBagEmpty; };
void setLastTimeBagEmpty(uint64_t lastTimeBagEmpty) { _lastTimeBagEmpty = lastTimeBagEmpty; };
uint64_t getLastTimeBagEmpty() const { return _lastTimeBagEmpty; }
void setLastTimeBagEmpty(uint64_t lastTimeBagEmpty) { _lastTimeBagEmpty = lastTimeBagEmpty; }
bool getCurrentPacketIsColor() const { return _currentPacketIsColor; };
bool getCurrentPacketIsColor() const { return _currentPacketIsColor; }
bool getCurrentPacketIsCompressed() const { return _currentPacketIsCompressed; }
bool getCurrentPacketFormatMatches() {
return (getCurrentPacketIsColor() == getWantColor() && getCurrentPacketIsCompressed() == getWantCompression());
}
bool hasLodChanged() const { return _lodChanged; };
@ -102,6 +106,7 @@ private:
bool _viewFrustumChanging;
bool _viewFrustumJustStoppedChanging;
bool _currentPacketIsColor;
bool _currentPacketIsCompressed;
VoxelSendThread* _voxelSendThread;
@ -110,6 +115,8 @@ private:
float _lastClientVoxelSizeScale;
bool _lodChanged;
bool _lodInitialized;
VOXEL_PACKET_SEQUENCE _sequenceNumber;
};
#endif /* defined(__hifi__VoxelNodeData__) */

View file

@ -29,7 +29,7 @@ uint64_t endSceneSleepTime = 0;
VoxelSendThread::VoxelSendThread(const QUuid& nodeUUID, VoxelServer* myServer) :
_nodeUUID(nodeUUID),
_myServer(myServer),
_tempPacket(VOXEL_PACKET_COMPRESSION_DEFAULT),
_packetData(),
_encodedSomething(false)
{
}
@ -228,32 +228,37 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod
// If we're starting a fresh packet, then...
// If we're moving, and the client asked for low res, then we force monochrome, otherwise, use
// the clients requested color state.
bool wantColor = LOW_RES_MONO && nodeData->getWantLowResMoving() && viewFrustumChanged ? false : nodeData->getWantColor();
bool wantColor = nodeData->getWantColor();
bool wantCompression = nodeData->getWantCompression();
// If we have a packet waiting, and our desired want color, doesn't match the current waiting packets color
// then let's just send that waiting packet.
if (wantColor != nodeData->getCurrentPacketIsColor()) {
if (!nodeData->getCurrentPacketFormatMatches()) {
if (nodeData->isPacketWaiting()) {
if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) {
printf("wantColor=%s --- SENDING PARTIAL PACKET! nodeData->getCurrentPacketIsColor()=%s\n",
debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()));
printf("wantColor=%s wantCompression=%s SENDING PARTIAL PACKET! currentPacketIsColor=%s currentPacketIsCompressed=%s\n",
debug::valueOf(wantColor), debug::valueOf(wantCompression),
debug::valueOf(nodeData->getCurrentPacketIsColor()),
debug::valueOf(nodeData->getCurrentPacketIsCompressed()) );
}
packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
} else {
if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) {
printf("wantColor=%s --- FIXING HEADER! nodeData->getCurrentPacketIsColor()=%s\n",
debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()));
printf("wantColor=%s wantCompression=%s FIXING HEADER! currentPacketIsColor=%s currentPacketIsCompressed=%s\n",
debug::valueOf(wantColor), debug::valueOf(wantCompression),
debug::valueOf(nodeData->getCurrentPacketIsColor()),
debug::valueOf(nodeData->getCurrentPacketIsCompressed()) );
}
nodeData->resetVoxelPacket();
}
_packetData.changeSettings(wantCompression);
}
if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) {
printf("wantColor=%s getCurrentPacketIsColor()=%s, viewFrustumChanged=%s, getWantLowResMoving()=%s\n",
debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()),
debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->getWantLowResMoving()));
if (true || (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug())) {
printf("wantColor/isColor=%s/%s wantCompression/isCompressed=%s/%s viewFrustumChanged=%s, getWantLowResMoving()=%s\n",
debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()),
debug::valueOf(wantCompression), debug::valueOf(nodeData->getCurrentPacketIsCompressed()),
debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->getWantLowResMoving()));
}
const ViewFrustum* lastViewFrustum = wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL;
@ -308,8 +313,16 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod
unsigned long elapsedTime = nodeData->stats.getElapsedTime();
packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
qDebug("Scene completed at %llu. encodeTime: %lu sleepTime: %lu elapsed: %lu Packets:[%llu]: Total Bytes:[%llu] Wasted bytes:[%llu]\n",
usecTimestampNow(), encodeTime, sleepTime, elapsedTime, _totalPackets, _totalBytes, _totalWastedBytes);
bool debug = false;
if (debug) {
qDebug() << "Scene completed at " << usecTimestampNow() <<
" encodeTime: "<< encodeTime <<
" sleepTime: " << sleepTime <<
" elapsed: "<< elapsedTime <<
" Packets:["<< _totalPackets <<"]"<<
" Total Bytes:["<< _totalBytes <<"]"<<
" Wasted bytes:["<< _totalWastedBytes << "]\n";
}
}
@ -326,9 +339,13 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod
nodeData->nodeBag.deleteAll();
}
qDebug("Scene started at %llu. Packets:[%llu]: Total Bytes:[%llu] Wasted bytes:[%llu]\n",
usecTimestampNow(), _totalPackets, _totalBytes, _totalWastedBytes);
bool debug = false;
if (debug) {
qDebug() << "Scene started at " << usecTimestampNow() <<
" Packets:["<< _totalPackets <<"]"<<
" Total Bytes:["<< _totalBytes <<"]"<<
" Wasted bytes:["<< _totalWastedBytes << "]\n";
}
::startSceneSleepTime = _usleepTime;
nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, _myServer->getServerTree().rootNode, _myServer->getJurisdiction());
@ -348,8 +365,8 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod
if (!nodeData->nodeBag.isEmpty()) {
int bytesWritten = 0;
uint64_t start = usecTimestampNow();
uint64_t startCompressTimeMsecs = VoxelPacket::_checkCompressTime / 1000;
uint64_t startCompressCalls = VoxelPacket::_checkCompressCalls;
uint64_t startCompressTimeMsecs = VoxelPacketData::_checkCompressTime / 1000;
uint64_t startCompressCalls = VoxelPacketData::_checkCompressCalls;
bool shouldSendEnvironments = _myServer->wantSendEnvironments() && shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS);
@ -394,9 +411,9 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod
_myServer->getServerTree().lockForRead();
nodeData->stats.encodeStarted();
bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, &_tempPacket, nodeData->nodeBag, params);
bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, &_packetData, nodeData->nodeBag, params);
if (_tempPacket.hasContent() && bytesWritten == 0 && params.stopReason == EncodeBitstreamParams::DIDNT_FIT) {
if (_packetData.hasContent() && bytesWritten == 0 && params.stopReason == EncodeBitstreamParams::DIDNT_FIT) {
lastNodeDidntFit = true;
}
@ -411,18 +428,18 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod
somethingToSend = false; // this will cause us to drop out of the loop...
}
// We only consider sending anything if there is something in the _tempPacket to send... But
// We only consider sending anything if there is something in the _packetData to send... But
// if bytesWritten == 0 it means either the subTree couldn't fit or we had an empty bag... Both cases
// mean we should send the previous packet contents and reset it.
bool sendNow = lastNodeDidntFit;
if (_tempPacket.hasContent() && sendNow) {
if (_packetData.hasContent() && sendNow) {
if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) {
printf("calling writeToPacket() compressedSize=%d uncompressedSize=%d\n",
_tempPacket.getFinalizedSize(), _tempPacket.getUncompressedSize());
_packetData.getFinalizedSize(), _packetData.getUncompressedSize());
}
nodeData->writeToPacket(_tempPacket.getFinalizedData(), _tempPacket.getFinalizedSize());
nodeData->writeToPacket(_packetData.getFinalizedData(), _packetData.getFinalizedSize());
packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
_tempPacket.reset();
_packetData.reset();
}
}
@ -445,10 +462,10 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod
uint64_t end = usecTimestampNow();
int elapsedmsec = (end - start)/1000;
uint64_t endCompressCalls = VoxelPacket::_checkCompressCalls;
uint64_t endCompressCalls = VoxelPacketData::_checkCompressCalls;
int elapsedCompressCalls = endCompressCalls - startCompressCalls;
uint64_t endCompressTimeMsecs = VoxelPacket::_checkCompressTime / 1000;
uint64_t endCompressTimeMsecs = VoxelPacketData::_checkCompressTime / 1000;
int elapsedCompressTimeMsecs = endCompressTimeMsecs - startCompressTimeMsecs;

View file

@ -42,7 +42,7 @@ private:
int deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nodeData, bool viewFrustumChanged);
unsigned char _tempOutputBuffer[MAX_VOXEL_PACKET_SIZE]; // used by environment sending code
VoxelPacket _tempPacket;
VoxelPacketData _packetData;
bool _encodedSomething;
};

View file

@ -268,9 +268,9 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) {
uint64_t totalOutboundPackets = VoxelSendThread::_totalPackets;
uint64_t totalOutboundBytes = VoxelSendThread::_totalBytes;
uint64_t totalWastedBytes = VoxelSendThread::_totalWastedBytes;
uint64_t totalBytesOfOctalCodes = VoxelPacket::_totalBytesOfOctalCodes;
uint64_t totalBytesOfBitMasks = VoxelPacket::_totalBytesOfBitMasks;
uint64_t totalBytesOfColor = VoxelPacket::_totalBytesOfColor;
uint64_t totalBytesOfOctalCodes = VoxelPacketData::_totalBytesOfOctalCodes;
uint64_t totalBytesOfBitMasks = VoxelPacketData::_totalBytesOfBitMasks;
uint64_t totalBytesOfColor = VoxelPacketData::_totalBytesOfColor;
const int COLUMN_WIDTH = 10;
mg_printf(connection, " Total Outbound Packets: %s packets\r\n",
@ -703,8 +703,10 @@ void VoxelServer::run() {
int numBytesPacketHeader = numBytesForPacketHeader(packetData);
if (packetData[0] == PACKET_TYPE_VOXEL_QUERY) {
qDebug("Got PACKET_TYPE_VOXEL_QUERY at %llu.\n", usecTimestampNow());
bool debug = false;
if (debug) {
qDebug("Got PACKET_TYPE_VOXEL_QUERY at %llu.\n", usecTimestampNow());
}
// If we got a PACKET_TYPE_VOXEL_QUERY, then we're talking to an NODE_TYPE_AVATAR, and we
// need to make sure we have it in our nodeList.
@ -732,8 +734,7 @@ void VoxelServer::run() {
} else if (_voxelServerPacketProcessor &&
(packetData[0] == PACKET_TYPE_SET_VOXEL
|| packetData[0] == PACKET_TYPE_SET_VOXEL_DESTRUCTIVE
|| packetData[0] == PACKET_TYPE_ERASE_VOXEL
|| packetData[0] == PACKET_TYPE_Z_COMMAND)) {
|| packetData[0] == PACKET_TYPE_ERASE_VOXEL)) {
const char* messageName;
@ -748,20 +749,6 @@ void VoxelServer::run() {
messageName = "PACKET_TYPE_ERASE_VOXEL";
break;
}
int numBytesPacketHeader = numBytesForPacketHeader(packetData);
if (packetData[0] != PACKET_TYPE_Z_COMMAND) {
unsigned short int sequence = (*((unsigned short int*)(packetData + numBytesPacketHeader)));
uint64_t sentAt = (*((uint64_t*)(packetData + numBytesPacketHeader + sizeof(sequence))));
uint64_t arrivedAt = usecTimestampNow();
uint64_t transitTime = arrivedAt - sentAt;
if (wantShowAnimationDebug() || wantsDebugVoxelReceiving()) {
printf("RECEIVE THREAD: got %s - command from client receivedBytes=%ld sequence=%d transitTime=%llu usecs\n",
messageName,
packetLength, sequence, transitTime);
}
}
_voxelServerPacketProcessor->queueReceivedPacket(senderAddress, packetData, packetLength);
} else {
// let processNodeData handle it.

View file

@ -169,35 +169,6 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned
_myServer->getServerTree().processRemoveVoxelBitstream((unsigned char*)packetData, packetLength);
_myServer->getServerTree().unlock();
// Make sure our Node and NodeList knows we've heard from this node.
Node* node = NodeList::getInstance()->nodeWithAddress(&senderAddress);
if (node) {
node->setLastHeardMicrostamp(usecTimestampNow());
}
} else if (packetData[0] == PACKET_TYPE_Z_COMMAND) {
// the Z command is a special command that allows the sender to send the voxel server high level semantic
// requests, like erase all, or add sphere scene
char* command = (char*) &packetData[numBytesPacketHeader]; // start of the command
int commandLength = strlen(command); // commands are null terminated strings
int totalLength = numBytesPacketHeader + commandLength + 1; // 1 for null termination
printf("got Z message len(%ld)= %s\n", packetLength, command);
bool rebroadcast = true; // by default rebroadcast
while (totalLength <= packetLength) {
if (strcmp(command, TEST_COMMAND) == 0) {
printf("got Z message == a message, nothing to do, just report\n");
}
totalLength += commandLength + 1; // 1 for null termination
}
if (rebroadcast) {
// Now send this to the connected nodes so they can also process these messages
printf("rebroadcasting Z message to connected nodes... nodeList.broadcastToNodes()\n");
NodeList::getInstance()->broadcastToNodes(packetData, packetLength, &NODE_TYPE_AGENT, 1);
}
// Make sure our Node and NodeList knows we've heard from this node.
Node* node = NodeList::getInstance()->nodeWithAddress(&senderAddress);
if (node) {

View file

@ -1,5 +1,5 @@
//
// VoxelPacket.cpp
// VoxelPacketData.cpp
// hifi
//
// Created by Brad Hefta-Gaub on 11/19/2013.
@ -7,27 +7,31 @@
//
#include <PerfStat.h>
#include "VoxelPacket.h"
#include "VoxelPacketData.h"
bool VoxelPacket::_debug = false;
uint64_t VoxelPacket::_totalBytesOfOctalCodes = 0;
uint64_t VoxelPacket::_totalBytesOfBitMasks = 0;
uint64_t VoxelPacket::_totalBytesOfColor = 0;
bool VoxelPacketData::_debug = false;
uint64_t VoxelPacketData::_totalBytesOfOctalCodes = 0;
uint64_t VoxelPacketData::_totalBytesOfBitMasks = 0;
uint64_t VoxelPacketData::_totalBytesOfColor = 0;
VoxelPacket::VoxelPacket(bool enableCompression, int maxFinalizedSize) {
VoxelPacketData::VoxelPacketData(bool enableCompression, int targetSize) {
changeSettings(enableCompression, targetSize); // does reset...
}
void VoxelPacketData::changeSettings(bool enableCompression, int targetSize) {
_enableCompression = enableCompression;
_maxFinalizedSize = maxFinalizedSize;
_targetSize = std::min(MAX_VOXEL_UNCOMRESSED_PACKET_SIZE, targetSize);
reset();
}
void VoxelPacket::reset() {
void VoxelPacketData::reset() {
_bytesInUse = 0;
if (_enableCompression) {
_bytesAvailable = MAX_VOXEL_UNCOMRESSED_PACKET_SIZE;
} else {
_bytesAvailable = _maxFinalizedSize;
_bytesAvailable = _targetSize;
}
_subTreeAt = 0;
_compressedBytes = 0;
@ -40,10 +44,10 @@ void VoxelPacket::reset() {
_bytesOfOctalCodesCurrentSubTree = 0;
}
VoxelPacket::~VoxelPacket() {
VoxelPacketData::~VoxelPacketData() {
}
bool VoxelPacket::append(const unsigned char* data, int length) {
bool VoxelPacketData::append(const unsigned char* data, int length) {
bool success = false;
if (length <= _bytesAvailable) {
@ -56,7 +60,7 @@ bool VoxelPacket::append(const unsigned char* data, int length) {
return success;
}
bool VoxelPacket::append(unsigned char byte) {
bool VoxelPacketData::append(unsigned char byte) {
bool success = false;
if (_bytesAvailable > 0) {
_uncompressed[_bytesInUse] = byte;
@ -68,7 +72,7 @@ bool VoxelPacket::append(unsigned char byte) {
return success;
}
bool VoxelPacket::updatePriorBitMask(int offset, unsigned char bitmask) {
bool VoxelPacketData::updatePriorBitMask(int offset, unsigned char bitmask) {
bool success = false;
if (offset >= 0 && offset < _bytesInUse) {
_uncompressed[offset] = bitmask;
@ -78,7 +82,7 @@ bool VoxelPacket::updatePriorBitMask(int offset, unsigned char bitmask) {
return success;
}
bool VoxelPacket::updatePriorBytes(int offset, const unsigned char* replacementBytes, int length) {
bool VoxelPacketData::updatePriorBytes(int offset, const unsigned char* replacementBytes, int length) {
bool success = false;
if (length >= 0 && offset >= 0 && ((offset + length) <= _bytesInUse)) {
memcpy(&_uncompressed[offset], replacementBytes, length); // copy new content
@ -88,7 +92,7 @@ bool VoxelPacket::updatePriorBytes(int offset, const unsigned char* replacementB
return success;
}
bool VoxelPacket::startSubTree(const unsigned char* octcode) {
bool VoxelPacketData::startSubTree(const unsigned char* octcode) {
_bytesOfOctalCodesCurrentSubTree = _bytesOfOctalCodes;
bool success = false;
int possibleStartAt = _bytesInUse;
@ -112,10 +116,11 @@ bool VoxelPacket::startSubTree(const unsigned char* octcode) {
return success;
}
const unsigned char* VoxelPacket::getFinalizedData() {
const unsigned char* VoxelPacketData::getFinalizedData() {
if (!_enableCompression) {
return &_uncompressed[0];
}
if (_dirty) {
if (_debug) {
@ -124,10 +129,12 @@ const unsigned char* VoxelPacket::getFinalizedData() {
checkCompress();
}
printf("VoxelPacketData::getFinalizedData()... _bytesInUse=%d compressed version..._compressedBytes=%d\n",_bytesInUse, _compressedBytes);
return &_compressed[0];
}
int VoxelPacket::getFinalizedSize() {
int VoxelPacketData::getFinalizedSize() {
if (!_enableCompression) {
return _bytesInUse;
}
@ -143,11 +150,11 @@ int VoxelPacket::getFinalizedSize() {
}
void VoxelPacket::endSubTree() {
void VoxelPacketData::endSubTree() {
_subTreeAt = _bytesInUse;
}
void VoxelPacket::discardSubTree() {
void VoxelPacketData::discardSubTree() {
int bytesInSubTree = _bytesInUse - _subTreeAt;
_bytesInUse -= bytesInSubTree;
_bytesAvailable += bytesInSubTree;
@ -160,12 +167,12 @@ void VoxelPacket::discardSubTree() {
_totalBytesOfOctalCodes -= reduceBytesOfOctalCodes;
}
LevelDetails VoxelPacket::startLevel() {
LevelDetails VoxelPacketData::startLevel() {
LevelDetails key(_bytesInUse, _bytesOfOctalCodes, _bytesOfBitMasks, _bytesOfColor);
return key;
}
void VoxelPacket::discardLevel(LevelDetails key) {
void VoxelPacketData::discardLevel(LevelDetails key) {
int bytesInLevel = _bytesInUse - key._startIndex;
// reset statistics...
@ -196,33 +203,12 @@ void VoxelPacket::discardLevel(LevelDetails key) {
}
}
bool VoxelPacket::endLevel(LevelDetails key) {
bool VoxelPacketData::endLevel(LevelDetails key) {
bool success = true;
// if we are dirty (something has changed) then try a compression test in the following cases...
// 1) If we've previously compressed and our _compressedBytes are "close enough to our limit" that we want to keep
// testing to make sure we don't overflow... VOXEL_PACKET_ALWAYS_TEST_COMPRESSION_THRESHOLD
// 2) If we've passed the uncompressed size where we believe we might pass the compressed threshold, and we've added
// a sufficient number of uncompressed bytes
if (_dirty && (
(_compressedBytes > VOXEL_PACKET_ALWAYS_TEST_COMPRESSED_THRESHOLD) ||
( (_bytesInUse > VOXEL_PACKET_TEST_UNCOMPRESSED_THRESHOLD) &&
(_bytesInUse - _bytesInUseLastCheck > VOXEL_PACKET_TEST_UNCOMPRESSED_CHANGE_THRESHOLD)
)
)) {
if (_debug) {
printf("endLevel() _dirty=%s _compressedBytes=%d _bytesInUse=%d\n",
debug::valueOf(_dirty), _compressedBytes, _bytesInUse);
}
success = checkCompress();
}
if (!success) {
discardLevel(key);
}
return success;
}
bool VoxelPacket::appendBitMask(unsigned char bitmask) {
bool VoxelPacketData::appendBitMask(unsigned char bitmask) {
bool success = append(bitmask); // handles checking compression
if (success) {
_bytesOfBitMasks++;
@ -231,7 +217,7 @@ bool VoxelPacket::appendBitMask(unsigned char bitmask) {
return success;
}
bool VoxelPacket::appendColor(const nodeColor& color) {
bool VoxelPacketData::appendColor(const nodeColor& color) {
// eventually we can make this use a dictionary...
bool success = false;
const int BYTES_PER_COLOR = 3;
@ -252,11 +238,11 @@ bool VoxelPacket::appendColor(const nodeColor& color) {
return success;
}
uint64_t VoxelPacket::_checkCompressTime = 0;
uint64_t VoxelPacket::_checkCompressCalls = 0;
uint64_t VoxelPacketData::_checkCompressTime = 0;
uint64_t VoxelPacketData::_checkCompressCalls = 0;
bool VoxelPacket::checkCompress() {
PerformanceWarning warn(false,"VoxelPacket::checkCompress()",false,&_checkCompressTime,&_checkCompressCalls);
bool VoxelPacketData::checkCompress() {
PerformanceWarning warn(false,"VoxelPacketData::checkCompress()",false,&_checkCompressTime,&_checkCompressCalls);
// without compression, we always pass...
if (!_enableCompression) {
@ -266,11 +252,15 @@ bool VoxelPacket::checkCompress() {
_bytesInUseLastCheck = _bytesInUse;
bool success = false;
const int MAX_COMPRESSION = 2;
const int MAX_COMPRESSION = 9;
// we only want to compress the data payload, not the message header
QByteArray compressedData = qCompress(_uncompressed, _bytesInUse, MAX_COMPRESSION);
if (compressedData.size() < MAX_VOXEL_PACKET_SIZE) {
const uchar* uncompressedData = &_uncompressed[0];
int uncompressedSize = _bytesInUse;
QByteArray compressedData = qCompress(uncompressedData, uncompressedSize, MAX_COMPRESSION);
if (compressedData.size() < MAX_VOXEL_PACKET_DATA_SIZE) {
_compressedBytes = compressedData.size();
for (int i = 0; i < _compressedBytes; i++) {
_compressed[i] = compressedData[i];
@ -278,26 +268,34 @@ bool VoxelPacket::checkCompress() {
_dirty = false;
success = true;
}
//printf("checkCompress() returning %s _compressedBytes=%d\n",debug::valueOf(success), _compressedBytes);
return success;
}
void VoxelPacket::loadFinalizedContent(const unsigned char* data, int length) {
reset(); // by definition we reset upon loading compressed content
if (length > 0) {
void VoxelPacketData::loadFinalizedContent(const unsigned char* data, int length) {
reset();
if (data && length > 0) {
if (_enableCompression) {
QByteArray compressedData;
printf("VoxelPacketData::loadCompressedContent()... copying %d bytes into compressedData \n", length);
for (int i = 0; i < length; i++) {
compressedData[i] = data[i];
_compressed[i] = compressedData[i];
}
_compressedBytes = length;
printf("VoxelPacketData::loadCompressedContent()... compressedData.size()=%d\n", compressedData.size());
QByteArray uncompressedData = qUncompress(compressedData);
printf("VoxelPacketData::loadCompressedContent()... uncompressedData.size()=%d\n", uncompressedData.size());
if (uncompressedData.size() <= _bytesAvailable) {
printf("VoxelPacketData::loadCompressedContent()... copying %d bytes into _uncompressed[] \n", uncompressedData.size());
_bytesInUse = uncompressedData.size();
_bytesAvailable -= uncompressedData.size();
@ -312,13 +310,13 @@ void VoxelPacket::loadFinalizedContent(const unsigned char* data, int length) {
_bytesInUse = _compressedBytes = length;
}
} else {
if (_debug) printf("VoxelPacket::loadCompressedContent()... length = 0, nothing to do...\n");
if (_debug) printf("VoxelPacketData::loadCompressedContent()... length = 0, nothing to do...\n");
}
}
void VoxelPacket::debugContent() {
void VoxelPacketData::debugContent() {
printf("VoxelPacket::debugContent()... COMPRESSED DATA.... size=%d\n",_compressedBytes);
printf("VoxelPacketData::debugContent()... COMPRESSED DATA.... size=%d\n",_compressedBytes);
int perline=0;
for (int i = 0; i < _compressedBytes; i++) {
printf("%.2x ",_compressed[i]);
@ -330,7 +328,7 @@ void VoxelPacket::debugContent() {
}
printf("\n");
printf("VoxelPacket::debugContent()... UNCOMPRESSED DATA.... size=%d\n",_bytesInUse);
printf("VoxelPacketData::debugContent()... UNCOMPRESSED DATA.... size=%d\n",_bytesInUse);
perline=0;
for (int i = 0; i < _bytesInUse; i++) {
printf("%.2x ",_uncompressed[i]);

View file

@ -1,5 +1,5 @@
//
// VoxelPacket.h
// VoxelPacketData.h
// hifi
//
// Created by Brad Hefta-Gaub on 11/19/2013
@ -16,19 +16,26 @@
// to be recalculated
//
#ifndef __hifi__VoxelPacket__
#define __hifi__VoxelPacket__
#ifndef __hifi__VoxelPacketData__
#define __hifi__VoxelPacketData__
#include <SharedUtil.h>
#include "VoxelConstants.h"
#include "VoxelNode.h"
const int MAX_VOXEL_PACKET_SIZE = MAX_PACKET_SIZE - (sizeof(PACKET_TYPE) + sizeof(PACKET_VERSION));
const int MAX_VOXEL_UNCOMRESSED_PACKET_SIZE = 4500;
const int VOXEL_PACKET_ALWAYS_TEST_COMPRESSED_THRESHOLD = 1400;
const int VOXEL_PACKET_TEST_UNCOMPRESSED_THRESHOLD = 4000;
const int VOXEL_PACKET_TEST_UNCOMPRESSED_CHANGE_THRESHOLD = 20;
const int VOXEL_PACKET_COMPRESSION_DEFAULT = false;
typedef unsigned char VOXEL_PACKET_FLAGS;
typedef uint16_t VOXEL_PACKET_SEQUENCE;
typedef uint64_t VOXEL_PACKET_SENT_TIME;
const int MAX_VOXEL_PACKET_SIZE = MAX_PACKET_SIZE;
const int VOXEL_PACKET_HEADER_SIZE = (sizeof(PACKET_TYPE) + sizeof(PACKET_VERSION) + sizeof(VOXEL_PACKET_FLAGS)
+ sizeof(VOXEL_PACKET_SEQUENCE) + sizeof(VOXEL_PACKET_SENT_TIME));
const int MAX_VOXEL_PACKET_DATA_SIZE = MAX_PACKET_SIZE - VOXEL_PACKET_HEADER_SIZE;
const int MAX_VOXEL_UNCOMRESSED_PACKET_SIZE = MAX_VOXEL_PACKET_DATA_SIZE;
const int PACKET_IS_COLOR_BIT = 0;
const int PACKET_IS_COMPRESSED_BIT = 1;
class LevelDetails {
LevelDetails(int startIndex, int bytesOfOctalCodes, int bytesOfBitmasks, int bytesOfColor) :
@ -38,7 +45,7 @@ class LevelDetails {
_bytesOfColor(bytesOfColor) {
}
friend class VoxelPacket;
friend class VoxelPacketData;
private:
int _startIndex;
@ -47,10 +54,13 @@ private:
int _bytesOfColor;
};
class VoxelPacket {
class VoxelPacketData {
public:
VoxelPacket(bool enableCompression = false, int maxFinalizedSize = MAX_VOXEL_PACKET_SIZE);
~VoxelPacket();
VoxelPacketData(bool enableCompression = false, int maxFinalizedSize = MAX_VOXEL_PACKET_DATA_SIZE);
~VoxelPacketData();
/// change compression and target size settings
void changeSettings(bool enableCompression = false, int targetSize = MAX_VOXEL_PACKET_DATA_SIZE);
/// reset completely, all data is discarded
void reset();
@ -108,6 +118,8 @@ public:
/// load finalized content to allow access to decoded content for parsing
void loadFinalizedContent(const unsigned char* data, int length);
bool isCompressed() const { return _enableCompression; }
void debugContent();
@ -125,9 +137,9 @@ private:
/// append a single byte, might fail if byte would cause packet to be too large
bool append(unsigned char byte);
int _targetSize;
bool _enableCompression;
int _maxFinalizedSize;
unsigned char _uncompressed[MAX_VOXEL_UNCOMRESSED_PACKET_SIZE];
int _bytesInUse;
int _bytesAvailable;
@ -150,4 +162,4 @@ private:
};
#endif /* defined(__hifi__VoxelPacket__) */
#endif /* defined(__hifi__VoxelPacketData__) */

View file

@ -35,6 +35,7 @@ VoxelQuery::VoxelQuery(Node* owningNode) :
_wantDelta(true),
_wantLowResMoving(true),
_wantOcclusionCulling(false), // disabled by default
_wantCompression(false), // disabled by default
_maxVoxelPPS(DEFAULT_MAX_VOXEL_PPS),
_voxelSizeScale(DEFAULT_VOXEL_SIZE_SCALE)
{
@ -74,6 +75,7 @@ int VoxelQuery::getBroadcastData(unsigned char* destinationBuffer) {
if (_wantColor) { setAtBit(bitItems, WANT_COLOR_AT_BIT); }
if (_wantDelta) { setAtBit(bitItems, WANT_DELTA_AT_BIT); }
if (_wantOcclusionCulling) { setAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT); }
if (_wantCompression) { setAtBit(bitItems, WANT_COMPRESSION); }
*destinationBuffer++ = bitItems;
@ -122,10 +124,11 @@ int VoxelQuery::parseData(unsigned char* sourceBuffer, int numBytes) {
// voxel sending features...
unsigned char bitItems = 0;
bitItems = (unsigned char)*sourceBuffer++;
_wantLowResMoving = oneAtBit(bitItems, WANT_LOW_RES_MOVING_BIT);
_wantColor = oneAtBit(bitItems, WANT_COLOR_AT_BIT);
_wantDelta = oneAtBit(bitItems, WANT_DELTA_AT_BIT);
_wantLowResMoving = oneAtBit(bitItems, WANT_LOW_RES_MOVING_BIT);
_wantColor = oneAtBit(bitItems, WANT_COLOR_AT_BIT);
_wantDelta = oneAtBit(bitItems, WANT_DELTA_AT_BIT);
_wantOcclusionCulling = oneAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT);
_wantCompression = oneAtBit(bitItems, WANT_COMPRESSION);
// desired Max Voxel PPS
memcpy(&_maxVoxelPPS, sourceBuffer, sizeof(_maxVoxelPPS));

View file

@ -28,7 +28,8 @@
const int WANT_LOW_RES_MOVING_BIT = 0;
const int WANT_COLOR_AT_BIT = 1;
const int WANT_DELTA_AT_BIT = 2;
const int WANT_OCCLUSION_CULLING_BIT = 3; // 4th bit
const int WANT_OCCLUSION_CULLING_BIT = 3;
const int WANT_COMPRESSION = 4; // 5th bit
class VoxelQuery : public NodeData {
Q_OBJECT
@ -68,6 +69,7 @@ public:
bool getWantDelta() const { return _wantDelta; }
bool getWantLowResMoving() const { return _wantLowResMoving; }
bool getWantOcclusionCulling() const { return _wantOcclusionCulling; }
bool getWantCompression() const { return _wantCompression; }
int getMaxVoxelPacketsPerSecond() const { return _maxVoxelPPS; }
float getVoxelSizeScale() const { return _voxelSizeScale; }
int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; }
@ -77,6 +79,7 @@ public slots:
void setWantColor(bool wantColor) { _wantColor = wantColor; }
void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; }
void setWantOcclusionCulling(bool wantOcclusionCulling) { _wantOcclusionCulling = wantOcclusionCulling; }
void setWantCompression(bool wantCompression) { _wantCompression = wantCompression; }
void setMaxVoxelPacketsPerSecond(int maxVoxelPPS) { _maxVoxelPPS = maxVoxelPPS; }
void setVoxelSizeScale(float voxelSizeScale) { _voxelSizeScale = voxelSizeScale; }
void setBoundaryLevelAdjust(int boundaryLevelAdjust) { _boundaryLevelAdjust = boundaryLevelAdjust; }
@ -98,6 +101,7 @@ protected:
bool _wantDelta;
bool _wantLowResMoving;
bool _wantOcclusionCulling;
bool _wantCompression;
int _maxVoxelPPS;
float _voxelSizeScale; /// used for LOD calculations
int _boundaryLevelAdjust; /// used for LOD calculations

View file

@ -1022,7 +1022,7 @@ bool VoxelTree::findCapsulePenetration(const glm::vec3& start, const glm::vec3&
}
int VoxelTree::encodeTreeBitstream(VoxelNode* node,
VoxelPacket* packet, VoxelNodeBag& bag,
VoxelPacketData* packetData, VoxelNodeBag& bag,
EncodeBitstreamParams& params) {
// How many bytes have we written so far at this level;
@ -1049,7 +1049,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node,
int codeLength;
if (params.chopLevels) {
unsigned char* newCode = chopOctalCode(node->getOctalCode(), params.chopLevels);
roomForOctalCode = packet->startSubTree(newCode);
roomForOctalCode = packetData->startSubTree(newCode);
if (newCode) {
delete newCode;
@ -1057,7 +1057,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node,
codeLength = 1;
}
} else {
roomForOctalCode = packet->startSubTree(node->getOctalCode());
roomForOctalCode = packetData->startSubTree(node->getOctalCode());
codeLength = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(node->getOctalCode()));
}
@ -1079,7 +1079,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node,
params.stats->traversed(node);
}
int childBytesWritten = encodeTreeBitstreamRecursion(node, packet, bag, params, currentEncodeLevel);
int childBytesWritten = encodeTreeBitstreamRecursion(node, packetData, bag, params, currentEncodeLevel);
// if childBytesWritten == 1 then something went wrong... that's not possible
assert(childBytesWritten != 1);
@ -1101,9 +1101,9 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node,
}
if (bytesWritten == 0) {
packet->discardSubTree();
packetData->discardSubTree();
} else {
packet->endSubTree();
packetData->endSubTree();
}
doneEncoding(node);
@ -1112,7 +1112,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node,
}
int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node,
VoxelPacket* packet, VoxelNodeBag& bag,
VoxelPacketData* packetData, VoxelNodeBag& bag,
EncodeBitstreamParams& params, int& currentEncodeLevel) const {
// How many bytes have we written so far at this level;
int bytesAtThisLevel = 0;
@ -1261,7 +1261,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node,
const int BYTES_PER_COLOR = 3;
// Make our local buffer large enough to handle writing at this level in case we need to.
LevelDetails thisLevelKey = packet->startLevel();
LevelDetails thisLevelKey = packetData->startLevel();
int inViewCount = 0;
int inViewNotLeafCount = 0;
@ -1440,7 +1440,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node,
}
bool continueThisLevel = true;
continueThisLevel = packet->appendBitMask(childrenColoredBits);
continueThisLevel = packetData->appendBitMask(childrenColoredBits);
if (continueThisLevel) {
bytesAtThisLevel += sizeof(childrenColoredBits); // keep track of byte count
@ -1454,7 +1454,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node,
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
if (oneAtBit(childrenColoredBits, i)) {
VoxelNode* childNode = node->getChildAtIndex(i);
continueThisLevel = packet->appendColor(childNode->getColor());
continueThisLevel = packetData->appendColor(childNode->getColor());
if (!continueThisLevel) {
break; // no point in continuing
@ -1474,7 +1474,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node,
// if the caller wants to include childExistsBits, then include them even if not in view, put them before the
// childrenExistInPacketBits, so that the lower code can properly repair the packet exists bits
if (continueThisLevel && params.includeExistsBits) {
continueThisLevel = packet->appendBitMask(childrenExistInTreeBits);
continueThisLevel = packetData->appendBitMask(childrenExistInTreeBits);
if (continueThisLevel) {
bytesAtThisLevel += sizeof(childrenExistInTreeBits); // keep track of byte count
if (params.stats) {
@ -1485,7 +1485,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node,
// write the child exist bits
if (continueThisLevel) {
continueThisLevel = packet->appendBitMask(childrenExistInPacketBits);
continueThisLevel = packetData->appendBitMask(childrenExistInPacketBits);
if (continueThisLevel) {
bytesAtThisLevel += sizeof(childrenExistInPacketBits); // keep track of byte count
if (params.stats) {
@ -1508,7 +1508,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node,
// write something, we keep them in the bits, if they don't, we take them out.
//
// we know the last thing we wrote to the packet was our childrenExistInPacketBits. Let's remember where that was!
int childExistsPlaceHolder = packet->getUncompressedByteOffset(sizeof(childrenExistInPacketBits));
int childExistsPlaceHolder = packetData->getUncompressedByteOffset(sizeof(childrenExistInPacketBits));
// we are also going to recurse these child trees in "distance" sorted order, but we need to pack them in the
// final packet in standard order. So what we're going to do is keep track of how big each subtree was in bytes,
@ -1516,7 +1516,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node,
// a single recursive pass in distance sorted order, but retain standard order in our encoded packet
int recursiveSliceSizes[NUMBER_OF_CHILDREN];
const unsigned char* recursiveSliceStarts[NUMBER_OF_CHILDREN];
int firstRecursiveSliceOffset = packet->getUncompressedByteOffset();
int firstRecursiveSliceOffset = packetData->getUncompressedByteOffset();
int allSlicesSize = 0;
// for each child node in Distance sorted order..., check to see if they exist, are colored, and in view, and if so
@ -1529,7 +1529,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node,
int thisLevel = currentEncodeLevel;
// remember this for reshuffling
recursiveSliceStarts[originalIndex] = packet->getUncompressedData() + packet->getUncompressedSize();
recursiveSliceStarts[originalIndex] = packetData->getUncompressedData() + packetData->getUncompressedSize();
int childTreeBytesOut = 0;
@ -1542,8 +1542,8 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node,
//
// This only applies in the view frustum case, in other cases, like file save and copy/past where
// no viewFrustum was requested, we still want to recurse the child tree.
if (!params.viewFrustum || !oneAtBit(childrenColoredBits, originalIndex)) {
childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, packet, bag, params, thisLevel);
if (true || !params.viewFrustum || !oneAtBit(childrenColoredBits, originalIndex)) {
childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, packetData, bag, params, thisLevel);
}
// remember this for reshuffling
@ -1586,7 +1586,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node,
childrenExistInPacketBits -= (1 << (7 - originalIndex));
// repair the child exists mask
continueThisLevel = packet->updatePriorBitMask(childExistsPlaceHolder, childrenExistInPacketBits);
continueThisLevel = packetData->updatePriorBitMask(childExistsPlaceHolder, childrenExistInPacketBits);
// 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) {
@ -1622,7 +1622,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node,
}
// now that all slices are back in the correct order, copy them to the correct output buffer
continueThisLevel = packet->updatePriorBytes(firstRecursiveSliceOffset, &tempReshuffleBuffer[0], allSlicesSize);
continueThisLevel = packetData->updatePriorBytes(firstRecursiveSliceOffset, &tempReshuffleBuffer[0], allSlicesSize);
}
} // end keepDiggingDeeper
@ -1640,9 +1640,9 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node,
// if we were unable to fit this level in our packet, then rewind and add it to the node bag for
// sending later...
if (continueThisLevel) {
continueThisLevel = packet->endLevel(thisLevelKey);
continueThisLevel = packetData->endLevel(thisLevelKey);
} else {
packet->discardLevel(thisLevelKey);
packetData->discardLevel(thisLevelKey);
}
if (!continueThisLevel) {
@ -1861,7 +1861,7 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) {
nodeBag.insert(rootNode);
}
static VoxelPacket packet;
static VoxelPacketData packetData;
int bytesWritten = 0;
bool lastPacketWritten = false;
@ -1870,17 +1870,17 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) {
lockForRead(); // do tree locking down here so that we have shorter slices and less thread contention
EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS);
bytesWritten = encodeTreeBitstream(subTree, &packet, nodeBag, params);
bytesWritten = encodeTreeBitstream(subTree, &packetData, nodeBag, params);
unlock();
// if bytesWritten == 0, then it means that the subTree couldn't fit, and so we should reset the packet
// and reinsert the node in our bag and try again...
if (bytesWritten == 0) {
if (packet.hasContent()) {
file.write((const char*)packet.getFinalizedData(), packet.getFinalizedSize());
if (packetData.hasContent()) {
file.write((const char*)packetData.getFinalizedData(), packetData.getFinalizedSize());
lastPacketWritten = true;
}
packet.reset(); // is there a better way to do this? could we fit more?
packetData.reset(); // is there a better way to do this? could we fit more?
nodeBag.insert(subTree);
} else {
lastPacketWritten = false;
@ -1888,7 +1888,7 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) {
}
if (!lastPacketWritten) {
file.write((const char*)packet.getFinalizedData(), packet.getFinalizedSize());
file.write((const char*)packetData.getFinalizedData(), packetData.getFinalizedSize());
}
}
@ -1914,18 +1914,18 @@ void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinat
chopLevels = numberOfThreeBitSectionsInCode(startNode->getOctalCode());
}
static VoxelPacket packet;
static VoxelPacketData packetData;
int bytesWritten = 0;
while (!nodeBag.isEmpty()) {
VoxelNode* subTree = nodeBag.extract();
packet.reset(); // reset the packet between usage
packetData.reset(); // reset the packet between usage
// ask our tree to write a bitsteam
EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS, chopLevels);
bytesWritten = encodeTreeBitstream(subTree, &packet, nodeBag, params);
bytesWritten = encodeTreeBitstream(subTree, &packetData, nodeBag, params);
// ask destination tree to read the bitstream
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS);
destinationTree->readBitstreamToTree(packet.getUncompressedData(), packet.getUncompressedSize(), args);
destinationTree->readBitstreamToTree(packetData.getUncompressedData(), packetData.getUncompressedSize(), args);
}
VoxelNode* destinationStartNode;
@ -1942,22 +1942,22 @@ void VoxelTree::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destin
// If we were given a specific node, start from there, otherwise start from root
nodeBag.insert(sourceTree->rootNode);
static VoxelPacket packet;
static VoxelPacketData packetData;
int bytesWritten = 0;
while (!nodeBag.isEmpty()) {
VoxelNode* subTree = nodeBag.extract();
packet.reset(); // reset between usage
packetData.reset(); // reset between usage
// ask our tree to write a bitsteam
EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS);
bytesWritten = sourceTree->encodeTreeBitstream(subTree, &packet, nodeBag, params);
bytesWritten = sourceTree->encodeTreeBitstream(subTree, &packetData, nodeBag, params);
// ask destination tree to read the bitstream
bool wantImportProgress = true;
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, destinationNode, 0, wantImportProgress);
readBitstreamToTree(packet.getUncompressedData(), packet.getUncompressedSize(), args);
readBitstreamToTree(packetData.getUncompressedData(), packetData.getUncompressedSize(), args);
}
}

View file

@ -17,7 +17,7 @@
#include "ViewFrustum.h"
#include "VoxelNode.h"
#include "VoxelNodeBag.h"
#include "VoxelPacket.h"
#include "VoxelPacketData.h"
#include "VoxelSceneStats.h"
#include "VoxelEditPacketSender.h"
@ -198,7 +198,7 @@ public:
void recurseTreeWithOperationDistanceSorted(RecurseVoxelTreeOperation operation,
const glm::vec3& point, void* extraData=NULL);
int encodeTreeBitstream(VoxelNode* node, VoxelPacket* packet, VoxelNodeBag& bag,
int encodeTreeBitstream(VoxelNode* node, VoxelPacketData* packetData, VoxelNodeBag& bag,
EncodeBitstreamParams& params) ;
bool isDirty() const { return _isDirty; }
@ -257,7 +257,7 @@ private:
void readCodeColorBufferToTreeRecursion(VoxelNode* node, void* extraData);
int encodeTreeBitstreamRecursion(VoxelNode* node,
VoxelPacket* packet, VoxelNodeBag& bag,
VoxelPacketData* packetData, VoxelNodeBag& bag,
EncodeBitstreamParams& params, int& currentEncodeLevel) const;
static bool countVoxelsOperation(VoxelNode* node, void* extraData);