mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 09:28:46 +02:00
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
This commit is contained in:
parent
9bc2f667b6
commit
785ef88820
2 changed files with 362 additions and 41 deletions
|
@ -5,6 +5,48 @@
|
||||||
// Created by Stephen Birarda on 3/13/13.
|
// Created by Stephen Birarda on 3/13/13.
|
||||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
// 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
|
#ifdef _WIN32
|
||||||
#define _USE_MATH_DEFINES
|
#define _USE_MATH_DEFINES
|
||||||
|
@ -117,12 +159,14 @@ VoxelNode * VoxelTree::nodeForOctalCode(VoxelNode *ancestorNode, unsigned char *
|
||||||
return ancestorNode;
|
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);
|
int indexOfNewChild = branchIndexWithDescendant(lastParentNode->octalCode, codeToReach);
|
||||||
lastParentNode->addChildAtIndex(indexOfNewChild);
|
lastParentNode->addChildAtIndex(indexOfNewChild);
|
||||||
|
|
||||||
if (*lastParentNode->children[indexOfNewChild]->octalCode == *codeToReach) {
|
if (*lastParentNode->children[indexOfNewChild]->octalCode == *codeToReach) {
|
||||||
return lastParentNode;
|
return lastParentNode->children[indexOfNewChild];
|
||||||
} else {
|
} else {
|
||||||
return createMissingNode(lastParentNode->children[indexOfNewChild], codeToReach);
|
return createMissingNode(lastParentNode->children[indexOfNewChild], codeToReach);
|
||||||
}
|
}
|
||||||
|
@ -134,24 +178,24 @@ VoxelNode * VoxelTree::createMissingNode(VoxelNode *lastParentNode, unsigned cha
|
||||||
int VoxelTree::readNodeData(VoxelNode *destinationNode,
|
int VoxelTree::readNodeData(VoxelNode *destinationNode,
|
||||||
unsigned char * nodeData,
|
unsigned char * nodeData,
|
||||||
int bytesLeftToRead) {
|
int bytesLeftToRead) {
|
||||||
|
|
||||||
// instantiate variable for bytes already read
|
// instantiate variable for bytes already read
|
||||||
int bytesRead = 1;
|
int bytesRead = 1;
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
// check the colors mask to see if we have a child to color in
|
// check the colors mask to see if we have a child to color in
|
||||||
if (oneAtBit(*nodeData, i)) {
|
if (oneAtBit(*nodeData, i)) {
|
||||||
|
|
||||||
// create the child if it doesn't exist
|
// create the child if it doesn't exist
|
||||||
if (destinationNode->children[i] == NULL) {
|
if (destinationNode->children[i] == NULL) {
|
||||||
destinationNode->addChildAtIndex(i);
|
destinationNode->addChildAtIndex(i);
|
||||||
this->voxelsCreated++;
|
this->voxelsCreated++;
|
||||||
this->voxelsCreatedStats.updateAverage(1);
|
this->voxelsCreatedStats.updateAverage(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// pull the color for this child
|
// pull the color for this child
|
||||||
nodeColor newColor;
|
nodeColor newColor;
|
||||||
memcpy(newColor, nodeData + bytesRead, 3);
|
memcpy(newColor, nodeData + bytesRead, 3);
|
||||||
newColor[3] = 1;
|
newColor[3] = 1;
|
||||||
|
|
||||||
destinationNode->children[i]->setColor(newColor);
|
destinationNode->children[i]->setColor(newColor);
|
||||||
this->voxelsColored++;
|
this->voxelsColored++;
|
||||||
this->voxelsColoredStats.updateAverage(1);
|
this->voxelsColoredStats.updateAverage(1);
|
||||||
|
@ -193,17 +237,33 @@ int VoxelTree::readNodeData(VoxelNode *destinationNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelTree::readBitstreamToTree(unsigned char * bitstream, int bufferSizeBytes) {
|
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) {
|
while (bytesRead < bufferSizeBytes) {
|
||||||
// if the octal code returned is not on the same level as
|
VoxelNode* bitstreamRootNode = nodeForOctalCode(rootNode, (unsigned char *)bitstream, NULL);
|
||||||
// the code being searched for, we have VoxelNodes to create
|
|
||||||
bitstreamRootNode = createMissingNode(bitstreamRootNode, (unsigned char *)bitstream);
|
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->voxelsBytesRead += bufferSizeBytes;
|
||||||
this->voxelsBytesReadStats.updateAverage(bufferSizeBytes);
|
this->voxelsBytesReadStats.updateAverage(bufferSizeBytes);
|
||||||
}
|
}
|
||||||
|
@ -247,12 +307,11 @@ void VoxelTree::eraseAllVoxels() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) {
|
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
|
// create the node if it does not exist
|
||||||
if (*lastCreatedNode->octalCode != *codeColorBuffer) {
|
if (*lastCreatedNode->octalCode != *codeColorBuffer) {
|
||||||
VoxelNode *parentNode = createMissingNode(lastCreatedNode, codeColorBuffer);
|
lastCreatedNode = createMissingNode(lastCreatedNode, codeColorBuffer);
|
||||||
lastCreatedNode = parentNode->children[branchIndexWithDescendant(parentNode->octalCode, codeColorBuffer)];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// give this node its color
|
// give this node its color
|
||||||
|
@ -325,15 +384,13 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer,
|
||||||
bool voxelIsClose = (distanceToVoxelCenter < boundaryDistanceForRenderLevel(*currentVoxelNode->octalCode + 1));
|
bool voxelIsClose = (distanceToVoxelCenter < boundaryDistanceForRenderLevel(*currentVoxelNode->octalCode + 1));
|
||||||
bool sendVoxel = voxelIsClose && voxelInView;
|
bool sendVoxel = voxelIsClose && voxelInView;
|
||||||
|
|
||||||
//printf("VoxelTree::loadBitstreamBuffer() sendVoxel=%d, voxelIsClose=%d, voxelInView=%d, viewFrustumCulling=%d\n",
|
|
||||||
// sendVoxel, voxelIsClose, voxelInView, viewFrustumCulling);
|
|
||||||
|
|
||||||
if (sendVoxel) {
|
if (sendVoxel) {
|
||||||
|
|
||||||
// write this voxel's data if we're below or at
|
// write this voxel's data if we're below or at
|
||||||
// or at the same level as the stopOctalCode
|
// or at the same level as the stopOctalCode
|
||||||
|
|
||||||
if (*currentVoxelNode->octalCode >= *stopOctalCode) {
|
if (*currentVoxelNode->octalCode >= *stopOctalCode) {
|
||||||
|
|
||||||
if ((bitstreamBuffer - initialBitstreamPos) + MAX_TREE_SLICE_BYTES > MAX_VOXEL_PACKET_SIZE) {
|
if ((bitstreamBuffer - initialBitstreamPos) + MAX_TREE_SLICE_BYTES > MAX_VOXEL_PACKET_SIZE) {
|
||||||
// we can't send this packet, not enough room
|
// we can't send this packet, not enough room
|
||||||
// return our octal code as the stop
|
// return our octal code as the stop
|
||||||
|
@ -359,13 +416,11 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer,
|
||||||
unsigned char *colorPointer = bitstreamBuffer + 1;
|
unsigned char *colorPointer = bitstreamBuffer + 1;
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
|
|
||||||
// Rules for including a child:
|
// Rules for including a child:
|
||||||
// 1) child must exists
|
// 1) child must exists
|
||||||
if ((currentVoxelNode->children[i] != NULL)) {
|
if ((currentVoxelNode->children[i] != NULL)) {
|
||||||
// 2) child must have a color...
|
// 2) child must have a color...
|
||||||
if (currentVoxelNode->children[i]->isColored()) {
|
if (currentVoxelNode->children[i]->isColored()) {
|
||||||
|
|
||||||
unsigned char* childOctalCode = currentVoxelNode->children[i]->octalCode;
|
unsigned char* childOctalCode = currentVoxelNode->children[i]->octalCode;
|
||||||
|
|
||||||
float childPosition[3];
|
float childPosition[3];
|
||||||
|
@ -384,9 +439,6 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer,
|
||||||
childBox.setBox(glm::vec3(childPosition[0], childPosition[1], childPosition[2]),
|
childBox.setBox(glm::vec3(childPosition[0], childPosition[1], childPosition[2]),
|
||||||
fullChildVoxel, fullChildVoxel, fullChildVoxel);
|
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.
|
// XXXBHG - not sure we want to do this "distance/LOD culling" at this level.
|
||||||
//bool childIsClose = (distanceToChildCenter < boundaryDistanceForRenderLevel(*childOctalCode + 1));
|
//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
|
// removed childIsClose - until we determine if we want to include that
|
||||||
bool sendChild = (childInView) || falseColorInsteadOfCulling;
|
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 we sendAnyway, we'll do false coloring of the voxels based on childIsClose && childInView
|
||||||
if (sendChild) {
|
if (sendChild) {
|
||||||
|
|
||||||
|
@ -449,15 +498,13 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer,
|
||||||
? branchIndexWithDescendant(currentVoxelNode->octalCode, stopOctalCode)
|
? branchIndexWithDescendant(currentVoxelNode->octalCode, stopOctalCode)
|
||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char * arrBufferBeforeChild = bitstreamBuffer;
|
unsigned char * arrBufferBeforeChild = bitstreamBuffer;
|
||||||
|
|
||||||
for (int i = firstIndexToCheck; i < 8; i ++) {
|
for (int i = firstIndexToCheck; i < 8; i ++) {
|
||||||
|
|
||||||
// ask the child to load this bitstream buffer
|
// ask the child to load this bitstream buffer
|
||||||
// if they or their descendants fill the MTU we will receive the childStopOctalCode back
|
// if they or their descendants fill the MTU we will receive the childStopOctalCode back
|
||||||
if (currentVoxelNode->children[i] != NULL) {
|
if (currentVoxelNode->children[i] != NULL) {
|
||||||
|
|
||||||
if (!oneAtBit(currentMarkerNode->childrenVisitedMask, i)) {
|
if (!oneAtBit(currentMarkerNode->childrenVisitedMask, i)) {
|
||||||
|
|
||||||
// create the marker node for this child if it does not yet exist
|
// 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 *****************************************************************************************/
|
**** disabled *****************************************************************************************/
|
||||||
|
|
||||||
// ask the child to load the bitstream buffer with their data
|
// ask the child to load the bitstream buffer with their data
|
||||||
childStopOctalCode = loadBitstreamBuffer(bitstreamBuffer,
|
childStopOctalCode = loadBitstreamBuffer(bitstreamBuffer,
|
||||||
currentVoxelNode->children[i],
|
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);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
const int MAX_VOXEL_PACKET_SIZE = 1492;
|
const int MAX_VOXEL_PACKET_SIZE = 1492;
|
||||||
const int MAX_TREE_SLICE_BYTES = 26;
|
const int MAX_TREE_SLICE_BYTES = 26;
|
||||||
const int TREE_SCALE = 10;
|
|
||||||
|
|
||||||
// Callback function, for recuseTreeWithOperation
|
// Callback function, for recuseTreeWithOperation
|
||||||
typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, bool down, void* extraData);
|
typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, bool down, void* extraData);
|
||||||
|
@ -48,25 +47,29 @@ public:
|
||||||
void deleteVoxelCodeFromTree(unsigned char *codeBuffer);
|
void deleteVoxelCodeFromTree(unsigned char *codeBuffer);
|
||||||
void printTreeForDebugging(VoxelNode *startNode);
|
void printTreeForDebugging(VoxelNode *startNode);
|
||||||
void reaverageVoxelColors(VoxelNode *startNode);
|
void reaverageVoxelColors(VoxelNode *startNode);
|
||||||
unsigned char * loadBitstreamBuffer(unsigned char *& bitstreamBuffer,
|
unsigned char * loadBitstreamBuffer(unsigned char*& bitstreamBuffer,
|
||||||
VoxelNode *currentVoxelNode,
|
VoxelNode* currentVoxelNode,
|
||||||
MarkerNode *currentMarkerNode,
|
MarkerNode* currentMarkerNode,
|
||||||
const glm::vec3& agentPosition,
|
const glm::vec3& agentPosition,
|
||||||
float thisNodePosition[3],
|
float thisNodePosition[3],
|
||||||
const ViewFrustum& viewFrustum,
|
const ViewFrustum& viewFrustum,
|
||||||
bool viewFrustumCulling,
|
bool viewFrustumCulling,
|
||||||
unsigned char * octalCode = NULL);
|
unsigned char* octalCode = NULL);
|
||||||
|
|
||||||
void loadVoxelsFile(const char* fileName, bool wantColorRandomizer);
|
void loadVoxelsFile(const char* fileName, bool wantColorRandomizer);
|
||||||
void createSphere(float r,float xc, float yc, float zc, float s, bool solid, 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);
|
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:
|
private:
|
||||||
void recurseNodeWithOperation(VoxelNode* node,RecurseVoxelTreeOperation operation, void* extraData);
|
void recurseNodeWithOperation(VoxelNode* node, RecurseVoxelTreeOperation operation, void* extraData);
|
||||||
VoxelNode * nodeForOctalCode(VoxelNode *ancestorNode, unsigned char * needleCode, VoxelNode** parentOfFoundNode);
|
VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode);
|
||||||
VoxelNode * createMissingNode(VoxelNode *lastParentNode, unsigned char *deepestCodeToCreate);
|
VoxelNode* createMissingNode(VoxelNode* lastParentNode, unsigned char* deepestCodeToCreate);
|
||||||
int readNodeData(VoxelNode *destinationNode, unsigned char * nodeData, int bufferSizeBytes);
|
int readNodeData(VoxelNode *destinationNode, unsigned char* nodeData, int bufferSizeBytes);
|
||||||
};
|
};
|
||||||
|
|
||||||
int boundaryDistanceForRenderLevel(unsigned int renderLevel);
|
int boundaryDistanceForRenderLevel(unsigned int renderLevel);
|
||||||
|
|
Loading…
Reference in a new issue