Merge pull request #1075 from ZappoMan/voxelnode_memory_savings

VoxelNode memory savings
This commit is contained in:
Philip Rosedale 2013-10-17 14:26:40 -07:00
commit c48856df52
21 changed files with 1262 additions and 263 deletions

View file

@ -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;

View file

@ -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;

View file

@ -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__) */

View file

@ -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;
}
};

View file

@ -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; }

View file

@ -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

View file

@ -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__) */

View file

@ -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;

View file

@ -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 {

View file

@ -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);
}
}

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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) {

View file

@ -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

View file

@ -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__) */

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;
}