From 287775e0f914d58d2f6d7e91779a5bf48537927a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 28 Mar 2013 14:35:45 -0700 Subject: [PATCH] change the loadBitstreamBuffer method to accommodate absence of childMask variable --- shared/src/VoxelTree.cpp | 326 ++++++++++++++++++++++++--------------- shared/src/VoxelTree.h | 12 +- 2 files changed, 211 insertions(+), 127 deletions(-) diff --git a/shared/src/VoxelTree.cpp b/shared/src/VoxelTree.cpp index ca76f4067a..61ee853f37 100644 --- a/shared/src/VoxelTree.cpp +++ b/shared/src/VoxelTree.cpp @@ -12,10 +12,35 @@ #include "OctalCode.h" #include "VoxelTree.h" +const int TREE_SCALE = 10; + +int boundaryDistanceForRenderLevel(unsigned int renderLevel) { + switch (renderLevel) { + case 1: + return 100; + break; + case 2: + return 50; + break; + case 3: + return 25; + break; + case 4: + return 12; + break; + case 5: + return 6; + break; + default: + return 3; + break; + } +} + VoxelTree::VoxelTree() { rootNode = new VoxelNode(); rootNode->octalCode = new unsigned char[1]; - *rootNode->octalCode = (char)0; + *rootNode->octalCode = 0; } VoxelTree::~VoxelTree() { @@ -26,22 +51,6 @@ VoxelTree::~VoxelTree() { } } -int VoxelTree::levelForViewerPosition(float *position) { - // get the distance to the viewer - // for now the voxel tree starts at 0,0,0 - float distance = sqrtf(powf(position[0] + 30, 2) + powf(position[2] + 30, 2)); - - // go through the if else branch to return the right level - // this is a gross way to do this for now for a friday demo - if (distance >= 50) { - return 3; - } else if (distance >= 20) { - return 4; - } else { - return 5; - } -} - VoxelNode * VoxelTree::nodeForOctalCode(VoxelNode *ancestorNode, unsigned char * needleCode) { // find the appropriate branch index based on this ancestorNode if (*needleCode > 0) { @@ -77,45 +86,39 @@ VoxelNode * VoxelTree::createMissingNode(VoxelNode *lastParentNode, unsigned cha } } -/// If node has color & <= 4 children then prune children +// if node has color & <= 4 children then prune children void VoxelTree::pruneTree(VoxelNode* pruneAt) { int childCount = 0; // determine how many children we have - for (int i = 0; i < 8; i++) - { - if (pruneAt->children[i]) - { + for (int i = 0; i < 8; i++) { + if (pruneAt->children[i]) { childCount++; } } + // if appropriate, prune them - if (pruneAt->color[3] && childCount <= 4) - { - for (int i = 0; i < 8; i++) - { - if (pruneAt->children[i]) - { + if (pruneAt->color[3] && childCount <= 4) { + for (int i = 0; i < 8; i++) { + if (pruneAt->children[i]) { delete pruneAt->children[i]; pruneAt->children[i]=NULL; } } - } - else - { + } else { // Otherwise, iterate the children and recursively call // prune on all of them - for (int i = 0; i < 8; i++) - { - if (pruneAt->children[i]) - { + for (int i = 0; i < 8; i++) { + if (pruneAt->children[i]) { this->pruneTree(pruneAt->children[i]); } } } } -int VoxelTree::readNodeData(VoxelNode *destinationNode, unsigned char * nodeData, int bytesLeftToRead) { +int VoxelTree::readNodeData(VoxelNode *destinationNode, + unsigned char * nodeData, + int bytesLeftToRead) { // instantiate variable for bytes already read int bytesRead = 1; @@ -147,7 +150,7 @@ int VoxelTree::readNodeData(VoxelNode *destinationNode, unsigned char * nodeData destinationNode->setColorFromAverageOfChildren(colorArray); // give this destination node the child mask from the packet - destinationNode->childMask = *(nodeData + bytesRead); + unsigned char childMask = *(nodeData + bytesRead); int childIndex = 0; bytesRead++; @@ -155,14 +158,16 @@ int VoxelTree::readNodeData(VoxelNode *destinationNode, unsigned char * nodeData while (bytesLeftToRead - bytesRead > 0 && childIndex < 8) { // check the exists mask to see if we have a child to traverse into - if (oneAtBit(destinationNode->childMask, childIndex)) { + if (oneAtBit(childMask, childIndex)) { if (destinationNode->children[childIndex] == NULL) { // add a child at that index, if it doesn't exist destinationNode->addChildAtIndex(childIndex); } // tell the child to read the subsequent data - bytesRead += readNodeData(destinationNode->children[childIndex], nodeData + bytesRead, bytesLeftToRead - bytesRead); + bytesRead += readNodeData(destinationNode->children[childIndex], + nodeData + bytesRead, + bytesLeftToRead - bytesRead); } childIndex++; @@ -200,97 +205,164 @@ void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) { } unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, - unsigned char * stopOctalCode, VoxelNode *currentVoxelNode, - int deepestLevel) + MarkerNode *currentMarkerNode, + float * agentPosition, + float thisNodePosition[3], + unsigned char * stopOctalCode) { static unsigned char *initialBitstreamPos = bitstreamBuffer; - int firstIndexToCheck = 0; - - // we'll only be writing data if we're lower than - // 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++) = 'V'; - - // 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++) { - - // check if the child exists and is not transparent - if (currentVoxelNode->children[i] != NULL - && currentVoxelNode->children[i]->color[3] != 0) { - - // copy in the childs color to bitstreamBuffer - memcpy(colorPointer, currentVoxelNode->children[i]->color, 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); - - // copy the childMask to the current position of the bitstreamBuffer - // and push the buffer pointer forwards - *(bitstreamBuffer++) = *currentVoxelNode->octalCode < deepestLevel - 1 - ? currentVoxelNode->childMask - : 0; - } else { - firstIndexToCheck = *stopOctalCode > 0 - ? branchIndexWithDescendant(currentVoxelNode->octalCode, stopOctalCode) - : 0; - } - unsigned char * childStopOctalCode = NULL; - if (currentVoxelNode->childMask == 0) { - leavesWrittenToBitstream++; + if (stopOctalCode == NULL) { + stopOctalCode = rootNode->octalCode; } - if (*currentVoxelNode->octalCode < deepestLevel - 1) { - for (int i = firstIndexToCheck; i < 8; i ++) { + // 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 the distance to this voxel's center is less than the threshold + // distance for its children, we should send the children + if (distanceToVoxelCenter < boundaryDistanceForRenderLevel(*currentVoxelNode->octalCode + 1)) { - // 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 (*currentVoxelNode->octalCode < *stopOctalCode - && i > firstIndexToCheck - && childStopOctalCode == NULL) { - return currentVoxelNode->children[i]->octalCode; - } else { - if (oneAtBit(currentVoxelNode->childMask, i)) { - childStopOctalCode = loadBitstreamBuffer(bitstreamBuffer, stopOctalCode, currentVoxelNode->children[i], deepestLevel); - } else { - childStopOctalCode = NULL; + // 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++) = 'V'; + + // 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++) { + + // check if the child exists and is not transparent + if (currentVoxelNode->children[i] != NULL + && currentVoxelNode->children[i]->color[3] != 0) { + + // copy in the childs color to bitstreamBuffer + memcpy(colorPointer, currentVoxelNode->children[i]->color, 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; + } - if (childStopOctalCode != NULL) { - break; + 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(); + } + + // calculate the child's position based on the parent position + float childNodePosition[3]; + + 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); + } + } + + // ask the child to load the bitstream buffer with their data + childStopOctalCode = loadBitstreamBuffer(bitstreamBuffer, + currentVoxelNode->children[i], + currentMarkerNode->children[i], + agentPosition, + childNodePosition, + 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; + } + } } } } @@ -319,13 +391,23 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { } } - outputBits(startNode->childMask); + unsigned char childMask = 0; - // ask children to recursively output their trees - // if they aren't a leaf for (int k = 0; k < 8; k++) { if (startNode->children[k] != NULL) { - printTreeForDebugging(startNode->children[k]); + childMask += (1 << (7 - k)); } } + + outputBits(childMask); + + if (childMask > 0) { + // ask children to recursively output their trees + // if they aren't a leaf + for (int l = 0; l < 8; l++) { + if (startNode->children[l] != NULL) { + printTreeForDebugging(startNode->children[l]); + } + } + } } \ No newline at end of file diff --git a/shared/src/VoxelTree.h b/shared/src/VoxelTree.h index bea2533543..d3b2ccb597 100644 --- a/shared/src/VoxelTree.h +++ b/shared/src/VoxelTree.h @@ -11,6 +11,7 @@ #include #include "VoxelNode.h" +#include "MarkerNode.h" const int MAX_VOXEL_PACKET_SIZE = 1492; const int MAX_TREE_SLICE_BYTES = 26; @@ -26,14 +27,15 @@ public: VoxelNode *rootNode; int leavesWrittenToBitstream; - int levelForViewerPosition(float * position); void readBitstreamToTree(unsigned char * bitstream, int bufferSizeBytes); void readCodeColorBufferToTree(unsigned char *codeColorBuffer); - unsigned char * loadBitstreamBuffer(unsigned char *& bitstreamBuffer, - unsigned char * octalCode, - VoxelNode *currentVoxelNode, - int deepestLevel); void printTreeForDebugging(VoxelNode *startNode); + unsigned char * loadBitstreamBuffer(unsigned char *& bitstreamBuffer, + VoxelNode *currentVoxelNode, + MarkerNode *currentMarkerNode, + float * agentPosition, + float thisNodePosition[3], + unsigned char * octalCode = NULL); void pruneTree(VoxelNode* pruneAt); };