From 4b726b7fba5f7ce9f1e0c96195c04d1b0b1c9da5 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 24 Apr 2013 22:49:09 -0700 Subject: [PATCH 01/76] added compareOctalCodes() and support for null octal code in printOctalCode() --- libraries/shared/src/OctalCode.cpp | 34 ++++++++++++++++++++++++++++-- libraries/shared/src/OctalCode.h | 9 ++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index 898eaed377..2e9fadb0f6 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -10,6 +10,9 @@ #include #include "SharedUtil.h" #include "OctalCode.h" +#include "shared_Log.h" + +using shared_lib::printLog; int numberOfThreeBitSectionsInCode(unsigned char * octalCode) { if (*octalCode == 255) { @@ -20,8 +23,13 @@ int numberOfThreeBitSectionsInCode(unsigned char * octalCode) { } void printOctalCode(unsigned char * octalCode) { - for (int i = 0; i < bytesRequiredForCodeLength(*octalCode); i++) { - outputBits(octalCode[i]); + if (!octalCode) { + printLog("NULL\n"); + } else { + for (int i = 0; i < bytesRequiredForCodeLength(*octalCode); i++) { + outputBits(octalCode[i],false); + } + printLog("\n"); } } @@ -126,3 +134,25 @@ float * firstVertexForCode(unsigned char * octalCode) { return firstVertex; } +OctalTreeDepth compareOctalCodes(unsigned char* codeA, unsigned char* codeB) { + if (!codeA || !codeB) { + return ILLEGAL_CODE; + } + + OctalTreeDepth result = SHALLOWER; // assume it's shallower + int codeLenthA = numberOfThreeBitSectionsInCode(codeA); + int codeLenthB = numberOfThreeBitSectionsInCode(codeB); + + if (codeLenthA > codeLenthB) { + result = DEEPER; + } else if (codeLenthA == codeLenthB) { + int numberOfBytes = bytesRequiredForCodeLength(*codeA); // they are the same!! + if (0 == memcmp(codeA,codeB,numberOfBytes)) { + result = EXACT_MATCH; + } else { + result = EQUAL_DEPTH; + } + } + return result; +} + diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index 7569e99868..65c2fcca91 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -23,4 +23,13 @@ unsigned char * childOctalCode(unsigned char * parentOctalCode, char childNumber float * firstVertexForCode(unsigned char * octalCode); void copyFirstVertexForCode(unsigned char * octalCode, float* output); +typedef enum { + SHALLOWER, + EQUAL_DEPTH, + EXACT_MATCH, + DEEPER, + ILLEGAL_CODE +} OctalTreeDepth; + +OctalTreeDepth compareOctalCodes(unsigned char* code1, unsigned char* code2); #endif /* defined(__hifi__OctalCode__) */ From bbdf97ccc40714e124b7ee44a18f05a36938e4bb Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 24 Apr 2013 22:50:40 -0700 Subject: [PATCH 02/76] added some helper functions for debugging and for improved voxel protocol - added outputBufferBits() which will output an entire buffer as debug bits/bytes - tweak to outputBits() to allow caller to ask for NewLine or not - added insertIntoSortedArrays() which keeps a set of arrays sorted by a key --- libraries/shared/src/SharedUtil.cpp | 53 +++++++++++++++++++++++++++-- libraries/shared/src/SharedUtil.h | 5 ++- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 533135d3ac..d7f2fdde73 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -52,14 +52,30 @@ bool randomBoolean() { return rand() % 2; } -void outputBits(unsigned char byte) { - printLog("%d: ", byte); +void outputBufferBits(unsigned char* buffer, int length, bool withNewLine) { + for (int i = 0; i < length; i++) { + outputBits(buffer[i],false); + } + if (withNewLine) { + printLog("\n"); + } +} + +void outputBits(unsigned char byte, bool withNewLine) { + if (isalnum(byte)) { + printLog("[ %d (%c): ", byte, byte); + } else { + printLog("[ %d (0x%x): ", byte, byte); + } for (int i = 0; i < 8; i++) { printLog("%d", byte >> (7 - i) & 1); } + printLog(" ] "); - printLog("\n"); + if (withNewLine) { + printLog("\n"); + } } int numberOfOnes(unsigned char byte) { @@ -356,3 +372,34 @@ void printVoxelCode(unsigned char* voxelCode) { } #endif + +// Inserts the value and key into three arrays sorted by the key array, the first array is the value, +// the second array is a sorted key for the value, the third array is the index for the value in it original +// non-sorted array +// returns -1 if size exceeded +int insertIntoSortedArrays(void* value, float key, int originalIndex, + void** valueArray, float* keyArray, int* originalIndexArray, int currentCount, int maxCount) { + + if (currentCount < maxCount) { + int i=0; + if (currentCount > 0) { + while (i keyArray[i]) { + i++; + } + // i is our desired location + // shift array elements to the right + if (i < currentCount && i+1 < maxCount) { + memcpy(&valueArray[i+1],&valueArray[i],sizeof(void*) * (currentCount-i)); + memcpy(&keyArray[i+1],&keyArray[i],sizeof(float) * (currentCount-i)); + memcpy(&originalIndexArray[i+1],&originalIndexArray[i],sizeof(int) * (currentCount-i)); + } + } + // place new element at i + valueArray[i]=value; + keyArray[i]=key; + originalIndexArray[i]=originalIndex; + return currentCount+1; + } + return -1; // error case +} + diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index e70229637a..d887cbe956 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -42,7 +42,8 @@ float randFloatInRange (float min,float max); unsigned char randomColorValue(int minimum); bool randomBoolean(); -void outputBits(unsigned char byte); +void outputBufferBits(unsigned char* buffer, int length, bool withNewLine = true); +void outputBits(unsigned char byte, bool withNewLine = true); void printVoxelCode(unsigned char* voxelCode); int numberOfOnes(unsigned char byte); bool oneAtBit(unsigned char byte, int bitIndex); @@ -70,5 +71,7 @@ bool createVoxelEditMessage(unsigned char command, short int sequence, void usleep(int waitTime); #endif +int insertIntoSortedArrays(void* value, float key, int originalIndex, + void** valueArray, float* keyArray, int* originalIndexArray, int currentCount, int maxCount); #endif /* defined(__hifi__SharedUtil__) */ From f449eafa633e3ffd34e05fb5c25831b33fba510c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 24 Apr 2013 22:53:34 -0700 Subject: [PATCH 03/76] added typedef for location enum --- libraries/voxels/src/ViewFrustum.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/voxels/src/ViewFrustum.h b/libraries/voxels/src/ViewFrustum.h index 9ebfba6e9a..d05bb9e1cf 100644 --- a/libraries/voxels/src/ViewFrustum.h +++ b/libraries/voxels/src/ViewFrustum.h @@ -92,7 +92,7 @@ public: void dump() const; - enum {OUTSIDE, INTERSECT, INSIDE}; + typedef enum {OUTSIDE, INTERSECT, INSIDE} location; int pointInFrustum(const glm::vec3& point) const; int sphereInFrustum(const glm::vec3& center, float radius) const; From 0c692ca0c0e4546211266e7811e90c2cf1629291 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 24 Apr 2013 22:54:55 -0700 Subject: [PATCH 04/76] added isLeaf(), isInView(), and distanceToCamera() helper methods --- libraries/voxels/src/VoxelNode.cpp | 29 +++++++++++++++++++++++++++++ libraries/voxels/src/VoxelNode.h | 8 ++++++++ 2 files changed, 37 insertions(+) diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 4278d8d75e..9168a722ba 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -7,6 +7,7 @@ // #include +#include #include #include "SharedUtil.h" //#include "voxels_Log.h" @@ -179,3 +180,31 @@ void VoxelNode::setRandomColor(int minimumBrightness) { newColor[3] = 1; setColor(newColor); } + +bool VoxelNode::isLeaf() const { + int childCount = 0; + for (int i = 0; i < 8; i++) { + if (NULL != children[i]) { + childCount++; + } + } + return (0 == childCount); +} + + +bool VoxelNode::isInView(const ViewFrustum& viewFrustum) const { + AABox box; + getAABox(box); + box.scale(TREE_SCALE); + bool inView = (ViewFrustum::OUTSIDE != viewFrustum.boxInFrustum(box)); + return inView; +} + +float VoxelNode::distanceToCamera(const ViewFrustum& viewFrustum) const { + AABox box; + getAABox(box); + float distanceToVoxelCenter = sqrtf(powf(viewFrustum.getPosition().x - (box.getCorner().x + box.getSize().x), 2) + + powf(viewFrustum.getPosition().y - (box.getCorner().y + box.getSize().y), 2) + + powf(viewFrustum.getPosition().z - (box.getCorner().z + box.getSize().z), 2)); + return distanceToVoxelCenter; +} diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index cf644a1fd1..406b753e96 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -10,10 +10,14 @@ #define __hifi__VoxelNode__ #include "AABox.h" +#include "ViewFrustum.h" typedef unsigned char colorPart; typedef unsigned char nodeColor[4]; +const int TREE_SCALE = 10; + + class VoxelNode { private: nodeColor _trueColor; @@ -34,6 +38,8 @@ public: VoxelNode *children[8]; bool isColored() const { return (_trueColor[3]==1); }; + bool isInView(const ViewFrustum& viewFrustum) const; + float distanceToCamera(const ViewFrustum& viewFrustum) const; #ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color void setFalseColor(colorPart red, colorPart green, colorPart blue); @@ -50,6 +56,8 @@ public: const nodeColor& getTrueColor() const { return _trueColor; }; const nodeColor& getColor() const { return _trueColor; }; #endif + + bool isLeaf() const; void getAABox(AABox& box) const; }; From 732b4879e09f962fbcdc7351864c20fcdfcf56ef Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 24 Apr 2013 23:20:20 -0700 Subject: [PATCH 05/76] added a test routine for testing insertIntoSortedArrays() --- interface/src/main.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index df77265ea9..e285b38848 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -1634,6 +1634,33 @@ int main(int argc, const char * argv[]) return EXIT_SUCCESS; } + // Quick test of sortedArrays helper + if (cmdOptionExists(argc, argv, "--testSortedArray")) { + void* values[8]; + float keys[8]; + int meta[8]; + int count = 0; + + count = insertIntoSortedArrays((void*)10, 10.0, 1, values, keys, meta, count, 8); + printf("after one insert...\n"); + for (int i=0; i Date: Wed, 24 Apr 2013 23:46:47 -0700 Subject: [PATCH 06/76] adding some temporary debugging code --- interface/src/VoxelSystem.cpp | 88 +++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index c9e6b3186f..bf75a47290 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -113,6 +113,7 @@ float VoxelSystem::getVoxelsBytesReadPerSecondAverage() { return tree->voxelsBytesReadStats.getAverageSampleValuePerSecond(); } +bool pickAorB = false; int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { @@ -121,8 +122,80 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { switch(command) { case PACKET_HEADER_VOXEL_DATA: + { + /***************** TEMPORARY CODE ********************************************************************************* + // YES! Stephen - I have intentionally placed this horrible UGLY LINE across your screen! I did it so you and I + // would make a point of removing this code when all this work is done. But in the mean time, I need it here for + // debugging purposes... When you do the code review... DO NOT tell me to remove it. :) Thank you! + // + unsigned char fakeBuffer[18] = { + 86, // V + 2,0, // octcode for root + 136, // child color bits + 0,0,255, // child 128 color + 0,255,0, // child 8 color + 0, // child tree bits - none + + // now some extra bits, what happens??? + 2,252, // octcode for root + 1, // child color bits + 255,0,0, // child 1 color + 0 // child tree bits + }; + + //printf("loading fake data! fakeBuffer \n"); + tree->readBitstreamToTree((unsigned char*)&fakeBuffer[1], sizeof(fakeBuffer)-1); + + unsigned char fakeBuffer[11] = { + 86, // V + 2,0, // octcode for root + 136, // child color bits + 0,0,255, // child 128 color + 0,255,0, // child 8 color + 0 // child tree bits - none + }; + + printf("loading fake data! fakeBuffer \n"); + tree->readBitstreamToTree((unsigned char*)&fakeBuffer[1], sizeof(fakeBuffer)-1); + + unsigned char fakeBufferA[11] = { + 86, // V + 0, // octcode for root + 0, // child color bits? + 128, // child exists bits + 0, // child color bits + 128, // child exists + 128, // child color bits + 0,0,255, // child color + 0 // child exists bits + }; + + unsigned char fakeBufferB[11] = { + 86, // V + 0, // octcode for root + 0, // child color bits? + 128, // child exists bits + 0, // child color bits + 128, // child exists + 16, // child color bits + 0,255,0, // child color?? + 0 // child exists bits + }; + + // trim off the "V" + printf("loading fake data! pickAorB=%s\n", (pickAorB ? "A" : "B") ); + if (pickAorB) { + tree->readBitstreamToTree((unsigned char*)&fakeBufferA[1], sizeof(fakeBufferA)-1); + } else { + tree->readBitstreamToTree((unsigned char*)&fakeBufferB[1], sizeof(fakeBufferB)-1); + } + pickAorB = !pickAorB; + + ***** END OF TEMPORARY CODE ***************************************************************************************/ + // ask the VoxelTree to read the bitstream into the tree tree->readBitstreamToTree(voxelData, numBytes - 1); + } break; case PACKET_HEADER_ERASE_VOXEL: // ask the tree to read the "remove" bitstream @@ -618,4 +691,19 @@ void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) { tree->recurseTreeWithOperation(falseColorizeDistanceFromViewOperation,(void*)viewFrustum); printf("setting in distance false color for %d nodes\n",_nodeCount); setupNewVoxelsForDrawing(); + + + printf("--------- DEBUG TESTING ------------\n"); + unsigned char* lastOctalCode = tree->rootNode->octalCode; + unsigned char* fullOutputBuffer = new unsigned char[MAX_VOXEL_PACKET_SIZE]; + unsigned char* outputBuffer = fullOutputBuffer; + bool startedWriting = false; + int bytesWritten = 0; + + bytesWritten = tree->bhgLoadBitstream(tree->rootNode, *viewFrustum, lastOctalCode, startedWriting, + outputBuffer,MAX_VOXEL_PACKET_SIZE); + + printf("--------- results ------------\n"); + outputBufferBits(fullOutputBuffer, bytesWritten, true); + printf("--------- DONE DEBUG TESTING ------------\n"); } From 785ef88820e5dd5101924d53e91fbfbc87b380bb Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 24 Apr 2013 23:47:38 -0700 Subject: [PATCH 07/76] Code cleanup, change readBitstreamToTree() to support multiple trees, first cut at new loadBitstream() - some small tweaks to cod to match coding standard for pointers - changed readBitstreamToTree() to handle multiple trees in a single packet - first cut at new version of loadBitstream() which is currently not in use --- libraries/voxels/src/VoxelTree.cpp | 382 ++++++++++++++++++++++++++--- libraries/voxels/src/VoxelTree.h | 21 +- 2 files changed, 362 insertions(+), 41 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index db69535e14..60031a3fc3 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -5,6 +5,48 @@ // Created by Stephen Birarda on 3/13/13. // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // +// +// +// Oct-Tree in bits, and child ordinals +// +// Location Decimal Bit Child in Array +// ------------------- ------- --- --------------- +// Bottom Right Near 128 8th 0 +// Bottom Right Far 64 7th 1 +// Top Right Near 32 6th 2 +// Top Right Far 16 5th 3 +// Bottom Left Near 8 4th 4 +// Bottom Left Far 4 3rd 5 +// Top Left Near 2 2nd 6 +// Top Left Far 1 1st 7 +// +// ^ +// +-------|------+ + Y +// / / | /| +// / 1 / | 16 / | +// /------/-------+ | +// / / | /|16| +// / 2 / 32 | / | | +// / / |/ | /| / +Z +// +--------------+ 32|/ | / +// | | | / | / +// | | | /| | / +// | 2 | 32 | / |64| / +// 4----| | |/ | |/ +// +------|------ + | / +// | | | | / +// | | |128|/ +// | 8 | 128 | / +// | | | / +// | | | / +// < - - - +------+-------+/ - - - - - - > +// +X (0,0,0) -X +// /| +// / | +// / | +// -Z / V -Y +// +// #ifdef _WIN32 #define _USE_MATH_DEFINES @@ -117,12 +159,14 @@ VoxelNode * VoxelTree::nodeForOctalCode(VoxelNode *ancestorNode, unsigned char * return ancestorNode; } -VoxelNode * VoxelTree::createMissingNode(VoxelNode *lastParentNode, unsigned char *codeToReach) { +// returns the node created! +VoxelNode* VoxelTree::createMissingNode(VoxelNode* lastParentNode, unsigned char* codeToReach) { + int indexOfNewChild = branchIndexWithDescendant(lastParentNode->octalCode, codeToReach); lastParentNode->addChildAtIndex(indexOfNewChild); - + if (*lastParentNode->children[indexOfNewChild]->octalCode == *codeToReach) { - return lastParentNode; + return lastParentNode->children[indexOfNewChild]; } else { return createMissingNode(lastParentNode->children[indexOfNewChild], codeToReach); } @@ -134,24 +178,24 @@ VoxelNode * VoxelTree::createMissingNode(VoxelNode *lastParentNode, unsigned cha int VoxelTree::readNodeData(VoxelNode *destinationNode, unsigned char * nodeData, int bytesLeftToRead) { - + // instantiate variable for bytes already read int bytesRead = 1; for (int i = 0; i < 8; i++) { // check the colors mask to see if we have a child to color in if (oneAtBit(*nodeData, i)) { - // create the child if it doesn't exist if (destinationNode->children[i] == NULL) { destinationNode->addChildAtIndex(i); this->voxelsCreated++; this->voxelsCreatedStats.updateAverage(1); } - + // pull the color for this child nodeColor newColor; memcpy(newColor, nodeData + bytesRead, 3); newColor[3] = 1; + destinationNode->children[i]->setColor(newColor); this->voxelsColored++; this->voxelsColoredStats.updateAverage(1); @@ -193,17 +237,33 @@ int VoxelTree::readNodeData(VoxelNode *destinationNode, } void VoxelTree::readBitstreamToTree(unsigned char * bitstream, int bufferSizeBytes) { - VoxelNode *bitstreamRootNode = nodeForOctalCode(rootNode, (unsigned char *)bitstream, NULL); + int bytesRead = 0; + + // Keep looping through the buffer calling readNodeData() this allows us to pack multiple root-relative Octal codes + // into a single network packet. readNodeData() basically goes down a tree from the root, and fills things in from there + // if there are more bytes after that, it's assumed to be another root relative tree - if (*bitstream != *bitstreamRootNode->octalCode) { - // if the octal code returned is not on the same level as - // the code being searched for, we have VoxelNodes to create - bitstreamRootNode = createMissingNode(bitstreamRootNode, (unsigned char *)bitstream); + while (bytesRead < bufferSizeBytes) { + VoxelNode* bitstreamRootNode = nodeForOctalCode(rootNode, (unsigned char *)bitstream, NULL); + + if (*bitstream != *bitstreamRootNode->octalCode) { + // 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(rootNode, (unsigned char *)bitstream); + } + + int octalCodeBytes = bytesRequiredForCodeLength(*bitstream); + + bytesRead += octalCodeBytes; + bytesRead += readNodeData(bitstreamRootNode, bitstream + octalCodeBytes, bufferSizeBytes - octalCodeBytes); + + // skip bitstream to new startPoint + bitstream += bytesRead; } - int octalCodeBytes = bytesRequiredForCodeLength(*bitstream); - readNodeData(bitstreamRootNode, bitstream + octalCodeBytes, bufferSizeBytes - octalCodeBytes); - this->voxelsBytesRead += bufferSizeBytes; this->voxelsBytesReadStats.updateAverage(bufferSizeBytes); } @@ -247,12 +307,11 @@ void VoxelTree::eraseAllVoxels() { } void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) { - VoxelNode *lastCreatedNode = nodeForOctalCode(rootNode, codeColorBuffer, NULL); + VoxelNode* lastCreatedNode = nodeForOctalCode(rootNode, codeColorBuffer, NULL); // create the node if it does not exist if (*lastCreatedNode->octalCode != *codeColorBuffer) { - VoxelNode *parentNode = createMissingNode(lastCreatedNode, codeColorBuffer); - lastCreatedNode = parentNode->children[branchIndexWithDescendant(parentNode->octalCode, codeColorBuffer)]; + lastCreatedNode = createMissingNode(lastCreatedNode, codeColorBuffer); } // give this node its color @@ -325,15 +384,13 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, bool voxelIsClose = (distanceToVoxelCenter < boundaryDistanceForRenderLevel(*currentVoxelNode->octalCode + 1)); bool sendVoxel = voxelIsClose && voxelInView; - //printf("VoxelTree::loadBitstreamBuffer() sendVoxel=%d, voxelIsClose=%d, voxelInView=%d, viewFrustumCulling=%d\n", - // sendVoxel, voxelIsClose, voxelInView, viewFrustumCulling); - if (sendVoxel) { // write this voxel's data if we're below or at // or at the same level as the stopOctalCode if (*currentVoxelNode->octalCode >= *stopOctalCode) { + if ((bitstreamBuffer - initialBitstreamPos) + MAX_TREE_SLICE_BYTES > MAX_VOXEL_PACKET_SIZE) { // we can't send this packet, not enough room // return our octal code as the stop @@ -359,13 +416,11 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, unsigned char *colorPointer = bitstreamBuffer + 1; for (int i = 0; i < 8; i++) { - // Rules for including a child: // 1) child must exists if ((currentVoxelNode->children[i] != NULL)) { // 2) child must have a color... if (currentVoxelNode->children[i]->isColored()) { - unsigned char* childOctalCode = currentVoxelNode->children[i]->octalCode; float childPosition[3]; @@ -384,9 +439,6 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, childBox.setBox(glm::vec3(childPosition[0], childPosition[1], childPosition[2]), fullChildVoxel, fullChildVoxel, fullChildVoxel); - //printf("VoxelTree::loadBitstreamBuffer() childBox.corner=(%f,%f,%f) x=%f \n", - // childBox.getCorner().x,childBox.getCorner().y,childBox.getCorner().z, childBox.getSize().x); - // XXXBHG - not sure we want to do this "distance/LOD culling" at this level. //bool childIsClose = (distanceToChildCenter < boundaryDistanceForRenderLevel(*childOctalCode + 1)); @@ -401,9 +453,6 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, // removed childIsClose - until we determine if we want to include that bool sendChild = (childInView) || falseColorInsteadOfCulling; - //printf("VoxelTree::loadBitstreamBuffer() childIsClose=%d, childInView=%d\n", - // childIsClose, childInView); - // if we sendAnyway, we'll do false coloring of the voxels based on childIsClose && childInView if (sendChild) { @@ -449,15 +498,13 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, ? branchIndexWithDescendant(currentVoxelNode->octalCode, stopOctalCode) : 0; } - + unsigned char * arrBufferBeforeChild = bitstreamBuffer; for (int i = firstIndexToCheck; i < 8; i ++) { - // ask the child to load this bitstream buffer // if they or their descendants fill the MTU we will receive the childStopOctalCode back if (currentVoxelNode->children[i] != NULL) { - if (!oneAtBit(currentMarkerNode->childrenVisitedMask, i)) { // create the marker node for this child if it does not yet exist @@ -488,7 +535,7 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, } } **** disabled *****************************************************************************************/ - + // ask the child to load the bitstream buffer with their data childStopOctalCode = loadBitstreamBuffer(bitstreamBuffer, currentVoxelNode->children[i], @@ -756,3 +803,274 @@ void VoxelTree::createSphere(float r,float xc, float yc, float zc, float s, bool } this->reaverageVoxelColors(this->rootNode); } + + +int VoxelTree::bhgLoadBitstream(VoxelNode* node, const ViewFrustum& viewFrustum, + unsigned char*& lastOctalCode, bool& startedWriting, + unsigned char*& outputBuffer, int availableBytes) const { + + // Some debugging code... where are we in the tree.. + AABox box; + node->getAABox(box); + printf("bhgLoadBitstream() box.corner=(%f,%f,%f) size=%f node=", + box.getCorner().x, box.getCorner().y, box.getCorner().z,box.getSize().x); + printOctalCode(node->octalCode); + + // How many bytes have we written so far at this level; + int bytesAtThisLevel = 0; + + // remember our prior writing state, because we might need to do something special with this information below + bool priorWritingState = startedWriting; + + // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! + if (!node->isInView(viewFrustum)) { + printf("bhgLoadBitstream() node NOT IN VIEW\n"); + return bytesAtThisLevel; + } + + bool keepDiggingDeeper = true; // Assuming we're in view we have a great work ethic, we're always ready for more! + + // At any given point in writing the bitstream, the largest minimum we might need to flesh out the current level + // is 1 byte for child colors + 3*8 bytes for the actual colors + 1 byte for child trees. There could be sub trees + // below this point, which might take many more bytes, but that's ok, because we can always mark our subtrees as + // not existing and stop the packet at this point, then start up with a new packet for the remaining sub trees. + const int CHILD_COLOR_MASK_BYTES = 1; + const int MAX_CHILDREN = 8; + const int BYTES_PER_COLOR = 3; + const int CHILD_TREE_EXISTS_BYTES = 1; + const int MAX_LEVEL_BYTES = CHILD_COLOR_MASK_BYTES + MAX_CHILDREN * BYTES_PER_COLOR + CHILD_TREE_EXISTS_BYTES; + + // If we haven't yet started writing we may also need to write an octcode for this level. Which we can determine + // the size of by looking at this node's octcode. + int thisLevelOctcodeSize = startedWriting ? 0 : bytesRequiredForCodeLength(*node->octalCode); + + // Some degenerate cases... If for some reason, we haven't started writing, and the available bytes left are less + // than what it would take to even write our octcode, we need to bail at this point + if (!startedWriting && (availableBytes < thisLevelOctcodeSize)) { + return bytesAtThisLevel; + } + + // Make our local buffer large enough to handle writing at this level in case we need to. + unsigned char thisLevelBuffer[thisLevelOctcodeSize+MAX_LEVEL_BYTES]; + unsigned char* writeToThisLevelBuffer = &thisLevelBuffer[0]; + + // XXXBHG - We are not yet using this. But we plan to soon... this is how we determine if we've previously sent out + // content at this level or not. In theory, if we're more shallow than where we left off, then we don't actually want + // to send data. If we're deeper than where we left off, then we want to be prepared to send data + bool sendData = compareOctalCodes(node->octalCode,lastOctalCode); + + VoxelNode* inViewChildren[MAX_CHILDREN]; + float distancesToChildren[MAX_CHILDREN]; + int positionOfChildren[MAX_CHILDREN]; + int inViewCount = 0; + int inViewNotLeafCount = 0; + int inViewWithColorCount = 0; + + unsigned char childrenExistBits = 0; + unsigned char childrenColoredBits = 0; + + // for each child node, check to see if they exist, are colored, and in view, and if so + // add them to our distance ordered array of children + for (int i = 0; i < MAX_CHILDREN; i++) { + VoxelNode* childNode = node->children[i]; + bool childExists = (childNode != NULL); + + if (childExists) { + AABox childBox; + childNode->getAABox(childBox); + printf("child[%d] childBox.corner=(%f,%f,%f) size=%f \n", i , + childBox.getCorner().x, childBox.getCorner().y, childBox.getCorner().z, childBox.getSize().x); + } + + bool childIsColored = (childExists && childNode->isColored()); + bool childIsInView = (childExists && childNode->isInView(viewFrustum)); + bool childIsLeaf = (childExists && childNode->isLeaf()); + + printf("childExists=%s childIsColored=%s childIsInView=%s childIsLeaf=%s \n", + (childExists ? "yes" : "no"), (childIsColored ? "yes" : "no"), + (childIsInView ? "yes" : "no"), (childIsLeaf ? "yes" : "no") ); + + // colored not important?? + if (childExists && childIsInView) { + + // track children in view as existing and not a leaf + if (!childIsLeaf) { + childrenExistBits += (1 << (7 - i)); + inViewNotLeafCount++; + } + + // track children with actual color + if (childIsColored) { + childrenColoredBits += (1 << (7 - i)); + inViewWithColorCount++; + } + + float distance = childNode->distanceToCamera(viewFrustum); + + printf("child[%d] distance=%f\n",i,distance); + + inViewCount = insertIntoSortedArrays((void*)childNode, distance, i, + (void**)&inViewChildren, (float*)&distancesToChildren, (int*)&positionOfChildren, + inViewCount, MAX_CHILDREN); + } + } + printf("bhgLoadBitstream() child nodes in view... inViewCount=%d\n",inViewCount); + printf("bhgLoadBitstream() child nodes in view with color... inViewWithColorCount=%d\n",inViewWithColorCount); + printf("bhgLoadBitstream() child nodes in view NOT LEAF... inViewNotLeafCount=%d\n",inViewNotLeafCount); + + // If we have children with color, then we must go ahead and start writing codes, + // we can't dig deeper before starting to write. + bool wroteOctcodeAtThisLevel = false; + if (inViewWithColorCount && !startedWriting) { + + // keep track that we've started writing + startedWriting = true; + + // write the octal code + int codeLength = bytesRequiredForCodeLength(*node->octalCode); + + printf("bhgLoadBitstream() writing my octal code\n"); + memcpy(writeToThisLevelBuffer,node->octalCode,codeLength); + + writeToThisLevelBuffer += codeLength; // move the pointer + bytesAtThisLevel += codeLength; // keep track of byte count + + // remember we wrote our octcode here + wroteOctcodeAtThisLevel = true; + } + + // Ok, no matter when we started writing (at this level, or above) if we've got children with color + // we need to write them here. + if (inViewWithColorCount && startedWriting) { + // write the child color bits + printf("bhgLoadBitstream() writing child color bits\n"); + *writeToThisLevelBuffer = childrenColoredBits; + + writeToThisLevelBuffer += sizeof(childrenColoredBits); // move the pointer + bytesAtThisLevel += sizeof(childrenColoredBits); // keep track of byte count + + // write the color data... + for (int i = 0; i < MAX_CHILDREN; i++) { + if (oneAtBit(childrenColoredBits, i)) { + printf("bhgLoadBitstream() writing color for child %d\n",i); + memcpy(writeToThisLevelBuffer,&node->children[i]->getColor(),BYTES_PER_COLOR); + writeToThisLevelBuffer += BYTES_PER_COLOR; // move the pointer for color + bytesAtThisLevel += BYTES_PER_COLOR; // keep track of byte count for color + } + } + } + + printf("startedWriting=%s inViewNotLeafCount=%d \n", (startedWriting ? "yes" : "no"), inViewNotLeafCount ); + + // If all of our IN VIEW children are LEAVES, then we're done + if (startedWriting && (0 == inViewNotLeafCount)) { + + printf("bhgLoadBitstream() writing child trees exist bits of 0\n"); + + // write the child color bits + *writeToThisLevelBuffer = childrenExistBits; + + writeToThisLevelBuffer += sizeof(childrenExistBits); // move the pointer + bytesAtThisLevel += sizeof(childrenExistBits); // keep track of byte count + + keepDiggingDeeper = false; + } + + // at this point we need to do a gut check. If we're writing, then we need to check how many bytes we've + // written at this level, and how many bytes we have available in the outputBuffer. If we can fit what we've got so far + // and room for the no more children terminator, then let's write what we got so far. + + // If we plan to keep digging deeper, we will need at least one more byte. Otherwise, we've got all the bytes we + // need to write already written in our thisLevelBuffer. If we have room for this in our outputBuffer, then copy + // it and proceed as expected. + int potentiallyMoreBytes = keepDiggingDeeper ? CHILD_TREE_EXISTS_BYTES : 0; + + printf("startedWriting=%s availableBytes=%d bytesAtThisLevel=%d keepDiggingDeeper=%s potentiallyMoreBytes=%d\n", + (startedWriting ? "yes" : "no"), availableBytes, bytesAtThisLevel, + (keepDiggingDeeper ? "yes" : "no"), potentiallyMoreBytes ); + + if (startedWriting && (availableBytes > (bytesAtThisLevel + potentiallyMoreBytes))) { + memcpy(outputBuffer,&thisLevelBuffer[0],bytesAtThisLevel); + availableBytes -= bytesAtThisLevel; + + printf("actually write our local bytes to the outputBuffer bytesAtThisLevel=%d availableBytes=%d\n", + bytesAtThisLevel, availableBytes); + } + + if (keepDiggingDeeper) { + + printf("keepDiggingDeeper == TRUE... dig deeper!\n"); + + // at this point, we need to iterate the children who are in view, even if not colored + // and we need to determine if there's a deeper tree below them that we care about. We will iterate + // these based on which tree is closer. + // + // We have potentially a couple of states here, it's possible we haven't started writing at all. In + // which case, the lower level trees may start writing. And so when we get back here, we need to check + // our writing state, if we had not been writing, and we started writing below, then we basically want + // to start a new top level tree. We do that by simply toggling our startedWriting flag, and then call + // the child node. + // + // It's also possible that we did start writing, but we have NOT yet written our childrenExistBits. This + // is because we don't really know how big the child tree will be. What we kinda would like to do is + // write our childExistsBits as a place holder. Then let each potential tree have a go at it. If they + // write something, we keep them in the bits, if they don't, we take them out. + // + unsigned char* childExistsPlaceHolder = NULL; + bool havePlaceHolderChildBits = false; + if (startedWriting) { + // write the child tree exists "placeholder" bits. + childExistsPlaceHolder = outputBuffer; + *outputBuffer = childrenExistBits; + + outputBuffer += sizeof(childrenExistBits); // move the pointer + bytesAtThisLevel += sizeof(childrenExistBits); // keep track of byte count + + havePlaceHolderChildBits = true; + } + for (int i = 0; i < inViewCount; i++) { + VoxelNode* childNode = inViewChildren[i]; + int childNodePosition = positionOfChildren[i]; + + printf("bhgLoadBitstream() calling inViewChildren[%d] startedWriting=%s\n",i, (startedWriting ? "yes" : "no") ); + + printf("about to dig deeper, priorWritingState=%s\n",(priorWritingState ? "yes" : "no")); + + int childTreeBytesOut = bhgLoadBitstream(childNode,viewFrustum,lastOctalCode,startedWriting, + outputBuffer,availableBytes); + + printf("back from dig deeper, priorWritingState=%s startedWriting=%s childTreeBytesOut=%d\n", + (priorWritingState ? "yes" : "no"), (startedWriting ? "yes" : "no"), childTreeBytesOut); + + bytesAtThisLevel += childTreeBytesOut; + + // If we had previously started writing, and if the child DIDN'T write any bytes, + // then we want to remove their bit from the childExistsPlaceHolder bitmask + if (havePlaceHolderChildBits && (0 == childTreeBytesOut)) { + + printf("bhgLoadBitstream() child %d orig %d didn't write bytes, removing from bitmask\n",i, childNodePosition ); + + // remove this child's bit... + childrenExistBits -= (1 << (7 - childNodePosition)); + + // repair the child exists mask + *childExistsPlaceHolder = childrenExistBits; + + // Note: no need to move the pointer, cause we already stored this + } + } + } + printf("bhgLoadBitstream() at bottom, returning... bytesAtThisLevel=%d\n",bytesAtThisLevel ); + + // If this was the level that we wrote our octcode at.. AND our prior state was not writing, THEN THIS + // is the level we want to switch back to not writing... + + // If before we started this tree, we WEREN'T writing, but after iterating this tree we ARE writing + // then we need to reset writing state, so we'll start a new tree when appropriate. + if (!priorWritingState && startedWriting) { + printf("bhgLoadBitstream() at bottom and returning prior writing state was FALSE, but we did write, so... we want a new tree!\n"); + startedWriting = false; + } + return bytesAtThisLevel; +} + diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 60c66925ec..462856ccfd 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -17,7 +17,6 @@ const int MAX_VOXEL_PACKET_SIZE = 1492; const int MAX_TREE_SLICE_BYTES = 26; -const int TREE_SCALE = 10; // Callback function, for recuseTreeWithOperation typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, bool down, void* extraData); @@ -48,25 +47,29 @@ public: void deleteVoxelCodeFromTree(unsigned char *codeBuffer); void printTreeForDebugging(VoxelNode *startNode); void reaverageVoxelColors(VoxelNode *startNode); - unsigned char * loadBitstreamBuffer(unsigned char *& bitstreamBuffer, - VoxelNode *currentVoxelNode, - MarkerNode *currentMarkerNode, + unsigned char * loadBitstreamBuffer(unsigned char*& bitstreamBuffer, + VoxelNode* currentVoxelNode, + MarkerNode* currentMarkerNode, const glm::vec3& agentPosition, float thisNodePosition[3], const ViewFrustum& viewFrustum, bool viewFrustumCulling, - unsigned char * octalCode = NULL); + unsigned char* octalCode = NULL); void loadVoxelsFile(const char* fileName, bool wantColorRandomizer); void createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer); void recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData=NULL); + + int bhgLoadBitstream(VoxelNode* node, const ViewFrustum& viewFrustum, + unsigned char*& lastOctalCode, bool& startedWriting, + unsigned char*& outputBuffer, int availableBytes) const; private: - void recurseNodeWithOperation(VoxelNode* node,RecurseVoxelTreeOperation operation, void* extraData); - VoxelNode * nodeForOctalCode(VoxelNode *ancestorNode, unsigned char * needleCode, VoxelNode** parentOfFoundNode); - VoxelNode * createMissingNode(VoxelNode *lastParentNode, unsigned char *deepestCodeToCreate); - int readNodeData(VoxelNode *destinationNode, unsigned char * nodeData, int bufferSizeBytes); + void recurseNodeWithOperation(VoxelNode* node, RecurseVoxelTreeOperation operation, void* extraData); + VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode); + VoxelNode* createMissingNode(VoxelNode* lastParentNode, unsigned char* deepestCodeToCreate); + int readNodeData(VoxelNode *destinationNode, unsigned char* nodeData, int bufferSizeBytes); }; int boundaryDistanceForRenderLevel(unsigned int renderLevel); From 2c48139ff390627294c09317c2acf00d2684f221 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 25 Apr 2013 00:02:51 -0700 Subject: [PATCH 08/76] some cleanup --- interface/src/VoxelSystem.cpp | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 3ba2fd0e3d..0b9d797ae8 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -547,24 +547,14 @@ bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, bool down, void* return true; } - ViewFrustum* viewFrustum = (ViewFrustum*) extraData; + const ViewFrustum* viewFrustum = (const ViewFrustum*) extraData; _nodeCount++; // only do this for truely colored voxels... if (node->isColored()) { - // first calculate the AAbox for the voxel - AABox voxelBox; - node->getAABox(voxelBox); - - voxelBox.scale(TREE_SCALE); - - printf("voxelBox corner=(%f,%f,%f) x=%f\n", - voxelBox.getCorner().x, voxelBox.getCorner().y, voxelBox.getCorner().z, - voxelBox.getSize().x); - // If the voxel is outside of the view frustum, then false color it red - if (ViewFrustum::OUTSIDE == viewFrustum->boxInFrustum(voxelBox)) { + if (!node->isInView(*viewFrustum)) { // Out of view voxels are colored RED unsigned char newR = 255; unsigned char newG = 0; @@ -573,11 +563,7 @@ bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, bool down, void* //printf("voxel OUTSIDE view - FALSE colorizing node %d TRUE color is %x,%x,%x \n", // _nodeCount,node->getTrueColor()[0],node->getTrueColor()[1],node->getTrueColor()[2]); node->setFalseColor(newR,newG,newB); - } else { - printf("voxel NOT OUTSIDE view\n"); } - } else { - printf("voxel not colored, don't consider it\n"); } return true; // keep going! From 667fe1169439a3d914bed98d926c1bed93ff49d8 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 25 Apr 2013 17:29:56 -0700 Subject: [PATCH 09/76] added VoxelNode::printDebugDetails() --- libraries/voxels/src/VoxelNode.cpp | 8 ++++++++ libraries/voxels/src/VoxelNode.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 9168a722ba..6ef82d9ea0 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -191,6 +191,14 @@ bool VoxelNode::isLeaf() const { return (0 == childCount); } +void VoxelNode::printDebugDetails(const char* label) const { + AABox box; + getAABox(box); + printf("%s - Voxel at corner=(%f,%f,%f) size=%f octcode=",label, + box.getCorner().x, box.getCorner().y, box.getCorner().z,box.getSize().x); + printOctalCode(octalCode); +} + bool VoxelNode::isInView(const ViewFrustum& viewFrustum) const { AABox box; diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 406b753e96..a8c0a1e00b 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -60,6 +60,8 @@ public: bool isLeaf() const; void getAABox(AABox& box) const; + + void printDebugDetails(const char* label) const; }; #endif /* defined(__hifi__VoxelNode__) */ From 3c7c85a98c19e67b5cc9917aa915be775ceed399 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 25 Apr 2013 17:31:32 -0700 Subject: [PATCH 10/76] Added second cut at new bitstream writers - added encodeTreeBitstream() which is new version of bitstream encoder that handles only encoding nodes that are in view. Also handles detecting packet overflow with new technique - added encodeTreeBitstreamRecursion() which is the private work horse function - moved temporary code to searchAndEncodeMultiTreeBitstream() which is still not ready for prime time --- libraries/voxels/src/VoxelTree.cpp | 325 ++++++++++++++++++++++++++++- libraries/voxels/src/VoxelTree.h | 14 +- 2 files changed, 327 insertions(+), 12 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 60031a3fc3..45369a1d87 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -804,18 +804,17 @@ void VoxelTree::createSphere(float r,float xc, float yc, float zc, float s, bool this->reaverageVoxelColors(this->rootNode); } - -int VoxelTree::bhgLoadBitstream(VoxelNode* node, const ViewFrustum& viewFrustum, +// This will encode a larger tree into multiple subtree bitstreams. Given a node it will search for deeper subtrees that +// have color. It will search for sub trees, and upon finding a subTree, it will call encodeTreeBitstream() to encode that +// tree. Once the subtree is encoded, it will keep searching for additional subtrees. +int VoxelTree::searchAndEncodeMultiTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrustum, unsigned char*& lastOctalCode, bool& startedWriting, unsigned char*& outputBuffer, int availableBytes) const { - // Some debugging code... where are we in the tree.. - AABox box; - node->getAABox(box); - printf("bhgLoadBitstream() box.corner=(%f,%f,%f) size=%f node=", - box.getCorner().x, box.getCorner().y, box.getCorner().z,box.getSize().x); - printOctalCode(node->octalCode); + // Some debugging code... where are we in the tree.. + node->printDebugDetails("encodeTreeBitstream() node="); + // How many bytes have we written so far at this level; int bytesAtThisLevel = 0; @@ -1036,7 +1035,7 @@ int VoxelTree::bhgLoadBitstream(VoxelNode* node, const ViewFrustum& viewFrustum, printf("about to dig deeper, priorWritingState=%s\n",(priorWritingState ? "yes" : "no")); - int childTreeBytesOut = bhgLoadBitstream(childNode,viewFrustum,lastOctalCode,startedWriting, + int childTreeBytesOut = searchAndEncodeMultiTreeBitstream(childNode,viewFrustum,lastOctalCode,startedWriting, outputBuffer,availableBytes); printf("back from dig deeper, priorWritingState=%s startedWriting=%s childTreeBytesOut=%d\n", @@ -1060,6 +1059,15 @@ int VoxelTree::bhgLoadBitstream(VoxelNode* node, const ViewFrustum& viewFrustum, } } } + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// THIS IS NOT WORKING!!!! +// +// Second trees are basically blowing up like crazy... not even sure what is going on... +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + printf("bhgLoadBitstream() at bottom, returning... bytesAtThisLevel=%d\n",bytesAtThisLevel ); // If this was the level that we wrote our octcode at.. AND our prior state was not writing, THEN THIS @@ -1072,5 +1080,304 @@ int VoxelTree::bhgLoadBitstream(VoxelNode* node, const ViewFrustum& viewFrustum, startedWriting = false; } return bytesAtThisLevel; + + +} + +// This will encode a tree bitstream, given a node it will encode the full tree from that point onward. +// It will ignore any branches that are not in view. But other than that, it will not (can not) do any +// prioritization of branches or deeper searching of the branches for optimization. +// +// NOTE: This STUB function DOES add the octcode to the buffer, then it calls the recursive helper to +// actually encode the tree +// +// extraTrees is assumed to me an allocated array of VoxelNode*, if we're unable to fully encode the tree +// because we run out of room on the outputBuffer, then we will add VoxelNode*'s of the trees that need +// to be encoded to that array. If the array +int VoxelTree::encodeTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrustum, + unsigned char* outputBuffer, int availableBytes, + VoxelNode**& extraTrees, int& sizeExtraTrees, int& countExtraTrees) const { + + // Some debugging code... where are we in the tree.. + node->printDebugDetails("encodeTreeBitstream() node="); + + // How many bytes have we written so far at this level; + int bytesWritten = 0; + + // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! + if (!node->isInView(viewFrustum)) { + printf("encodeTreeBitstream() node NOT IN VIEW\n"); + return bytesWritten; + } + + // write the octal code + int codeLength = bytesRequiredForCodeLength(*node->octalCode); + memcpy(outputBuffer,node->octalCode,codeLength); + + outputBuffer += codeLength; // move the pointer + bytesWritten += codeLength; // keep track of byte count + availableBytes -= codeLength; // keep track or remaining space + + int childBytesWritten = encodeTreeBitstreamRecursion(node, viewFrustum, + outputBuffer, availableBytes, extraTrees, sizeExtraTrees, countExtraTrees); + + // if childBytesWritten == 1 then something went wrong... that's not possible + assert(childBytesWritten != 1); + + // if childBytesWritten == 2, then it can only mean that the lower level trees don't exist or for some reason + // couldn't be written... so reset them here... + if (childBytesWritten == 2) { + childBytesWritten = 0; + } + + // if we wrote child bytes, then return our result of all bytes written + if (childBytesWritten) { + bytesWritten += childBytesWritten; + } else { + // otherwise... if we didn't write any child bytes, then pretend like we also didn't write our octal code + printf("encodeTreeBitstreamRecursion() no bytes below...\n"); + bytesWritten = 0; + } + + return bytesWritten; +} + +// This will encode a tree bitstream, given a node it will encode the full tree from that point onward. +// It will ignore any branches that are not in view. But other than that, it will not (can not) do any +// prioritization of branches or deeper searching of the branches for optimization. +// +// NOTE: This recursive function DOES NOT add the octcode to the buffer. It's assumed that the caller has +// already done that. +int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& viewFrustum, + unsigned char* outputBuffer, int availableBytes, + VoxelNode**& extraTrees, int& sizeExtraTrees, int& countExtraTrees) const { + + // Some debugging code... where are we in the tree.. + node->printDebugDetails("encodeTreeBitstreamRecursion() node="); + + // How many bytes have we written so far at this level; + int bytesAtThisLevel = 0; + + // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! + // although technically, we really shouldn't ever be here, because our callers shouldn't be calling us if + // we're out of view + if (!node->isInView(viewFrustum)) { + printf("encodeTreeBitstreamRecursion() node NOT IN VIEW\n"); + return bytesAtThisLevel; + } + + bool keepDiggingDeeper = true; // Assuming we're in view we have a great work ethic, we're always ready for more! + + // At any given point in writing the bitstream, the largest minimum we might need to flesh out the current level + // is 1 byte for child colors + 3*8 bytes for the actual colors + 1 byte for child trees. There could be sub trees + // below this point, which might take many more bytes, but that's ok, because we can always mark our subtrees as + // not existing and stop the packet at this point, then start up with a new packet for the remaining sub trees. + const int CHILD_COLOR_MASK_BYTES = 1; + const int MAX_CHILDREN = 8; + const int BYTES_PER_COLOR = 3; + const int CHILD_TREE_EXISTS_BYTES = 1; + const int MAX_LEVEL_BYTES = CHILD_COLOR_MASK_BYTES + MAX_CHILDREN * BYTES_PER_COLOR + CHILD_TREE_EXISTS_BYTES; + + // Make our local buffer large enough to handle writing at this level in case we need to. + unsigned char thisLevelBuffer[MAX_LEVEL_BYTES]; + unsigned char* writeToThisLevelBuffer = &thisLevelBuffer[0]; + + unsigned char childrenExistBits = 0; + unsigned char childrenColoredBits = 0; + int inViewCount = 0; + int inViewNotLeafCount = 0; + int inViewWithColorCount = 0; + + // for each child node, check to see if they exist, are colored, and in view, and if so + // add them to our distance ordered array of children + for (int i = 0; i < MAX_CHILDREN; i++) { + VoxelNode* childNode = node->children[i]; + bool childExists = (childNode != NULL); + + if (childExists) { + childNode->printDebugDetails("encodeTreeBitstream() looping children"); + } + + bool childIsColored = (childExists && childNode->isColored()); + bool childIsInView = (childExists && childNode->isInView(viewFrustum)); + bool childIsLeaf = (childExists && childNode->isLeaf()); + + printf("childExists=%s childIsColored=%s childIsInView=%s childIsLeaf=%s \n", + (childExists ? "yes" : "no"), (childIsColored ? "yes" : "no"), + (childIsInView ? "yes" : "no"), (childIsLeaf ? "yes" : "no") ); + + if (childIsInView) { + inViewCount++; + + // track children in view as existing and not a leaf, if they're a leaf, + // we don't care about recursing deeper on them, and we don't consider their + // subtree to exist + if (!childIsLeaf) { + childrenExistBits += (1 << (7 - i)); + inViewNotLeafCount++; + } + + // track children with actual color + if (childIsColored) { + childrenColoredBits += (1 << (7 - i)); + inViewWithColorCount++; + } + } + } + printf("bhgLoadBitstream() child nodes in view... inViewCount=%d\n",inViewCount); + printf("bhgLoadBitstream() child nodes in view with color... inViewWithColorCount=%d\n",inViewWithColorCount); + printf("bhgLoadBitstream() child nodes in view NOT LEAF... inViewNotLeafCount=%d\n",inViewNotLeafCount); + + // write the child color bits + printf("bhgLoadBitstream() writing child color bits="); + outputBits(childrenColoredBits); + + *writeToThisLevelBuffer = childrenColoredBits; + + writeToThisLevelBuffer += sizeof(childrenColoredBits); // move the pointer + bytesAtThisLevel += sizeof(childrenColoredBits); // keep track of byte count + + // write the color data... + for (int i = 0; i < MAX_CHILDREN; i++) { + if (oneAtBit(childrenColoredBits, i)) { + printf("bhgLoadBitstream() writing color for child %d\n",i); + memcpy(writeToThisLevelBuffer,&node->children[i]->getColor(),BYTES_PER_COLOR); + writeToThisLevelBuffer += BYTES_PER_COLOR; // move the pointer for color + bytesAtThisLevel += BYTES_PER_COLOR; // keep track of byte count for color + } + } + + printf("inViewNotLeafCount=%d \n", inViewNotLeafCount ); + + printf("bhgLoadBitstream() writing child trees exist bits="); + outputBits(childrenExistBits); + + // write the child exist bits + *writeToThisLevelBuffer = childrenExistBits; + + writeToThisLevelBuffer += sizeof(childrenExistBits); // move the pointer + bytesAtThisLevel += sizeof(childrenExistBits); // keep track of byte count + + // We only need to keep digging, if there is at least one child that is inView, and not a leaf. + keepDiggingDeeper = (inViewNotLeafCount > 0); + + // at this point we need to do a gut check. If we're writing, then we need to check how many bytes we've + // written at this level, and how many bytes we have available in the outputBuffer. If we can fit what we've got so far + // and room for the no more children terminator, then let's write what we got so far. + + printf("availableBytes=%d bytesAtThisLevel=%d keepDiggingDeeper=%s \n", + availableBytes, bytesAtThisLevel, (keepDiggingDeeper ? "yes" : "no") ); + + // If we have enough room to copy our local results into the buffer, then do so... + if (availableBytes >= bytesAtThisLevel) { + memcpy(outputBuffer,&thisLevelBuffer[0],bytesAtThisLevel); + + outputBuffer += bytesAtThisLevel; + availableBytes -= bytesAtThisLevel; + + printf("actually write our local bytes to the outputBuffer bytesAtThisLevel=%d availableBytes=%d\n", + bytesAtThisLevel, availableBytes); + } else { + // we've run out of room!!! What do we do!!! + printf("we don't have room to write bytes bytesAtThisLevel=%d availableBytes=%d\n",bytesAtThisLevel, availableBytes); + + // 1) return 0 for bytes written so upper levels do the right thing, namely prune us from their trees + // 2) add our node to the list of extra nodes for later output... + // Note: we don't do any termination for this level, we just return 0, then the upper level is in charge + // of handling things. For example, in case of child iteration, it needs to unset the child exist bit for + // this child. + + // add our node the the list of extra nodes to output later... + + // If we have room on our extra tree list, then add ourselves to the end. + if (countExtraTrees < sizeExtraTrees) { + extraTrees[countExtraTrees] = node; + countExtraTrees++; + } else { + // do we want to expand the extraTrees array here, or do we bail??? + } + + return 0; + } + + if (keepDiggingDeeper) { + + printf("keepDiggingDeeper == TRUE... dig deeper!\n"); + + // at this point, we need to iterate the children who are in view, even if not colored + // and we need to determine if there's a deeper tree below them that we care about. + // + // Since this recursive function assumes we're already writing, we know we've already written our + // childrenExistBits. But... we don't really know how big the child tree will be. And we don't know if + // we'll have room in our buffer to actually write all these child trees. What we kinda would like to do is + // write our childExistsBits as a place holder. Then let each potential tree have a go at it. If they + // 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 outputBuffer was our childrenExistBits. Let's remember where that was! + unsigned char* childExistsPlaceHolder = outputBuffer-sizeof(childrenExistBits); + + for (int i = 0; i < MAX_CHILDREN; i++) { + + if (oneAtBit(childrenExistBits, i)) { + VoxelNode* childNode = node->children[i]; + + printf("about to dig deeper child[%d] outputBuffer=%p, availableBytes=%d\n",i,outputBuffer,availableBytes); + + int childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, viewFrustum, + outputBuffer, availableBytes, extraTrees, sizeExtraTrees, countExtraTrees); + + // if the child wrote 0 bytes, it means that nothing below exists or was in view, or we ran out of space, + // basically, the children below don't contain any info. + + // if the child tree wrote 1 byte??? something must have gone wrong... because it must have at least the color + // byte and the child exist byte. + // + assert(childTreeBytesOut != 1); + + // if the child tree wrote just 2 bytes, then it means: it had no colors and no child nodes, because... + // if it had colors it would write 1 byte for the color mask, + // and at least a color's worth of bytes for the node of colors. + // if it had child trees (with something in them) then it would have the 1 byte for child mask + // and some number of bytes of lower children... + // so, if the child returns 2 bytes out, we can actually consider that an empty tree also!! + // + // we can make this act like no bytes out, by just resetting the bytes out in this case + if (2 == childTreeBytesOut) { + printf("after to dig deeper child[%d] childTreeBytesOut was 2, we're resetting to 0\n",i); + childTreeBytesOut = 0; // this is the degenerate case of a tree with no colors and no child trees + } + + bytesAtThisLevel += childTreeBytesOut; + availableBytes -= childTreeBytesOut; + outputBuffer += childTreeBytesOut; + + printf("after dig deeper child[%d] childTreeBytesOut=%d outputBuffer=%p, availableBytes=%d\n", + i,childTreeBytesOut, outputBuffer, availableBytes); + + // If we had previously started writing, and if the child DIDN'T write any bytes, + // then we want to remove their bit from the childExistsPlaceHolder bitmask + if (0 == childTreeBytesOut) { + + printf("bhgLoadBitstream() child %d didn't write bytes, removing from bitmask\n",i ); + + // remove this child's bit... + childrenExistBits -= (1 << (7 - i)); + + // repair the child exists mask + *childExistsPlaceHolder = childrenExistBits; + + // Note: no need to move the pointer, cause we already stored this + + } // end if (0 == childTreeBytesOut) + + } // end if (oneAtBit(childrenExistBits, i)) + } // end for + + } // end keepDiggingDeeper + + + printf("bhgLoadBitstream() at bottom, returning... bytesAtThisLevel=%d\n",bytesAtThisLevel ); + + return bytesAtThisLevel; } diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 462856ccfd..3b6ea57256 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -61,11 +61,19 @@ public: void recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData=NULL); - int bhgLoadBitstream(VoxelNode* node, const ViewFrustum& viewFrustum, - unsigned char*& lastOctalCode, bool& startedWriting, - unsigned char*& outputBuffer, int availableBytes) const; + int encodeTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrustum, + unsigned char* outputBuffer, int availableBytes, + VoxelNode**& extraTrees, int& sizeExtraTrees, int& countExtraTrees) const; + + int searchAndEncodeMultiTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrustum, + unsigned char*& lastOctalCode, bool& startedWriting, + unsigned char*& outputBuffer, int availableBytes) const; private: + int encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& viewFrustum, + unsigned char* outputBuffer, int availableBytes, + VoxelNode**& extraTrees, int& sizeExtraTrees, int& countExtraTrees) const; + void recurseNodeWithOperation(VoxelNode* node, RecurseVoxelTreeOperation operation, void* extraData); VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode); VoxelNode* createMissingNode(VoxelNode* lastParentNode, unsigned char* deepestCodeToCreate); From 32da105d622d056a38dfa9779fd17e82956d1a53 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 25 Apr 2013 17:33:43 -0700 Subject: [PATCH 11/76] new testing/debug code for encodeTreeBitstream() --- interface/src/VoxelSystem.cpp | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 0b9d797ae8..d57ae0bc66 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -706,15 +706,39 @@ void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) { printf("--------- DEBUG TESTING ------------\n"); unsigned char* lastOctalCode = tree->rootNode->octalCode; + const int MAX_VOXEL_PACKET_SIZE=13; // nothing should fit... unsigned char* fullOutputBuffer = new unsigned char[MAX_VOXEL_PACKET_SIZE]; unsigned char* outputBuffer = fullOutputBuffer; bool startedWriting = false; int bytesWritten = 0; + + const int LIKELY_EXTRA_TREES = 10; + int sizeExtraTrees = LIKELY_EXTRA_TREES; + int countExtraTrees = 0; + VoxelNode** extraTrees = new VoxelNode*[sizeExtraTrees]; - bytesWritten = tree->bhgLoadBitstream(tree->rootNode, *viewFrustum, lastOctalCode, startedWriting, - outputBuffer,MAX_VOXEL_PACKET_SIZE); + bytesWritten = tree->encodeTreeBitstream(tree->rootNode, *viewFrustum, + outputBuffer, MAX_VOXEL_PACKET_SIZE, extraTrees, sizeExtraTrees, countExtraTrees); - printf("--------- results ------------\n"); + printf("--------- initial results ------------\n"); outputBufferBits(fullOutputBuffer, bytesWritten, true); + printf("--------- DONE initial results ------------\n"); + + printf("--------- extra trees ------------\n"); + printf("countExtraTrees=%d\n",countExtraTrees); + + for(int i=0; i < countExtraTrees; i++) { + printf("processing extraTree[%d] countExtraTrees=%d\n", i, countExtraTrees); + VoxelNode* extraTree = extraTrees[i]; + bytesWritten = tree->encodeTreeBitstream(extraTree, *viewFrustum, + outputBuffer, MAX_VOXEL_PACKET_SIZE, extraTrees, sizeExtraTrees, countExtraTrees); + printf("--------- extra results ------------\n"); + outputBufferBits(fullOutputBuffer, bytesWritten, true); + printf("--------- DONE extra results ------------\n"); + + } + + + printf("--------- DONE DEBUG TESTING ------------\n"); } From c014abbe6cf227f29d536fd6e9e6a7e8e5067155 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 25 Apr 2013 23:41:07 -0700 Subject: [PATCH 12/76] new VoxelNodeBag class which is used to store a collection of voxel node pointers --- libraries/voxels/src/VoxelNodeBag.cpp | 93 +++++++++++++++++++++++++++ libraries/voxels/src/VoxelNodeBag.h | 42 ++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 libraries/voxels/src/VoxelNodeBag.cpp create mode 100644 libraries/voxels/src/VoxelNodeBag.h diff --git a/libraries/voxels/src/VoxelNodeBag.cpp b/libraries/voxels/src/VoxelNodeBag.cpp new file mode 100644 index 0000000000..d9e27d5500 --- /dev/null +++ b/libraries/voxels/src/VoxelNodeBag.cpp @@ -0,0 +1,93 @@ +// +// VoxelNodeBag.cpp +// hifi +// +// Created by Brad Hefta-Gaub on 4/25/2013 +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// +// This class is used by the VoxelTree:encodeTreeBitstream() functions to store extra nodes that need to be sent +// it's a generic bag style storage mechanism. But It has the property that you can't put the same node into the bag +// more than once (in other words, it de-dupes automatically), also, it supports collapsing it's several peer nodes +// into a parent node in cases where you add enough peers that it makes more sense to just add the parent. +// + +#include "VoxelNodeBag.h" +#include + +VoxelNodeBag::~VoxelNodeBag() { + if (_bagElements) { + delete[] _bagElements; + } +} + +const int GROW_BAG_BY = 500; + +// put a node into the bag +void VoxelNodeBag::insert(VoxelNode* node) { + +printf("VoxelNodeBag::insert(node) node="); +node->printDebugDetails(""); + + // Search for where we should live in the bag (sorted) + // Note: change this to binary search... instead of linear! + int insertAt = _elementsInUse; + for (int i = 0; i < _elementsInUse; i++) { + + // compare the newNode to the elements already in the bag + OctalTreeDepth comparison = compareOctalCodes(_bagElements[i]->octalCode,node->octalCode); + + // If we found a code in the bag that matches, then just return, since the element is already in the bag. + if (comparison == EXACT_MATCH) { + return; // exit early!! + } + + // if we found a node "greater than" the inserted node, then + // we want to insert our node here. + if (comparison == GREATER_THAN) { + insertAt = i; + break; + } + } + // at this point, inserAt will be the location we want to insert at. + + // If we don't have room in our bag, then grow the bag + if (_sizeOfElementsArray < _elementsInUse+1) { + VoxelNode** oldBag = _bagElements; + _bagElements = new VoxelNode*[_sizeOfElementsArray + GROW_BAG_BY]; + _sizeOfElementsArray += GROW_BAG_BY; + + // If we had an old bag... + if (oldBag) { + // copy old elements into the new bag, but leave a space where we need to + // insert the new node + memcpy(_bagElements, oldBag, insertAt); + memcpy(&_bagElements[insertAt+1], &oldBag[insertAt], (_elementsInUse-insertAt)); + } + } else { + // move existing elements further back in the bag array, leave a space where we need to + // insert the new node + memcpy(&_bagElements[insertAt+1], &_bagElements[insertAt], (_elementsInUse-insertAt)); + } + _bagElements[insertAt] = node; + _elementsInUse++; +} + +// pull a node out of the bag (could come in any order) +VoxelNode* VoxelNodeBag::extract() { + // pull the last node out, and shrink our list... + if (_elementsInUse) { + + // get the last element + VoxelNode* node = _bagElements[_elementsInUse-1]; + + // reduce the count + _elementsInUse--; + + // debug!! + printf("VoxelNodeBag::extract() node="); + node->printDebugDetails(""); + + return node; + } + return NULL; +} diff --git a/libraries/voxels/src/VoxelNodeBag.h b/libraries/voxels/src/VoxelNodeBag.h new file mode 100644 index 0000000000..4d1f3efb19 --- /dev/null +++ b/libraries/voxels/src/VoxelNodeBag.h @@ -0,0 +1,42 @@ +// +// VoxelNodeBag.h +// hifi +// +// Created by Brad Hefta-Gaub on 4/25/2013 +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// +// This class is used by the VoxelTree:encodeTreeBitstream() functions to store extra nodes that need to be sent +// it's a generic bag style storage mechanism. But It has the property that you can't put the same node into the bag +// more than once (in other words, it de-dupes automatically), also, it supports collapsing it's several peer nodes +// into a parent node in cases where you add enough peers that it makes more sense to just add the parent. +// + +#ifndef __hifi__VoxelNodeBag__ +#define __hifi__VoxelNodeBag__ + +#include "VoxelNode.h" + +class VoxelNodeBag { + +public: + VoxelNodeBag() : + _bagElements(NULL), + _elementsInUse(0), + _sizeOfElementsArray(0) {}; + + ~VoxelNodeBag(); + + void insert(VoxelNode* node); // put a node into the bag + VoxelNode* extract(); // pull a node out of the bag (could come in any order) + + bool isEmpty() const { return (_elementsInUse > 0); } + int count() const { return _elementsInUse; } + +private: + + VoxelNode** _bagElements; + int _elementsInUse; + int _sizeOfElementsArray; +}; + +#endif /* defined(__hifi__VoxelNodeBag__) */ From 3f158c075395819f56b2dfc84cfb70eb20a577bc Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 25 Apr 2013 23:42:35 -0700 Subject: [PATCH 13/76] Added new version of compareOctalCodes() which actually compares octal codes --- libraries/shared/src/OctalCode.cpp | 38 +++++++++++++++++++++++++++++- libraries/shared/src/OctalCode.h | 4 +++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index 2e9fadb0f6..62768569f1 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -7,6 +7,7 @@ // #include +#include // std:min #include #include "SharedUtil.h" #include "OctalCode.h" @@ -134,7 +135,7 @@ float * firstVertexForCode(unsigned char * octalCode) { return firstVertex; } -OctalTreeDepth compareOctalCodes(unsigned char* codeA, unsigned char* codeB) { +OctalTreeDepth compareOctalCodesDepth(unsigned char* codeA, unsigned char* codeB) { if (!codeA || !codeB) { return ILLEGAL_CODE; } @@ -156,3 +157,38 @@ OctalTreeDepth compareOctalCodes(unsigned char* codeA, unsigned char* codeB) { return result; } +OctalTreeDepth compareOctalCodes(unsigned char* codeA, unsigned char* codeB) { + if (!codeA || !codeB) { + return ILLEGAL_CODE; + } + + OctalTreeDepth result = LESS_THAN; // assume it's shallower + + int numberOfBytes = std::min(bytesRequiredForCodeLength(*codeA),bytesRequiredForCodeLength(*codeB)); + int compare = memcmp(codeA,codeB,numberOfBytes); + + if (compare < 0) { + result = LESS_THAN; + } else if (compare > 0) { + result = GREATER_THAN; + } else { + int codeLenthA = numberOfThreeBitSectionsInCode(codeA); + int codeLenthB = numberOfThreeBitSectionsInCode(codeB); + + if (codeLenthA == codeLenthB) { + // if the memcmp matched exactly, and they were the same length, + // then these must be the same code! + result = EXACT_MATCH; + } else { + // if the memcmp matched exactly, but they aren't the same length, + // then they have a matching common parent, but they aren't the same + if (codeLenthA < codeLenthB) { + result = LESS_THAN; + } else { + result = GREATER_THAN; + } + } + } + return result; +} + diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index 65c2fcca91..be939f2495 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -28,7 +28,9 @@ typedef enum { EQUAL_DEPTH, EXACT_MATCH, DEEPER, - ILLEGAL_CODE + ILLEGAL_CODE, + GREATER_THAN, + LESS_THAN } OctalTreeDepth; OctalTreeDepth compareOctalCodes(unsigned char* code1, unsigned char* code2); From d6e27d8f2ff3a8927adcc85557fbe004a40e2a7b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 25 Apr 2013 23:45:34 -0700 Subject: [PATCH 14/76] thread safety in VoxelTree (aded mutex to prevent reads and adds/deletes at same time) also added VoxelNodeBag class to handle running out of room in the encode tree functions --- libraries/voxels/src/VoxelTree.cpp | 298 ++++++++++++++++++----------- libraries/voxels/src/VoxelTree.h | 9 +- 2 files changed, 191 insertions(+), 116 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 45369a1d87..95241a8211 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -59,11 +59,49 @@ #include "PacketHeaders.h" #include "OctalCode.h" #include "VoxelTree.h" +#include "VoxelNodeBag.h" #include "ViewFrustum.h" #include // to load voxels from file +#include +#include + using voxels_lib::printLog; + +void debugThreadError(const char* message, int err) { + switch (err) { + case EINVAL: + printf("%s -> EINVAL\n",message); + break; + + case EBUSY: + printf("%s -> EBUSY\n",message); + break; + + case EAGAIN: + printf("%s -> EAGAIN\n",message); + break; + + case EDEADLK: + printf("%s -> EDEADLK\n",message); + break; + + case EPERM: + printf("%s -> EPERM\n",message); + break; + + case EINTR: + printf("%s -> EINTR\n",message); + break; + + default: + printf("%s -> %d\n",message,err); + break; + } + +} + int boundaryDistanceForRenderLevel(unsigned int renderLevel) { switch (renderLevel) { case 1: @@ -99,20 +137,30 @@ VoxelTree::VoxelTree() : rootNode = new VoxelNode(); rootNode->octalCode = new unsigned char[1]; *rootNode->octalCode = 0; + + //pthread_mutexattr_t mta; + //pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE); + int res = pthread_mutex_init(&_treeNodeDelete, NULL); + debugThreadError("pthread_mutex_init(&_treeNodeDelete, &mta);", res); } VoxelTree::~VoxelTree() { + pthread_mutex_lock(&_treeNodeDelete); // delete the children of the root node // this recursively deletes the tree for (int i = 0; i < 8; i++) { delete rootNode->children[i]; } + pthread_mutex_unlock(&_treeNodeDelete); + pthread_mutex_destroy(&_treeNodeDelete); } // Recurses voxel tree calling the RecurseVoxelTreeOperation function for each node. // stops recursion if operation function returns false. void VoxelTree::recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData) { + pthread_mutex_lock(&_treeNodeDelete); recurseNodeWithOperation(rootNode, operation,extraData); + pthread_mutex_unlock(&_treeNodeDelete); } // Recurses voxel node with an operation function @@ -237,12 +285,17 @@ int VoxelTree::readNodeData(VoxelNode *destinationNode, } void VoxelTree::readBitstreamToTree(unsigned char * bitstream, int bufferSizeBytes) { + + int mutexLock; + mutexLock = pthread_mutex_lock(&_treeNodeDelete); + debugThreadError("pthread_mutex_lock(&_treeNodeDelete)", mutexLock); + int bytesRead = 0; // Keep looping through the buffer calling readNodeData() this allows us to pack multiple root-relative Octal codes // into a single network packet. readNodeData() basically goes down a tree from the root, and fills things in from there // if there are more bytes after that, it's assumed to be another root relative tree - + while (bytesRead < bufferSizeBytes) { VoxelNode* bitstreamRootNode = nodeForOctalCode(rootNode, (unsigned char *)bitstream, NULL); @@ -254,7 +307,7 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, int bufferSizeByt // octal code is always relative to root! bitstreamRootNode = createMissingNode(rootNode, (unsigned char *)bitstream); } - + int octalCodeBytes = bytesRequiredForCodeLength(*bitstream); bytesRead += octalCodeBytes; @@ -263,9 +316,11 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, int bufferSizeByt // skip bitstream to new startPoint bitstream += bytesRead; } - + this->voxelsBytesRead += bufferSizeBytes; - this->voxelsBytesReadStats.updateAverage(bufferSizeBytes); + this->voxelsBytesReadStats.updateAverage(bufferSizeBytes); + + pthread_mutex_unlock(&_treeNodeDelete); } // Note: uses the codeColorBuffer format, but the color's are ignored, because @@ -288,8 +343,10 @@ void VoxelTree::deleteVoxelCodeFromTree(unsigned char *codeBuffer) { int childNDX = branchIndexWithDescendant(parentNode->octalCode, codeBuffer); - delete parentNode->children[childNDX]; // delete the child nodes - parentNode->children[childNDX]=NULL; // set it to NULL + pthread_mutex_lock(&_treeNodeDelete); + delete parentNode->children[childNDX]; // delete the child nodes + parentNode->children[childNDX]=NULL; // set it to NULL + pthread_mutex_unlock(&_treeNodeDelete); reaverageVoxelColors(rootNode); // Fix our colors!! Need to call it on rootNode } @@ -300,20 +357,23 @@ void VoxelTree::eraseAllVoxels() { // XXXBHG Hack attack - is there a better way to erase the voxel tree? - delete rootNode; // this will recurse and delete all children - rootNode = new VoxelNode(); - rootNode->octalCode = new unsigned char[1]; - *rootNode->octalCode = 0; + pthread_mutex_lock(&_treeNodeDelete); + delete rootNode; // this will recurse and delete all children + rootNode = new VoxelNode(); + rootNode->octalCode = new unsigned char[1]; + *rootNode->octalCode = 0; + pthread_mutex_unlock(&_treeNodeDelete); } void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) { + pthread_mutex_lock(&_treeNodeDelete); VoxelNode* lastCreatedNode = nodeForOctalCode(rootNode, codeColorBuffer, NULL); - + // create the node if it does not exist if (*lastCreatedNode->octalCode != *codeColorBuffer) { lastCreatedNode = createMissingNode(lastCreatedNode, codeColorBuffer); } - + // give this node its color int octalCodeBytes = bytesRequiredForCodeLength(*codeColorBuffer); @@ -321,6 +381,7 @@ void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) { memcpy(newColor, codeColorBuffer + octalCodeBytes, 3); newColor[3] = 1; lastCreatedNode->setColor(newColor); + pthread_mutex_unlock(&_treeNodeDelete); } unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, @@ -332,29 +393,30 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, bool viewFrustumCulling, unsigned char * stopOctalCode) { - static unsigned char *initialBitstreamPos = bitstreamBuffer; - unsigned char * childStopOctalCode = NULL; - + // could we make this tighter? + pthread_mutex_lock(&_treeNodeDelete); + static unsigned char *initialBitstreamPos = bitstreamBuffer; + if (stopOctalCode == NULL) { stopOctalCode = rootNode->octalCode; } - + // check if we have any children bool hasAtLeastOneChild; - + for (int i = 0; i < 8; i++) { if (currentVoxelNode->children[i] != NULL) { hasAtLeastOneChild = true; } } - + // if we have at least one child, check if it will be worth recursing into our children if (hasAtLeastOneChild) { - + int firstIndexToCheck = 0; unsigned char * childMaskPointer = NULL; - + float halfUnitForVoxel = powf(0.5, *currentVoxelNode->octalCode) * (0.5 * TREE_SCALE); float distanceToVoxelCenter = sqrtf(powf(agentPosition[0] - thisNodePosition[0] - halfUnitForVoxel, 2) + powf(agentPosition[1] - thisNodePosition[1] - halfUnitForVoxel, 2) + @@ -362,59 +424,60 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, // If the voxel is outside of the view frustum, then don't bother sending or recursing bool voxelInView = true; - + /**** not yet working properly at this level! ************************************************************************** if (viewFrustumCulling) { float fullUnitForVoxel = halfUnitForVoxel * 2.0f; AABox voxelBox; voxelBox.setBox(glm::vec3(thisNodePosition[0],thisNodePosition[1],thisNodePosition[2]), fullUnitForVoxel,fullUnitForVoxel,fullUnitForVoxel); - + //printf("VoxelTree::loadBitstreamBuffer() voxelBox.corner=(%f,%f,%f) x=%f \n", // voxelBox.getCorner().x,voxelBox.getCorner().y,voxelBox.getCorner().z, voxelBox.getSize().x); - + voxelInView = (ViewFrustum::OUTSIDE != viewFrustum.pointInFrustum(voxelBox.getCorner())); } else { voxelInView = true; } **********************************************************************************************************************/ - + // if the distance to this voxel's center is less than the threshold // distance for its children, we should send the children bool voxelIsClose = (distanceToVoxelCenter < boundaryDistanceForRenderLevel(*currentVoxelNode->octalCode + 1)); bool sendVoxel = voxelIsClose && voxelInView; if (sendVoxel) { - + // write this voxel's data if we're below or at // or at the same level as the stopOctalCode - + if (*currentVoxelNode->octalCode >= *stopOctalCode) { if ((bitstreamBuffer - initialBitstreamPos) + MAX_TREE_SLICE_BYTES > MAX_VOXEL_PACKET_SIZE) { // we can't send this packet, not enough room // return our octal code as the stop + pthread_mutex_unlock(&_treeNodeDelete); return currentVoxelNode->octalCode; } - + if (strcmp((char *)stopOctalCode, (char *)currentVoxelNode->octalCode) == 0) { // this is is the root node for this packet // add the leading V *(bitstreamBuffer++) = PACKET_HEADER_VOXEL_DATA; - + // add its octal code to the packet int octalCodeBytes = bytesRequiredForCodeLength(*currentVoxelNode->octalCode); - + memcpy(bitstreamBuffer, currentVoxelNode->octalCode, octalCodeBytes); bitstreamBuffer += octalCodeBytes; } - + // default color mask is 0, increment pointer for colors *bitstreamBuffer = 0; - + // keep a colorPointer so we can check how many colors were added unsigned char *colorPointer = bitstreamBuffer + 1; - + for (int i = 0; i < 8; i++) { // Rules for including a child: // 1) child must exists @@ -428,7 +491,7 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, childPosition[0] *= TREE_SCALE; // scale it up childPosition[1] *= TREE_SCALE; // scale it up childPosition[2] *= TREE_SCALE; // scale it up - + float halfChildVoxel = powf(0.5, *childOctalCode) * (0.5 * TREE_SCALE); float distanceToChildCenter = sqrtf(powf(agentPosition[0] - childPosition[0] - halfChildVoxel, 2) + powf(agentPosition[1] - childPosition[1] - halfChildVoxel, 2) + @@ -438,10 +501,10 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, AABox childBox; childBox.setBox(glm::vec3(childPosition[0], childPosition[1], childPosition[2]), fullChildVoxel, fullChildVoxel, fullChildVoxel); - + // XXXBHG - not sure we want to do this "distance/LOD culling" at this level. //bool childIsClose = (distanceToChildCenter < boundaryDistanceForRenderLevel(*childOctalCode + 1)); - + bool childIsClose = true; // for now, assume we're close enough bool childInView = !viewFrustumCulling || (ViewFrustum::OUTSIDE != viewFrustum.boxInFrustum(childBox)); @@ -449,13 +512,13 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, /// XXXBHG - debug code, switch this to true, and we'll send everything but include false coloring // on voxels based on whether or not they match these rules. bool falseColorInsteadOfCulling = false; - + // removed childIsClose - until we determine if we want to include that bool sendChild = (childInView) || falseColorInsteadOfCulling; - + // if we sendAnyway, we'll do false coloring of the voxels based on childIsClose && childInView if (sendChild) { - + // copy in the childs color to bitstreamBuffer if (childIsClose && childInView) { // true color @@ -476,21 +539,21 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, } } colorPointer += 3; - + // set the colorMask by bitshifting the value of childExists *bitstreamBuffer += (1 << (7 - i)); } } } } - + // push the bitstreamBuffer forwards for the number of added colors bitstreamBuffer += (colorPointer - bitstreamBuffer); - + // maintain a pointer to this spot in the buffer so we can set our child mask // depending on the results of the recursion below childMaskPointer = bitstreamBuffer++; - + // reset the childMaskPointer for this node to 0 *childMaskPointer = 0; } else { @@ -500,24 +563,24 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, } unsigned char * arrBufferBeforeChild = bitstreamBuffer; - + for (int i = firstIndexToCheck; i < 8; i ++) { // ask the child to load this bitstream buffer // if they or their descendants fill the MTU we will receive the childStopOctalCode back if (currentVoxelNode->children[i] != NULL) { if (!oneAtBit(currentMarkerNode->childrenVisitedMask, i)) { - + // create the marker node for this child if it does not yet exist if (currentMarkerNode->children[i] == NULL) { currentMarkerNode->children[i] = new MarkerNode(); } - + float childNodePosition[3]; copyFirstVertexForCode(currentVoxelNode->children[i]->octalCode,(float*)&childNodePosition); childNodePosition[0] *= TREE_SCALE; // scale it up childNodePosition[1] *= TREE_SCALE; // scale it up childNodePosition[2] *= TREE_SCALE; // scale it up - + /**** disabled ***************************************************************************************** // Note: Stephen, I intentionally left this in so you would talk to me about it. Here's the deal, this // code doesn't seem to work correctly. It returns X and Z flipped and the values are negative. Since @@ -527,7 +590,7 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, // calculate the child's position based on the parent position for (int j = 0; j < 3; j++) { childNodePosition[j] = thisNodePosition[j]; - + if (oneAtBit(branchIndexWithDescendant(currentVoxelNode->octalCode, currentVoxelNode->children[i]->octalCode), (7 - j))) { @@ -545,25 +608,25 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, viewFrustum, viewFrustumCulling, stopOctalCode); - + if (bitstreamBuffer - arrBufferBeforeChild > 0) { // this child added data to the packet - add it to our child mask if (childMaskPointer != NULL) { *childMaskPointer += (1 << (7 - i)); } - + arrBufferBeforeChild = bitstreamBuffer; } } } - + if (childStopOctalCode != NULL) { break; } else { // this child node has been covered // add the appropriate bit to the childrenVisitedMask for the current marker node currentMarkerNode->childrenVisitedMask += 1 << (7 - i); - + // if we are above the stopOctal and we got a NULL code // we cannot go to the next child // so break and return the NULL stop code @@ -574,11 +637,14 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, } } } - + pthread_mutex_unlock(&_treeNodeDelete); return childStopOctalCode; } void VoxelTree::processRemoveVoxelBitstream(unsigned char * bitstream, int bufferSizeBytes) { + // do we need to lock out tree mutex + //if (0 == pthread_mutex_lock(&_treeNodeDelete)) + // XXXBHG: validate buffer is at least 4 bytes long? other guards?? unsigned short int itemNumber = (*((unsigned short int*)&bitstream[1])); printLog("processRemoveVoxelBitstream() receivedBytes=%d itemNumber=%d\n",bufferSizeBytes,itemNumber); @@ -600,17 +666,19 @@ void VoxelTree::processRemoveVoxelBitstream(unsigned char * bitstream, int buffe } void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { + // could we make this tighter? + pthread_mutex_lock(&_treeNodeDelete); int colorMask = 0; - + // create the color mask for (int i = 0; i < 8; i++) { if (startNode->children[i] != NULL && startNode->children[i]->isColored()) { colorMask += (1 << (7 - i)); } } - + outputBits(colorMask); - + // output the colors we have for (int j = 0; j < 8; j++) { if (startNode->children[j] != NULL && startNode->children[j]->isColored()) { @@ -619,17 +687,17 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { } } } - + unsigned char childMask = 0; - + for (int k = 0; k < 8; k++) { if (startNode->children[k] != NULL) { childMask += (1 << (7 - k)); } } - + outputBits(childMask); - + if (childMask > 0) { // ask children to recursively output their trees // if they aren't a leaf @@ -639,26 +707,29 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { } } } + pthread_mutex_unlock(&_treeNodeDelete); } void VoxelTree::reaverageVoxelColors(VoxelNode *startNode) { + // could we make this tighter? + pthread_mutex_lock(&_treeNodeDelete); bool hasChildren = false; - + for (int i = 0; i < 8; i++) { if (startNode->children[i] != NULL) { reaverageVoxelColors(startNode->children[i]); hasChildren = true; } } - + if (hasChildren) { - bool childrenCollapsed = startNode->collapseIdenticalLeaves(); - - if (!childrenCollapsed) { - startNode->setColorFromAverageOfChildren(); - } - } + bool childrenCollapsed = startNode->collapseIdenticalLeaves(); + if (!childrenCollapsed) { + startNode->setColorFromAverageOfChildren(); + } + } + pthread_mutex_unlock(&_treeNodeDelete); } ////////////////////////////////////////////////////////////////////////////////////////// // Method: VoxelTree::loadVoxelsFile() @@ -712,7 +783,10 @@ void VoxelTree::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) { voxelData[lengthInBytes+1], voxelData[lengthInBytes+2], voxelData[lengthInBytes+3]); //printVoxelCode(voxelData); + pthread_mutex_lock(&_treeNodeDelete); this->readCodeColorBufferToTree(voxelData); + pthread_mutex_unlock(&_treeNodeDelete); + delete voxelData; } file.close(); @@ -1096,17 +1170,21 @@ int VoxelTree::searchAndEncodeMultiTreeBitstream(VoxelNode* node, const ViewFrus // to be encoded to that array. If the array int VoxelTree::encodeTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrustum, unsigned char* outputBuffer, int availableBytes, - VoxelNode**& extraTrees, int& sizeExtraTrees, int& countExtraTrees) const { - - // Some debugging code... where are we in the tree.. - node->printDebugDetails("encodeTreeBitstream() node="); + VoxelNodeBag& bag) { // How many bytes have we written so far at this level; int bytesWritten = 0; + // could we make this tighter? + pthread_mutex_lock(&_treeNodeDelete); + + // Some debugging code... where are we in the tree.. + //node->printDebugDetails("encodeTreeBitstream() node="); + // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! if (!node->isInView(viewFrustum)) { - printf("encodeTreeBitstream() node NOT IN VIEW\n"); + //printf("encodeTreeBitstream() node NOT IN VIEW\n"); + pthread_mutex_unlock(&_treeNodeDelete); return bytesWritten; } @@ -1119,26 +1197,26 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrust availableBytes -= codeLength; // keep track or remaining space int childBytesWritten = encodeTreeBitstreamRecursion(node, viewFrustum, - outputBuffer, availableBytes, extraTrees, sizeExtraTrees, countExtraTrees); - + outputBuffer, availableBytes, bag); + // if childBytesWritten == 1 then something went wrong... that's not possible assert(childBytesWritten != 1); - + // if childBytesWritten == 2, then it can only mean that the lower level trees don't exist or for some reason // couldn't be written... so reset them here... if (childBytesWritten == 2) { childBytesWritten = 0; } - + // if we wrote child bytes, then return our result of all bytes written if (childBytesWritten) { bytesWritten += childBytesWritten; } else { // otherwise... if we didn't write any child bytes, then pretend like we also didn't write our octal code - printf("encodeTreeBitstreamRecursion() no bytes below...\n"); + //printf("encodeTreeBitstreamRecursion() no bytes below...\n"); bytesWritten = 0; } - + pthread_mutex_unlock(&_treeNodeDelete); return bytesWritten; } @@ -1150,10 +1228,10 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrust // already done that. int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& viewFrustum, unsigned char* outputBuffer, int availableBytes, - VoxelNode**& extraTrees, int& sizeExtraTrees, int& countExtraTrees) const { + VoxelNodeBag& bag) const { // Some debugging code... where are we in the tree.. - node->printDebugDetails("encodeTreeBitstreamRecursion() node="); + //node->printDebugDetails("encodeTreeBitstreamRecursion() node="); // How many bytes have we written so far at this level; int bytesAtThisLevel = 0; @@ -1162,7 +1240,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& // although technically, we really shouldn't ever be here, because our callers shouldn't be calling us if // we're out of view if (!node->isInView(viewFrustum)) { - printf("encodeTreeBitstreamRecursion() node NOT IN VIEW\n"); + //printf("encodeTreeBitstreamRecursion() node NOT IN VIEW\n"); return bytesAtThisLevel; } @@ -1195,16 +1273,16 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& bool childExists = (childNode != NULL); if (childExists) { - childNode->printDebugDetails("encodeTreeBitstream() looping children"); + //childNode->printDebugDetails("encodeTreeBitstream() looping children"); } bool childIsColored = (childExists && childNode->isColored()); bool childIsInView = (childExists && childNode->isInView(viewFrustum)); bool childIsLeaf = (childExists && childNode->isLeaf()); - printf("childExists=%s childIsColored=%s childIsInView=%s childIsLeaf=%s \n", - (childExists ? "yes" : "no"), (childIsColored ? "yes" : "no"), - (childIsInView ? "yes" : "no"), (childIsLeaf ? "yes" : "no") ); + //printf("childExists=%s childIsColored=%s childIsInView=%s childIsLeaf=%s \n", + // (childExists ? "yes" : "no"), (childIsColored ? "yes" : "no"), + // (childIsInView ? "yes" : "no"), (childIsLeaf ? "yes" : "no") ); if (childIsInView) { inViewCount++; @@ -1224,13 +1302,13 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& } } } - printf("bhgLoadBitstream() child nodes in view... inViewCount=%d\n",inViewCount); - printf("bhgLoadBitstream() child nodes in view with color... inViewWithColorCount=%d\n",inViewWithColorCount); - printf("bhgLoadBitstream() child nodes in view NOT LEAF... inViewNotLeafCount=%d\n",inViewNotLeafCount); + //printf("bhgLoadBitstream() child nodes in view... inViewCount=%d\n",inViewCount); + //printf("bhgLoadBitstream() child nodes in view with color... inViewWithColorCount=%d\n",inViewWithColorCount); + //printf("bhgLoadBitstream() child nodes in view NOT LEAF... inViewNotLeafCount=%d\n",inViewNotLeafCount); // write the child color bits - printf("bhgLoadBitstream() writing child color bits="); - outputBits(childrenColoredBits); + //printf("bhgLoadBitstream() writing child color bits="); + //outputBits(childrenColoredBits); *writeToThisLevelBuffer = childrenColoredBits; @@ -1240,17 +1318,17 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& // write the color data... for (int i = 0; i < MAX_CHILDREN; i++) { if (oneAtBit(childrenColoredBits, i)) { - printf("bhgLoadBitstream() writing color for child %d\n",i); + //printf("bhgLoadBitstream() writing color for child %d\n",i); memcpy(writeToThisLevelBuffer,&node->children[i]->getColor(),BYTES_PER_COLOR); writeToThisLevelBuffer += BYTES_PER_COLOR; // move the pointer for color bytesAtThisLevel += BYTES_PER_COLOR; // keep track of byte count for color } } - printf("inViewNotLeafCount=%d \n", inViewNotLeafCount ); + //printf("inViewNotLeafCount=%d \n", inViewNotLeafCount ); - printf("bhgLoadBitstream() writing child trees exist bits="); - outputBits(childrenExistBits); + //printf("bhgLoadBitstream() writing child trees exist bits="); + //outputBits(childrenExistBits); // write the child exist bits *writeToThisLevelBuffer = childrenExistBits; @@ -1265,8 +1343,8 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& // written at this level, and how many bytes we have available in the outputBuffer. If we can fit what we've got so far // and room for the no more children terminator, then let's write what we got so far. - printf("availableBytes=%d bytesAtThisLevel=%d keepDiggingDeeper=%s \n", - availableBytes, bytesAtThisLevel, (keepDiggingDeeper ? "yes" : "no") ); + //printf("availableBytes=%d bytesAtThisLevel=%d keepDiggingDeeper=%s \n", + // availableBytes, bytesAtThisLevel, (keepDiggingDeeper ? "yes" : "no") ); // If we have enough room to copy our local results into the buffer, then do so... if (availableBytes >= bytesAtThisLevel) { @@ -1275,8 +1353,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& outputBuffer += bytesAtThisLevel; availableBytes -= bytesAtThisLevel; - printf("actually write our local bytes to the outputBuffer bytesAtThisLevel=%d availableBytes=%d\n", - bytesAtThisLevel, availableBytes); + //printf("actually write our local bytes to the outputBuffer bytesAtThisLevel=%d availableBytes=%d\n",bytesAtThisLevel, availableBytes); } else { // we've run out of room!!! What do we do!!! printf("we don't have room to write bytes bytesAtThisLevel=%d availableBytes=%d\n",bytesAtThisLevel, availableBytes); @@ -1289,20 +1366,14 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& // add our node the the list of extra nodes to output later... - // If we have room on our extra tree list, then add ourselves to the end. - if (countExtraTrees < sizeExtraTrees) { - extraTrees[countExtraTrees] = node; - countExtraTrees++; - } else { - // do we want to expand the extraTrees array here, or do we bail??? - } + bag.insert(node); return 0; } if (keepDiggingDeeper) { - printf("keepDiggingDeeper == TRUE... dig deeper!\n"); + //printf("keepDiggingDeeper == TRUE... dig deeper!\n"); // at this point, we need to iterate the children who are in view, even if not colored // and we need to determine if there's a deeper tree below them that we care about. @@ -1321,10 +1392,9 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& if (oneAtBit(childrenExistBits, i)) { VoxelNode* childNode = node->children[i]; - printf("about to dig deeper child[%d] outputBuffer=%p, availableBytes=%d\n",i,outputBuffer,availableBytes); + //printf("about to dig deeper child[%d] outputBuffer=%p, availableBytes=%d\n",i,outputBuffer,availableBytes); - int childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, viewFrustum, - outputBuffer, availableBytes, extraTrees, sizeExtraTrees, countExtraTrees); + int childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, viewFrustum, outputBuffer, availableBytes, bag); // if the child wrote 0 bytes, it means that nothing below exists or was in view, or we ran out of space, // basically, the children below don't contain any info. @@ -1343,7 +1413,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& // // we can make this act like no bytes out, by just resetting the bytes out in this case if (2 == childTreeBytesOut) { - printf("after to dig deeper child[%d] childTreeBytesOut was 2, we're resetting to 0\n",i); + //printf("after to dig deeper child[%d] childTreeBytesOut was 2, we're resetting to 0\n",i); childTreeBytesOut = 0; // this is the degenerate case of a tree with no colors and no child trees } @@ -1351,14 +1421,14 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& availableBytes -= childTreeBytesOut; outputBuffer += childTreeBytesOut; - printf("after dig deeper child[%d] childTreeBytesOut=%d outputBuffer=%p, availableBytes=%d\n", - i,childTreeBytesOut, outputBuffer, availableBytes); + //printf("after dig deeper child[%d] childTreeBytesOut=%d outputBuffer=%p, availableBytes=%d\n", + // i,childTreeBytesOut, outputBuffer, availableBytes); // If we had previously started writing, and if the child DIDN'T write any bytes, // then we want to remove their bit from the childExistsPlaceHolder bitmask if (0 == childTreeBytesOut) { - printf("bhgLoadBitstream() child %d didn't write bytes, removing from bitmask\n",i ); + //printf("bhgLoadBitstream() child %d didn't write bytes, removing from bitmask\n",i ); // remove this child's bit... childrenExistBits -= (1 << (7 - i)); @@ -1376,7 +1446,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& } // end keepDiggingDeeper - printf("bhgLoadBitstream() at bottom, returning... bytesAtThisLevel=%d\n",bytesAtThisLevel ); + //printf("bhgLoadBitstream() at bottom, returning... bytesAtThisLevel=%d\n",bytesAtThisLevel ); return bytesAtThisLevel; } diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 3b6ea57256..c797b92218 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -9,10 +9,13 @@ #ifndef __hifi__VoxelTree__ #define __hifi__VoxelTree__ +#include + #include "SimpleMovingAverage.h" #include "ViewFrustum.h" #include "VoxelNode.h" +#include "VoxelNodeBag.h" #include "MarkerNode.h" const int MAX_VOXEL_PACKET_SIZE = 1492; @@ -63,7 +66,7 @@ public: int encodeTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrustum, unsigned char* outputBuffer, int availableBytes, - VoxelNode**& extraTrees, int& sizeExtraTrees, int& countExtraTrees) const; + VoxelNodeBag& bag); int searchAndEncodeMultiTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrustum, unsigned char*& lastOctalCode, bool& startedWriting, @@ -72,12 +75,14 @@ public: private: int encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& viewFrustum, unsigned char* outputBuffer, int availableBytes, - VoxelNode**& extraTrees, int& sizeExtraTrees, int& countExtraTrees) const; + VoxelNodeBag& bag) const; void recurseNodeWithOperation(VoxelNode* node, RecurseVoxelTreeOperation operation, void* extraData); VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode); VoxelNode* createMissingNode(VoxelNode* lastParentNode, unsigned char* deepestCodeToCreate); int readNodeData(VoxelNode *destinationNode, unsigned char* nodeData, int bufferSizeBytes); + + pthread_mutex_t _treeNodeDelete; }; int boundaryDistanceForRenderLevel(unsigned int renderLevel); From a17675337904c359faa7d56b4f1ba40ef0ce445d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 25 Apr 2013 23:47:12 -0700 Subject: [PATCH 15/76] added VoxelNodeBag --- interface/src/VoxelSystem.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index d57ae0bc66..fbb2056c67 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -706,33 +706,33 @@ void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) { printf("--------- DEBUG TESTING ------------\n"); unsigned char* lastOctalCode = tree->rootNode->octalCode; - const int MAX_VOXEL_PACKET_SIZE=13; // nothing should fit... + //const int MAX_VOXEL_PACKET_SIZE=13; // test tight fit... unsigned char* fullOutputBuffer = new unsigned char[MAX_VOXEL_PACKET_SIZE]; unsigned char* outputBuffer = fullOutputBuffer; bool startedWriting = false; int bytesWritten = 0; - const int LIKELY_EXTRA_TREES = 10; - int sizeExtraTrees = LIKELY_EXTRA_TREES; - int countExtraTrees = 0; - VoxelNode** extraTrees = new VoxelNode*[sizeExtraTrees]; + VoxelNodeBag bagOfTrees; - bytesWritten = tree->encodeTreeBitstream(tree->rootNode, *viewFrustum, - outputBuffer, MAX_VOXEL_PACKET_SIZE, extraTrees, sizeExtraTrees, countExtraTrees); + bytesWritten = tree->encodeTreeBitstream(tree->rootNode, *viewFrustum, outputBuffer, MAX_VOXEL_PACKET_SIZE, bagOfTrees); - printf("--------- initial results ------------\n"); + printf("--------- initial results ---- bytesWritten=%d ------------\n",bytesWritten); outputBufferBits(fullOutputBuffer, bytesWritten, true); printf("--------- DONE initial results ------------\n"); printf("--------- extra trees ------------\n"); - printf("countExtraTrees=%d\n",countExtraTrees); + printf("bagOfTrees.count()=%d\n",bagOfTrees.count()); - for(int i=0; i < countExtraTrees; i++) { - printf("processing extraTree[%d] countExtraTrees=%d\n", i, countExtraTrees); - VoxelNode* extraTree = extraTrees[i]; - bytesWritten = tree->encodeTreeBitstream(extraTree, *viewFrustum, - outputBuffer, MAX_VOXEL_PACKET_SIZE, extraTrees, sizeExtraTrees, countExtraTrees); - printf("--------- extra results ------------\n"); + int countOfExtra = 0; + while (!bagOfTrees.isEmpty()) { + countOfExtra++; + VoxelNode* extraTree = bagOfTrees.extract(); + printf("processing countOfExtra=%d\n", countOfExtra); + + bytesWritten = tree->encodeTreeBitstream(extraTree, *viewFrustum, outputBuffer, MAX_VOXEL_PACKET_SIZE, bagOfTrees); + + + printf("--------- extra results ---- bytesWritten=%d ------------\n",bytesWritten); outputBufferBits(fullOutputBuffer, bytesWritten, true); printf("--------- DONE extra results ------------\n"); From 2ba24e17162587eeae9f9ca35e012ad0b466dc62 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 26 Apr 2013 00:46:29 -0700 Subject: [PATCH 16/76] fixed a couple bugs in VoxelNodeBag --- libraries/voxels/src/VoxelNodeBag.cpp | 11 ++++------- libraries/voxels/src/VoxelNodeBag.h | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/libraries/voxels/src/VoxelNodeBag.cpp b/libraries/voxels/src/VoxelNodeBag.cpp index d9e27d5500..3c001177d7 100644 --- a/libraries/voxels/src/VoxelNodeBag.cpp +++ b/libraries/voxels/src/VoxelNodeBag.cpp @@ -25,14 +25,11 @@ const int GROW_BAG_BY = 500; // put a node into the bag void VoxelNodeBag::insert(VoxelNode* node) { -printf("VoxelNodeBag::insert(node) node="); -node->printDebugDetails(""); - // Search for where we should live in the bag (sorted) // Note: change this to binary search... instead of linear! int insertAt = _elementsInUse; for (int i = 0; i < _elementsInUse; i++) { - + // compare the newNode to the elements already in the bag OctalTreeDepth comparison = compareOctalCodes(_bagElements[i]->octalCode,node->octalCode); @@ -60,13 +57,13 @@ node->printDebugDetails(""); if (oldBag) { // copy old elements into the new bag, but leave a space where we need to // insert the new node - memcpy(_bagElements, oldBag, insertAt); - memcpy(&_bagElements[insertAt+1], &oldBag[insertAt], (_elementsInUse-insertAt)); + memcpy(_bagElements, oldBag, insertAt*sizeof(VoxelNode*)); + memcpy(&_bagElements[insertAt+1], &oldBag[insertAt], (_elementsInUse-insertAt)*sizeof(VoxelNode*)); } } else { // move existing elements further back in the bag array, leave a space where we need to // insert the new node - memcpy(&_bagElements[insertAt+1], &_bagElements[insertAt], (_elementsInUse-insertAt)); + memmove(&_bagElements[insertAt+1], &_bagElements[insertAt], (_elementsInUse-insertAt)*sizeof(VoxelNode*)); } _bagElements[insertAt] = node; _elementsInUse++; diff --git a/libraries/voxels/src/VoxelNodeBag.h b/libraries/voxels/src/VoxelNodeBag.h index 4d1f3efb19..75943eb6b2 100644 --- a/libraries/voxels/src/VoxelNodeBag.h +++ b/libraries/voxels/src/VoxelNodeBag.h @@ -29,7 +29,7 @@ public: void insert(VoxelNode* node); // put a node into the bag VoxelNode* extract(); // pull a node out of the bag (could come in any order) - bool isEmpty() const { return (_elementsInUse > 0); } + bool isEmpty() const { return (_elementsInUse == 0); } int count() const { return _elementsInUse; } private: From 99c0cbc7cd1e14fa93f5d3d4c30dec1523ba8ecc Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 26 Apr 2013 00:47:14 -0700 Subject: [PATCH 17/76] removed some debug code --- libraries/voxels/src/VoxelTree.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 95241a8211..8af3d437eb 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -141,7 +141,7 @@ VoxelTree::VoxelTree() : //pthread_mutexattr_t mta; //pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE); int res = pthread_mutex_init(&_treeNodeDelete, NULL); - debugThreadError("pthread_mutex_init(&_treeNodeDelete, &mta);", res); + //debugThreadError("pthread_mutex_init(&_treeNodeDelete, &mta);", res); } VoxelTree::~VoxelTree() { @@ -288,7 +288,7 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, int bufferSizeByt int mutexLock; mutexLock = pthread_mutex_lock(&_treeNodeDelete); - debugThreadError("pthread_mutex_lock(&_treeNodeDelete)", mutexLock); + //debugThreadError("pthread_mutex_lock(&_treeNodeDelete)", mutexLock); int bytesRead = 0; @@ -1356,7 +1356,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& //printf("actually write our local bytes to the outputBuffer bytesAtThisLevel=%d availableBytes=%d\n",bytesAtThisLevel, availableBytes); } else { // we've run out of room!!! What do we do!!! - printf("we don't have room to write bytes bytesAtThisLevel=%d availableBytes=%d\n",bytesAtThisLevel, availableBytes); + //printf("we don't have room to write bytes bytesAtThisLevel=%d availableBytes=%d\n",bytesAtThisLevel, availableBytes); // 1) return 0 for bytes written so upper levels do the right thing, namely prune us from their trees // 2) add our node to the list of extra nodes for later output... From 0dfa5d573a757356f6c31c6a68ac40943d136816 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 26 Apr 2013 09:22:26 -0700 Subject: [PATCH 18/76] removed debug code --- libraries/voxels/src/VoxelNodeBag.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/voxels/src/VoxelNodeBag.cpp b/libraries/voxels/src/VoxelNodeBag.cpp index 3c001177d7..232d43ee57 100644 --- a/libraries/voxels/src/VoxelNodeBag.cpp +++ b/libraries/voxels/src/VoxelNodeBag.cpp @@ -81,8 +81,8 @@ VoxelNode* VoxelNodeBag::extract() { _elementsInUse--; // debug!! - printf("VoxelNodeBag::extract() node="); - node->printDebugDetails(""); + //printf("VoxelNodeBag::extract() node="); + //node->printDebugDetails(""); return node; } From e1defb8681e5d4ebb66c553eb135cfbcec8db6f9 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 26 Apr 2013 09:23:10 -0700 Subject: [PATCH 19/76] added searchForColoredNodes() --- libraries/voxels/src/VoxelTree.cpp | 246 +++-------------------------- libraries/voxels/src/VoxelTree.h | 8 +- 2 files changed, 28 insertions(+), 226 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 8af3d437eb..d49134079c 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -879,59 +879,26 @@ void VoxelTree::createSphere(float r,float xc, float yc, float zc, float s, bool } // This will encode a larger tree into multiple subtree bitstreams. Given a node it will search for deeper subtrees that -// have color. It will search for sub trees, and upon finding a subTree, it will call encodeTreeBitstream() to encode that -// tree. Once the subtree is encoded, it will keep searching for additional subtrees. -int VoxelTree::searchAndEncodeMultiTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrustum, - unsigned char*& lastOctalCode, bool& startedWriting, - unsigned char*& outputBuffer, int availableBytes) const { +// have color. It will search for sub trees, and upon finding a subTree, it will stick the node in the bag to for later +// endcoding. +void VoxelTree::searchForColoredNodes(VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag) { + + // call the recursive version, this will add all found colored node roots to the bag + searchForColoredNodesRecursion(rootNode, viewFrustum, bag); +} - // Some debugging code... where are we in the tree.. - node->printDebugDetails("encodeTreeBitstream() node="); - - // How many bytes have we written so far at this level; - int bytesAtThisLevel = 0; - // remember our prior writing state, because we might need to do something special with this information below - bool priorWritingState = startedWriting; +void VoxelTree::searchForColoredNodesRecursion(VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag) { // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! if (!node->isInView(viewFrustum)) { - printf("bhgLoadBitstream() node NOT IN VIEW\n"); - return bytesAtThisLevel; + return; } bool keepDiggingDeeper = true; // Assuming we're in view we have a great work ethic, we're always ready for more! - // At any given point in writing the bitstream, the largest minimum we might need to flesh out the current level - // is 1 byte for child colors + 3*8 bytes for the actual colors + 1 byte for child trees. There could be sub trees - // below this point, which might take many more bytes, but that's ok, because we can always mark our subtrees as - // not existing and stop the packet at this point, then start up with a new packet for the remaining sub trees. - const int CHILD_COLOR_MASK_BYTES = 1; - const int MAX_CHILDREN = 8; - const int BYTES_PER_COLOR = 3; - const int CHILD_TREE_EXISTS_BYTES = 1; - const int MAX_LEVEL_BYTES = CHILD_COLOR_MASK_BYTES + MAX_CHILDREN * BYTES_PER_COLOR + CHILD_TREE_EXISTS_BYTES; - - // If we haven't yet started writing we may also need to write an octcode for this level. Which we can determine - // the size of by looking at this node's octcode. - int thisLevelOctcodeSize = startedWriting ? 0 : bytesRequiredForCodeLength(*node->octalCode); - - // Some degenerate cases... If for some reason, we haven't started writing, and the available bytes left are less - // than what it would take to even write our octcode, we need to bail at this point - if (!startedWriting && (availableBytes < thisLevelOctcodeSize)) { - return bytesAtThisLevel; - } - - // Make our local buffer large enough to handle writing at this level in case we need to. - unsigned char thisLevelBuffer[thisLevelOctcodeSize+MAX_LEVEL_BYTES]; - unsigned char* writeToThisLevelBuffer = &thisLevelBuffer[0]; - - // XXXBHG - We are not yet using this. But we plan to soon... this is how we determine if we've previously sent out - // content at this level or not. In theory, if we're more shallow than where we left off, then we don't actually want - // to send data. If we're deeper than where we left off, then we want to be prepared to send data - bool sendData = compareOctalCodes(node->octalCode,lastOctalCode); - + const int MAX_CHILDREN = 8; VoxelNode* inViewChildren[MAX_CHILDREN]; float distancesToChildren[MAX_CHILDREN]; int positionOfChildren[MAX_CHILDREN]; @@ -939,223 +906,58 @@ int VoxelTree::searchAndEncodeMultiTreeBitstream(VoxelNode* node, const ViewFrus int inViewNotLeafCount = 0; int inViewWithColorCount = 0; - unsigned char childrenExistBits = 0; - unsigned char childrenColoredBits = 0; - // for each child node, check to see if they exist, are colored, and in view, and if so // add them to our distance ordered array of children for (int i = 0; i < MAX_CHILDREN; i++) { VoxelNode* childNode = node->children[i]; bool childExists = (childNode != NULL); - - if (childExists) { - AABox childBox; - childNode->getAABox(childBox); - printf("child[%d] childBox.corner=(%f,%f,%f) size=%f \n", i , - childBox.getCorner().x, childBox.getCorner().y, childBox.getCorner().z, childBox.getSize().x); - } - bool childIsColored = (childExists && childNode->isColored()); bool childIsInView = (childExists && childNode->isInView(viewFrustum)); bool childIsLeaf = (childExists && childNode->isLeaf()); - printf("childExists=%s childIsColored=%s childIsInView=%s childIsLeaf=%s \n", - (childExists ? "yes" : "no"), (childIsColored ? "yes" : "no"), - (childIsInView ? "yes" : "no"), (childIsLeaf ? "yes" : "no") ); + //printf("childExists=%s childIsColored=%s childIsInView=%s childIsLeaf=%s \n", + // (childExists ? "yes" : "no"), (childIsColored ? "yes" : "no"), + // (childIsInView ? "yes" : "no"), (childIsLeaf ? "yes" : "no") ); - // colored not important?? - if (childExists && childIsInView) { + if (childIsInView) { // track children in view as existing and not a leaf if (!childIsLeaf) { - childrenExistBits += (1 << (7 - i)); inViewNotLeafCount++; } // track children with actual color if (childIsColored) { - childrenColoredBits += (1 << (7 - i)); inViewWithColorCount++; } float distance = childNode->distanceToCamera(viewFrustum); - printf("child[%d] distance=%f\n",i,distance); + //printf("child[%d] distance=%f\n",i,distance); inViewCount = insertIntoSortedArrays((void*)childNode, distance, i, (void**)&inViewChildren, (float*)&distancesToChildren, (int*)&positionOfChildren, inViewCount, MAX_CHILDREN); } } - printf("bhgLoadBitstream() child nodes in view... inViewCount=%d\n",inViewCount); - printf("bhgLoadBitstream() child nodes in view with color... inViewWithColorCount=%d\n",inViewWithColorCount); - printf("bhgLoadBitstream() child nodes in view NOT LEAF... inViewNotLeafCount=%d\n",inViewNotLeafCount); - - // If we have children with color, then we must go ahead and start writing codes, - // we can't dig deeper before starting to write. - bool wroteOctcodeAtThisLevel = false; - if (inViewWithColorCount && !startedWriting) { - - // keep track that we've started writing - startedWriting = true; - - // write the octal code - int codeLength = bytesRequiredForCodeLength(*node->octalCode); - printf("bhgLoadBitstream() writing my octal code\n"); - memcpy(writeToThisLevelBuffer,node->octalCode,codeLength); - - writeToThisLevelBuffer += codeLength; // move the pointer - bytesAtThisLevel += codeLength; // keep track of byte count - - // remember we wrote our octcode here - wroteOctcodeAtThisLevel = true; - } - - // Ok, no matter when we started writing (at this level, or above) if we've got children with color - // we need to write them here. - if (inViewWithColorCount && startedWriting) { - // write the child color bits - printf("bhgLoadBitstream() writing child color bits\n"); - *writeToThisLevelBuffer = childrenColoredBits; - - writeToThisLevelBuffer += sizeof(childrenColoredBits); // move the pointer - bytesAtThisLevel += sizeof(childrenColoredBits); // keep track of byte count - - // write the color data... - for (int i = 0; i < MAX_CHILDREN; i++) { - if (oneAtBit(childrenColoredBits, i)) { - printf("bhgLoadBitstream() writing color for child %d\n",i); - memcpy(writeToThisLevelBuffer,&node->children[i]->getColor(),BYTES_PER_COLOR); - writeToThisLevelBuffer += BYTES_PER_COLOR; // move the pointer for color - bytesAtThisLevel += BYTES_PER_COLOR; // keep track of byte count for color - } - } - } - - printf("startedWriting=%s inViewNotLeafCount=%d \n", (startedWriting ? "yes" : "no"), inViewNotLeafCount ); - - // If all of our IN VIEW children are LEAVES, then we're done - if (startedWriting && (0 == inViewNotLeafCount)) { - - printf("bhgLoadBitstream() writing child trees exist bits of 0\n"); - - // write the child color bits - *writeToThisLevelBuffer = childrenExistBits; - - writeToThisLevelBuffer += sizeof(childrenExistBits); // move the pointer - bytesAtThisLevel += sizeof(childrenExistBits); // keep track of byte count - - keepDiggingDeeper = false; - } - - // at this point we need to do a gut check. If we're writing, then we need to check how many bytes we've - // written at this level, and how many bytes we have available in the outputBuffer. If we can fit what we've got so far - // and room for the no more children terminator, then let's write what we got so far. - - // If we plan to keep digging deeper, we will need at least one more byte. Otherwise, we've got all the bytes we - // need to write already written in our thisLevelBuffer. If we have room for this in our outputBuffer, then copy - // it and proceed as expected. - int potentiallyMoreBytes = keepDiggingDeeper ? CHILD_TREE_EXISTS_BYTES : 0; - - printf("startedWriting=%s availableBytes=%d bytesAtThisLevel=%d keepDiggingDeeper=%s potentiallyMoreBytes=%d\n", - (startedWriting ? "yes" : "no"), availableBytes, bytesAtThisLevel, - (keepDiggingDeeper ? "yes" : "no"), potentiallyMoreBytes ); - - if (startedWriting && (availableBytes > (bytesAtThisLevel + potentiallyMoreBytes))) { - memcpy(outputBuffer,&thisLevelBuffer[0],bytesAtThisLevel); - availableBytes -= bytesAtThisLevel; - - printf("actually write our local bytes to the outputBuffer bytesAtThisLevel=%d availableBytes=%d\n", - bytesAtThisLevel, availableBytes); - } - - if (keepDiggingDeeper) { - - printf("keepDiggingDeeper == TRUE... dig deeper!\n"); - + // If we have children with color, then we do want to add this node (and it's descendants) to the bag to be written + // we don't need to dig deeper. + // + // XXXBHG - this might be a good time to look at colors and add them to a dictionary? But we're not planning + // on scanning the whole tree, so we won't actually see all the colors, so maybe no point in that. + if (inViewWithColorCount) { + bag.insert(node); + } else { // at this point, we need to iterate the children who are in view, even if not colored // and we need to determine if there's a deeper tree below them that we care about. We will iterate // these based on which tree is closer. // - // We have potentially a couple of states here, it's possible we haven't started writing at all. In - // which case, the lower level trees may start writing. And so when we get back here, we need to check - // our writing state, if we had not been writing, and we started writing below, then we basically want - // to start a new top level tree. We do that by simply toggling our startedWriting flag, and then call - // the child node. - // - // It's also possible that we did start writing, but we have NOT yet written our childrenExistBits. This - // is because we don't really know how big the child tree will be. What we kinda would like to do is - // write our childExistsBits as a place holder. Then let each potential tree have a go at it. If they - // write something, we keep them in the bits, if they don't, we take them out. - // - unsigned char* childExistsPlaceHolder = NULL; - bool havePlaceHolderChildBits = false; - if (startedWriting) { - // write the child tree exists "placeholder" bits. - childExistsPlaceHolder = outputBuffer; - *outputBuffer = childrenExistBits; - - outputBuffer += sizeof(childrenExistBits); // move the pointer - bytesAtThisLevel += sizeof(childrenExistBits); // keep track of byte count - - havePlaceHolderChildBits = true; - } for (int i = 0; i < inViewCount; i++) { VoxelNode* childNode = inViewChildren[i]; - int childNodePosition = positionOfChildren[i]; - - printf("bhgLoadBitstream() calling inViewChildren[%d] startedWriting=%s\n",i, (startedWriting ? "yes" : "no") ); - - printf("about to dig deeper, priorWritingState=%s\n",(priorWritingState ? "yes" : "no")); - - int childTreeBytesOut = searchAndEncodeMultiTreeBitstream(childNode,viewFrustum,lastOctalCode,startedWriting, - outputBuffer,availableBytes); - - printf("back from dig deeper, priorWritingState=%s startedWriting=%s childTreeBytesOut=%d\n", - (priorWritingState ? "yes" : "no"), (startedWriting ? "yes" : "no"), childTreeBytesOut); - - bytesAtThisLevel += childTreeBytesOut; - - // If we had previously started writing, and if the child DIDN'T write any bytes, - // then we want to remove their bit from the childExistsPlaceHolder bitmask - if (havePlaceHolderChildBits && (0 == childTreeBytesOut)) { - - printf("bhgLoadBitstream() child %d orig %d didn't write bytes, removing from bitmask\n",i, childNodePosition ); - - // remove this child's bit... - childrenExistBits -= (1 << (7 - childNodePosition)); - - // repair the child exists mask - *childExistsPlaceHolder = childrenExistBits; - - // Note: no need to move the pointer, cause we already stored this - } + searchForColoredNodesRecursion(childNode, viewFrustum, bag); } } - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// THIS IS NOT WORKING!!!! -// -// Second trees are basically blowing up like crazy... not even sure what is going on... -// -//////////////////////////////////////////////////////////////////////////////////////////////////// - - printf("bhgLoadBitstream() at bottom, returning... bytesAtThisLevel=%d\n",bytesAtThisLevel ); - - // If this was the level that we wrote our octcode at.. AND our prior state was not writing, THEN THIS - // is the level we want to switch back to not writing... - - // If before we started this tree, we WEREN'T writing, but after iterating this tree we ARE writing - // then we need to reset writing state, so we'll start a new tree when appropriate. - if (!priorWritingState && startedWriting) { - printf("bhgLoadBitstream() at bottom and returning prior writing state was FALSE, but we did write, so... we want a new tree!\n"); - startedWriting = false; - } - return bytesAtThisLevel; - - } // This will encode a tree bitstream, given a node it will encode the full tree from that point onward. diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index c797b92218..5820bdf1f6 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -68,15 +68,15 @@ public: unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag); - int searchAndEncodeMultiTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrustum, - unsigned char*& lastOctalCode, bool& startedWriting, - unsigned char*& outputBuffer, int availableBytes) const; - + void searchForColoredNodes(VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag); + private: int encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& viewFrustum, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag) const; + void searchForColoredNodesRecursion(VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag); + void recurseNodeWithOperation(VoxelNode* node, RecurseVoxelTreeOperation operation, void* extraData); VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode); VoxelNode* createMissingNode(VoxelNode* lastParentNode, unsigned char* deepestCodeToCreate); From 91f6aaa96e9bf3c1cab49c9e4de0624745f666ff Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 26 Apr 2013 09:23:48 -0700 Subject: [PATCH 20/76] testing of new searchForColoredNodes() --- interface/src/VoxelSystem.cpp | 86 +++++++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 19 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index fbb2056c67..5dd3ccd3e9 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -705,40 +705,88 @@ void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) { printf("--------- DEBUG TESTING ------------\n"); - unsigned char* lastOctalCode = tree->rootNode->octalCode; //const int MAX_VOXEL_PACKET_SIZE=13; // test tight fit... - unsigned char* fullOutputBuffer = new unsigned char[MAX_VOXEL_PACKET_SIZE]; - unsigned char* outputBuffer = fullOutputBuffer; - bool startedWriting = false; + unsigned char* tempOutputBuffer = new unsigned char[MAX_VOXEL_PACKET_SIZE]; + unsigned char* finalOutputBuffer = new unsigned char[MAX_VOXEL_PACKET_SIZE]; + unsigned char* finalOutputBufferAt = finalOutputBuffer; + int availableInFinal = MAX_VOXEL_PACKET_SIZE; int bytesWritten = 0; + int totalBytesWritten = 0; + int totalPackets = 0; VoxelNodeBag bagOfTrees; - bytesWritten = tree->encodeTreeBitstream(tree->rootNode, *viewFrustum, outputBuffer, MAX_VOXEL_PACKET_SIZE, bagOfTrees); + // stick a "V" in the finalOutputBuffer + finalOutputBuffer[0] = 'V'; + finalOutputBufferAt++; + availableInFinal = MAX_VOXEL_PACKET_SIZE-1; - printf("--------- initial results ---- bytesWritten=%d ------------\n",bytesWritten); - outputBufferBits(fullOutputBuffer, bytesWritten, true); - printf("--------- DONE initial results ------------\n"); + //bytesWritten = tree->encodeTreeBitstream(tree->rootNode, *viewFrustum, outputBuffer, MAX_VOXEL_PACKET_SIZE, bagOfTrees); + //totalBytesWritten += bytesWritten; + //printf("--------- initial results ---- bytesWritten=%d ------------\n",bytesWritten); + //outputBufferBits(finalOutputBuffer, bytesWritten, true); + //printf("--------- DONE initial results ------------\n"); + + printf("--------- searchForColoredNodes() ------------\n"); + tree->searchForColoredNodes(tree->rootNode, *viewFrustum, bagOfTrees); + printf("--------- DONE searchForColoredNodes() ------------\n"); - printf("--------- extra trees ------------\n"); + printf("--------- bag of trees ------------\n"); printf("bagOfTrees.count()=%d\n",bagOfTrees.count()); - int countOfExtra = 0; + int countOfTrees = 0; + bool finalOutputBufferWaiting = false; while (!bagOfTrees.isEmpty()) { - countOfExtra++; + countOfTrees++; VoxelNode* extraTree = bagOfTrees.extract(); - printf("processing countOfExtra=%d\n", countOfExtra); + printf("processing countOfTrees=%d\n", countOfTrees); - bytesWritten = tree->encodeTreeBitstream(extraTree, *viewFrustum, outputBuffer, MAX_VOXEL_PACKET_SIZE, bagOfTrees); + // Only let this guy create at largest packets equal to the amount of space we have left in our final??? + // Or let it create the largest possible size (minus 1 for the "V") + bytesWritten = tree->encodeTreeBitstream(extraTree, *viewFrustum, tempOutputBuffer, MAX_VOXEL_PACKET_SIZE-1, bagOfTrees); - - printf("--------- extra results ---- bytesWritten=%d ------------\n",bytesWritten); - outputBufferBits(fullOutputBuffer, bytesWritten, true); - printf("--------- DONE extra results ------------\n"); + printf("this tree size=%d\n", bytesWritten); + // if we have room in our final packet, add this buffer to the final packet + if (availableInFinal >= bytesWritten) { + memcpy(finalOutputBufferAt, tempOutputBuffer, bytesWritten); + availableInFinal -= bytesWritten; + finalOutputBufferAt += bytesWritten; + finalOutputBufferWaiting = true; + } else { + // otherwise "send" the packet! + int sizeOfFinal = MAX_VOXEL_PACKET_SIZE - availableInFinal; + + totalBytesWritten += sizeOfFinal; + totalPackets++; + printf("---- voxel packet ---- sizeOfFinal=%d totalPackets=%d ----\n",sizeOfFinal,totalPackets); + //outputBufferBits(finalOutputBuffer, sizeOfFinal, true); + printf("---- DONE voxel packet ------------\n"); + + // reset our finalOutputBuffer (keep the 'V') + finalOutputBufferAt = &finalOutputBuffer[1]; + availableInFinal = MAX_VOXEL_PACKET_SIZE - 1; + finalOutputBufferWaiting = false; + + // we also need to stick the last created packet in here!! + memcpy(finalOutputBufferAt, tempOutputBuffer, bytesWritten); + availableInFinal -= bytesWritten; + finalOutputBufferAt += bytesWritten; + finalOutputBufferWaiting = true; + } } + if (finalOutputBufferWaiting) { + // otherwise "send" the packet! + int sizeOfFinal = MAX_VOXEL_PACKET_SIZE - availableInFinal; + + totalBytesWritten += sizeOfFinal; + totalPackets++; + printf("---- voxel packet ---- sizeOfFinal=%d totalPackets=%d ----\n",sizeOfFinal,totalPackets); + //outputBufferBits(finalOutputBuffer, sizeOfFinal, true); + printf("---- DONE voxel packet ------------\n"); + } - - printf("--------- DONE DEBUG TESTING ------------\n"); + printf("--- DONE DEBUG TESTING --- countOfTrees=%d totalBytesWritten=%d totalPackets=%d ------\n", + countOfTrees, totalBytesWritten,totalPackets); } From e93cab40ed554ba898b7d148346b9be4d5c19b21 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 26 Apr 2013 12:12:41 -0700 Subject: [PATCH 21/76] change default grow size --- libraries/voxels/src/VoxelNodeBag.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/voxels/src/VoxelNodeBag.cpp b/libraries/voxels/src/VoxelNodeBag.cpp index 232d43ee57..a45231bcae 100644 --- a/libraries/voxels/src/VoxelNodeBag.cpp +++ b/libraries/voxels/src/VoxelNodeBag.cpp @@ -20,7 +20,7 @@ VoxelNodeBag::~VoxelNodeBag() { } } -const int GROW_BAG_BY = 500; +const int GROW_BAG_BY = 100; // put a node into the bag void VoxelNodeBag::insert(VoxelNode* node) { From 8445790183bcb746f828c2ba3c81142719fc9295 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 26 Apr 2013 12:13:37 -0700 Subject: [PATCH 22/76] added new voxel sending support to VoxelAgentData - added VoxelNodeBag member to keep track of which nodes this agent needs to have sent to it - added _voxelPacket and other members to keep track of the next packet to be sent to this client. This is because as we fill in packets to send we may run out of room in the current packet, but not want to have to reencode that data - cleaned up constructors to use common init() method --- voxel-server/src/VoxelAgentData.cpp | 25 ++++++++++++++++++++++++- voxel-server/src/VoxelAgentData.h | 21 ++++++++++++++++++++- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/voxel-server/src/VoxelAgentData.cpp b/voxel-server/src/VoxelAgentData.cpp index e01ae90a69..bb258ee052 100644 --- a/voxel-server/src/VoxelAgentData.cpp +++ b/voxel-server/src/VoxelAgentData.cpp @@ -11,16 +11,39 @@ #include VoxelAgentData::VoxelAgentData() { + init(); +} + +void VoxelAgentData::init() { rootMarkerNode = new MarkerNode(); + _voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE]; + _voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE; + + resetVoxelPacket(); +} + +void VoxelAgentData::resetVoxelPacket() { + _voxelPacket[0] = 'V'; + _voxelPacketAt = &voxelPacket[1]; + _voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE-1; + _voxelPacketWaiting = false; +} + +void VoxelAgentData::writeToPacket(unsigned char* buffer, int bytes) { + memcpy(_voxelPacketAt, buffer, bytes); + _voxelPacketAvailableBytes -= bytes; + _voxelPacketAt += bytes; + _voxelPacketWaiting = true; } VoxelAgentData::~VoxelAgentData() { delete rootMarkerNode; + delete[] _voxelPacket; } VoxelAgentData::VoxelAgentData(const VoxelAgentData &otherAgentData) { memcpy(&_position, &otherAgentData._position, sizeof(_position)); - rootMarkerNode = new MarkerNode(); + init(); } VoxelAgentData* VoxelAgentData::clone() const { diff --git a/voxel-server/src/VoxelAgentData.h b/voxel-server/src/VoxelAgentData.h index 4ca7949b92..61446b41cc 100644 --- a/voxel-server/src/VoxelAgentData.h +++ b/voxel-server/src/VoxelAgentData.h @@ -16,13 +16,32 @@ class VoxelAgentData : public AvatarData { public: - MarkerNode *rootMarkerNode; + MarkerNode* rootMarkerNode; VoxelAgentData(); ~VoxelAgentData(); VoxelAgentData(const VoxelAgentData &otherAgentData); VoxelAgentData* clone() const; + + void init(); // sets up data internals + void resetVoxelPacket(); // resets voxel packet to after "V" header + + void writeToPacket(unsigned char* buffer, int bytes); // writes to end of packet + + const unsigned char* getPacket() const { return _voxelPacket; } + int getPacketLength() const { return (MAX_VOXEL_PACKET_SIZE-_voxelPacketAvailableBytes); } + bool isPacketWaiting() const { return _voxelPacketWaiting; } + int getAvailable() const { return _voxelPacketAvailableBytes; } + + VoxelNodeBag nodeBag; + +private: + unsigned char* _voxelPacket; + int _voxelPacketAvailableBytes; + bool _voxelPacketWaiting; + + }; #endif /* defined(__hifi__VoxelAgentData__) */ From bcdc4d6654bb75f28ff1ea436d78f78a9bcf830b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 26 Apr 2013 12:16:41 -0700 Subject: [PATCH 23/76] new version of voxel encoding and sending --- voxel-server/src/main.cpp | 138 ++++++++++++++++++++++++++++++-------- 1 file changed, 111 insertions(+), 27 deletions(-) diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index a3c018765a..cc44ba15e7 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -122,22 +122,30 @@ void eraseVoxelTreeAndCleanupAgentVisitData() { ::randomTree.eraseAllVoxels(); // enumerate the agents clean up their marker nodes - - for (AgentList::iterator agent = AgentList::getInstance()->begin(); agent != AgentList::getInstance()->end(); agent++) { + for (int i = 0; i < AgentList::getInstance()->getAgents().size(); i++) { //printf("eraseVoxelTreeAndCleanupAgentVisitData() agent[%d]\n",i); - VoxelAgentData *agentData = (VoxelAgentData *)agent->getLinkedData(); + Agent *thisAgent = (Agent *)&AgentList::getInstance()->getAgents()[i]; + VoxelAgentData *agentData = (VoxelAgentData *)(thisAgent->getLinkedData()); + + // lock this agent's delete mutex so that the delete thread doesn't + // kill the agent while we are working with it + pthread_mutex_lock(thisAgent->deleteMutex); // clean up the agent visit data delete agentData->rootMarkerNode; agentData->rootMarkerNode = new MarkerNode(); + + // unlock the delete mutex so the other thread can + // kill the agent if it has dissapeared + pthread_mutex_unlock(thisAgent->deleteMutex); } } void *distributeVoxelsToListeners(void *args) { - AgentList* agentList = AgentList::getInstance(); + AgentList *agentList = AgentList::getInstance(); timeval lastSendTime; unsigned char *stopOctal; @@ -145,36 +153,107 @@ void *distributeVoxelsToListeners(void *args) { int totalBytesSent; - unsigned char *voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE]; - unsigned char *voxelPacketEnd; - float treeRoot[3] = {0, 0, 0}; while (true) { gettimeofday(&lastSendTime, NULL); // enumerate the agents to send 3 packets to each - for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { - VoxelAgentData *agentData = (VoxelAgentData *)agent->getLinkedData(); - - ViewFrustum viewFrustum; - // get position and orientation details from the camera - viewFrustum.setPosition(agentData->getCameraPosition()); - viewFrustum.setOrientation(agentData->getCameraDirection(), agentData->getCameraUp(), agentData->getCameraRight()); - - // Also make sure it's got the correct lens details from the camera - viewFrustum.setFieldOfView(agentData->getCameraFov()); - viewFrustum.setAspectRatio(agentData->getCameraAspectRatio()); - viewFrustum.setNearClip(agentData->getCameraNearClip()); - viewFrustum.setFarClip(agentData->getCameraFarClip()); - - viewFrustum.calculate(); + for (int i = 0; i < agentList->getAgents().size(); i++) { - // debug for fun!! - if (::debugViewFrustum) { - viewFrustum.dump(); + Agent* thisAgent = (Agent *)&agentList->getAgents()[i]; + + // lock this agent's delete mutex so that the delete thread doesn't + // kill the agent while we are working with it + pthread_mutex_lock(thisAgent->deleteMutex); + + VoxelAgentData* agentData = (VoxelAgentData *)(thisAgent->getLinkedData()); + + // If we don't have nodes already in our agent's node bag, then fill the node bag + if (agentData->nodeBag.isEmpty()) { + ViewFrustum viewFrustum; + // get position and orientation details from the camera + viewFrustum.setPosition(agentData->getCameraPosition()); + viewFrustum.setOrientation(agentData->getCameraDirection(), agentData->getCameraUp(), agentData->getCameraRight()); + + // Also make sure it's got the correct lens details from the camera + viewFrustum.setFieldOfView(agentData->getCameraFov()); + viewFrustum.setAspectRatio(agentData->getCameraAspectRatio()); + viewFrustum.setNearClip(agentData->getCameraNearClip()); + viewFrustum.setFarClip(agentData->getCameraFarClip()); + + viewFrustum.calculate(); + + randomTree.searchForColoredNodes(randomTree.rootNode, viewFrustum, agentData->nodeBag); } + // If we have something in our nodeBag, then turn them into packets and send them out... + if (!agentData->nodeBag.isEmpty()) { + + unsigned char* tempOutputBuffer = new unsigned char[MAX_VOXEL_PACKET_SIZE-1]; // save 1 for "V" in final + int bytesWritten = 0; + + // NOTE: we can assume the voxelPacket has already been set up with a "V" + + int packetsSentThisInterval = 0; + + while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL) { + + if (!agentData->nodeBag.isEmpty()) { + + VoxelNode* subTree = agentData->nodeBag.extract(); + + // Only let this guy create at largest packets equal to the amount of space we have left in our final??? + // Or let it create the largest possible size (minus 1 for the "V") + bytesWritten = randomTree.encodeTreeBitstream(subTree, viewFrustum, + tempOutputBuffer, MAX_VOXEL_PACKET_SIZE-1, agentData->nodeBag); + + //printf("this tree size=%d\n", bytesWritten); + + // if we have room in our final packet, add this buffer to the final packet + if (agentData->getAvailable() >= bytesWritten) { + agentData->writeToPacket(tempOutputBuffer, bytesWritten); + } else { + // otherwise "send" the packet because it's as full as we can make it for now + + //outputBufferBits(agentData->getPacket(), agentData->getPacketLength(), true); + agentList->getAgentSocket().send(thisAgent->getActiveSocket(), + agentData->getPacket(), agentData->getPacketLength()); + + // keep track that we sent it + packetsSentThisInterval++; + + // reset our finalOutputBuffer (keep the 'V') + agentData->resetVoxelPacket(); + + // we also need to stick the last created partial packet in here!! + agentData->writeToPacket(tempOutputBuffer, bytesWritten); + } + } else { + // we're here, if there are no more nodes in our bag waiting to be sent. + + // If we have a partial packet ready, then send it... + if (agentData->isPacketWaiting()) { + //outputBufferBits(agentData->getPacket(), agentData->getPacketLength(), true); + agentList->getAgentSocket().send(thisAgent->getActiveSocket(), + agentData->getPacket(), agentData->getPacketLength()); + } + + // and we're done now for this interval, because we know we have not nodes in our + // bag, and we just sent the last waiting packet if we had one, so tell ourselves + // we done for the interval + packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; + } + } + + // end + delete[] tempOutputBuffer; + } +/*** + + unsigned char *voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE]; + unsigned char *voxelPacketEnd; + stopOctal = NULL; packetCount = 0; totalBytesSent = 0; @@ -191,7 +270,7 @@ void *distributeVoxelsToListeners(void *args) { ::viewFrustumCulling, stopOctal); - agentList->getAgentSocket().send(agent->getActiveSocket(), voxelPacket, voxelPacketEnd - voxelPacket); + agentList->getAgentSocket().send(thisAgent->getActiveSocket(), voxelPacket, voxelPacketEnd - voxelPacket); packetCount++; totalBytesSent += voxelPacketEnd - voxelPacket; @@ -212,6 +291,11 @@ void *distributeVoxelsToListeners(void *args) { delete agentData->rootMarkerNode; agentData->rootMarkerNode = new MarkerNode(); } +***/ + + // unlock the delete mutex so the other thread can + // kill the agent if it has dissapeared + pthread_mutex_unlock(thisAgent->deleteMutex); } // dynamically sleep until we need to fire off the next set of voxels @@ -236,7 +320,7 @@ void attachVoxelAgentDataToAgent(Agent *newAgent) { int main(int argc, const char * argv[]) { - AgentList* agentList = AgentList::createInstance(AGENT_TYPE_VOXEL, VOXEL_LISTEN_PORT); + AgentList *agentList = AgentList::createInstance(AGENT_TYPE_VOXEL, VOXEL_LISTEN_PORT); setvbuf(stdout, NULL, _IOLBF, 0); // Handle Local Domain testing with the --local command line From 3cb41a6fa682ce9341c0335a0eb7f96e55c0d97d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 26 Apr 2013 12:36:25 -0700 Subject: [PATCH 24/76] re-apply agentlist changes to voxel server that somehow got smashed --- voxel-server/src/main.cpp | 35 ++++++++--------------------------- 1 file changed, 8 insertions(+), 27 deletions(-) diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index cc44ba15e7..7aa858a182 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -122,30 +122,22 @@ void eraseVoxelTreeAndCleanupAgentVisitData() { ::randomTree.eraseAllVoxels(); // enumerate the agents clean up their marker nodes - for (int i = 0; i < AgentList::getInstance()->getAgents().size(); i++) { + + for (AgentList::iterator agent = AgentList::getInstance()->begin(); agent != AgentList::getInstance()->end(); agent++) { //printf("eraseVoxelTreeAndCleanupAgentVisitData() agent[%d]\n",i); - Agent *thisAgent = (Agent *)&AgentList::getInstance()->getAgents()[i]; - VoxelAgentData *agentData = (VoxelAgentData *)(thisAgent->getLinkedData()); - - // lock this agent's delete mutex so that the delete thread doesn't - // kill the agent while we are working with it - pthread_mutex_lock(thisAgent->deleteMutex); + VoxelAgentData *agentData = (VoxelAgentData *)agent->getLinkedData(); // clean up the agent visit data delete agentData->rootMarkerNode; agentData->rootMarkerNode = new MarkerNode(); - - // unlock the delete mutex so the other thread can - // kill the agent if it has dissapeared - pthread_mutex_unlock(thisAgent->deleteMutex); } } -void *distributeVoxelsToListeners(void *args) { +void* distributeVoxelsToListeners(void *args) { - AgentList *agentList = AgentList::getInstance(); + AgentList* agentList = AgentList::getInstance(); timeval lastSendTime; unsigned char *stopOctal; @@ -159,15 +151,8 @@ void *distributeVoxelsToListeners(void *args) { gettimeofday(&lastSendTime, NULL); // enumerate the agents to send 3 packets to each - for (int i = 0; i < agentList->getAgents().size(); i++) { - - Agent* thisAgent = (Agent *)&agentList->getAgents()[i]; - - // lock this agent's delete mutex so that the delete thread doesn't - // kill the agent while we are working with it - pthread_mutex_lock(thisAgent->deleteMutex); - - VoxelAgentData* agentData = (VoxelAgentData *)(thisAgent->getLinkedData()); + for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { + VoxelAgentData* agentData = (VoxelAgentData*)agent->getLinkedData(); // If we don't have nodes already in our agent's node bag, then fill the node bag if (agentData->nodeBag.isEmpty()) { @@ -292,10 +277,6 @@ void *distributeVoxelsToListeners(void *args) { agentData->rootMarkerNode = new MarkerNode(); } ***/ - - // unlock the delete mutex so the other thread can - // kill the agent if it has dissapeared - pthread_mutex_unlock(thisAgent->deleteMutex); } // dynamically sleep until we need to fire off the next set of voxels @@ -320,7 +301,7 @@ void attachVoxelAgentDataToAgent(Agent *newAgent) { int main(int argc, const char * argv[]) { - AgentList *agentList = AgentList::createInstance(AGENT_TYPE_VOXEL, VOXEL_LISTEN_PORT); + AgentList* agentList = AgentList::createInstance(AGENT_TYPE_VOXEL, VOXEL_LISTEN_PORT); setvbuf(stdout, NULL, _IOLBF, 0); // Handle Local Domain testing with the --local command line From 70818bd3fe6125cf06e7b197b3c9ada473ccc576 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 27 Apr 2013 12:03:20 -0700 Subject: [PATCH 25/76] Added some new debugging code, removed some old debugging code, some small coding standard tweaks --- interface/src/VoxelSystem.cpp | 111 +++++++++++++++++++++++----------- 1 file changed, 75 insertions(+), 36 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 5dd3ccd3e9..14941bb35f 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -115,8 +115,6 @@ float VoxelSystem::getVoxelsBytesReadPerSecondAverage() { return tree->voxelsBytesReadStats.getAverageSampleValuePerSecond(); } -bool pickAorB = false; - int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { unsigned char command = *sourceBuffer; @@ -130,6 +128,71 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { // would make a point of removing this code when all this work is done. But in the mean time, I need it here for // debugging purposes... When you do the code review... DO NOT tell me to remove it. :) Thank you! // + unsigned char fakePacketA[18] = { 86,4,39,128,232,128,128,128,139,138,139,139,137,139,138,139,139,0 }; + unsigned char fakePacketB[13] = { 86, + 7,39,135,128, + 136, + 255,0,0, + 0,255,0, + 0 + }; + unsigned char fakePacketC[13] = { 86, + 7,39,135,64, + 136, + 0,0,255, + 0,255,255, + 0 + }; + + unsigned char fakePacketD[25] = { 86, + 6,39,135,64, + 136, + 0,0,255, + 0,255,255, + 0, + 6,39,135,128, + 136, + 255,0,0, + 0,255,0, + 0 + }; + + unsigned char fakePacketE[60] = { + 86 // V + + ,6,39,135,64, + 136, + 0,0,255, + 0,255,255, + 0 + + ,6,39,135,128, + 136, + 255,0,0, + 0,255,0, + 0 + + // now some extra bits, what happens??? + ,2,252, // octcode for root + 7, // child color bits + 255,0,0, // child 1 color + 255,255,0, // child 1 color + 128,128,0, // child 1 color + 0 // child tree bits + + ,3,0,0, // octcode for root + 3, // child color bits + 0,0,255, // child 128 color + 0,255,0, // child 8 color + 0 // child tree bits - none + + ,3,0,0, // octcode for root + 136, // child color bits + 0,0,255, // child 128 color + 0,255,0, // child 8 color + 0 // child tree bits - none + }; + unsigned char fakeBuffer[18] = { 86, // V 2,0, // octcode for root @@ -185,13 +248,6 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { }; // trim off the "V" - printf("loading fake data! pickAorB=%s\n", (pickAorB ? "A" : "B") ); - if (pickAorB) { - tree->readBitstreamToTree((unsigned char*)&fakeBufferA[1], sizeof(fakeBufferA)-1); - } else { - tree->readBitstreamToTree((unsigned char*)&fakeBufferB[1], sizeof(fakeBufferB)-1); - } - pickAorB = !pickAorB; ***** END OF TEMPORARY CODE ***************************************************************************************/ @@ -256,9 +312,8 @@ void VoxelSystem::copyWrittenDataToReadArrays() { pthread_mutex_unlock(&bufferWriteLock); } -int VoxelSystem::treeToArrays(VoxelNode *currentNode, const glm::vec3& nodePosition) { +int VoxelSystem::treeToArrays(VoxelNode* currentNode, const glm::vec3& nodePosition) { int voxelsAdded = 0; - float halfUnitForVoxel = powf(0.5, *currentNode->octalCode) * (0.5 * TREE_SCALE); glm::vec3 viewerPosition = viewerAvatar->getPosition(); @@ -266,21 +321,12 @@ int VoxelSystem::treeToArrays(VoxelNode *currentNode, const glm::vec3& nodePosi glm::vec3 debugNodePosition; copyFirstVertexForCode(currentNode->octalCode,(float*)&debugNodePosition); - //printf("-----------------\n"); - //printf("halfUnitForVoxel=%f\n",halfUnitForVoxel); - //printf("viewer.x=%f y=%f z=%f \n", viewerPosition.x, viewerPosition.y, viewerPosition.z); - //printf("node.x=%f y=%f z=%f \n", nodePosition[0], nodePosition[1], nodePosition[2]); - //printf("debugNodePosition.x=%f y=%f z=%f \n", debugNodePosition[0], debugNodePosition[1], debugNodePosition[2]); - float distanceToVoxelCenter = sqrtf(powf(viewerPosition.x - nodePosition[0] - halfUnitForVoxel, 2) + powf(viewerPosition.y - nodePosition[1] - halfUnitForVoxel, 2) + powf(viewerPosition.z - nodePosition[2] - halfUnitForVoxel, 2)); int renderLevel = *currentNode->octalCode + 1; int boundaryPosition = boundaryDistanceForRenderLevel(renderLevel); - //printLog("treeToArrays() renderLevel=%d distanceToVoxelCenter=%f boundaryPosition=%d\n", - // renderLevel,distanceToVoxelCenter,boundaryPosition); - bool alwaysDraw = false; // XXXBHG - temporary debug code. Flip this to true to disable LOD blurring if (alwaysDraw || distanceToVoxelCenter < boundaryPosition) { @@ -291,22 +337,6 @@ int VoxelSystem::treeToArrays(VoxelNode *currentNode, const glm::vec3& nodePosi glm::vec3 childNodePosition; copyFirstVertexForCode(currentNode->children[i]->octalCode,(float*)&childNodePosition); childNodePosition *= (float)TREE_SCALE; // scale it up - - /**** disabled ************************************************************************************************ - // Note: Stephen, I intentionally left this in so you would talk to me about it. Here's the deal, this code - // doesn't seem to work correctly. It returns X and Z flipped and the values are negative. Since we use the - // firstVertexForCode() function below to calculate the child vertex and that DOES work, I've decided to use - // that function to calculate our position for LOD handling. - // - // calculate the child's position based on the parent position - for (int j = 0; j < 3; j++) { - childNodePosition[j] = nodePosition[j]; - - if (oneAtBit(branchIndexWithDescendant(currentNode->octalCode,currentNode->children[i]->octalCode),(7 - j))) { - childNodePosition[j] -= (powf(0.5, *currentNode->children[i]->octalCode) * TREE_SCALE); - } - } - **** disabled ************************************************************************************************/ voxelsAdded += treeToArrays(currentNode->children[i], childNodePosition); } } @@ -314,6 +344,15 @@ int VoxelSystem::treeToArrays(VoxelNode *currentNode, const glm::vec3& nodePosi // if we didn't get any voxels added then we're a leaf // add our vertex and color information to the interleaved array + /****** XXXBHG ***** Stephen!!! ******************************************************************************************** + * What is this code about??? Why are we checking to see if voxelsAdded==0???? Shouldn't we always be writing arrays? + * Help me understand this? If I remove this check, then two things happen: + * 1) I get much more blinking... which is not desirable. + * 2) I seem to get large blocks of "average color" voxels... namely I see big voxels, where their should be smaller ones + * + * But with this check in here, the blinking stops... which kind of makes sense... and the average blocks go away??? not + * sure why, but updates seem to be slower... namely, we don't seem to see the new voxels even though the client got them. + ***************************************************************************************************************************/ if (voxelsAdded == 0 && currentNode->isColored()) { float startVertex[3]; copyFirstVertexForCode(currentNode->octalCode,(float*)&startVertex); From 5758e42870b44a4d95e3dc6a0be1c98ae97f9453 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 27 Apr 2013 12:04:33 -0700 Subject: [PATCH 26/76] Added deleteAll() member to VoxelNodeBag class --- libraries/voxels/src/VoxelNodeBag.cpp | 8 ++++++++ libraries/voxels/src/VoxelNodeBag.h | 6 ++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/libraries/voxels/src/VoxelNodeBag.cpp b/libraries/voxels/src/VoxelNodeBag.cpp index a45231bcae..e1a612432d 100644 --- a/libraries/voxels/src/VoxelNodeBag.cpp +++ b/libraries/voxels/src/VoxelNodeBag.cpp @@ -15,11 +15,19 @@ #include VoxelNodeBag::~VoxelNodeBag() { + deleteAll(); +} + +void VoxelNodeBag::deleteAll() { if (_bagElements) { delete[] _bagElements; } + _bagElements = NULL; + _elementsInUse = 0; + _sizeOfElementsArray = 0; } + const int GROW_BAG_BY = 100; // put a node into the bag diff --git a/libraries/voxels/src/VoxelNodeBag.h b/libraries/voxels/src/VoxelNodeBag.h index 75943eb6b2..9eb6a91e6a 100644 --- a/libraries/voxels/src/VoxelNodeBag.h +++ b/libraries/voxels/src/VoxelNodeBag.h @@ -29,8 +29,10 @@ public: void insert(VoxelNode* node); // put a node into the bag VoxelNode* extract(); // pull a node out of the bag (could come in any order) - bool isEmpty() const { return (_elementsInUse == 0); } - int count() const { return _elementsInUse; } + bool isEmpty() const { return (_elementsInUse == 0); }; + int count() const { return _elementsInUse; }; + + void deleteAll(); private: From d49607b4cd38dfe84f8071f572c01449a9323a3f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 27 Apr 2013 12:05:38 -0700 Subject: [PATCH 27/76] fix typo --- voxel-server/src/VoxelAgentData.cpp | 4 ++-- voxel-server/src/VoxelAgentData.h | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/voxel-server/src/VoxelAgentData.cpp b/voxel-server/src/VoxelAgentData.cpp index bb258ee052..3db302f74f 100644 --- a/voxel-server/src/VoxelAgentData.cpp +++ b/voxel-server/src/VoxelAgentData.cpp @@ -18,13 +18,13 @@ void VoxelAgentData::init() { rootMarkerNode = new MarkerNode(); _voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE]; _voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE; - + _voxelPacketAt = _voxelPacket; resetVoxelPacket(); } void VoxelAgentData::resetVoxelPacket() { _voxelPacket[0] = 'V'; - _voxelPacketAt = &voxelPacket[1]; + _voxelPacketAt = &_voxelPacket[1]; _voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE-1; _voxelPacketWaiting = false; } diff --git a/voxel-server/src/VoxelAgentData.h b/voxel-server/src/VoxelAgentData.h index 61446b41cc..3e3569379a 100644 --- a/voxel-server/src/VoxelAgentData.h +++ b/voxel-server/src/VoxelAgentData.h @@ -13,6 +13,8 @@ #include #include #include "MarkerNode.h" +#include "VoxelNodeBag.h" +#include "VoxelTree.h" // for MAX_VOXEL_PACKET_SIZE class VoxelAgentData : public AvatarData { public: @@ -35,9 +37,9 @@ public: int getAvailable() const { return _voxelPacketAvailableBytes; } VoxelNodeBag nodeBag; - private: unsigned char* _voxelPacket; + unsigned char* _voxelPacketAt; int _voxelPacketAvailableBytes; bool _voxelPacketWaiting; From 82c5c3706a45d41af245fd04c18cc2deac9e4f17 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 27 Apr 2013 12:08:50 -0700 Subject: [PATCH 28/76] Latest work on new voxel sending strategy - removed mutex locking for now. do we need this? - fixed bug in createMissingNode() where we would accidentally stomp on a previously created peer tree while creating a new node - improved printTreeForDebugging() to include more details - fixed a bug in readBitstreamToTree() for multi-tree case where we weren't correctly walking through the buffer --- libraries/voxels/src/VoxelTree.cpp | 109 +++++++++++++++-------------- libraries/voxels/src/VoxelTree.h | 2 +- 2 files changed, 57 insertions(+), 54 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index d49134079c..669407cc4d 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -140,27 +140,27 @@ VoxelTree::VoxelTree() : //pthread_mutexattr_t mta; //pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE); - int res = pthread_mutex_init(&_treeNodeDelete, NULL); + //int res = pthread_mutex_init(&_treeNodeDelete, NULL); //debugThreadError("pthread_mutex_init(&_treeNodeDelete, &mta);", res); } VoxelTree::~VoxelTree() { - pthread_mutex_lock(&_treeNodeDelete); + //pthread_mutex_lock(&_treeNodeDelete); // delete the children of the root node // this recursively deletes the tree for (int i = 0; i < 8; i++) { delete rootNode->children[i]; } - pthread_mutex_unlock(&_treeNodeDelete); - pthread_mutex_destroy(&_treeNodeDelete); + //pthread_mutex_unlock(&_treeNodeDelete); + //pthread_mutex_destroy(&_treeNodeDelete); } // Recurses voxel tree calling the RecurseVoxelTreeOperation function for each node. // stops recursion if operation function returns false. void VoxelTree::recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData) { - pthread_mutex_lock(&_treeNodeDelete); + //pthread_mutex_lock(&_treeNodeDelete); recurseNodeWithOperation(rootNode, operation,extraData); - pthread_mutex_unlock(&_treeNodeDelete); + //pthread_mutex_unlock(&_treeNodeDelete); } // Recurses voxel node with an operation function @@ -211,8 +211,13 @@ VoxelNode * VoxelTree::nodeForOctalCode(VoxelNode *ancestorNode, unsigned char * VoxelNode* VoxelTree::createMissingNode(VoxelNode* lastParentNode, unsigned char* codeToReach) { int indexOfNewChild = branchIndexWithDescendant(lastParentNode->octalCode, codeToReach); - lastParentNode->addChildAtIndex(indexOfNewChild); + + // we could be coming down a branch that was already created, so don't stomp on it. + if (lastParentNode->children[indexOfNewChild] == NULL) { + lastParentNode->addChildAtIndex(indexOfNewChild); + } + // This works because we know we traversed down the same tree so if the length is the same, then the whole code is the same if (*lastParentNode->children[indexOfNewChild]->octalCode == *codeToReach) { return lastParentNode->children[indexOfNewChild]; } else { @@ -223,10 +228,9 @@ VoxelNode* VoxelTree::createMissingNode(VoxelNode* lastParentNode, unsigned char // BHG Notes: We appear to call this function for every Voxel Node getting created. // This is recursive in nature. So, for example, if we are given an octal code for // a 1/256th size voxel, we appear to call this function 8 times. Maybe?? -int VoxelTree::readNodeData(VoxelNode *destinationNode, - unsigned char * nodeData, +int VoxelTree::readNodeData(VoxelNode* destinationNode, + unsigned char* nodeData, int bytesLeftToRead) { - // instantiate variable for bytes already read int bytesRead = 1; for (int i = 0; i < 8; i++) { @@ -243,7 +247,6 @@ int VoxelTree::readNodeData(VoxelNode *destinationNode, nodeColor newColor; memcpy(newColor, nodeData + bytesRead, 3); newColor[3] = 1; - destinationNode->children[i]->setColor(newColor); this->voxelsColored++; this->voxelsColoredStats.updateAverage(1); @@ -251,10 +254,9 @@ int VoxelTree::readNodeData(VoxelNode *destinationNode, bytesRead += 3; } } - // average node's color based on color of children destinationNode->setColorFromAverageOfChildren(); - + // give this destination node the child mask from the packet unsigned char childMask = *(nodeData + bytesRead); @@ -286,41 +288,41 @@ int VoxelTree::readNodeData(VoxelNode *destinationNode, void VoxelTree::readBitstreamToTree(unsigned char * bitstream, int bufferSizeBytes) { - int mutexLock; - mutexLock = pthread_mutex_lock(&_treeNodeDelete); + //int mutexLock; + //mutexLock = pthread_mutex_lock(&_treeNodeDelete); //debugThreadError("pthread_mutex_lock(&_treeNodeDelete)", mutexLock); int bytesRead = 0; + unsigned char* bitstreamAt = bitstream; // Keep looping through the buffer calling readNodeData() this allows us to pack multiple root-relative Octal codes // into a single network packet. readNodeData() basically goes down a tree from the root, and fills things in from there // if there are more bytes after that, it's assumed to be another root relative tree - while (bytesRead < bufferSizeBytes) { - VoxelNode* bitstreamRootNode = nodeForOctalCode(rootNode, (unsigned char *)bitstream, NULL); - - if (*bitstream != *bitstreamRootNode->octalCode) { + while (bitstreamAt < bitstream+bufferSizeBytes) { + VoxelNode* bitstreamRootNode = nodeForOctalCode(rootNode, (unsigned char *)bitstreamAt, NULL); + if (*bitstreamAt != *bitstreamRootNode->octalCode) { // 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(rootNode, (unsigned char *)bitstream); + bitstreamRootNode = createMissingNode(rootNode, (unsigned char *)bitstreamAt); } - int octalCodeBytes = bytesRequiredForCodeLength(*bitstream); - - bytesRead += octalCodeBytes; - bytesRead += readNodeData(bitstreamRootNode, bitstream + octalCodeBytes, bufferSizeBytes - octalCodeBytes); + int octalCodeBytes = bytesRequiredForCodeLength(*bitstreamAt); + int theseBytesRead = 0; + theseBytesRead += octalCodeBytes; + theseBytesRead += readNodeData(bitstreamRootNode, bitstreamAt + octalCodeBytes, bufferSizeBytes - (bytesRead+octalCodeBytes)); // skip bitstream to new startPoint - bitstream += bytesRead; + bitstreamAt += theseBytesRead; + bytesRead += theseBytesRead; } this->voxelsBytesRead += bufferSizeBytes; this->voxelsBytesReadStats.updateAverage(bufferSizeBytes); - - pthread_mutex_unlock(&_treeNodeDelete); + //pthread_mutex_unlock(&_treeNodeDelete); } // Note: uses the codeColorBuffer format, but the color's are ignored, because @@ -343,10 +345,10 @@ void VoxelTree::deleteVoxelCodeFromTree(unsigned char *codeBuffer) { int childNDX = branchIndexWithDescendant(parentNode->octalCode, codeBuffer); - pthread_mutex_lock(&_treeNodeDelete); + //pthread_mutex_lock(&_treeNodeDelete); delete parentNode->children[childNDX]; // delete the child nodes parentNode->children[childNDX]=NULL; // set it to NULL - pthread_mutex_unlock(&_treeNodeDelete); + //pthread_mutex_unlock(&_treeNodeDelete); reaverageVoxelColors(rootNode); // Fix our colors!! Need to call it on rootNode } @@ -357,16 +359,16 @@ void VoxelTree::eraseAllVoxels() { // XXXBHG Hack attack - is there a better way to erase the voxel tree? - pthread_mutex_lock(&_treeNodeDelete); + //pthread_mutex_lock(&_treeNodeDelete); delete rootNode; // this will recurse and delete all children rootNode = new VoxelNode(); rootNode->octalCode = new unsigned char[1]; *rootNode->octalCode = 0; - pthread_mutex_unlock(&_treeNodeDelete); + //pthread_mutex_unlock(&_treeNodeDelete); } void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) { - pthread_mutex_lock(&_treeNodeDelete); + ////pthread_mutex_lock(&_treeNodeDelete); VoxelNode* lastCreatedNode = nodeForOctalCode(rootNode, codeColorBuffer, NULL); // create the node if it does not exist @@ -381,7 +383,7 @@ void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) { memcpy(newColor, codeColorBuffer + octalCodeBytes, 3); newColor[3] = 1; lastCreatedNode->setColor(newColor); - pthread_mutex_unlock(&_treeNodeDelete); + //pthread_mutex_unlock(&_treeNodeDelete); } unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, @@ -395,7 +397,7 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, { unsigned char * childStopOctalCode = NULL; // could we make this tighter? - pthread_mutex_lock(&_treeNodeDelete); + //pthread_mutex_lock(&_treeNodeDelete); static unsigned char *initialBitstreamPos = bitstreamBuffer; if (stopOctalCode == NULL) { @@ -456,7 +458,7 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, if ((bitstreamBuffer - initialBitstreamPos) + MAX_TREE_SLICE_BYTES > MAX_VOXEL_PACKET_SIZE) { // we can't send this packet, not enough room // return our octal code as the stop - pthread_mutex_unlock(&_treeNodeDelete); + //pthread_mutex_unlock(&_treeNodeDelete); return currentVoxelNode->octalCode; } @@ -493,9 +495,9 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, childPosition[2] *= TREE_SCALE; // scale it up float halfChildVoxel = powf(0.5, *childOctalCode) * (0.5 * TREE_SCALE); - float distanceToChildCenter = sqrtf(powf(agentPosition[0] - childPosition[0] - halfChildVoxel, 2) + - powf(agentPosition[1] - childPosition[1] - halfChildVoxel, 2) + - powf(agentPosition[2] - childPosition[2] - halfChildVoxel, 2)); + //float distanceToChildCenter = sqrtf(powf(agentPosition[0] - childPosition[0] - halfChildVoxel, 2) + + // powf(agentPosition[1] - childPosition[1] - halfChildVoxel, 2) + + // powf(agentPosition[2] - childPosition[2] - halfChildVoxel, 2)); float fullChildVoxel = halfChildVoxel * 2.0f; AABox childBox; @@ -637,7 +639,7 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, } } } - pthread_mutex_unlock(&_treeNodeDelete); + //pthread_mutex_unlock(&_treeNodeDelete); return childStopOctalCode; } @@ -667,7 +669,7 @@ void VoxelTree::processRemoveVoxelBitstream(unsigned char * bitstream, int buffe void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { // could we make this tighter? - pthread_mutex_lock(&_treeNodeDelete); + //pthread_mutex_lock(&_treeNodeDelete); int colorMask = 0; // create the color mask @@ -677,14 +679,18 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { } } + printLog("color mask: "); outputBits(colorMask); // output the colors we have for (int j = 0; j < 8; j++) { if (startNode->children[j] != NULL && startNode->children[j]->isColored()) { + printf("color %d : ",j); for (int c = 0; c < 3; c++) { - outputBits(startNode->children[j]->getTrueColor()[c]); + outputBits(startNode->children[j]->getTrueColor()[c],false); } + startNode->children[j]->printDebugDetails(""); + //printf("\n"); } } @@ -696,6 +702,7 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { } } + printLog("child mask: "); outputBits(childMask); if (childMask > 0) { @@ -707,12 +714,12 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { } } } - pthread_mutex_unlock(&_treeNodeDelete); + //pthread_mutex_unlock(&_treeNodeDelete); } void VoxelTree::reaverageVoxelColors(VoxelNode *startNode) { // could we make this tighter? - pthread_mutex_lock(&_treeNodeDelete); + //pthread_mutex_lock(&_treeNodeDelete); // can't be recursed! bool hasChildren = false; for (int i = 0; i < 8; i++) { @@ -729,7 +736,7 @@ void VoxelTree::reaverageVoxelColors(VoxelNode *startNode) { startNode->setColorFromAverageOfChildren(); } } - pthread_mutex_unlock(&_treeNodeDelete); + //pthread_mutex_unlock(&_treeNodeDelete); } ////////////////////////////////////////////////////////////////////////////////////////// // Method: VoxelTree::loadVoxelsFile() @@ -783,9 +790,9 @@ void VoxelTree::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) { voxelData[lengthInBytes+1], voxelData[lengthInBytes+2], voxelData[lengthInBytes+3]); //printVoxelCode(voxelData); - pthread_mutex_lock(&_treeNodeDelete); + //pthread_mutex_lock(&_treeNodeDelete); this->readCodeColorBufferToTree(voxelData); - pthread_mutex_unlock(&_treeNodeDelete); + //pthread_mutex_unlock(&_treeNodeDelete); delete voxelData; } @@ -869,8 +876,6 @@ void VoxelTree::createSphere(float r,float xc, float yc, float zc, float s, bool unsigned char* voxelData = pointToVoxel(x,y,z,s,red,green,blue); this->readCodeColorBufferToTree(voxelData); - //printLog("voxel data for x:%f y:%f z:%f s:%f\n",x,y,z,s); - //printVoxelCode(voxelData); delete voxelData; } } @@ -896,8 +901,6 @@ void VoxelTree::searchForColoredNodesRecursion(VoxelNode* node, const ViewFrustu return; } - bool keepDiggingDeeper = true; // Assuming we're in view we have a great work ethic, we're always ready for more! - const int MAX_CHILDREN = 8; VoxelNode* inViewChildren[MAX_CHILDREN]; float distancesToChildren[MAX_CHILDREN]; @@ -978,7 +981,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrust int bytesWritten = 0; // could we make this tighter? - pthread_mutex_lock(&_treeNodeDelete); + //pthread_mutex_lock(&_treeNodeDelete); // Some debugging code... where are we in the tree.. //node->printDebugDetails("encodeTreeBitstream() node="); @@ -986,7 +989,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrust // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! if (!node->isInView(viewFrustum)) { //printf("encodeTreeBitstream() node NOT IN VIEW\n"); - pthread_mutex_unlock(&_treeNodeDelete); + //pthread_mutex_unlock(&_treeNodeDelete); return bytesWritten; } @@ -1018,7 +1021,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrust //printf("encodeTreeBitstreamRecursion() no bytes below...\n"); bytesWritten = 0; } - pthread_mutex_unlock(&_treeNodeDelete); + //pthread_mutex_unlock(&_treeNodeDelete); return bytesWritten; } diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 5820bdf1f6..24f25320b7 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -82,7 +82,7 @@ private: VoxelNode* createMissingNode(VoxelNode* lastParentNode, unsigned char* deepestCodeToCreate); int readNodeData(VoxelNode *destinationNode, unsigned char* nodeData, int bufferSizeBytes); - pthread_mutex_t _treeNodeDelete; + //pthread_mutex_t _treeNodeDelete; }; int boundaryDistanceForRenderLevel(unsigned int renderLevel); From 2fb172f3db874e65e075192422c0b9b5d73978a9 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 27 Apr 2013 12:12:43 -0700 Subject: [PATCH 29/76] added support for command line option to use OLD or NEW voxel distribution schemes - moved new voxel distribution strategy to helper function - added back old technique - added "--newVoxelDistributor" command line option - fixed crashing bug for derefrencing NULL pointer in case where server is started which interface agents already in the domain. Basically agentData may not yet be setup properly - added proper cleanup support to node bag in case where voxel tree is erased - first cut at new version of sphere scene, we will make it richer in case of new distribution - bumped packets per interval to 5 --- voxel-server/src/main.cpp | 278 +++++++++++++++++++++----------------- 1 file changed, 157 insertions(+), 121 deletions(-) diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 7aa858a182..c03b0749cb 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -41,7 +41,7 @@ const float DEATH_STAR_RADIUS = 4.0; const float MAX_CUBE = 0.05f; const int VOXEL_SEND_INTERVAL_USECS = 100 * 1000; -const int PACKETS_PER_CLIENT_PER_INTERVAL = 2; +const int PACKETS_PER_CLIENT_PER_INTERVAL = 5; const int MAX_VOXEL_TREE_DEPTH_LEVELS = 4; @@ -50,6 +50,7 @@ VoxelTree randomTree; bool wantColorRandomizer = false; bool debugViewFrustum = false; bool viewFrustumCulling = true; // for now +bool newVoxelDistributor = false; // for now void addSphere(VoxelTree * tree,bool random, bool wantColorRandomizer) { float r = random ? randFloatInRange(0.05,0.1) : 0.25; @@ -72,12 +73,25 @@ void addSphere(VoxelTree * tree,bool random, bool wantColorRandomizer) { void addSphereScene(VoxelTree * tree, bool wantColorRandomizer) { printf("adding scene of spheres...\n"); - tree->createSphere(0.25,0.5,0.5,0.5,(1.0/256),true,wantColorRandomizer); - tree->createSphere(0.030625,0.5,0.5,(0.25-0.06125),(1.0/512),true,true); - tree->createSphere(0.030625,(1.0-0.030625),(1.0-0.030625),(1.0-0.06125),(1.0/512),true,true); - tree->createSphere(0.030625,(1.0-0.030625),(1.0-0.030625),0.06125,(1.0/512),true,true); - tree->createSphere(0.030625,(1.0-0.030625),0.06125,(1.0-0.06125),(1.0/512),true,true); - tree->createSphere(0.06125,0.125,0.125,(1.0-0.125),(1.0/512),true,true); + + // The old voxel distributor has a hard time with smaller voxels and more + // complex scenes... so if we're using the old distributor make our scene + // simple with larger sized voxels + //int sphereBaseSize = ::newVoxelDistributor ? 512 : 256; + int sphereBaseSize = 256; + + tree->createSphere(0.25,0.5,0.5,0.5,(1.0/sphereBaseSize),true,wantColorRandomizer); + printf("one sphere added...\n"); + tree->createSphere(0.030625,0.5,0.5,(0.25-0.06125),(1.0/(sphereBaseSize*2)),true,true); + printf("two spheres added...\n"); + tree->createSphere(0.030625,(1.0-0.030625),(1.0-0.030625),(1.0-0.06125),(1.0/(sphereBaseSize*2)),true,true); + printf("three spheres added...\n"); + tree->createSphere(0.030625,(1.0-0.030625),(1.0-0.030625),0.06125,(1.0/(sphereBaseSize*2)),true,true); + printf("four spheres added...\n"); + tree->createSphere(0.030625,(1.0-0.030625),0.06125,(1.0-0.06125),(1.0/(sphereBaseSize*2)),true,true); + printf("five spheres added...\n"); + tree->createSphere(0.06125,0.125,0.125,(1.0-0.125),(1.0/(sphereBaseSize*2)),true,true); + printf("DONE adding scene of spheres...\n"); } @@ -127,15 +141,96 @@ void eraseVoxelTreeAndCleanupAgentVisitData() { //printf("eraseVoxelTreeAndCleanupAgentVisitData() agent[%d]\n",i); - VoxelAgentData *agentData = (VoxelAgentData *)agent->getLinkedData(); - - // clean up the agent visit data - delete agentData->rootMarkerNode; - agentData->rootMarkerNode = new MarkerNode(); + VoxelAgentData* agentData = (VoxelAgentData *)agent->getLinkedData(); + + if (agentData) { + // clean up the agent visit data + agentData->nodeBag.deleteAll(); + // old way + delete agentData->rootMarkerNode; + agentData->rootMarkerNode = new MarkerNode(); + } } } -void* distributeVoxelsToListeners(void *args) { + +void newDistributeHelper(AgentList* agentList, AgentList::iterator& agent, VoxelAgentData* agentData, ViewFrustum& viewFrustum) { + // If we don't have nodes already in our agent's node bag, then fill the node bag + if (agentData->nodeBag.isEmpty()) { + + printf("agent calling searchForColoredNodes()\n"); + randomTree.searchForColoredNodes(randomTree.rootNode, viewFrustum, agentData->nodeBag); + + // this would add the whole tree + //agentData->nodeBag.insert(randomTree.rootNode); + } + + // If we have something in our nodeBag, then turn them into packets and send them out... + if (!agentData->nodeBag.isEmpty()) { + unsigned char* tempOutputBuffer = new unsigned char[MAX_VOXEL_PACKET_SIZE-1]; // save 1 for "V" in final + int bytesWritten = 0; + + // NOTE: we can assume the voxelPacket has already been set up with a "V" + int packetsSentThisInterval = 0; + + while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL) { + if (!agentData->nodeBag.isEmpty()) { + VoxelNode* subTree = agentData->nodeBag.extract(); + + // Only let this guy create at largest packets equal to the amount of space we have left in our final??? + // Or let it create the largest possible size (minus 1 for the "V") + bytesWritten = randomTree.encodeTreeBitstream(subTree, viewFrustum, + tempOutputBuffer, MAX_VOXEL_PACKET_SIZE-1, agentData->nodeBag); + + // if we have room in our final packet, add this buffer to the final packet + if (agentData->getAvailable() >= bytesWritten) { + agentData->writeToPacket(tempOutputBuffer, bytesWritten); + } else { + // otherwise "send" the packet because it's as full as we can make it for now + agentList->getAgentSocket().send(agent->getActiveSocket(), + agentData->getPacket(), agentData->getPacketLength()); + + // keep track that we sent it + packetsSentThisInterval++; + + //printf("main loop send... this packetSize=%d packetsSentThisInterval=%d \n", + // agentData->getPacketLength(), packetsSentThisInterval); + //outputBufferBits((unsigned char*)agentData->getPacket(), agentData->getPacketLength(), true); + + // reset our finalOutputBuffer (keep the 'V') + agentData->resetVoxelPacket(); + + // we also need to stick the last created partial packet in here!! + agentData->writeToPacket(tempOutputBuffer, bytesWritten); + } + } else { + // we're here, if there are no more nodes in our bag waiting to be sent. + // If we have a partial packet ready, then send it... + if (agentData->isPacketWaiting()) { + agentList->getAgentSocket().send(agent->getActiveSocket(), + agentData->getPacket(), agentData->getPacketLength()); + + //printf("isPacketWaiting() send... this packetSize=%d packetsSentThisInterval=%d \n", + // agentData->getPacketLength(), packetsSentThisInterval); + //outputBufferBits((unsigned char*)agentData->getPacket(), agentData->getPacketLength(), true); + + // reset our finalOutputBuffer (keep the 'V') + agentData->resetVoxelPacket(); + } + + // and we're done now for this interval, because we know we have not nodes in our + // bag, and we just sent the last waiting packet if we had one, so tell ourselves + // we done for the interval + packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; + } + } + + // end + delete[] tempOutputBuffer; + } +} + +void *distributeVoxelsToListeners(void *args) { AgentList* agentList = AgentList::getInstance(); timeval lastSendTime; @@ -145,6 +240,9 @@ void* distributeVoxelsToListeners(void *args) { int totalBytesSent; + unsigned char *voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE]; + unsigned char *voxelPacketEnd; + float treeRoot[3] = {0, 0, 0}; while (true) { @@ -152,10 +250,10 @@ void* distributeVoxelsToListeners(void *args) { // enumerate the agents to send 3 packets to each for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { - VoxelAgentData* agentData = (VoxelAgentData*)agent->getLinkedData(); - - // If we don't have nodes already in our agent's node bag, then fill the node bag - if (agentData->nodeBag.isEmpty()) { + VoxelAgentData* agentData = (VoxelAgentData *)agent->getLinkedData(); + + // Sometimes the agent data has not yet been linked, in which case we can't really do anything + if (agentData) { ViewFrustum viewFrustum; // get position and orientation details from the camera viewFrustum.setPosition(agentData->getCameraPosition()); @@ -169,114 +267,48 @@ void* distributeVoxelsToListeners(void *args) { viewFrustum.calculate(); - randomTree.searchForColoredNodes(randomTree.rootNode, viewFrustum, agentData->nodeBag); - } + if (::newVoxelDistributor) { + newDistributeHelper(agentList, agent, agentData, viewFrustum); + } else { + stopOctal = NULL; + packetCount = 0; + totalBytesSent = 0; + randomTree.leavesWrittenToBitstream = 0; - // If we have something in our nodeBag, then turn them into packets and send them out... - if (!agentData->nodeBag.isEmpty()) { - - unsigned char* tempOutputBuffer = new unsigned char[MAX_VOXEL_PACKET_SIZE-1]; // save 1 for "V" in final - int bytesWritten = 0; - - // NOTE: we can assume the voxelPacket has already been set up with a "V" - - int packetsSentThisInterval = 0; - - while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL) { - - if (!agentData->nodeBag.isEmpty()) { - - VoxelNode* subTree = agentData->nodeBag.extract(); - - // Only let this guy create at largest packets equal to the amount of space we have left in our final??? - // Or let it create the largest possible size (minus 1 for the "V") - bytesWritten = randomTree.encodeTreeBitstream(subTree, viewFrustum, - tempOutputBuffer, MAX_VOXEL_PACKET_SIZE-1, agentData->nodeBag); - - //printf("this tree size=%d\n", bytesWritten); - - // if we have room in our final packet, add this buffer to the final packet - if (agentData->getAvailable() >= bytesWritten) { - agentData->writeToPacket(tempOutputBuffer, bytesWritten); - } else { - // otherwise "send" the packet because it's as full as we can make it for now - - //outputBufferBits(agentData->getPacket(), agentData->getPacketLength(), true); - agentList->getAgentSocket().send(thisAgent->getActiveSocket(), - agentData->getPacket(), agentData->getPacketLength()); - - // keep track that we sent it - packetsSentThisInterval++; - - // reset our finalOutputBuffer (keep the 'V') - agentData->resetVoxelPacket(); - - // we also need to stick the last created partial packet in here!! - agentData->writeToPacket(tempOutputBuffer, bytesWritten); + for (int j = 0; j < PACKETS_PER_CLIENT_PER_INTERVAL; j++) { + voxelPacketEnd = voxelPacket; + stopOctal = randomTree.loadBitstreamBuffer(voxelPacketEnd, + randomTree.rootNode, + agentData->rootMarkerNode, + agentData->getPosition(), + treeRoot, + viewFrustum, + ::viewFrustumCulling, + stopOctal); + + agentList->getAgentSocket().send(agent->getActiveSocket(), voxelPacket, voxelPacketEnd - voxelPacket); + + packetCount++; + totalBytesSent += voxelPacketEnd - voxelPacket; + + // XXXBHG Hack Attack: This is temporary code to help debug an issue. + // Normally we use this break to prevent resending voxels that an agent has + // already visited. But since we might be modifying the voxel tree we might + // want to always send. This is a hack to test the behavior + bool alwaysSend = true; + if (!alwaysSend && agentData->rootMarkerNode->childrenVisitedMask == 255) { + break; } - } else { - // we're here, if there are no more nodes in our bag waiting to be sent. - - // If we have a partial packet ready, then send it... - if (agentData->isPacketWaiting()) { - //outputBufferBits(agentData->getPacket(), agentData->getPacketLength(), true); - agentList->getAgentSocket().send(thisAgent->getActiveSocket(), - agentData->getPacket(), agentData->getPacketLength()); - } - - // and we're done now for this interval, because we know we have not nodes in our - // bag, and we just sent the last waiting packet if we had one, so tell ourselves - // we done for the interval - packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; + } + + // for any agent that has a root marker node with 8 visited children + // recursively delete its marker nodes so we can revisit + if (agentData->rootMarkerNode->childrenVisitedMask == 255) { + delete agentData->rootMarkerNode; + agentData->rootMarkerNode = new MarkerNode(); } } - - // end - delete[] tempOutputBuffer; } -/*** - - unsigned char *voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE]; - unsigned char *voxelPacketEnd; - - stopOctal = NULL; - packetCount = 0; - totalBytesSent = 0; - randomTree.leavesWrittenToBitstream = 0; - - for (int j = 0; j < PACKETS_PER_CLIENT_PER_INTERVAL; j++) { - voxelPacketEnd = voxelPacket; - stopOctal = randomTree.loadBitstreamBuffer(voxelPacketEnd, - randomTree.rootNode, - agentData->rootMarkerNode, - agentData->getPosition(), - treeRoot, - viewFrustum, - ::viewFrustumCulling, - stopOctal); - - agentList->getAgentSocket().send(thisAgent->getActiveSocket(), voxelPacket, voxelPacketEnd - voxelPacket); - - packetCount++; - totalBytesSent += voxelPacketEnd - voxelPacket; - - // XXXBHG Hack Attack: This is temporary code to help debug an issue. - // Normally we use this break to prevent resending voxels that an agent has - // already visited. But since we might be modifying the voxel tree we might - // want to always send. This is a hack to test the behavior - bool alwaysSend = true; - if (!alwaysSend && agentData->rootMarkerNode->childrenVisitedMask == 255) { - break; - } - } - - // for any agent that has a root marker node with 8 visited children - // recursively delete its marker nodes so we can revisit - if (agentData->rootMarkerNode->childrenVisitedMask == 255) { - delete agentData->rootMarkerNode; - agentData->rootMarkerNode = new MarkerNode(); - } -***/ } // dynamically sleep until we need to fire off the next set of voxels @@ -327,10 +359,14 @@ int main(int argc, const char * argv[]) ::viewFrustumCulling = !cmdOptionExists(argc, argv, NO_VIEW_FRUSTUM_CULLING); printf("viewFrustumCulling=%s\n", (::viewFrustumCulling ? "yes" : "no")); - const char* WANT_COLOR_RANDOMIZER = "--WantColorRandomizer"; + const char* WANT_COLOR_RANDOMIZER = "--wantColorRandomizer"; ::wantColorRandomizer = cmdOptionExists(argc, argv, WANT_COLOR_RANDOMIZER); printf("wantColorRandomizer=%s\n", (::wantColorRandomizer ? "yes" : "no")); + const char* NEW_VOXEL_DISTRIBUTOR = "--newVoxelDistributor"; + ::newVoxelDistributor = cmdOptionExists(argc, argv, NEW_VOXEL_DISTRIBUTOR); + printf("newVoxelDistributor=%s\n", (::newVoxelDistributor ? "yes" : "no")); + // Check to see if the user passed in a command line option for loading a local // Voxel File. If so, load it now. const char* INPUT_FILE = "-i"; From 2f2af7ec09489d167f2cd31d4d5d6def2b2a732c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 27 Apr 2013 14:53:08 -0700 Subject: [PATCH 30/76] removed some debug code --- interface/src/VoxelSystem.cpp | 87 ----------------------------------- 1 file changed, 87 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 14941bb35f..49dc408c8d 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -741,91 +741,4 @@ void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) { tree->recurseTreeWithOperation(falseColorizeDistanceFromViewOperation,(void*)viewFrustum); printf("setting in distance false color for %d nodes\n",_nodeCount); setupNewVoxelsForDrawing(); - - - printf("--------- DEBUG TESTING ------------\n"); - //const int MAX_VOXEL_PACKET_SIZE=13; // test tight fit... - unsigned char* tempOutputBuffer = new unsigned char[MAX_VOXEL_PACKET_SIZE]; - unsigned char* finalOutputBuffer = new unsigned char[MAX_VOXEL_PACKET_SIZE]; - unsigned char* finalOutputBufferAt = finalOutputBuffer; - int availableInFinal = MAX_VOXEL_PACKET_SIZE; - int bytesWritten = 0; - int totalBytesWritten = 0; - int totalPackets = 0; - - VoxelNodeBag bagOfTrees; - - // stick a "V" in the finalOutputBuffer - finalOutputBuffer[0] = 'V'; - finalOutputBufferAt++; - availableInFinal = MAX_VOXEL_PACKET_SIZE-1; - - //bytesWritten = tree->encodeTreeBitstream(tree->rootNode, *viewFrustum, outputBuffer, MAX_VOXEL_PACKET_SIZE, bagOfTrees); - //totalBytesWritten += bytesWritten; - //printf("--------- initial results ---- bytesWritten=%d ------------\n",bytesWritten); - //outputBufferBits(finalOutputBuffer, bytesWritten, true); - //printf("--------- DONE initial results ------------\n"); - - printf("--------- searchForColoredNodes() ------------\n"); - tree->searchForColoredNodes(tree->rootNode, *viewFrustum, bagOfTrees); - printf("--------- DONE searchForColoredNodes() ------------\n"); - - printf("--------- bag of trees ------------\n"); - printf("bagOfTrees.count()=%d\n",bagOfTrees.count()); - - int countOfTrees = 0; - bool finalOutputBufferWaiting = false; - while (!bagOfTrees.isEmpty()) { - countOfTrees++; - VoxelNode* extraTree = bagOfTrees.extract(); - printf("processing countOfTrees=%d\n", countOfTrees); - - // Only let this guy create at largest packets equal to the amount of space we have left in our final??? - // Or let it create the largest possible size (minus 1 for the "V") - bytesWritten = tree->encodeTreeBitstream(extraTree, *viewFrustum, tempOutputBuffer, MAX_VOXEL_PACKET_SIZE-1, bagOfTrees); - - printf("this tree size=%d\n", bytesWritten); - - // if we have room in our final packet, add this buffer to the final packet - if (availableInFinal >= bytesWritten) { - memcpy(finalOutputBufferAt, tempOutputBuffer, bytesWritten); - availableInFinal -= bytesWritten; - finalOutputBufferAt += bytesWritten; - finalOutputBufferWaiting = true; - } else { - // otherwise "send" the packet! - int sizeOfFinal = MAX_VOXEL_PACKET_SIZE - availableInFinal; - - totalBytesWritten += sizeOfFinal; - totalPackets++; - printf("---- voxel packet ---- sizeOfFinal=%d totalPackets=%d ----\n",sizeOfFinal,totalPackets); - //outputBufferBits(finalOutputBuffer, sizeOfFinal, true); - printf("---- DONE voxel packet ------------\n"); - - // reset our finalOutputBuffer (keep the 'V') - finalOutputBufferAt = &finalOutputBuffer[1]; - availableInFinal = MAX_VOXEL_PACKET_SIZE - 1; - finalOutputBufferWaiting = false; - - // we also need to stick the last created packet in here!! - memcpy(finalOutputBufferAt, tempOutputBuffer, bytesWritten); - availableInFinal -= bytesWritten; - finalOutputBufferAt += bytesWritten; - finalOutputBufferWaiting = true; - } - } - - if (finalOutputBufferWaiting) { - // otherwise "send" the packet! - int sizeOfFinal = MAX_VOXEL_PACKET_SIZE - availableInFinal; - - totalBytesWritten += sizeOfFinal; - totalPackets++; - printf("---- voxel packet ---- sizeOfFinal=%d totalPackets=%d ----\n",sizeOfFinal,totalPackets); - //outputBufferBits(finalOutputBuffer, sizeOfFinal, true); - printf("---- DONE voxel packet ------------\n"); - } - - printf("--- DONE DEBUG TESTING --- countOfTrees=%d totalBytesWritten=%d totalPackets=%d ------\n", - countOfTrees, totalBytesWritten,totalPackets); } From 999930743e9c3b3f3907ef1fb3c97f84e5a279d4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 27 Apr 2013 14:55:34 -0700 Subject: [PATCH 31/76] removed some debug code --- interface/src/VoxelSystem.cpp | 141 +--------------------------------- 1 file changed, 1 insertion(+), 140 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 49dc408c8d..21b3ab6625 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -122,138 +122,8 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { switch(command) { case PACKET_HEADER_VOXEL_DATA: - { - /***************** TEMPORARY CODE ********************************************************************************* - // YES! Stephen - I have intentionally placed this horrible UGLY LINE across your screen! I did it so you and I - // would make a point of removing this code when all this work is done. But in the mean time, I need it here for - // debugging purposes... When you do the code review... DO NOT tell me to remove it. :) Thank you! - // - unsigned char fakePacketA[18] = { 86,4,39,128,232,128,128,128,139,138,139,139,137,139,138,139,139,0 }; - unsigned char fakePacketB[13] = { 86, - 7,39,135,128, - 136, - 255,0,0, - 0,255,0, - 0 - }; - unsigned char fakePacketC[13] = { 86, - 7,39,135,64, - 136, - 0,0,255, - 0,255,255, - 0 - }; - - unsigned char fakePacketD[25] = { 86, - 6,39,135,64, - 136, - 0,0,255, - 0,255,255, - 0, - 6,39,135,128, - 136, - 255,0,0, - 0,255,0, - 0 - }; - - unsigned char fakePacketE[60] = { - 86 // V - - ,6,39,135,64, - 136, - 0,0,255, - 0,255,255, - 0 - - ,6,39,135,128, - 136, - 255,0,0, - 0,255,0, - 0 - - // now some extra bits, what happens??? - ,2,252, // octcode for root - 7, // child color bits - 255,0,0, // child 1 color - 255,255,0, // child 1 color - 128,128,0, // child 1 color - 0 // child tree bits - - ,3,0,0, // octcode for root - 3, // child color bits - 0,0,255, // child 128 color - 0,255,0, // child 8 color - 0 // child tree bits - none - - ,3,0,0, // octcode for root - 136, // child color bits - 0,0,255, // child 128 color - 0,255,0, // child 8 color - 0 // child tree bits - none - }; - - unsigned char fakeBuffer[18] = { - 86, // V - 2,0, // octcode for root - 136, // child color bits - 0,0,255, // child 128 color - 0,255,0, // child 8 color - 0, // child tree bits - none - - // now some extra bits, what happens??? - 2,252, // octcode for root - 1, // child color bits - 255,0,0, // child 1 color - 0 // child tree bits - }; - - //printf("loading fake data! fakeBuffer \n"); - tree->readBitstreamToTree((unsigned char*)&fakeBuffer[1], sizeof(fakeBuffer)-1); - - unsigned char fakeBuffer[11] = { - 86, // V - 2,0, // octcode for root - 136, // child color bits - 0,0,255, // child 128 color - 0,255,0, // child 8 color - 0 // child tree bits - none - }; - - printf("loading fake data! fakeBuffer \n"); - tree->readBitstreamToTree((unsigned char*)&fakeBuffer[1], sizeof(fakeBuffer)-1); - - unsigned char fakeBufferA[11] = { - 86, // V - 0, // octcode for root - 0, // child color bits? - 128, // child exists bits - 0, // child color bits - 128, // child exists - 128, // child color bits - 0,0,255, // child color - 0 // child exists bits - }; - - unsigned char fakeBufferB[11] = { - 86, // V - 0, // octcode for root - 0, // child color bits? - 128, // child exists bits - 0, // child color bits - 128, // child exists - 16, // child color bits - 0,255,0, // child color?? - 0 // child exists bits - }; - - // trim off the "V" - - ***** END OF TEMPORARY CODE ***************************************************************************************/ - // ask the VoxelTree to read the bitstream into the tree tree->readBitstreamToTree(voxelData, numBytes - 1); - } break; case PACKET_HEADER_ERASE_VOXEL: // ask the tree to read the "remove" bitstream @@ -342,17 +212,8 @@ int VoxelSystem::treeToArrays(VoxelNode* currentNode, const glm::vec3& nodePosi } } - // if we didn't get any voxels added then we're a leaf + // if we didn't get any voxels added then we're a leaf (XXXBHG - Stephen can you explain this to me????) // add our vertex and color information to the interleaved array - /****** XXXBHG ***** Stephen!!! ******************************************************************************************** - * What is this code about??? Why are we checking to see if voxelsAdded==0???? Shouldn't we always be writing arrays? - * Help me understand this? If I remove this check, then two things happen: - * 1) I get much more blinking... which is not desirable. - * 2) I seem to get large blocks of "average color" voxels... namely I see big voxels, where their should be smaller ones - * - * But with this check in here, the blinking stops... which kind of makes sense... and the average blocks go away??? not - * sure why, but updates seem to be slower... namely, we don't seem to see the new voxels even though the client got them. - ***************************************************************************************************************************/ if (voxelsAdded == 0 && currentNode->isColored()) { float startVertex[3]; copyFirstVertexForCode(currentNode->octalCode,(float*)&startVertex); From 94bb6a1b0f3328548f6ddb6c26d9435286b347e8 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 27 Apr 2013 14:57:23 -0700 Subject: [PATCH 32/76] removed some testing/debug code --- interface/src/main.cpp | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 664da497ca..daeb983a32 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -1626,39 +1626,6 @@ int main(int argc, const char * argv[]) voxels_lib::printLog = & ::printLog; avatars_lib::printLog = & ::printLog; - // Quick test of the Orientation class on startup! - if (cmdOptionExists(argc, argv, "--testOrientation")) { - testOrientationClass(); - return EXIT_SUCCESS; - } - - // Quick test of sortedArrays helper - if (cmdOptionExists(argc, argv, "--testSortedArray")) { - void* values[8]; - float keys[8]; - int meta[8]; - int count = 0; - - count = insertIntoSortedArrays((void*)10, 10.0, 1, values, keys, meta, count, 8); - printf("after one insert...\n"); - for (int i=0; i Date: Sat, 27 Apr 2013 14:58:38 -0700 Subject: [PATCH 33/76] removed extra AgentList() constructor which got accidentally included in merge mistake --- interface/src/main.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index daeb983a32..e764e7ff98 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -1626,8 +1626,6 @@ int main(int argc, const char * argv[]) voxels_lib::printLog = & ::printLog; avatars_lib::printLog = & ::printLog; - AgentList::createInstance(AGENT_TYPE_AVATAR); - unsigned int listenPort = AGENT_SOCKET_LISTEN_PORT; const char* portStr = getCmdOption(argc, argv, "--listenPort"); if (portStr) { From e373a8b86663949cc53fe359a399837a68cdccb8 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 27 Apr 2013 14:59:58 -0700 Subject: [PATCH 34/76] removed accidentally added whitespace --- interface/src/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index e764e7ff98..2dc3022357 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -1632,7 +1632,6 @@ int main(int argc, const char * argv[]) listenPort = atoi(portStr); } AgentList::createInstance(AGENT_TYPE_AVATAR, listenPort); - enableNetworkThread = !cmdOptionExists(argc, argv, "--nonblocking"); if (!enableNetworkThread) { AgentList::getInstance()->getAgentSocket().setBlocking(false); From e55993abf10e9aecab765c826d591cd498f9d874 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 27 Apr 2013 15:04:08 -0700 Subject: [PATCH 35/76] removed accidental whitespace --- libraries/voxels/src/VoxelNode.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index a8c0a1e00b..4153f1ff88 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -40,6 +40,9 @@ public: bool isColored() const { return (_trueColor[3]==1); }; bool isInView(const ViewFrustum& viewFrustum) const; float distanceToCamera(const ViewFrustum& viewFrustum) const; + bool isLeaf() const; + void getAABox(AABox& box) const; + void printDebugDetails(const char* label) const; #ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color void setFalseColor(colorPart red, colorPart green, colorPart blue); @@ -56,12 +59,6 @@ public: const nodeColor& getTrueColor() const { return _trueColor; }; const nodeColor& getColor() const { return _trueColor; }; #endif - - bool isLeaf() const; - - void getAABox(AABox& box) const; - - void printDebugDetails(const char* label) const; }; #endif /* defined(__hifi__VoxelNode__) */ From 9d6c53a5350d49a654770c67071f98cd5fe9a56f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 27 Apr 2013 15:08:17 -0700 Subject: [PATCH 36/76] remove mutex locking from VoxelTree for now, isn't needed --- libraries/voxels/src/VoxelTree.cpp | 49 ------------------------------ libraries/voxels/src/VoxelTree.h | 2 -- 2 files changed, 51 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 669407cc4d..7513fd5e47 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -137,30 +137,20 @@ VoxelTree::VoxelTree() : rootNode = new VoxelNode(); rootNode->octalCode = new unsigned char[1]; *rootNode->octalCode = 0; - - //pthread_mutexattr_t mta; - //pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE); - //int res = pthread_mutex_init(&_treeNodeDelete, NULL); - //debugThreadError("pthread_mutex_init(&_treeNodeDelete, &mta);", res); } VoxelTree::~VoxelTree() { - //pthread_mutex_lock(&_treeNodeDelete); // delete the children of the root node // this recursively deletes the tree for (int i = 0; i < 8; i++) { delete rootNode->children[i]; } - //pthread_mutex_unlock(&_treeNodeDelete); - //pthread_mutex_destroy(&_treeNodeDelete); } // Recurses voxel tree calling the RecurseVoxelTreeOperation function for each node. // stops recursion if operation function returns false. void VoxelTree::recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData) { - //pthread_mutex_lock(&_treeNodeDelete); recurseNodeWithOperation(rootNode, operation,extraData); - //pthread_mutex_unlock(&_treeNodeDelete); } // Recurses voxel node with an operation function @@ -287,11 +277,6 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, } void VoxelTree::readBitstreamToTree(unsigned char * bitstream, int bufferSizeBytes) { - - //int mutexLock; - //mutexLock = pthread_mutex_lock(&_treeNodeDelete); - //debugThreadError("pthread_mutex_lock(&_treeNodeDelete)", mutexLock); - int bytesRead = 0; unsigned char* bitstreamAt = bitstream; @@ -322,7 +307,6 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, int bufferSizeByt this->voxelsBytesRead += bufferSizeBytes; this->voxelsBytesReadStats.updateAverage(bufferSizeBytes); - //pthread_mutex_unlock(&_treeNodeDelete); } // Note: uses the codeColorBuffer format, but the color's are ignored, because @@ -345,10 +329,8 @@ void VoxelTree::deleteVoxelCodeFromTree(unsigned char *codeBuffer) { int childNDX = branchIndexWithDescendant(parentNode->octalCode, codeBuffer); - //pthread_mutex_lock(&_treeNodeDelete); delete parentNode->children[childNDX]; // delete the child nodes parentNode->children[childNDX]=NULL; // set it to NULL - //pthread_mutex_unlock(&_treeNodeDelete); reaverageVoxelColors(rootNode); // Fix our colors!! Need to call it on rootNode } @@ -356,19 +338,14 @@ void VoxelTree::deleteVoxelCodeFromTree(unsigned char *codeBuffer) { } void VoxelTree::eraseAllVoxels() { - // XXXBHG Hack attack - is there a better way to erase the voxel tree? - - //pthread_mutex_lock(&_treeNodeDelete); delete rootNode; // this will recurse and delete all children rootNode = new VoxelNode(); rootNode->octalCode = new unsigned char[1]; *rootNode->octalCode = 0; - //pthread_mutex_unlock(&_treeNodeDelete); } void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) { - ////pthread_mutex_lock(&_treeNodeDelete); VoxelNode* lastCreatedNode = nodeForOctalCode(rootNode, codeColorBuffer, NULL); // create the node if it does not exist @@ -383,7 +360,6 @@ void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) { memcpy(newColor, codeColorBuffer + octalCodeBytes, 3); newColor[3] = 1; lastCreatedNode->setColor(newColor); - //pthread_mutex_unlock(&_treeNodeDelete); } unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, @@ -396,8 +372,6 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, unsigned char * stopOctalCode) { unsigned char * childStopOctalCode = NULL; - // could we make this tighter? - //pthread_mutex_lock(&_treeNodeDelete); static unsigned char *initialBitstreamPos = bitstreamBuffer; if (stopOctalCode == NULL) { @@ -458,7 +432,6 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, if ((bitstreamBuffer - initialBitstreamPos) + MAX_TREE_SLICE_BYTES > MAX_VOXEL_PACKET_SIZE) { // we can't send this packet, not enough room // return our octal code as the stop - //pthread_mutex_unlock(&_treeNodeDelete); return currentVoxelNode->octalCode; } @@ -639,14 +612,10 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, } } } - //pthread_mutex_unlock(&_treeNodeDelete); return childStopOctalCode; } void VoxelTree::processRemoveVoxelBitstream(unsigned char * bitstream, int bufferSizeBytes) { - // do we need to lock out tree mutex - //if (0 == pthread_mutex_lock(&_treeNodeDelete)) - // XXXBHG: validate buffer is at least 4 bytes long? other guards?? unsigned short int itemNumber = (*((unsigned short int*)&bitstream[1])); printLog("processRemoveVoxelBitstream() receivedBytes=%d itemNumber=%d\n",bufferSizeBytes,itemNumber); @@ -668,8 +637,6 @@ void VoxelTree::processRemoveVoxelBitstream(unsigned char * bitstream, int buffe } void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { - // could we make this tighter? - //pthread_mutex_lock(&_treeNodeDelete); int colorMask = 0; // create the color mask @@ -714,12 +681,9 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { } } } - //pthread_mutex_unlock(&_treeNodeDelete); } void VoxelTree::reaverageVoxelColors(VoxelNode *startNode) { - // could we make this tighter? - //pthread_mutex_lock(&_treeNodeDelete); // can't be recursed! bool hasChildren = false; for (int i = 0; i < 8; i++) { @@ -736,7 +700,6 @@ void VoxelTree::reaverageVoxelColors(VoxelNode *startNode) { startNode->setColorFromAverageOfChildren(); } } - //pthread_mutex_unlock(&_treeNodeDelete); } ////////////////////////////////////////////////////////////////////////////////////////// // Method: VoxelTree::loadVoxelsFile() @@ -790,10 +753,7 @@ void VoxelTree::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) { voxelData[lengthInBytes+1], voxelData[lengthInBytes+2], voxelData[lengthInBytes+3]); //printVoxelCode(voxelData); - //pthread_mutex_lock(&_treeNodeDelete); this->readCodeColorBufferToTree(voxelData); - //pthread_mutex_unlock(&_treeNodeDelete); - delete voxelData; } file.close(); @@ -980,16 +940,8 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrust // How many bytes have we written so far at this level; int bytesWritten = 0; - // could we make this tighter? - //pthread_mutex_lock(&_treeNodeDelete); - - // Some debugging code... where are we in the tree.. - //node->printDebugDetails("encodeTreeBitstream() node="); - // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! if (!node->isInView(viewFrustum)) { - //printf("encodeTreeBitstream() node NOT IN VIEW\n"); - //pthread_mutex_unlock(&_treeNodeDelete); return bytesWritten; } @@ -1021,7 +973,6 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrust //printf("encodeTreeBitstreamRecursion() no bytes below...\n"); bytesWritten = 0; } - //pthread_mutex_unlock(&_treeNodeDelete); return bytesWritten; } diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 24f25320b7..7274667605 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -81,8 +81,6 @@ private: VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode); VoxelNode* createMissingNode(VoxelNode* lastParentNode, unsigned char* deepestCodeToCreate); int readNodeData(VoxelNode *destinationNode, unsigned char* nodeData, int bufferSizeBytes); - - //pthread_mutex_t _treeNodeDelete; }; int boundaryDistanceForRenderLevel(unsigned int renderLevel); From c364ec0dc7a1eaa7b18aa1a9e2088c49a48550a2 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 27 Apr 2013 15:09:32 -0700 Subject: [PATCH 37/76] removed mutex locking from VoxelTree for now --- libraries/voxels/src/VoxelTree.cpp | 37 ------------------------------ 1 file changed, 37 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 7513fd5e47..eb54fc08eb 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -63,45 +63,8 @@ #include "ViewFrustum.h" #include // to load voxels from file -#include -#include - using voxels_lib::printLog; - -void debugThreadError(const char* message, int err) { - switch (err) { - case EINVAL: - printf("%s -> EINVAL\n",message); - break; - - case EBUSY: - printf("%s -> EBUSY\n",message); - break; - - case EAGAIN: - printf("%s -> EAGAIN\n",message); - break; - - case EDEADLK: - printf("%s -> EDEADLK\n",message); - break; - - case EPERM: - printf("%s -> EPERM\n",message); - break; - - case EINTR: - printf("%s -> EINTR\n",message); - break; - - default: - printf("%s -> %d\n",message,err); - break; - } - -} - int boundaryDistanceForRenderLevel(unsigned int renderLevel) { switch (renderLevel) { case 1: From 71555571270523673474c827a190490c0ea138c0 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 27 Apr 2013 15:13:24 -0700 Subject: [PATCH 38/76] removed some dead code --- libraries/voxels/src/VoxelTree.cpp | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index eb54fc08eb..02d57a0fd8 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -361,31 +361,7 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, powf(agentPosition[1] - thisNodePosition[1] - halfUnitForVoxel, 2) + powf(agentPosition[2] - thisNodePosition[2] - halfUnitForVoxel, 2)); - // If the voxel is outside of the view frustum, then don't bother sending or recursing - bool voxelInView = true; - - /**** not yet working properly at this level! ************************************************************************** - if (viewFrustumCulling) { - float fullUnitForVoxel = halfUnitForVoxel * 2.0f; - AABox voxelBox; - voxelBox.setBox(glm::vec3(thisNodePosition[0],thisNodePosition[1],thisNodePosition[2]), - fullUnitForVoxel,fullUnitForVoxel,fullUnitForVoxel); - - //printf("VoxelTree::loadBitstreamBuffer() voxelBox.corner=(%f,%f,%f) x=%f \n", - // voxelBox.getCorner().x,voxelBox.getCorner().y,voxelBox.getCorner().z, voxelBox.getSize().x); - - voxelInView = (ViewFrustum::OUTSIDE != viewFrustum.pointInFrustum(voxelBox.getCorner())); - } else { - voxelInView = true; - } - **********************************************************************************************************************/ - - // if the distance to this voxel's center is less than the threshold - // distance for its children, we should send the children - bool voxelIsClose = (distanceToVoxelCenter < boundaryDistanceForRenderLevel(*currentVoxelNode->octalCode + 1)); - bool sendVoxel = voxelIsClose && voxelInView; - - if (sendVoxel) { + if (distanceToVoxelCenter < boundaryDistanceForRenderLevel(*currentVoxelNode->octalCode + 1)) { // write this voxel's data if we're below or at // or at the same level as the stopOctalCode From 7fda49a5e1c64bd9dc6b48714989bf7e563f5dae Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 27 Apr 2013 15:17:59 -0700 Subject: [PATCH 39/76] removed some dead code --- libraries/voxels/src/VoxelTree.cpp | 46 ++++-------------------------- 1 file changed, 5 insertions(+), 41 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 02d57a0fd8..a7bb254fdc 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -407,49 +407,31 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, childPosition[2] *= TREE_SCALE; // scale it up float halfChildVoxel = powf(0.5, *childOctalCode) * (0.5 * TREE_SCALE); - //float distanceToChildCenter = sqrtf(powf(agentPosition[0] - childPosition[0] - halfChildVoxel, 2) + - // powf(agentPosition[1] - childPosition[1] - halfChildVoxel, 2) + - // powf(agentPosition[2] - childPosition[2] - halfChildVoxel, 2)); - float fullChildVoxel = halfChildVoxel * 2.0f; AABox childBox; childBox.setBox(glm::vec3(childPosition[0], childPosition[1], childPosition[2]), fullChildVoxel, fullChildVoxel, fullChildVoxel); - // XXXBHG - not sure we want to do this "distance/LOD culling" at this level. - //bool childIsClose = (distanceToChildCenter < boundaryDistanceForRenderLevel(*childOctalCode + 1)); - - bool childIsClose = true; // for now, assume we're close enough bool childInView = !viewFrustumCulling || (ViewFrustum::OUTSIDE != viewFrustum.boxInFrustum(childBox)); /// XXXBHG - debug code, switch this to true, and we'll send everything but include false coloring // on voxels based on whether or not they match these rules. bool falseColorInsteadOfCulling = false; + bool sendChild = childInView || falseColorInsteadOfCulling; - // removed childIsClose - until we determine if we want to include that - bool sendChild = (childInView) || falseColorInsteadOfCulling; - - // if we sendAnyway, we'll do false coloring of the voxels based on childIsClose && childInView + // if we sendAnyway, we'll do false coloring of the voxels based on childInView if (sendChild) { // copy in the childs color to bitstreamBuffer - if (childIsClose && childInView) { + if (childInView) { // true color memcpy(colorPointer, currentVoxelNode->children[i]->getTrueColor(), 3); } else { unsigned char red[3] = {255,0,0}; - unsigned char green[3] = {0,255,0}; - unsigned char blue[3] = {0,0,255}; - if (!childIsClose && !childInView) { - // If both too far, and not in view, color them red + if (!childInView) { + // If not in view, color them red memcpy(colorPointer, red, 3); - } else if (!childIsClose) { - // If too far, but in view, color them blue - memcpy(colorPointer, blue, 3); - } else { - // If close, but out of view, color them green - memcpy(colorPointer, green, 3); } } colorPointer += 3; @@ -495,24 +477,6 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, childNodePosition[1] *= TREE_SCALE; // scale it up childNodePosition[2] *= TREE_SCALE; // scale it up - /**** disabled ***************************************************************************************** - // Note: Stephen, I intentionally left this in so you would talk to me about it. Here's the deal, this - // code doesn't seem to work correctly. It returns X and Z flipped and the values are negative. Since - // we use the firstVertexForCode() function in VoxelSystem to calculate the child vertex and that DOES - // work, I've decided to use that function to calculate our position for LOD handling. - // - // calculate the child's position based on the parent position - for (int j = 0; j < 3; j++) { - childNodePosition[j] = thisNodePosition[j]; - - if (oneAtBit(branchIndexWithDescendant(currentVoxelNode->octalCode, - currentVoxelNode->children[i]->octalCode), - (7 - j))) { - childNodePosition[j] -= (powf(0.5, *currentVoxelNode->children[i]->octalCode) * TREE_SCALE); - } - } - **** disabled *****************************************************************************************/ - // ask the child to load the bitstream buffer with their data childStopOctalCode = loadBitstreamBuffer(bitstreamBuffer, currentVoxelNode->children[i], From 628b74b8e1e2765c31ba44e28f92105b05506b50 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 27 Apr 2013 15:21:40 -0700 Subject: [PATCH 40/76] removed some dead code --- libraries/voxels/src/VoxelTree.cpp | 58 ------------------------------ 1 file changed, 58 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index a7bb254fdc..c93dc7f6a9 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -560,7 +560,6 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { outputBits(startNode->children[j]->getTrueColor()[c],false); } startNode->children[j]->printDebugDetails(""); - //printf("\n"); } } @@ -888,10 +887,6 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrust int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& viewFrustum, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag) const { - - // Some debugging code... where are we in the tree.. - //node->printDebugDetails("encodeTreeBitstreamRecursion() node="); - // How many bytes have we written so far at this level; int bytesAtThisLevel = 0; @@ -931,18 +926,10 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& VoxelNode* childNode = node->children[i]; bool childExists = (childNode != NULL); - if (childExists) { - //childNode->printDebugDetails("encodeTreeBitstream() looping children"); - } - bool childIsColored = (childExists && childNode->isColored()); bool childIsInView = (childExists && childNode->isInView(viewFrustum)); bool childIsLeaf = (childExists && childNode->isLeaf()); - //printf("childExists=%s childIsColored=%s childIsInView=%s childIsLeaf=%s \n", - // (childExists ? "yes" : "no"), (childIsColored ? "yes" : "no"), - // (childIsInView ? "yes" : "no"), (childIsLeaf ? "yes" : "no") ); - if (childIsInView) { inViewCount++; @@ -961,16 +948,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& } } } - //printf("bhgLoadBitstream() child nodes in view... inViewCount=%d\n",inViewCount); - //printf("bhgLoadBitstream() child nodes in view with color... inViewWithColorCount=%d\n",inViewWithColorCount); - //printf("bhgLoadBitstream() child nodes in view NOT LEAF... inViewNotLeafCount=%d\n",inViewNotLeafCount); - - // write the child color bits - //printf("bhgLoadBitstream() writing child color bits="); - //outputBits(childrenColoredBits); - *writeToThisLevelBuffer = childrenColoredBits; - writeToThisLevelBuffer += sizeof(childrenColoredBits); // move the pointer bytesAtThisLevel += sizeof(childrenColoredBits); // keep track of byte count @@ -983,12 +961,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& bytesAtThisLevel += BYTES_PER_COLOR; // keep track of byte count for color } } - - //printf("inViewNotLeafCount=%d \n", inViewNotLeafCount ); - - //printf("bhgLoadBitstream() writing child trees exist bits="); - //outputBits(childrenExistBits); - // write the child exist bits *writeToThisLevelBuffer = childrenExistBits; @@ -1002,38 +974,26 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& // written at this level, and how many bytes we have available in the outputBuffer. If we can fit what we've got so far // and room for the no more children terminator, then let's write what we got so far. - //printf("availableBytes=%d bytesAtThisLevel=%d keepDiggingDeeper=%s \n", - // availableBytes, bytesAtThisLevel, (keepDiggingDeeper ? "yes" : "no") ); - // If we have enough room to copy our local results into the buffer, then do so... if (availableBytes >= bytesAtThisLevel) { memcpy(outputBuffer,&thisLevelBuffer[0],bytesAtThisLevel); outputBuffer += bytesAtThisLevel; availableBytes -= bytesAtThisLevel; - - //printf("actually write our local bytes to the outputBuffer bytesAtThisLevel=%d availableBytes=%d\n",bytesAtThisLevel, availableBytes); } else { // we've run out of room!!! What do we do!!! - //printf("we don't have room to write bytes bytesAtThisLevel=%d availableBytes=%d\n",bytesAtThisLevel, availableBytes); - // 1) return 0 for bytes written so upper levels do the right thing, namely prune us from their trees // 2) add our node to the list of extra nodes for later output... // Note: we don't do any termination for this level, we just return 0, then the upper level is in charge // of handling things. For example, in case of child iteration, it needs to unset the child exist bit for // this child. - // add our node the the list of extra nodes to output later... bag.insert(node); - return 0; } if (keepDiggingDeeper) { - - //printf("keepDiggingDeeper == TRUE... dig deeper!\n"); - // at this point, we need to iterate the children who are in view, even if not colored // and we need to determine if there's a deeper tree below them that we care about. // @@ -1050,9 +1010,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& if (oneAtBit(childrenExistBits, i)) { VoxelNode* childNode = node->children[i]; - - //printf("about to dig deeper child[%d] outputBuffer=%p, availableBytes=%d\n",i,outputBuffer,availableBytes); - int childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, viewFrustum, outputBuffer, availableBytes, bag); // if the child wrote 0 bytes, it means that nothing below exists or was in view, or we ran out of space, @@ -1072,7 +1029,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& // // we can make this act like no bytes out, by just resetting the bytes out in this case if (2 == childTreeBytesOut) { - //printf("after to dig deeper child[%d] childTreeBytesOut was 2, we're resetting to 0\n",i); childTreeBytesOut = 0; // this is the degenerate case of a tree with no colors and no child trees } @@ -1080,33 +1036,19 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& availableBytes -= childTreeBytesOut; outputBuffer += childTreeBytesOut; - //printf("after dig deeper child[%d] childTreeBytesOut=%d outputBuffer=%p, availableBytes=%d\n", - // i,childTreeBytesOut, outputBuffer, availableBytes); - // If we had previously started writing, and if the child DIDN'T write any bytes, // then we want to remove their bit from the childExistsPlaceHolder bitmask if (0 == childTreeBytesOut) { - - //printf("bhgLoadBitstream() child %d didn't write bytes, removing from bitmask\n",i ); - // remove this child's bit... childrenExistBits -= (1 << (7 - i)); // repair the child exists mask *childExistsPlaceHolder = childrenExistBits; - // Note: no need to move the pointer, cause we already stored this - } // end if (0 == childTreeBytesOut) - } // end if (oneAtBit(childrenExistBits, i)) } // end for - } // end keepDiggingDeeper - - - //printf("bhgLoadBitstream() at bottom, returning... bytesAtThisLevel=%d\n",bytesAtThisLevel ); - return bytesAtThisLevel; } From 2f9c3da914a178588b47b7eb4d453d1fdace332e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 27 Apr 2013 15:22:50 -0700 Subject: [PATCH 41/76] removed some dead code --- libraries/voxels/src/VoxelTree.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 7274667605..86b2c40d5e 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -9,8 +9,6 @@ #ifndef __hifi__VoxelTree__ #define __hifi__VoxelTree__ -#include - #include "SimpleMovingAverage.h" #include "ViewFrustum.h" From 0ebf3395626787eda33258890888795e3fae91f4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 27 Apr 2013 15:25:44 -0700 Subject: [PATCH 42/76] removed some dead code --- voxel-server/src/main.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index c03b0749cb..d1363afb2e 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -157,12 +157,7 @@ void eraseVoxelTreeAndCleanupAgentVisitData() { void newDistributeHelper(AgentList* agentList, AgentList::iterator& agent, VoxelAgentData* agentData, ViewFrustum& viewFrustum) { // If we don't have nodes already in our agent's node bag, then fill the node bag if (agentData->nodeBag.isEmpty()) { - - printf("agent calling searchForColoredNodes()\n"); randomTree.searchForColoredNodes(randomTree.rootNode, viewFrustum, agentData->nodeBag); - - // this would add the whole tree - //agentData->nodeBag.insert(randomTree.rootNode); } // If we have something in our nodeBag, then turn them into packets and send them out... @@ -193,10 +188,6 @@ void newDistributeHelper(AgentList* agentList, AgentList::iterator& agent, Voxel // keep track that we sent it packetsSentThisInterval++; - //printf("main loop send... this packetSize=%d packetsSentThisInterval=%d \n", - // agentData->getPacketLength(), packetsSentThisInterval); - //outputBufferBits((unsigned char*)agentData->getPacket(), agentData->getPacketLength(), true); - // reset our finalOutputBuffer (keep the 'V') agentData->resetVoxelPacket(); @@ -210,10 +201,6 @@ void newDistributeHelper(AgentList* agentList, AgentList::iterator& agent, Voxel agentList->getAgentSocket().send(agent->getActiveSocket(), agentData->getPacket(), agentData->getPacketLength()); - //printf("isPacketWaiting() send... this packetSize=%d packetsSentThisInterval=%d \n", - // agentData->getPacketLength(), packetsSentThisInterval); - //outputBufferBits((unsigned char*)agentData->getPacket(), agentData->getPacketLength(), true); - // reset our finalOutputBuffer (keep the 'V') agentData->resetVoxelPacket(); } From 7c180c800f13a45e7ede34fd21f55c9cc0e1e280 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 29 Apr 2013 06:28:19 -0700 Subject: [PATCH 43/76] printf/pringLog cleanup --- interface/src/VoxelSystem.cpp | 41 ++++----------------------- libraries/voxels/src/VoxelNode.cpp | 7 +++-- libraries/voxels/src/VoxelNodeBag.cpp | 4 --- libraries/voxels/src/VoxelTree.cpp | 11 +------ 4 files changed, 11 insertions(+), 52 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 21b3ab6625..e194df403b 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -372,13 +372,7 @@ bool VoxelSystem::randomColorOperation(VoxelNode* node, bool down, void* extraDa newColor[0] = randomColorValue(150); newColor[1] = randomColorValue(150); newColor[1] = randomColorValue(150); - - //printf("randomize color node %d was %x,%x,%x NOW %x,%x,%x\n", - // _nodeCount,node->getTrueColor()[0],node->getTrueColor()[1],node->getTrueColor()[2], - // newColor[0],newColor[1],newColor[2]); node->setColor(newColor); - } else { - //printf("not randomizing color node of %d since it has no color\n",_nodeCount); } return true; } @@ -386,7 +380,7 @@ bool VoxelSystem::randomColorOperation(VoxelNode* node, bool down, void* extraDa void VoxelSystem::randomizeVoxelColors() { _nodeCount = 0; tree->recurseTreeWithOperation(randomColorOperation); - printf("setting randomized true color for %d nodes\n",_nodeCount); + printLog("setting randomized true color for %d nodes\n",_nodeCount); setupNewVoxelsForDrawing(); } @@ -403,10 +397,6 @@ bool VoxelSystem::falseColorizeRandomOperation(VoxelNode* node, bool down, void* unsigned char newR = randomColorValue(150); unsigned char newG = randomColorValue(150); unsigned char newB = randomColorValue(150); - - printf("randomize FALSE color node %d was %x,%x,%x NOW %x,%x,%x\n", - _nodeCount,node->getTrueColor()[0],node->getTrueColor()[1],node->getTrueColor()[2], - newR,newG,newB); node->setFalseColor(newR,newG,newB); return true; // keep going! @@ -415,7 +405,7 @@ bool VoxelSystem::falseColorizeRandomOperation(VoxelNode* node, bool down, void* void VoxelSystem::falseColorizeRandom() { _nodeCount = 0; tree->recurseTreeWithOperation(falseColorizeRandomOperation); - printf("setting randomized false color for %d nodes\n",_nodeCount); + printLog("setting randomized false color for %d nodes\n",_nodeCount); setupNewVoxelsForDrawing(); } @@ -428,14 +418,13 @@ bool VoxelSystem::trueColorizeOperation(VoxelNode* node, bool down, void* extraD _nodeCount++; node->setFalseColored(false); - //printf("setting true color for node %d\n",_nodeCount); return true; } void VoxelSystem::trueColorize() { _nodeCount = 0; tree->recurseTreeWithOperation(trueColorizeOperation); - printf("setting true color for %d nodes\n",_nodeCount); + printLog("setting true color for %d nodes\n",_nodeCount); setupNewVoxelsForDrawing(); } @@ -459,9 +448,6 @@ bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, bool down, void* unsigned char newR = 255; unsigned char newG = 0; unsigned char newB = 0; - - //printf("voxel OUTSIDE view - FALSE colorizing node %d TRUE color is %x,%x,%x \n", - // _nodeCount,node->getTrueColor()[0],node->getTrueColor()[1],node->getTrueColor()[2]); node->setFalseColor(newR,newG,newB); } } @@ -472,15 +458,13 @@ bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, bool down, void* void VoxelSystem::falseColorizeInView(ViewFrustum* viewFrustum) { _nodeCount = 0; tree->recurseTreeWithOperation(falseColorizeInViewOperation,(void*)viewFrustum); - printf("setting in view false color for %d nodes\n",_nodeCount); + printLog("setting in view false color for %d nodes\n",_nodeCount); setupNewVoxelsForDrawing(); } // Will false colorize voxels based on distance from view bool VoxelSystem::falseColorizeDistanceFromViewOperation(VoxelNode* node, bool down, void* extraData) { - //printf("falseColorizeDistanceFromViewOperation() down=%s\n",(down ? "TRUE" : "FALSE")); - // we do our operations on the way up! if (down) { return true; @@ -505,10 +489,6 @@ bool VoxelSystem::falseColorizeDistanceFromViewOperation(VoxelNode* node, bool d float halfUnitForVoxel = powf(0.5, *node->octalCode) * (0.5 * TREE_SCALE); glm::vec3 viewerPosition = viewFrustum->getPosition(); - //printf("halfUnitForVoxel=%f\n",halfUnitForVoxel); - //printf("viewer.x=%f y=%f z=%f \n", viewerPosition.x, viewerPosition.y, viewerPosition.z); - //printf("node.x=%f y=%f z=%f \n", nodePosition.x, nodePosition.y, nodePosition.z); - float distance = sqrtf(powf(viewerPosition.x - nodePosition.x - halfUnitForVoxel, 2) + powf(viewerPosition.y - nodePosition.y - halfUnitForVoxel, 2) + powf(viewerPosition.z - nodePosition.z - halfUnitForVoxel, 2)); @@ -526,12 +506,7 @@ bool VoxelSystem::falseColorizeDistanceFromViewOperation(VoxelNode* node, bool d unsigned char newR = (colorBand*(gradientOver/colorBands))+(maxColor-gradientOver); unsigned char newG = 0; unsigned char newB = 0; - //printf("Setting color down=%s distance=%f min=%f max=%f distanceRatio=%f color=%d \n", - // (down ? "TRUE" : "FALSE"), distance, _minDistance, _maxDistance, distanceRatio, (int)newR); - node->setFalseColor(newR,newG,newB); - } else { - //printf("voxel not colored, don't consider it - down=%s\n",(down ? "TRUE" : "FALSE")); } return true; // keep going! } @@ -549,8 +524,6 @@ bool VoxelSystem::getDistanceFromViewRangeOperation(VoxelNode* node, bool down, return true; } - //printf("getDistanceFromViewRangeOperation() down=%s\n",(down ? "TRUE" : "FALSE")); - ViewFrustum* viewFrustum = (ViewFrustum*) extraData; // only do this for truly colored voxels... @@ -577,11 +550,9 @@ bool VoxelSystem::getDistanceFromViewRangeOperation(VoxelNode* node, bool down, // on way down, calculate the range of distances if (distance > _maxDistance) { _maxDistance = distance; - //printf("new maxDistance=%f down=%s\n",_maxDistance, (down ? "TRUE" : "FALSE")); } if (distance < _minDistance) { _minDistance = distance; - //printf("new minDistance=%f down=%s\n",_minDistance, (down ? "TRUE" : "FALSE")); } _nodeCount++; @@ -595,11 +566,11 @@ void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) { _maxDistance = 0.0; _minDistance = FLT_MAX; tree->recurseTreeWithOperation(getDistanceFromViewRangeOperation,(void*)viewFrustum); - printf("determining distance range for %d nodes\n",_nodeCount); + printLog("determining distance range for %d nodes\n",_nodeCount); _nodeCount = 0; tree->recurseTreeWithOperation(falseColorizeDistanceFromViewOperation,(void*)viewFrustum); - printf("setting in distance false color for %d nodes\n",_nodeCount); + printLog("setting in distance false color for %d nodes\n",_nodeCount); setupNewVoxelsForDrawing(); } diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 6ef82d9ea0..de0940a0ee 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -10,11 +10,13 @@ #include #include #include "SharedUtil.h" -//#include "voxels_Log.h" +#include "voxels_Log.h" #include "VoxelNode.h" #include "OctalCode.h" #include "AABox.h" +using voxels_lib::printLog; + // using voxels_lib::printLog; VoxelNode::VoxelNode() { @@ -119,7 +121,6 @@ void VoxelNode::setFalseColored(bool isFalseColored) { void VoxelNode::setColor(const nodeColor& color) { - //printf("VoxelNode::setColor() isFalseColored=%s\n",_falseColored ? "Yes" : "No"); memcpy(&_trueColor,&color,sizeof(nodeColor)); if (!_falseColored) { memcpy(&_currentColor,&color,sizeof(nodeColor)); @@ -194,7 +195,7 @@ bool VoxelNode::isLeaf() const { void VoxelNode::printDebugDetails(const char* label) const { AABox box; getAABox(box); - printf("%s - Voxel at corner=(%f,%f,%f) size=%f octcode=",label, + printLog("%s - Voxel at corner=(%f,%f,%f) size=%f octcode=",label, box.getCorner().x, box.getCorner().y, box.getCorner().z,box.getSize().x); printOctalCode(octalCode); } diff --git a/libraries/voxels/src/VoxelNodeBag.cpp b/libraries/voxels/src/VoxelNodeBag.cpp index e1a612432d..370b2dac02 100644 --- a/libraries/voxels/src/VoxelNodeBag.cpp +++ b/libraries/voxels/src/VoxelNodeBag.cpp @@ -88,10 +88,6 @@ VoxelNode* VoxelNodeBag::extract() { // reduce the count _elementsInUse--; - // debug!! - //printf("VoxelNodeBag::extract() node="); - //node->printDebugDetails(""); - return node; } return NULL; diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index c93dc7f6a9..b1f1d3e0a1 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -555,7 +555,7 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { // output the colors we have for (int j = 0; j < 8; j++) { if (startNode->children[j] != NULL && startNode->children[j]->isColored()) { - printf("color %d : ",j); + printLog("color %d : ",j); for (int c = 0; c < 3; c++) { outputBits(startNode->children[j]->getTrueColor()[c],false); } @@ -780,10 +780,6 @@ void VoxelTree::searchForColoredNodesRecursion(VoxelNode* node, const ViewFrustu bool childIsInView = (childExists && childNode->isInView(viewFrustum)); bool childIsLeaf = (childExists && childNode->isLeaf()); - //printf("childExists=%s childIsColored=%s childIsInView=%s childIsLeaf=%s \n", - // (childExists ? "yes" : "no"), (childIsColored ? "yes" : "no"), - // (childIsInView ? "yes" : "no"), (childIsLeaf ? "yes" : "no") ); - if (childIsInView) { // track children in view as existing and not a leaf @@ -798,8 +794,6 @@ void VoxelTree::searchForColoredNodesRecursion(VoxelNode* node, const ViewFrustu float distance = childNode->distanceToCamera(viewFrustum); - //printf("child[%d] distance=%f\n",i,distance); - inViewCount = insertIntoSortedArrays((void*)childNode, distance, i, (void**)&inViewChildren, (float*)&distancesToChildren, (int*)&positionOfChildren, inViewCount, MAX_CHILDREN); @@ -872,7 +866,6 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrust bytesWritten += childBytesWritten; } else { // otherwise... if we didn't write any child bytes, then pretend like we also didn't write our octal code - //printf("encodeTreeBitstreamRecursion() no bytes below...\n"); bytesWritten = 0; } return bytesWritten; @@ -894,7 +887,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& // although technically, we really shouldn't ever be here, because our callers shouldn't be calling us if // we're out of view if (!node->isInView(viewFrustum)) { - //printf("encodeTreeBitstreamRecursion() node NOT IN VIEW\n"); return bytesAtThisLevel; } @@ -955,7 +947,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& // write the color data... for (int i = 0; i < MAX_CHILDREN; i++) { if (oneAtBit(childrenColoredBits, i)) { - //printf("bhgLoadBitstream() writing color for child %d\n",i); memcpy(writeToThisLevelBuffer,&node->children[i]->getColor(),BYTES_PER_COLOR); writeToThisLevelBuffer += BYTES_PER_COLOR; // move the pointer for color bytesAtThisLevel += BYTES_PER_COLOR; // keep track of byte count for color From 78e8751a792f97bebb6e154e2602e3a59e64cc53 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 29 Apr 2013 06:31:06 -0700 Subject: [PATCH 44/76] use constant for 'V' header --- voxel-server/src/VoxelAgentData.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/voxel-server/src/VoxelAgentData.cpp b/voxel-server/src/VoxelAgentData.cpp index 3db302f74f..a86b25b78d 100644 --- a/voxel-server/src/VoxelAgentData.cpp +++ b/voxel-server/src/VoxelAgentData.cpp @@ -6,6 +6,7 @@ // // +#include "PacketHeaders.h" #include "VoxelAgentData.h" #include #include @@ -23,7 +24,7 @@ void VoxelAgentData::init() { } void VoxelAgentData::resetVoxelPacket() { - _voxelPacket[0] = 'V'; + _voxelPacket[0] = PACKET_HEADER_VOXEL_DATA; _voxelPacketAt = &_voxelPacket[1]; _voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE-1; _voxelPacketWaiting = false; From 781721b79cdee639fae4ca1322a6fa8d55d353f2 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 29 Apr 2013 06:49:57 -0700 Subject: [PATCH 45/76] clean up constants for voxels --- interface/src/VoxelSystem.cpp | 7 +------ libraries/voxels/src/VoxelNode.cpp | 2 +- libraries/voxels/src/VoxelNode.h | 3 --- libraries/voxels/src/VoxelTree.cpp | 1 + libraries/voxels/src/VoxelTree.h | 3 --- voxel-server/src/VoxelAgentData.h | 2 +- voxel-server/src/main.cpp | 3 --- 7 files changed, 4 insertions(+), 17 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index e194df403b..b018bd1f96 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -18,15 +18,10 @@ #include #include #include "Log.h" +#include "VoxelConstants.h" #include "VoxelSystem.h" -const int MAX_VOXELS_PER_SYSTEM = 250000; - -const int VERTICES_PER_VOXEL = 24; -const int VERTEX_POINTS_PER_VOXEL = 3 * VERTICES_PER_VOXEL; -const int INDICES_PER_VOXEL = 3 * 12; - float identityVertices[] = { 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1, 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1, 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1 }; diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index de0940a0ee..6129f9c16c 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -12,9 +12,9 @@ #include "SharedUtil.h" #include "voxels_Log.h" #include "VoxelNode.h" +#include "VoxelConstants.h" #include "OctalCode.h" #include "AABox.h" - using voxels_lib::printLog; // using voxels_lib::printLog; diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 4153f1ff88..4cda55f8a7 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -15,9 +15,6 @@ typedef unsigned char colorPart; typedef unsigned char nodeColor[4]; -const int TREE_SCALE = 10; - - class VoxelNode { private: nodeColor _trueColor; diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index b1f1d3e0a1..615f63df47 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -62,6 +62,7 @@ #include "VoxelNodeBag.h" #include "ViewFrustum.h" #include // to load voxels from file +#include "VoxelConstants.h" using voxels_lib::printLog; diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 86b2c40d5e..05d6d39062 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -16,9 +16,6 @@ #include "VoxelNodeBag.h" #include "MarkerNode.h" -const int MAX_VOXEL_PACKET_SIZE = 1492; -const int MAX_TREE_SLICE_BYTES = 26; - // Callback function, for recuseTreeWithOperation typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, bool down, void* extraData); diff --git a/voxel-server/src/VoxelAgentData.h b/voxel-server/src/VoxelAgentData.h index 3e3569379a..56d9ebf03e 100644 --- a/voxel-server/src/VoxelAgentData.h +++ b/voxel-server/src/VoxelAgentData.h @@ -14,7 +14,7 @@ #include #include "MarkerNode.h" #include "VoxelNodeBag.h" -#include "VoxelTree.h" // for MAX_VOXEL_PACKET_SIZE +#include "VoxelConstants.h" class VoxelAgentData : public AvatarData { public: diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index d1363afb2e..30eef7835f 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -29,9 +29,6 @@ const int VOXEL_LISTEN_PORT = 40106; -const int VERTICES_PER_VOXEL = 8; -const int VERTEX_POINTS_PER_VOXEL = 3 * VERTICES_PER_VOXEL; -const int COLOR_VALUES_PER_VOXEL = 3 * VERTICES_PER_VOXEL; const int VOXEL_SIZE_BYTES = 3 + (3 * sizeof(float)); const int VOXELS_PER_PACKET = (MAX_PACKET_SIZE - 1) / VOXEL_SIZE_BYTES; From e7296e1851b396b6a091766d397a209992285f2e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 29 Apr 2013 08:00:31 -0700 Subject: [PATCH 46/76] made tempOutputBuffer static, added some comments --- voxel-server/src/main.cpp | 43 ++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 30eef7835f..15d71aa504 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -152,14 +152,46 @@ void eraseVoxelTreeAndCleanupAgentVisitData() { void newDistributeHelper(AgentList* agentList, AgentList::iterator& agent, VoxelAgentData* agentData, ViewFrustum& viewFrustum) { + + // A quick explanation of the strategy here. First, each time through, we ask ourselves, do we have voxels + // that need to be sent? If not, we search for them, if we do, then we send them. We store our to be sent voxel sub trees + // in a VoxelNodeBag on a per agent basis. The bag stores just pointers to the root node of the sub tree to be sent, so + // it doesn't store much on a per agent basis. + // + // There could be multiple strategies at play for how we determine which voxels need to be sent. For example, at the + // simplest level, we can just add the root node to this bag, and let the system send it. The other thing that we use + // this bag for is, keeping track of voxels sub trees we wanted to send in the packet, but wouldn't fit into the current + // packet because they were too big once encoded. So, as we run though this function multiple times, we start out with + // voxel sub trees that we determined needed to be sent because they were in view, new, correct distance, etc. But as + // we send those sub trees, if their child trees don't fit in a packet, we'll add those sub trees to this bag as well, and + // next chance we get, we'll also send those needed sub trees. // If we don't have nodes already in our agent's node bag, then fill the node bag if (agentData->nodeBag.isEmpty()) { + + // To get things started, we look for colored nodes. We could have also just started with the root node. In fact, if + // you substitute this call with something as simple as agentData->nodeBag.insert(rootNod), you'll see almost the same + // behavior on the client. The scene will appear. + // + // So why do we do this extra effort to look for colored nodes? It turns out that there are subtle differences between + // how many bytes it takes to encode a tree based on how deep it is relative to the root node (which effects the octal + // code size) vs how dense the tree is (which effects how many bits in the bitMask are being wasted, and maybe more + // importantly, how many subtrees are also included). There is a break point where the more dense a tree is, it's more + // efficient to encode the peers together with their empty parents. This would argue that we shouldn't search for these + // sub trees, and we should instead encode the parent for dense scenes. + // + // But, there's another important side effect of dense trees related to out maximum packet size. Namely... if a tree + // is very dense, then you can't fit as many branches in a single network packet. Because when we encode the parent and + // children in a single packet, we must include the entire child branch (all the way down to our target LOD) before we + // can include the siblings. Since dense trees take more space per ranch, we often end up only being able to encode a + // single branch. This means on a per packet basis, the trees actually _are not_ dense. And sparse trees are shorter to + // encode when we only include the child tree. randomTree.searchForColoredNodes(randomTree.rootNode, viewFrustum, agentData->nodeBag); } // If we have something in our nodeBag, then turn them into packets and send them out... if (!agentData->nodeBag.isEmpty()) { - unsigned char* tempOutputBuffer = new unsigned char[MAX_VOXEL_PACKET_SIZE-1]; // save 1 for "V" in final + + static unsigned char tempOutputBuffer[MAX_VOXEL_PACKET_SIZE-1]; // save on allocs by making this static int bytesWritten = 0; // NOTE: we can assume the voxelPacket has already been set up with a "V" @@ -172,11 +204,11 @@ void newDistributeHelper(AgentList* agentList, AgentList::iterator& agent, Voxel // Only let this guy create at largest packets equal to the amount of space we have left in our final??? // Or let it create the largest possible size (minus 1 for the "V") bytesWritten = randomTree.encodeTreeBitstream(subTree, viewFrustum, - tempOutputBuffer, MAX_VOXEL_PACKET_SIZE-1, agentData->nodeBag); + &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE-1, agentData->nodeBag); // if we have room in our final packet, add this buffer to the final packet if (agentData->getAvailable() >= bytesWritten) { - agentData->writeToPacket(tempOutputBuffer, bytesWritten); + agentData->writeToPacket(&tempOutputBuffer[0], bytesWritten); } else { // otherwise "send" the packet because it's as full as we can make it for now agentList->getAgentSocket().send(agent->getActiveSocket(), @@ -189,7 +221,7 @@ void newDistributeHelper(AgentList* agentList, AgentList::iterator& agent, Voxel agentData->resetVoxelPacket(); // we also need to stick the last created partial packet in here!! - agentData->writeToPacket(tempOutputBuffer, bytesWritten); + agentData->writeToPacket(&tempOutputBuffer[0], bytesWritten); } } else { // we're here, if there are no more nodes in our bag waiting to be sent. @@ -208,9 +240,6 @@ void newDistributeHelper(AgentList* agentList, AgentList::iterator& agent, Voxel packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; } } - - // end - delete[] tempOutputBuffer; } } From fe9ab0a2136032905af7f06197a38bb2bdf726c8 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 29 Apr 2013 14:11:33 -0700 Subject: [PATCH 47/76] improved collisions --- interface/src/Avatar.cpp | 144 +++++++++++++++----------- interface/src/Avatar.h | 188 ++++++++++++++++------------------ interface/src/AvatarTouch.cpp | 6 +- interface/src/AvatarTouch.h | 2 + 4 files changed, 177 insertions(+), 163 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 24af81dfdf..21fa44e651 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -109,8 +109,6 @@ Avatar::Avatar(bool isMine) { _head.noise = 0; _movedHandOffset = glm::vec3( 0.0, 0.0, 0.0 ); _usingBodySprings = true; - _springForce = 6.0f; - _springVelocityDecay = 16.0f; _renderYaw = 0.0; _renderPitch = 0.0; _sphere = NULL; @@ -156,8 +154,6 @@ Avatar::Avatar(const Avatar &otherAvatar) { _TEST_bigSpherePosition = otherAvatar._TEST_bigSpherePosition; _movedHandOffset = otherAvatar._movedHandOffset; _usingBodySprings = otherAvatar._usingBodySprings; - _springForce = otherAvatar._springForce; - _springVelocityDecay = otherAvatar._springVelocityDecay; _orientation.set( otherAvatar._orientation ); _sphere = NULL; @@ -293,6 +289,7 @@ void Avatar::setMousePressed( bool d ) { _mousePressed = d; } + void Avatar::simulate(float deltaTime) { // update balls @@ -318,14 +315,13 @@ void Avatar::simulate(float deltaTime) { float closestDistance = 10000.0f; AgentList* agentList = AgentList::getInstance(); - for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) { Avatar *otherAvatar = (Avatar *)agent->getLinkedData(); // check for collisions with other avatars and respond updateCollisionWithOtherAvatar(otherAvatar, deltaTime ); - + // test other avatar hand position for proximity glm::vec3 v( _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position ); v -= otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_HAND ); @@ -419,10 +415,24 @@ void Avatar::simulate(float deltaTime) { // decay velocity _velocity *= ( 1.0 - LIN_VEL_DECAY * deltaTime ); - // - // Update Head information - // + // update head information + updateHead(deltaTime); + // calculate speed, and use that to determine walking vs. standing + _speed = glm::length( _velocity ); + float rotationalSpeed = fabs( _bodyYawDelta ); + + if ( _speed + rotationalSpeed > 0.2 ) { + _mode = AVATAR_MODE_WALKING; + } else { + _mode = AVATAR_MODE_INTERACTING; + } +} + + + + +void Avatar::updateHead(float deltaTime) { if (!_head.noise) { // Decay back toward center _headPitch *= (1.0f - DECAY * 2 * deltaTime); @@ -515,17 +525,12 @@ void Avatar::simulate(float deltaTime) { const float AUDIO_AVERAGING_SECS = 0.05; _head.averageLoudness = (1.f - deltaTime / AUDIO_AVERAGING_SECS) * _head.averageLoudness + (deltaTime / AUDIO_AVERAGING_SECS) * _audioLoudness; - - _speed = glm::length( _velocity ); - float rotationalSpeed = fabs( _bodyYawDelta ); - - if ( _speed + rotationalSpeed > 0.2 ) { - _mode = AVATAR_MODE_WALKING; - } else { - _mode = AVATAR_MODE_INTERACTING; - } } + + + + float Avatar::getHeight() { return _height; } @@ -539,23 +544,21 @@ void Avatar::updateCollisionWithSphere( glm::vec3 position, float radius, float float distanceToBigSphere = glm::length(vectorFromMyBodyToBigSphere); if ( distanceToBigSphere < myBodyApproximateBoundingRadius + radius ) { for (int b = 0; b < NUM_AVATAR_BONES; b++) { - if ( _bone[b].isCollidable ) { - glm::vec3 vectorFromJointToBigSphereCenter(_bone[b].springyPosition - position); - float distanceToBigSphereCenter = glm::length(vectorFromJointToBigSphereCenter); - float combinedRadius = _bone[b].radius + radius; - - if ( distanceToBigSphereCenter < combinedRadius ) { - jointCollision = true; - if (distanceToBigSphereCenter > 0.0) { - glm::vec3 directionVector = vectorFromJointToBigSphereCenter / distanceToBigSphereCenter; - - float penetration = 1.0 - (distanceToBigSphereCenter / combinedRadius); - glm::vec3 collisionForce = vectorFromJointToBigSphereCenter * penetration; - - _bone[b].springyVelocity += collisionForce * 30.0f * deltaTime; - _velocity += collisionForce * 100.0f * deltaTime; - _bone[b].springyPosition = position + directionVector * combinedRadius; - } + glm::vec3 vectorFromJointToBigSphereCenter(_bone[b].springyPosition - position); + float distanceToBigSphereCenter = glm::length(vectorFromJointToBigSphereCenter); + float combinedRadius = _bone[b].radius + radius; + + if ( distanceToBigSphereCenter < combinedRadius ) { + jointCollision = true; + if (distanceToBigSphereCenter > 0.0) { + glm::vec3 directionVector = vectorFromJointToBigSphereCenter / distanceToBigSphereCenter; + + float penetration = 1.0 - (distanceToBigSphereCenter / combinedRadius); + glm::vec3 collisionForce = vectorFromJointToBigSphereCenter * penetration; + + _bone[b].springyVelocity += collisionForce * 30.0f * deltaTime; + _velocity += collisionForce * 100.0f * deltaTime; + _bone[b].springyPosition = position + directionVector * combinedRadius; } } } @@ -577,40 +580,63 @@ void Avatar::updateCollisionWithOtherAvatar( Avatar * otherAvatar, float deltaTi glm::vec3 vectorBetweenBoundingSpheres(_position - otherAvatar->_position); if ( glm::length(vectorBetweenBoundingSpheres) < _height * ONE_HALF + otherAvatar->_height * ONE_HALF ) { + float bodyMomentum = 1.0f; + glm::vec3 bodyPushForce = glm::vec3( 0.0, 0.0, 0.0 ); + // loop through the bones of each avatar to check for every possible collision for (int b=1; b_bone[o].isCollidable ) { glm::vec3 vectorBetweenJoints(_bone[b].springyPosition - otherAvatar->_bone[o].springyPosition); float distanceBetweenJoints = glm::length(vectorBetweenJoints); - - // to avoid divide by zero - if ( distanceBetweenJoints > 0.0 ) { + + if ( distanceBetweenJoints > 0.0 ) { // to avoid divide by zero float combinedRadius = _bone[b].radius + otherAvatar->_bone[o].radius; // check for collision if ( distanceBetweenJoints < combinedRadius * COLLISION_RADIUS_SCALAR) { glm::vec3 directionVector = vectorBetweenJoints / distanceBetweenJoints; - // push ball away from colliding other ball and puch avatar body (_velocity) as well - _bone[b].springyVelocity += directionVector * COLLISION_BALL_FORCE * deltaTime; - _velocity += directionVector * COLLISION_BODY_FORCE * deltaTime; + // push balls away from each other and apply friction + glm::vec3 ballPushForce = directionVector * COLLISION_BALL_FORCE * deltaTime; + + + float ballMomentum = COLLISION_BALL_FRICTION * deltaTime; + if ( ballMomentum < 0.0 ) { ballMomentum = 0.0;} + + + _bone[b].springyVelocity += ballPushForce; + otherAvatar->_bone[o].springyVelocity -= ballPushForce; - // apply fruction to _velocity - float momentum = 1.0 - COLLISION_FRICTION * deltaTime; - if ( momentum < 0.0 ) { momentum = 0.0;} - _velocity *= momentum; - } - } - } - } - } - } - } -} + _bone[b].springyVelocity *= 0.9; + otherAvatar->_bone[o].springyVelocity *= 0.9; + + // accumulate forces and frictions to the velocities of avatar bodies + bodyPushForce += directionVector * COLLISION_BODY_FORCE * deltaTime; + bodyMomentum -= COLLISION_BODY_FRICTION * deltaTime; + if ( bodyMomentum < 0.0 ) { bodyMomentum = 0.0;} + + }// check for collision + } // to avoid divide by zero + } // o loop + } // collidable + } // b loop + } // collidable + + + //apply forces and frictions on the bodies of both avatars + _velocity += bodyPushForce; + otherAvatar->_velocity -= bodyPushForce; + _velocity *= bodyMomentum; + otherAvatar->_velocity *= bodyMomentum; + + } // bounding sphere collision +} //method + + void Avatar::setDisplayingHead( bool displayingHead ) { @@ -1069,20 +1095,20 @@ void Avatar::updateBodySprings( float deltaTime ) { if ( length > 0.0f ) { glm::vec3 springDirection = springVector / length; - float force = ( length - _bone[b].length ) * _springForce * deltaTime; + float force = (length - _bone[b].length) * BODY_SPRING_FORCE * deltaTime; _bone[b].springyVelocity -= springDirection * force; if ( _bone[b].parent != AVATAR_BONE_NULL ) { - _bone[ _bone[b].parent ].springyVelocity += springDirection * force; + _bone[_bone[b].parent].springyVelocity += springDirection * force; } } - _bone[b].springyVelocity += ( _bone[b].position - _bone[b].springyPosition ) * _bone[b].springBodyTightness * deltaTime; + _bone[b].springyVelocity += (_bone[b].position - _bone[b].springyPosition) * _bone[b].springBodyTightness * deltaTime; - float decay = 1.0 - _springVelocityDecay * deltaTime; + float decay = 1.0 - BODY_SPRING_DECAY * deltaTime; - if ( decay > 0.0 ) { + if (decay > 0.0) { _bone[b].springyVelocity *= decay; } else { diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 8f5a7fe41d..0f252af378 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -9,36 +9,16 @@ #ifndef __interface__avatar__ #define __interface__avatar__ -#include -#include - -#include "world.h" -#include "AvatarTouch.h" - -#include "InterfaceConfig.h" -#include "SerialInterface.h" - #include #include -#include //looks like we might not need this - +#include +#include +#include "world.h" +#include "AvatarTouch.h" +#include "InterfaceConfig.h" +#include "SerialInterface.h" #include "Balls.h" -const bool AVATAR_GRAVITY = true; -const float DECAY = 0.1; -const float THRUST_MAG = 1200.0; -const float YAW_MAG = 500.0; //JJV - changed from 300.0; -const float TEST_YAW_DECAY = 5.0; -const float LIN_VEL_DECAY = 5.0; - -const float COLLISION_FRICTION = 0.5; -const float COLLISION_RADIUS_SCALAR = 1.8; -const float COLLISION_BALL_FORCE = 0.1; -const float COLLISION_BODY_FORCE = 3.0; - -const float MY_HAND_HOLDING_PULL = 0.2; -const float YOUR_HAND_HOLDING_PULL = 1.0; - enum eyeContactTargets {LEFT_EYE, RIGHT_EYE, MOUTH}; enum DriveKeys @@ -54,22 +34,6 @@ enum DriveKeys MAX_DRIVE_KEYS }; -/* -#define FWD 0 -#define BACK 1 -#define LEFT 2 -#define RIGHT 3 -#define UP 4 -#define DOWN 5 -#define ROT_LEFT 6 -#define ROT_RIGHT 7 -#define MAX_DRIVE_KEYS 8 -*/ - -//#define MAX_OTHER_AVATARS 10 // temporary - for testing purposes! - - - enum AvatarMode { AVATAR_MODE_STANDING = 0, @@ -108,62 +72,6 @@ enum AvatarBoneID NUM_AVATAR_BONES }; -struct AvatarBone -{ - AvatarBoneID parent; // which bone is this bone connected to? - glm::vec3 position; // the position at the "end" of the bone - in global space - glm::vec3 defaultPosePosition; // the parent relative position when the avatar is in the "T-pose" - glm::vec3 springyPosition; // used for special effects (a 'flexible' variant of position) - glm::vec3 springyVelocity; // used for special effects ( the velocity of the springy position) - float springBodyTightness; // how tightly the springy position tries to stay on the position - glm::quat rotation; // this will eventually replace yaw, pitch and roll (and maybe orientation) - float yaw; // the yaw Euler angle of the bone rotation off the parent - float pitch; // the pitch Euler angle of the bone rotation off the parent - float roll; // the roll Euler angle of the bone rotation off the parent - Orientation orientation; // three orthogonal normals determined by yaw, pitch, roll - float length; // the length of the bone - float radius; // used for detecting collisions for certain physical effects - bool isCollidable; // when false, the bone position will not register a collision -}; - -struct AvatarHead -{ - float pitchRate; - float yawRate; - float rollRate; - float noise; - float eyeballPitch[2]; - float eyeballYaw [2]; - float eyebrowPitch[2]; - float eyebrowRoll [2]; - float eyeballScaleX; - float eyeballScaleY; - float eyeballScaleZ; - float interPupilDistance; - float interBrowDistance; - float nominalPupilSize; - float pupilSize; - float mouthPitch; - float mouthYaw; - float mouthWidth; - float mouthHeight; - float leanForward; - float leanSideways; - float pitchTarget; - float yawTarget; - float noiseEnvelope; - float pupilConverge; - float scale; - int eyeContact; - float browAudioLift; - eyeContactTargets eyeContactTarget; - - // Sound loudness information - float lastLoudness; - float averageLoudness; - float audioAttack; -}; - class Avatar : public AvatarData { public: @@ -234,8 +142,87 @@ public: // Find out what the local gravity vector is at this location glm::vec3 getGravity(glm::vec3 pos); - + private: + + const bool AVATAR_GRAVITY = true; + const float DECAY = 0.1; + const float THRUST_MAG = 1200.0; + const float YAW_MAG = 500.0; //JJV - changed from 300.0; + const float TEST_YAW_DECAY = 5.0; + const float LIN_VEL_DECAY = 5.0; + const float MY_HAND_HOLDING_PULL = 0.2; + const float YOUR_HAND_HOLDING_PULL = 1.0; + const float BODY_SPRING_FORCE = 6.0f; + const float BODY_SPRING_DECAY = 16.0f; + + //const float COLLISION_FRICTION = 0.5; + //const float COLLISION_RADIUS_SCALAR = 1.8; + //const float COLLISION_BALL_FORCE = 0.1; + //const float COLLISION_BODY_FORCE = 3.0; + + const float COLLISION_RADIUS_SCALAR = 1.8; + const float COLLISION_BALL_FORCE = 0.6; + const float COLLISION_BODY_FORCE = 6.0; + const float COLLISION_BALL_FRICTION = 200.0; + const float COLLISION_BODY_FRICTION = 0.5; + + struct AvatarBone + { + AvatarBoneID parent; // which bone is this bone connected to? + glm::vec3 position; // the position at the "end" of the bone - in global space + glm::vec3 defaultPosePosition; // the parent relative position when the avatar is in the "T-pose" + glm::vec3 springyPosition; // used for special effects (a 'flexible' variant of position) + glm::vec3 springyVelocity; // used for special effects ( the velocity of the springy position) + float springBodyTightness; // how tightly the springy position tries to stay on the position + glm::quat rotation; // this will eventually replace yaw, pitch and roll (and maybe orientation) + float yaw; // the yaw Euler angle of the bone rotation off the parent + float pitch; // the pitch Euler angle of the bone rotation off the parent + float roll; // the roll Euler angle of the bone rotation off the parent + Orientation orientation; // three orthogonal normals determined by yaw, pitch, roll + float length; // the length of the bone + float radius; // used for detecting collisions for certain physical effects + bool isCollidable; // when false, the bone position will not register a collision + }; + + struct AvatarHead + { + float pitchRate; + float yawRate; + float rollRate; + float noise; + float eyeballPitch[2]; + float eyeballYaw [2]; + float eyebrowPitch[2]; + float eyebrowRoll [2]; + float eyeballScaleX; + float eyeballScaleY; + float eyeballScaleZ; + float interPupilDistance; + float interBrowDistance; + float nominalPupilSize; + float pupilSize; + float mouthPitch; + float mouthYaw; + float mouthWidth; + float mouthHeight; + float leanForward; + float leanSideways; + float pitchTarget; + float yawTarget; + float noiseEnvelope; + float pupilConverge; + float scale; + int eyeContact; + float browAudioLift; + eyeContactTargets eyeContactTarget; + + // Sound loudness information + float lastLoudness; + float averageLoudness; + float audioAttack; + }; + AvatarHead _head; bool _isMine; glm::vec3 _TEST_bigSpherePosition; @@ -244,8 +231,6 @@ private: float _bodyYawDelta; bool _usingBodySprings; glm::vec3 _movedHandOffset; - float _springVelocityDecay; - float _springForce; glm::quat _rotation; // the rotation of the avatar body as a whole expressed as a quaternion AvatarBone _bone[ NUM_AVATAR_BONES ]; AvatarMode _mode; @@ -277,6 +262,7 @@ private: void updateBodySprings( float deltaTime ); void calculateBoneLengths(); void readSensors(); + void updateHead( float deltaTime ); void updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime ); void updateCollisionWithOtherAvatar( Avatar * other, float deltaTime ); }; diff --git a/interface/src/AvatarTouch.cpp b/interface/src/AvatarTouch.cpp index ad4f0ccf33..41e040c382 100644 --- a/interface/src/AvatarTouch.cpp +++ b/interface/src/AvatarTouch.cpp @@ -56,8 +56,8 @@ void AvatarTouch::simulate (float deltaTime) { glm::vec3 v = _yourHandPosition - _myHandPosition; for (int p=0; p Date: Mon, 29 Apr 2013 14:34:17 -0700 Subject: [PATCH 48/76] added support for LOD scanned sendding order of voxel scene --- libraries/voxels/src/VoxelTree.cpp | 61 +++++++++++++++++++++++------ libraries/voxels/src/VoxelTree.h | 10 +++-- voxel-server/src/VoxelAgentData.cpp | 2 + voxel-server/src/VoxelAgentData.h | 10 ++++- voxel-server/src/main.cpp | 34 ++++++++++++++-- 5 files changed, 96 insertions(+), 21 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 615f63df47..d6934c4042 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -748,22 +748,45 @@ void VoxelTree::createSphere(float r,float xc, float yc, float zc, float s, bool // This will encode a larger tree into multiple subtree bitstreams. Given a node it will search for deeper subtrees that // have color. It will search for sub trees, and upon finding a subTree, it will stick the node in the bag to for later -// endcoding. -void VoxelTree::searchForColoredNodes(VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag) { +// endcoding. It returns the maximum level that we reached during our search. That might be the maximum level we were asked +// to search (if the tree is deeper than that max level), or it will be the maximum level of the tree (if we asked to search +// deeper than the tree exists). +int VoxelTree::searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag) { // call the recursive version, this will add all found colored node roots to the bag - searchForColoredNodesRecursion(rootNode, viewFrustum, bag); + int currentSearchLevel = 0; + + // levelReached will be the maximum level reached. If we made it to the maxSearchLevel, then it will be that. + // but if the tree is shallower than the maxSearchLevel, then we will return the deepest level of the tree that + // exists. + int levelReached = searchForColoredNodesRecursion(maxSearchLevel, currentSearchLevel, rootNode, viewFrustum, bag); + return levelReached; } -void VoxelTree::searchForColoredNodesRecursion(VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag) { +int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSearchLevel, + VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag) { + + // Keep track of how deep we've searched. + currentSearchLevel++; + + // If we've reached our max Search Level, then stop searching. + if (currentSearchLevel >= maxSearchLevel) { + return currentSearchLevel; + } // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! if (!node->isInView(viewFrustum)) { - return; + return currentSearchLevel; } + // Ok, this is a little tricky, each child may have been deeper than the others, so we need to track + // how deep each child went. And we actually return the maximum of each child. We use these variables below + // when we recurse the children. + int thisLevel = currentSearchLevel; + int maxChildLevel = thisLevel; + const int MAX_CHILDREN = 8; VoxelNode* inViewChildren[MAX_CHILDREN]; float distancesToChildren[MAX_CHILDREN]; @@ -812,12 +835,14 @@ void VoxelTree::searchForColoredNodesRecursion(VoxelNode* node, const ViewFrustu // at this point, we need to iterate the children who are in view, even if not colored // and we need to determine if there's a deeper tree below them that we care about. We will iterate // these based on which tree is closer. - // for (int i = 0; i < inViewCount; i++) { VoxelNode* childNode = inViewChildren[i]; - searchForColoredNodesRecursion(childNode, viewFrustum, bag); + thisLevel = currentSearchLevel; // reset this, since the children will munge it up + int childLevelReached = searchForColoredNodesRecursion(maxSearchLevel, thisLevel, childNode, viewFrustum, bag); + maxChildLevel = std::max(maxChildLevel, childLevelReached); } } + return maxChildLevel; } // This will encode a tree bitstream, given a node it will encode the full tree from that point onward. @@ -830,7 +855,7 @@ void VoxelTree::searchForColoredNodesRecursion(VoxelNode* node, const ViewFrustu // extraTrees is assumed to me an allocated array of VoxelNode*, if we're unable to fully encode the tree // because we run out of room on the outputBuffer, then we will add VoxelNode*'s of the trees that need // to be encoded to that array. If the array -int VoxelTree::encodeTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrustum, +int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, const ViewFrustum& viewFrustum, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag) { @@ -850,7 +875,9 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrust bytesWritten += codeLength; // keep track of byte count availableBytes -= codeLength; // keep track or remaining space - int childBytesWritten = encodeTreeBitstreamRecursion(node, viewFrustum, + int currentEncodeLevel = 0; + int childBytesWritten = encodeTreeBitstreamRecursion(maxEncodeLevel, currentEncodeLevel, + node, viewFrustum, outputBuffer, availableBytes, bag); // if childBytesWritten == 1 then something went wrong... that's not possible @@ -878,12 +905,21 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrust // // NOTE: This recursive function DOES NOT add the octcode to the buffer. It's assumed that the caller has // already done that. -int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& viewFrustum, +int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel, + VoxelNode* node, const ViewFrustum& viewFrustum, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag) const { // How many bytes have we written so far at this level; int bytesAtThisLevel = 0; + // Keep track of how deep we've encoded. + currentEncodeLevel++; + + // If we've reached our max Search Level, then stop searching. + if (currentEncodeLevel >= maxEncodeLevel) { + return bytesAtThisLevel; + } + // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! // although technically, we really shouldn't ever be here, because our callers shouldn't be calling us if // we're out of view @@ -1002,7 +1038,10 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& if (oneAtBit(childrenExistBits, i)) { VoxelNode* childNode = node->children[i]; - int childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, viewFrustum, outputBuffer, availableBytes, bag); + + int thisLevel = currentEncodeLevel; + int childTreeBytesOut = encodeTreeBitstreamRecursion(maxEncodeLevel, thisLevel, + childNode, viewFrustum, outputBuffer, availableBytes, bag); // if the child wrote 0 bytes, it means that nothing below exists or was in view, or we ran out of space, // basically, the children below don't contain any info. diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 05d6d39062..c94d4ee2a7 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -59,18 +59,20 @@ public: void recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData=NULL); - int encodeTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrustum, + int encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, const ViewFrustum& viewFrustum, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag); - void searchForColoredNodes(VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag); + int searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag); private: - int encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& viewFrustum, + int encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel, + VoxelNode* node, const ViewFrustum& viewFrustum, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag) const; - void searchForColoredNodesRecursion(VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag); + int searchForColoredNodesRecursion(int maxSearchLevel, int& currentSearchLevel, + VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag); void recurseNodeWithOperation(VoxelNode* node, RecurseVoxelTreeOperation operation, void* extraData); VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode); diff --git a/voxel-server/src/VoxelAgentData.cpp b/voxel-server/src/VoxelAgentData.cpp index a86b25b78d..53e07dcc7e 100644 --- a/voxel-server/src/VoxelAgentData.cpp +++ b/voxel-server/src/VoxelAgentData.cpp @@ -20,6 +20,8 @@ void VoxelAgentData::init() { _voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE]; _voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE; _voxelPacketAt = _voxelPacket; + _maxSearchLevel = 1; + _maxLevelReachedInLastSearch = 1; resetVoxelPacket(); } diff --git a/voxel-server/src/VoxelAgentData.h b/voxel-server/src/VoxelAgentData.h index 56d9ebf03e..1955c6130a 100644 --- a/voxel-server/src/VoxelAgentData.h +++ b/voxel-server/src/VoxelAgentData.h @@ -35,6 +35,12 @@ public: int getPacketLength() const { return (MAX_VOXEL_PACKET_SIZE-_voxelPacketAvailableBytes); } bool isPacketWaiting() const { return _voxelPacketWaiting; } int getAvailable() const { return _voxelPacketAvailableBytes; } + int getMaxSearchLevel() const { return _maxSearchLevel; }; + void resetMaxSearchLevel() { _maxSearchLevel = 1; }; + void incrementMaxSearchLevel() { _maxSearchLevel++; }; + + int getMaxLevelReached() const { return _maxLevelReachedInLastSearch; }; + void setMaxLevelReached(int maxLevelReached) { _maxLevelReachedInLastSearch = maxLevelReached; } VoxelNodeBag nodeBag; private: @@ -42,8 +48,8 @@ private: unsigned char* _voxelPacketAt; int _voxelPacketAvailableBytes; bool _voxelPacketWaiting; - - + int _maxSearchLevel; + int _maxLevelReachedInLastSearch; }; #endif /* defined(__hifi__VoxelAgentData__) */ diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 15d71aa504..319723e7e3 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -152,7 +152,6 @@ void eraseVoxelTreeAndCleanupAgentVisitData() { void newDistributeHelper(AgentList* agentList, AgentList::iterator& agent, VoxelAgentData* agentData, ViewFrustum& viewFrustum) { - // A quick explanation of the strategy here. First, each time through, we ask ourselves, do we have voxels // that need to be sent? If not, we search for them, if we do, then we send them. We store our to be sent voxel sub trees // in a VoxelNodeBag on a per agent basis. The bag stores just pointers to the root node of the sub tree to be sent, so @@ -185,12 +184,28 @@ void newDistributeHelper(AgentList* agentList, AgentList::iterator& agent, Voxel // can include the siblings. Since dense trees take more space per ranch, we often end up only being able to encode a // single branch. This means on a per packet basis, the trees actually _are not_ dense. And sparse trees are shorter to // encode when we only include the child tree. - randomTree.searchForColoredNodes(randomTree.rootNode, viewFrustum, agentData->nodeBag); + // + // Now, a quick explanation of maxSearchLevel: We will actually send the entire scene, multiple times for each search + // level. We start at level 1, and we scan the scene for this level, then we increment to the next level until we've + // sent the entire scene at it's deepest possible level. This means that clients will get an initial view of the scene + // with chunky granularity and then finer and finer granularity until they've gotten the whole scene. Then we start + // over to handle packet loss and changes in the scene. + int maxLevelReached = randomTree.searchForColoredNodes(agentData->getMaxSearchLevel(), randomTree.rootNode, + viewFrustum, agentData->nodeBag); + agentData->setMaxLevelReached(maxLevelReached); + + // If nothing got added, then we bump our levels. + if (agentData->nodeBag.isEmpty()) { + if (agentData->getMaxLevelReached() < agentData->getMaxSearchLevel()) { + agentData->resetMaxSearchLevel(); + } else { + agentData->incrementMaxSearchLevel(); + } + } } // If we have something in our nodeBag, then turn them into packets and send them out... if (!agentData->nodeBag.isEmpty()) { - static unsigned char tempOutputBuffer[MAX_VOXEL_PACKET_SIZE-1]; // save on allocs by making this static int bytesWritten = 0; @@ -203,7 +218,7 @@ void newDistributeHelper(AgentList* agentList, AgentList::iterator& agent, Voxel // Only let this guy create at largest packets equal to the amount of space we have left in our final??? // Or let it create the largest possible size (minus 1 for the "V") - bytesWritten = randomTree.encodeTreeBitstream(subTree, viewFrustum, + bytesWritten = randomTree.encodeTreeBitstream(agentData->getMaxSearchLevel(), subTree, viewFrustum, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE-1, agentData->nodeBag); // if we have room in our final packet, add this buffer to the final packet @@ -232,6 +247,7 @@ void newDistributeHelper(AgentList* agentList, AgentList::iterator& agent, Voxel // reset our finalOutputBuffer (keep the 'V') agentData->resetVoxelPacket(); + } // and we're done now for this interval, because we know we have not nodes in our @@ -240,6 +256,16 @@ void newDistributeHelper(AgentList* agentList, AgentList::iterator& agent, Voxel packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; } } + + // Ok, so we're in the "send from our bag mode"... if during this last pass, we emptied our bag, then + // we want to move to the next level. + if (agentData->nodeBag.isEmpty()) { + if (agentData->getMaxLevelReached() < agentData->getMaxSearchLevel()) { + agentData->resetMaxSearchLevel(); + } else { + agentData->incrementMaxSearchLevel(); + } + } } } From accda966d5113cc4a276be8e9d1fbaaad1170421 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 29 Apr 2013 17:38:52 -0700 Subject: [PATCH 49/76] Add LOD culling to the server protocol. - Add LOD/distance culling to VoxelTree:encodeTreeBitstreamRecursion() and VoxelTree::searchForColoredNodesRecursion() - added new levels to boundaryDistanceForRenderLevel() - added more spheres to the scene to get a better sense of LOD behavior --- interface/src/VoxelSystem.cpp | 6 +-- interface/src/VoxelSystem.h | 7 ++- interface/src/main.cpp | 1 + libraries/voxels/src/VoxelTree.cpp | 73 +++++++++++++++++++++--------- voxel-server/src/main.cpp | 33 +++++++++++++- 5 files changed, 90 insertions(+), 30 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index b018bd1f96..e9040ac48a 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -55,10 +55,6 @@ VoxelSystem::~VoxelSystem() { pthread_mutex_destroy(&bufferWriteLock); } -void VoxelSystem::setViewerAvatar(Avatar *newViewerAvatar) { - viewerAvatar = newViewerAvatar; -} - ////////////////////////////////////////////////////////////////////////////////////////// // Method: VoxelSystem::loadVoxelsFile() // Description: Loads HiFidelity encoded Voxels from a binary file. The current file @@ -180,7 +176,7 @@ void VoxelSystem::copyWrittenDataToReadArrays() { int VoxelSystem::treeToArrays(VoxelNode* currentNode, const glm::vec3& nodePosition) { int voxelsAdded = 0; float halfUnitForVoxel = powf(0.5, *currentNode->octalCode) * (0.5 * TREE_SCALE); - glm::vec3 viewerPosition = viewerAvatar->getPosition(); + glm::vec3 viewerPosition = _camera->getPosition(); //_viewerAvatar->getPosition(); // debug LOD code glm::vec3 debugNodePosition; diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index ca4825121b..f12cc7521a 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -16,6 +16,7 @@ #include #include #include "Avatar.h" +#include "Camera.h" #include "Util.h" #include "world.h" @@ -34,7 +35,8 @@ public: void render(); void setVoxelsRendered(int v) {voxelsRendered = v;}; int getVoxelsRendered() {return voxelsRendered;}; - void setViewerAvatar(Avatar *newViewerAvatar); + void setViewerAvatar(Avatar *newViewerAvatar) { _viewerAvatar = newViewerAvatar; }; + void setCamera(Camera* newCamera) { _camera = newCamera; }; void loadVoxelsFile(const char* fileName,bool wantColorRandomizer); void createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer); @@ -67,7 +69,8 @@ private: static float _minDistance; int voxelsRendered; - Avatar *viewerAvatar; + Avatar* _viewerAvatar; + Camera* _camera; VoxelTree *tree; GLfloat *readVerticesArray; GLubyte *readColorsArray; diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 37c15ecbeb..fe914b2e52 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -299,6 +299,7 @@ void init(void) { voxels.init(); voxels.setViewerAvatar(&myAvatar); + voxels.setCamera(&myCamera); handControl.setScreenDimensions(WIDTH, HEIGHT); diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index d6934c4042..ecdb77a617 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -84,9 +84,27 @@ int boundaryDistanceForRenderLevel(unsigned int renderLevel) { case 7: return 12; break; - default: + case 8: + return 10; + break; + case 9: return 6; break; + case 10: + return 4.5; + break; + case 11: + return 3; + break; + case 12: + return 2.25; + break; + case 13: + return 1.5; + break; + default: + return 1; + break; } } @@ -817,10 +835,12 @@ int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSe } float distance = childNode->distanceToCamera(viewFrustum); - - inViewCount = insertIntoSortedArrays((void*)childNode, distance, i, - (void**)&inViewChildren, (float*)&distancesToChildren, (int*)&positionOfChildren, - inViewCount, MAX_CHILDREN); + + if (distance < boundaryDistanceForRenderLevel(*childNode->octalCode + 1)) { + inViewCount = insertIntoSortedArrays((void*)childNode, distance, i, + (void**)&inViewChildren, (float*)&distancesToChildren, (int*)&positionOfChildren, + inViewCount, MAX_CHILDREN); + } } } @@ -920,6 +940,14 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco return bytesAtThisLevel; } + float distance = node->distanceToCamera(viewFrustum); + float boundaryDistance = boundaryDistanceForRenderLevel(*node->octalCode + 1); + + // If we're too far away for our render level, then just return + if (distance >= boundaryDistance) { + return bytesAtThisLevel; + } + // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! // although technically, we really shouldn't ever be here, because our callers shouldn't be calling us if // we're out of view @@ -954,26 +982,28 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco for (int i = 0; i < MAX_CHILDREN; i++) { VoxelNode* childNode = node->children[i]; bool childExists = (childNode != NULL); - - bool childIsColored = (childExists && childNode->isColored()); bool childIsInView = (childExists && childNode->isInView(viewFrustum)); - bool childIsLeaf = (childExists && childNode->isLeaf()); - if (childIsInView) { - inViewCount++; + // Before we determine consider this further, let's see if it's in our LOD scope... + float distance = childNode->distanceToCamera(viewFrustum); + float boundaryDistance = boundaryDistanceForRenderLevel(*childNode->octalCode + 1); + + if (distance < boundaryDistance) { + inViewCount++; - // track children in view as existing and not a leaf, if they're a leaf, - // we don't care about recursing deeper on them, and we don't consider their - // subtree to exist - if (!childIsLeaf) { - childrenExistBits += (1 << (7 - i)); - inViewNotLeafCount++; - } + // track children in view as existing and not a leaf, if they're a leaf, + // we don't care about recursing deeper on them, and we don't consider their + // subtree to exist + if (!(childExists && childNode->isLeaf())) { + childrenExistBits += (1 << (7 - i)); + inViewNotLeafCount++; + } - // track children with actual color - if (childIsColored) { - childrenColoredBits += (1 << (7 - i)); - inViewWithColorCount++; + // track children with actual color + if (childExists && childNode->isColored()) { + childrenColoredBits += (1 << (7 - i)); + inViewWithColorCount++; + } } } } @@ -1016,7 +1046,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco // of handling things. For example, in case of child iteration, it needs to unset the child exist bit for // this child. // add our node the the list of extra nodes to output later... - bag.insert(node); return 0; } diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 319723e7e3..9eff5451a7 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -38,7 +38,7 @@ const float DEATH_STAR_RADIUS = 4.0; const float MAX_CUBE = 0.05f; const int VOXEL_SEND_INTERVAL_USECS = 100 * 1000; -const int PACKETS_PER_CLIENT_PER_INTERVAL = 5; +const int PACKETS_PER_CLIENT_PER_INTERVAL = 2; const int MAX_VOXEL_TREE_DEPTH_LEVELS = 4; @@ -68,6 +68,16 @@ void addSphere(VoxelTree * tree,bool random, bool wantColorRandomizer) { tree->createSphere(r,xc,yc,zc,s,solid,wantColorRandomizer); } +int _nodeCount=0; +bool countVoxelsOperation(VoxelNode* node, bool down, void* extraData) { + if (down) { + if (node->isColored()){ + _nodeCount++; + } + } + return true; // keep going +} + void addSphereScene(VoxelTree * tree, bool wantColorRandomizer) { printf("adding scene of spheres...\n"); @@ -80,6 +90,8 @@ void addSphereScene(VoxelTree * tree, bool wantColorRandomizer) { tree->createSphere(0.25,0.5,0.5,0.5,(1.0/sphereBaseSize),true,wantColorRandomizer); printf("one sphere added...\n"); tree->createSphere(0.030625,0.5,0.5,(0.25-0.06125),(1.0/(sphereBaseSize*2)),true,true); + + printf("two spheres added...\n"); tree->createSphere(0.030625,(1.0-0.030625),(1.0-0.030625),(1.0-0.06125),(1.0/(sphereBaseSize*2)),true,true); printf("three spheres added...\n"); @@ -88,6 +100,25 @@ void addSphereScene(VoxelTree * tree, bool wantColorRandomizer) { tree->createSphere(0.030625,(1.0-0.030625),0.06125,(1.0-0.06125),(1.0/(sphereBaseSize*2)),true,true); printf("five spheres added...\n"); tree->createSphere(0.06125,0.125,0.125,(1.0-0.125),(1.0/(sphereBaseSize*2)),true,true); + + float radius = 0.0125f; + printf("6 spheres added...\n"); + tree->createSphere(radius,0.25,radius*5.0f,0.25,(1.0/(4096)),true,true); + printf("7 spheres added...\n"); + tree->createSphere(radius,0.125,radius*5.0f,0.25,(1.0/(4096)),true,true); + printf("8 spheres added...\n"); + tree->createSphere(radius,0.075,radius*5.0f,0.25,(1.0/(4096)),true,true); + printf("9 spheres added...\n"); + tree->createSphere(radius,0.05,radius*5.0f,0.25,(1.0/(4096)),true,true); + printf("10 spheres added...\n"); + tree->createSphere(radius,0.025,radius*5.0f,0.25,(1.0/(4096)),true,true); + printf("11 spheres added...\n"); + + _nodeCount=0; + tree->recurseTreeWithOperation(countVoxelsOperation); + printf("Nodes after adding scene %d nodes\n",_nodeCount); + + printf("DONE adding scene of spheres...\n"); } From 33f86513ab2de86ce817f62861558b7718d6a58b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 29 Apr 2013 17:45:36 -0700 Subject: [PATCH 50/76] make new voxel distribution default behavior --- voxel-server/src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 9eff5451a7..208d2b12f0 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -433,8 +433,8 @@ int main(int argc, const char * argv[]) ::wantColorRandomizer = cmdOptionExists(argc, argv, WANT_COLOR_RANDOMIZER); printf("wantColorRandomizer=%s\n", (::wantColorRandomizer ? "yes" : "no")); - const char* NEW_VOXEL_DISTRIBUTOR = "--newVoxelDistributor"; - ::newVoxelDistributor = cmdOptionExists(argc, argv, NEW_VOXEL_DISTRIBUTOR); + const char* OLD_VOXEL_DISTRIBUTOR = "--OldVoxelDistributor"; + ::newVoxelDistributor = !cmdOptionExists(argc, argv, OLD_VOXEL_DISTRIBUTOR); printf("newVoxelDistributor=%s\n", (::newVoxelDistributor ? "yes" : "no")); // Check to see if the user passed in a command line option for loading a local From 823e23d50ae9fa3e15ccced6b51011a1d2da996a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 29 Apr 2013 17:46:02 -0700 Subject: [PATCH 51/76] add VoxelConstants.h --- libraries/voxels/src/VoxelConstants.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 libraries/voxels/src/VoxelConstants.h diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h new file mode 100644 index 0000000000..66ddbcb915 --- /dev/null +++ b/libraries/voxels/src/VoxelConstants.h @@ -0,0 +1,24 @@ +// +// VoxelConstants.h +// hifi +// +// Created by Brad Hefta-Gaub on 4/29/13. +// +// +// Various important constants used throughout the system related to voxels +// +// + +#ifndef __hifi_VoxelConstants_h__ +#define __hifi_VoxelConstants_h__ + +const int MAX_VOXEL_PACKET_SIZE = 1492; +const int MAX_TREE_SLICE_BYTES = 26; +const int TREE_SCALE = 10; +const int MAX_VOXELS_PER_SYSTEM = 250000; +const int VERTICES_PER_VOXEL = 24; +const int VERTEX_POINTS_PER_VOXEL = 3 * VERTICES_PER_VOXEL; +const int INDICES_PER_VOXEL = 3 * 12; +const int COLOR_VALUES_PER_VOXEL = 3 * VERTICES_PER_VOXEL; + +#endif From ee814d7ddcc9170a80d76b4b562838c7611d0a4d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 29 Apr 2013 19:18:38 -0700 Subject: [PATCH 52/76] better version of boundaryDistanceForRenderLevel() --- libraries/voxels/src/VoxelTree.cpp | 41 ++---------------------------- 1 file changed, 2 insertions(+), 39 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index ecdb77a617..13f7d17aae 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -67,45 +67,8 @@ using voxels_lib::printLog; int boundaryDistanceForRenderLevel(unsigned int renderLevel) { - switch (renderLevel) { - case 1: - case 2: - case 3: - return 100; - case 4: - return 75; - break; - case 5: - return 50; - break; - case 6: - return 25; - break; - case 7: - return 12; - break; - case 8: - return 10; - break; - case 9: - return 6; - break; - case 10: - return 4.5; - break; - case 11: - return 3; - break; - case 12: - return 2.25; - break; - case 13: - return 1.5; - break; - default: - return 1; - break; - } + float voxelSizeScale = 5000.0; + return voxelSizeScale/pow(2,renderLevel); } VoxelTree::VoxelTree() : From 8a5633a0dbe6b89e0fa0beef9eee6b2a8e0ab46a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Apr 2013 10:09:15 -0700 Subject: [PATCH 53/76] got rid of compareOctalCodesDepth() and cleaned up compareOctalCodes() --- libraries/shared/src/OctalCode.cpp | 38 ++++++--------------------- libraries/shared/src/OctalCode.h | 15 +++++------ libraries/voxels/src/VoxelNodeBag.cpp | 2 +- 3 files changed, 15 insertions(+), 40 deletions(-) diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index 62768569f1..da2b017875 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -135,54 +135,32 @@ float * firstVertexForCode(unsigned char * octalCode) { return firstVertex; } -OctalTreeDepth compareOctalCodesDepth(unsigned char* codeA, unsigned char* codeB) { +OctalCodeComparison compareOctalCodes(unsigned char* codeA, unsigned char* codeB) { if (!codeA || !codeB) { return ILLEGAL_CODE; } - OctalTreeDepth result = SHALLOWER; // assume it's shallower - int codeLenthA = numberOfThreeBitSectionsInCode(codeA); - int codeLenthB = numberOfThreeBitSectionsInCode(codeB); + OctalCodeComparison result = LESS_THAN; // assume it's shallower - if (codeLenthA > codeLenthB) { - result = DEEPER; - } else if (codeLenthA == codeLenthB) { - int numberOfBytes = bytesRequiredForCodeLength(*codeA); // they are the same!! - if (0 == memcmp(codeA,codeB,numberOfBytes)) { - result = EXACT_MATCH; - } else { - result = EQUAL_DEPTH; - } - } - return result; -} - -OctalTreeDepth compareOctalCodes(unsigned char* codeA, unsigned char* codeB) { - if (!codeA || !codeB) { - return ILLEGAL_CODE; - } - - OctalTreeDepth result = LESS_THAN; // assume it's shallower - - int numberOfBytes = std::min(bytesRequiredForCodeLength(*codeA),bytesRequiredForCodeLength(*codeB)); - int compare = memcmp(codeA,codeB,numberOfBytes); + int numberOfBytes = std::min(bytesRequiredForCodeLength(*codeA), bytesRequiredForCodeLength(*codeB)); + int compare = memcmp(codeA, codeB, numberOfBytes); if (compare < 0) { result = LESS_THAN; } else if (compare > 0) { result = GREATER_THAN; } else { - int codeLenthA = numberOfThreeBitSectionsInCode(codeA); - int codeLenthB = numberOfThreeBitSectionsInCode(codeB); + int codeLengthA = numberOfThreeBitSectionsInCode(codeA); + int codeLengthB = numberOfThreeBitSectionsInCode(codeB); - if (codeLenthA == codeLenthB) { + if (codeLengthA == codeLengthB) { // if the memcmp matched exactly, and they were the same length, // then these must be the same code! result = EXACT_MATCH; } else { // if the memcmp matched exactly, but they aren't the same length, // then they have a matching common parent, but they aren't the same - if (codeLenthA < codeLenthB) { + if (codeLengthA < codeLengthB) { result = LESS_THAN; } else { result = GREATER_THAN; diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index be939f2495..bf4a6ef699 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -24,14 +24,11 @@ float * firstVertexForCode(unsigned char * octalCode); void copyFirstVertexForCode(unsigned char * octalCode, float* output); typedef enum { - SHALLOWER, - EQUAL_DEPTH, - EXACT_MATCH, - DEEPER, - ILLEGAL_CODE, - GREATER_THAN, - LESS_THAN -} OctalTreeDepth; + ILLEGAL_CODE = -2, + LESS_THAN = -1, + EXACT_MATCH = 0, + GREATER_THAN = 1 +} OctalCodeComparison; -OctalTreeDepth compareOctalCodes(unsigned char* code1, unsigned char* code2); +OctalCodeComparison compareOctalCodes(unsigned char* code1, unsigned char* code2); #endif /* defined(__hifi__OctalCode__) */ diff --git a/libraries/voxels/src/VoxelNodeBag.cpp b/libraries/voxels/src/VoxelNodeBag.cpp index 370b2dac02..60ea2e47d4 100644 --- a/libraries/voxels/src/VoxelNodeBag.cpp +++ b/libraries/voxels/src/VoxelNodeBag.cpp @@ -39,7 +39,7 @@ void VoxelNodeBag::insert(VoxelNode* node) { for (int i = 0; i < _elementsInUse; i++) { // compare the newNode to the elements already in the bag - OctalTreeDepth comparison = compareOctalCodes(_bagElements[i]->octalCode,node->octalCode); + OctalCodeComparison comparison = compareOctalCodes(_bagElements[i]->octalCode,node->octalCode); // If we found a code in the bag that matches, then just return, since the element is already in the bag. if (comparison == EXACT_MATCH) { From 622a078d248e9e4cac174b52c7c6db26dcce7722 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Apr 2013 10:10:17 -0700 Subject: [PATCH 54/76] code review cleanup --- interface/src/VoxelSystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index e9040ac48a..24f7665e50 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -203,7 +203,7 @@ int VoxelSystem::treeToArrays(VoxelNode* currentNode, const glm::vec3& nodePosi } } - // if we didn't get any voxels added then we're a leaf (XXXBHG - Stephen can you explain this to me????) + // if we didn't get any voxels added then we're a leaf // add our vertex and color information to the interleaved array if (voxelsAdded == 0 && currentNode->isColored()) { float startVertex[3]; From bf3b01474372f78aae0d4573a8a5323f8fdbb586 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Apr 2013 10:16:04 -0700 Subject: [PATCH 55/76] code review cleanup --- libraries/shared/src/SharedUtil.cpp | 26 ++++++++++++++------------ libraries/shared/src/SharedUtil.h | 6 ++++-- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index d7f2fdde73..6410bcfa09 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -54,7 +54,7 @@ bool randomBoolean() { void outputBufferBits(unsigned char* buffer, int length, bool withNewLine) { for (int i = 0; i < length; i++) { - outputBits(buffer[i],false); + outputBits(buffer[i], false); } if (withNewLine) { printLog("\n"); @@ -377,28 +377,30 @@ void printVoxelCode(unsigned char* voxelCode) { // the second array is a sorted key for the value, the third array is the index for the value in it original // non-sorted array // returns -1 if size exceeded -int insertIntoSortedArrays(void* value, float key, int originalIndex, - void** valueArray, float* keyArray, int* originalIndexArray, int currentCount, int maxCount) { +int insertIntoSortedArrays( + void* value, float key, int originalIndex, + void** valueArray, float* keyArray, int* originalIndexArray, + int currentCount, int maxCount) { if (currentCount < maxCount) { - int i=0; + int i = 0; if (currentCount > 0) { - while (i keyArray[i]) { + while (i < currentCount && key > keyArray[i]) { i++; } // i is our desired location // shift array elements to the right if (i < currentCount && i+1 < maxCount) { - memcpy(&valueArray[i+1],&valueArray[i],sizeof(void*) * (currentCount-i)); - memcpy(&keyArray[i+1],&keyArray[i],sizeof(float) * (currentCount-i)); - memcpy(&originalIndexArray[i+1],&originalIndexArray[i],sizeof(int) * (currentCount-i)); + memcpy(&valueArray[i + 1], &valueArray[i], sizeof(void*) * (currentCount - i)); + memcpy(&keyArray[i + 1], &keyArray[i], sizeof(float) * (currentCount - i)); + memcpy(&originalIndexArray[i + 1], &originalIndexArray[i], sizeof(int) * (currentCount - i)); } } // place new element at i - valueArray[i]=value; - keyArray[i]=key; - originalIndexArray[i]=originalIndex; - return currentCount+1; + valueArray[i] = value; + keyArray[i] = key; + originalIndexArray[i] = originalIndex; + return currentCount + 1; } return -1; // error case } diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index d887cbe956..2b0c1d195b 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -71,7 +71,9 @@ bool createVoxelEditMessage(unsigned char command, short int sequence, void usleep(int waitTime); #endif -int insertIntoSortedArrays(void* value, float key, int originalIndex, - void** valueArray, float* keyArray, int* originalIndexArray, int currentCount, int maxCount); +int insertIntoSortedArrays( + void* value, float key, int originalIndex, + void** valueArray, float* keyArray, int* originalIndexArray, + int currentCount, int maxCount); #endif /* defined(__hifi__SharedUtil__) */ From 3673ee36ad378803359ff5e8de29e048a9ff782a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Apr 2013 10:23:35 -0700 Subject: [PATCH 56/76] cr cleanup and optimization of isLeaf() --- libraries/voxels/src/VoxelNode.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 6129f9c16c..c76d52845b 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -183,13 +183,12 @@ void VoxelNode::setRandomColor(int minimumBrightness) { } bool VoxelNode::isLeaf() const { - int childCount = 0; for (int i = 0; i < 8; i++) { - if (NULL != children[i]) { - childCount++; + if (children[i]) { + return false; } } - return (0 == childCount); + return true; } void VoxelNode::printDebugDetails(const char* label) const { From 6d378281a80dd1b748e18cdea59052a01bd09bf3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Apr 2013 10:24:13 -0700 Subject: [PATCH 57/76] cr cleaup - third times a charm? --- libraries/shared/src/SharedUtil.cpp | 7 +++---- libraries/shared/src/SharedUtil.h | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 6410bcfa09..463bd2a339 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -377,10 +377,9 @@ void printVoxelCode(unsigned char* voxelCode) { // the second array is a sorted key for the value, the third array is the index for the value in it original // non-sorted array // returns -1 if size exceeded -int insertIntoSortedArrays( - void* value, float key, int originalIndex, - void** valueArray, float* keyArray, int* originalIndexArray, - int currentCount, int maxCount) { +int insertIntoSortedArrays(void* value, float key, int originalIndex, + void** valueArray, float* keyArray, int* originalIndexArray, + int currentCount, int maxCount) { if (currentCount < maxCount) { int i = 0; diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 2b0c1d195b..1b40de5448 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -71,9 +71,8 @@ bool createVoxelEditMessage(unsigned char command, short int sequence, void usleep(int waitTime); #endif -int insertIntoSortedArrays( - void* value, float key, int originalIndex, - void** valueArray, float* keyArray, int* originalIndexArray, - int currentCount, int maxCount); +int insertIntoSortedArrays(void* value, float key, int originalIndex, + void** valueArray, float* keyArray, int* originalIndexArray, + int currentCount, int maxCount); #endif /* defined(__hifi__SharedUtil__) */ From 37b139621ab865219e1de4a154664d023cf9622b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Apr 2013 10:27:32 -0700 Subject: [PATCH 58/76] cr cleanup --- libraries/voxels/src/VoxelNode.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index c76d52845b..c1527d3334 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -194,8 +194,8 @@ bool VoxelNode::isLeaf() const { void VoxelNode::printDebugDetails(const char* label) const { AABox box; getAABox(box); - printLog("%s - Voxel at corner=(%f,%f,%f) size=%f octcode=",label, - box.getCorner().x, box.getCorner().y, box.getCorner().z,box.getSize().x); + printLog("%s - Voxel at corner=(%f,%f,%f) size=%f octcode=", label, + box.getCorner().x, box.getCorner().y, box.getCorner().z, box.getSize().x); printOctalCode(octalCode); } From 218dd3d62b663ad9fa4b6038abdf860d19f75763 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Apr 2013 10:27:38 -0700 Subject: [PATCH 59/76] cr cleanup --- libraries/voxels/src/VoxelNodeBag.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/voxels/src/VoxelNodeBag.cpp b/libraries/voxels/src/VoxelNodeBag.cpp index 60ea2e47d4..a1396ad2c2 100644 --- a/libraries/voxels/src/VoxelNodeBag.cpp +++ b/libraries/voxels/src/VoxelNodeBag.cpp @@ -39,7 +39,7 @@ void VoxelNodeBag::insert(VoxelNode* node) { for (int i = 0; i < _elementsInUse; i++) { // compare the newNode to the elements already in the bag - OctalCodeComparison comparison = compareOctalCodes(_bagElements[i]->octalCode,node->octalCode); + OctalCodeComparison comparison = compareOctalCodes(_bagElements[i]->octalCode, node->octalCode); // If we found a code in the bag that matches, then just return, since the element is already in the bag. if (comparison == EXACT_MATCH) { @@ -56,9 +56,9 @@ void VoxelNodeBag::insert(VoxelNode* node) { // at this point, inserAt will be the location we want to insert at. // If we don't have room in our bag, then grow the bag - if (_sizeOfElementsArray < _elementsInUse+1) { + if (_sizeOfElementsArray < _elementsInUse + 1) { VoxelNode** oldBag = _bagElements; - _bagElements = new VoxelNode*[_sizeOfElementsArray + GROW_BAG_BY]; + _bagElements = new VoxelNode * [_sizeOfElementsArray + GROW_BAG_BY]; _sizeOfElementsArray += GROW_BAG_BY; // If we had an old bag... @@ -66,12 +66,12 @@ void VoxelNodeBag::insert(VoxelNode* node) { // copy old elements into the new bag, but leave a space where we need to // insert the new node memcpy(_bagElements, oldBag, insertAt*sizeof(VoxelNode*)); - memcpy(&_bagElements[insertAt+1], &oldBag[insertAt], (_elementsInUse-insertAt)*sizeof(VoxelNode*)); + memcpy(&_bagElements[insertAt+1], &oldBag[insertAt], (_elementsInUse-insertAt) * sizeof(VoxelNode*)); } } else { // move existing elements further back in the bag array, leave a space where we need to // insert the new node - memmove(&_bagElements[insertAt+1], &_bagElements[insertAt], (_elementsInUse-insertAt)*sizeof(VoxelNode*)); + memmove(&_bagElements[insertAt+1], &_bagElements[insertAt], (_elementsInUse-insertAt) * sizeof(VoxelNode*)); } _bagElements[insertAt] = node; _elementsInUse++; @@ -83,7 +83,7 @@ VoxelNode* VoxelNodeBag::extract() { if (_elementsInUse) { // get the last element - VoxelNode* node = _bagElements[_elementsInUse-1]; + VoxelNode* node = _bagElements[_elementsInUse - 1]; // reduce the count _elementsInUse--; From 0fd3f00054bcb813b60840a6e0a6563ded12fcbe Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Apr 2013 10:28:34 -0700 Subject: [PATCH 60/76] cr cleanup --- libraries/voxels/src/VoxelNodeBag.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libraries/voxels/src/VoxelNodeBag.cpp b/libraries/voxels/src/VoxelNodeBag.cpp index a1396ad2c2..7723565e7a 100644 --- a/libraries/voxels/src/VoxelNodeBag.cpp +++ b/libraries/voxels/src/VoxelNodeBag.cpp @@ -5,11 +5,6 @@ // Created by Brad Hefta-Gaub on 4/25/2013 // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // -// This class is used by the VoxelTree:encodeTreeBitstream() functions to store extra nodes that need to be sent -// it's a generic bag style storage mechanism. But It has the property that you can't put the same node into the bag -// more than once (in other words, it de-dupes automatically), also, it supports collapsing it's several peer nodes -// into a parent node in cases where you add enough peers that it makes more sense to just add the parent. -// #include "VoxelNodeBag.h" #include From 5a90dc4487754e5215936d18eb9e4c6cde986b64 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Apr 2013 10:32:55 -0700 Subject: [PATCH 61/76] cr cleanup --- libraries/voxels/src/VoxelNodeBag.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/voxels/src/VoxelNodeBag.cpp b/libraries/voxels/src/VoxelNodeBag.cpp index 7723565e7a..63fcc97349 100644 --- a/libraries/voxels/src/VoxelNodeBag.cpp +++ b/libraries/voxels/src/VoxelNodeBag.cpp @@ -60,7 +60,7 @@ void VoxelNodeBag::insert(VoxelNode* node) { if (oldBag) { // copy old elements into the new bag, but leave a space where we need to // insert the new node - memcpy(_bagElements, oldBag, insertAt*sizeof(VoxelNode*)); + memcpy(_bagElements, oldBag, insertAt * sizeof(VoxelNode*)); memcpy(&_bagElements[insertAt+1], &oldBag[insertAt], (_elementsInUse-insertAt) * sizeof(VoxelNode*)); } } else { From 4cea0ffa10f796bdb4df061aa9a1254298eae2c2 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Apr 2013 10:33:13 -0700 Subject: [PATCH 62/76] cr cleanup --- libraries/voxels/src/VoxelTree.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 13f7d17aae..2d09b41d98 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -68,7 +68,7 @@ using voxels_lib::printLog; int boundaryDistanceForRenderLevel(unsigned int renderLevel) { float voxelSizeScale = 5000.0; - return voxelSizeScale/pow(2,renderLevel); + return voxelSizeScale / powf(2, renderLevel); } VoxelTree::VoxelTree() : From 778d3715cee8b6e2335f2dd4c67856e63502ebd4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Apr 2013 10:37:02 -0700 Subject: [PATCH 63/76] cr cleanup --- libraries/voxels/src/VoxelNodeBag.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/voxels/src/VoxelNodeBag.cpp b/libraries/voxels/src/VoxelNodeBag.cpp index 63fcc97349..e6b20cbf4b 100644 --- a/libraries/voxels/src/VoxelNodeBag.cpp +++ b/libraries/voxels/src/VoxelNodeBag.cpp @@ -61,12 +61,13 @@ void VoxelNodeBag::insert(VoxelNode* node) { // copy old elements into the new bag, but leave a space where we need to // insert the new node memcpy(_bagElements, oldBag, insertAt * sizeof(VoxelNode*)); - memcpy(&_bagElements[insertAt+1], &oldBag[insertAt], (_elementsInUse-insertAt) * sizeof(VoxelNode*)); + memcpy(&_bagElements[insertAt + 1], &oldBag[insertAt], (_elementsInUse - insertAt) * sizeof(VoxelNode*)); + delete[] oldBag; } } else { // move existing elements further back in the bag array, leave a space where we need to // insert the new node - memmove(&_bagElements[insertAt+1], &_bagElements[insertAt], (_elementsInUse-insertAt) * sizeof(VoxelNode*)); + memmove(&_bagElements[insertAt + 1], &_bagElements[insertAt], (_elementsInUse - insertAt) * sizeof(VoxelNode*)); } _bagElements[insertAt] = node; _elementsInUse++; From 59ce9216453579e61b28f0213405f20305ff8885 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Apr 2013 10:38:30 -0700 Subject: [PATCH 64/76] cr cleanup --- libraries/voxels/src/VoxelTree.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 2d09b41d98..299e189e8f 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -229,7 +229,7 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, int bufferSizeByt // into a single network packet. readNodeData() basically goes down a tree from the root, and fills things in from there // if there are more bytes after that, it's assumed to be another root relative tree - while (bitstreamAt < bitstream+bufferSizeBytes) { + while (bitstreamAt < bitstream + bufferSizeBytes) { VoxelNode* bitstreamRootNode = nodeForOctalCode(rootNode, (unsigned char *)bitstreamAt, NULL); if (*bitstreamAt != *bitstreamRootNode->octalCode) { // if the octal code returned is not on the same level as From a6b486aa890d913c90a5408be6544bab12dcf42b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Apr 2013 10:39:45 -0700 Subject: [PATCH 65/76] cr cleanup --- libraries/voxels/src/VoxelTree.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 299e189e8f..7227d1e6e6 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -237,7 +237,7 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, int bufferSizeByt // 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(rootNode, (unsigned char *)bitstreamAt); + bitstreamRootNode = createMissingNode(rootNode, (unsigned char*) bitstreamAt); } int octalCodeBytes = bytesRequiredForCodeLength(*bitstreamAt); From 2ec2824e8ffbc04dbb0f25c569de7f192c1810b9 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Apr 2013 10:46:48 -0700 Subject: [PATCH 66/76] cr cleanup --- libraries/voxels/src/VoxelTree.cpp | 33 +++++++++++++++--------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 7227d1e6e6..f94b4b9f26 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -243,7 +243,8 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, int bufferSizeByt int octalCodeBytes = bytesRequiredForCodeLength(*bitstreamAt); int theseBytesRead = 0; theseBytesRead += octalCodeBytes; - theseBytesRead += readNodeData(bitstreamRootNode, bitstreamAt + octalCodeBytes, bufferSizeBytes - (bytesRead+octalCodeBytes)); + theseBytesRead += readNodeData(bitstreamRootNode, bitstreamAt + octalCodeBytes, + bufferSizeBytes - (bytesRead + octalCodeBytes)); // skip bitstream to new startPoint bitstreamAt += theseBytesRead; @@ -257,33 +258,33 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, int bufferSizeByt // Note: uses the codeColorBuffer format, but the color's are ignored, because // this only finds and deletes the node from the tree. void VoxelTree::deleteVoxelCodeFromTree(unsigned char *codeBuffer) { - VoxelNode* parentNode = NULL; + VoxelNode* parentNode = NULL; VoxelNode* nodeToDelete = nodeForOctalCode(rootNode, codeBuffer, &parentNode); - + // If the node exists... - int lengthInBytes = bytesRequiredForCodeLength(*codeBuffer); // includes octet count, not color! + int lengthInBytes = bytesRequiredForCodeLength(*codeBuffer); // includes octet count, not color! if (0 == memcmp(nodeToDelete->octalCode,codeBuffer,lengthInBytes)) { - float* vertices = firstVertexForCode(nodeToDelete->octalCode); - delete []vertices; + float* vertices = firstVertexForCode(nodeToDelete->octalCode); + delete[] vertices; - if (parentNode) { - float* vertices = firstVertexForCode(parentNode->octalCode); - delete []vertices; - - int childNDX = branchIndexWithDescendant(parentNode->octalCode, codeBuffer); + if (parentNode) { + float* vertices = firstVertexForCode(parentNode->octalCode); + delete[] vertices; + + int childIndex = branchIndexWithDescendant(parentNode->octalCode, codeBuffer); - delete parentNode->children[childNDX]; // delete the child nodes - parentNode->children[childNDX]=NULL; // set it to NULL + delete parentNode->children[childIndex]; // delete the child nodes + parentNode->children[childIndex] = NULL; // set it to NULL - reaverageVoxelColors(rootNode); // Fix our colors!! Need to call it on rootNode - } + reaverageVoxelColors(rootNode); // Fix our colors!! Need to call it on rootNode + } } } void VoxelTree::eraseAllVoxels() { - // XXXBHG Hack attack - is there a better way to erase the voxel tree? + // XXXBHG Hack attack - is there a better way to erase the voxel tree? delete rootNode; // this will recurse and delete all children rootNode = new VoxelNode(); rootNode->octalCode = new unsigned char[1]; From 7d801e99d1bf7162b2fdea7a8dbe65467ac780a5 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Apr 2013 10:55:04 -0700 Subject: [PATCH 67/76] cr cleanup --- libraries/voxels/src/VoxelTree.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index f94b4b9f26..f7ce3eacb2 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -748,7 +748,7 @@ int VoxelTree::searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSearchLevel, - VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag) { + VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag) { // Keep track of how deep we've searched. currentSearchLevel++; @@ -802,8 +802,8 @@ int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSe if (distance < boundaryDistanceForRenderLevel(*childNode->octalCode + 1)) { inViewCount = insertIntoSortedArrays((void*)childNode, distance, i, - (void**)&inViewChildren, (float*)&distancesToChildren, (int*)&positionOfChildren, - inViewCount, MAX_CHILDREN); + (void**)&inViewChildren, (float*)&distancesToChildren, + (int*)&positionOfChildren, inViewCount, MAX_CHILDREN); } } } From 447de68fb57ba64b0e5ba024d6734d781b30182f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Apr 2013 11:06:30 -0700 Subject: [PATCH 68/76] cr cleanup, remove loadBitstreamBuffer() --- libraries/voxels/src/VoxelTree.cpp | 219 ++--------------------------- libraries/voxels/src/VoxelTree.h | 9 -- voxel-server/src/main.cpp | 61 +------- 3 files changed, 13 insertions(+), 276 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index f7ce3eacb2..a63c906d8b 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -308,199 +308,6 @@ void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) { lastCreatedNode->setColor(newColor); } -unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, - VoxelNode *currentVoxelNode, - MarkerNode *currentMarkerNode, - const glm::vec3& agentPosition, - float thisNodePosition[3], - const ViewFrustum& viewFrustum, - bool viewFrustumCulling, - unsigned char * stopOctalCode) -{ - unsigned char * childStopOctalCode = NULL; - static unsigned char *initialBitstreamPos = bitstreamBuffer; - - if (stopOctalCode == NULL) { - stopOctalCode = rootNode->octalCode; - } - - // check if we have any children - bool hasAtLeastOneChild; - - for (int i = 0; i < 8; i++) { - if (currentVoxelNode->children[i] != NULL) { - hasAtLeastOneChild = true; - } - } - - // if we have at least one child, check if it will be worth recursing into our children - if (hasAtLeastOneChild) { - - int firstIndexToCheck = 0; - unsigned char * childMaskPointer = NULL; - - float halfUnitForVoxel = powf(0.5, *currentVoxelNode->octalCode) * (0.5 * TREE_SCALE); - float distanceToVoxelCenter = sqrtf(powf(agentPosition[0] - thisNodePosition[0] - halfUnitForVoxel, 2) + - powf(agentPosition[1] - thisNodePosition[1] - halfUnitForVoxel, 2) + - powf(agentPosition[2] - thisNodePosition[2] - halfUnitForVoxel, 2)); - - if (distanceToVoxelCenter < boundaryDistanceForRenderLevel(*currentVoxelNode->octalCode + 1)) { - - // write this voxel's data if we're below or at - // or at the same level as the stopOctalCode - - if (*currentVoxelNode->octalCode >= *stopOctalCode) { - - if ((bitstreamBuffer - initialBitstreamPos) + MAX_TREE_SLICE_BYTES > MAX_VOXEL_PACKET_SIZE) { - // we can't send this packet, not enough room - // return our octal code as the stop - return currentVoxelNode->octalCode; - } - - if (strcmp((char *)stopOctalCode, (char *)currentVoxelNode->octalCode) == 0) { - // this is is the root node for this packet - // add the leading V - *(bitstreamBuffer++) = PACKET_HEADER_VOXEL_DATA; - - // add its octal code to the packet - int octalCodeBytes = bytesRequiredForCodeLength(*currentVoxelNode->octalCode); - - memcpy(bitstreamBuffer, currentVoxelNode->octalCode, octalCodeBytes); - bitstreamBuffer += octalCodeBytes; - } - - // default color mask is 0, increment pointer for colors - *bitstreamBuffer = 0; - - // keep a colorPointer so we can check how many colors were added - unsigned char *colorPointer = bitstreamBuffer + 1; - - for (int i = 0; i < 8; i++) { - // Rules for including a child: - // 1) child must exists - if ((currentVoxelNode->children[i] != NULL)) { - // 2) child must have a color... - if (currentVoxelNode->children[i]->isColored()) { - unsigned char* childOctalCode = currentVoxelNode->children[i]->octalCode; - - float childPosition[3]; - copyFirstVertexForCode(childOctalCode,(float*)&childPosition); - childPosition[0] *= TREE_SCALE; // scale it up - childPosition[1] *= TREE_SCALE; // scale it up - childPosition[2] *= TREE_SCALE; // scale it up - - float halfChildVoxel = powf(0.5, *childOctalCode) * (0.5 * TREE_SCALE); - float fullChildVoxel = halfChildVoxel * 2.0f; - AABox childBox; - childBox.setBox(glm::vec3(childPosition[0], childPosition[1], childPosition[2]), - fullChildVoxel, fullChildVoxel, fullChildVoxel); - - bool childInView = !viewFrustumCulling || - (ViewFrustum::OUTSIDE != viewFrustum.boxInFrustum(childBox)); - - /// XXXBHG - debug code, switch this to true, and we'll send everything but include false coloring - // on voxels based on whether or not they match these rules. - bool falseColorInsteadOfCulling = false; - bool sendChild = childInView || falseColorInsteadOfCulling; - - // if we sendAnyway, we'll do false coloring of the voxels based on childInView - if (sendChild) { - - // copy in the childs color to bitstreamBuffer - if (childInView) { - // true color - memcpy(colorPointer, currentVoxelNode->children[i]->getTrueColor(), 3); - } else { - unsigned char red[3] = {255,0,0}; - if (!childInView) { - // If not in view, color them red - memcpy(colorPointer, red, 3); - } - } - colorPointer += 3; - - // set the colorMask by bitshifting the value of childExists - *bitstreamBuffer += (1 << (7 - i)); - } - } - } - } - - // push the bitstreamBuffer forwards for the number of added colors - bitstreamBuffer += (colorPointer - bitstreamBuffer); - - // maintain a pointer to this spot in the buffer so we can set our child mask - // depending on the results of the recursion below - childMaskPointer = bitstreamBuffer++; - - // reset the childMaskPointer for this node to 0 - *childMaskPointer = 0; - } else { - firstIndexToCheck = *stopOctalCode > 0 - ? branchIndexWithDescendant(currentVoxelNode->octalCode, stopOctalCode) - : 0; - } - - unsigned char * arrBufferBeforeChild = bitstreamBuffer; - - for (int i = firstIndexToCheck; i < 8; i ++) { - // ask the child to load this bitstream buffer - // if they or their descendants fill the MTU we will receive the childStopOctalCode back - if (currentVoxelNode->children[i] != NULL) { - if (!oneAtBit(currentMarkerNode->childrenVisitedMask, i)) { - - // create the marker node for this child if it does not yet exist - if (currentMarkerNode->children[i] == NULL) { - currentMarkerNode->children[i] = new MarkerNode(); - } - - float childNodePosition[3]; - copyFirstVertexForCode(currentVoxelNode->children[i]->octalCode,(float*)&childNodePosition); - childNodePosition[0] *= TREE_SCALE; // scale it up - childNodePosition[1] *= TREE_SCALE; // scale it up - childNodePosition[2] *= TREE_SCALE; // scale it up - - // ask the child to load the bitstream buffer with their data - childStopOctalCode = loadBitstreamBuffer(bitstreamBuffer, - currentVoxelNode->children[i], - currentMarkerNode->children[i], - agentPosition, - childNodePosition, - viewFrustum, - viewFrustumCulling, - stopOctalCode); - - if (bitstreamBuffer - arrBufferBeforeChild > 0) { - // this child added data to the packet - add it to our child mask - if (childMaskPointer != NULL) { - *childMaskPointer += (1 << (7 - i)); - } - - arrBufferBeforeChild = bitstreamBuffer; - } - } - } - - if (childStopOctalCode != NULL) { - break; - } else { - // this child node has been covered - // add the appropriate bit to the childrenVisitedMask for the current marker node - currentMarkerNode->childrenVisitedMask += 1 << (7 - i); - - // if we are above the stopOctal and we got a NULL code - // we cannot go to the next child - // so break and return the NULL stop code - if (*currentVoxelNode->octalCode < *stopOctalCode) { - break; - } - } - } - } - } - return childStopOctalCode; -} - void VoxelTree::processRemoveVoxelBitstream(unsigned char * bitstream, int bufferSizeBytes) { // XXXBHG: validate buffer is at least 4 bytes long? other guards?? unsigned short int itemNumber = (*((unsigned short int*)&bitstream[1])); @@ -861,8 +668,8 @@ int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, const Vi int currentEncodeLevel = 0; int childBytesWritten = encodeTreeBitstreamRecursion(maxEncodeLevel, currentEncodeLevel, - node, viewFrustum, - outputBuffer, availableBytes, bag); + node, viewFrustum, + outputBuffer, availableBytes, bag); // if childBytesWritten == 1 then something went wrong... that's not possible assert(childBytesWritten != 1); @@ -890,9 +697,9 @@ int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, const Vi // NOTE: This recursive function DOES NOT add the octcode to the buffer. It's assumed that the caller has // already done that. int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel, - VoxelNode* node, const ViewFrustum& viewFrustum, - unsigned char* outputBuffer, int availableBytes, - VoxelNodeBag& bag) const { + VoxelNode* node, const ViewFrustum& viewFrustum, + unsigned char* outputBuffer, int availableBytes, + VoxelNodeBag& bag) const { // How many bytes have we written so far at this level; int bytesAtThisLevel = 0; @@ -978,7 +785,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco // write the color data... for (int i = 0; i < MAX_CHILDREN; i++) { if (oneAtBit(childrenColoredBits, i)) { - memcpy(writeToThisLevelBuffer,&node->children[i]->getColor(),BYTES_PER_COLOR); + memcpy(writeToThisLevelBuffer, &node->children[i]->getColor(), BYTES_PER_COLOR); writeToThisLevelBuffer += BYTES_PER_COLOR; // move the pointer for color bytesAtThisLevel += BYTES_PER_COLOR; // keep track of byte count for color } @@ -998,7 +805,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco // If we have enough room to copy our local results into the buffer, then do so... if (availableBytes >= bytesAtThisLevel) { - memcpy(outputBuffer,&thisLevelBuffer[0],bytesAtThisLevel); + memcpy(outputBuffer, &thisLevelBuffer[0], bytesAtThisLevel); outputBuffer += bytesAtThisLevel; availableBytes -= bytesAtThisLevel; @@ -1033,8 +840,8 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco VoxelNode* childNode = node->children[i]; int thisLevel = currentEncodeLevel; - int childTreeBytesOut = encodeTreeBitstreamRecursion(maxEncodeLevel, thisLevel, - childNode, viewFrustum, outputBuffer, availableBytes, bag); + int childTreeBytesOut = encodeTreeBitstreamRecursion(maxEncodeLevel, thisLevel, childNode, + viewFrustum, outputBuffer, availableBytes, bag); // if the child wrote 0 bytes, it means that nothing below exists or was in view, or we ran out of space, // basically, the children below don't contain any info. @@ -1052,7 +859,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco // so, if the child returns 2 bytes out, we can actually consider that an empty tree also!! // // we can make this act like no bytes out, by just resetting the bytes out in this case - if (2 == childTreeBytesOut) { + if (childTreeBytesOut == 2) { childTreeBytesOut = 0; // this is the degenerate case of a tree with no colors and no child trees } @@ -1062,17 +869,15 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco // If we had previously started writing, and if the child DIDN'T write any bytes, // then we want to remove their bit from the childExistsPlaceHolder bitmask - if (0 == childTreeBytesOut) { + if (childTreeBytesOut == 0) { // remove this child's bit... childrenExistBits -= (1 << (7 - i)); - // repair the child exists mask *childExistsPlaceHolder = childrenExistBits; // Note: no need to move the pointer, cause we already stored this - } // end if (0 == childTreeBytesOut) + } // end if (childTreeBytesOut == 0) } // end if (oneAtBit(childrenExistBits, i)) } // end for } // end keepDiggingDeeper return bytesAtThisLevel; } - diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index c94d4ee2a7..ce0e24509f 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -45,15 +45,6 @@ public: void deleteVoxelCodeFromTree(unsigned char *codeBuffer); void printTreeForDebugging(VoxelNode *startNode); void reaverageVoxelColors(VoxelNode *startNode); - unsigned char * loadBitstreamBuffer(unsigned char*& bitstreamBuffer, - VoxelNode* currentVoxelNode, - MarkerNode* currentMarkerNode, - const glm::vec3& agentPosition, - float thisNodePosition[3], - const ViewFrustum& viewFrustum, - bool viewFrustumCulling, - unsigned char* octalCode = NULL); - void loadVoxelsFile(const char* fileName, bool wantColorRandomizer); void createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer); diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 208d2b12f0..13f8ab15a2 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -47,7 +47,6 @@ VoxelTree randomTree; bool wantColorRandomizer = false; bool debugViewFrustum = false; bool viewFrustumCulling = true; // for now -bool newVoxelDistributor = false; // for now void addSphere(VoxelTree * tree,bool random, bool wantColorRandomizer) { float r = random ? randFloatInRange(0.05,0.1) : 0.25; @@ -81,10 +80,6 @@ bool countVoxelsOperation(VoxelNode* node, bool down, void* extraData) { void addSphereScene(VoxelTree * tree, bool wantColorRandomizer) { printf("adding scene of spheres...\n"); - // The old voxel distributor has a hard time with smaller voxels and more - // complex scenes... so if we're using the old distributor make our scene - // simple with larger sized voxels - //int sphereBaseSize = ::newVoxelDistributor ? 512 : 256; int sphereBaseSize = 256; tree->createSphere(0.25,0.5,0.5,0.5,(1.0/sphereBaseSize),true,wantColorRandomizer); @@ -305,16 +300,6 @@ void *distributeVoxelsToListeners(void *args) { AgentList* agentList = AgentList::getInstance(); timeval lastSendTime; - unsigned char *stopOctal; - int packetCount; - - int totalBytesSent; - - unsigned char *voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE]; - unsigned char *voxelPacketEnd; - - float treeRoot[3] = {0, 0, 0}; - while (true) { gettimeofday(&lastSendTime, NULL); @@ -337,47 +322,7 @@ void *distributeVoxelsToListeners(void *args) { viewFrustum.calculate(); - if (::newVoxelDistributor) { - newDistributeHelper(agentList, agent, agentData, viewFrustum); - } else { - stopOctal = NULL; - packetCount = 0; - totalBytesSent = 0; - randomTree.leavesWrittenToBitstream = 0; - - for (int j = 0; j < PACKETS_PER_CLIENT_PER_INTERVAL; j++) { - voxelPacketEnd = voxelPacket; - stopOctal = randomTree.loadBitstreamBuffer(voxelPacketEnd, - randomTree.rootNode, - agentData->rootMarkerNode, - agentData->getPosition(), - treeRoot, - viewFrustum, - ::viewFrustumCulling, - stopOctal); - - agentList->getAgentSocket().send(agent->getActiveSocket(), voxelPacket, voxelPacketEnd - voxelPacket); - - packetCount++; - totalBytesSent += voxelPacketEnd - voxelPacket; - - // XXXBHG Hack Attack: This is temporary code to help debug an issue. - // Normally we use this break to prevent resending voxels that an agent has - // already visited. But since we might be modifying the voxel tree we might - // want to always send. This is a hack to test the behavior - bool alwaysSend = true; - if (!alwaysSend && agentData->rootMarkerNode->childrenVisitedMask == 255) { - break; - } - } - - // for any agent that has a root marker node with 8 visited children - // recursively delete its marker nodes so we can revisit - if (agentData->rootMarkerNode->childrenVisitedMask == 255) { - delete agentData->rootMarkerNode; - agentData->rootMarkerNode = new MarkerNode(); - } - } + newDistributeHelper(agentList, agent, agentData, viewFrustum); } } @@ -433,10 +378,6 @@ int main(int argc, const char * argv[]) ::wantColorRandomizer = cmdOptionExists(argc, argv, WANT_COLOR_RANDOMIZER); printf("wantColorRandomizer=%s\n", (::wantColorRandomizer ? "yes" : "no")); - const char* OLD_VOXEL_DISTRIBUTOR = "--OldVoxelDistributor"; - ::newVoxelDistributor = !cmdOptionExists(argc, argv, OLD_VOXEL_DISTRIBUTOR); - printf("newVoxelDistributor=%s\n", (::newVoxelDistributor ? "yes" : "no")); - // Check to see if the user passed in a command line option for loading a local // Voxel File. If so, load it now. const char* INPUT_FILE = "-i"; From dae3881821d6b7e4e3f39bf1d302910164894244 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Apr 2013 11:13:41 -0700 Subject: [PATCH 69/76] removed MarkerNode --- libraries/voxels/src/MarkerNode.cpp | 35 ----------------------------- libraries/voxels/src/MarkerNode.h | 22 ------------------ voxel-server/src/VoxelAgentData.cpp | 2 -- voxel-server/src/VoxelAgentData.h | 3 --- voxel-server/src/main.cpp | 7 ++---- 5 files changed, 2 insertions(+), 67 deletions(-) delete mode 100644 libraries/voxels/src/MarkerNode.cpp delete mode 100644 libraries/voxels/src/MarkerNode.h diff --git a/libraries/voxels/src/MarkerNode.cpp b/libraries/voxels/src/MarkerNode.cpp deleted file mode 100644 index f3199f4a32..0000000000 --- a/libraries/voxels/src/MarkerNode.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// -// MarkerNode.cpp -// hifi -// -// Created by Stephen Birarda on 3/26/13. -// -// - -#include "MarkerNode.h" -#include - -MarkerNode::MarkerNode() { - for (int i = 0; i < 8; i++) { - children[i] = NULL; - } - - childrenVisitedMask = 0; -} - -MarkerNode::~MarkerNode() { - for (int i = 0; i < 8; i++) { - delete children[i]; - } -} - -MarkerNode::MarkerNode(const MarkerNode &otherMarkerNode) { - childrenVisitedMask = otherMarkerNode.childrenVisitedMask; - - // recursively copy the children marker nodes - for (int i = 0; i < 8; i++) { - if (children[i] != NULL) { - children[i] = new MarkerNode(*otherMarkerNode.children[i]); - } - } -} diff --git a/libraries/voxels/src/MarkerNode.h b/libraries/voxels/src/MarkerNode.h deleted file mode 100644 index b411830325..0000000000 --- a/libraries/voxels/src/MarkerNode.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// MarkerNode.h -// hifi -// -// Created by Stephen Birarda on 3/26/13. -// -// - -#ifndef __hifi__MarkerNode__ -#define __hifi__MarkerNode__ - -class MarkerNode { -public: - MarkerNode(); - ~MarkerNode(); - MarkerNode(const MarkerNode &otherMarkerNode); - - unsigned char childrenVisitedMask; - MarkerNode *children[8]; -}; - -#endif /* defined(__hifi__MarkerNode__) */ diff --git a/voxel-server/src/VoxelAgentData.cpp b/voxel-server/src/VoxelAgentData.cpp index 53e07dcc7e..e4b2a38774 100644 --- a/voxel-server/src/VoxelAgentData.cpp +++ b/voxel-server/src/VoxelAgentData.cpp @@ -16,7 +16,6 @@ VoxelAgentData::VoxelAgentData() { } void VoxelAgentData::init() { - rootMarkerNode = new MarkerNode(); _voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE]; _voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE; _voxelPacketAt = _voxelPacket; @@ -40,7 +39,6 @@ void VoxelAgentData::writeToPacket(unsigned char* buffer, int bytes) { } VoxelAgentData::~VoxelAgentData() { - delete rootMarkerNode; delete[] _voxelPacket; } diff --git a/voxel-server/src/VoxelAgentData.h b/voxel-server/src/VoxelAgentData.h index 1955c6130a..d0afd5d3e3 100644 --- a/voxel-server/src/VoxelAgentData.h +++ b/voxel-server/src/VoxelAgentData.h @@ -12,14 +12,11 @@ #include #include #include -#include "MarkerNode.h" #include "VoxelNodeBag.h" #include "VoxelConstants.h" class VoxelAgentData : public AvatarData { public: - MarkerNode* rootMarkerNode; - VoxelAgentData(); ~VoxelAgentData(); VoxelAgentData(const VoxelAgentData &otherAgentData); diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 13f8ab15a2..a14085c924 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -169,15 +169,12 @@ void eraseVoxelTreeAndCleanupAgentVisitData() { if (agentData) { // clean up the agent visit data agentData->nodeBag.deleteAll(); - // old way - delete agentData->rootMarkerNode; - agentData->rootMarkerNode = new MarkerNode(); } } } -void newDistributeHelper(AgentList* agentList, AgentList::iterator& agent, VoxelAgentData* agentData, ViewFrustum& viewFrustum) { +void voxelDistributeHelper(AgentList* agentList, AgentList::iterator& agent, VoxelAgentData* agentData, ViewFrustum& viewFrustum) { // A quick explanation of the strategy here. First, each time through, we ask ourselves, do we have voxels // that need to be sent? If not, we search for them, if we do, then we send them. We store our to be sent voxel sub trees // in a VoxelNodeBag on a per agent basis. The bag stores just pointers to the root node of the sub tree to be sent, so @@ -322,7 +319,7 @@ void *distributeVoxelsToListeners(void *args) { viewFrustum.calculate(); - newDistributeHelper(agentList, agent, agentData, viewFrustum); + voxelDistributeHelper(agentList, agent, agentData, viewFrustum); } } From 91ca787e2f177e9a8d1a8775b24d7a8bcee03e5a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Apr 2013 11:14:36 -0700 Subject: [PATCH 70/76] removed MarkerNode --- libraries/voxels/src/VoxelTree.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index ce0e24509f..284d3e8f4a 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -14,7 +14,6 @@ #include "ViewFrustum.h" #include "VoxelNode.h" #include "VoxelNodeBag.h" -#include "MarkerNode.h" // Callback function, for recuseTreeWithOperation typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, bool down, void* extraData); From 747cfc04bec88ee9c8576c85983f4e86c0d35973 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Apr 2013 11:21:50 -0700 Subject: [PATCH 71/76] cr cleanup --- voxel-server/src/VoxelAgentData.cpp | 2 +- voxel-server/src/VoxelAgentData.h | 2 +- voxel-server/src/main.cpp | 24 ++++++++++++------------ 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/voxel-server/src/VoxelAgentData.cpp b/voxel-server/src/VoxelAgentData.cpp index e4b2a38774..7eba95364b 100644 --- a/voxel-server/src/VoxelAgentData.cpp +++ b/voxel-server/src/VoxelAgentData.cpp @@ -27,7 +27,7 @@ void VoxelAgentData::init() { void VoxelAgentData::resetVoxelPacket() { _voxelPacket[0] = PACKET_HEADER_VOXEL_DATA; _voxelPacketAt = &_voxelPacket[1]; - _voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE-1; + _voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE - 1; _voxelPacketWaiting = false; } diff --git a/voxel-server/src/VoxelAgentData.h b/voxel-server/src/VoxelAgentData.h index d0afd5d3e3..74a402bb78 100644 --- a/voxel-server/src/VoxelAgentData.h +++ b/voxel-server/src/VoxelAgentData.h @@ -29,7 +29,7 @@ public: void writeToPacket(unsigned char* buffer, int bytes); // writes to end of packet const unsigned char* getPacket() const { return _voxelPacket; } - int getPacketLength() const { return (MAX_VOXEL_PACKET_SIZE-_voxelPacketAvailableBytes); } + int getPacketLength() const { return (MAX_VOXEL_PACKET_SIZE - _voxelPacketAvailableBytes); } bool isPacketWaiting() const { return _voxelPacketWaiting; } int getAvailable() const { return _voxelPacketAvailableBytes; } int getMaxSearchLevel() const { return _maxSearchLevel; }; diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index a14085c924..452c6d272f 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -82,36 +82,36 @@ void addSphereScene(VoxelTree * tree, bool wantColorRandomizer) { int sphereBaseSize = 256; - tree->createSphere(0.25,0.5,0.5,0.5,(1.0/sphereBaseSize),true,wantColorRandomizer); + tree->createSphere(0.25, 0.5, 0.5, 0.5, (1.0 / sphereBaseSize), true, wantColorRandomizer); printf("one sphere added...\n"); - tree->createSphere(0.030625,0.5,0.5,(0.25-0.06125),(1.0/(sphereBaseSize*2)),true,true); + tree->createSphere(0.030625, 0.5, 0.5, (0.25-0.06125), (1.0 / (sphereBaseSize * 2)), true, true); printf("two spheres added...\n"); - tree->createSphere(0.030625,(1.0-0.030625),(1.0-0.030625),(1.0-0.06125),(1.0/(sphereBaseSize*2)),true,true); + tree->createSphere(0.030625, (1.0 - 0.030625), (1.0 - 0.030625), (1.0 - 0.06125), (1.0 / (sphereBaseSize * 2)), true, true); printf("three spheres added...\n"); - tree->createSphere(0.030625,(1.0-0.030625),(1.0-0.030625),0.06125,(1.0/(sphereBaseSize*2)),true,true); + tree->createSphere(0.030625, (1.0 - 0.030625), (1.0 - 0.030625), 0.06125, (1.0 / (sphereBaseSize * 2)), true, true); printf("four spheres added...\n"); - tree->createSphere(0.030625,(1.0-0.030625),0.06125,(1.0-0.06125),(1.0/(sphereBaseSize*2)),true,true); + tree->createSphere(0.030625, (1.0 - 0.030625), 0.06125, (1.0 - 0.06125), (1.0 / (sphereBaseSize * 2)), true, true); printf("five spheres added...\n"); - tree->createSphere(0.06125,0.125,0.125,(1.0-0.125),(1.0/(sphereBaseSize*2)),true,true); + tree->createSphere(0.06125, 0.125, 0.125, (1.0 - 0.125), (1.0 / (sphereBaseSize * 2)), true, true); float radius = 0.0125f; printf("6 spheres added...\n"); - tree->createSphere(radius,0.25,radius*5.0f,0.25,(1.0/(4096)),true,true); + tree->createSphere(radius, 0.25, radius * 5.0f, 0.25, (1.0 / 4096), true, true); printf("7 spheres added...\n"); - tree->createSphere(radius,0.125,radius*5.0f,0.25,(1.0/(4096)),true,true); + tree->createSphere(radius, 0.125, radius * 5.0f, 0.25, (1.0 / 4096), true, true); printf("8 spheres added...\n"); - tree->createSphere(radius,0.075,radius*5.0f,0.25,(1.0/(4096)),true,true); + tree->createSphere(radius, 0.075, radius * 5.0f, 0.25, (1.0 / 4096), true, true); printf("9 spheres added...\n"); - tree->createSphere(radius,0.05,radius*5.0f,0.25,(1.0/(4096)),true,true); + tree->createSphere(radius, 0.05, radius * 5.0f, 0.25, (1.0 / 4096), true, true); printf("10 spheres added...\n"); - tree->createSphere(radius,0.025,radius*5.0f,0.25,(1.0/(4096)),true,true); + tree->createSphere(radius, 0.025, radius * 5.0f, 0.25, (1.0 / 4096), true, true); printf("11 spheres added...\n"); _nodeCount=0; tree->recurseTreeWithOperation(countVoxelsOperation); - printf("Nodes after adding scene %d nodes\n",_nodeCount); + printf("Nodes after adding scene %d nodes\n", _nodeCount); printf("DONE adding scene of spheres...\n"); From 7fddd63a6199d9a08175fb89395c083f599e8f5e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Apr 2013 11:29:13 -0700 Subject: [PATCH 72/76] cr cleanup --- libraries/voxels/src/VoxelTree.h | 12 ++++++------ voxel-server/src/main.cpp | 33 ++++++++++++++------------------ 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 284d3e8f4a..ac3c762fcf 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -50,19 +50,19 @@ public: void recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData=NULL); int encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, const ViewFrustum& viewFrustum, - unsigned char* outputBuffer, int availableBytes, - VoxelNodeBag& bag); + unsigned char* outputBuffer, int availableBytes, + VoxelNodeBag& bag); int searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag); private: int encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel, - VoxelNode* node, const ViewFrustum& viewFrustum, - unsigned char* outputBuffer, int availableBytes, - VoxelNodeBag& bag) const; + VoxelNode* node, const ViewFrustum& viewFrustum, + unsigned char* outputBuffer, int availableBytes, + VoxelNodeBag& bag) const; int searchForColoredNodesRecursion(int maxSearchLevel, int& currentSearchLevel, - VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag); + VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag); void recurseNodeWithOperation(VoxelNode* node, RecurseVoxelTreeOperation operation, void* extraData); VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode); diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 452c6d272f..752babf40b 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -155,22 +155,16 @@ void randomlyFillVoxelTree(int levelsToGo, VoxelNode *currentRootNode) { void eraseVoxelTreeAndCleanupAgentVisitData() { - // As our tree to erase all it's voxels - ::randomTree.eraseAllVoxels(); - - // enumerate the agents clean up their marker nodes - - for (AgentList::iterator agent = AgentList::getInstance()->begin(); agent != AgentList::getInstance()->end(); agent++) { - - //printf("eraseVoxelTreeAndCleanupAgentVisitData() agent[%d]\n",i); - - VoxelAgentData* agentData = (VoxelAgentData *)agent->getLinkedData(); - - if (agentData) { + // As our tree to erase all it's voxels + ::randomTree.eraseAllVoxels(); + // enumerate the agents clean up their marker nodes + for (AgentList::iterator agent = AgentList::getInstance()->begin(); agent != AgentList::getInstance()->end(); agent++) { + VoxelAgentData* agentData = (VoxelAgentData*) agent->getLinkedData(); + if (agentData) { // clean up the agent visit data agentData->nodeBag.deleteAll(); } - } + } } @@ -214,7 +208,7 @@ void voxelDistributeHelper(AgentList* agentList, AgentList::iterator& agent, Vox // with chunky granularity and then finer and finer granularity until they've gotten the whole scene. Then we start // over to handle packet loss and changes in the scene. int maxLevelReached = randomTree.searchForColoredNodes(agentData->getMaxSearchLevel(), randomTree.rootNode, - viewFrustum, agentData->nodeBag); + viewFrustum, agentData->nodeBag); agentData->setMaxLevelReached(maxLevelReached); // If nothing got added, then we bump our levels. @@ -229,7 +223,7 @@ void voxelDistributeHelper(AgentList* agentList, AgentList::iterator& agent, Vox // If we have something in our nodeBag, then turn them into packets and send them out... if (!agentData->nodeBag.isEmpty()) { - static unsigned char tempOutputBuffer[MAX_VOXEL_PACKET_SIZE-1]; // save on allocs by making this static + static unsigned char tempOutputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static int bytesWritten = 0; // NOTE: we can assume the voxelPacket has already been set up with a "V" @@ -242,7 +236,8 @@ void voxelDistributeHelper(AgentList* agentList, AgentList::iterator& agent, Vox // Only let this guy create at largest packets equal to the amount of space we have left in our final??? // Or let it create the largest possible size (minus 1 for the "V") bytesWritten = randomTree.encodeTreeBitstream(agentData->getMaxSearchLevel(), subTree, viewFrustum, - &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE-1, agentData->nodeBag); + &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, + agentData->nodeBag); // if we have room in our final packet, add this buffer to the final packet if (agentData->getAvailable() >= bytesWritten) { @@ -250,7 +245,7 @@ void voxelDistributeHelper(AgentList* agentList, AgentList::iterator& agent, Vox } else { // otherwise "send" the packet because it's as full as we can make it for now agentList->getAgentSocket().send(agent->getActiveSocket(), - agentData->getPacket(), agentData->getPacketLength()); + agentData->getPacket(), agentData->getPacketLength()); // keep track that we sent it packetsSentThisInterval++; @@ -266,7 +261,7 @@ void voxelDistributeHelper(AgentList* agentList, AgentList::iterator& agent, Vox // If we have a partial packet ready, then send it... if (agentData->isPacketWaiting()) { agentList->getAgentSocket().send(agent->getActiveSocket(), - agentData->getPacket(), agentData->getPacketLength()); + agentData->getPacket(), agentData->getPacketLength()); // reset our finalOutputBuffer (keep the 'V') agentData->resetVoxelPacket(); @@ -302,7 +297,7 @@ void *distributeVoxelsToListeners(void *args) { // enumerate the agents to send 3 packets to each for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { - VoxelAgentData* agentData = (VoxelAgentData *)agent->getLinkedData(); + VoxelAgentData* agentData = (VoxelAgentData*) agent->getLinkedData(); // Sometimes the agent data has not yet been linked, in which case we can't really do anything if (agentData) { From 2a746ec1117894582a3d1db21487322c6b71a642 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Apr 2013 11:34:14 -0700 Subject: [PATCH 73/76] cr cleanup --- libraries/voxels/src/VoxelTree.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index a63c906d8b..bd5bd5c8a3 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -647,8 +647,8 @@ int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSe // because we run out of room on the outputBuffer, then we will add VoxelNode*'s of the trees that need // to be encoded to that array. If the array int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, const ViewFrustum& viewFrustum, - unsigned char* outputBuffer, int availableBytes, - VoxelNodeBag& bag) { + unsigned char* outputBuffer, int availableBytes, + VoxelNodeBag& bag) { // How many bytes have we written so far at this level; int bytesWritten = 0; From 08c7c486d9bb71d334bea287d01d4015496493aa Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Apr 2013 11:40:12 -0700 Subject: [PATCH 74/76] cr cleanup --- voxel-server/src/main.cpp | 70 +++------------------------------------ 1 file changed, 5 insertions(+), 65 deletions(-) diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 752babf40b..716a4e9d7b 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -168,45 +168,9 @@ void eraseVoxelTreeAndCleanupAgentVisitData() { } -void voxelDistributeHelper(AgentList* agentList, AgentList::iterator& agent, VoxelAgentData* agentData, ViewFrustum& viewFrustum) { - // A quick explanation of the strategy here. First, each time through, we ask ourselves, do we have voxels - // that need to be sent? If not, we search for them, if we do, then we send them. We store our to be sent voxel sub trees - // in a VoxelNodeBag on a per agent basis. The bag stores just pointers to the root node of the sub tree to be sent, so - // it doesn't store much on a per agent basis. - // - // There could be multiple strategies at play for how we determine which voxels need to be sent. For example, at the - // simplest level, we can just add the root node to this bag, and let the system send it. The other thing that we use - // this bag for is, keeping track of voxels sub trees we wanted to send in the packet, but wouldn't fit into the current - // packet because they were too big once encoded. So, as we run though this function multiple times, we start out with - // voxel sub trees that we determined needed to be sent because they were in view, new, correct distance, etc. But as - // we send those sub trees, if their child trees don't fit in a packet, we'll add those sub trees to this bag as well, and - // next chance we get, we'll also send those needed sub trees. - // If we don't have nodes already in our agent's node bag, then fill the node bag +void voxelDistributor(AgentList* agentList, AgentList::iterator& agent, VoxelAgentData* agentData, ViewFrustum& viewFrustum) { + // If the bag is empty, fill it... if (agentData->nodeBag.isEmpty()) { - - // To get things started, we look for colored nodes. We could have also just started with the root node. In fact, if - // you substitute this call with something as simple as agentData->nodeBag.insert(rootNod), you'll see almost the same - // behavior on the client. The scene will appear. - // - // So why do we do this extra effort to look for colored nodes? It turns out that there are subtle differences between - // how many bytes it takes to encode a tree based on how deep it is relative to the root node (which effects the octal - // code size) vs how dense the tree is (which effects how many bits in the bitMask are being wasted, and maybe more - // importantly, how many subtrees are also included). There is a break point where the more dense a tree is, it's more - // efficient to encode the peers together with their empty parents. This would argue that we shouldn't search for these - // sub trees, and we should instead encode the parent for dense scenes. - // - // But, there's another important side effect of dense trees related to out maximum packet size. Namely... if a tree - // is very dense, then you can't fit as many branches in a single network packet. Because when we encode the parent and - // children in a single packet, we must include the entire child branch (all the way down to our target LOD) before we - // can include the siblings. Since dense trees take more space per ranch, we often end up only being able to encode a - // single branch. This means on a per packet basis, the trees actually _are not_ dense. And sparse trees are shorter to - // encode when we only include the child tree. - // - // Now, a quick explanation of maxSearchLevel: We will actually send the entire scene, multiple times for each search - // level. We start at level 1, and we scan the scene for this level, then we increment to the next level until we've - // sent the entire scene at it's deepest possible level. This means that clients will get an initial view of the scene - // with chunky granularity and then finer and finer granularity until they've gotten the whole scene. Then we start - // over to handle packet loss and changes in the scene. int maxLevelReached = randomTree.searchForColoredNodes(agentData->getMaxSearchLevel(), randomTree.rootNode, viewFrustum, agentData->nodeBag); agentData->setMaxLevelReached(maxLevelReached); @@ -225,58 +189,34 @@ void voxelDistributeHelper(AgentList* agentList, AgentList::iterator& agent, Vox if (!agentData->nodeBag.isEmpty()) { static unsigned char tempOutputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static int bytesWritten = 0; - - // NOTE: we can assume the voxelPacket has already been set up with a "V" int packetsSentThisInterval = 0; - while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL) { if (!agentData->nodeBag.isEmpty()) { VoxelNode* subTree = agentData->nodeBag.extract(); - - // Only let this guy create at largest packets equal to the amount of space we have left in our final??? - // Or let it create the largest possible size (minus 1 for the "V") bytesWritten = randomTree.encodeTreeBitstream(agentData->getMaxSearchLevel(), subTree, viewFrustum, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, agentData->nodeBag); - // if we have room in our final packet, add this buffer to the final packet if (agentData->getAvailable() >= bytesWritten) { agentData->writeToPacket(&tempOutputBuffer[0], bytesWritten); } else { - // otherwise "send" the packet because it's as full as we can make it for now agentList->getAgentSocket().send(agent->getActiveSocket(), agentData->getPacket(), agentData->getPacketLength()); - - // keep track that we sent it packetsSentThisInterval++; - - // reset our finalOutputBuffer (keep the 'V') agentData->resetVoxelPacket(); - - // we also need to stick the last created partial packet in here!! agentData->writeToPacket(&tempOutputBuffer[0], bytesWritten); } } else { - // we're here, if there are no more nodes in our bag waiting to be sent. - // If we have a partial packet ready, then send it... if (agentData->isPacketWaiting()) { agentList->getAgentSocket().send(agent->getActiveSocket(), agentData->getPacket(), agentData->getPacketLength()); - - // reset our finalOutputBuffer (keep the 'V') agentData->resetVoxelPacket(); } - - // and we're done now for this interval, because we know we have not nodes in our - // bag, and we just sent the last waiting packet if we had one, so tell ourselves - // we done for the interval - packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; + packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; // done for now, no nodes left } } - - // Ok, so we're in the "send from our bag mode"... if during this last pass, we emptied our bag, then - // we want to move to the next level. + // if during this last pass, we emptied our bag, then we want to move to the next level. if (agentData->nodeBag.isEmpty()) { if (agentData->getMaxLevelReached() < agentData->getMaxSearchLevel()) { agentData->resetMaxSearchLevel(); @@ -314,7 +254,7 @@ void *distributeVoxelsToListeners(void *args) { viewFrustum.calculate(); - voxelDistributeHelper(agentList, agent, agentData, viewFrustum); + voxelDistributor(agentList, agent, agentData, viewFrustum); } } From f8523e135d5601581231c2ab015bf46a13eb1da1 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Apr 2013 11:44:59 -0700 Subject: [PATCH 75/76] cr cleanup --- libraries/voxels/src/VoxelTree.cpp | 88 +----------------------------- 1 file changed, 1 insertion(+), 87 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index bd5bd5c8a3..cbbccedb59 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -5,48 +5,6 @@ // Created by Stephen Birarda on 3/13/13. // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // -// -// -// Oct-Tree in bits, and child ordinals -// -// Location Decimal Bit Child in Array -// ------------------- ------- --- --------------- -// Bottom Right Near 128 8th 0 -// Bottom Right Far 64 7th 1 -// Top Right Near 32 6th 2 -// Top Right Far 16 5th 3 -// Bottom Left Near 8 4th 4 -// Bottom Left Far 4 3rd 5 -// Top Left Near 2 2nd 6 -// Top Left Far 1 1st 7 -// -// ^ -// +-------|------+ + Y -// / / | /| -// / 1 / | 16 / | -// /------/-------+ | -// / / | /|16| -// / 2 / 32 | / | | -// / / |/ | /| / +Z -// +--------------+ 32|/ | / -// | | | / | / -// | | | /| | / -// | 2 | 32 | / |64| / -// 4----| | |/ | |/ -// +------|------ + | / -// | | | | / -// | | |128|/ -// | 8 | 128 | / -// | | | / -// | | | / -// < - - - +------+-------+/ - - - - - - > -// +X (0,0,0) -X -// /| -// / | -// / | -// -Z / V -Y -// -// #ifdef _WIN32 #define _USE_MATH_DEFINES @@ -393,11 +351,7 @@ void VoxelTree::reaverageVoxelColors(VoxelNode *startNode) { } } } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: VoxelTree::loadVoxelsFile() -// Description: Loads HiFidelity encoded Voxels from a binary file. The current file -// format is a stream of single voxels with color data. -// Complaints: Brad :) + void VoxelTree::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) { int vCount = 0; @@ -452,11 +406,6 @@ void VoxelTree::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) { } } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: VoxelTree::createSphere() -// Description: Creates a sphere of voxels in the local system at a given location/radius -// To Do: Move this function someplace better? -// Complaints: Brad :) void VoxelTree::createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer) { // About the color of the sphere... we're going to make this sphere be a gradient // between two RGB colors. We will do the gradient along the phi spectrum @@ -535,19 +484,11 @@ void VoxelTree::createSphere(float r,float xc, float yc, float zc, float s, bool this->reaverageVoxelColors(this->rootNode); } -// This will encode a larger tree into multiple subtree bitstreams. Given a node it will search for deeper subtrees that -// have color. It will search for sub trees, and upon finding a subTree, it will stick the node in the bag to for later -// endcoding. It returns the maximum level that we reached during our search. That might be the maximum level we were asked -// to search (if the tree is deeper than that max level), or it will be the maximum level of the tree (if we asked to search -// deeper than the tree exists). int VoxelTree::searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag) { // call the recursive version, this will add all found colored node roots to the bag int currentSearchLevel = 0; - // levelReached will be the maximum level reached. If we made it to the maxSearchLevel, then it will be that. - // but if the tree is shallower than the maxSearchLevel, then we will return the deepest level of the tree that - // exists. int levelReached = searchForColoredNodesRecursion(maxSearchLevel, currentSearchLevel, rootNode, viewFrustum, bag); return levelReached; } @@ -636,16 +577,6 @@ int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSe return maxChildLevel; } -// This will encode a tree bitstream, given a node it will encode the full tree from that point onward. -// It will ignore any branches that are not in view. But other than that, it will not (can not) do any -// prioritization of branches or deeper searching of the branches for optimization. -// -// NOTE: This STUB function DOES add the octcode to the buffer, then it calls the recursive helper to -// actually encode the tree -// -// extraTrees is assumed to me an allocated array of VoxelNode*, if we're unable to fully encode the tree -// because we run out of room on the outputBuffer, then we will add VoxelNode*'s of the trees that need -// to be encoded to that array. If the array int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, const ViewFrustum& viewFrustum, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag) { @@ -690,12 +621,6 @@ int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, const Vi return bytesWritten; } -// This will encode a tree bitstream, given a node it will encode the full tree from that point onward. -// It will ignore any branches that are not in view. But other than that, it will not (can not) do any -// prioritization of branches or deeper searching of the branches for optimization. -// -// NOTE: This recursive function DOES NOT add the octcode to the buffer. It's assumed that the caller has -// already done that. int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel, VoxelNode* node, const ViewFrustum& viewFrustum, unsigned char* outputBuffer, int availableBytes, @@ -799,10 +724,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco // We only need to keep digging, if there is at least one child that is inView, and not a leaf. keepDiggingDeeper = (inViewNotLeafCount > 0); - // at this point we need to do a gut check. If we're writing, then we need to check how many bytes we've - // written at this level, and how many bytes we have available in the outputBuffer. If we can fit what we've got so far - // and room for the no more children terminator, then let's write what we got so far. - // If we have enough room to copy our local results into the buffer, then do so... if (availableBytes >= bytesAtThisLevel) { memcpy(outputBuffer, &thisLevelBuffer[0], bytesAtThisLevel); @@ -810,13 +731,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco outputBuffer += bytesAtThisLevel; availableBytes -= bytesAtThisLevel; } else { - // we've run out of room!!! What do we do!!! - // 1) return 0 for bytes written so upper levels do the right thing, namely prune us from their trees - // 2) add our node to the list of extra nodes for later output... - // Note: we don't do any termination for this level, we just return 0, then the upper level is in charge - // of handling things. For example, in case of child iteration, it needs to unset the child exist bit for - // this child. - // add our node the the list of extra nodes to output later... bag.insert(node); return 0; } From 47326230a1702a81d6ac9723d8d934732aa29cc4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Apr 2013 11:57:06 -0700 Subject: [PATCH 76/76] fixed build buster --- libraries/shared/src/SharedUtil.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 463bd2a339..7c8f7f5e9b 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #ifdef _WIN32 #include "Syssocket.h" #endif