mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 18:23:54 +02:00
Merge pull request #1075 from ZappoMan/voxelnode_memory_savings
VoxelNode memory savings
This commit is contained in:
commit
c48856df52
21 changed files with 1262 additions and 263 deletions
|
@ -1392,13 +1392,13 @@ void Application::increaseVoxelSize() {
|
|||
|
||||
const int MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE = 1500;
|
||||
struct SendVoxelsOperationArgs {
|
||||
unsigned char* newBaseOctCode;
|
||||
const unsigned char* newBaseOctCode;
|
||||
};
|
||||
|
||||
bool Application::sendVoxelsOperation(VoxelNode* node, void* extraData) {
|
||||
SendVoxelsOperationArgs* args = (SendVoxelsOperationArgs*)extraData;
|
||||
if (node->isColored()) {
|
||||
unsigned char* nodeOctalCode = node->getOctalCode();
|
||||
const unsigned char* nodeOctalCode = node->getOctalCode();
|
||||
|
||||
unsigned char* codeColorBuffer = NULL;
|
||||
int codeLength = 0;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "SharedUtil.h"
|
||||
#include "OctalCode.h"
|
||||
|
||||
int numberOfThreeBitSectionsInCode(unsigned char * octalCode) {
|
||||
int numberOfThreeBitSectionsInCode(const unsigned char* octalCode) {
|
||||
assert(octalCode);
|
||||
if (*octalCode == 255) {
|
||||
return *octalCode + numberOfThreeBitSectionsInCode(octalCode + 1);
|
||||
|
@ -25,18 +25,18 @@ int numberOfThreeBitSectionsInCode(unsigned char * octalCode) {
|
|||
}
|
||||
}
|
||||
|
||||
void printOctalCode(unsigned char * octalCode) {
|
||||
void printOctalCode(const unsigned char* octalCode) {
|
||||
if (!octalCode) {
|
||||
qDebug("NULL\n");
|
||||
} else {
|
||||
for (int i = 0; i < bytesRequiredForCodeLength(*octalCode); i++) {
|
||||
for (int i = 0; i < bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(octalCode)); i++) {
|
||||
outputBits(octalCode[i],false);
|
||||
}
|
||||
qDebug("\n");
|
||||
}
|
||||
}
|
||||
|
||||
char sectionValue(unsigned char * startByte, char startIndexInByte) {
|
||||
char sectionValue(const unsigned char* startByte, char startIndexInByte) {
|
||||
char rightShift = 8 - startIndexInByte - 3;
|
||||
|
||||
if (rightShift < 0) {
|
||||
|
@ -54,14 +54,14 @@ int bytesRequiredForCodeLength(unsigned char threeBitCodes) {
|
|||
}
|
||||
}
|
||||
|
||||
int branchIndexWithDescendant(unsigned char * ancestorOctalCode, unsigned char * descendantOctalCode) {
|
||||
int branchIndexWithDescendant(const unsigned char* ancestorOctalCode, const unsigned char* descendantOctalCode) {
|
||||
int parentSections = numberOfThreeBitSectionsInCode(ancestorOctalCode);
|
||||
|
||||
int branchStartBit = parentSections * 3;
|
||||
return sectionValue(descendantOctalCode + 1 + (branchStartBit / 8), branchStartBit % 8);
|
||||
}
|
||||
|
||||
unsigned char * childOctalCode(unsigned char * parentOctalCode, char childNumber) {
|
||||
unsigned char* childOctalCode(const unsigned char* parentOctalCode, char childNumber) {
|
||||
|
||||
// find the length (in number of three bit code sequences)
|
||||
// in the parent
|
||||
|
@ -76,7 +76,7 @@ unsigned char * childOctalCode(unsigned char * parentOctalCode, char childNumber
|
|||
int childCodeBytes = bytesRequiredForCodeLength(parentCodeSections + 1);
|
||||
|
||||
// create a new buffer to hold the new octal code
|
||||
unsigned char *newCode = new unsigned char[childCodeBytes];
|
||||
unsigned char* newCode = new unsigned char[childCodeBytes];
|
||||
|
||||
// copy the parent code to the child
|
||||
if (parentOctalCode != NULL) {
|
||||
|
@ -115,7 +115,7 @@ unsigned char * childOctalCode(unsigned char * parentOctalCode, char childNumber
|
|||
return newCode;
|
||||
}
|
||||
|
||||
void voxelDetailsForCode(unsigned char * octalCode, VoxelPositionSize& voxelPositionSize) {
|
||||
void voxelDetailsForCode(const unsigned char* octalCode, VoxelPositionSize& voxelPositionSize) {
|
||||
float output[3];
|
||||
memset(&output[0], 0, 3 * sizeof(float));
|
||||
float currentScale = 1.0;
|
||||
|
@ -138,7 +138,7 @@ void voxelDetailsForCode(unsigned char * octalCode, VoxelPositionSize& voxelPosi
|
|||
voxelPositionSize.s = currentScale;
|
||||
}
|
||||
|
||||
void copyFirstVertexForCode(unsigned char * octalCode, float* output) {
|
||||
void copyFirstVertexForCode(const unsigned char* octalCode, float* output) {
|
||||
memset(output, 0, 3 * sizeof(float));
|
||||
|
||||
float currentScale = 0.5;
|
||||
|
@ -154,13 +154,13 @@ void copyFirstVertexForCode(unsigned char * octalCode, float* output) {
|
|||
}
|
||||
}
|
||||
|
||||
float * firstVertexForCode(unsigned char * octalCode) {
|
||||
float * firstVertexForCode(const unsigned char* octalCode) {
|
||||
float * firstVertex = new float[3];
|
||||
copyFirstVertexForCode(octalCode, firstVertex);
|
||||
return firstVertex;
|
||||
}
|
||||
|
||||
OctalCodeComparison compareOctalCodes(unsigned char* codeA, unsigned char* codeB) {
|
||||
OctalCodeComparison compareOctalCodes(const unsigned char* codeA, const unsigned char* codeB) {
|
||||
if (!codeA || !codeB) {
|
||||
return ILLEGAL_CODE;
|
||||
}
|
||||
|
@ -196,10 +196,10 @@ OctalCodeComparison compareOctalCodes(unsigned char* codeA, unsigned char* codeB
|
|||
}
|
||||
|
||||
|
||||
char getOctalCodeSectionValue(unsigned char* octalCode, int section) {
|
||||
char getOctalCodeSectionValue(const unsigned char* octalCode, int section) {
|
||||
int startAtByte = 1 + (BITS_IN_OCTAL * section / BITS_IN_BYTE);
|
||||
char startIndexInByte = (BITS_IN_OCTAL * section) % BITS_IN_BYTE;
|
||||
unsigned char* startByte = octalCode + startAtByte;
|
||||
const unsigned char* startByte = octalCode + startAtByte;
|
||||
|
||||
return sectionValue(startByte, startIndexInByte);
|
||||
}
|
||||
|
@ -243,7 +243,7 @@ void setOctalCodeSectionValue(unsigned char* octalCode, int section, char sectio
|
|||
}
|
||||
}
|
||||
|
||||
unsigned char* chopOctalCode(unsigned char* originalOctalCode, int chopLevels) {
|
||||
unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLevels) {
|
||||
int codeLength = numberOfThreeBitSectionsInCode(originalOctalCode);
|
||||
unsigned char* newCode = NULL;
|
||||
if (codeLength > chopLevels) {
|
||||
|
@ -259,7 +259,9 @@ unsigned char* chopOctalCode(unsigned char* originalOctalCode, int chopLevels) {
|
|||
return newCode;
|
||||
}
|
||||
|
||||
unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* newParentOctalCode, bool includeColorSpace) {
|
||||
unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode,
|
||||
bool includeColorSpace) {
|
||||
|
||||
int oldCodeLength = numberOfThreeBitSectionsInCode(originalOctalCode);
|
||||
int newParentCodeLength = numberOfThreeBitSectionsInCode(newParentOctalCode);
|
||||
int newCodeLength = newParentCodeLength + oldCodeLength;
|
||||
|
@ -280,7 +282,7 @@ unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char*
|
|||
return newCode;
|
||||
}
|
||||
|
||||
bool isAncestorOf(unsigned char* possibleAncestor, unsigned char* possibleDescendent, int descendentsChild) {
|
||||
bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* possibleDescendent, int descendentsChild) {
|
||||
if (!possibleAncestor || !possibleDescendent) {
|
||||
return false;
|
||||
}
|
||||
|
@ -350,7 +352,7 @@ unsigned char* hexStringToOctalCode(const QString& input) {
|
|||
return bytes;
|
||||
}
|
||||
|
||||
QString octalCodeToHexString(unsigned char* octalCode) {
|
||||
QString octalCodeToHexString(const unsigned char* octalCode) {
|
||||
const int HEX_NUMBER_BASE = 16;
|
||||
const int HEX_BYTE_SIZE = 2;
|
||||
QString output;
|
||||
|
|
|
@ -20,27 +20,28 @@ const int RED_INDEX = 0;
|
|||
const int GREEN_INDEX = 1;
|
||||
const int BLUE_INDEX = 2;
|
||||
|
||||
void printOctalCode(unsigned char * octalCode);
|
||||
void printOctalCode(const unsigned char* octalCode);
|
||||
int bytesRequiredForCodeLength(unsigned char threeBitCodes);
|
||||
int branchIndexWithDescendant(unsigned char * ancestorOctalCode, unsigned char * descendantOctalCode);
|
||||
unsigned char * childOctalCode(unsigned char * parentOctalCode, char childNumber);
|
||||
int numberOfThreeBitSectionsInCode(unsigned char * octalCode);
|
||||
unsigned char* chopOctalCode(unsigned char* originalOctalCode, int chopLevels);
|
||||
unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* newParentOctalCode,
|
||||
int branchIndexWithDescendant(const unsigned char* ancestorOctalCode, const unsigned char* descendantOctalCode);
|
||||
unsigned char* childOctalCode(const unsigned char* parentOctalCode, char childNumber);
|
||||
int numberOfThreeBitSectionsInCode(const unsigned char* octalCode);
|
||||
unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLevels);
|
||||
unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode,
|
||||
bool includeColorSpace = false);
|
||||
|
||||
const int CHECK_NODE_ONLY = -1;
|
||||
bool isAncestorOf(unsigned char* possibleAncestor, unsigned char* possibleDescendent, int descendentsChild = CHECK_NODE_ONLY);
|
||||
bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* possibleDescendent,
|
||||
int descendentsChild = CHECK_NODE_ONLY);
|
||||
|
||||
// Note: copyFirstVertexForCode() is preferred because it doesn't allocate memory for the return
|
||||
// but other than that these do the same thing.
|
||||
float * firstVertexForCode(unsigned char * octalCode);
|
||||
void copyFirstVertexForCode(unsigned char * octalCode, float* output);
|
||||
float * firstVertexForCode(const unsigned char* octalCode);
|
||||
void copyFirstVertexForCode(const unsigned char* octalCode, float* output);
|
||||
|
||||
struct VoxelPositionSize {
|
||||
float x, y, z, s;
|
||||
};
|
||||
void voxelDetailsForCode(unsigned char* octalCode, VoxelPositionSize& voxelPositionSize);
|
||||
void voxelDetailsForCode(const unsigned char* octalCode, VoxelPositionSize& voxelPositionSize);
|
||||
|
||||
typedef enum {
|
||||
ILLEGAL_CODE = -2,
|
||||
|
@ -49,9 +50,9 @@ typedef enum {
|
|||
GREATER_THAN = 1
|
||||
} OctalCodeComparison;
|
||||
|
||||
OctalCodeComparison compareOctalCodes(unsigned char* code1, unsigned char* code2);
|
||||
OctalCodeComparison compareOctalCodes(const unsigned char* code1, const unsigned char* code2);
|
||||
|
||||
QString octalCodeToHexString(unsigned char* octalCode);
|
||||
QString octalCodeToHexString(const unsigned char* octalCode);
|
||||
unsigned char* hexStringToOctalCode(const QString& input);
|
||||
|
||||
#endif /* defined(__hifi__OctalCode__) */
|
||||
|
|
|
@ -108,7 +108,8 @@ bool PerformanceWarning::_suppressShortTimings = false;
|
|||
// Destructor handles recording all of our stats
|
||||
PerformanceWarning::~PerformanceWarning() {
|
||||
uint64_t end = usecTimestampNow();
|
||||
double elapsedmsec = (end - _start) / 1000.0;
|
||||
uint64_t elapsedusec = (end - _start);
|
||||
double elapsedmsec = elapsedusec / 1000.0;
|
||||
if ((_alwaysDisplay || _renderWarningsOn) && elapsedmsec > 1) {
|
||||
if (elapsedmsec > 1000) {
|
||||
double elapsedsec = (end - _start) / 1000000.0;
|
||||
|
@ -127,6 +128,13 @@ PerformanceWarning::~PerformanceWarning() {
|
|||
} else if (_alwaysDisplay) {
|
||||
qDebug("%s took %lf milliseconds\n", _message, elapsedmsec);
|
||||
}
|
||||
// if the caller gave us a pointer to store the running total, track it now.
|
||||
if (_runningTotal) {
|
||||
*_runningTotal += elapsedusec;
|
||||
}
|
||||
if (_totalCalls) {
|
||||
*_totalCalls += 1;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -89,14 +89,19 @@ private:
|
|||
const char* _message;
|
||||
bool _renderWarningsOn;
|
||||
bool _alwaysDisplay;
|
||||
uint64_t* _runningTotal;
|
||||
uint64_t* _totalCalls;
|
||||
static bool _suppressShortTimings;
|
||||
public:
|
||||
PerformanceWarning(bool renderWarnings, const char* message, bool alwaysDisplay = false) :
|
||||
|
||||
PerformanceWarning(bool renderWarnings, const char* message, bool alwaysDisplay = false, uint64_t* runningTotal = NULL, uint64_t* totalCalls = NULL) :
|
||||
_start(usecTimestampNow()),
|
||||
_message(message),
|
||||
_renderWarningsOn(renderWarnings),
|
||||
_alwaysDisplay(alwaysDisplay) { }
|
||||
|
||||
_alwaysDisplay(alwaysDisplay),
|
||||
_runningTotal(runningTotal),
|
||||
_totalCalls(totalCalls) { }
|
||||
|
||||
~PerformanceWarning();
|
||||
|
||||
static void setSuppressShortTimings(bool suppressShortTimings) { _suppressShortTimings = suppressShortTimings; }
|
||||
|
|
|
@ -105,10 +105,41 @@ void setAtBit(unsigned char& byte, int bitIndex) {
|
|||
byte += (1 << (7 - bitIndex));
|
||||
}
|
||||
|
||||
void clearAtBit(unsigned char& byte, int bitIndex) {
|
||||
if (oneAtBit(byte, bitIndex)) {
|
||||
byte -= (1 << (7 - bitIndex));
|
||||
}
|
||||
}
|
||||
|
||||
int getSemiNibbleAt(unsigned char& byte, int bitIndex) {
|
||||
return (byte >> (6 - bitIndex) & 3); // semi-nibbles store 00, 01, 10, or 11
|
||||
}
|
||||
|
||||
int getNthBit(unsigned char byte, int ordinal) {
|
||||
const int ERROR = -1;
|
||||
const int MIN_ORDINAL = 1;
|
||||
const int MAX_ORDINAL = 8;
|
||||
if (ordinal < MIN_ORDINAL || ordinal > MAX_ORDINAL) {
|
||||
return ERROR;
|
||||
}
|
||||
int bitsSet = 0;
|
||||
for (int bitIndex = 0; bitIndex < MAX_ORDINAL; bitIndex++) {
|
||||
if (oneAtBit(byte, bitIndex)) {
|
||||
bitsSet++;
|
||||
}
|
||||
if (bitsSet == ordinal) {
|
||||
return bitIndex;
|
||||
}
|
||||
}
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
bool isBetween(int64_t value, int64_t max, int64_t min) {
|
||||
return ((value <= max) && (value >= min));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value) {
|
||||
//assert(value <= 3 && value >= 0);
|
||||
byte += ((value & 3) << (6 - bitIndex)); // semi-nibbles store 00, 01, 10, or 11
|
||||
|
|
|
@ -55,10 +55,12 @@ void printVoxelCode(unsigned char* voxelCode);
|
|||
int numberOfOnes(unsigned char byte);
|
||||
bool oneAtBit(unsigned char byte, int bitIndex);
|
||||
void setAtBit(unsigned char& byte, int bitIndex);
|
||||
|
||||
void clearAtBit(unsigned char& byte, int bitIndex);
|
||||
int getSemiNibbleAt(unsigned char& byte, int bitIndex);
|
||||
void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value);
|
||||
|
||||
int getNthBit(unsigned char byte, int ordinal); /// determines the bit placement 0-7 of the ordinal set bit
|
||||
|
||||
bool isInEnvironment(const char* environment);
|
||||
|
||||
void switchToResourcesParentIfRequired();
|
||||
|
@ -109,4 +111,6 @@ public:
|
|||
static const char* valueOf(bool checkValue) { return checkValue ? "yes" : "no"; }
|
||||
};
|
||||
|
||||
bool isBetween(int64_t value, int64_t max, int64_t min);
|
||||
|
||||
#endif /* defined(__hifi__SharedUtil__) */
|
||||
|
|
|
@ -29,21 +29,38 @@ bool VoxelPersistThread::process() {
|
|||
_initialLoad = true;
|
||||
qDebug("loading voxels from file: %s...\n", _filename);
|
||||
|
||||
bool persistantFileRead = _tree->readFromSVOFile(_filename);
|
||||
bool persistantFileRead;
|
||||
|
||||
{
|
||||
PerformanceWarning warn(true, "Loading Voxel File", true);
|
||||
persistantFileRead = _tree->readFromSVOFile(_filename);
|
||||
}
|
||||
|
||||
if (persistantFileRead) {
|
||||
PerformanceWarning warn(true, "reaverageVoxelColors()", true);
|
||||
PerformanceWarning warn(true, "Voxels Re-Averaging", true);
|
||||
|
||||
// after done inserting all these voxels, then reaverage colors
|
||||
qDebug("BEGIN Voxels Re-Averaging\n");
|
||||
_tree->reaverageVoxelColors(_tree->rootNode);
|
||||
qDebug("Voxels reAveraged\n");
|
||||
qDebug("DONE WITH Voxels Re-Averaging\n");
|
||||
}
|
||||
|
||||
_tree->clearDirtyBit(); // the tree is clean since we just loaded it
|
||||
qDebug("DONE loading voxels from file... fileRead=%s\n", debug::valueOf(persistantFileRead));
|
||||
unsigned long nodeCount = _tree->rootNode->getSubTreeNodeCount();
|
||||
unsigned long internalNodeCount = _tree->rootNode->getSubTreeInternalNodeCount();
|
||||
unsigned long leafNodeCount = _tree->rootNode->getSubTreeLeafNodeCount();
|
||||
|
||||
unsigned long nodeCount = VoxelNode::getNodeCount();
|
||||
unsigned long internalNodeCount = VoxelNode::getInternalNodeCount();
|
||||
unsigned long leafNodeCount = VoxelNode::getLeafNodeCount();
|
||||
qDebug("Nodes after loading scene %lu nodes %lu internal %lu leaves\n", nodeCount, internalNodeCount, leafNodeCount);
|
||||
|
||||
double usecPerGet = (double)VoxelNode::getGetChildAtIndexTime() / (double)VoxelNode::getGetChildAtIndexCalls();
|
||||
qDebug("getChildAtIndexCalls=%llu getChildAtIndexTime=%llu perGet=%lf \n",
|
||||
VoxelNode::getGetChildAtIndexTime(), VoxelNode::getGetChildAtIndexCalls(), usecPerGet);
|
||||
|
||||
double usecPerSet = (double)VoxelNode::getSetChildAtIndexTime() / (double)VoxelNode::getSetChildAtIndexCalls();
|
||||
qDebug("setChildAtIndexCalls=%llu setChildAtIndexTime=%llu perSet=%lf\n",
|
||||
VoxelNode::getSetChildAtIndexTime(), VoxelNode::getSetChildAtIndexCalls(), usecPerSet);
|
||||
|
||||
}
|
||||
|
||||
uint64_t MSECS_TO_USECS = 1000;
|
||||
|
|
|
@ -136,18 +136,74 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) {
|
|||
mg_printf(connection, "%s", "HTTP/1.0 200 OK\r\n\r\n");
|
||||
mg_printf(connection, "%s", "Your Voxel Server is running.\r\n");
|
||||
mg_printf(connection, "%s", "Current Statistics\r\n");
|
||||
mg_printf(connection, "Voxel Node Memory Usage: %f MB\r\n", VoxelNode::getVoxelMemoryUsage() / 1000000.f);
|
||||
mg_printf(connection, "Octcode Memory Usage: %f MB\r\n", VoxelNode::getOctcodeMemoryUsage() / 1000000.f);
|
||||
mg_printf(connection, "%s", "\r\n");
|
||||
mg_printf(connection, "Voxel Node Memory Usage: %8.2f MB\r\n", VoxelNode::getVoxelMemoryUsage() / 1000000.f);
|
||||
mg_printf(connection, "Octcode Memory Usage: %8.2f MB\r\n", VoxelNode::getOctcodeMemoryUsage() / 1000000.f);
|
||||
mg_printf(connection, "External Children Memory Usage: %8.2f MB\r\n",
|
||||
VoxelNode::getExternalChildrenMemoryUsage() / 1000000.f);
|
||||
mg_printf(connection, "%s", " -----------\r\n");
|
||||
mg_printf(connection, " Total: %8.2f MB\r\n", VoxelNode::getTotalMemoryUsage() / 1000000.f);
|
||||
|
||||
VoxelTree* theTree = VoxelServer::GetInstance()->getTree();
|
||||
unsigned long nodeCount = theTree->rootNode->getSubTreeNodeCount();
|
||||
unsigned long internalNodeCount = theTree->rootNode->getSubTreeInternalNodeCount();
|
||||
unsigned long leafNodeCount = theTree->rootNode->getSubTreeLeafNodeCount();
|
||||
unsigned long nodeCount = VoxelNode::getNodeCount();
|
||||
unsigned long internalNodeCount = VoxelNode::getInternalNodeCount();
|
||||
unsigned long leafNodeCount = VoxelNode::getLeafNodeCount();
|
||||
|
||||
const float AS_PERCENT = 100.0;
|
||||
|
||||
mg_printf(connection, "%s", "\r\n");
|
||||
mg_printf(connection, "%s", "Current Nodes in scene\r\n");
|
||||
mg_printf(connection, " Total Nodes: %lu nodes\r\n", nodeCount);
|
||||
mg_printf(connection, " Internal Nodes: %lu nodes\r\n", internalNodeCount);
|
||||
mg_printf(connection, " Leaf Nodes: %lu leaves\r\n", leafNodeCount);
|
||||
mg_printf(connection, " Total Nodes: %10.lu nodes\r\n", nodeCount);
|
||||
mg_printf(connection, " Internal Nodes: %10.lu nodes (%5.2f%%)\r\n",
|
||||
internalNodeCount, ((float)internalNodeCount/(float)nodeCount) * AS_PERCENT);
|
||||
mg_printf(connection, " Leaf Nodes: %10.lu nodes (%5.2f%%)\r\n",
|
||||
leafNodeCount, ((float)leafNodeCount/(float)nodeCount) * AS_PERCENT);
|
||||
|
||||
mg_printf(connection, "%s", "\r\n");
|
||||
mg_printf(connection, "%s", "VoxelNode Children Encoding Statistics...\r\n");
|
||||
mg_printf(connection, " Single or No Children: %10.llu nodes (%5.2f%%)\r\n",
|
||||
VoxelNode::getSingleChildrenCount(), ((float)VoxelNode::getSingleChildrenCount()/(float)nodeCount) * AS_PERCENT);
|
||||
mg_printf(connection, " Two Children as Offset: %10.llu nodes (%5.2f%%)\r\n",
|
||||
VoxelNode::getTwoChildrenOffsetCount(),
|
||||
((float)VoxelNode::getTwoChildrenOffsetCount()/(float)nodeCount) * AS_PERCENT);
|
||||
mg_printf(connection, " Two Children as External: %10.llu nodes (%5.2f%%)\r\n",
|
||||
VoxelNode::getTwoChildrenExternalCount(),
|
||||
((float)VoxelNode::getTwoChildrenExternalCount()/(float)nodeCount) * AS_PERCENT);
|
||||
mg_printf(connection, " Three Children as Offset: %10.llu nodes (%5.2f%%)\r\n",
|
||||
VoxelNode::getThreeChildrenOffsetCount(),
|
||||
((float)VoxelNode::getThreeChildrenOffsetCount()/(float)nodeCount) * AS_PERCENT);
|
||||
mg_printf(connection, " Three Children as External: %10.llu nodes (%5.2f%%)\r\n",
|
||||
VoxelNode::getThreeChildrenExternalCount(),
|
||||
((float)VoxelNode::getThreeChildrenExternalCount()/(float)nodeCount) * AS_PERCENT);
|
||||
mg_printf(connection, " Children as External Array: %10.llu nodes (%5.2f%%)\r\n",
|
||||
VoxelNode::getExternalChildrenCount(),
|
||||
((float)VoxelNode::getExternalChildrenCount()/(float)nodeCount) * AS_PERCENT);
|
||||
|
||||
uint64_t checkSum = VoxelNode::getSingleChildrenCount() +
|
||||
VoxelNode::getTwoChildrenOffsetCount() + VoxelNode::getTwoChildrenExternalCount() +
|
||||
VoxelNode::getThreeChildrenOffsetCount() + VoxelNode::getThreeChildrenExternalCount() +
|
||||
VoxelNode::getExternalChildrenCount();
|
||||
|
||||
mg_printf(connection, "%s", " ----------------\r\n");
|
||||
mg_printf(connection, " Total: %10.llu nodes\r\n", checkSum);
|
||||
mg_printf(connection, " Expected: %10.lu nodes\r\n", nodeCount);
|
||||
|
||||
mg_printf(connection, "%s", "\r\n");
|
||||
mg_printf(connection, "%s", "VoxelNode Children Population Statistics...\r\n");
|
||||
checkSum = 0;
|
||||
for (int i=0; i <= NUMBER_OF_CHILDREN; i++) {
|
||||
checkSum += VoxelNode::getChildrenCount(i);
|
||||
mg_printf(connection, " Nodes with %d children: %10.llu nodes (%5.2f%%)\r\n", i,
|
||||
VoxelNode::getChildrenCount(i), ((float)VoxelNode::getChildrenCount(i)/(float)nodeCount) * AS_PERCENT);
|
||||
}
|
||||
mg_printf(connection, "%s", " ----------------\r\n");
|
||||
mg_printf(connection, " Total: %10.llu nodes\r\n", checkSum);
|
||||
|
||||
mg_printf(connection, "%s", "\r\n");
|
||||
mg_printf(connection, "%s", "In other news....\r\n");
|
||||
mg_printf(connection, "could store 4 children internally: %10.llu nodes\r\n",
|
||||
VoxelNode::getCouldStoreFourChildrenInternally());
|
||||
mg_printf(connection, "could NOT store 4 children internally: %10.llu nodes\r\n",
|
||||
VoxelNode::getCouldNotStoreFourChildrenInternally());
|
||||
|
||||
return 1;
|
||||
} else {
|
||||
|
|
|
@ -13,83 +13,66 @@
|
|||
#include "AABox.h"
|
||||
#include "GeometryUtil.h"
|
||||
|
||||
AABox::AABox(const glm::vec3& corner, float size) : _corner(corner), _size(size, size, size), _topFarLeft(_corner + _size)
|
||||
{
|
||||
AABox::AABox(const glm::vec3& corner, float size) :
|
||||
_corner(corner), _scale(size) {
|
||||
};
|
||||
|
||||
AABox::AABox(const glm::vec3& corner, float x, float y, float z) : _corner(corner), _size(x, y, z), _topFarLeft(_corner + _size)
|
||||
{
|
||||
AABox::AABox() : _corner(0,0,0), _scale(0) {
|
||||
};
|
||||
|
||||
AABox::AABox(const glm::vec3& corner, const glm::vec3& size) : _corner(corner), _size(size), _topFarLeft(_corner + _size)
|
||||
{
|
||||
};
|
||||
glm::vec3 AABox::calcCenter() const {
|
||||
glm::vec3 center(_corner);
|
||||
center += (glm::vec3(_scale, _scale, _scale) * 0.5f);
|
||||
return center;
|
||||
}
|
||||
|
||||
AABox::AABox() : _corner(0,0,0), _size(0,0,0), _topFarLeft(0,0,0)
|
||||
{
|
||||
glm::vec3 AABox::calcTopFarLeft() const {
|
||||
glm::vec3 topFarLeft(_corner);
|
||||
topFarLeft += glm::vec3(_scale, _scale, _scale);
|
||||
return topFarLeft;
|
||||
};
|
||||
|
||||
|
||||
void AABox::scale(float scale) {
|
||||
_corner = _corner * scale;
|
||||
_size = _size * scale;
|
||||
_center = _center * scale;
|
||||
_topFarLeft = _topFarLeft * scale;
|
||||
_scale = _scale * scale;
|
||||
}
|
||||
|
||||
|
||||
glm::vec3 AABox::getVertex(BoxVertex vertex) const {
|
||||
switch (vertex) {
|
||||
case BOTTOM_LEFT_NEAR:
|
||||
return _corner + glm::vec3(_size.x, 0, 0);
|
||||
return _corner + glm::vec3(_scale, 0, 0);
|
||||
case BOTTOM_RIGHT_NEAR:
|
||||
return _corner;
|
||||
case TOP_RIGHT_NEAR:
|
||||
return _corner + glm::vec3(0, _size.y, 0);
|
||||
return _corner + glm::vec3(0, _scale, 0);
|
||||
case TOP_LEFT_NEAR:
|
||||
return _corner + glm::vec3(_size.x, _size.y, 0);
|
||||
return _corner + glm::vec3(_scale, _scale, 0);
|
||||
case BOTTOM_LEFT_FAR:
|
||||
return _corner + glm::vec3(_size.x, 0, _size.z);
|
||||
return _corner + glm::vec3(_scale, 0, _scale);
|
||||
case BOTTOM_RIGHT_FAR:
|
||||
return _corner + glm::vec3(0, 0, _size.z);
|
||||
return _corner + glm::vec3(0, 0, _scale);
|
||||
case TOP_RIGHT_FAR:
|
||||
return _corner + glm::vec3(0, _size.y, _size.z);
|
||||
return _corner + glm::vec3(0, _scale, _scale);
|
||||
case TOP_LEFT_FAR:
|
||||
return _corner + _size;
|
||||
return _corner + glm::vec3(_scale, _scale, _scale);
|
||||
}
|
||||
}
|
||||
|
||||
void AABox::setBox(const glm::vec3& corner, const glm::vec3& size) {
|
||||
void AABox::setBox(const glm::vec3& corner, float scale) {
|
||||
_corner = corner;
|
||||
_size = size;
|
||||
|
||||
// In the event that the caller gave us negative sizes, fix things up to be reasonable
|
||||
if (_size.x < 0.0) {
|
||||
_size.x = -size.x;
|
||||
_corner.x -= _size.x;
|
||||
}
|
||||
if (_size.y < 0.0) {
|
||||
_size.y = -size.y;
|
||||
_corner.y -= _size.y;
|
||||
}
|
||||
if (_size.z < 0.0) {
|
||||
_size.z = -size.z;
|
||||
_corner.z -= _size.z;
|
||||
}
|
||||
_center = _corner + (_size * 0.5f);
|
||||
_topFarLeft = _corner + _size;
|
||||
_scale = scale;
|
||||
}
|
||||
|
||||
glm::vec3 AABox::getVertexP(const glm::vec3& normal) const {
|
||||
glm::vec3 result = _corner;
|
||||
if (normal.x > 0) {
|
||||
result.x += _size.x;
|
||||
result.x += _scale;
|
||||
}
|
||||
if (normal.y > 0) {
|
||||
result.y += _size.y;
|
||||
result.y += _scale;
|
||||
}
|
||||
if (normal.z > 0) {
|
||||
result.z += _size.z;
|
||||
result.z += _scale;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -98,15 +81,15 @@ glm::vec3 AABox::getVertexN(const glm::vec3& normal) const {
|
|||
glm::vec3 result = _corner;
|
||||
|
||||
if (normal.x < 0) {
|
||||
result.x += _size.x;
|
||||
result.x += _scale;
|
||||
}
|
||||
|
||||
if (normal.y < 0) {
|
||||
result.y += _size.y;
|
||||
result.y += _scale;
|
||||
}
|
||||
|
||||
if (normal.z < 0) {
|
||||
result.z += _size.z;
|
||||
result.z += _scale;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -118,9 +101,9 @@ static bool isWithin(float value, float corner, float size) {
|
|||
}
|
||||
|
||||
bool AABox::contains(const glm::vec3& point) const {
|
||||
return isWithin(point.x, _corner.x, _size.x) &&
|
||||
isWithin(point.y, _corner.y, _size.y) &&
|
||||
isWithin(point.z, _corner.z, _size.z);
|
||||
return isWithin(point.x, _corner.x, _scale) &&
|
||||
isWithin(point.y, _corner.y, _scale) &&
|
||||
isWithin(point.z, _corner.z, _scale);
|
||||
}
|
||||
|
||||
bool AABox::contains(const AABox& otherBox) const {
|
||||
|
@ -140,9 +123,9 @@ static bool isWithinExpanded(float value, float corner, float size, float expans
|
|||
}
|
||||
|
||||
bool AABox::expandedContains(const glm::vec3& point, float expansion) const {
|
||||
return isWithinExpanded(point.x, _corner.x, _size.x, expansion) &&
|
||||
isWithinExpanded(point.y, _corner.y, _size.y, expansion) &&
|
||||
isWithinExpanded(point.z, _corner.z, _size.z, expansion);
|
||||
return isWithinExpanded(point.x, _corner.x, _scale, expansion) &&
|
||||
isWithinExpanded(point.y, _corner.y, _scale, expansion) &&
|
||||
isWithinExpanded(point.z, _corner.z, _scale, expansion);
|
||||
}
|
||||
|
||||
// finds the intersection between a ray and the facing plane on one axis
|
||||
|
@ -164,7 +147,7 @@ bool AABox::expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& e
|
|||
}
|
||||
// check each axis
|
||||
glm::vec3 expandedCorner = _corner - glm::vec3(expansion, expansion, expansion);
|
||||
glm::vec3 expandedSize = _size + glm::vec3(expansion, expansion, expansion) * 2.0f;
|
||||
glm::vec3 expandedSize = glm::vec3(_scale, _scale, _scale) + glm::vec3(expansion, expansion, expansion) * 2.0f;
|
||||
glm::vec3 direction = end - start;
|
||||
float axisDistance;
|
||||
return (findIntersection(start.x, direction.x, expandedCorner.x, expandedSize.x, axisDistance) &&
|
||||
|
@ -189,23 +172,23 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct
|
|||
}
|
||||
// check each axis
|
||||
float axisDistance;
|
||||
if ((findIntersection(origin.x, direction.x, _corner.x, _size.x, axisDistance) && axisDistance >= 0 &&
|
||||
isWithin(origin.y + axisDistance*direction.y, _corner.y, _size.y) &&
|
||||
isWithin(origin.z + axisDistance*direction.z, _corner.z, _size.z))) {
|
||||
if ((findIntersection(origin.x, direction.x, _corner.x, _scale, axisDistance) && axisDistance >= 0 &&
|
||||
isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) &&
|
||||
isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale))) {
|
||||
distance = axisDistance;
|
||||
face = direction.x > 0 ? MIN_X_FACE : MAX_X_FACE;
|
||||
return true;
|
||||
}
|
||||
if ((findIntersection(origin.y, direction.y, _corner.y, _size.y, axisDistance) && axisDistance >= 0 &&
|
||||
isWithin(origin.x + axisDistance*direction.x, _corner.x, _size.x) &&
|
||||
isWithin(origin.z + axisDistance*direction.z, _corner.z, _size.z))) {
|
||||
if ((findIntersection(origin.y, direction.y, _corner.y, _scale, axisDistance) && axisDistance >= 0 &&
|
||||
isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale) &&
|
||||
isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale))) {
|
||||
distance = axisDistance;
|
||||
face = direction.y > 0 ? MIN_Y_FACE : MAX_Y_FACE;
|
||||
return true;
|
||||
}
|
||||
if ((findIntersection(origin.z, direction.z, _corner.z, _size.z, axisDistance) && axisDistance >= 0 &&
|
||||
isWithin(origin.y + axisDistance*direction.y, _corner.y, _size.y) &&
|
||||
isWithin(origin.x + axisDistance*direction.x, _corner.x, _size.x))) {
|
||||
if ((findIntersection(origin.z, direction.z, _corner.z, _scale, axisDistance) && axisDistance >= 0 &&
|
||||
isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) &&
|
||||
isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale))) {
|
||||
distance = axisDistance;
|
||||
face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE;
|
||||
return true;
|
||||
|
@ -268,27 +251,27 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec3& point, BoxFace face) con
|
|||
switch (face) {
|
||||
case MIN_X_FACE:
|
||||
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
|
||||
glm::vec3(_corner.x, _corner.y + _size.y, _corner.z + _size.z));
|
||||
glm::vec3(_corner.x, _corner.y + _scale, _corner.z + _scale));
|
||||
|
||||
case MAX_X_FACE:
|
||||
return glm::clamp(point, glm::vec3(_corner.x + _size.x, _corner.y, _corner.z),
|
||||
glm::vec3(_corner.x + _size.x, _corner.y + _size.y, _corner.z + _size.z));
|
||||
return glm::clamp(point, glm::vec3(_corner.x + _scale, _corner.y, _corner.z),
|
||||
glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale));
|
||||
|
||||
case MIN_Y_FACE:
|
||||
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
|
||||
glm::vec3(_corner.x + _size.x, _corner.y, _corner.z + _size.z));
|
||||
glm::vec3(_corner.x + _scale, _corner.y, _corner.z + _scale));
|
||||
|
||||
case MAX_Y_FACE:
|
||||
return glm::clamp(point, glm::vec3(_corner.x, _corner.y + _size.y, _corner.z),
|
||||
glm::vec3(_corner.x + _size.x, _corner.y + _size.y, _corner.z + _size.z));
|
||||
return glm::clamp(point, glm::vec3(_corner.x, _corner.y + _scale, _corner.z),
|
||||
glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale));
|
||||
|
||||
case MIN_Z_FACE:
|
||||
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
|
||||
glm::vec3(_corner.x + _size.x, _corner.y + _size.y, _corner.z));
|
||||
glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z));
|
||||
|
||||
case MAX_Z_FACE:
|
||||
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z + _size.z),
|
||||
glm::vec3(_corner.x + _size.x, _corner.y + _size.y, _corner.z + _size.z));
|
||||
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z + _scale),
|
||||
glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,7 +321,7 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4&
|
|||
glm::vec4 thirdAxisMaxPlane = getPlane((BoxFace)(thirdAxis * 2 + 1));
|
||||
|
||||
glm::vec4 offset = glm::vec4(0.0f, 0.0f, 0.0f,
|
||||
glm::dot(glm::vec3(secondAxisMaxPlane + thirdAxisMaxPlane), _size) * 0.5f);
|
||||
glm::dot(glm::vec3(secondAxisMaxPlane + thirdAxisMaxPlane), glm::vec3(_scale, _scale, _scale)) * 0.5f);
|
||||
glm::vec4 diagonals[] = { secondAxisMinPlane + thirdAxisMaxPlane + offset,
|
||||
secondAxisMaxPlane + thirdAxisMaxPlane + offset };
|
||||
|
||||
|
@ -362,11 +345,11 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4&
|
|||
glm::vec4 AABox::getPlane(BoxFace face) const {
|
||||
switch (face) {
|
||||
case MIN_X_FACE: return glm::vec4(-1.0f, 0.0f, 0.0f, _corner.x);
|
||||
case MAX_X_FACE: return glm::vec4(1.0f, 0.0f, 0.0f, -_corner.x - _size.x);
|
||||
case MAX_X_FACE: return glm::vec4(1.0f, 0.0f, 0.0f, -_corner.x - _scale);
|
||||
case MIN_Y_FACE: return glm::vec4(0.0f, -1.0f, 0.0f, _corner.y);
|
||||
case MAX_Y_FACE: return glm::vec4(0.0f, 1.0f, 0.0f, -_corner.y - _size.y);
|
||||
case MAX_Y_FACE: return glm::vec4(0.0f, 1.0f, 0.0f, -_corner.y - _scale);
|
||||
case MIN_Z_FACE: return glm::vec4(0.0f, 0.0f, -1.0f, _corner.z);
|
||||
case MAX_Z_FACE: return glm::vec4(0.0f, 0.0f, 1.0f, -_corner.z - _size.z);
|
||||
case MAX_Z_FACE: return glm::vec4(0.0f, 0.0f, 1.0f, -_corner.z - _scale);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,19 +36,14 @@ enum BoxVertex {
|
|||
|
||||
const int FACE_COUNT = 6;
|
||||
|
||||
class AABox
|
||||
{
|
||||
class AABox {
|
||||
|
||||
public:
|
||||
|
||||
AABox(const glm::vec3& corner, float size);
|
||||
AABox(const glm::vec3& corner, float x, float y, float z);
|
||||
AABox(const glm::vec3& corner, const glm::vec3& size);
|
||||
AABox();
|
||||
~AABox() {};
|
||||
|
||||
void setBox(const glm::vec3& corner, float x, float y, float z) { setBox(corner,glm::vec3(x,y,z)); };
|
||||
void setBox(const glm::vec3& corner, const glm::vec3& size);
|
||||
void setBox(const glm::vec3& corner, float scale);
|
||||
|
||||
// for use in frustum computations
|
||||
glm::vec3 getVertexP(const glm::vec3& normal) const;
|
||||
|
@ -57,9 +52,10 @@ public:
|
|||
void scale(float scale);
|
||||
|
||||
const glm::vec3& getCorner() const { return _corner; };
|
||||
const glm::vec3& getSize() const { return _size; };
|
||||
const glm::vec3& getCenter() const { return _center; };
|
||||
const glm::vec3& getTopFarLeft() const { return _topFarLeft; };
|
||||
float getScale() const { return _scale; }
|
||||
|
||||
glm::vec3 calcCenter() const;
|
||||
glm::vec3 calcTopFarLeft() const;
|
||||
|
||||
glm::vec3 getVertex(BoxVertex vertex) const;
|
||||
|
||||
|
@ -72,7 +68,6 @@ public:
|
|||
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const;
|
||||
|
||||
private:
|
||||
|
||||
glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const;
|
||||
glm::vec3 getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, BoxFace face) const;
|
||||
glm::vec4 getPlane(BoxFace face) const;
|
||||
|
@ -80,10 +75,7 @@ private:
|
|||
static BoxFace getOppositeFace(BoxFace face);
|
||||
|
||||
glm::vec3 _corner;
|
||||
glm::vec3 _center;
|
||||
glm::vec3 _size;
|
||||
glm::vec3 _topFarLeft;
|
||||
float _scale;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -132,7 +132,7 @@ void JurisdictionMap::init(unsigned char* rootOctalCode, const std::vector<unsig
|
|||
_endNodes = endNodes;
|
||||
}
|
||||
|
||||
JurisdictionMap::Area JurisdictionMap::isMyJurisdiction(unsigned char* nodeOctalCode, int childIndex) const {
|
||||
JurisdictionMap::Area JurisdictionMap::isMyJurisdiction(const unsigned char* nodeOctalCode, int childIndex) const {
|
||||
// to be in our jurisdiction, we must be under the root...
|
||||
|
||||
// if the node is an ancestor of my root, then we return ABOVE
|
||||
|
|
|
@ -41,7 +41,7 @@ public:
|
|||
JurisdictionMap(const char* rootHextString, const char* endNodesHextString);
|
||||
~JurisdictionMap();
|
||||
|
||||
Area isMyJurisdiction(unsigned char* nodeOctalCode, int childIndex) const;
|
||||
Area isMyJurisdiction(const unsigned char* nodeOctalCode, int childIndex) const;
|
||||
|
||||
bool writeToFile(const char* filename);
|
||||
bool readFromFile(const char* filename);
|
||||
|
|
|
@ -543,7 +543,8 @@ const int hullVertexLookup[MAX_POSSIBLE_COMBINATIONS][MAX_PROJECTED_POLYGON_VERT
|
|||
|
||||
VoxelProjectedPolygon ViewFrustum::getProjectedPolygon(const AABox& box) const {
|
||||
const glm::vec3& bottomNearRight = box.getCorner();
|
||||
const glm::vec3& topFarLeft = box.getTopFarLeft();
|
||||
glm::vec3 topFarLeft = box.calcTopFarLeft();
|
||||
|
||||
int lookUp = ((_position.x < bottomNearRight.x) ) // 1 = right | compute 6-bit
|
||||
+ ((_position.x > topFarLeft.x ) << 1) // 2 = left | code to
|
||||
+ ((_position.y < bottomNearRight.y) << 2) // 4 = bottom | classify camera
|
||||
|
@ -596,7 +597,7 @@ VoxelProjectedPolygon ViewFrustum::getProjectedPolygon(const AABox& box) const {
|
|||
***/
|
||||
}
|
||||
// set the distance from our camera position, to the closest vertex
|
||||
float distance = glm::distance(getPosition(), box.getCenter());
|
||||
float distance = glm::distance(getPosition(), box.calcCenter());
|
||||
projectedPolygon.setDistance(distance);
|
||||
projectedPolygon.setAnyInView(anyPointsInView);
|
||||
projectedPolygon.setAllInView(allPointsInView);
|
||||
|
@ -609,9 +610,9 @@ VoxelProjectedPolygon ViewFrustum::getProjectedPolygon(const AABox& box) const {
|
|||
// axis-aligned voxels to determine which of the voxels vertices must be the furthest. No need for
|
||||
// squares and square-roots. Just compares.
|
||||
glm::vec3 ViewFrustum::getFurthestPointFromCamera(const AABox& box) const {
|
||||
const glm::vec3& center = box.getCenter();
|
||||
const glm::vec3& bottomNearRight = box.getCorner();
|
||||
const glm::vec3& topFarLeft = box.getTopFarLeft();
|
||||
glm::vec3 center = box.calcCenter();
|
||||
glm::vec3 topFarLeft = box.calcTopFarLeft();
|
||||
|
||||
glm::vec3 furthestPoint;
|
||||
if (_position.x < center.x) {
|
||||
|
|
|
@ -97,7 +97,6 @@ public:
|
|||
glm::vec3 getFurthestPointFromCamera(const AABox& box) const;
|
||||
|
||||
private:
|
||||
|
||||
// Used for keyhole calculations
|
||||
ViewFrustum::location pointInKeyhole(const glm::vec3& point) const;
|
||||
ViewFrustum::location sphereInKeyhole(const glm::vec3& center, float radius) const;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -41,8 +41,8 @@ public:
|
|||
VoxelNode(unsigned char * octalCode); // regular constructor
|
||||
~VoxelNode();
|
||||
|
||||
unsigned char* getOctalCode() const { return _octalCode; }
|
||||
VoxelNode* getChildAtIndex(int childIndex) const { return _children[childIndex]; }
|
||||
const unsigned char* getOctalCode() const { return (_octcodePointer) ? _octalCode.pointer : &_octalCode.buffer[0]; }
|
||||
VoxelNode* getChildAtIndex(int childIndex) const;
|
||||
void deleteChildAtIndex(int childIndex);
|
||||
VoxelNode* removeChildAtIndex(int childIndex);
|
||||
VoxelNode* addChildAtIndex(int childIndex);
|
||||
|
@ -53,10 +53,9 @@ public:
|
|||
bool collapseIdenticalLeaves();
|
||||
|
||||
const AABox& getAABox() const { return _box; }
|
||||
const glm::vec3& getCenter() const { return _box.getCenter(); }
|
||||
const glm::vec3& getCorner() const { return _box.getCorner(); }
|
||||
float getScale() const { return _box.getSize().x; } // voxelScale = (1 / powf(2, *node->getOctalCode())); }
|
||||
int getLevel() const { return *_octalCode + 1; } // one based or zero based? this doesn't correctly handle 2 byte case
|
||||
float getScale() const { return _box.getScale(); }
|
||||
int getLevel() const { return numberOfThreeBitSectionsInCode(getOctalCode()) + 1; }
|
||||
|
||||
float getEnclosingRadius() const;
|
||||
|
||||
|
@ -72,8 +71,8 @@ public:
|
|||
float distanceSquareToPoint(const glm::vec3& point) const; // when you don't need the actual distance, use this.
|
||||
float distanceToPoint(const glm::vec3& point) const;
|
||||
|
||||
bool isLeaf() const { return _childCount == 0; }
|
||||
int getChildCount() const { return _childCount; }
|
||||
bool isLeaf() const { return getChildCount() == 0; }
|
||||
int getChildCount() const { return numberOfOnes(_childBitmask); }
|
||||
void printDebugDetails(const char* label) const;
|
||||
bool isDirty() const { return _isDirty; }
|
||||
void clearDirtyBit() { _isDirty = false; }
|
||||
|
@ -84,32 +83,21 @@ public:
|
|||
void handleSubtreeChanged(VoxelTree* myTree);
|
||||
|
||||
glBufferIndex getBufferIndex() const { return _glBufferIndex; }
|
||||
bool isKnownBufferIndex() const { return (_glBufferIndex != GLBUFFER_INDEX_UNKNOWN); }
|
||||
void setBufferIndex(glBufferIndex index) { _glBufferIndex = index; }
|
||||
VoxelSystem* getVoxelSystem() const { return _voxelSystem; }
|
||||
void setVoxelSystem(VoxelSystem* voxelSystem) { _voxelSystem = voxelSystem; }
|
||||
|
||||
bool isKnownBufferIndex() const { return !_unknownBufferIndex; }
|
||||
void setBufferIndex(glBufferIndex index) { _glBufferIndex = index; _unknownBufferIndex =(index == GLBUFFER_INDEX_UNKNOWN);}
|
||||
VoxelSystem* getVoxelSystem() const;
|
||||
void setVoxelSystem(VoxelSystem* voxelSystem);
|
||||
|
||||
// Used by VoxelSystem for rendering in/out of view and LOD
|
||||
void setShouldRender(bool shouldRender);
|
||||
bool getShouldRender() const { return _shouldRender; }
|
||||
|
||||
#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color
|
||||
void setFalseColor(colorPart red, colorPart green, colorPart blue);
|
||||
void setFalseColored(bool isFalseColored);
|
||||
bool getFalseColored() { return _falseColored; }
|
||||
void setColor(const nodeColor& color);
|
||||
const nodeColor& getTrueColor() const { return _trueColor; }
|
||||
const nodeColor& getColor() const { return _currentColor; }
|
||||
#else
|
||||
void setFalseColor(colorPart red, colorPart green, colorPart blue) { /* no op */ };
|
||||
void setFalseColored(bool isFalseColored) { /* no op */ };
|
||||
bool getFalseColored() { return false; };
|
||||
void setColor(const nodeColor& color) { memcpy(_trueColor,color,sizeof(nodeColor)); };
|
||||
void setDensity(const float density) { _density = density; };
|
||||
const nodeColor& getTrueColor() const { return _trueColor; };
|
||||
const nodeColor& getColor() const { return _trueColor; };
|
||||
#endif
|
||||
|
||||
void setDensity(float density) { _density = density; }
|
||||
float getDensity() const { return _density; }
|
||||
|
@ -122,49 +110,123 @@ public:
|
|||
static void addUpdateHook(VoxelNodeUpdateHook* hook);
|
||||
static void removeUpdateHook(VoxelNodeUpdateHook* hook);
|
||||
|
||||
void recalculateSubTreeNodeCount();
|
||||
unsigned long getSubTreeNodeCount() const { return _subtreeNodeCount; }
|
||||
unsigned long getSubTreeInternalNodeCount() const { return _subtreeNodeCount - _subtreeLeafNodeCount; }
|
||||
unsigned long getSubTreeLeafNodeCount() const { return _subtreeLeafNodeCount; }
|
||||
static unsigned long getNodeCount() { return _voxelNodeCount; }
|
||||
static unsigned long getInternalNodeCount() { return _voxelNodeCount - _voxelNodeLeafCount; }
|
||||
static unsigned long getLeafNodeCount() { return _voxelNodeLeafCount; }
|
||||
|
||||
static uint64_t getVoxelMemoryUsage() { return _voxelMemoryUsage; }
|
||||
static uint64_t getOctcodeMemoryUsage() { return _octcodeMemoryUsage; }
|
||||
static uint64_t getExternalChildrenMemoryUsage() { return _externalChildrenMemoryUsage; }
|
||||
static uint64_t getTotalMemoryUsage() { return _voxelMemoryUsage + _octcodeMemoryUsage + _externalChildrenMemoryUsage; }
|
||||
|
||||
static uint64_t getGetChildAtIndexTime() { return _getChildAtIndexTime; }
|
||||
static uint64_t getGetChildAtIndexCalls() { return _getChildAtIndexCalls; }
|
||||
static uint64_t getSetChildAtIndexTime() { return _setChildAtIndexTime; }
|
||||
static uint64_t getSetChildAtIndexCalls() { return _setChildAtIndexCalls; }
|
||||
|
||||
static uint64_t getSingleChildrenCount() { return _singleChildrenCount; }
|
||||
static uint64_t getTwoChildrenOffsetCount() { return _twoChildrenOffsetCount; }
|
||||
static uint64_t getTwoChildrenExternalCount() { return _twoChildrenExternalCount; }
|
||||
static uint64_t getThreeChildrenOffsetCount() { return _threeChildrenOffsetCount; }
|
||||
static uint64_t getThreeChildrenExternalCount() { return _threeChildrenExternalCount; }
|
||||
static uint64_t getExternalChildrenCount() { return _externalChildrenCount; }
|
||||
static uint64_t getChildrenCount(int childCount) { return _childrenCount[childCount]; }
|
||||
|
||||
static uint64_t getCouldStoreFourChildrenInternally() { return _couldStoreFourChildrenInternally; }
|
||||
static uint64_t getCouldNotStoreFourChildrenInternally() { return _couldNotStoreFourChildrenInternally; }
|
||||
|
||||
#ifdef HAS_AUDIT_CHILDREN
|
||||
void auditChildren(const char* label) const;
|
||||
#endif // def HAS_AUDIT_CHILDREN
|
||||
|
||||
private:
|
||||
void setChildAtIndex(int childIndex, VoxelNode* child);
|
||||
void storeTwoChildren(VoxelNode* childOne, VoxelNode* childTwo);
|
||||
void retrieveTwoChildren(VoxelNode*& childOne, VoxelNode*& childTwo);
|
||||
void storeThreeChildren(VoxelNode* childOne, VoxelNode* childTwo, VoxelNode* childThree);
|
||||
void retrieveThreeChildren(VoxelNode*& childOne, VoxelNode*& childTwo, VoxelNode*& childThree);
|
||||
void decodeThreeOffsets(int64_t& offsetOne, int64_t& offsetTwo, int64_t& offsetThree) const;
|
||||
void encodeThreeOffsets(int64_t offsetOne, int64_t offsetTwo, int64_t offsetThree);
|
||||
void checkStoreFourChildren(VoxelNode* childOne, VoxelNode* childTwo, VoxelNode* childThree, VoxelNode* childFour);
|
||||
|
||||
void calculateAABox();
|
||||
void init(unsigned char * octalCode);
|
||||
void notifyDeleteHooks();
|
||||
void notifyUpdateHooks();
|
||||
|
||||
VoxelNode* _children[8]; /// Client and server, pointers to child nodes, 64 bytes
|
||||
AABox _box; /// Client and server, axis aligned box for bounds of this voxel, 48 bytes
|
||||
unsigned char* _octalCode; /// Client and server, pointer to octal code for this node, 8 bytes
|
||||
|
||||
/// Client and server, buffer containing the octal code or a pointer to octal code for this node, 8 bytes
|
||||
union octalCode_t {
|
||||
unsigned char buffer[8];
|
||||
unsigned char* pointer;
|
||||
} _octalCode;
|
||||
|
||||
uint64_t _lastChanged; /// Client and server, timestamp this node was last changed, 8 bytes
|
||||
unsigned long _subtreeNodeCount; /// Client and server, nodes below this node, 8 bytes
|
||||
unsigned long _subtreeLeafNodeCount; /// Client and server, leaves below this node, 8 bytes
|
||||
|
||||
glBufferIndex _glBufferIndex; /// Client only, vbo index for this voxel if being rendered, 8 bytes
|
||||
VoxelSystem* _voxelSystem; /// Client only, pointer to VoxelSystem rendering this voxel, 8 bytes
|
||||
/// Client and server, pointers to child nodes, various encodings
|
||||
union children_t {
|
||||
VoxelNode* single;
|
||||
int32_t offsetsTwoChildren[2];
|
||||
uint64_t offsetsThreeChildrenEncoded;
|
||||
VoxelNode** external;
|
||||
} _children;
|
||||
|
||||
#ifdef HAS_AUDIT_CHILDREN
|
||||
VoxelNode* _childrenArray[8]; /// Only used when HAS_AUDIT_CHILDREN is enabled to help debug children encoding
|
||||
#endif // def HAS_AUDIT_CHILDREN
|
||||
|
||||
uint32_t _glBufferIndex : 24, /// Client only, vbo index for this voxel if being rendered, 3 bytes
|
||||
_voxelSystemIndex : 8; /// Client only, index to the VoxelSystem rendering this voxel, 1 bytes
|
||||
|
||||
// Support for _voxelSystemIndex, we use these static member variables to track the VoxelSystems that are
|
||||
// in use by various voxel nodes. We map the VoxelSystem pointers into an 1 byte key, this limits us to at
|
||||
// most 255 voxel systems in use at a time within the client. Which is far more than we need.
|
||||
static uint8_t _nextIndex;
|
||||
static std::map<VoxelSystem*, uint8_t> _mapVoxelSystemPointersToIndex;
|
||||
static std::map<uint8_t, VoxelSystem*> _mapIndexToVoxelSystemPointers;
|
||||
|
||||
float _density; /// Client and server, If leaf: density = 1, if internal node: 0-1 density of voxels inside, 4 bytes
|
||||
int _childCount; /// Client and server, current child nodes set to non-null in _children, 4 bytes
|
||||
|
||||
nodeColor _trueColor; /// Client and server, true color of this voxel, 4 bytes
|
||||
#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color
|
||||
nodeColor _currentColor; /// Client only, false color of this voxel, 4 bytes
|
||||
bool _falseColored; /// Client only, is this voxel false colored, 1 bytes
|
||||
#endif
|
||||
|
||||
bool _isDirty; /// Client only, has this voxel changed since being rendered, 1 byte
|
||||
bool _shouldRender; /// Client only, should this voxel render at this time, 1 byte
|
||||
uint16_t _sourceID; /// Client only, stores node id of voxel server that sent his voxel, 2 bytes
|
||||
|
||||
unsigned char _childBitmask; // 1 byte
|
||||
|
||||
bool _falseColored : 1, /// Client only, is this voxel false colored, 1 bit
|
||||
_isDirty : 1, /// Client only, has this voxel changed since being rendered, 1 bit
|
||||
_shouldRender : 1, /// Client only, should this voxel render at this time, 1 bit
|
||||
_octcodePointer : 1, /// Client and Server only, is this voxel's octal code a pointer or buffer, 1 bit
|
||||
_unknownBufferIndex : 1,
|
||||
_childrenExternal : 1; /// Client only, is this voxel's VBO buffer the unknown buffer index, 1 bit
|
||||
|
||||
static std::vector<VoxelNodeDeleteHook*> _deleteHooks;
|
||||
static std::vector<VoxelNodeUpdateHook*> _updateHooks;
|
||||
|
||||
static uint64_t _voxelNodeCount;
|
||||
static uint64_t _voxelNodeLeafCount;
|
||||
|
||||
static uint64_t _voxelMemoryUsage;
|
||||
static uint64_t _octcodeMemoryUsage;
|
||||
static uint64_t _externalChildrenMemoryUsage;
|
||||
|
||||
static uint64_t _getChildAtIndexTime;
|
||||
static uint64_t _getChildAtIndexCalls;
|
||||
static uint64_t _setChildAtIndexTime;
|
||||
static uint64_t _setChildAtIndexCalls;
|
||||
|
||||
static uint64_t _singleChildrenCount;
|
||||
static uint64_t _twoChildrenOffsetCount;
|
||||
static uint64_t _twoChildrenExternalCount;
|
||||
static uint64_t _threeChildrenOffsetCount;
|
||||
static uint64_t _threeChildrenExternalCount;
|
||||
static uint64_t _externalChildrenCount;
|
||||
static uint64_t _childrenCount[NUMBER_OF_CHILDREN + 1];
|
||||
|
||||
static uint64_t _couldStoreFourChildrenInternally;
|
||||
static uint64_t _couldNotStoreFourChildrenInternally;
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__VoxelNode__) */
|
|
@ -33,9 +33,10 @@ void VoxelSceneStats::sceneStarted(bool isFullScene, bool isMoving, VoxelNode* r
|
|||
reset(); // resets packet and voxel stats
|
||||
_isStarted = true;
|
||||
_start = usecTimestampNow();
|
||||
_totalVoxels = root->getSubTreeNodeCount();
|
||||
_totalInternal = root->getSubTreeInternalNodeCount();
|
||||
_totalLeaves = root->getSubTreeLeafNodeCount();
|
||||
|
||||
_totalVoxels = VoxelNode::getNodeCount();
|
||||
_totalInternal = VoxelNode::getInternalNodeCount();
|
||||
_totalLeaves = VoxelNode::getLeafNodeCount();
|
||||
|
||||
_isFullScene = isFullScene;
|
||||
_isMoving = isMoving;
|
||||
|
|
|
@ -134,7 +134,7 @@ void VoxelTree::recurseNodeWithOperationDistanceSorted(VoxelNode* node, RecurseV
|
|||
|
||||
|
||||
VoxelNode* VoxelTree::nodeForOctalCode(VoxelNode* ancestorNode,
|
||||
unsigned char* needleCode, VoxelNode** parentOfFoundNode) const {
|
||||
const unsigned char* needleCode, VoxelNode** parentOfFoundNode) const {
|
||||
// find the appropriate branch index based on this ancestorNode
|
||||
if (*needleCode > 0) {
|
||||
int branchForNeedle = branchIndexWithDescendant(ancestorNode->getOctalCode(), needleCode);
|
||||
|
@ -630,9 +630,22 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) {
|
|||
}
|
||||
|
||||
// Note: this is an expensive call. Don't call it unless you really need to reaverage the entire tree (from startNode)
|
||||
void VoxelTree::reaverageVoxelColors(VoxelNode *startNode) {
|
||||
void VoxelTree::reaverageVoxelColors(VoxelNode* startNode) {
|
||||
// if our tree is a reaveraging tree, then we do this, otherwise we don't do anything
|
||||
if (_shouldReaverage) {
|
||||
static int recursionCount;
|
||||
if (startNode == rootNode) {
|
||||
recursionCount = 0;
|
||||
} else {
|
||||
recursionCount++;
|
||||
}
|
||||
const int UNREASONABLY_DEEP_RECURSION = 20;
|
||||
if (recursionCount > UNREASONABLY_DEEP_RECURSION) {
|
||||
qDebug("VoxelTree::reaverageVoxelColors()... bailing out of UNREASONABLY_DEEP_RECURSION\n");
|
||||
recursionCount--;
|
||||
return;
|
||||
}
|
||||
|
||||
bool hasChildren = false;
|
||||
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
|
@ -647,9 +660,7 @@ void VoxelTree::reaverageVoxelColors(VoxelNode *startNode) {
|
|||
if (hasChildren && !startNode->collapseIdenticalLeaves()) {
|
||||
startNode->setColorFromAverageOfChildren();
|
||||
}
|
||||
|
||||
// this is also a good time to recalculateSubTreeNodeCount()
|
||||
startNode->recalculateSubTreeNodeCount();
|
||||
recursionCount--;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -713,6 +724,11 @@ VoxelNode* VoxelTree::getVoxelAt(float x, float y, float z, float s) const {
|
|||
node = NULL;
|
||||
}
|
||||
delete[] octalCode; // cleanup memory
|
||||
#ifdef HAS_AUDIT_CHILDREN
|
||||
if (node) {
|
||||
node->auditChildren("VoxelTree::getVoxelAt()");
|
||||
}
|
||||
#endif // def HAS_AUDIT_CHILDREN
|
||||
return node;
|
||||
}
|
||||
|
||||
|
@ -1981,7 +1997,7 @@ bool VoxelTree::nudgeCheck(VoxelNode* node, void* extraData) {
|
|||
NodeChunkArgs* args = (NodeChunkArgs*)extraData;
|
||||
|
||||
// get octal code of this node
|
||||
unsigned char* octalCode = node->getOctalCode();
|
||||
const unsigned char* octalCode = node->getOctalCode();
|
||||
|
||||
// get voxel position/size
|
||||
VoxelPositionSize unNudgedDetails;
|
||||
|
@ -2020,7 +2036,7 @@ void VoxelTree::nudgeLeaf(VoxelNode* node, void* extraData) {
|
|||
NodeChunkArgs* args = (NodeChunkArgs*)extraData;
|
||||
|
||||
// get octal code of this node
|
||||
unsigned char* octalCode = node->getOctalCode();
|
||||
const unsigned char* octalCode = node->getOctalCode();
|
||||
|
||||
// get voxel position/size
|
||||
VoxelPositionSize unNudgedDetails;
|
||||
|
|
|
@ -214,7 +214,7 @@ private:
|
|||
|
||||
static bool countVoxelsOperation(VoxelNode* node, void* extraData);
|
||||
|
||||
VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode) const;
|
||||
VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, const unsigned char* needleCode, VoxelNode** parentOfFoundNode) const;
|
||||
VoxelNode* createMissingNode(VoxelNode* lastParentNode, unsigned char* deepestCodeToCreate);
|
||||
int readNodeData(VoxelNode *destinationNode, unsigned char* nodeData, int bufferSizeBytes, ReadBitstreamToTreeParams& args);
|
||||
|
||||
|
@ -225,7 +225,7 @@ private:
|
|||
|
||||
/// Octal Codes of any subtrees currently being encoded. While any of these codes is being encoded, ancestors and
|
||||
/// descendants of them can not be deleted.
|
||||
std::set<unsigned char*> _codesBeingEncoded;
|
||||
std::set<const unsigned char*> _codesBeingEncoded;
|
||||
/// mutex lock to protect the encoding set
|
||||
pthread_mutex_t _encodeSetLock;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//
|
||||
//
|
||||
// main.cpp
|
||||
// Voxel Edit
|
||||
//
|
||||
|
@ -233,7 +233,7 @@ void processFillSVOFile(const char* fillSVOFile) {
|
|||
}
|
||||
|
||||
|
||||
int main(int argc, const char * argv[])
|
||||
int old_main(int argc, const char * argv[])
|
||||
{
|
||||
qInstallMessageHandler(sharedMessageHandler);
|
||||
|
||||
|
@ -294,4 +294,76 @@ int main(int argc, const char * argv[])
|
|||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void unitTest(VoxelTree * tree) {
|
||||
printf("unit tests...\n");
|
||||
|
||||
// We want our corner voxels to be about 1/2 meter high, and our TREE_SCALE is in meters, so...
|
||||
float voxelSize = 0.5f;
|
||||
|
||||
// Here's an example of how to create a voxel.
|
||||
printf("creating corner points...\n");
|
||||
tree->createVoxel(0, 0, 0, voxelSize, 255, 255 ,255);
|
||||
|
||||
// Here's an example of how to test if a voxel exists
|
||||
VoxelNode* node = tree->getVoxelAt(0, 0, 0, voxelSize);
|
||||
if (node) {
|
||||
// and how to access it's color
|
||||
printf("corner point 0,0,0 exists... color is (%d,%d,%d) \n",
|
||||
node->getColor()[0], node->getColor()[1], node->getColor()[2]);
|
||||
}
|
||||
|
||||
// here's an example of how to delete a voxel
|
||||
printf("attempting to delete corner point 0,0,0\n");
|
||||
tree->deleteVoxelAt(0, 0, 0, voxelSize);
|
||||
|
||||
// Test to see that the delete worked... it should be FALSE...
|
||||
if (tree->getVoxelAt(0, 0, 0, voxelSize)) {
|
||||
printf("corner point 0,0,0 exists...\n");
|
||||
} else {
|
||||
printf("corner point 0,0,0 does not exists...\n");
|
||||
}
|
||||
|
||||
tree->createVoxel(0, 0, 0, voxelSize, 255, 255 ,255);
|
||||
if (tree->getVoxelAt(0, 0, 0, voxelSize)) {
|
||||
printf("corner point 0,0,0 exists...\n");
|
||||
} else {
|
||||
printf("corner point 0,0,0 does not exists...\n");
|
||||
}
|
||||
|
||||
tree->createVoxel(voxelSize, 0, 0, voxelSize, 255, 255 ,255);
|
||||
if (tree->getVoxelAt(voxelSize, 0, 0, voxelSize)) {
|
||||
printf("corner point voxelSize,0,0 exists...\n");
|
||||
} else {
|
||||
printf("corner point voxelSize,0,0 does not exists...\n");
|
||||
}
|
||||
|
||||
tree->createVoxel(0, 0, voxelSize, voxelSize, 255, 255 ,255);
|
||||
if (tree->getVoxelAt(0, 0, voxelSize, voxelSize)) {
|
||||
printf("corner point 0, 0, voxelSize exists...\n");
|
||||
} else {
|
||||
printf("corner point 0, 0, voxelSize does not exists...\n");
|
||||
}
|
||||
|
||||
tree->createVoxel(voxelSize, 0, voxelSize, voxelSize, 255, 255 ,255);
|
||||
if (tree->getVoxelAt(voxelSize, 0, voxelSize, voxelSize)) {
|
||||
printf("corner point voxelSize, 0, voxelSize exists...\n");
|
||||
} else {
|
||||
printf("corner point voxelSize, 0, voxelSize does not exists...\n");
|
||||
}
|
||||
|
||||
printf("check root voxel exists...\n");
|
||||
if (tree->getVoxelAt(0,0,0,1.0)) {
|
||||
printf("of course it does\n");
|
||||
} else {
|
||||
printf("WTH!?!\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, const char * argv[]) {
|
||||
unitTest(&myTree);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue