From 86bf268eef4f939ceb08f763a16742b8e0e906d0 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 29 Jul 2013 14:56:33 -0700 Subject: [PATCH 01/11] first cut at multiple voxel servers --- interface/src/Application.cpp | 3 ++- libraries/shared/src/NodeList.cpp | 7 +++--- libraries/shared/src/NodeList.h | 2 +- libraries/voxels/src/VoxelTree.cpp | 2 +- voxel-server/src/main.cpp | 40 +++++++++++++++++++++++++++--- 5 files changed, 44 insertions(+), 10 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c56a58ce90..3122dcdb4f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3496,7 +3496,8 @@ void* Application::networkReceive(void* args) { } // fall through to piggyback message if (app->_renderVoxels->isChecked()) { - Node* voxelServer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_VOXEL_SERVER); + //Node* voxelServer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_VOXEL_SERVER); + Node* voxelServer = NodeList::getInstance()->nodeWithAddress(&senderAddress); if (voxelServer && socketMatch(voxelServer->getActiveSocket(), &senderAddress)) { voxelServer->lock(); diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 9406c6b14d..4e24a6636c 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -24,10 +24,11 @@ #include #endif -const char SOLO_NODE_TYPES[3] = { +// NODE_TYPE_VOXEL_SERVER - removed! + +const char SOLO_NODE_TYPES[2] = { NODE_TYPE_AVATAR_MIXER, - NODE_TYPE_AUDIO_MIXER, - NODE_TYPE_VOXEL_SERVER + NODE_TYPE_AUDIO_MIXER }; const char DEFAULT_DOMAIN_HOSTNAME[MAX_HOSTNAME_BYTES] = "root.highfidelity.io"; diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index 2a66fc7374..4c4795bdb0 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -32,7 +32,7 @@ const unsigned int NODE_SOCKET_LISTEN_PORT = 40103; const int NODE_SILENCE_THRESHOLD_USECS = 2 * 1000000; const int DOMAIN_SERVER_CHECK_IN_USECS = 1 * 1000000; -extern const char SOLO_NODE_TYPES[3]; +extern const char SOLO_NODE_TYPES[2]; const int MAX_HOSTNAME_BYTES = 256; diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index fe67a50dee..9df72e8f4b 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -306,7 +306,7 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData, } - if (includeExistsBits) { + if (false && includeExistsBits) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { // now also check the childrenInTreeMask, if the mask is missing the bit, then it means we need to delete this child // subtree/node, because it shouldn't actually exist in the tree. diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index c009eec2a5..58a1dd036b 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -32,8 +32,12 @@ const char* LOCAL_VOXELS_PERSIST_FILE = "resources/voxels.svo"; const char* VOXELS_PERSIST_FILE = "/etc/highfidelity/voxel-server/resources/voxels.svo"; +const int MAX_FILENAME_LENGTH = 1024; +char voxelPersistFilename[MAX_FILENAME_LENGTH]; const int VOXEL_PERSIST_INTERVAL = 1000 * 30; // every 30 seconds +//::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE + const int VOXEL_LISTEN_PORT = 40106; @@ -375,7 +379,7 @@ void persistVoxelsWhenDirty() { "persistVoxelsWhenDirty() - writeToSVOFile()", ::shouldShowAnimationDebug); printf("saving voxels to file...\n"); - serverTree.writeToSVOFile(::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE); + serverTree.writeToSVOFile(::voxelPersistFilename); serverTree.clearDirtyBit(); // tree is clean after saving printf("DONE saving voxels to file...\n"); } @@ -431,7 +435,20 @@ int main(int argc, const char * argv[]) { qInstallMsgHandler(sharedMessageHandler); - NodeList* nodeList = NodeList::createInstance(NODE_TYPE_VOXEL_SERVER, VOXEL_LISTEN_PORT); + int listenPort = VOXEL_LISTEN_PORT; + // Check to see if the user passed in a command line option for setting listen port + const char* PORT_PARAMETER = "--port"; + const char* portParameter = getCmdOption(argc, argv, PORT_PARAMETER); + if (portParameter) { + listenPort = atoi(portParameter); + if (listenPort < 1) { + listenPort = VOXEL_LISTEN_PORT; + } + printf("portParameter=%s listenPort=%d\n", portParameter, listenPort); + } + + + NodeList* nodeList = NodeList::createInstance(NODE_TYPE_VOXEL_SERVER, listenPort); setvbuf(stdout, NULL, _IOLBF, 0); // Handle Local Domain testing with the --local command line @@ -473,8 +490,19 @@ int main(int argc, const char * argv[]) { // if we want Voxel Persistance, load the local file now... bool persistantFileRead = false; if (::wantVoxelPersist) { - printf("loading voxels from file...\n"); - persistantFileRead = ::serverTree.readFromSVOFile(::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE); + + // Check to see if the user passed in a command line option for setting packet send rate + const char* VOXELS_PERSIST_FILENAME = "--voxelsPersistFilename"; + const char* voxelsPersistFilenameParameter = getCmdOption(argc, argv, VOXELS_PERSIST_FILENAME); + if (voxelsPersistFilenameParameter) { + strcpy(voxelPersistFilename, voxelsPersistFilenameParameter); + } else { + strcpy(voxelPersistFilename, ::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE); + } + + printf("loading voxels from file: %s...\n", voxelPersistFilename); + + persistantFileRead = ::serverTree.readFromSVOFile(::voxelPersistFilename); if (persistantFileRead) { PerformanceWarning warn(::shouldShowAnimationDebug, "persistVoxelsWhenDirty() - reaverageVoxelColors()", ::shouldShowAnimationDebug); @@ -672,11 +700,15 @@ int main(int argc, const char * argv[]) { nodeList->broadcastToNodes(packetData, receivedBytes, &NODE_TYPE_AGENT, 1); } } else if (packetData[0] == PACKET_TYPE_HEAD_DATA) { + // If we got a PACKET_TYPE_HEAD_DATA, then we're talking to an NODE_TYPE_AVATAR, and we // need to make sure we have it in our nodeList. uint16_t nodeID = 0; unpackNodeId(packetData + numBytesPacketHeader, &nodeID); + +printf("got PACKET_TYPE_HEAD_DATA... nodeID=%d\n", nodeID); + Node* node = nodeList->addOrUpdateNode(&nodePublicAddress, &nodePublicAddress, NODE_TYPE_AGENT, From 1b85ad1b828f0d247fe2e3ca673b949116487068 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 29 Jul 2013 16:15:37 -0700 Subject: [PATCH 02/11] cleanup --- voxel-server/src/main.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 58a1dd036b..9ae8f080cc 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -36,8 +36,6 @@ const int MAX_FILENAME_LENGTH = 1024; char voxelPersistFilename[MAX_FILENAME_LENGTH]; const int VOXEL_PERSIST_INTERVAL = 1000 * 30; // every 30 seconds -//::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE - const int VOXEL_LISTEN_PORT = 40106; @@ -700,15 +698,11 @@ int main(int argc, const char * argv[]) { nodeList->broadcastToNodes(packetData, receivedBytes, &NODE_TYPE_AGENT, 1); } } else if (packetData[0] == PACKET_TYPE_HEAD_DATA) { - // If we got a PACKET_TYPE_HEAD_DATA, then we're talking to an NODE_TYPE_AVATAR, and we // need to make sure we have it in our nodeList. uint16_t nodeID = 0; unpackNodeId(packetData + numBytesPacketHeader, &nodeID); - -printf("got PACKET_TYPE_HEAD_DATA... nodeID=%d\n", nodeID); - Node* node = nodeList->addOrUpdateNode(&nodePublicAddress, &nodePublicAddress, NODE_TYPE_AGENT, From 95e6fb16d09b497b8324b4465523acacff97b2c3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 29 Jul 2013 16:17:57 -0700 Subject: [PATCH 03/11] cleanup --- libraries/shared/src/NodeList.cpp | 2 -- libraries/voxels/src/VoxelTree.cpp | 9 +++++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 4e24a6636c..48810f7521 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -24,8 +24,6 @@ #include #endif -// NODE_TYPE_VOXEL_SERVER - removed! - const char SOLO_NODE_TYPES[2] = { NODE_TYPE_AVATAR_MIXER, NODE_TYPE_AUDIO_MIXER diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index b758c8697d..7b8dd67dc2 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -305,8 +305,13 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData, childIndex++; } - - if (false && includeExistsBits) { + // Here's where we need to handle the idea of multiple voxel servers. If we have multiple voxel + // servers, then we don't want to "honor" exists bits for portions of the tree that the server in + // question is responsible for. Maybe we can handle this in the server and not "remove" bits for + // portions of the server that the server is not responsible for.... or maybe we need to let the client + // manage this concept. + const bool singleVoxelServer = true; + if (singleVoxelServer && includeExistsBits) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { // now also check the childrenInTreeMask, if the mask is missing the bit, then it means we need to delete this child // subtree/node, because it shouldn't actually exist in the tree. From 620fe12358cfa410c4e92f5c0759e727e1a754cb Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 29 Jul 2013 16:31:14 -0700 Subject: [PATCH 04/11] support for multiple voxel servers in ping stats --- interface/src/Application.cpp | 31 ++++++++++++++++++++++-------- libraries/voxels/src/VoxelTree.cpp | 2 +- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 42895db69b..70efa48356 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2883,19 +2883,35 @@ void Application::displayStats() { drawtext(10, statsVerticalOffset + 15, 0.10f, 0, 1.0, 0, stats); if (_testPing->isChecked()) { - int pingAudio = 0, pingAvatar = 0, pingVoxel = 0; + int pingAudio = 0, pingAvatar = 0, pingVoxel = 0, pingVoxelMax = 0; - NodeList *nodeList = NodeList::getInstance(); - Node *audioMixerNode = nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER); - Node *avatarMixerNode = nodeList->soloNodeOfType(NODE_TYPE_AVATAR_MIXER); - Node *voxelServerNode = nodeList->soloNodeOfType(NODE_TYPE_VOXEL_SERVER); + NodeList* nodeList = NodeList::getInstance(); + Node* audioMixerNode = nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER); + Node* avatarMixerNode = nodeList->soloNodeOfType(NODE_TYPE_AVATAR_MIXER); pingAudio = audioMixerNode ? audioMixerNode->getPingMs() : 0; pingAvatar = avatarMixerNode ? avatarMixerNode->getPingMs() : 0; - pingVoxel = voxelServerNode ? voxelServerNode->getPingMs() : 0; + + + // Now handle voxel servers, since there could be more than one, we average their ping times + unsigned long totalPingVoxel = 0; + int voxelServerCount = 0; + for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + if (node->getType() == NODE_TYPE_VOXEL_SERVER) { + totalPingVoxel += node->getPingMs(); + voxelServerCount++; + if (pingVoxelMax < node->getPingMs()) { + pingVoxelMax = node->getPingMs(); + } + } + } + if (voxelServerCount) { + pingVoxel = totalPingVoxel/voxelServerCount; + } + char pingStats[200]; - sprintf(pingStats, "Ping audio/avatar/voxel: %d / %d / %d ", pingAudio, pingAvatar, pingVoxel); + sprintf(pingStats, "Ping audio/avatar/voxel: %d / %d / %d avg %d max ", pingAudio, pingAvatar, pingVoxel, pingVoxelMax); drawtext(10, statsVerticalOffset + 35, 0.10f, 0, 1.0, 0, pingStats); } @@ -3495,7 +3511,6 @@ void* Application::networkReceive(void* args) { } // fall through to piggyback message if (app->_renderVoxels->isChecked()) { - //Node* voxelServer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_VOXEL_SERVER); Node* voxelServer = NodeList::getInstance()->nodeWithAddress(&senderAddress); if (voxelServer && socketMatch(voxelServer->getActiveSocket(), &senderAddress)) { voxelServer->lock(); diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 7b8dd67dc2..6fa843fdfe 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -310,7 +310,7 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData, // question is responsible for. Maybe we can handle this in the server and not "remove" bits for // portions of the server that the server is not responsible for.... or maybe we need to let the client // manage this concept. - const bool singleVoxelServer = true; + const bool singleVoxelServer = false; if (singleVoxelServer && includeExistsBits) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { // now also check the childrenInTreeMask, if the mask is missing the bit, then it means we need to delete this child From c7e3fe5ef6a2b95242df5ea2dedae53fca6cee67 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Jul 2013 11:08:48 -0700 Subject: [PATCH 05/11] Added false colorization by voxel server source - switched readBitstreamToTree() to take params struct for future expansion - switched readNodeData() to take params for future expansion - added sourceID to VoxelNode - fixed false colorize routines to correctly redraw by marking tree as dirty --- interface/src/Application.cpp | 7 ++ interface/src/Application.h | 1 + interface/src/VoxelSystem.cpp | 95 +++++++++++++++++++++- interface/src/VoxelSystem.h | 12 ++- interface/src/avatar/AvatarVoxelSystem.cpp | 3 +- libraries/voxels/src/VoxelNode.cpp | 3 + libraries/voxels/src/VoxelNode.h | 8 +- libraries/voxels/src/VoxelTree.cpp | 40 +++++---- libraries/voxels/src/VoxelTree.h | 26 ++++-- 9 files changed, 165 insertions(+), 30 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 70efa48356..f9b40f5ab4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1361,6 +1361,10 @@ void Application::doFalseColorizeOccludedV2() { _voxels.falseColorizeOccludedV2(); } +void Application::doFalseColorizeBySource() { + _voxels.falseColorizeBySource(); +} + void Application::doTrueVoxelColors() { _voxels.trueColorize(); } @@ -1837,6 +1841,7 @@ void Application::initMenu() { renderDebugMenu->addAction("FALSE Color Voxel Out of View", this, SLOT(doFalseColorizeInView())); renderDebugMenu->addAction("FALSE Color Occluded Voxels", this, SLOT(doFalseColorizeOccluded()), Qt::CTRL | Qt::Key_O); renderDebugMenu->addAction("FALSE Color Occluded V2 Voxels", this, SLOT(doFalseColorizeOccludedV2()), Qt::CTRL | Qt::Key_P); + renderDebugMenu->addAction("FALSE Color By Source", this, SLOT(doFalseColorizeBySource()), Qt::CTRL | Qt::SHIFT | Qt::Key_S); renderDebugMenu->addAction("Show TRUE Colors", this, SLOT(doTrueVoxelColors()), Qt::CTRL | Qt::Key_T); (_shouldLowPassFilter = debugMenu->addAction("Test: LowPass filter"))->setCheckable(true); @@ -3518,7 +3523,9 @@ void* Application::networkReceive(void* args) { if (messageData[0] == PACKET_TYPE_ENVIRONMENT_DATA) { app->_environment.parseData(&senderAddress, messageData, messageLength); } else { + app->_voxels.setDataSourceID(voxelServer->getNodeID()); app->_voxels.parseData(messageData, messageLength); + app->_voxels.setDataSourceID(UNKNOWN_NODE_ID); } voxelServer->unlock(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 80ebd34250..42da66bf93 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -151,6 +151,7 @@ private slots: void doFalseColorizeByDistance(); void doFalseColorizeOccluded(); void doFalseColorizeOccludedV2(); + void doFalseColorizeBySource(); void doFalseColorizeInView(); void doTrueVoxelColors(); void doTreeStats(); diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 2d1bfb577c..b30cf362c3 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include "Application.h" #include "CoverageMap.h" @@ -61,6 +63,8 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) : VoxelNode::addDeleteHook(this); _abandonedVBOSlots = 0; + _falseColorizeBySource = false; + _dataSourceID = UNKNOWN_NODE_ID; } void VoxelSystem::nodeDeleted(VoxelNode* node) { @@ -153,13 +157,15 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { case PACKET_TYPE_VOXEL_DATA: { PerformanceWarning warn(_renderWarningsOn, "readBitstreamToTree()"); // ask the VoxelTree to read the bitstream into the tree - _tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, WANT_COLOR, WANT_EXISTS_BITS); + ReadBitstreamToTreeParams args(WANT_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceID()); + _tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args); } break; case PACKET_TYPE_VOXEL_DATA_MONOCHROME: { PerformanceWarning warn(_renderWarningsOn, "readBitstreamToTree()"); // ask the VoxelTree to read the MONOCHROME bitstream into the tree - _tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, NO_COLOR, WANT_EXISTS_BITS); + ReadBitstreamToTreeParams args(NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceID()); + _tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args); } break; case PACKET_TYPE_Z_COMMAND: @@ -747,6 +753,7 @@ void VoxelSystem::randomizeVoxelColors() { _nodeCount = 0; _tree->recurseTreeWithOperation(randomColorOperation); qDebug("setting randomized true color for %d nodes\n", _nodeCount); + _tree->setDirtyBit(); setupNewVoxelsForDrawing(); } @@ -761,6 +768,7 @@ void VoxelSystem::falseColorizeRandom() { _nodeCount = 0; _tree->recurseTreeWithOperation(falseColorizeRandomOperation); qDebug("setting randomized false color for %d nodes\n", _nodeCount); + _tree->setDirtyBit(); setupNewVoxelsForDrawing(); } @@ -775,6 +783,7 @@ void VoxelSystem::trueColorize() { _nodeCount = 0; _tree->recurseTreeWithOperation(trueColorizeOperation); qDebug("setting true color for %d nodes\n", _nodeCount); + _tree->setDirtyBit(); setupNewVoxelsForDrawing(); } @@ -795,6 +804,84 @@ void VoxelSystem::falseColorizeInView(ViewFrustum* viewFrustum) { _nodeCount = 0; _tree->recurseTreeWithOperation(falseColorizeInViewOperation,(void*)viewFrustum); qDebug("setting in view false color for %d nodes\n", _nodeCount); + _tree->setDirtyBit(); + setupNewVoxelsForDrawing(); +} + +// combines the removeOutOfView args into a single class +class groupColor { +public: + unsigned char red, green, blue; + groupColor(unsigned char red, unsigned char green, unsigned char blue) : + red(red), green(green), blue(blue) { }; + + groupColor(const groupColor& color) : + red(color.red), green(color.green), blue(color.blue) { }; + + groupColor() : + red(0), green(0), blue(0) { }; + +}; + +class colorizeBySourceArgs { +public: + std::map colors; +}; + +// Will false colorize voxels that are not in view +bool VoxelSystem::falseColorizeBySourceOperation(VoxelNode* node, void* extraData) { + colorizeBySourceArgs* args = (colorizeBySourceArgs*)extraData; + _nodeCount++; + if (node->isColored()) { + // pick a color based on the source - we want each source to be obviously different + uint16_t nodeID = node->getSourceID(); + + //printf("false colorizing from source %d, color: %d, %d, %d\n", nodeID, + // args->colors[nodeID].red, args->colors[nodeID].green, args->colors[nodeID].blue); + + node->setFalseColor(args->colors[nodeID].red, args->colors[nodeID].green, args->colors[nodeID].blue); + } + return true; // keep going! +} + +void VoxelSystem::falseColorizeBySource() { + _nodeCount = 0; + colorizeBySourceArgs args; + const int NUMBER_OF_COLOR_GROUPS = 3; + const unsigned char MIN_COLOR = 128; + int voxelServerCount = 0; + groupColor groupColors[NUMBER_OF_COLOR_GROUPS] = { groupColor(255, 0, 0), + groupColor(0, 255, 0), + groupColor(0, 0, 255)}; + + // create a bunch of colors we'll use during colorization + NodeList* nodeList = NodeList::getInstance(); + for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + if (node->getType() == NODE_TYPE_VOXEL_SERVER) { + uint16_t nodeID = node->getNodeID(); + int groupColor = voxelServerCount % NUMBER_OF_COLOR_GROUPS; + args.colors[nodeID] = groupColors[groupColor]; + + //printf("assigning color for source %d, color: %d, %d, %d\n", nodeID, + // args.colors[nodeID].red, args.colors[nodeID].green, args.colors[nodeID].blue); + + if (groupColors[groupColor].red > 0) { + groupColors[groupColor].red = ((groupColors[groupColor].red - MIN_COLOR)/2) + MIN_COLOR; + } + if (groupColors[groupColor].green > 0) { + groupColors[groupColor].green = ((groupColors[groupColor].green - MIN_COLOR)/2) + MIN_COLOR; + } + if (groupColors[groupColor].blue > 0) { + groupColors[groupColor].blue = ((groupColors[groupColor].blue - MIN_COLOR)/2) + MIN_COLOR; + } + + voxelServerCount++; + } + } + + _tree->recurseTreeWithOperation(falseColorizeBySourceOperation, &args); + qDebug("setting false color by source for %d nodes\n", _nodeCount); + _tree->setDirtyBit(); setupNewVoxelsForDrawing(); } @@ -848,6 +935,7 @@ void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) { _nodeCount = 0; _tree->recurseTreeWithOperation(falseColorizeDistanceFromViewOperation,(void*)viewFrustum); qDebug("setting in distance false color for %d nodes\n", _nodeCount); + _tree->setDirtyBit(); setupNewVoxelsForDrawing(); } @@ -1027,6 +1115,7 @@ void VoxelSystem::falseColorizeRandomEveryOther() { _tree->recurseTreeWithOperation(falseColorizeRandomEveryOtherOperation,&args); qDebug("randomized false color for every other node: total %ld, colorable %ld, colored %ld\n", args.totalNodes, args.colorableNodes, args.coloredNodes); + _tree->setDirtyBit(); setupNewVoxelsForDrawing(); } @@ -1331,6 +1420,7 @@ void VoxelSystem::falseColorizeOccluded() { //myCoverageMap.erase(); + _tree->setDirtyBit(); setupNewVoxelsForDrawing(); } @@ -1447,6 +1537,7 @@ void VoxelSystem::falseColorizeOccludedV2() { //myCoverageMapV2.erase(); + _tree->setDirtyBit(); setupNewVoxelsForDrawing(); } diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index ca390a5a20..ef7c33ee43 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -33,6 +33,9 @@ public: VoxelSystem(float treeScale = TREE_SCALE, int maxVoxels = MAX_VOXELS_PER_SYSTEM); ~VoxelSystem(); + void setDataSourceID(int dataSourceID) { _dataSourceID = dataSourceID; }; + int getDataSourceID() const { return _dataSourceID; }; + int parseData(unsigned char* sourceBuffer, int numBytes); virtual void init(); @@ -62,6 +65,8 @@ public: void falseColorizeRandomEveryOther(); void falseColorizeOccluded(); void falseColorizeOccludedV2(); + void falseColorizeBySource(); + void killLocalVoxels(); void setRenderPipelineWarnings(bool on) { _renderWarningsOn = on; }; @@ -94,7 +99,7 @@ public: CoverageMap myCoverageMap; virtual void nodeDeleted(VoxelNode* node); - + protected: float _treeScale; int _maxVoxels; @@ -134,7 +139,7 @@ private: static bool falseColorizeOccludedOperation(VoxelNode* node, void* extraData); static bool falseColorizeSubTreeOperation(VoxelNode* node, void* extraData); static bool falseColorizeOccludedV2Operation(VoxelNode* node, void* extraData); - + static bool falseColorizeBySourceOperation(VoxelNode* node, void* extraData); int updateNodeInArraysAsFullVBO(VoxelNode* node); int updateNodeInArraysAsPartialVBO(VoxelNode* node); @@ -195,6 +200,9 @@ private: void freeBufferIndex(glBufferIndex index); void clearFreeBufferIndexes(); + + bool _falseColorizeBySource; + int _dataSourceID; }; #endif diff --git a/interface/src/avatar/AvatarVoxelSystem.cpp b/interface/src/avatar/AvatarVoxelSystem.cpp index c85ea1a343..9a48c7b320 100644 --- a/interface/src/avatar/AvatarVoxelSystem.cpp +++ b/interface/src/avatar/AvatarVoxelSystem.cpp @@ -250,7 +250,8 @@ void AvatarVoxelSystem::handleVoxelDownloadProgress(qint64 bytesReceived, qint64 _voxelReply->deleteLater(); _voxelReply = 0; - _tree->readBitstreamToTree((unsigned char*)entirety.data(), entirety.size(), WANT_COLOR, NO_EXISTS_BITS); + ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS); + _tree->readBitstreamToTree((unsigned char*)entirety.data(), entirety.size(), args); setupNewVoxelsForDrawing(); } diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 8a76d9dfe8..42b34dd542 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -12,6 +12,8 @@ #include +#include + #include "AABox.h" #include "OctalCode.h" #include "SharedUtil.h" @@ -51,6 +53,7 @@ void VoxelNode::init(unsigned char * octalCode) { _voxelSystem = NULL; _isDirty = true; _shouldRender = false; + _sourceID = UNKNOWN_NODE_ID; markWithChangedTime(); calculateAABox(); } diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 38e9627848..5035dbaad3 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -93,8 +93,6 @@ public: void setColor(const nodeColor& color); const nodeColor& getTrueColor() const { return _trueColor; }; const nodeColor& getColor() const { return _currentColor; }; - void setDensity(float density) { _density = density; }; - float getDensity() const { return _density; }; #else void setFalseColor(colorPart red, colorPart green, colorPart blue) { /* no op */ }; void setFalseColored(bool isFalseColored) { /* no op */ }; @@ -105,6 +103,11 @@ public: const nodeColor& getColor() const { return _trueColor; }; #endif + void setDensity(float density) { _density = density; }; + float getDensity() const { return _density; }; + void setSourceID(uint16_t sourceID) { _sourceID = sourceID; }; + uint16_t getSourceID() const { return _sourceID; }; + static void addDeleteHook(VoxelNodeDeleteHook* hook); static void removeDeleteHook(VoxelNodeDeleteHook* hook); @@ -135,6 +138,7 @@ private: unsigned long _subtreeNodeCount; unsigned long _subtreeLeafNodeCount; float _density; // If leaf: density = 1, if internal node: 0-1 density of voxels inside + uint16_t _sourceID; static std::vector _hooks; }; diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 6fa843fdfe..14244ec1e4 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -231,7 +231,7 @@ VoxelNode* VoxelTree::createMissingNode(VoxelNode* lastParentNode, unsigned char } int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData, int bytesLeftToRead, - bool includeColor, bool includeExistsBits) { + ReadBitstreamToTreeParams& args) { // give this destination node the child mask from the packet const unsigned char ALL_CHILDREN_ASSUMED_TO_EXIST = 0xFF; unsigned char colorInPacketMask = *nodeData; @@ -254,12 +254,13 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData, // pull the color for this child nodeColor newColor = { 128, 128, 128, 1}; - if (includeColor) { + if (args.includeColor) { memcpy(newColor, nodeData + bytesRead, 3); bytesRead += 3; } bool nodeWasDirty = destinationNode->getChildAtIndex(i)->isDirty(); destinationNode->getChildAtIndex(i)->setColor(newColor); + destinationNode->getChildAtIndex(i)->setSourceID(args.sourceID); bool nodeIsDirty = destinationNode->getChildAtIndex(i)->isDirty(); if (nodeIsDirty) { _isDirty = true; @@ -273,11 +274,11 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData, } // give this destination node the child mask from the packet - unsigned char childrenInTreeMask = includeExistsBits ? *(nodeData + bytesRead) : ALL_CHILDREN_ASSUMED_TO_EXIST; - unsigned char childMask = *(nodeData + bytesRead + (includeExistsBits ? sizeof(childrenInTreeMask) : 0)); + unsigned char childrenInTreeMask = args.includeExistsBits ? *(nodeData + bytesRead) : ALL_CHILDREN_ASSUMED_TO_EXIST; + unsigned char childMask = *(nodeData + bytesRead + (args.includeExistsBits ? sizeof(childrenInTreeMask) : 0)); int childIndex = 0; - bytesRead += includeExistsBits ? sizeof(childrenInTreeMask) + sizeof(childMask) : sizeof(childMask); + bytesRead += args.includeExistsBits ? sizeof(childrenInTreeMask) + sizeof(childMask) : sizeof(childMask); while (bytesLeftToRead - bytesRead > 0 && childIndex < NUMBER_OF_CHILDREN) { // check the exists mask to see if we have a child to traverse into @@ -300,7 +301,7 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData, // tell the child to read the subsequent data bytesRead += readNodeData(destinationNode->getChildAtIndex(childIndex), - nodeData + bytesRead, bytesLeftToRead - bytesRead, includeColor, includeExistsBits); + nodeData + bytesRead, bytesLeftToRead - bytesRead, args); } childIndex++; } @@ -311,7 +312,7 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData, // portions of the server that the server is not responsible for.... or maybe we need to let the client // manage this concept. const bool singleVoxelServer = false; - if (singleVoxelServer && includeExistsBits) { + if (singleVoxelServer && args.includeExistsBits) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { // now also check the childrenInTreeMask, if the mask is missing the bit, then it means we need to delete this child // subtree/node, because it shouldn't actually exist in the tree. @@ -324,14 +325,14 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData, return bytesRead; } -void VoxelTree::readBitstreamToTree(unsigned char * bitstream, unsigned long int bufferSizeBytes, - bool includeColor, bool includeExistsBits, VoxelNode* destinationNode) { +void VoxelTree::readBitstreamToTree(unsigned char * bitstream, unsigned long int bufferSizeBytes, + ReadBitstreamToTreeParams& args) { int bytesRead = 0; unsigned char* bitstreamAt = bitstream; // If destination node is not included, set it to root - if (!destinationNode) { - destinationNode = rootNode; + if (!args.destinationNode) { + args.destinationNode = rootNode; } _nodesChangedFromBitstream = 0; @@ -341,14 +342,14 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, unsigned long int // if there are more bytes after that, it's assumed to be another root relative tree while (bitstreamAt < bitstream + bufferSizeBytes) { - VoxelNode* bitstreamRootNode = nodeForOctalCode(destinationNode, (unsigned char *)bitstreamAt, NULL); + VoxelNode* bitstreamRootNode = nodeForOctalCode(args.destinationNode, (unsigned char *)bitstreamAt, NULL); if (*bitstreamAt != *bitstreamRootNode->getOctalCode()) { // if the octal code returned is not on the same level as // the code being searched for, we have VoxelNodes to create // Note: we need to create this node relative to root, because we're assuming that the bitstream for the initial // octal code is always relative to root! - bitstreamRootNode = createMissingNode(destinationNode, (unsigned char*) bitstreamAt); + bitstreamRootNode = createMissingNode(args.destinationNode, (unsigned char*) bitstreamAt); if (bitstreamRootNode->isDirty()) { _isDirty = true; _nodesChangedFromBitstream++; @@ -358,8 +359,8 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, unsigned long int int octalCodeBytes = bytesRequiredForCodeLength(*bitstreamAt); int theseBytesRead = 0; theseBytesRead += octalCodeBytes; - theseBytesRead += readNodeData(bitstreamRootNode, bitstreamAt + octalCodeBytes, - bufferSizeBytes - (bytesRead + octalCodeBytes), includeColor, includeExistsBits); + theseBytesRead += readNodeData(bitstreamRootNode, bitstreamAt + octalCodeBytes, + bufferSizeBytes - (bytesRead + octalCodeBytes), args); // skip bitstream to new startPoint bitstreamAt += theseBytesRead; @@ -1553,7 +1554,8 @@ bool VoxelTree::readFromSVOFile(const char* fileName) { // read the entire file into a buffer, WHAT!? Why not. unsigned char* entireFile = new unsigned char[fileLength]; file.read((char*)entireFile, fileLength); - readBitstreamToTree(entireFile, fileLength, WANT_COLOR, NO_EXISTS_BITS); + ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS); + readBitstreamToTree(entireFile, fileLength, args); delete[] entireFile; file.close(); @@ -1707,7 +1709,8 @@ void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinat bytesWritten = encodeTreeBitstream(subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, nodeBag, params); // ask destination tree to read the bitstream - destinationTree->readBitstreamToTree(&outputBuffer[0], bytesWritten, WANT_COLOR, NO_EXISTS_BITS); + ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS); + destinationTree->readBitstreamToTree(&outputBuffer[0], bytesWritten, args); } } @@ -1727,7 +1730,8 @@ void VoxelTree::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destin bytesWritten = sourceTree->encodeTreeBitstream(subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, nodeBag, params); // ask destination tree to read the bitstream - readBitstreamToTree(&outputBuffer[0], bytesWritten, WANT_COLOR, NO_EXISTS_BITS, destinationNode); + ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, destinationNode); + readBitstreamToTree(&outputBuffer[0], bytesWritten, args); } } diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 88394bd825..4d3a906874 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -88,6 +88,25 @@ public: {} }; +class ReadBitstreamToTreeParams { +public: + bool includeColor; + bool includeExistsBits; + VoxelNode* destinationNode; + uint16_t sourceID; + + ReadBitstreamToTreeParams( + bool includeColor = WANT_COLOR, + bool includeExistsBits = WANT_EXISTS_BITS, + VoxelNode* destinationNode = NULL, + uint16_t sourceID = UNKNOWN_NODE_ID) : + includeColor (includeColor), + includeExistsBits (includeExistsBits), + destinationNode (destinationNode), + sourceID (sourceID) + {} +}; + class VoxelTree { public: // when a voxel is created in the tree (object new'd) @@ -109,9 +128,7 @@ public: void eraseAllVoxels(); void processRemoveVoxelBitstream(unsigned char* bitstream, int bufferSizeBytes); - void readBitstreamToTree(unsigned char* bitstream, unsigned long int bufferSizeBytes, - bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS, - VoxelNode* destinationNode = NULL); + void readBitstreamToTree(unsigned char* bitstream, unsigned long int bufferSizeBytes, ReadBitstreamToTreeParams& args); void readCodeColorBufferToTree(unsigned char* codeColorBuffer, bool destructive = false); void deleteVoxelCodeFromTree(unsigned char* codeBuffer, bool collapseEmptyTrees = DONT_COLLAPSE); void printTreeForDebugging(VoxelNode* startNode); @@ -181,8 +198,7 @@ private: VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode) const; VoxelNode* createMissingNode(VoxelNode* lastParentNode, unsigned char* deepestCodeToCreate); - int readNodeData(VoxelNode *destinationNode, unsigned char* nodeData, int bufferSizeBytes, - bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS); + int readNodeData(VoxelNode *destinationNode, unsigned char* nodeData, int bufferSizeBytes, ReadBitstreamToTreeParams& args); bool _isDirty; unsigned long int _nodesChangedFromBitstream; From 93a8e1782d369a28f0436642b5d1cbcc5cc1616e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Jul 2013 12:13:45 -0700 Subject: [PATCH 06/11] cleanup --- interface/src/VoxelSystem.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index b30cf362c3..2631e255fb 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -808,19 +808,15 @@ void VoxelSystem::falseColorizeInView(ViewFrustum* viewFrustum) { setupNewVoxelsForDrawing(); } -// combines the removeOutOfView args into a single class +// helper classes and args for falseColorizeBySource class groupColor { public: unsigned char red, green, blue; groupColor(unsigned char red, unsigned char green, unsigned char blue) : red(red), green(green), blue(blue) { }; - groupColor(const groupColor& color) : - red(color.red), green(color.green), blue(color.blue) { }; - groupColor() : red(0), green(0), blue(0) { }; - }; class colorizeBySourceArgs { From 75fe53263c22e4a28cca57d697a6ea4ccea059b5 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 1 Aug 2013 12:40:40 -0700 Subject: [PATCH 07/11] first cut at jurisdiction maps, not working yet --- libraries/voxels/src/JurisdictionMap.cpp | 64 ++++++++++++++++++++++++ libraries/voxels/src/JurisdictionMap.h | 40 +++++++++++++++ libraries/voxels/src/VoxelTree.cpp | 25 +++++---- libraries/voxels/src/VoxelTree.h | 18 ++++--- 4 files changed, 130 insertions(+), 17 deletions(-) create mode 100644 libraries/voxels/src/JurisdictionMap.cpp create mode 100644 libraries/voxels/src/JurisdictionMap.h diff --git a/libraries/voxels/src/JurisdictionMap.cpp b/libraries/voxels/src/JurisdictionMap.cpp new file mode 100644 index 0000000000..1a2b57965b --- /dev/null +++ b/libraries/voxels/src/JurisdictionMap.cpp @@ -0,0 +1,64 @@ +// +// JurisdictionMap.cpp +// hifi +// +// Created by Brad Hefta-Gaub on 8/1/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#include + +#include "JurisdictionMap.h" +#include "VoxelNode.h" + +JurisdictionMap::~JurisdictionMap() { + clear(); +} + +void JurisdictionMap::clear() { + delete[] _rootOctalCode; + _rootOctalCode = NULL; + + for (int i = 0; i < _endNodes.size(); i++) { + delete[] _endNodes[i]; + } + _endNodes.clear(); +} + +JurisdictionMap::JurisdictionMap() { + unsigned char* rootCode = new unsigned char[1]; + *rootCode = 0; + + std::vector emptyEndNodes; + init(rootCode, emptyEndNodes); +} + +JurisdictionMap::JurisdictionMap(const char* filename) { + clear(); // clean up our own memory + readFromFile(filename); +} + + +JurisdictionMap::JurisdictionMap(unsigned char* rootOctalCode, const std::vector& endNodes) { + init(rootOctalCode, endNodes); +} + +void JurisdictionMap::init(unsigned char* rootOctalCode, const std::vector& endNodes) { + clear(); // clean up our own memory + _rootOctalCode = rootOctalCode; + _endNodes = endNodes; +} + +bool JurisdictionMap::isMyJurisdiction(VoxelNode* node, int childIndex) const { + return true; +} + + +bool JurisdictionMap::readFromFile(const char* filename) { + QSettings settings(QString(filename), QSettings::IniFormat); + QString rootCode = settings->value("root","").toString(); + qDebug("rootCode=%s\n",rootCode); +} + +bool JurisdictionMap::writeToFile(const char* filename) { +} diff --git a/libraries/voxels/src/JurisdictionMap.h b/libraries/voxels/src/JurisdictionMap.h new file mode 100644 index 0000000000..9c9ed9ec0a --- /dev/null +++ b/libraries/voxels/src/JurisdictionMap.h @@ -0,0 +1,40 @@ +// +// JurisdictionMap.h +// hifi +// +// Created by Brad Hefta-Gaub on 8/1/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __hifi__JurisdictionMap__ +#define __hifi__JurisdictionMap__ + +#include + +class VoxelNode; // forward declaration + +class JurisdictionMap { +public: + JurisdictionMap(); + JurisdictionMap(const char* filename); + JurisdictionMap(unsigned char* rootOctalCode, const std::vector& endNodes); + ~JurisdictionMap(); + + + bool isMyJurisdiction(VoxelNode* node, int childIndex) const; + +private: + void clear(); + void init(unsigned char* rootOctalCode, const std::vector& endNodes); + + bool writeToFile(const char* filename); + bool readFromFile(const char* filename); + + + unsigned char* _rootOctalCode; + std::vector _endNodes; +}; + +#endif /* defined(__hifi__JurisdictionMap__) */ + + diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 14244ec1e4..0b8812f850 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -306,13 +306,7 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData, childIndex++; } - // Here's where we need to handle the idea of multiple voxel servers. If we have multiple voxel - // servers, then we don't want to "honor" exists bits for portions of the tree that the server in - // question is responsible for. Maybe we can handle this in the server and not "remove" bits for - // portions of the server that the server is not responsible for.... or maybe we need to let the client - // manage this concept. - const bool singleVoxelServer = false; - if (singleVoxelServer && args.includeExistsBits) { + if (args.includeExistsBits) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { // now also check the childrenInTreeMask, if the mask is missing the bit, then it means we need to delete this child // subtree/node, because it shouldn't actually exist in the tree. @@ -1203,9 +1197,18 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { VoxelNode* childNode = node->getChildAtIndex(i); - // if the caller wants to include childExistsBits, then include them even if not in view - if (params.includeExistsBits && childNode) { - childrenExistInTreeBits += (1 << (7 - i)); + // if the caller wants to include childExistsBits, then include them even if not in view, if however, + // we're in a portion of the tree that's not our responsibility, then we assume the child nodes exist + // even if they don't in our local tree + bool notMyJurisdictionBro = false; + if (params.jurisdictionMap) { + notMyJurisdictionBro = !params.jurisdictionMap->isMyJurisdiction(node, i); + } + if (params.includeExistsBits) { + // If the child is known to exist, OR, it's not my jurisdiction, then we mark the bit as existing + if (childNode || notMyJurisdictionBro) { + childrenExistInTreeBits += (1 << (7 - i)); + } } if (params.wantOcclusionCulling) { @@ -1886,4 +1889,4 @@ void VoxelTree::computeBlockColor(int id, int data, int& red, int& green, int& b create = 0; break; } -} +} \ No newline at end of file diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 4d3a906874..f27543caa8 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -13,6 +13,7 @@ #include #include "CoverageMap.h" +#include "JurisdictionMap.h" #include "ViewFrustum.h" #include "VoxelNode.h" #include "VoxelNodeBag.h" @@ -36,9 +37,10 @@ const int NO_BOUNDARY_ADJUST = 0; const int LOW_RES_MOVING_ADJUST = 1; const uint64_t IGNORE_LAST_SENT = 0; -#define IGNORE_SCENE_STATS NULL -#define IGNORE_VIEW_FRUSTUM NULL -#define IGNORE_COVERAGE_MAP NULL +#define IGNORE_SCENE_STATS NULL +#define IGNORE_VIEW_FRUSTUM NULL +#define IGNORE_COVERAGE_MAP NULL +#define IGNORE_JURISDICTION_MAP NULL class EncodeBitstreamParams { public: @@ -56,6 +58,7 @@ public: bool forceSendScene; VoxelSceneStats* stats; CoverageMap* map; + JurisdictionMap* jurisdictionMap; EncodeBitstreamParams( int maxEncodeLevel = INT_MAX, @@ -70,7 +73,8 @@ public: int boundaryLevelAdjust = NO_BOUNDARY_ADJUST, uint64_t lastViewFrustumSent = IGNORE_LAST_SENT, bool forceSendScene = true, - VoxelSceneStats* stats = IGNORE_SCENE_STATS) : + VoxelSceneStats* stats = IGNORE_SCENE_STATS, + JurisdictionMap* jurisdictionMap = IGNORE_JURISDICTION_MAP) : maxEncodeLevel (maxEncodeLevel), maxLevelReached (0), viewFrustum (viewFrustum), @@ -84,7 +88,8 @@ public: lastViewFrustumSent (lastViewFrustumSent), forceSendScene (forceSendScene), stats (stats), - map (map) + map (map), + jurisdictionMap (jurisdictionMap) {} }; @@ -186,7 +191,8 @@ public: void recurseTreeWithOperationDistanceSortedTimed(PointerStack* stackOfNodes, long allowedTime, RecurseVoxelTreeOperation operation, const glm::vec3& point, void* extraData); - + + private: void deleteVoxelCodeFromTreeRecursion(VoxelNode* node, void* extraData); void readCodeColorBufferToTreeRecursion(VoxelNode* node, void* extraData); From 81a363f053de0335c1b0bbcb5260fee6aeba28fb Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 1 Aug 2013 22:05:13 -0700 Subject: [PATCH 08/11] added reading/writing to jurisdiction files --- libraries/voxels/src/JurisdictionMap.cpp | 80 +++++++++++++++++++++--- libraries/voxels/src/JurisdictionMap.h | 8 ++- voxel-server/src/main.cpp | 21 ++++++- 3 files changed, 96 insertions(+), 13 deletions(-) diff --git a/libraries/voxels/src/JurisdictionMap.cpp b/libraries/voxels/src/JurisdictionMap.cpp index 1a2b57965b..b3ea5f21f5 100644 --- a/libraries/voxels/src/JurisdictionMap.cpp +++ b/libraries/voxels/src/JurisdictionMap.cpp @@ -7,6 +7,8 @@ // #include +#include +#include #include "JurisdictionMap.h" #include "VoxelNode.h" @@ -16,16 +18,20 @@ JurisdictionMap::~JurisdictionMap() { } void JurisdictionMap::clear() { - delete[] _rootOctalCode; - _rootOctalCode = NULL; + if (_rootOctalCode) { + delete[] _rootOctalCode; + _rootOctalCode = NULL; + } for (int i = 0; i < _endNodes.size(); i++) { - delete[] _endNodes[i]; + if (_endNodes[i]) { + delete[] _endNodes[i]; + } } _endNodes.clear(); } -JurisdictionMap::JurisdictionMap() { +JurisdictionMap::JurisdictionMap() : _rootOctalCode(NULL) { unsigned char* rootCode = new unsigned char[1]; *rootCode = 0; @@ -33,13 +39,14 @@ JurisdictionMap::JurisdictionMap() { init(rootCode, emptyEndNodes); } -JurisdictionMap::JurisdictionMap(const char* filename) { +JurisdictionMap::JurisdictionMap(const char* filename) : _rootOctalCode(NULL) { clear(); // clean up our own memory readFromFile(filename); } -JurisdictionMap::JurisdictionMap(unsigned char* rootOctalCode, const std::vector& endNodes) { +JurisdictionMap::JurisdictionMap(unsigned char* rootOctalCode, const std::vector& endNodes) + : _rootOctalCode(NULL) { init(rootOctalCode, endNodes); } @@ -55,10 +62,65 @@ bool JurisdictionMap::isMyJurisdiction(VoxelNode* node, int childIndex) const { bool JurisdictionMap::readFromFile(const char* filename) { - QSettings settings(QString(filename), QSettings::IniFormat); - QString rootCode = settings->value("root","").toString(); - qDebug("rootCode=%s\n",rootCode); + QString settingsFile(filename); + QSettings settings(settingsFile, QSettings::IniFormat); + QString rootCode = settings.value("root","").toString(); + qDebug() << "rootCode=" << rootCode << "\n"; + + unsigned char* rootOctCode = hexStringToOctalCode(rootCode); + printOctalCode(rootOctCode); + + settings.beginGroup("endNodes"); + const QStringList childKeys = settings.childKeys(); + QHash values; + foreach (const QString &childKey, childKeys) { + QString childValue = settings.value(childKey).toString(); + values.insert(childKey, childValue); + qDebug() << childKey << "=" << childValue << "\n"; + + unsigned char* octcode = hexStringToOctalCode(childValue); + printOctalCode(octcode); + + _endNodes.push_back(octcode); + } + settings.endGroup(); + return true; } bool JurisdictionMap::writeToFile(const char* filename) { + QString settingsFile(filename); + QSettings settings(settingsFile, QSettings::IniFormat); + + settings.setValue("root", "rootNodeValue"); + + settings.beginGroup("endNodes"); + for (int i = 0; i < _endNodes.size(); i++) { + QString key = QString("endnode%1").arg(i); + QString value = QString("valuenode%1").arg(i); + settings.setValue(key, value); + } + settings.endGroup(); + return true; } + + +unsigned char* JurisdictionMap::hexStringToOctalCode(const QString& input) { + // i variable used to hold position in string + int i = 0; + // x variable used to hold byte array element position + int x = 0; + // allocate byte array based on half of string length + unsigned char* bytes = new unsigned char[(input.length()) / 2]; + // loop through the string - 2 bytes at a time converting + // it to decimal equivalent and store in byte array + while (input.length() > i + 1) { + + bool ok; + uint value = input.mid(i, 2).toUInt(&ok,16); + bytes[x] = (unsigned char)value; + i += 2; + x += 1; + } + // return the finished byte array of decimal values + return bytes; +} \ No newline at end of file diff --git a/libraries/voxels/src/JurisdictionMap.h b/libraries/voxels/src/JurisdictionMap.h index 9c9ed9ec0a..dd0160e7a1 100644 --- a/libraries/voxels/src/JurisdictionMap.h +++ b/libraries/voxels/src/JurisdictionMap.h @@ -10,6 +10,7 @@ #define __hifi__JurisdictionMap__ #include +#include class VoxelNode; // forward declaration @@ -20,15 +21,16 @@ public: JurisdictionMap(unsigned char* rootOctalCode, const std::vector& endNodes); ~JurisdictionMap(); - bool isMyJurisdiction(VoxelNode* node, int childIndex) const; + + bool writeToFile(const char* filename); + bool readFromFile(const char* filename); private: void clear(); void init(unsigned char* rootOctalCode, const std::vector& endNodes); - bool writeToFile(const char* filename); - bool readFromFile(const char* filename); + unsigned char* hexStringToOctalCode(const QString& input); unsigned char* _rootOctalCode; diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 75eac7353b..ef0a785fc8 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -430,6 +430,7 @@ void attachVoxelNodeDataToNode(Node* newNode) { } int receivedPacketCount = 0; +JurisdictionMap* jurisdiction = NULL; int main(int argc, const char * argv[]) { pthread_mutex_init(&::treeLock, NULL); @@ -447,7 +448,21 @@ int main(int argc, const char * argv[]) { } printf("portParameter=%s listenPort=%d\n", portParameter, listenPort); } - + + const char* JURISDICTION_FILE = "--jurisdictionFile"; + const char* jurisdictionFile = getCmdOption(argc, argv, JURISDICTION_FILE); + if (jurisdictionFile) { + printf("jurisdictionFile=%s\n", jurisdictionFile); + + printf("about to readFromFile().... jurisdictionFile=%s\n", jurisdictionFile); + jurisdiction = new JurisdictionMap(jurisdictionFile); + printf("after readFromFile().... jurisdictionFile=%s\n", jurisdictionFile); + + // test writing the file... + //printf("about to writeToFile().... jurisdictionFile=%s\n", jurisdictionFile); + //jurisdiction->writeToFile(jurisdictionFile); + //printf("after writeToFile().... jurisdictionFile=%s\n", jurisdictionFile); + } NodeList* nodeList = NodeList::createInstance(NODE_TYPE_VOXEL_SERVER, listenPort); setvbuf(stdout, NULL, _IOLBF, 0); @@ -733,6 +748,10 @@ int main(int argc, const char * argv[]) { pthread_join(sendVoxelThread, NULL); pthread_mutex_destroy(&::treeLock); + + if (jurisdiction) { + delete jurisdiction; + } return 0; } From f57d86ddb200d0313bbf1fb18c3ddb5b762ef8dc Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 2 Aug 2013 08:56:55 -0700 Subject: [PATCH 09/11] writing jurisdiction map configs --- libraries/voxels/src/JurisdictionMap.cpp | 66 +++++++++++++++++------- libraries/voxels/src/JurisdictionMap.h | 3 +- voxel-server/src/main.cpp | 6 +-- 3 files changed, 51 insertions(+), 24 deletions(-) diff --git a/libraries/voxels/src/JurisdictionMap.cpp b/libraries/voxels/src/JurisdictionMap.cpp index b3ea5f21f5..5c1fc5c52f 100644 --- a/libraries/voxels/src/JurisdictionMap.cpp +++ b/libraries/voxels/src/JurisdictionMap.cpp @@ -64,11 +64,11 @@ bool JurisdictionMap::isMyJurisdiction(VoxelNode* node, int childIndex) const { bool JurisdictionMap::readFromFile(const char* filename) { QString settingsFile(filename); QSettings settings(settingsFile, QSettings::IniFormat); - QString rootCode = settings.value("root","").toString(); + QString rootCode = settings.value("root","00").toString(); qDebug() << "rootCode=" << rootCode << "\n"; - unsigned char* rootOctCode = hexStringToOctalCode(rootCode); - printOctalCode(rootOctCode); + _rootOctalCode = hexStringToOctalCode(rootCode); + printOctalCode(_rootOctalCode); settings.beginGroup("endNodes"); const QStringList childKeys = settings.childKeys(); @@ -91,12 +91,15 @@ bool JurisdictionMap::writeToFile(const char* filename) { QString settingsFile(filename); QSettings settings(settingsFile, QSettings::IniFormat); - settings.setValue("root", "rootNodeValue"); + + QString rootNodeValue = octalCodeToHexString(_rootOctalCode); + + settings.setValue("root", rootNodeValue); settings.beginGroup("endNodes"); for (int i = 0; i < _endNodes.size(); i++) { QString key = QString("endnode%1").arg(i); - QString value = QString("valuenode%1").arg(i); + QString value = octalCodeToHexString(_endNodes[i]); settings.setValue(key, value); } settings.endGroup(); @@ -104,23 +107,46 @@ bool JurisdictionMap::writeToFile(const char* filename) { } -unsigned char* JurisdictionMap::hexStringToOctalCode(const QString& input) { - // i variable used to hold position in string - int i = 0; - // x variable used to hold byte array element position - int x = 0; +unsigned char* JurisdictionMap::hexStringToOctalCode(const QString& input) const { + const int HEX_NUMBER_BASE = 16; + const int HEX_BYTE_SIZE = 2; + int stringIndex = 0; + int byteArrayIndex = 0; + // allocate byte array based on half of string length - unsigned char* bytes = new unsigned char[(input.length()) / 2]; + unsigned char* bytes = new unsigned char[(input.length()) / HEX_BYTE_SIZE]; + // loop through the string - 2 bytes at a time converting // it to decimal equivalent and store in byte array - while (input.length() > i + 1) { - - bool ok; - uint value = input.mid(i, 2).toUInt(&ok,16); - bytes[x] = (unsigned char)value; - i += 2; - x += 1; + bool ok; + while (stringIndex < input.length()) { + uint value = input.mid(stringIndex, HEX_BYTE_SIZE).toUInt(&ok, HEX_NUMBER_BASE); + if (!ok) { + break; + } + bytes[byteArrayIndex] = (unsigned char)value; + stringIndex += HEX_BYTE_SIZE; + byteArrayIndex++; + } + + // something went wrong + if (!ok) { + delete[] bytes; + return NULL; } - // return the finished byte array of decimal values return bytes; -} \ No newline at end of file +} + +QString JurisdictionMap::octalCodeToHexString(unsigned char* octalCode) const { + const int HEX_NUMBER_BASE = 16; + const int HEX_BYTE_SIZE = 2; + QString output; + if (!octalCode) { + output = "00"; + } else { + for (int i = 0; i < bytesRequiredForCodeLength(*octalCode); i++) { + output.append(QString("%1").arg(octalCode[i], HEX_BYTE_SIZE, HEX_NUMBER_BASE, QChar('0')).toUpper()); + } + } + return output; +} diff --git a/libraries/voxels/src/JurisdictionMap.h b/libraries/voxels/src/JurisdictionMap.h index dd0160e7a1..bf091a6cce 100644 --- a/libraries/voxels/src/JurisdictionMap.h +++ b/libraries/voxels/src/JurisdictionMap.h @@ -30,7 +30,8 @@ private: void clear(); void init(unsigned char* rootOctalCode, const std::vector& endNodes); - unsigned char* hexStringToOctalCode(const QString& input); + unsigned char* hexStringToOctalCode(const QString& input) const; + QString octalCodeToHexString(unsigned char* octalCode) const; unsigned char* _rootOctalCode; diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index ef0a785fc8..0c82bd5f09 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -459,9 +459,9 @@ int main(int argc, const char * argv[]) { printf("after readFromFile().... jurisdictionFile=%s\n", jurisdictionFile); // test writing the file... - //printf("about to writeToFile().... jurisdictionFile=%s\n", jurisdictionFile); - //jurisdiction->writeToFile(jurisdictionFile); - //printf("after writeToFile().... jurisdictionFile=%s\n", jurisdictionFile); + printf("about to writeToFile().... jurisdictionFile=%s\n", jurisdictionFile); + jurisdiction->writeToFile(jurisdictionFile); + printf("after writeToFile().... jurisdictionFile=%s\n", jurisdictionFile); } NodeList* nodeList = NodeList::createInstance(NODE_TYPE_VOXEL_SERVER, listenPort); From 558fca79360c69e451e20a550bcdf345e73cd0f7 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 2 Aug 2013 11:12:33 -0700 Subject: [PATCH 10/11] latest jurisdiction work --- libraries/shared/src/OctalCode.cpp | 39 ++++++++++++++++++++++++ libraries/shared/src/OctalCode.h | 4 ++- libraries/voxels/src/JurisdictionMap.cpp | 30 ++++++++++++++++-- libraries/voxels/src/JurisdictionMap.h | 11 ++++--- libraries/voxels/src/VoxelTree.cpp | 15 +++++++-- voxel-server/src/main.cpp | 7 ++--- 6 files changed, 92 insertions(+), 14 deletions(-) diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index b085a146a2..8acc9a922f 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -257,3 +257,42 @@ unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* return newCode; } +bool isAncestorOf(unsigned char* possibleAncestor, unsigned char* possibleDescendent, int descendentsChild) { + if (!possibleAncestor || !possibleDescendent) { + return false; + } + + int ancestorCodeLength = numberOfThreeBitSectionsInCode(possibleAncestor); + if (ancestorCodeLength == 0) { + return true; // this is the root, it's the anscestor of all + } + + int descendentCodeLength = numberOfThreeBitSectionsInCode(possibleDescendent); + + // if the caller also include a child, then our descendent length is actually one extra! + if (descendentsChild != CHECK_NODE_ONLY) { + descendentCodeLength++; + } + + if (ancestorCodeLength > descendentCodeLength) { + return false; // if the descendent is shorter, it can't be a descendent + } + + // compare the sections for the ancestor to the descendent + for (int section = 0; section < ancestorCodeLength; section++) { + char sectionValueAncestor = getOctalCodeSectionValue(possibleAncestor, section); + char sectionValueDescendent; + if (ancestorCodeLength <= descendentCodeLength) { + sectionValueDescendent = getOctalCodeSectionValue(possibleDescendent, section); + } else { + assert(descendentsChild != CHECK_NODE_ONLY); + sectionValueDescendent = descendentsChild; + } + if (sectionValueAncestor != sectionValueDescendent) { + return false; // first non-match, means they don't match + } + } + + // they all match, so we are an ancestor + return true; +} diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index 228d5f72b5..477751ea7c 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -21,7 +21,6 @@ const int BLUE_INDEX = 2; void printOctalCode(unsigned char * octalCode); int bytesRequiredForCodeLength(unsigned char threeBitCodes); -bool isDirectParentOfChild(unsigned char *parentOctalCode, unsigned char * childOctalCode); int branchIndexWithDescendant(unsigned char * ancestorOctalCode, unsigned char * descendantOctalCode); unsigned char * childOctalCode(unsigned char * parentOctalCode, char childNumber); int numberOfThreeBitSectionsInCode(unsigned char * octalCode); @@ -29,6 +28,9 @@ unsigned char* chopOctalCode(unsigned char* originalOctalCode, int chopLevels); unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* newParentOctalCode, bool includeColorSpace = false); +const int CHECK_NODE_ONLY = -1; +bool isAncestorOf(unsigned char* possibleAncestor, unsigned char* possibleDescendent, int descendentsChild = CHECK_NODE_ONLY); + // Note: copyFirstVertexForCode() is preferred because it doesn't allocate memory for the return // but other than that these do the same thing. float * firstVertexForCode(unsigned char * octalCode); diff --git a/libraries/voxels/src/JurisdictionMap.cpp b/libraries/voxels/src/JurisdictionMap.cpp index 5c1fc5c52f..b67963d8d6 100644 --- a/libraries/voxels/src/JurisdictionMap.cpp +++ b/libraries/voxels/src/JurisdictionMap.cpp @@ -56,8 +56,34 @@ void JurisdictionMap::init(unsigned char* rootOctalCode, const std::vector