mirror of
https://github.com/overte-org/overte.git
synced 2025-04-25 18:35:32 +02:00
more file moving
This commit is contained in:
parent
b34d1b5c05
commit
724bddf749
4 changed files with 0 additions and 860 deletions
|
@ -1,114 +0,0 @@
|
|||
//
|
||||
// VoxelNode.cpp
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 3/13/13.
|
||||
//
|
||||
//
|
||||
|
||||
#include <cstring>
|
||||
#include "SharedUtil.h"
|
||||
#include "VoxelNode.h"
|
||||
#include "OctalCode.h"
|
||||
|
||||
VoxelNode::VoxelNode() {
|
||||
octalCode = NULL;
|
||||
|
||||
// default pointers to child nodes to NULL
|
||||
for (int i = 0; i < 8; i++) {
|
||||
children[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
VoxelNode::~VoxelNode() {
|
||||
delete[] octalCode;
|
||||
|
||||
// delete all of this node's children
|
||||
for (int i = 0; i < 8; i++) {
|
||||
delete children[i];
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelNode::addChildAtIndex(int childIndex) {
|
||||
children[childIndex] = new VoxelNode();
|
||||
|
||||
// give this child its octal code
|
||||
children[childIndex]->octalCode = childOctalCode(octalCode, childIndex);
|
||||
}
|
||||
|
||||
// will average the child colors...
|
||||
void VoxelNode::setColorFromAverageOfChildren() {
|
||||
int colorArray[4] = {0,0,0,0};
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (children[i] != NULL && children[i]->color[3] == 1) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
colorArray[j] += children[i]->color[j];
|
||||
}
|
||||
colorArray[3]++;
|
||||
}
|
||||
}
|
||||
|
||||
if (colorArray[3] > 4) {
|
||||
// we need at least 4 colored children to have an average color value
|
||||
// or if we have none we generate random values
|
||||
for (int c = 0; c < 3; c++) {
|
||||
// set the average color value
|
||||
color[c] = colorArray[c] / colorArray[3];
|
||||
}
|
||||
// set the alpha to 1 to indicate that this isn't transparent
|
||||
color[3] = 1;
|
||||
} else {
|
||||
// some children, but not enough
|
||||
// set this node's alpha to 0
|
||||
color[3] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// will detect if children are leaves AND the same color
|
||||
// and in that case will delete the children and make this node
|
||||
// a leaf, returns TRUE if all the leaves are collapsed into a
|
||||
// single node
|
||||
bool VoxelNode::collapseIdenticalLeaves() {
|
||||
// scan children, verify that they are ALL present and accounted for
|
||||
bool allChildrenMatch = true; // assume the best (ottimista)
|
||||
int red,green,blue;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
// if no child, or child doesn't have a color
|
||||
if (children[i] == NULL || children[i]->color[3] != 1) {
|
||||
allChildrenMatch=false;
|
||||
//printf("SADNESS child missing or not colored! i=%d\n",i);
|
||||
break;
|
||||
} else {
|
||||
if (i==0) {
|
||||
red = children[i]->color[0];
|
||||
green = children[i]->color[1];
|
||||
blue = children[i]->color[2];
|
||||
} else if (red != children[i]->color[0] || green != children[i]->color[1] || blue != children[i]->color[2]) {
|
||||
allChildrenMatch=false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (allChildrenMatch) {
|
||||
//printf("allChildrenMatch: pruning tree\n");
|
||||
for (int i = 0; i < 8; i++) {
|
||||
delete children[i]; // delete all the child nodes
|
||||
children[i]=NULL; // set it to NULL
|
||||
}
|
||||
color[0]=red;
|
||||
color[1]=green;
|
||||
color[2]=blue;
|
||||
color[3]=1; // color is set
|
||||
}
|
||||
return allChildrenMatch;
|
||||
}
|
||||
|
||||
void VoxelNode::setRandomColor(int minimumBrightness) {
|
||||
for (int c = 0; c < 3; c++) {
|
||||
color[c] = randomColorValue(minimumBrightness);
|
||||
}
|
||||
|
||||
color[3] = 1;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
//
|
||||
// VoxelNode.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 3/13/13.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef __hifi__VoxelNode__
|
||||
#define __hifi__VoxelNode__
|
||||
|
||||
#include <iostream>
|
||||
|
||||
class VoxelNode {
|
||||
public:
|
||||
VoxelNode();
|
||||
~VoxelNode();
|
||||
|
||||
void addChildAtIndex(int childIndex);
|
||||
void setColorFromAverageOfChildren();
|
||||
void setRandomColor(int minimumBrightness);
|
||||
bool collapseIdenticalLeaves();
|
||||
|
||||
unsigned char *octalCode;
|
||||
unsigned char color[4];
|
||||
VoxelNode *children[8];
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__VoxelNode__) */
|
|
@ -1,654 +0,0 @@
|
|||
//
|
||||
// VoxelTree.cpp
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 3/13/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifdef _WIN32
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cmath>
|
||||
#include "SharedUtil.h"
|
||||
#include "PacketHeaders.h"
|
||||
#include "CounterStats.h"
|
||||
#include "OctalCode.h"
|
||||
#include "VoxelTree.h"
|
||||
#include <iostream> // to load voxels from file
|
||||
#include <fstream> // to load voxels from file
|
||||
|
||||
|
||||
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;
|
||||
default:
|
||||
return 6;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VoxelTree::VoxelTree() {
|
||||
rootNode = new VoxelNode();
|
||||
rootNode->octalCode = new unsigned char[1];
|
||||
*rootNode->octalCode = 0;
|
||||
|
||||
// Some stats tracking
|
||||
this->voxelsCreated = 0; // when a voxel is created in the tree (object new'd)
|
||||
this->voxelsColored = 0; // when a voxel is colored/set in the tree (object may have already existed)
|
||||
this->voxelsBytesRead = 0;
|
||||
voxelsCreatedStats.name = "voxelsCreated";
|
||||
voxelsColoredStats.name = "voxelsColored";
|
||||
voxelsBytesReadStats.name = "voxelsBytesRead";
|
||||
|
||||
}
|
||||
|
||||
VoxelTree::~VoxelTree() {
|
||||
// delete the children of the root node
|
||||
// this recursively deletes the tree
|
||||
for (int i = 0; i < 8; i++) {
|
||||
delete rootNode->children[i];
|
||||
}
|
||||
}
|
||||
|
||||
VoxelNode * VoxelTree::nodeForOctalCode(VoxelNode *ancestorNode, unsigned char * needleCode, VoxelNode** parentOfFoundNode) {
|
||||
// find the appropriate branch index based on this ancestorNode
|
||||
if (*needleCode > 0) {
|
||||
int branchForNeedle = branchIndexWithDescendant(ancestorNode->octalCode, needleCode);
|
||||
VoxelNode *childNode = ancestorNode->children[branchForNeedle];
|
||||
|
||||
if (childNode != NULL) {
|
||||
if (*childNode->octalCode == *needleCode) {
|
||||
|
||||
// If the caller asked for the parent, then give them that too...
|
||||
if (parentOfFoundNode) {
|
||||
*parentOfFoundNode=ancestorNode;
|
||||
}
|
||||
// the fact that the number of sections is equivalent does not always guarantee
|
||||
// that this is the same node, however due to the recursive traversal
|
||||
// we know that this is our node
|
||||
return childNode;
|
||||
} else {
|
||||
// we need to go deeper
|
||||
return nodeForOctalCode(childNode, needleCode,parentOfFoundNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we've been given a code we don't have a node for
|
||||
// return this node as the last created parent
|
||||
return ancestorNode;
|
||||
}
|
||||
|
||||
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;
|
||||
} else {
|
||||
return createMissingNode(lastParentNode->children[indexOfNewChild], codeToReach);
|
||||
}
|
||||
}
|
||||
|
||||
// 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 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.recordSample(this->voxelsCreated);
|
||||
}
|
||||
|
||||
// pull the color for this child
|
||||
memcpy(destinationNode->children[i]->color, nodeData + bytesRead, 3);
|
||||
destinationNode->children[i]->color[3] = 1;
|
||||
this->voxelsColored++;
|
||||
this->voxelsColoredStats.recordSample(this->voxelsColored);
|
||||
|
||||
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);
|
||||
|
||||
int childIndex = 0;
|
||||
bytesRead++;
|
||||
|
||||
while (bytesLeftToRead - bytesRead > 0 && childIndex < 8) {
|
||||
// check the exists mask to see if we have a child to traverse into
|
||||
|
||||
if (oneAtBit(childMask, childIndex)) {
|
||||
if (destinationNode->children[childIndex] == NULL) {
|
||||
// add a child at that index, if it doesn't exist
|
||||
destinationNode->addChildAtIndex(childIndex);
|
||||
this->voxelsCreated++;
|
||||
this->voxelsCreatedStats.recordSample(this->voxelsCreated);
|
||||
}
|
||||
|
||||
// tell the child to read the subsequent data
|
||||
bytesRead += readNodeData(destinationNode->children[childIndex],
|
||||
nodeData + bytesRead,
|
||||
bytesLeftToRead - bytesRead);
|
||||
}
|
||||
|
||||
childIndex++;
|
||||
}
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
void VoxelTree::readBitstreamToTree(unsigned char * bitstream, int 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
|
||||
bitstreamRootNode = createMissingNode(bitstreamRootNode, (unsigned char *)bitstream);
|
||||
}
|
||||
|
||||
int octalCodeBytes = bytesRequiredForCodeLength(*bitstream);
|
||||
readNodeData(bitstreamRootNode, bitstream + octalCodeBytes, bufferSizeBytes - octalCodeBytes);
|
||||
|
||||
this->voxelsBytesRead += bufferSizeBytes;
|
||||
this->voxelsBytesReadStats.recordSample(this->voxelsBytesRead);
|
||||
}
|
||||
|
||||
// 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* nodeToDelete = nodeForOctalCode(rootNode, codeBuffer, &parentNode);
|
||||
|
||||
printf("deleteVoxelCodeFromTree() looking [codeBuffer] for:\n");
|
||||
printOctalCode(codeBuffer);
|
||||
|
||||
printf("deleteVoxelCodeFromTree() found [nodeToDelete->octalCode] for:\n");
|
||||
printOctalCode(nodeToDelete->octalCode);
|
||||
|
||||
// If the node exists...
|
||||
int lengthInBytes = bytesRequiredForCodeLength(*codeBuffer); // includes octet count, not color!
|
||||
printf("compare octal codes of length %d\n",lengthInBytes);
|
||||
|
||||
if (0==memcmp(nodeToDelete->octalCode,codeBuffer,lengthInBytes)) {
|
||||
printf("found node to delete...\n");
|
||||
|
||||
float* vertices = firstVertexForCode(nodeToDelete->octalCode);
|
||||
printf("deleting voxel at: %f,%f,%f\n",vertices[0],vertices[1],vertices[2]);
|
||||
delete []vertices;
|
||||
|
||||
if (parentNode) {
|
||||
float* vertices = firstVertexForCode(parentNode->octalCode);
|
||||
printf("parent of deleting voxel at: %f,%f,%f\n",vertices[0],vertices[1],vertices[2]);
|
||||
delete []vertices;
|
||||
|
||||
int childNDX = branchIndexWithDescendant(parentNode->octalCode, codeBuffer);
|
||||
printf("child INDEX=%d\n",childNDX);
|
||||
|
||||
printf("deleting Node at parentNode->children[%d]\n",childNDX);
|
||||
delete parentNode->children[childNDX]; // delete the child nodes
|
||||
printf("setting parentNode->children[%d] to NULL\n",childNDX);
|
||||
parentNode->children[childNDX]=NULL; // set it to NULL
|
||||
|
||||
printf("reaverageVoxelColors()\n");
|
||||
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?
|
||||
|
||||
delete rootNode; // this will recurse and delete all children
|
||||
rootNode = new VoxelNode();
|
||||
rootNode->octalCode = new unsigned char[1];
|
||||
*rootNode->octalCode = 0;
|
||||
}
|
||||
|
||||
void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) {
|
||||
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)];
|
||||
}
|
||||
|
||||
// give this node its color
|
||||
int octalCodeBytes = bytesRequiredForCodeLength(*codeColorBuffer);
|
||||
memcpy(lastCreatedNode->color, codeColorBuffer + octalCodeBytes, 3);
|
||||
lastCreatedNode->color[3] = 1;
|
||||
}
|
||||
|
||||
unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer,
|
||||
VoxelNode *currentVoxelNode,
|
||||
MarkerNode *currentMarkerNode,
|
||||
float * agentPosition,
|
||||
float thisNodePosition[3],
|
||||
unsigned char * stopOctalCode)
|
||||
{
|
||||
static unsigned char *initialBitstreamPos = bitstreamBuffer;
|
||||
|
||||
unsigned char * childStopOctalCode = NULL;
|
||||
|
||||
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);
|
||||
|
||||
// XXXBHG - Note: It appears as if the X and Z coordinates of Head or Agent are flip-flopped relative to the
|
||||
// coords of the voxel space. This flip flop causes LOD behavior to be extremely odd. This is my temporary hack
|
||||
// to fix this behavior. To disable this swap, set swapXandZ to false.
|
||||
// XXXBHG - 2013/04/11 - adding a note to my branch, I think this code is now broken.
|
||||
bool swapXandZ=true;
|
||||
float agentX = swapXandZ ? agentPosition[2] : agentPosition[0];
|
||||
float agentZ = swapXandZ ? agentPosition[0] : agentPosition[2];
|
||||
|
||||
float distanceToVoxelCenter = sqrtf(powf(agentX - thisNodePosition[0] - halfUnitForVoxel, 2) +
|
||||
powf(agentPosition[1] - thisNodePosition[1] - halfUnitForVoxel, 2) +
|
||||
powf(agentZ - 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)) {
|
||||
|
||||
// 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++) {
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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]));
|
||||
printf("processRemoveVoxelBitstream() receivedBytes=%d itemNumber=%d\n",bufferSizeBytes,itemNumber);
|
||||
int atByte = 3;
|
||||
unsigned char* pVoxelData = (unsigned char*)&bitstream[3];
|
||||
while (atByte < bufferSizeBytes) {
|
||||
unsigned char octets = (unsigned char)*pVoxelData;
|
||||
int voxelDataSize = bytesRequiredForCodeLength(octets)+3; // 3 for color!
|
||||
|
||||
float* vertices = firstVertexForCode(pVoxelData);
|
||||
printf("deleting voxel at: %f,%f,%f\n",vertices[0],vertices[1],vertices[2]);
|
||||
delete []vertices;
|
||||
|
||||
deleteVoxelCodeFromTree(pVoxelData);
|
||||
|
||||
pVoxelData+=voxelDataSize;
|
||||
atByte+=voxelDataSize;
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelTree::printTreeForDebugging(VoxelNode *startNode) {
|
||||
int colorMask = 0;
|
||||
|
||||
// create the color mask
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (startNode->children[i] != NULL && startNode->children[i]->color[3] != 0) {
|
||||
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]->color[3] != 0) {
|
||||
for (int c = 0; c < 3; c++) {
|
||||
outputBits(startNode->children[j]->color[c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
for (int l = 0; l < 8; l++) {
|
||||
if (startNode->children[l] != NULL) {
|
||||
printTreeForDebugging(startNode->children[l]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelTree::reaverageVoxelColors(VoxelNode *startNode) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 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;
|
||||
|
||||
std::ifstream file(fileName, std::ios::in|std::ios::binary);
|
||||
|
||||
char octets;
|
||||
unsigned int lengthInBytes;
|
||||
|
||||
int totalBytesRead = 0;
|
||||
if(file.is_open()) {
|
||||
printf("loading file...\n");
|
||||
bool bail = false;
|
||||
while (!file.eof() && !bail) {
|
||||
file.get(octets);
|
||||
//printf("octets=%d...\n",octets);
|
||||
totalBytesRead++;
|
||||
lengthInBytes = bytesRequiredForCodeLength(octets)-1; //(octets*3/8)+1;
|
||||
unsigned char * voxelData = new unsigned char[lengthInBytes+1+3];
|
||||
voxelData[0]=octets;
|
||||
char byte;
|
||||
|
||||
for (size_t i = 0; i < lengthInBytes; i++) {
|
||||
file.get(byte);
|
||||
totalBytesRead++;
|
||||
voxelData[i+1] = byte;
|
||||
}
|
||||
// read color data
|
||||
char colorRead;
|
||||
unsigned char red,green,blue;
|
||||
file.get(colorRead);
|
||||
red = (unsigned char)colorRead;
|
||||
file.get(colorRead);
|
||||
green = (unsigned char)colorRead;
|
||||
file.get(colorRead);
|
||||
blue = (unsigned char)colorRead;
|
||||
|
||||
printf("voxel color from file red:%d, green:%d, blue:%d \n",red,green,blue);
|
||||
vCount++;
|
||||
|
||||
int colorRandomizer = wantColorRandomizer ? randIntInRange (-5, 5) : 0;
|
||||
voxelData[lengthInBytes+1] = std::max(0,std::min(255,red + colorRandomizer));
|
||||
voxelData[lengthInBytes+2] = std::max(0,std::min(255,green + colorRandomizer));
|
||||
voxelData[lengthInBytes+3] = std::max(0,std::min(255,blue + colorRandomizer));
|
||||
printf("voxel color after rand red:%d, green:%d, blue:%d\n",
|
||||
voxelData[lengthInBytes+1], voxelData[lengthInBytes+2], voxelData[lengthInBytes+3]);
|
||||
|
||||
//printVoxelCode(voxelData);
|
||||
this->readCodeColorBufferToTree(voxelData);
|
||||
delete voxelData;
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
unsigned char dominantColor1 = randIntInRange(1,3); //1=r, 2=g, 3=b dominant
|
||||
unsigned char dominantColor2 = randIntInRange(1,3);
|
||||
|
||||
if (dominantColor1==dominantColor2) {
|
||||
dominantColor2 = dominantColor1+1%3;
|
||||
}
|
||||
|
||||
unsigned char r1 = (dominantColor1==1)?randIntInRange(200,255):randIntInRange(40,100);
|
||||
unsigned char g1 = (dominantColor1==2)?randIntInRange(200,255):randIntInRange(40,100);
|
||||
unsigned char b1 = (dominantColor1==3)?randIntInRange(200,255):randIntInRange(40,100);
|
||||
unsigned char r2 = (dominantColor2==1)?randIntInRange(200,255):randIntInRange(40,100);
|
||||
unsigned char g2 = (dominantColor2==2)?randIntInRange(200,255):randIntInRange(40,100);
|
||||
unsigned char b2 = (dominantColor2==3)?randIntInRange(200,255):randIntInRange(40,100);
|
||||
|
||||
// We initialize our rgb to be either "grey" in case of randomized surface, or
|
||||
// the average of the gradient, in the case of the gradient sphere.
|
||||
unsigned char red = wantColorRandomizer ? 128 : (r1+r2)/2; // average of the colors
|
||||
unsigned char green = wantColorRandomizer ? 128 : (g1+g2)/2;
|
||||
unsigned char blue = wantColorRandomizer ? 128 : (b1+b2)/2;
|
||||
|
||||
// Psuedocode for creating a sphere:
|
||||
//
|
||||
// for (theta from 0 to 2pi):
|
||||
// for (phi from 0 to pi):
|
||||
// x = xc+r*cos(theta)*sin(phi)
|
||||
// y = yc+r*sin(theta)*sin(phi)
|
||||
// z = zc+r*cos(phi)
|
||||
|
||||
int t=0; // total points
|
||||
|
||||
// We want to make sure that as we "sweep" through our angles we use a delta angle that's small enough to not skip any
|
||||
// voxels we can calculate theta from our desired arc length
|
||||
// lenArc = ndeg/360deg * 2pi*R ---> lenArc = theta/2pi * 2pi*R
|
||||
// lenArc = theta*R ---> theta = lenArc/R ---> theta = g/r
|
||||
float angleDelta = (s/r);
|
||||
|
||||
// assume solid for now
|
||||
float ri = 0.0;
|
||||
|
||||
if (!solid) {
|
||||
ri=r; // just the outer surface
|
||||
}
|
||||
|
||||
// If you also iterate form the interior of the sphere to the radius, makeing
|
||||
// larger and larger sphere's you'd end up with a solid sphere. And lots of voxels!
|
||||
for (; ri <= (r+(s/2.0)); ri+=s) {
|
||||
//printf("radius: ri=%f ri+s=%f (r+(s/2.0))=%f\n",ri,ri+s,(r+(s/2.0)));
|
||||
for (float theta=0.0; theta <= 2*M_PI; theta += angleDelta) {
|
||||
for (float phi=0.0; phi <= M_PI; phi += angleDelta) {
|
||||
t++; // total voxels
|
||||
float x = xc+ri*cos(theta)*sin(phi);
|
||||
float y = yc+ri*sin(theta)*sin(phi);
|
||||
float z = zc+ri*cos(phi);
|
||||
|
||||
// gradient color data
|
||||
float gradient = (phi/M_PI);
|
||||
|
||||
// only use our actual desired color on the outer edge, otherwise
|
||||
// use our "average" color
|
||||
if (ri+(s*2.0)>=r) {
|
||||
//printf("painting candy shell radius: ri=%f r=%f\n",ri,r);
|
||||
red = wantColorRandomizer ? randomColorValue(165) : r1+((r2-r1)*gradient);
|
||||
green = wantColorRandomizer ? randomColorValue(165) : g1+((g2-g1)*gradient);
|
||||
blue = wantColorRandomizer ? randomColorValue(165) : b1+((b2-b1)*gradient);
|
||||
}
|
||||
|
||||
unsigned char* voxelData = pointToVoxel(x,y,z,s,red,green,blue);
|
||||
this->readCodeColorBufferToTree(voxelData);
|
||||
//printf("voxel data for x:%f y:%f z:%f s:%f\n",x,y,z,s);
|
||||
//printVoxelCode(voxelData);
|
||||
delete voxelData;
|
||||
}
|
||||
}
|
||||
}
|
||||
this->reaverageVoxelColors(this->rootNode);
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
//
|
||||
// VoxelTree.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 3/13/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __hifi__VoxelTree__
|
||||
#define __hifi__VoxelTree__
|
||||
|
||||
#include "CounterStats.h"
|
||||
|
||||
#include "VoxelNode.h"
|
||||
#include "MarkerNode.h"
|
||||
|
||||
const int MAX_VOXEL_PACKET_SIZE = 1492;
|
||||
const int MAX_TREE_SLICE_BYTES = 26;
|
||||
const int TREE_SCALE = 10;
|
||||
|
||||
class VoxelTree {
|
||||
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);
|
||||
|
||||
|
||||
public:
|
||||
long int voxelsCreated;
|
||||
long int voxelsColored;
|
||||
long int voxelsBytesRead;
|
||||
|
||||
CounterStatHistory voxelsCreatedStats;
|
||||
CounterStatHistory voxelsColoredStats;
|
||||
CounterStatHistory voxelsBytesReadStats;
|
||||
|
||||
VoxelTree();
|
||||
~VoxelTree();
|
||||
|
||||
VoxelNode *rootNode;
|
||||
int leavesWrittenToBitstream;
|
||||
|
||||
void eraseAllVoxels();
|
||||
|
||||
void processRemoveVoxelBitstream(unsigned char * bitstream, int bufferSizeBytes);
|
||||
void readBitstreamToTree(unsigned char * bitstream, int bufferSizeBytes);
|
||||
void readCodeColorBufferToTree(unsigned char *codeColorBuffer);
|
||||
void deleteVoxelCodeFromTree(unsigned char *codeBuffer);
|
||||
void printTreeForDebugging(VoxelNode *startNode);
|
||||
void reaverageVoxelColors(VoxelNode *startNode);
|
||||
unsigned char * loadBitstreamBuffer(unsigned char *& bitstreamBuffer,
|
||||
VoxelNode *currentVoxelNode,
|
||||
MarkerNode *currentMarkerNode,
|
||||
float * agentPosition,
|
||||
float thisNodePosition[3],
|
||||
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);
|
||||
};
|
||||
|
||||
int boundaryDistanceForRenderLevel(unsigned int renderLevel);
|
||||
|
||||
#endif /* defined(__hifi__VoxelTree__) */
|
Loading…
Reference in a new issue