From 2c8c6a2600c4804e8f01b1b5e147106128206297 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 5 May 2013 10:17:02 -0700 Subject: [PATCH 01/25] Coding standard cleanup and VoxelNode optimization - make octalCode and children members private - add public getters for accessing these private members - change constructor to require an OctalCode for all non-roots - default constructor constructs a rootNode - make primary access for deleting, adding, and accessing children through public methods that do bookkeeping - calculate AABox on voxel creation so that we don't need to do all the math when we deal with voxels - added methods on VoxelNode for common items like getCorner(), getCenter(), getLevel(), etc --- interface/src/VoxelSystem.cpp | 12 +-- libraries/voxels/src/AABox.cpp | 2 + libraries/voxels/src/AABox.h | 2 + libraries/voxels/src/VoxelConstants.h | 2 + libraries/voxels/src/VoxelNode.cpp | 86 ++++++++++++--------- libraries/voxels/src/VoxelNode.h | 24 ++++-- libraries/voxels/src/VoxelNodeBag.cpp | 2 +- libraries/voxels/src/VoxelTree.cpp | 106 ++++++++++++-------------- voxel-server/src/main.cpp | 8 +- 9 files changed, 132 insertions(+), 112 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 989ab8ff3d..258b604b0c 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -221,8 +221,8 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) { assert(_viewFrustum); // you must set up _viewFrustum before calling this int voxelsUpdated = 0; float distanceToNode = node->distanceToCamera(*_viewFrustum); - float boundary = boundaryDistanceForRenderLevel(*node->octalCode + 1); - float childBoundary = boundaryDistanceForRenderLevel(*node->octalCode + 2); + float boundary = boundaryDistanceForRenderLevel(node->getLevel()); + float childBoundary = boundaryDistanceForRenderLevel(node->getLevel() + 1); bool inBoundary = (distanceToNode <= boundary); bool inChildBoundary = (distanceToNode <= childBoundary); bool shouldRender = node->isColored() && ((node->isLeaf() && inChildBoundary) || (inBoundary && !inChildBoundary)); @@ -230,8 +230,8 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) { node->setShouldRender(shouldRender); // let children figure out their renderness for (int i = 0; i < 8; i++) { - if (node->children[i]) { - voxelsUpdated += newTreeToArrays(node->children[i]); + if (node->getChildAtIndex(i)) { + voxelsUpdated += newTreeToArrays(node->getChildAtIndex(i)); } } @@ -242,8 +242,8 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) { // If we're should render, use our legit location and scale, if (node->getShouldRender()) { - copyFirstVertexForCode(node->octalCode, (float*)&startVertex); - voxelScale = (1 / powf(2, *node->octalCode)); + startVertex = node->getCorner(); + voxelScale = node->getScale(); } else { // if we shouldn't render then set out location to some infinitely distant location, // and our scale as infinitely small diff --git a/libraries/voxels/src/AABox.cpp b/libraries/voxels/src/AABox.cpp index 0187bae853..00cace6ae5 100755 --- a/libraries/voxels/src/AABox.cpp +++ b/libraries/voxels/src/AABox.cpp @@ -14,6 +14,7 @@ void AABox::scale(float scale) { _corner = _corner*scale; _size = _size*scale; + _center = _center*scale; } @@ -34,6 +35,7 @@ void AABox::setBox(const glm::vec3& corner, const glm::vec3& size) { _size.z = -size.z; _corner.z -= _size.z; } + _center = _corner + (_size * 0.5f); } glm::vec3 AABox::getVertexP(const glm::vec3 &normal) const { diff --git a/libraries/voxels/src/AABox.h b/libraries/voxels/src/AABox.h index 0a69b8608d..fd399a95e6 100755 --- a/libraries/voxels/src/AABox.h +++ b/libraries/voxels/src/AABox.h @@ -34,9 +34,11 @@ public: const glm::vec3& getCorner() const { return _corner; }; const glm::vec3& getSize() const { return _size; }; + const glm::vec3& getCenter() const { return _center; }; private: glm::vec3 _corner; + glm::vec3 _center; glm::vec3 _size; }; diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index 16bab45e4f..f278017f23 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -14,6 +14,8 @@ #include +const int NUMBER_OF_CHILDREN = 8; + const int MAX_VOXEL_PACKET_SIZE = 1492; const int MAX_TREE_SLICE_BYTES = 26; const int TREE_SCALE = 10; diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 3d0e400782..30d8ea1f68 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -20,7 +20,17 @@ using voxels_lib::printLog; // using voxels_lib::printLog; VoxelNode::VoxelNode() { - octalCode = NULL; + unsigned char* rootCode = new unsigned char[1]; + *rootCode = 0; + init(rootCode); +} + +VoxelNode::VoxelNode(unsigned char * octalCode) { + init(octalCode); +} + +void VoxelNode::init(unsigned char * octalCode) { + _octalCode = octalCode; #ifdef HAS_FALSE_COLOR _falseColored = false; // assume true color @@ -28,21 +38,23 @@ VoxelNode::VoxelNode() { // default pointers to child nodes to NULL for (int i = 0; i < 8; i++) { - children[i] = NULL; + _children[i] = NULL; } _glBufferIndex = GLBUFFER_INDEX_UNKNOWN; _isDirty = true; _shouldRender = false; + + calculateAABox(); } VoxelNode::~VoxelNode() { - delete[] octalCode; + delete[] _octalCode; // delete all of this node's children for (int i = 0; i < 8; i++) { - if (children[i]) { - delete children[i]; + if (_children[i]) { + delete _children[i]; } } } @@ -55,33 +67,38 @@ void VoxelNode::setShouldRender(bool shouldRender) { } } -void VoxelNode::getAABox(AABox& box) const { +void VoxelNode::calculateAABox() { glm::vec3 corner; glm::vec3 size; // copy corner into box - copyFirstVertexForCode(octalCode,(float*)&corner); + copyFirstVertexForCode(_octalCode,(float*)&corner); // this tells you the "size" of the voxel - float voxelScale = 1 / powf(2, *octalCode); + float voxelScale = 1 / powf(2, *_octalCode); size = glm::vec3(voxelScale,voxelScale,voxelScale); - box.setBox(corner,size); + _box.setBox(corner,size); +} + +void VoxelNode::deleteChildAtIndex(int childIndex) { + if (_children[childIndex]) { + delete _children[childIndex]; + _children[childIndex] = NULL; + } } void VoxelNode::addChildAtIndex(int childIndex) { - if (!children[childIndex]) { - children[childIndex] = new VoxelNode(); + if (!_children[childIndex]) { + _children[childIndex] = new VoxelNode(childOctalCode(_octalCode, childIndex)); // XXXBHG - When the node is constructed, it should be cleanly set up as // true colored, but for some reason, not so much. I've added a a basecamp // to-do to research this. But for now we'll use belt and suspenders and set // it to not-false-colored here! - children[childIndex]->setFalseColored(false); + _children[childIndex]->setFalseColored(false); - // give this child its octal code - children[childIndex]->octalCode = childOctalCode(octalCode, childIndex); _isDirty = true; } } @@ -90,9 +107,9 @@ void VoxelNode::addChildAtIndex(int childIndex) { void VoxelNode::setColorFromAverageOfChildren() { int colorArray[4] = {0,0,0,0}; for (int i = 0; i < 8; i++) { - if (children[i] != NULL && children[i]->isColored()) { + if (_children[i] != NULL && _children[i]->isColored()) { for (int j = 0; j < 3; j++) { - colorArray[j] += children[i]->getTrueColor()[j]; // color averaging should always be based on true colors + colorArray[j] += _children[i]->getTrueColor()[j]; // color averaging should always be based on true colors } colorArray[3]++; } @@ -170,17 +187,17 @@ bool VoxelNode::collapseIdenticalLeaves() { int red,green,blue; for (int i = 0; i < 8; i++) { // if no child, or child doesn't have a color - if (children[i] == NULL || !children[i]->isColored()) { + if (_children[i] == NULL || !_children[i]->isColored()) { allChildrenMatch=false; //printLog("SADNESS child missing or not colored! i=%d\n",i); break; } else { if (i==0) { - red = children[i]->getColor()[0]; - green = children[i]->getColor()[1]; - blue = children[i]->getColor()[2]; - } else if (red != children[i]->getColor()[0] || - green != children[i]->getColor()[1] || blue != children[i]->getColor()[2]) { + red = _children[i]->getColor()[0]; + green = _children[i]->getColor()[1]; + blue = _children[i]->getColor()[2]; + } else if (red != _children[i]->getColor()[0] || + green != _children[i]->getColor()[1] || blue != _children[i]->getColor()[2]) { allChildrenMatch=false; break; } @@ -191,8 +208,8 @@ bool VoxelNode::collapseIdenticalLeaves() { if (allChildrenMatch) { //printLog("allChildrenMatch: pruning tree\n"); for (int i = 0; i < 8; i++) { - delete children[i]; // delete all the child nodes - children[i]=NULL; // set it to NULL + delete _children[i]; // delete all the child nodes + _children[i]=NULL; // set it to NULL } nodeColor collapsedColor; collapsedColor[0]=red; @@ -216,7 +233,7 @@ void VoxelNode::setRandomColor(int minimumBrightness) { bool VoxelNode::isLeaf() const { for (int i = 0; i < 8; i++) { - if (children[i]) { + if (_children[i]) { return false; } } @@ -224,27 +241,22 @@ bool VoxelNode::isLeaf() const { } void VoxelNode::printDebugDetails(const char* label) const { - AABox box; - getAABox(box); printLog("%s - Voxel at corner=(%f,%f,%f) size=%f octcode=", label, - box.getCorner().x, box.getCorner().y, box.getCorner().z, box.getSize().x); - printOctalCode(octalCode); + _box.getCorner().x, _box.getCorner().y, _box.getCorner().z, _box.getSize().x); + printOctalCode(_octalCode); } bool VoxelNode::isInView(const ViewFrustum& viewFrustum) const { - AABox box; - getAABox(box); + AABox box = _box; // use temporary box so we can scale it box.scale(TREE_SCALE); bool inView = (ViewFrustum::OUTSIDE != viewFrustum.boxInFrustum(box)); return inView; } float VoxelNode::distanceToCamera(const ViewFrustum& viewFrustum) const { - AABox box; - getAABox(box); - box.scale(TREE_SCALE); - float distanceToVoxelCenter = sqrtf(powf(viewFrustum.getPosition().x - (box.getCorner().x + box.getSize().x), 2) + - powf(viewFrustum.getPosition().y - (box.getCorner().y + box.getSize().y), 2) + - powf(viewFrustum.getPosition().z - (box.getCorner().z + box.getSize().z), 2)); + glm::vec3 center = _box.getCenter() * (float)TREE_SCALE; + float distanceToVoxelCenter = sqrtf(powf(viewFrustum.getPosition().x - center.x, 2) + + powf(viewFrustum.getPosition().y - center.y, 2) + + powf(viewFrustum.getPosition().z - center.z, 2)); return distanceToVoxelCenter; } diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 90ee3bf730..8e3fa1b4d6 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -27,23 +27,37 @@ private: glBufferIndex _glBufferIndex; bool _isDirty; bool _shouldRender; + AABox _box; + unsigned char* _octalCode; + VoxelNode* _children[8]; + + void calculateAABox(); + + void init(unsigned char * octalCode); + public: - VoxelNode(); + VoxelNode(); // root node constructor + VoxelNode(unsigned char * octalCode); // regular constructor ~VoxelNode(); + unsigned char* getOctalCode() const { return _octalCode; }; + VoxelNode* getChildAtIndex(int i) const { return _children[i]; }; + void deleteChildAtIndex(int childIndex); void addChildAtIndex(int childIndex); void setColorFromAverageOfChildren(); void setRandomColor(int minimumBrightness); bool collapseIdenticalLeaves(); - - unsigned char *octalCode; - VoxelNode *children[8]; + + 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? */ }; bool isColored() const { return (_trueColor[3]==1); }; bool isInView(const ViewFrustum& viewFrustum) const; float distanceToCamera(const ViewFrustum& viewFrustum) const; bool isLeaf() const; - void getAABox(AABox& box) const; void printDebugDetails(const char* label) const; bool isDirty() const { return _isDirty; }; void clearDirtyBit() { _isDirty = false; }; diff --git a/libraries/voxels/src/VoxelNodeBag.cpp b/libraries/voxels/src/VoxelNodeBag.cpp index e6b20cbf4b..132405ba6e 100644 --- a/libraries/voxels/src/VoxelNodeBag.cpp +++ b/libraries/voxels/src/VoxelNodeBag.cpp @@ -34,7 +34,7 @@ void VoxelNodeBag::insert(VoxelNode* node) { for (int i = 0; i < _elementsInUse; i++) { // compare the newNode to the elements already in the bag - OctalCodeComparison comparison = compareOctalCodes(_bagElements[i]->octalCode, node->octalCode); + OctalCodeComparison comparison = compareOctalCodes(_bagElements[i]->getOctalCode(), node->getOctalCode()); // If we found a code in the bag that matches, then just return, since the element is already in the bag. if (comparison == EXACT_MATCH) { diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index fee0c698bb..519d87d430 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -37,17 +37,14 @@ VoxelTree::VoxelTree() : voxelsColoredStats(100), voxelsBytesReadStats(100), _isDirty(true) { - rootNode = new VoxelNode(); - rootNode->octalCode = new unsigned char[1]; - *rootNode->octalCode = 0; } VoxelTree::~VoxelTree() { // delete the children of the root node // this recursively deletes the tree for (int i = 0; i < 8; i++) { - delete rootNode->children[i]; + delete rootNode->getChildAtIndex(i); } } @@ -60,8 +57,8 @@ void VoxelTree::recurseTreeWithOperation(RecurseVoxelTreeOperation operation, vo // Recurses voxel node with an operation function void VoxelTree::recurseNodeWithOperation(VoxelNode* node,RecurseVoxelTreeOperation operation, void* extraData) { if (operation(node, extraData)) { - for (int i = 0; i < sizeof(node->children) / sizeof(node->children[0]); i++) { - VoxelNode* child = node->children[i]; + for (int i = 0; i < 8; i++) { + VoxelNode* child = node->getChildAtIndex(i); if (child) { recurseNodeWithOperation(child, operation, extraData); } @@ -72,11 +69,11 @@ void VoxelTree::recurseNodeWithOperation(VoxelNode* node,RecurseVoxelTreeOperati VoxelNode * VoxelTree::nodeForOctalCode(VoxelNode *ancestorNode, unsigned char * needleCode, VoxelNode** parentOfFoundNode) const { // find the appropriate branch index based on this ancestorNode if (*needleCode > 0) { - int branchForNeedle = branchIndexWithDescendant(ancestorNode->octalCode, needleCode); - VoxelNode *childNode = ancestorNode->children[branchForNeedle]; + int branchForNeedle = branchIndexWithDescendant(ancestorNode->getOctalCode(), needleCode); + VoxelNode *childNode = ancestorNode->getChildAtIndex(branchForNeedle); - if (childNode != NULL) { - if (*childNode->octalCode == *needleCode) { + if (childNode) { + if (*childNode->getOctalCode() == *needleCode) { // If the caller asked for the parent, then give them that too... if (parentOfFoundNode) { @@ -101,18 +98,18 @@ VoxelNode * VoxelTree::nodeForOctalCode(VoxelNode *ancestorNode, unsigned char * // returns the node created! VoxelNode* VoxelTree::createMissingNode(VoxelNode* lastParentNode, unsigned char* codeToReach) { - int indexOfNewChild = branchIndexWithDescendant(lastParentNode->octalCode, codeToReach); + int indexOfNewChild = branchIndexWithDescendant(lastParentNode->getOctalCode(), codeToReach); // we could be coming down a branch that was already created, so don't stomp on it. - if (lastParentNode->children[indexOfNewChild] == NULL) { + if (!lastParentNode->getChildAtIndex(indexOfNewChild)) { lastParentNode->addChildAtIndex(indexOfNewChild); } // This works because we know we traversed down the same tree so if the length is the same, then the whole code is the same - if (*lastParentNode->children[indexOfNewChild]->octalCode == *codeToReach) { - return lastParentNode->children[indexOfNewChild]; + if (*lastParentNode->getChildAtIndex(indexOfNewChild)->getOctalCode() == *codeToReach) { + return lastParentNode->getChildAtIndex(indexOfNewChild); } else { - return createMissingNode(lastParentNode->children[indexOfNewChild], codeToReach); + return createMissingNode(lastParentNode->getChildAtIndex(indexOfNewChild), codeToReach); } } @@ -124,11 +121,11 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, int bytesLeftToRead) { // instantiate variable for bytes already read int bytesRead = 1; - for (int i = 0; i < 8; i++) { + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { // check the colors mask to see if we have a child to color in if (oneAtBit(*nodeData, i)) { // create the child if it doesn't exist - if (!destinationNode->children[i]) { + if (!destinationNode->getChildAtIndex(i)) { destinationNode->addChildAtIndex(i); if (destinationNode->isDirty()) { _isDirty = true; @@ -142,9 +139,9 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, nodeColor newColor; memcpy(newColor, nodeData + bytesRead, 3); newColor[3] = 1; - bool nodeWasDirty = destinationNode->children[i]->isDirty(); - destinationNode->children[i]->setColor(newColor); - bool nodeIsDirty = destinationNode->children[i]->isDirty(); + bool nodeWasDirty = destinationNode->getChildAtIndex(i)->isDirty(); + destinationNode->getChildAtIndex(i)->setColor(newColor); + bool nodeIsDirty = destinationNode->getChildAtIndex(i)->isDirty(); if (nodeIsDirty) { _isDirty = true; } @@ -168,7 +165,7 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, // check the exists mask to see if we have a child to traverse into if (oneAtBit(childMask, childIndex)) { - if (!destinationNode->children[childIndex]) { + if (!destinationNode->getChildAtIndex(childIndex)) { // add a child at that index, if it doesn't exist bool nodeWasDirty = destinationNode->isDirty(); destinationNode->addChildAtIndex(childIndex); @@ -184,7 +181,7 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, } // tell the child to read the subsequent data - bytesRead += readNodeData(destinationNode->children[childIndex], + bytesRead += readNodeData(destinationNode->getChildAtIndex(childIndex), nodeData + bytesRead, bytesLeftToRead - bytesRead); } @@ -207,7 +204,7 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, unsigned long int while (bitstreamAt < bitstream + bufferSizeBytes) { VoxelNode* bitstreamRootNode = nodeForOctalCode(rootNode, (unsigned char *)bitstreamAt, NULL); - if (*bitstreamAt != *bitstreamRootNode->octalCode) { + if (*bitstreamAt != *bitstreamRootNode->getOctalCode()) { // if the octal code returned is not on the same level as // the code being searched for, we have VoxelNodes to create @@ -251,12 +248,11 @@ void VoxelTree::deleteVoxelCodeFromTree(unsigned char *codeBuffer) { // If the node exists... int lengthInBytes = bytesRequiredForCodeLength(*codeBuffer); // includes octet count, not color! - if (0 == memcmp(nodeToDelete->octalCode,codeBuffer,lengthInBytes)) { + if (0 == memcmp(nodeToDelete->getOctalCode(),codeBuffer,lengthInBytes)) { if (parentNode) { - int childIndex = branchIndexWithDescendant(parentNode->octalCode, codeBuffer); + int childIndex = branchIndexWithDescendant(parentNode->getOctalCode(), codeBuffer); - delete parentNode->children[childIndex]; // delete the child nodes - parentNode->children[childIndex] = NULL; // set it to NULL + parentNode->deleteChildAtIndex(childIndex); reaverageVoxelColors(rootNode); // Fix our colors!! Need to call it on rootNode _isDirty = true; @@ -268,8 +264,6 @@ void VoxelTree::eraseAllVoxels() { // XXXBHG Hack attack - is there a better way to erase the voxel tree? delete rootNode; // this will recurse and delete all children rootNode = new VoxelNode(); - rootNode->octalCode = new unsigned char[1]; - *rootNode->octalCode = 0; _isDirty = true; } @@ -277,7 +271,7 @@ void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) { VoxelNode* lastCreatedNode = nodeForOctalCode(rootNode, codeColorBuffer, NULL); // create the node if it does not exist - if (*lastCreatedNode->octalCode != *codeColorBuffer) { + if (*lastCreatedNode->getOctalCode() != *codeColorBuffer) { lastCreatedNode = createMissingNode(lastCreatedNode, codeColorBuffer); _isDirty = true; } @@ -320,7 +314,7 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { // create the color mask for (int i = 0; i < 8; i++) { - if (startNode->children[i] != NULL && startNode->children[i]->isColored()) { + if (startNode->getChildAtIndex(i) && startNode->getChildAtIndex(i)->isColored()) { colorMask += (1 << (7 - i)); } } @@ -330,19 +324,19 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { // output the colors we have for (int j = 0; j < 8; j++) { - if (startNode->children[j] != NULL && startNode->children[j]->isColored()) { + if (startNode->getChildAtIndex(j) && startNode->getChildAtIndex(j)->isColored()) { printLog("color %d : ",j); for (int c = 0; c < 3; c++) { - outputBits(startNode->children[j]->getTrueColor()[c],false); + outputBits(startNode->getChildAtIndex(j)->getTrueColor()[c],false); } - startNode->children[j]->printDebugDetails(""); + startNode->getChildAtIndex(j)->printDebugDetails(""); } } unsigned char childMask = 0; for (int k = 0; k < 8; k++) { - if (startNode->children[k] != NULL) { + if (startNode->getChildAtIndex(k)) { childMask += (1 << (7 - k)); } } @@ -354,8 +348,8 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { // ask children to recursively output their trees // if they aren't a leaf for (int l = 0; l < 8; l++) { - if (startNode->children[l] != NULL) { - printTreeForDebugging(startNode->children[l]); + if (startNode->getChildAtIndex(l)) { + printTreeForDebugging(startNode->getChildAtIndex(l)); } } } @@ -365,8 +359,8 @@ void VoxelTree::reaverageVoxelColors(VoxelNode *startNode) { bool hasChildren = false; for (int i = 0; i < 8; i++) { - if (startNode->children[i] != NULL) { - reaverageVoxelColors(startNode->children[i]); + if (startNode->getChildAtIndex(i)) { + reaverageVoxelColors(startNode->getChildAtIndex(i)); hasChildren = true; } } @@ -437,7 +431,7 @@ void VoxelTree::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) { VoxelNode* VoxelTree::getVoxelAt(float x, float y, float z, float s) const { unsigned char* octalCode = pointToVoxel(x,y,z,s,0,0,0); VoxelNode* node = nodeForOctalCode(rootNode, octalCode, NULL); - if (*node->octalCode != *octalCode) { + if (*node->getOctalCode() != *octalCode) { node = NULL; } delete octalCode; // cleanup memory @@ -587,11 +581,10 @@ int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSe // for each child node, check to see if they exist, are colored, and in view, and if so // add them to our distance ordered array of children for (int i = 0; i < MAX_CHILDREN; i++) { - VoxelNode* childNode = node->children[i]; - bool childExists = (childNode != NULL); - bool childIsColored = (childExists && childNode->isColored()); - bool childIsInView = (childExists && childNode->isInView(viewFrustum)); - bool childIsLeaf = (childExists && childNode->isLeaf()); + VoxelNode* childNode = node->getChildAtIndex(i); + bool childIsColored = (childNode && childNode->isColored()); + bool childIsInView = (childNode && childNode->isInView(viewFrustum)); + bool childIsLeaf = (childNode && childNode->isLeaf()); if (childIsInView) { @@ -607,7 +600,7 @@ int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSe float distance = childNode->distanceToCamera(viewFrustum); - if (distance < boundaryDistanceForRenderLevel(*childNode->octalCode + 1)) { + if (distance < boundaryDistanceForRenderLevel(*childNode->getOctalCode() + 1)) { inViewCount = insertIntoSortedArrays((void*)childNode, distance, i, (void**)&inViewChildren, (float*)&distancesToChildren, (int*)&positionOfChildren, inViewCount, MAX_CHILDREN); @@ -648,8 +641,8 @@ int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned } // write the octal code - int codeLength = bytesRequiredForCodeLength(*node->octalCode); - memcpy(outputBuffer,node->octalCode,codeLength); + int codeLength = bytesRequiredForCodeLength(*node->getOctalCode()); + memcpy(outputBuffer,node->getOctalCode(),codeLength); outputBuffer += codeLength; // move the pointer bytesWritten += codeLength; // keep track of byte count @@ -695,7 +688,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco // caller can pass NULL as viewFrustum if they want everything if (viewFrustum) { float distance = node->distanceToCamera(*viewFrustum); - float boundaryDistance = boundaryDistanceForRenderLevel(*node->octalCode + 1); + float boundaryDistance = boundaryDistanceForRenderLevel(*node->getOctalCode() + 1); // If we're too far away for our render level, then just return if (distance >= boundaryDistance) { @@ -735,13 +728,12 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco // for each child node, check to see if they exist, are colored, and in view, and if so // add them to our distance ordered array of children for (int i = 0; i < MAX_CHILDREN; i++) { - VoxelNode* childNode = node->children[i]; - bool childExists = (childNode != NULL); - bool childIsInView = (childExists && (!viewFrustum || childNode->isInView(*viewFrustum))); + VoxelNode* childNode = node->getChildAtIndex(i); + bool childIsInView = (childNode && (!viewFrustum || childNode->isInView(*viewFrustum))); if (childIsInView) { // Before we determine consider this further, let's see if it's in our LOD scope... float distance = viewFrustum ? childNode->distanceToCamera(*viewFrustum) : 0; - float boundaryDistance = viewFrustum ? boundaryDistanceForRenderLevel(*childNode->octalCode + 1) : 1; + float boundaryDistance = viewFrustum ? boundaryDistanceForRenderLevel(*childNode->getOctalCode() + 1) : 1; if (distance < boundaryDistance) { inViewCount++; @@ -749,13 +741,13 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco // track children in view as existing and not a leaf, if they're a leaf, // we don't care about recursing deeper on them, and we don't consider their // subtree to exist - if (!(childExists && childNode->isLeaf())) { + if (!(childNode && childNode->isLeaf())) { childrenExistBits += (1 << (7 - i)); inViewNotLeafCount++; } // track children with actual color - if (childExists && childNode->isColored()) { + if (childNode && childNode->isColored()) { childrenColoredBits += (1 << (7 - i)); inViewWithColorCount++; } @@ -769,7 +761,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco // write the color data... for (int i = 0; i < MAX_CHILDREN; i++) { if (oneAtBit(childrenColoredBits, i)) { - memcpy(writeToThisLevelBuffer, &node->children[i]->getColor(), BYTES_PER_COLOR); + memcpy(writeToThisLevelBuffer, &node->getChildAtIndex(i)->getColor(), BYTES_PER_COLOR); writeToThisLevelBuffer += BYTES_PER_COLOR; // move the pointer for color bytesAtThisLevel += BYTES_PER_COLOR; // keep track of byte count for color } @@ -810,7 +802,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco for (int i = 0; i < MAX_CHILDREN; i++) { if (oneAtBit(childrenExistBits, i)) { - VoxelNode* childNode = node->children[i]; + VoxelNode* childNode = node->getChildAtIndex(i); int thisLevel = currentEncodeLevel; int childTreeBytesOut = encodeTreeBitstreamRecursion(maxEncodeLevel, thisLevel, childNode, diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index eec5bb308a..366b81ad6d 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -153,12 +153,8 @@ void randomlyFillVoxelTree(int levelsToGo, VoxelNode *currentRootNode) { for (int i = 0; i < 8; i++) { if (true) { // create a new VoxelNode to put here - currentRootNode->children[i] = new VoxelNode(); - - // give this child it's octal code - currentRootNode->children[i]->octalCode = childOctalCode(currentRootNode->octalCode, i); - - randomlyFillVoxelTree(levelsToGo - 1, currentRootNode->children[i]); + currentRootNode->addChildAtIndex(i); + randomlyFillVoxelTree(levelsToGo - 1, currentRootNode->getChildAtIndex(i)); createdChildren = true; } } From af6f51527af29fb9db041104ce2c63dbe600f066 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 5 May 2013 10:34:09 -0700 Subject: [PATCH 02/25] short circuit shouldRender logic in treeToArrays() --- interface/src/VoxelSystem.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 258b604b0c..0f349bd0b3 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -220,12 +220,19 @@ void VoxelSystem::copyWrittenDataToReadArrays() { int VoxelSystem::newTreeToArrays(VoxelNode* node) { assert(_viewFrustum); // you must set up _viewFrustum before calling this int voxelsUpdated = 0; - float distanceToNode = node->distanceToCamera(*_viewFrustum); - float boundary = boundaryDistanceForRenderLevel(node->getLevel()); - float childBoundary = boundaryDistanceForRenderLevel(node->getLevel() + 1); - bool inBoundary = (distanceToNode <= boundary); - bool inChildBoundary = (distanceToNode <= childBoundary); - bool shouldRender = node->isColored() && ((node->isLeaf() && inChildBoundary) || (inBoundary && !inChildBoundary)); + bool shouldRender = false; // assume we don't need to render it + + // if it's colored, we might need to render it! + if (node->isColored()) { + float distanceToNode = node->distanceToCamera(*_viewFrustum); + float boundary = boundaryDistanceForRenderLevel(node->getLevel()); + float childBoundary = boundaryDistanceForRenderLevel(node->getLevel() + 1); + bool inBoundary = (distanceToNode <= boundary); + bool inChildBoundary = (distanceToNode <= childBoundary); + + shouldRender = (node->isLeaf() && inChildBoundary) || (inBoundary && !inChildBoundary); + } + node->setShouldRender(shouldRender); // let children figure out their renderness From 17e26b2d42733359e5b82b06670e05461aad87cf Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 May 2013 10:59:09 -0700 Subject: [PATCH 03/25] add matches() --- libraries/voxels/src/ViewFrustum.cpp | 13 +++++++++++++ libraries/voxels/src/ViewFrustum.h | 4 ++++ 2 files changed, 17 insertions(+) diff --git a/libraries/voxels/src/ViewFrustum.cpp b/libraries/voxels/src/ViewFrustum.cpp index 8bdb2d97cb..f967c9f69a 100644 --- a/libraries/voxels/src/ViewFrustum.cpp +++ b/libraries/voxels/src/ViewFrustum.cpp @@ -224,4 +224,17 @@ int ViewFrustum::boxInFrustum(const AABox& box) const { } return(result); } + +bool ViewFrustum::matches(const ViewFrustum& compareTo) const { + return compareTo._position == _position && + compareTo._direction == _direction && + compareTo._up == _up && + compareTo._right == _right && + compareTo._fieldOfView == _fieldOfView && + compareTo._aspectRatio == _aspectRatio && + compareTo._nearClip == _nearClip && + compareTo._farClip == _farClip; +} + + diff --git a/libraries/voxels/src/ViewFrustum.h b/libraries/voxels/src/ViewFrustum.h index d05bb9e1cf..cec380e35a 100644 --- a/libraries/voxels/src/ViewFrustum.h +++ b/libraries/voxels/src/ViewFrustum.h @@ -98,6 +98,10 @@ public: int sphereInFrustum(const glm::vec3& center, float radius) const; int boxInFrustum(const AABox& box) const; + // some frustum comparisons + bool matches(const ViewFrustum& compareTo) const; + bool matches(const ViewFrustum* compareTo) const { return matches(*compareTo); }; + }; From 16b93f8c924a88d3377c7978b96422e47849a4c9 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 May 2013 11:00:01 -0700 Subject: [PATCH 04/25] added PerformanceWarning class --- libraries/shared/src/PerfStat.cpp | 25 +++++++++++++++++++++++++ libraries/shared/src/PerfStat.h | 11 +++++++++++ 2 files changed, 36 insertions(+) diff --git a/libraries/shared/src/PerfStat.cpp b/libraries/shared/src/PerfStat.cpp index 2c3dcf93b7..85e96ea4db 100644 --- a/libraries/shared/src/PerfStat.cpp +++ b/libraries/shared/src/PerfStat.cpp @@ -103,3 +103,28 @@ int PerfStat::DumpStats(char** array) { return lineCount; } + +// Constructor handles starting the warning timer +PerformanceWarning::PerformanceWarning(bool renderWarnings, const char* message) { + _start = usecTimestampNow(); + _message = message; + _renderWarningsOn = renderWarnings; + // need to also store the args... +} + +// Destructor handles recording all of our stats +PerformanceWarning::~PerformanceWarning() { + double end = usecTimestampNow(); + double elapsedmsec = (end - _start)/1000.0; + if (_renderWarningsOn && elapsedmsec > 1) { + if (elapsedmsec > 1000) { + double elapsedsec = (end - _start)/1000000.0; + printLog("WARNING! %s took %lf seconds\n", _message, elapsedsec); + } else { + printLog("WARNING! %s took %lf milliseconds\n", _message, elapsedmsec); + } + } + +}; + + diff --git a/libraries/shared/src/PerfStat.h b/libraries/shared/src/PerfStat.h index 1ccde5c28c..f52a3ec49c 100644 --- a/libraries/shared/src/PerfStat.h +++ b/libraries/shared/src/PerfStat.h @@ -13,6 +13,7 @@ #define __hifi__PerfStat__ #include +#include "SharedUtil.h" #ifdef _WIN32 #define snprintf _snprintf @@ -81,5 +82,15 @@ public: typedef std::map >::iterator PerfStatMapItr; +class PerformanceWarning { +private: + double _start; + const char* _message; + bool _renderWarningsOn; +public: + PerformanceWarning(bool renderWarnings, const char* message); + ~PerformanceWarning(); +}; + #endif /* defined(__hifi__PerfStat__) */ From 17b137cc53656cac08662f4360fb0e597cc7231c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 May 2013 11:01:29 -0700 Subject: [PATCH 05/25] changed VoxelNodeBag to just compare pointers, since we don't really care about ordering the bag --- libraries/voxels/src/VoxelNodeBag.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/libraries/voxels/src/VoxelNodeBag.cpp b/libraries/voxels/src/VoxelNodeBag.cpp index 132405ba6e..9646c2d2fc 100644 --- a/libraries/voxels/src/VoxelNodeBag.cpp +++ b/libraries/voxels/src/VoxelNodeBag.cpp @@ -32,18 +32,12 @@ void VoxelNodeBag::insert(VoxelNode* node) { // Note: change this to binary search... instead of linear! int insertAt = _elementsInUse; for (int i = 0; i < _elementsInUse; i++) { - - // compare the newNode to the elements already in the bag - OctalCodeComparison comparison = compareOctalCodes(_bagElements[i]->getOctalCode(), node->getOctalCode()); - - // If we found a code in the bag that matches, then just return, since the element is already in the bag. - if (comparison == EXACT_MATCH) { + // just compare the pointers... that's good enough + if (_bagElements[i] == node) { return; // exit early!! - } + } - // if we found a node "greater than" the inserted node, then - // we want to insert our node here. - if (comparison == GREATER_THAN) { + if (_bagElements[i] > node) { insertAt = i; break; } From e0d040a73be6cd60b04f1e2140a9352c2e4035e8 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 May 2013 11:02:28 -0700 Subject: [PATCH 06/25] added removeChildAtIndex() which removes a node, but doesn't delete it --- libraries/voxels/src/VoxelNode.cpp | 9 +++++++++ libraries/voxels/src/VoxelNode.h | 1 + 2 files changed, 10 insertions(+) diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 30d8ea1f68..2556aa910a 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -89,6 +89,15 @@ void VoxelNode::deleteChildAtIndex(int childIndex) { } } +// does not delete the node! +VoxelNode* VoxelNode::removeChildAtIndex(int childIndex) { + VoxelNode* returnedChild = _children[childIndex]; + if (_children[childIndex]) { + _children[childIndex] = NULL; + } + return returnedChild; +} + void VoxelNode::addChildAtIndex(int childIndex) { if (!_children[childIndex]) { _children[childIndex] = new VoxelNode(childOctalCode(_octalCode, childIndex)); diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 8e3fa1b4d6..386f95e634 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -43,6 +43,7 @@ public: unsigned char* getOctalCode() const { return _octalCode; }; VoxelNode* getChildAtIndex(int i) const { return _children[i]; }; void deleteChildAtIndex(int childIndex); + VoxelNode* removeChildAtIndex(int childIndex); void addChildAtIndex(int childIndex); void setColorFromAverageOfChildren(); void setRandomColor(int minimumBrightness); From 7ba9d4aa864eae5c2ce29203b4dd213238b19a72 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 May 2013 13:32:09 -0700 Subject: [PATCH 07/25] First cut are removing out of view voxels and switch to using PerformanceWarnings --- interface/src/VoxelSystem.cpp | 137 ++++++++++++++++++---------------- interface/src/VoxelSystem.h | 9 +++ 2 files changed, 83 insertions(+), 63 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 0f349bd0b3..0b56ea2f49 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -15,6 +15,7 @@ #include // to load voxels from file #include #include +#include #include #include #include "Log.h" @@ -44,6 +45,7 @@ VoxelSystem::VoxelSystem() { _voxelsInArrays = _voxelsUpdated = 0; _tree = new VoxelTree(); pthread_mutex_init(&_bufferWriteLock, NULL); + pthread_mutex_init(&_voxelCleanupLock, NULL); } VoxelSystem::~VoxelSystem() { @@ -54,6 +56,7 @@ VoxelSystem::~VoxelSystem() { delete[] _voxelDirtyArray; delete _tree; pthread_mutex_destroy(&_bufferWriteLock); + pthread_mutex_destroy(&_voxelCleanupLock); } void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) { @@ -98,24 +101,13 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { switch(command) { case PACKET_HEADER_VOXEL_DATA: { - double start = usecTimestampNow(); + PerformanceWarning warn(_renderWarningsOn, "readBitstreamToTree()"); // ask the VoxelTree to read the bitstream into the tree _tree->readBitstreamToTree(voxelData, numBytes - 1); if (_renderWarningsOn && _tree->getNodesChangedFromBitstream()) { printLog("readBitstreamToTree()... getNodesChangedFromBitstream=%ld _tree->isDirty()=%s \n", _tree->getNodesChangedFromBitstream(), (_tree->isDirty() ? "yes" : "no") ); } - - double end = usecTimestampNow(); - double elapsedmsec = (end - start)/1000.0; - if (_renderWarningsOn && elapsedmsec > 1) { - if (elapsedmsec > 1000) { - double elapsedsec = (end - start)/1000000.0; - printLog("WARNING! readBitstreamToTree() took %lf seconds\n",elapsedsec); - } else { - printLog("WARNING! readBitstreamToTree() took %lf milliseconds\n",elapsedmsec); - } - } } break; case PACKET_HEADER_ERASE_VOXEL: @@ -153,14 +145,19 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { } void VoxelSystem::setupNewVoxelsForDrawing() { + PerformanceWarning warn(_renderWarningsOn, "copyWrittenDataToReadArrays()"); // would like to include _voxelsInArrays, _voxelsUpdated double start = usecTimestampNow(); - double sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished); if (sinceLastTime <= std::max(_setupNewVoxelsForDrawingLastElapsed,SIXTY_FPS_IN_MILLISECONDS)) { return; // bail early, it hasn't been long enough since the last time we ran } + // If the view frustum has changed, since last time, then remove nodes that are out of view + //if (hasViewChanged()) { + // removeOutOfView(); + //} + if (_tree->isDirty()) { _callsToTreesToArrays++; _voxelsUpdated = newTreeToArrays(_tree->rootNode); @@ -179,21 +176,12 @@ void VoxelSystem::setupNewVoxelsForDrawing() { double end = usecTimestampNow(); double elapsedmsec = (end - start)/1000.0; - if (_renderWarningsOn && elapsedmsec > 1) { - if (elapsedmsec > 1000) { - double elapsedsec = (end - start)/1000000.0; - printLog("WARNING! newTreeToArrays() took %lf seconds %ld voxels updated\n", elapsedsec, _voxelsUpdated); - } else { - printLog("WARNING! newTreeToArrays() took %lf milliseconds %ld voxels updated\n", elapsedmsec, _voxelsUpdated); - } - } - _setupNewVoxelsForDrawingLastFinished = end; _setupNewVoxelsForDrawingLastElapsed = elapsedmsec; } void VoxelSystem::copyWrittenDataToReadArrays() { - double start = usecTimestampNow(); + PerformanceWarning warn(_renderWarningsOn, "copyWrittenDataToReadArrays()"); // would like to include _voxelsInArrays, _voxelsUpdated if (_voxelsDirty && _voxelsUpdated) { // lock on the buffer write lock so we can't modify the data when the GPU is reading it pthread_mutex_lock(&_bufferWriteLock); @@ -203,18 +191,6 @@ void VoxelSystem::copyWrittenDataToReadArrays() { memcpy(_readColorsArray, _writeColorsArray, bytesOfColors ); pthread_mutex_unlock(&_bufferWriteLock); } - double end = usecTimestampNow(); - double elapsedmsec = (end - start)/1000.0; - if (_renderWarningsOn && elapsedmsec > 1) { - if (elapsedmsec > 1000) { - double elapsedsec = (end - start)/1000000.0; - printLog("WARNING! copyWrittenDataToReadArrays() took %lf seconds for %ld voxels %ld updated\n", - elapsedsec, _voxelsInArrays, _voxelsUpdated); - } else { - printLog("WARNING! copyWrittenDataToReadArrays() took %lf milliseconds for %ld voxels %ld updated\n", - elapsedmsec, _voxelsInArrays, _voxelsUpdated); - } - } } int VoxelSystem::newTreeToArrays(VoxelNode* node) { @@ -301,6 +277,7 @@ void VoxelSystem::init() { // When we change voxels representations in the arrays, we'll update this _voxelsDirty = false; _voxelsInArrays = 0; + _unusedArraySpace = 0; // we will track individual dirty sections with this array of bools _voxelDirtyArray = new bool[MAX_VOXELS_PER_SYSTEM]; @@ -369,7 +346,7 @@ void VoxelSystem::init() { } void VoxelSystem::updateVBOs() { - double start = usecTimestampNow(); + PerformanceWarning warn(_renderWarningsOn, "updateVBOs()"); // would like to include _callsToTreesToArrays if (_voxelsDirty) { glBufferIndex segmentStart = 0; glBufferIndex segmentEnd = 0; @@ -401,28 +378,13 @@ void VoxelSystem::updateVBOs() { } _voxelsDirty = false; } - double end = usecTimestampNow(); - double elapsedmsec = (end - start)/1000.0; - if (_renderWarningsOn && elapsedmsec > 1) { - if (elapsedmsec > 1) { - if (elapsedmsec > 1000) { - double elapsedsec = (end - start)/1000000.0; - printLog("WARNING! updateVBOs() took %lf seconds after %d calls to newTreeToArrays()\n", - elapsedsec, _callsToTreesToArrays); - } else { - printLog("WARNING! updateVBOs() took %lf milliseconds after %d calls to newTreeToArrays()\n", - elapsedmsec, _callsToTreesToArrays); - } - } else { - printLog("WARNING! updateVBOs() called after %d calls to newTreeToArrays()\n",_callsToTreesToArrays); - } - } _callsToTreesToArrays = 0; // clear it } void VoxelSystem::render() { - double start = usecTimestampNow(); + PerformanceWarning warn(_renderWarningsOn, "render()"); glPushMatrix(); + //cleanupRemovedVoxels(); updateVBOs(); // tell OpenGL where to find vertex and color information glEnableClientState(GL_VERTEX_ARRAY); @@ -454,16 +416,6 @@ void VoxelSystem::render() { // scale back down to 1 so heads aren't massive glPopMatrix(); - double end = usecTimestampNow(); - double elapsedmsec = (end - start)/1000.0; - if (_renderWarningsOn && elapsedmsec > 1) { - if (elapsedmsec > 1000) { - double elapsedsec = (end - start)/1000000.0; - printLog("WARNING! render() took %lf seconds\n",elapsedsec); - } else { - printLog("WARNING! render() took %lf milliseconds\n",elapsedmsec); - } - } } int VoxelSystem::_nodeCount = 0; @@ -591,4 +543,63 @@ void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) { setupNewVoxelsForDrawing(); } +// "Remove" voxels from the tree that are not in view. We don't actually delete them, +// we remove them from the tree and place them into a holding area for later deletion +int removedCount; +bool VoxelSystem::removeOutOfViewOperation(VoxelNode* node, void* extraData) { + VoxelSystem* thisVoxelSystem = (VoxelSystem*) extraData; + _nodeCount++; + // Need to operate on our child nodes, so we can remove them + for (int i = 0; i < 8; i++) { + VoxelNode* childNode = node->getChildAtIndex(i); + if (childNode && !childNode->isInView(*thisVoxelSystem->_viewFrustum)) { + node->removeChildAtIndex(i); + removedCount++; + + // Note: VoxelNodeBag is more expensive than we need, because it checks octal code matches, + // we really just want a simple bag that checks pointers only, consider switching + thisVoxelSystem->_removedVoxels.insert(childNode); + } + } + return true; // keep going! +} +bool VoxelSystem::hasViewChanged() { + bool result = false; // assume the best + if (_viewFrustum && !_lastKnowViewFrustum.matches(_viewFrustum)) { + result = true; + _lastKnowViewFrustum = *_viewFrustum; // save last known + } + return result; +} + +void VoxelSystem::removeOutOfView() { + PerformanceWarning warn(_renderWarningsOn, "removeOutOfView()"); // would like to include removedCount, _nodeCount, _removedVoxels.count() + pthread_mutex_lock(&_voxelCleanupLock); + _nodeCount = 0; + removedCount = 0; + _tree->recurseTreeWithOperation(removeOutOfViewOperation,(void*)this); + pthread_mutex_unlock(&_voxelCleanupLock); +} + +// Deletes the VoxelNodes from the _removedVoxels bag, but also cleans up those items from the vertex arrays +void VoxelSystem::cleanupRemovedVoxels() { + if (!pthread_mutex_trylock(&_voxelCleanupLock)) { + while (!_removedVoxels.isEmpty()){ + VoxelNode* node = _removedVoxels.extract(); + // If the voxel is in the vertex, and it was previously rendered, then set it's vertices to "hidden" + if (node->isKnownBufferIndex() && node->getShouldRender()) { + unsigned long nodeIndex = node->getBufferIndex(); + _voxelDirtyArray[nodeIndex] = true; + for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) { + GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); + *(writeVerticesAt+j) = FLT_MAX; + } + _voxelsDirty = true; // yep + } + _unusedArraySpace++; // track this so we can blow away our arrays if they get too much + delete node; // actually delete the node + } + pthread_mutex_unlock(&_voxelCleanupLock); + } +} diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index d217e8aa55..15339b0f24 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -61,9 +61,14 @@ public: void killLocalVoxels(); void setRenderPipelineWarnings(bool on) { _renderWarningsOn = on; }; bool getRenderPipelineWarnings() const { return _renderWarningsOn; }; + + void removeOutOfView(); + bool hasViewChanged(); + void cleanupRemovedVoxels(); private: int _callsToTreesToArrays; + VoxelNodeBag _removedVoxels; bool _renderWarningsOn; // Operation functions for tree recursion methods @@ -74,6 +79,7 @@ private: static bool falseColorizeInViewOperation(VoxelNode* node, void* extraData); static bool falseColorizeDistanceFromViewOperation(VoxelNode* node, void* extraData); static bool getDistanceFromViewRangeOperation(VoxelNode* node, void* extraData); + static bool removeOutOfViewOperation(VoxelNode* node, void* extraData); // these are kinda hacks, used by getDistanceFromViewRangeOperation() probably shouldn't be here static float _maxDistance; @@ -89,6 +95,7 @@ private: bool* _voxelDirtyArray; unsigned long _voxelsUpdated; unsigned long _voxelsInArrays; + unsigned long _unusedArraySpace; double _setupNewVoxelsForDrawingLastElapsed; @@ -99,8 +106,10 @@ private: GLuint _vboColorsID; GLuint _vboIndicesID; pthread_mutex_t _bufferWriteLock; + pthread_mutex_t _voxelCleanupLock; ViewFrustum* _viewFrustum; + ViewFrustum _lastKnowViewFrustum; int newTreeToArrays(VoxelNode *currentNode); void setupNewVoxelsForDrawing(); From c975699cea70116402c692790d1b177b60acf8c6 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 May 2013 15:48:05 -0700 Subject: [PATCH 08/25] added debug to ViewFrustum::matches() --- libraries/voxels/src/ViewFrustum.cpp | 36 +++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/libraries/voxels/src/ViewFrustum.cpp b/libraries/voxels/src/ViewFrustum.cpp index 695dbe4185..51b04e9640 100644 --- a/libraries/voxels/src/ViewFrustum.cpp +++ b/libraries/voxels/src/ViewFrustum.cpp @@ -226,7 +226,8 @@ int ViewFrustum::boxInFrustum(const AABox& box) const { } bool ViewFrustum::matches(const ViewFrustum& compareTo) const { - return compareTo._position == _position && + bool debug = false; + bool result = compareTo._position == _position && compareTo._direction == _direction && compareTo._up == _up && compareTo._right == _right && @@ -234,6 +235,39 @@ bool ViewFrustum::matches(const ViewFrustum& compareTo) const { compareTo._aspectRatio == _aspectRatio && compareTo._nearClip == _nearClip && compareTo._farClip == _farClip; + + if (!result && debug) { + printLog("ViewFrustum::matches()... result=%s\n", (result ? "yes" : "no")); + printLog("%s -- compareTo._position=%f,%f,%f _position=%f,%f,%f\n", + (compareTo._position == _position ? "MATCHES " : "NO MATCH"), + compareTo._position.x, compareTo._position.y, compareTo._position.z, + _position.x, _position.y, _position.z ); + printLog("%s -- compareTo._direction=%f,%f,%f _direction=%f,%f,%f\n", + (compareTo._direction == _direction ? "MATCHES " : "NO MATCH"), + compareTo._direction.x, compareTo._direction.y, compareTo._direction.z, + _direction.x, _direction.y, _direction.z ); + printLog("%s -- compareTo._up=%f,%f,%f _up=%f,%f,%f\n", + (compareTo._up == _up ? "MATCHES " : "NO MATCH"), + compareTo._up.x, compareTo._up.y, compareTo._up.z, + _up.x, _up.y, _up.z ); + printLog("%s -- compareTo._right=%f,%f,%f _right=%f,%f,%f\n", + (compareTo._right == _right ? "MATCHES " : "NO MATCH"), + compareTo._right.x, compareTo._right.y, compareTo._right.z, + _right.x, _right.y, _right.z ); + printLog("%s -- compareTo._fieldOfView=%f _fieldOfView=%f\n", + (compareTo._fieldOfView == _fieldOfView ? "MATCHES " : "NO MATCH"), + compareTo._fieldOfView, _fieldOfView); + printLog("%s -- compareTo._aspectRatio=%f _aspectRatio=%f\n", + (compareTo._aspectRatio == _aspectRatio ? "MATCHES " : "NO MATCH"), + compareTo._aspectRatio, _aspectRatio); + printLog("%s -- compareTo._nearClip=%f _nearClip=%f\n", + (compareTo._nearClip == _nearClip ? "MATCHES " : "NO MATCH"), + compareTo._nearClip, _nearClip); + printLog("%s -- compareTo._farClip=%f _farClip=%f\n", + (compareTo._farClip == _farClip ? "MATCHES " : "NO MATCH"), + compareTo._farClip, _farClip); + } + return result; } From 96561e97d88581a106913368db7bd867a9595f62 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 May 2013 15:49:54 -0700 Subject: [PATCH 09/25] added VIEW_CULLING_RATE_IN_MILLISECONDS --- libraries/voxels/src/VoxelConstants.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index f278017f23..91562a29d6 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -29,4 +29,5 @@ typedef unsigned long int glBufferIndex; const glBufferIndex GLBUFFER_INDEX_UNKNOWN = ULONG_MAX; const double SIXTY_FPS_IN_MILLISECONDS = 1000.0/60; +const double VIEW_CULLING_RATE_IN_MILLISECONDS = 1000.0; // once a second is fine #endif From 89226b18a55d5a050cd066796e36b0aa6e24b63a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 May 2013 15:50:42 -0700 Subject: [PATCH 10/25] switched getAABox() interface --- libraries/voxels/src/VoxelTree.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 3b39adcfeb..264d2c6a3a 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -558,8 +558,7 @@ public: bool findRayOperation(VoxelNode* node, void* extraData) { RayArgs* args = static_cast(extraData); - AABox box; - node->getAABox(box); + AABox box = node->getAABox(); float distance; if (!box.findRayIntersection(args->origin, args->direction, distance)) { return false; From 09923d1c97ba6db48e2b605155fedf5235842d05 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 May 2013 15:51:56 -0700 Subject: [PATCH 11/25] second cut at view culling voxels --- interface/src/VoxelSystem.cpp | 156 +++++++++++++++++++++++----------- interface/src/VoxelSystem.h | 10 ++- 2 files changed, 115 insertions(+), 51 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 0b56ea2f49..3dcaa101e9 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -42,7 +42,8 @@ GLubyte identityIndices[] = { 0,2,1, 0,3,2, // Z- . 4,5,6, 4,6,7 }; // Z+ . VoxelSystem::VoxelSystem() { - _voxelsInArrays = _voxelsUpdated = 0; + _voxelsInReadArrays = _voxelsInWriteArrays = _voxelsUpdated = 0; + _alwaysRenderFullVBO = true; _tree = new VoxelTree(); pthread_mutex_init(&_bufferWriteLock, NULL); pthread_mutex_init(&_voxelCleanupLock, NULL); @@ -61,7 +62,7 @@ VoxelSystem::~VoxelSystem() { void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) { _tree->loadVoxelsFile(fileName, wantColorRandomizer); - copyWrittenDataToReadArrays(); + setupNewVoxelsForDrawing(); } void VoxelSystem::createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer) { @@ -130,7 +131,7 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { if (0==strcmp(command,(char*)"erase all")) { printLog("got Z message == erase all\n"); _tree->eraseAllVoxels(); - _voxelsInArrays = 0; // better way to do this?? + _voxelsInReadArrays = _voxelsInWriteArrays = 0; // better way to do this?? } if (0==strcmp(command,(char*)"add scene")) { printLog("got Z message == add scene - NOT SUPPORTED ON INTERFACE\n"); @@ -145,34 +146,41 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { } void VoxelSystem::setupNewVoxelsForDrawing() { - PerformanceWarning warn(_renderWarningsOn, "copyWrittenDataToReadArrays()"); // would like to include _voxelsInArrays, _voxelsUpdated + PerformanceWarning warn(_renderWarningsOn, "setupNewVoxelsForDrawing()"); // would like to include _voxelsInArrays, _voxelsUpdated double start = usecTimestampNow(); - double sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished); + double sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000.0; if (sinceLastTime <= std::max(_setupNewVoxelsForDrawingLastElapsed,SIXTY_FPS_IN_MILLISECONDS)) { return; // bail early, it hasn't been long enough since the last time we ran } + + double sinceLastViewCulling = (start - _lastViewCulling) / 1000.0; // If the view frustum has changed, since last time, then remove nodes that are out of view - //if (hasViewChanged()) { - // removeOutOfView(); - //} + if ((sinceLastViewCulling >= VIEW_CULLING_RATE_IN_MILLISECONDS) && hasViewChanged()) { + _lastViewCulling = start; + removeOutOfView(); + } if (_tree->isDirty()) { + PerformanceWarning warn(_renderWarningsOn, "calling... newTreeToArrays()"); _callsToTreesToArrays++; + + if (_alwaysRenderFullVBO) { + _voxelsInWriteArrays = 0; // reset our VBO + } _voxelsUpdated = newTreeToArrays(_tree->rootNode); _tree->clearDirtyBit(); // after we pull the trees into the array, we can consider the tree clean } else { _voxelsUpdated = 0; } + //printLog("setupNewVoxelsForDrawing() AFTER treeToArray _voxelsUpdated=%ld _voxelsDirty=%s\n", _voxelsUpdated, (_voxelsDirty ? "yes" : "no")); if (_voxelsUpdated) { _voxelsDirty=true; } - if (_voxelsDirty) { - // copy the newly written data to the arrays designated for reading - copyWrittenDataToReadArrays(); - } + // copy the newly written data to the arrays designated for reading, only does something if _voxelsDirty && _voxelsUpdated + copyWrittenDataToReadArrays(); double end = usecTimestampNow(); double elapsedmsec = (end - start)/1000.0; @@ -185,16 +193,18 @@ void VoxelSystem::copyWrittenDataToReadArrays() { if (_voxelsDirty && _voxelsUpdated) { // lock on the buffer write lock so we can't modify the data when the GPU is reading it pthread_mutex_lock(&_bufferWriteLock); - int bytesOfVertices = (_voxelsInArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLfloat); - int bytesOfColors = (_voxelsInArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLubyte); + int bytesOfVertices = (_voxelsInWriteArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLfloat); + int bytesOfColors = (_voxelsInWriteArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLubyte); memcpy(_readVerticesArray, _writeVerticesArray, bytesOfVertices); memcpy(_readColorsArray, _writeColorsArray, bytesOfColors ); + _voxelsInReadArrays = _voxelsInWriteArrays; pthread_mutex_unlock(&_bufferWriteLock); } } int VoxelSystem::newTreeToArrays(VoxelNode* node) { assert(_viewFrustum); // you must set up _viewFrustum before calling this + int voxelsUpdated = 0; bool shouldRender = false; // assume we don't need to render it @@ -217,9 +227,39 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) { voxelsUpdated += newTreeToArrays(node->getChildAtIndex(i)); } } - + + if (_alwaysRenderFullVBO) { + voxelsUpdated += newway__updateNodeInArray(node); + } else { + voxelsUpdated += oldway__updateNodeInArray(node); + } + node->clearDirtyBit(); // always clear the dirty bit, even if it doesn't need to be rendered + return voxelsUpdated; +} + +int VoxelSystem::newway__updateNodeInArray(VoxelNode* node) { + if (node->getShouldRender()) { + glm::vec3 startVertex = node->getCorner(); + float voxelScale = node->getScale(); + glBufferIndex nodeIndex = _voxelsInWriteArrays; + + // populate the array with points for the 8 vertices + // and RGB color for each added vertex + for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) { + GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); + GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); + *(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale); + *(writeColorsAt +j) = node->getColor()[j % 3]; + } + _voxelsInWriteArrays++; // our know vertices in the arrays + return 1; // rendered + } + return 0; // not-rendered +} + +int VoxelSystem::oldway__updateNodeInArray(VoxelNode* node) { // Now, if we've changed any attributes (our renderness, our color, etc) then update the Arrays... for us - if (node->isDirty() && (shouldRender || node->isKnownBufferIndex())) { + if (node->isDirty() && (node->getShouldRender() || node->isKnownBufferIndex())) { glm::vec3 startVertex; float voxelScale = 0; @@ -239,7 +279,7 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) { if (node->isKnownBufferIndex()) { nodeIndex = node->getBufferIndex(); } else { - nodeIndex = _voxelsInArrays; + nodeIndex = _voxelsInWriteArrays; } _voxelDirtyArray[nodeIndex] = true; @@ -254,12 +294,11 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) { } if (!node->isKnownBufferIndex()) { node->setBufferIndex(nodeIndex); - _voxelsInArrays++; // our know vertices in the arrays + _voxelsInWriteArrays++; // our know vertices in the arrays } - voxelsUpdated++; + return 1; // updated! } - node->clearDirtyBit(); // always clear the dirty bit, even if it doesn't need to be rendered - return voxelsUpdated; + return 0; // not-updated } VoxelSystem* VoxelSystem::clone() const { @@ -273,10 +312,12 @@ void VoxelSystem::init() { _callsToTreesToArrays = 0; _setupNewVoxelsForDrawingLastFinished = 0; _setupNewVoxelsForDrawingLastElapsed = 0; + _lastViewCulling = 0; // When we change voxels representations in the arrays, we'll update this _voxelsDirty = false; - _voxelsInArrays = 0; + _voxelsInWriteArrays = 0; + _voxelsInReadArrays = 0; _unusedArraySpace = 0; // we will track individual dirty sections with this array of bools @@ -348,31 +389,48 @@ void VoxelSystem::init() { void VoxelSystem::updateVBOs() { PerformanceWarning warn(_renderWarningsOn, "updateVBOs()"); // would like to include _callsToTreesToArrays if (_voxelsDirty) { - glBufferIndex segmentStart = 0; - glBufferIndex segmentEnd = 0; - bool inSegment = false; - for (glBufferIndex i = 0; i < _voxelsInArrays; i++) { - if (!inSegment) { - if (_voxelDirtyArray[i]) { - segmentStart = i; - inSegment = true; - _voxelDirtyArray[i] = false; // consider us clean! - } - } else { - if (!_voxelDirtyArray[i] || (i == (_voxelsInArrays - 1)) ) { - segmentEnd = i; - inSegment = false; - int segmentLength = (segmentEnd - segmentStart) + 1; - GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); - glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); - segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); - glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); + if (_alwaysRenderFullVBO) { + glBufferIndex segmentStart = 0; + glBufferIndex segmentEnd = _voxelsInWriteArrays; + + int segmentLength = (segmentEnd - segmentStart) + 1; + GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); + GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); + GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); + glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); + segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); + segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); + GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); + glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); + } else { + glBufferIndex segmentStart = 0; + glBufferIndex segmentEnd = 0; + bool inSegment = false; + for (glBufferIndex i = 0; i < _voxelsInWriteArrays; i++) { + if (!inSegment) { + if (_voxelDirtyArray[i]) { + segmentStart = i; + inSegment = true; + _voxelDirtyArray[i] = false; // consider us clean! + } + } else { + if (!_voxelDirtyArray[i] || (i == (_voxelsInWriteArrays - 1)) ) { + segmentEnd = i; + inSegment = false; + int segmentLength = (segmentEnd - segmentStart) + 1; + GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); + GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); + GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); + glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); + segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); + segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); + GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); + glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); + } } } } @@ -403,7 +461,7 @@ void VoxelSystem::render() { // draw the number of voxels we have glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID); glScalef(TREE_SCALE, TREE_SCALE, TREE_SCALE); - glDrawElements(GL_TRIANGLES, 36 * _voxelsInArrays, GL_UNSIGNED_INT, 0); + glDrawElements(GL_TRIANGLES, 36 * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); // deactivate vertex and color arrays after drawing glDisableClientState(GL_VERTEX_ARRAY); @@ -422,7 +480,7 @@ int VoxelSystem::_nodeCount = 0; void VoxelSystem::killLocalVoxels() { _tree->eraseAllVoxels(); - _voxelsInArrays = 0; // better way to do this?? + _voxelsInWriteArrays = _voxelsInReadArrays = 0; // better way to do this?? //setupNewVoxelsForDrawing(); } diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 15339b0f24..81330dbdab 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -37,7 +37,7 @@ public: void render(); unsigned long getVoxelsUpdated() const {return _voxelsUpdated;}; - unsigned long getVoxelsRendered() const {return _voxelsInArrays;}; + unsigned long getVoxelsRendered() const {return _voxelsInReadArrays;}; void setViewerAvatar(Avatar *newViewerAvatar) { _viewerAvatar = newViewerAvatar; }; void setCamera(Camera* newCamera) { _camera = newCamera; }; @@ -81,6 +81,9 @@ private: static bool getDistanceFromViewRangeOperation(VoxelNode* node, void* extraData); static bool removeOutOfViewOperation(VoxelNode* node, void* extraData); + int newway__updateNodeInArray(VoxelNode* node); + int oldway__updateNodeInArray(VoxelNode* node); + // these are kinda hacks, used by getDistanceFromViewRangeOperation() probably shouldn't be here static float _maxDistance; static float _minDistance; @@ -94,12 +97,15 @@ private: GLubyte* _writeColorsArray; bool* _voxelDirtyArray; unsigned long _voxelsUpdated; - unsigned long _voxelsInArrays; + unsigned long _voxelsInWriteArrays; + unsigned long _voxelsInReadArrays; unsigned long _unusedArraySpace; + bool _alwaysRenderFullVBO; double _setupNewVoxelsForDrawingLastElapsed; double _setupNewVoxelsForDrawingLastFinished; + double _lastViewCulling; GLuint _vboVerticesID; GLuint _vboNormalsID; From dc481002ec5065f0723f49ab1d452fde36e62387 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 May 2013 16:00:43 -0700 Subject: [PATCH 12/25] fixed Xcode compiler warnings --- libraries/voxels/src/AABox.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/voxels/src/AABox.cpp b/libraries/voxels/src/AABox.cpp index 9f86b3a7dd..8c3d3f2a77 100755 --- a/libraries/voxels/src/AABox.cpp +++ b/libraries/voxels/src/AABox.cpp @@ -103,15 +103,15 @@ 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 && + 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) || - findIntersection(origin.y, direction.y, _corner.y, _size.y, axisDistance) && axisDistance >= 0 && + isWithin(origin.z + axisDistance*direction.z, _corner.z, _size.z)) || + (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) || - findIntersection(origin.z, direction.z, _corner.z, _size.z, axisDistance) && axisDistance >= 0 && + isWithin(origin.z + axisDistance*direction.z, _corner.z, _size.z)) || + (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)) { + isWithin(origin.x + axisDistance*direction.x, _corner.x, _size.x))) { distance = axisDistance; return true; } From 4b0cde0b0d7ab62f1ca24a611bc0b859cf493f4a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 May 2013 16:09:04 -0700 Subject: [PATCH 13/25] bump up voxel send rate, since client can now handle it --- voxel-server/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 366b81ad6d..7e39eb5483 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -38,7 +38,7 @@ const float DEATH_STAR_RADIUS = 4.0; const float MAX_CUBE = 0.05f; const int VOXEL_SEND_INTERVAL_USECS = 100 * 1000; -int PACKETS_PER_CLIENT_PER_INTERVAL = 20; +int PACKETS_PER_CLIENT_PER_INTERVAL = 50; const int MAX_VOXEL_TREE_DEPTH_LEVELS = 4; From 68d58650a542ee07b9b3f8ffe7af5e4d097c6fb3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 May 2013 16:09:21 -0700 Subject: [PATCH 14/25] removed some debug code --- interface/src/VoxelSystem.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 3dcaa101e9..0548a70f4c 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -105,10 +105,6 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { PerformanceWarning warn(_renderWarningsOn, "readBitstreamToTree()"); // ask the VoxelTree to read the bitstream into the tree _tree->readBitstreamToTree(voxelData, numBytes - 1); - if (_renderWarningsOn && _tree->getNodesChangedFromBitstream()) { - printLog("readBitstreamToTree()... getNodesChangedFromBitstream=%ld _tree->isDirty()=%s \n", - _tree->getNodesChangedFromBitstream(), (_tree->isDirty() ? "yes" : "no") ); - } } break; case PACKET_HEADER_ERASE_VOXEL: From b69c1a3474f6973820d753dd48118fd88b44e563 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 May 2013 16:14:10 -0700 Subject: [PATCH 15/25] some cleanup pre CR --- interface/src/VoxelSystem.cpp | 30 ------------------------------ interface/src/VoxelSystem.h | 1 - 2 files changed, 31 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 0548a70f4c..78698dbdf3 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -170,7 +170,6 @@ void VoxelSystem::setupNewVoxelsForDrawing() { } else { _voxelsUpdated = 0; } - //printLog("setupNewVoxelsForDrawing() AFTER treeToArray _voxelsUpdated=%ld _voxelsDirty=%s\n", _voxelsUpdated, (_voxelsDirty ? "yes" : "no")); if (_voxelsUpdated) { _voxelsDirty=true; } @@ -200,10 +199,8 @@ void VoxelSystem::copyWrittenDataToReadArrays() { int VoxelSystem::newTreeToArrays(VoxelNode* node) { assert(_viewFrustum); // you must set up _viewFrustum before calling this - int voxelsUpdated = 0; bool shouldRender = false; // assume we don't need to render it - // if it's colored, we might need to render it! if (node->isColored()) { float distanceToNode = node->distanceToCamera(*_viewFrustum); @@ -211,11 +208,8 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) { float childBoundary = boundaryDistanceForRenderLevel(node->getLevel() + 1); bool inBoundary = (distanceToNode <= boundary); bool inChildBoundary = (distanceToNode <= childBoundary); - shouldRender = (node->isLeaf() && inChildBoundary) || (inBoundary && !inChildBoundary); } - - node->setShouldRender(shouldRender); // let children figure out their renderness for (int i = 0; i < 8; i++) { @@ -223,7 +217,6 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) { voxelsUpdated += newTreeToArrays(node->getChildAtIndex(i)); } } - if (_alwaysRenderFullVBO) { voxelsUpdated += newway__updateNodeInArray(node); } else { @@ -438,7 +431,6 @@ void VoxelSystem::updateVBOs() { void VoxelSystem::render() { PerformanceWarning warn(_renderWarningsOn, "render()"); glPushMatrix(); - //cleanupRemovedVoxels(); updateVBOs(); // tell OpenGL where to find vertex and color information glEnableClientState(GL_VERTEX_ARRAY); @@ -635,25 +627,3 @@ void VoxelSystem::removeOutOfView() { _tree->recurseTreeWithOperation(removeOutOfViewOperation,(void*)this); pthread_mutex_unlock(&_voxelCleanupLock); } - -// Deletes the VoxelNodes from the _removedVoxels bag, but also cleans up those items from the vertex arrays -void VoxelSystem::cleanupRemovedVoxels() { - if (!pthread_mutex_trylock(&_voxelCleanupLock)) { - while (!_removedVoxels.isEmpty()){ - VoxelNode* node = _removedVoxels.extract(); - // If the voxel is in the vertex, and it was previously rendered, then set it's vertices to "hidden" - if (node->isKnownBufferIndex() && node->getShouldRender()) { - unsigned long nodeIndex = node->getBufferIndex(); - _voxelDirtyArray[nodeIndex] = true; - for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) { - GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); - *(writeVerticesAt+j) = FLT_MAX; - } - _voxelsDirty = true; // yep - } - _unusedArraySpace++; // track this so we can blow away our arrays if they get too much - delete node; // actually delete the node - } - pthread_mutex_unlock(&_voxelCleanupLock); - } -} diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 81330dbdab..1cc7580efb 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -64,7 +64,6 @@ public: void removeOutOfView(); bool hasViewChanged(); - void cleanupRemovedVoxels(); private: int _callsToTreesToArrays; From 94529d54e85736ecd566db010b06d07d92521716 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 May 2013 16:16:21 -0700 Subject: [PATCH 16/25] some cleanup pre CR --- interface/src/VoxelSystem.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 78698dbdf3..1f5ce93283 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -591,7 +591,6 @@ void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) { // "Remove" voxels from the tree that are not in view. We don't actually delete them, // we remove them from the tree and place them into a holding area for later deletion -int removedCount; bool VoxelSystem::removeOutOfViewOperation(VoxelNode* node, void* extraData) { VoxelSystem* thisVoxelSystem = (VoxelSystem*) extraData; _nodeCount++; @@ -600,10 +599,6 @@ bool VoxelSystem::removeOutOfViewOperation(VoxelNode* node, void* extraData) { VoxelNode* childNode = node->getChildAtIndex(i); if (childNode && !childNode->isInView(*thisVoxelSystem->_viewFrustum)) { node->removeChildAtIndex(i); - removedCount++; - - // Note: VoxelNodeBag is more expensive than we need, because it checks octal code matches, - // we really just want a simple bag that checks pointers only, consider switching thisVoxelSystem->_removedVoxels.insert(childNode); } } @@ -623,7 +618,6 @@ void VoxelSystem::removeOutOfView() { PerformanceWarning warn(_renderWarningsOn, "removeOutOfView()"); // would like to include removedCount, _nodeCount, _removedVoxels.count() pthread_mutex_lock(&_voxelCleanupLock); _nodeCount = 0; - removedCount = 0; _tree->recurseTreeWithOperation(removeOutOfViewOperation,(void*)this); pthread_mutex_unlock(&_voxelCleanupLock); } From 239aa1ed49692580f362c4a5f4b39630dbd18c67 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 May 2013 16:18:30 -0700 Subject: [PATCH 17/25] some cleanup pre CR --- libraries/shared/src/PerfStat.cpp | 8 -------- libraries/shared/src/PerfStat.h | 6 +++++- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/libraries/shared/src/PerfStat.cpp b/libraries/shared/src/PerfStat.cpp index 85e96ea4db..5f48813c3b 100644 --- a/libraries/shared/src/PerfStat.cpp +++ b/libraries/shared/src/PerfStat.cpp @@ -104,14 +104,6 @@ int PerfStat::DumpStats(char** array) { } -// Constructor handles starting the warning timer -PerformanceWarning::PerformanceWarning(bool renderWarnings, const char* message) { - _start = usecTimestampNow(); - _message = message; - _renderWarningsOn = renderWarnings; - // need to also store the args... -} - // Destructor handles recording all of our stats PerformanceWarning::~PerformanceWarning() { double end = usecTimestampNow(); diff --git a/libraries/shared/src/PerfStat.h b/libraries/shared/src/PerfStat.h index f52a3ec49c..09d351a11b 100644 --- a/libraries/shared/src/PerfStat.h +++ b/libraries/shared/src/PerfStat.h @@ -88,7 +88,11 @@ private: const char* _message; bool _renderWarningsOn; public: - PerformanceWarning(bool renderWarnings, const char* message); + PerformanceWarning(bool renderWarnings, const char* message) : + _start(usecTimestampNow()), + _message(message), + _renderWarningsOn(renderWarnings) { }; + ~PerformanceWarning(); }; From 9fb57feb3b68b53dc6c34cf7e5c1bc8a4815c4d9 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 May 2013 16:21:58 -0700 Subject: [PATCH 18/25] some cleanup pre CR --- libraries/voxels/src/VoxelNode.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 2556aa910a..7f6d422fff 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -116,7 +116,7 @@ void VoxelNode::addChildAtIndex(int childIndex) { void VoxelNode::setColorFromAverageOfChildren() { int colorArray[4] = {0,0,0,0}; for (int i = 0; i < 8; i++) { - if (_children[i] != NULL && _children[i]->isColored()) { + if (_children[i] && _children[i]->isColored()) { for (int j = 0; j < 3; j++) { colorArray[j] += _children[i]->getTrueColor()[j]; // color averaging should always be based on true colors } @@ -196,7 +196,7 @@ bool VoxelNode::collapseIdenticalLeaves() { int red,green,blue; for (int i = 0; i < 8; i++) { // if no child, or child doesn't have a color - if (_children[i] == NULL || !_children[i]->isColored()) { + if (!_children[i] || !_children[i]->isColored()) { allChildrenMatch=false; //printLog("SADNESS child missing or not colored! i=%d\n",i); break; From f5808f43b57033dbf8d61e0bfcb05726e17c02ef Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 May 2013 16:24:09 -0700 Subject: [PATCH 19/25] some cleanup pre CR --- interface/src/VoxelSystem.cpp | 4 ++-- libraries/voxels/src/VoxelNode.cpp | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 1f5ce93283..1679526b82 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -212,7 +212,7 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) { } node->setShouldRender(shouldRender); // let children figure out their renderness - for (int i = 0; i < 8; i++) { + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { if (node->getChildAtIndex(i)) { voxelsUpdated += newTreeToArrays(node->getChildAtIndex(i)); } @@ -595,7 +595,7 @@ bool VoxelSystem::removeOutOfViewOperation(VoxelNode* node, void* extraData) { VoxelSystem* thisVoxelSystem = (VoxelSystem*) extraData; _nodeCount++; // Need to operate on our child nodes, so we can remove them - for (int i = 0; i < 8; i++) { + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { VoxelNode* childNode = node->getChildAtIndex(i); if (childNode && !childNode->isInView(*thisVoxelSystem->_viewFrustum)) { node->removeChildAtIndex(i); diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 7f6d422fff..95e71b2b76 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -37,7 +37,7 @@ void VoxelNode::init(unsigned char * octalCode) { #endif // default pointers to child nodes to NULL - for (int i = 0; i < 8; i++) { + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { _children[i] = NULL; } @@ -52,7 +52,7 @@ VoxelNode::~VoxelNode() { delete[] _octalCode; // delete all of this node's children - for (int i = 0; i < 8; i++) { + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { if (_children[i]) { delete _children[i]; } @@ -115,7 +115,7 @@ void VoxelNode::addChildAtIndex(int childIndex) { // will average the child colors... void VoxelNode::setColorFromAverageOfChildren() { int colorArray[4] = {0,0,0,0}; - for (int i = 0; i < 8; i++) { + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { if (_children[i] && _children[i]->isColored()) { for (int j = 0; j < 3; j++) { colorArray[j] += _children[i]->getTrueColor()[j]; // color averaging should always be based on true colors @@ -194,7 +194,7 @@ bool VoxelNode::collapseIdenticalLeaves() { // scan children, verify that they are ALL present and accounted for bool allChildrenMatch = true; // assume the best (ottimista) int red,green,blue; - for (int i = 0; i < 8; i++) { + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { // if no child, or child doesn't have a color if (!_children[i] || !_children[i]->isColored()) { allChildrenMatch=false; @@ -216,7 +216,7 @@ bool VoxelNode::collapseIdenticalLeaves() { if (allChildrenMatch) { //printLog("allChildrenMatch: pruning tree\n"); - for (int i = 0; i < 8; i++) { + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { delete _children[i]; // delete all the child nodes _children[i]=NULL; // set it to NULL } @@ -241,7 +241,7 @@ void VoxelNode::setRandomColor(int minimumBrightness) { } bool VoxelNode::isLeaf() const { - for (int i = 0; i < 8; i++) { + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { if (_children[i]) { return false; } From 37b165c8e94ad2d90d6ba1b809eb1832cb312c48 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 May 2013 16:30:34 -0700 Subject: [PATCH 20/25] some cleanup pre CR --- libraries/voxels/src/VoxelTree.cpp | 42 ++++++++++++++---------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 264d2c6a3a..2cfe5e7be8 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -43,7 +43,7 @@ VoxelTree::VoxelTree() : VoxelTree::~VoxelTree() { // delete the children of the root node // this recursively deletes the tree - for (int i = 0; i < 8; i++) { + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { delete rootNode->getChildAtIndex(i); } } @@ -57,7 +57,7 @@ void VoxelTree::recurseTreeWithOperation(RecurseVoxelTreeOperation operation, vo // Recurses voxel node with an operation function void VoxelTree::recurseNodeWithOperation(VoxelNode* node,RecurseVoxelTreeOperation operation, void* extraData) { if (operation(node, extraData)) { - for (int i = 0; i < 8; i++) { + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { VoxelNode* child = node->getChildAtIndex(i); if (child) { recurseNodeWithOperation(child, operation, extraData); @@ -115,7 +115,7 @@ VoxelNode* VoxelTree::createMissingNode(VoxelNode* lastParentNode, unsigned char // BHG Notes: We appear to call this function for every Voxel Node getting created. // This is recursive in nature. So, for example, if we are given an octal code for -// a 1/256th size voxel, we appear to call this function 8 times. Maybe?? +// a 1/256th size voxel, we appear to call this function NUMBER_OF_CHILDREN times. Maybe?? int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData, int bytesLeftToRead) { @@ -161,7 +161,7 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, int childIndex = 0; bytesRead++; - while (bytesLeftToRead - bytesRead > 0 && childIndex < 8) { + while (bytesLeftToRead - bytesRead > 0 && childIndex < NUMBER_OF_CHILDREN) { // check the exists mask to see if we have a child to traverse into if (oneAtBit(childMask, childIndex)) { @@ -313,7 +313,7 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { int colorMask = 0; // create the color mask - for (int i = 0; i < 8; i++) { + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { if (startNode->getChildAtIndex(i) && startNode->getChildAtIndex(i)->isColored()) { colorMask += (1 << (7 - i)); } @@ -323,7 +323,7 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { outputBits(colorMask); // output the colors we have - for (int j = 0; j < 8; j++) { + for (int j = 0; j < NUMBER_OF_CHILDREN; j++) { if (startNode->getChildAtIndex(j) && startNode->getChildAtIndex(j)->isColored()) { printLog("color %d : ",j); for (int c = 0; c < 3; c++) { @@ -335,7 +335,7 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { unsigned char childMask = 0; - for (int k = 0; k < 8; k++) { + for (int k = 0; k < NUMBER_OF_CHILDREN; k++) { if (startNode->getChildAtIndex(k)) { childMask += (1 << (7 - k)); } @@ -347,7 +347,7 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { if (childMask > 0) { // ask children to recursively output their trees // if they aren't a leaf - for (int l = 0; l < 8; l++) { + for (int l = 0; l < NUMBER_OF_CHILDREN; l++) { if (startNode->getChildAtIndex(l)) { printTreeForDebugging(startNode->getChildAtIndex(l)); } @@ -358,7 +358,7 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { void VoxelTree::reaverageVoxelColors(VoxelNode *startNode) { bool hasChildren = false; - for (int i = 0; i < 8; i++) { + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { if (startNode->getChildAtIndex(i)) { reaverageVoxelColors(startNode->getChildAtIndex(i)); hasChildren = true; @@ -390,7 +390,7 @@ void VoxelTree::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) { file.get(octets); //printLog("octets=%d...\n",octets); totalBytesRead++; - lengthInBytes = bytesRequiredForCodeLength(octets)-1; //(octets*3/8)+1; + lengthInBytes = bytesRequiredForCodeLength(octets)-1; unsigned char * voxelData = new unsigned char[lengthInBytes+1+3]; voxelData[0]=octets; char byte; @@ -603,17 +603,16 @@ int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSe int thisLevel = currentSearchLevel; int maxChildLevel = thisLevel; - const int MAX_CHILDREN = 8; - VoxelNode* inViewChildren[MAX_CHILDREN]; - float distancesToChildren[MAX_CHILDREN]; - int positionOfChildren[MAX_CHILDREN]; + VoxelNode* inViewChildren[NUMBER_OF_CHILDREN]; + float distancesToChildren[NUMBER_OF_CHILDREN]; + int positionOfChildren[NUMBER_OF_CHILDREN]; int inViewCount = 0; int inViewNotLeafCount = 0; int inViewWithColorCount = 0; // for each child node, check to see if they exist, are colored, and in view, and if so // add them to our distance ordered array of children - for (int i = 0; i < MAX_CHILDREN; i++) { + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { VoxelNode* childNode = node->getChildAtIndex(i); bool childIsColored = (childNode && childNode->isColored()); bool childIsInView = (childNode && childNode->isInView(viewFrustum)); @@ -636,7 +635,7 @@ int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSe if (distance < boundaryDistanceForRenderLevel(*childNode->getOctalCode() + 1)) { inViewCount = insertIntoSortedArrays((void*)childNode, distance, i, (void**)&inViewChildren, (float*)&distancesToChildren, - (int*)&positionOfChildren, inViewCount, MAX_CHILDREN); + (int*)&positionOfChildren, inViewCount, NUMBER_OF_CHILDREN); } } } @@ -739,14 +738,13 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco bool keepDiggingDeeper = true; // Assuming we're in view we have a great work ethic, we're always ready for more! // At any given point in writing the bitstream, the largest minimum we might need to flesh out the current level - // is 1 byte for child colors + 3*8 bytes for the actual colors + 1 byte for child trees. There could be sub trees + // is 1 byte for child colors + 3*NUMBER_OF_CHILDREN bytes for the actual colors + 1 byte for child trees. There could be sub trees // below this point, which might take many more bytes, but that's ok, because we can always mark our subtrees as // not existing and stop the packet at this point, then start up with a new packet for the remaining sub trees. const int CHILD_COLOR_MASK_BYTES = 1; - const int MAX_CHILDREN = 8; const int BYTES_PER_COLOR = 3; const int CHILD_TREE_EXISTS_BYTES = 1; - const int MAX_LEVEL_BYTES = CHILD_COLOR_MASK_BYTES + MAX_CHILDREN * BYTES_PER_COLOR + CHILD_TREE_EXISTS_BYTES; + const int MAX_LEVEL_BYTES = CHILD_COLOR_MASK_BYTES + NUMBER_OF_CHILDREN * BYTES_PER_COLOR + CHILD_TREE_EXISTS_BYTES; // Make our local buffer large enough to handle writing at this level in case we need to. unsigned char thisLevelBuffer[MAX_LEVEL_BYTES]; @@ -760,7 +758,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco // for each child node, check to see if they exist, are colored, and in view, and if so // add them to our distance ordered array of children - for (int i = 0; i < MAX_CHILDREN; i++) { + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { VoxelNode* childNode = node->getChildAtIndex(i); bool childIsInView = (childNode && (!viewFrustum || childNode->isInView(*viewFrustum))); if (childIsInView) { @@ -792,7 +790,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco bytesAtThisLevel += sizeof(childrenColoredBits); // keep track of byte count // write the color data... - for (int i = 0; i < MAX_CHILDREN; i++) { + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { if (oneAtBit(childrenColoredBits, i)) { memcpy(writeToThisLevelBuffer, &node->getChildAtIndex(i)->getColor(), BYTES_PER_COLOR); writeToThisLevelBuffer += BYTES_PER_COLOR; // move the pointer for color @@ -832,7 +830,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco // we know the last thing we wrote to the outputBuffer was our childrenExistBits. Let's remember where that was! unsigned char* childExistsPlaceHolder = outputBuffer-sizeof(childrenExistBits); - for (int i = 0; i < MAX_CHILDREN; i++) { + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { if (oneAtBit(childrenExistBits, i)) { VoxelNode* childNode = node->getChildAtIndex(i); From cfbcc4418fbd92df97773cb58760db7f6fa50f44 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 May 2013 16:34:34 -0700 Subject: [PATCH 21/25] some cleanup pre CR --- libraries/voxels/src/VoxelTree.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 2cfe5e7be8..d1f4b6523a 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -113,9 +113,6 @@ VoxelNode* VoxelTree::createMissingNode(VoxelNode* lastParentNode, unsigned char } } -// BHG Notes: We appear to call this function for every Voxel Node getting created. -// This is recursive in nature. So, for example, if we are given an octal code for -// a 1/256th size voxel, we appear to call this function NUMBER_OF_CHILDREN times. Maybe?? int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData, int bytesLeftToRead) { From 84da97638358b0a8ad31fecc27ac336a547cab87 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 May 2013 16:38:24 -0700 Subject: [PATCH 22/25] removed _voxelCleanupLock --- interface/src/VoxelSystem.cpp | 4 ---- interface/src/VoxelSystem.h | 1 - 2 files changed, 5 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 1679526b82..7ed31ec7cc 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -46,7 +46,6 @@ VoxelSystem::VoxelSystem() { _alwaysRenderFullVBO = true; _tree = new VoxelTree(); pthread_mutex_init(&_bufferWriteLock, NULL); - pthread_mutex_init(&_voxelCleanupLock, NULL); } VoxelSystem::~VoxelSystem() { @@ -57,7 +56,6 @@ VoxelSystem::~VoxelSystem() { delete[] _voxelDirtyArray; delete _tree; pthread_mutex_destroy(&_bufferWriteLock); - pthread_mutex_destroy(&_voxelCleanupLock); } void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) { @@ -616,8 +614,6 @@ bool VoxelSystem::hasViewChanged() { void VoxelSystem::removeOutOfView() { PerformanceWarning warn(_renderWarningsOn, "removeOutOfView()"); // would like to include removedCount, _nodeCount, _removedVoxels.count() - pthread_mutex_lock(&_voxelCleanupLock); _nodeCount = 0; _tree->recurseTreeWithOperation(removeOutOfViewOperation,(void*)this); - pthread_mutex_unlock(&_voxelCleanupLock); } diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 1cc7580efb..97d5fa1518 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -111,7 +111,6 @@ private: GLuint _vboColorsID; GLuint _vboIndicesID; pthread_mutex_t _bufferWriteLock; - pthread_mutex_t _voxelCleanupLock; ViewFrustum* _viewFrustum; ViewFrustum _lastKnowViewFrustum; From c2588e01208d5f4f7ee9fdba279978d1e3e58a54 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 May 2013 16:42:12 -0700 Subject: [PATCH 23/25] fixed CR issue --- libraries/shared/src/PerfStat.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/PerfStat.cpp b/libraries/shared/src/PerfStat.cpp index 5f48813c3b..5b4d1cc591 100644 --- a/libraries/shared/src/PerfStat.cpp +++ b/libraries/shared/src/PerfStat.cpp @@ -107,10 +107,10 @@ int PerfStat::DumpStats(char** array) { // Destructor handles recording all of our stats PerformanceWarning::~PerformanceWarning() { double end = usecTimestampNow(); - double elapsedmsec = (end - _start)/1000.0; + double elapsedmsec = (end - _start) / 1000.0; if (_renderWarningsOn && elapsedmsec > 1) { if (elapsedmsec > 1000) { - double elapsedsec = (end - _start)/1000000.0; + double elapsedsec = (end - _start) / 1000000.0; printLog("WARNING! %s took %lf seconds\n", _message, elapsedsec); } else { printLog("WARNING! %s took %lf milliseconds\n", _message, elapsedmsec); From 342e3e04077ce6403b82ea6e31efec6e505a3bea Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 May 2013 16:43:25 -0700 Subject: [PATCH 24/25] fixed CR issue --- libraries/voxels/src/AABox.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/voxels/src/AABox.cpp b/libraries/voxels/src/AABox.cpp index 8c3d3f2a77..d253167bc6 100755 --- a/libraries/voxels/src/AABox.cpp +++ b/libraries/voxels/src/AABox.cpp @@ -14,9 +14,9 @@ void AABox::scale(float scale) { - _corner = _corner*scale; - _size = _size*scale; - _center = _center*scale; + _corner = _corner * scale; + _size = _size * scale; + _center = _center * scale; } From bccad01e0ec5be1e4d8b92a09ff5b79d1013d0dc Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 May 2013 16:47:31 -0700 Subject: [PATCH 25/25] fixed CR issue --- libraries/voxels/src/VoxelTree.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index d1f4b6523a..8f1f072fe5 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -387,8 +387,8 @@ void VoxelTree::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) { file.get(octets); //printLog("octets=%d...\n",octets); totalBytesRead++; - lengthInBytes = bytesRequiredForCodeLength(octets)-1; - unsigned char * voxelData = new unsigned char[lengthInBytes+1+3]; + lengthInBytes = bytesRequiredForCodeLength(octets) - 1; + unsigned char * voxelData = new unsigned char[lengthInBytes + 1 + 3]; voxelData[0]=octets; char byte;