From c9b0edf34507e930ed0cc6330cf98a0ef9863940 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 15 Oct 2013 11:29:04 -0700 Subject: [PATCH 01/22] first cut at reducing memory footprint of AABox --- libraries/shared/src/PerfStat.cpp | 7 +- libraries/shared/src/PerfStat.h | 6 +- .../src/VoxelSendThread.cpp | 9 +- libraries/voxels/src/AABox.cpp | 126 ++++++++---------- libraries/voxels/src/AABox.h | 13 +- libraries/voxels/src/ViewFrustum.cpp | 20 ++- libraries/voxels/src/ViewFrustum.h | 5 + libraries/voxels/src/VoxelNode.cpp | 20 ++- libraries/voxels/src/VoxelNode.h | 2 +- 9 files changed, 107 insertions(+), 101 deletions(-) diff --git a/libraries/shared/src/PerfStat.cpp b/libraries/shared/src/PerfStat.cpp index 31f4b1a30b..961e24744f 100644 --- a/libraries/shared/src/PerfStat.cpp +++ b/libraries/shared/src/PerfStat.cpp @@ -108,7 +108,8 @@ bool PerformanceWarning::_suppressShortTimings = false; // Destructor handles recording all of our stats PerformanceWarning::~PerformanceWarning() { uint64_t end = usecTimestampNow(); - double elapsedmsec = (end - _start) / 1000.0; + uint64_t elapsedusec = (end - _start); + double elapsedmsec = elapsedusec / 1000.0; if ((_alwaysDisplay || _renderWarningsOn) && elapsedmsec > 1) { if (elapsedmsec > 1000) { double elapsedsec = (end - _start) / 1000000.0; @@ -127,6 +128,10 @@ PerformanceWarning::~PerformanceWarning() { } else if (_alwaysDisplay) { qDebug("%s took %lf milliseconds\n", _message, elapsedmsec); } + // if the caller gave us a pointer to store the running total, track it now. + if (_runningTotal) { + *_runningTotal += elapsedusec; + } }; diff --git a/libraries/shared/src/PerfStat.h b/libraries/shared/src/PerfStat.h index 2c5924e5ce..3343c9fd62 100644 --- a/libraries/shared/src/PerfStat.h +++ b/libraries/shared/src/PerfStat.h @@ -89,13 +89,15 @@ private: const char* _message; bool _renderWarningsOn; bool _alwaysDisplay; + uint64_t* _runningTotal; static bool _suppressShortTimings; public: - PerformanceWarning(bool renderWarnings, const char* message, bool alwaysDisplay = false) : + PerformanceWarning(bool renderWarnings, const char* message, bool alwaysDisplay = false, uint64_t* runningTotal = NULL) : _start(usecTimestampNow()), _message(message), _renderWarningsOn(renderWarnings), - _alwaysDisplay(alwaysDisplay) { } + _alwaysDisplay(alwaysDisplay), + _runningTotal(runningTotal) { } ~PerformanceWarning(); diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index ac2c56d2d3..f12577bd2f 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -52,7 +52,14 @@ bool VoxelSendThread::process() { std::cout << "Last send took too much time, not sleeping!\n"; } } - + + // some debugging... + printf("ViewFrustum::getProjectedPolygonTime=%llu ViewFrustum::getProjectedPolygonCalls=%llu\n", + ViewFrustum::getProjectedPolygonTime, ViewFrustum::getProjectedPolygonCalls); + + printf("ViewFrustum::getFurthestPointFromCameraTime=%llu ViewFrustum::getFurthestPointFromCameraCalls=%llu\n", + ViewFrustum::getFurthestPointFromCameraTime, ViewFrustum::getFurthestPointFromCameraCalls); + return isStillRunning(); // keep running till they terminate us } diff --git a/libraries/voxels/src/AABox.cpp b/libraries/voxels/src/AABox.cpp index 6a9dd68082..24f6384aee 100644 --- a/libraries/voxels/src/AABox.cpp +++ b/libraries/voxels/src/AABox.cpp @@ -13,83 +13,63 @@ #include "AABox.h" #include "GeometryUtil.h" -AABox::AABox(const glm::vec3& corner, float size) : _corner(corner), _size(size, size, size), _topFarLeft(_corner + _size) -{ +AABox::AABox(const glm::vec3& corner, float size) : + _corner(corner), _scale(size) { }; -AABox::AABox(const glm::vec3& corner, float x, float y, float z) : _corner(corner), _size(x, y, z), _topFarLeft(_corner + _size) -{ +AABox::AABox() : _corner(0,0,0), _scale(0) { }; -AABox::AABox(const glm::vec3& corner, const glm::vec3& size) : _corner(corner), _size(size), _topFarLeft(_corner + _size) -{ +glm::vec3 AABox::calcTopFarLeft() const { + glm::vec3 topFarLeft(_corner); + topFarLeft += glm::vec3(_scale, _scale, _scale); + return topFarLeft; }; -AABox::AABox() : _corner(0,0,0), _size(0,0,0), _topFarLeft(0,0,0) -{ -}; - - void AABox::scale(float scale) { _corner = _corner * scale; - _size = _size * scale; _center = _center * scale; - _topFarLeft = _topFarLeft * scale; + _scale = _scale * scale; } glm::vec3 AABox::getVertex(BoxVertex vertex) const { switch (vertex) { case BOTTOM_LEFT_NEAR: - return _corner + glm::vec3(_size.x, 0, 0); + return _corner + glm::vec3(_scale, 0, 0); case BOTTOM_RIGHT_NEAR: return _corner; case TOP_RIGHT_NEAR: - return _corner + glm::vec3(0, _size.y, 0); + return _corner + glm::vec3(0, _scale, 0); case TOP_LEFT_NEAR: - return _corner + glm::vec3(_size.x, _size.y, 0); + return _corner + glm::vec3(_scale, _scale, 0); case BOTTOM_LEFT_FAR: - return _corner + glm::vec3(_size.x, 0, _size.z); + return _corner + glm::vec3(_scale, 0, _scale); case BOTTOM_RIGHT_FAR: - return _corner + glm::vec3(0, 0, _size.z); + return _corner + glm::vec3(0, 0, _scale); case TOP_RIGHT_FAR: - return _corner + glm::vec3(0, _size.y, _size.z); + return _corner + glm::vec3(0, _scale, _scale); case TOP_LEFT_FAR: - return _corner + _size; + return _corner + glm::vec3(_scale, _scale, _scale); } } -void AABox::setBox(const glm::vec3& corner, const glm::vec3& size) { +void AABox::setBox(const glm::vec3& corner, float scale) { _corner = corner; - _size = size; - - // In the event that the caller gave us negative sizes, fix things up to be reasonable - if (_size.x < 0.0) { - _size.x = -size.x; - _corner.x -= _size.x; - } - if (_size.y < 0.0) { - _size.y = -size.y; - _corner.y -= _size.y; - } - if (_size.z < 0.0) { - _size.z = -size.z; - _corner.z -= _size.z; - } - _center = _corner + (_size * 0.5f); - _topFarLeft = _corner + _size; + _scale = scale; + _center = _corner + (glm::vec3(_scale, _scale, _scale) * 0.5f); } glm::vec3 AABox::getVertexP(const glm::vec3& normal) const { glm::vec3 result = _corner; if (normal.x > 0) { - result.x += _size.x; + result.x += _scale; } if (normal.y > 0) { - result.y += _size.y; + result.y += _scale; } if (normal.z > 0) { - result.z += _size.z; + result.z += _scale; } return result; } @@ -98,15 +78,15 @@ glm::vec3 AABox::getVertexN(const glm::vec3& normal) const { glm::vec3 result = _corner; if (normal.x < 0) { - result.x += _size.x; + result.x += _scale; } if (normal.y < 0) { - result.y += _size.y; + result.y += _scale; } if (normal.z < 0) { - result.z += _size.z; + result.z += _scale; } return result; @@ -118,9 +98,9 @@ static bool isWithin(float value, float corner, float size) { } bool AABox::contains(const glm::vec3& point) const { - return isWithin(point.x, _corner.x, _size.x) && - isWithin(point.y, _corner.y, _size.y) && - isWithin(point.z, _corner.z, _size.z); + return isWithin(point.x, _corner.x, _scale) && + isWithin(point.y, _corner.y, _scale) && + isWithin(point.z, _corner.z, _scale); } bool AABox::contains(const AABox& otherBox) const { @@ -140,9 +120,9 @@ static bool isWithinExpanded(float value, float corner, float size, float expans } bool AABox::expandedContains(const glm::vec3& point, float expansion) const { - return isWithinExpanded(point.x, _corner.x, _size.x, expansion) && - isWithinExpanded(point.y, _corner.y, _size.y, expansion) && - isWithinExpanded(point.z, _corner.z, _size.z, expansion); + return isWithinExpanded(point.x, _corner.x, _scale, expansion) && + isWithinExpanded(point.y, _corner.y, _scale, expansion) && + isWithinExpanded(point.z, _corner.z, _scale, expansion); } // finds the intersection between a ray and the facing plane on one axis @@ -164,7 +144,7 @@ bool AABox::expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& e } // check each axis glm::vec3 expandedCorner = _corner - glm::vec3(expansion, expansion, expansion); - glm::vec3 expandedSize = _size + glm::vec3(expansion, expansion, expansion) * 2.0f; + glm::vec3 expandedSize = glm::vec3(_scale, _scale, _scale) + glm::vec3(expansion, expansion, expansion) * 2.0f; glm::vec3 direction = end - start; float axisDistance; return (findIntersection(start.x, direction.x, expandedCorner.x, expandedSize.x, axisDistance) && @@ -189,23 +169,23 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct } // check each axis float axisDistance; - if ((findIntersection(origin.x, direction.x, _corner.x, _size.x, axisDistance) && axisDistance >= 0 && - isWithin(origin.y + axisDistance*direction.y, _corner.y, _size.y) && - isWithin(origin.z + axisDistance*direction.z, _corner.z, _size.z))) { + if ((findIntersection(origin.x, direction.x, _corner.x, _scale, axisDistance) && axisDistance >= 0 && + isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) && + isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale))) { distance = axisDistance; face = direction.x > 0 ? MIN_X_FACE : MAX_X_FACE; return true; } - if ((findIntersection(origin.y, direction.y, _corner.y, _size.y, axisDistance) && axisDistance >= 0 && - isWithin(origin.x + axisDistance*direction.x, _corner.x, _size.x) && - isWithin(origin.z + axisDistance*direction.z, _corner.z, _size.z))) { + if ((findIntersection(origin.y, direction.y, _corner.y, _scale, axisDistance) && axisDistance >= 0 && + isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale) && + isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale))) { distance = axisDistance; face = direction.y > 0 ? MIN_Y_FACE : MAX_Y_FACE; return true; } - if ((findIntersection(origin.z, direction.z, _corner.z, _size.z, axisDistance) && axisDistance >= 0 && - isWithin(origin.y + axisDistance*direction.y, _corner.y, _size.y) && - isWithin(origin.x + axisDistance*direction.x, _corner.x, _size.x))) { + if ((findIntersection(origin.z, direction.z, _corner.z, _scale, axisDistance) && axisDistance >= 0 && + isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) && + isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale))) { distance = axisDistance; face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE; return true; @@ -268,27 +248,27 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec3& point, BoxFace face) con switch (face) { case MIN_X_FACE: return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), - glm::vec3(_corner.x, _corner.y + _size.y, _corner.z + _size.z)); + glm::vec3(_corner.x, _corner.y + _scale, _corner.z + _scale)); case MAX_X_FACE: - return glm::clamp(point, glm::vec3(_corner.x + _size.x, _corner.y, _corner.z), - glm::vec3(_corner.x + _size.x, _corner.y + _size.y, _corner.z + _size.z)); + return glm::clamp(point, glm::vec3(_corner.x + _scale, _corner.y, _corner.z), + glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale)); case MIN_Y_FACE: return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), - glm::vec3(_corner.x + _size.x, _corner.y, _corner.z + _size.z)); + glm::vec3(_corner.x + _scale, _corner.y, _corner.z + _scale)); case MAX_Y_FACE: - return glm::clamp(point, glm::vec3(_corner.x, _corner.y + _size.y, _corner.z), - glm::vec3(_corner.x + _size.x, _corner.y + _size.y, _corner.z + _size.z)); + return glm::clamp(point, glm::vec3(_corner.x, _corner.y + _scale, _corner.z), + glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale)); case MIN_Z_FACE: return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), - glm::vec3(_corner.x + _size.x, _corner.y + _size.y, _corner.z)); + glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z)); case MAX_Z_FACE: - return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z + _size.z), - glm::vec3(_corner.x + _size.x, _corner.y + _size.y, _corner.z + _size.z)); + return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z + _scale), + glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale)); } } @@ -338,7 +318,7 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& glm::vec4 thirdAxisMaxPlane = getPlane((BoxFace)(thirdAxis * 2 + 1)); glm::vec4 offset = glm::vec4(0.0f, 0.0f, 0.0f, - glm::dot(glm::vec3(secondAxisMaxPlane + thirdAxisMaxPlane), _size) * 0.5f); + glm::dot(glm::vec3(secondAxisMaxPlane + thirdAxisMaxPlane), glm::vec3(_scale, _scale, _scale)) * 0.5f); glm::vec4 diagonals[] = { secondAxisMinPlane + thirdAxisMaxPlane + offset, secondAxisMaxPlane + thirdAxisMaxPlane + offset }; @@ -362,11 +342,11 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& glm::vec4 AABox::getPlane(BoxFace face) const { switch (face) { case MIN_X_FACE: return glm::vec4(-1.0f, 0.0f, 0.0f, _corner.x); - case MAX_X_FACE: return glm::vec4(1.0f, 0.0f, 0.0f, -_corner.x - _size.x); + case MAX_X_FACE: return glm::vec4(1.0f, 0.0f, 0.0f, -_corner.x - _scale); case MIN_Y_FACE: return glm::vec4(0.0f, -1.0f, 0.0f, _corner.y); - case MAX_Y_FACE: return glm::vec4(0.0f, 1.0f, 0.0f, -_corner.y - _size.y); + case MAX_Y_FACE: return glm::vec4(0.0f, 1.0f, 0.0f, -_corner.y - _scale); case MIN_Z_FACE: return glm::vec4(0.0f, 0.0f, -1.0f, _corner.z); - case MAX_Z_FACE: return glm::vec4(0.0f, 0.0f, 1.0f, -_corner.z - _size.z); + case MAX_Z_FACE: return glm::vec4(0.0f, 0.0f, 1.0f, -_corner.z - _scale); } } diff --git a/libraries/voxels/src/AABox.h b/libraries/voxels/src/AABox.h index 7bb203aaf4..b08f94df5c 100644 --- a/libraries/voxels/src/AABox.h +++ b/libraries/voxels/src/AABox.h @@ -42,13 +42,10 @@ class AABox public: AABox(const glm::vec3& corner, float size); - AABox(const glm::vec3& corner, float x, float y, float z); - AABox(const glm::vec3& corner, const glm::vec3& size); AABox(); ~AABox() {}; - void setBox(const glm::vec3& corner, float x, float y, float z) { setBox(corner,glm::vec3(x,y,z)); }; - void setBox(const glm::vec3& corner, const glm::vec3& size); + void setBox(const glm::vec3& corner, float scale); // for use in frustum computations glm::vec3 getVertexP(const glm::vec3& normal) const; @@ -57,9 +54,10 @@ public: void scale(float scale); const glm::vec3& getCorner() const { return _corner; }; - const glm::vec3& getSize() const { return _size; }; const glm::vec3& getCenter() const { return _center; }; - const glm::vec3& getTopFarLeft() const { return _topFarLeft; }; + + glm::vec3 calcTopFarLeft() const; + float getScale() const { return _scale; } glm::vec3 getVertex(BoxVertex vertex) const; @@ -81,8 +79,7 @@ private: glm::vec3 _corner; glm::vec3 _center; - glm::vec3 _size; - glm::vec3 _topFarLeft; + float _scale; }; diff --git a/libraries/voxels/src/ViewFrustum.cpp b/libraries/voxels/src/ViewFrustum.cpp index e0cfa7cd97..3733442e9c 100644 --- a/libraries/voxels/src/ViewFrustum.cpp +++ b/libraries/voxels/src/ViewFrustum.cpp @@ -541,9 +541,17 @@ const int hullVertexLookup[MAX_POSSIBLE_COMBINATIONS][MAX_PROJECTED_POLYGON_VERT {6, TOP_RIGHT_NEAR, TOP_RIGHT_FAR, BOTTOM_RIGHT_FAR, BOTTOM_LEFT_FAR, BOTTOM_LEFT_NEAR, TOP_LEFT_NEAR}, // back, top, left }; +uint64_t ViewFrustum::getProjectedPolygonTime = 0; +uint64_t ViewFrustum::getProjectedPolygonCalls = 0; +#include + VoxelProjectedPolygon ViewFrustum::getProjectedPolygon(const AABox& box) const { + getProjectedPolygonCalls++; + PerformanceWarning(false, "ViewFrustum::getProjectedPolygon", false, &getProjectedPolygonTime); + const glm::vec3& bottomNearRight = box.getCorner(); - const glm::vec3& topFarLeft = box.getTopFarLeft(); + glm::vec3 topFarLeft = box.calcTopFarLeft(); + int lookUp = ((_position.x < bottomNearRight.x) ) // 1 = right | compute 6-bit + ((_position.x > topFarLeft.x ) << 1) // 2 = left | code to + ((_position.y < bottomNearRight.y) << 2) // 4 = bottom | classify camera @@ -605,13 +613,19 @@ VoxelProjectedPolygon ViewFrustum::getProjectedPolygon(const AABox& box) const { } +uint64_t ViewFrustum::getFurthestPointFromCameraTime = 0; +uint64_t ViewFrustum::getFurthestPointFromCameraCalls = 0; + // Similar strategy to getProjectedPolygon() we use the knowledge of camera position relative to the // axis-aligned voxels to determine which of the voxels vertices must be the furthest. No need for // squares and square-roots. Just compares. glm::vec3 ViewFrustum::getFurthestPointFromCamera(const AABox& box) const { - const glm::vec3& center = box.getCenter(); + getFurthestPointFromCameraCalls++; + PerformanceWarning(false, "ViewFrustum::getFurthestPointFromCamera", false, &getFurthestPointFromCameraTime); + + const glm::vec3& center = box.getCenter(); const glm::vec3& bottomNearRight = box.getCorner(); - const glm::vec3& topFarLeft = box.getTopFarLeft(); + glm::vec3 topFarLeft = box.calcTopFarLeft(); glm::vec3 furthestPoint; if (_position.x < center.x) { diff --git a/libraries/voxels/src/ViewFrustum.h b/libraries/voxels/src/ViewFrustum.h index 803e52908e..d3341ede23 100644 --- a/libraries/voxels/src/ViewFrustum.h +++ b/libraries/voxels/src/ViewFrustum.h @@ -96,6 +96,11 @@ public: VoxelProjectedPolygon getProjectedPolygon(const AABox& box) const; glm::vec3 getFurthestPointFromCamera(const AABox& box) const; + static uint64_t getProjectedPolygonTime; + static uint64_t getProjectedPolygonCalls; + static uint64_t getFurthestPointFromCameraTime; + static uint64_t getFurthestPointFromCameraCalls; + private: // Used for keyhole calculations diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index ad83b5a9cf..6c45bde441 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -61,14 +61,14 @@ void VoxelNode::init(unsigned char * octalCode) { markWithChangedTime(); _voxelMemoryUsage += sizeof(VoxelNode); - _octcodeMemoryUsage += bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(_octalCode)); + _octcodeMemoryUsage += bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(getOctalCode())); } VoxelNode::~VoxelNode() { notifyDeleteHooks(); _voxelMemoryUsage -= sizeof(VoxelNode); - _octcodeMemoryUsage -= bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(_octalCode)); + _octcodeMemoryUsage -= bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(getOctalCode())); delete[] _octalCode; @@ -128,18 +128,14 @@ void VoxelNode::setShouldRender(bool shouldRender) { } void VoxelNode::calculateAABox() { - glm::vec3 corner; - glm::vec3 size; // copy corner into box - copyFirstVertexForCode(_octalCode,(float*)&corner); + copyFirstVertexForCode(getOctalCode(),(float*)&corner); // this tells you the "size" of the voxel - float voxelScale = 1 / powf(2, *_octalCode); - size = glm::vec3(voxelScale,voxelScale,voxelScale); - - _box.setBox(corner,size); + float voxelScale = 1 / powf(2, numberOfThreeBitSectionsInCode(getOctalCode())); + _box.setBox(corner,voxelScale); } void VoxelNode::deleteChildAtIndex(int childIndex) { @@ -166,7 +162,7 @@ VoxelNode* VoxelNode::removeChildAtIndex(int childIndex) { VoxelNode* VoxelNode::addChildAtIndex(int childIndex) { if (!_children[childIndex]) { - _children[childIndex] = new VoxelNode(childOctalCode(_octalCode, childIndex)); + _children[childIndex] = new VoxelNode(childOctalCode(getOctalCode(), childIndex)); _children[childIndex]->setVoxelSystem(_voxelSystem); // our child is always part of our voxel system NULL ok _isDirty = true; _childCount++; @@ -339,13 +335,13 @@ void VoxelNode::printDebugDetails(const char* label) const { } qDebug("%s - Voxel at corner=(%f,%f,%f) size=%f\n isLeaf=%s isColored=%s (%d,%d,%d,%d) isDirty=%s shouldRender=%s\n children=", label, - _box.getCorner().x, _box.getCorner().y, _box.getCorner().z, _box.getSize().x, + _box.getCorner().x, _box.getCorner().y, _box.getCorner().z, _box.getScale(), debug::valueOf(isLeaf()), debug::valueOf(isColored()), getColor()[0], getColor()[1], getColor()[2], getColor()[3], debug::valueOf(isDirty()), debug::valueOf(getShouldRender())); outputBits(childBits, false); qDebug("\n octalCode="); - printOctalCode(_octalCode); + printOctalCode(getOctalCode()); } float VoxelNode::getEnclosingRadius() const { diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 41196c81b5..2cd3c90389 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -55,7 +55,7 @@ public: 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())); } + float getScale() const { return _box.getScale(); } // voxelScale = (1 / powf(2, *node->getOctalCode())); } int getLevel() const { return *_octalCode + 1; } // one based or zero based? this doesn't correctly handle 2 byte case float getEnclosingRadius() const; From 9ba39c3a84cb3db1a2999757fdcde5cfb63a9d10 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 15 Oct 2013 12:05:54 -0700 Subject: [PATCH 02/22] removed center from AABox to further save memory --- .../src/VoxelSendThread.cpp | 7 ------- libraries/voxels/src/AABox.cpp | 9 ++++++--- libraries/voxels/src/AABox.h | 12 ++++-------- libraries/voxels/src/ViewFrustum.cpp | 17 ++--------------- libraries/voxels/src/ViewFrustum.h | 6 ------ libraries/voxels/src/VoxelNode.cpp | 6 +++--- libraries/voxels/src/VoxelNode.h | 5 ++--- 7 files changed, 17 insertions(+), 45 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index f12577bd2f..961712a46f 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -53,13 +53,6 @@ bool VoxelSendThread::process() { } } - // some debugging... - printf("ViewFrustum::getProjectedPolygonTime=%llu ViewFrustum::getProjectedPolygonCalls=%llu\n", - ViewFrustum::getProjectedPolygonTime, ViewFrustum::getProjectedPolygonCalls); - - printf("ViewFrustum::getFurthestPointFromCameraTime=%llu ViewFrustum::getFurthestPointFromCameraCalls=%llu\n", - ViewFrustum::getFurthestPointFromCameraTime, ViewFrustum::getFurthestPointFromCameraCalls); - return isStillRunning(); // keep running till they terminate us } diff --git a/libraries/voxels/src/AABox.cpp b/libraries/voxels/src/AABox.cpp index 24f6384aee..50b0958ae4 100644 --- a/libraries/voxels/src/AABox.cpp +++ b/libraries/voxels/src/AABox.cpp @@ -20,6 +20,12 @@ AABox::AABox(const glm::vec3& corner, float size) : AABox::AABox() : _corner(0,0,0), _scale(0) { }; +glm::vec3 AABox::calcCenter() const { + glm::vec3 center(_corner); + center += (glm::vec3(_scale, _scale, _scale) * 0.5f); + return center; +} + glm::vec3 AABox::calcTopFarLeft() const { glm::vec3 topFarLeft(_corner); topFarLeft += glm::vec3(_scale, _scale, _scale); @@ -28,11 +34,9 @@ glm::vec3 AABox::calcTopFarLeft() const { void AABox::scale(float scale) { _corner = _corner * scale; - _center = _center * scale; _scale = _scale * scale; } - glm::vec3 AABox::getVertex(BoxVertex vertex) const { switch (vertex) { case BOTTOM_LEFT_NEAR: @@ -57,7 +61,6 @@ glm::vec3 AABox::getVertex(BoxVertex vertex) const { void AABox::setBox(const glm::vec3& corner, float scale) { _corner = corner; _scale = scale; - _center = _corner + (glm::vec3(_scale, _scale, _scale) * 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 b08f94df5c..c6ae5c98c3 100644 --- a/libraries/voxels/src/AABox.h +++ b/libraries/voxels/src/AABox.h @@ -36,11 +36,9 @@ enum BoxVertex { const int FACE_COUNT = 6; -class AABox -{ +class AABox { public: - AABox(const glm::vec3& corner, float size); AABox(); ~AABox() {}; @@ -54,11 +52,11 @@ public: void scale(float scale); const glm::vec3& getCorner() const { return _corner; }; - const glm::vec3& getCenter() const { return _center; }; - - glm::vec3 calcTopFarLeft() const; float getScale() const { return _scale; } + glm::vec3 calcCenter() const; + glm::vec3 calcTopFarLeft() const; + glm::vec3 getVertex(BoxVertex vertex) const; bool contains(const glm::vec3& point) const; @@ -70,7 +68,6 @@ public: bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const; private: - glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const; glm::vec3 getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, BoxFace face) const; glm::vec4 getPlane(BoxFace face) const; @@ -78,7 +75,6 @@ private: static BoxFace getOppositeFace(BoxFace face); glm::vec3 _corner; - glm::vec3 _center; float _scale; }; diff --git a/libraries/voxels/src/ViewFrustum.cpp b/libraries/voxels/src/ViewFrustum.cpp index 3733442e9c..05380c9e4a 100644 --- a/libraries/voxels/src/ViewFrustum.cpp +++ b/libraries/voxels/src/ViewFrustum.cpp @@ -541,14 +541,7 @@ const int hullVertexLookup[MAX_POSSIBLE_COMBINATIONS][MAX_PROJECTED_POLYGON_VERT {6, TOP_RIGHT_NEAR, TOP_RIGHT_FAR, BOTTOM_RIGHT_FAR, BOTTOM_LEFT_FAR, BOTTOM_LEFT_NEAR, TOP_LEFT_NEAR}, // back, top, left }; -uint64_t ViewFrustum::getProjectedPolygonTime = 0; -uint64_t ViewFrustum::getProjectedPolygonCalls = 0; -#include - VoxelProjectedPolygon ViewFrustum::getProjectedPolygon(const AABox& box) const { - getProjectedPolygonCalls++; - PerformanceWarning(false, "ViewFrustum::getProjectedPolygon", false, &getProjectedPolygonTime); - const glm::vec3& bottomNearRight = box.getCorner(); glm::vec3 topFarLeft = box.calcTopFarLeft(); @@ -604,7 +597,7 @@ VoxelProjectedPolygon ViewFrustum::getProjectedPolygon(const AABox& box) const { ***/ } // set the distance from our camera position, to the closest vertex - float distance = glm::distance(getPosition(), box.getCenter()); + float distance = glm::distance(getPosition(), box.calcCenter()); projectedPolygon.setDistance(distance); projectedPolygon.setAnyInView(anyPointsInView); projectedPolygon.setAllInView(allPointsInView); @@ -613,18 +606,12 @@ VoxelProjectedPolygon ViewFrustum::getProjectedPolygon(const AABox& box) const { } -uint64_t ViewFrustum::getFurthestPointFromCameraTime = 0; -uint64_t ViewFrustum::getFurthestPointFromCameraCalls = 0; - // Similar strategy to getProjectedPolygon() we use the knowledge of camera position relative to the // axis-aligned voxels to determine which of the voxels vertices must be the furthest. No need for // squares and square-roots. Just compares. glm::vec3 ViewFrustum::getFurthestPointFromCamera(const AABox& box) const { - getFurthestPointFromCameraCalls++; - PerformanceWarning(false, "ViewFrustum::getFurthestPointFromCamera", false, &getFurthestPointFromCameraTime); - - const glm::vec3& center = box.getCenter(); const glm::vec3& bottomNearRight = box.getCorner(); + glm::vec3 center = box.calcCenter(); glm::vec3 topFarLeft = box.calcTopFarLeft(); glm::vec3 furthestPoint; diff --git a/libraries/voxels/src/ViewFrustum.h b/libraries/voxels/src/ViewFrustum.h index d3341ede23..9a3c69ca7c 100644 --- a/libraries/voxels/src/ViewFrustum.h +++ b/libraries/voxels/src/ViewFrustum.h @@ -96,13 +96,7 @@ public: VoxelProjectedPolygon getProjectedPolygon(const AABox& box) const; glm::vec3 getFurthestPointFromCamera(const AABox& box) const; - static uint64_t getProjectedPolygonTime; - static uint64_t getProjectedPolygonCalls; - static uint64_t getFurthestPointFromCameraTime; - static uint64_t getFurthestPointFromCameraCalls; - private: - // Used for keyhole calculations ViewFrustum::location pointInKeyhole(const glm::vec3& point) const; ViewFrustum::location sphereInKeyhole(const glm::vec3& center, float radius) const; diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 6c45bde441..c7b5c9e7e6 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -394,20 +394,20 @@ float VoxelNode::furthestDistanceToCamera(const ViewFrustum& viewFrustum) const } float VoxelNode::distanceToCamera(const ViewFrustum& viewFrustum) const { - glm::vec3 center = _box.getCenter() * (float)TREE_SCALE; + glm::vec3 center = _box.calcCenter() * (float)TREE_SCALE; glm::vec3 temp = viewFrustum.getPosition() - center; float distanceToVoxelCenter = sqrtf(glm::dot(temp, temp)); return distanceToVoxelCenter; } float VoxelNode::distanceSquareToPoint(const glm::vec3& point) const { - glm::vec3 temp = point - _box.getCenter(); + glm::vec3 temp = point - _box.calcCenter(); float distanceSquare = glm::dot(temp, temp); return distanceSquare; } float VoxelNode::distanceToPoint(const glm::vec3& point) const { - glm::vec3 temp = point - _box.getCenter(); + glm::vec3 temp = point - _box.calcCenter(); float distance = sqrtf(glm::dot(temp, temp)); return distance; } diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 2cd3c90389..2fe3507669 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -53,10 +53,9 @@ public: bool collapseIdenticalLeaves(); const AABox& getAABox() const { return _box; } - const glm::vec3& getCenter() const { return _box.getCenter(); } const glm::vec3& getCorner() const { return _box.getCorner(); } - float getScale() const { return _box.getScale(); } // voxelScale = (1 / powf(2, *node->getOctalCode())); } - int getLevel() const { return *_octalCode + 1; } // one based or zero based? this doesn't correctly handle 2 byte case + float getScale() const { return _box.getScale(); } + int getLevel() const { return numberOfThreeBitSectionsInCode(getOctalCode()) + 1; } float getEnclosingRadius() const; From 86ba5e3064aa0ed3d95598c9a0538f8c7f666872 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 15 Oct 2013 12:11:49 -0700 Subject: [PATCH 03/22] some size comparison debugging --- libraries/voxel-server-library/src/VoxelPersistThread.cpp | 2 ++ libraries/voxels/src/AABox.h | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/libraries/voxel-server-library/src/VoxelPersistThread.cpp b/libraries/voxel-server-library/src/VoxelPersistThread.cpp index 8ad2bfaa4d..c77ff44755 100644 --- a/libraries/voxel-server-library/src/VoxelPersistThread.cpp +++ b/libraries/voxel-server-library/src/VoxelPersistThread.cpp @@ -29,6 +29,8 @@ bool VoxelPersistThread::process() { _initialLoad = true; qDebug("loading voxels from file: %s...\n", _filename); + qDebug("sizeof(VoxelNode)=%d sizeof(AABox)=%d sizeof(oldAABox)=%d\n", sizeof(VoxelNode), sizeof(AABox), sizeof(oldAABox)); + bool persistantFileRead = _tree->readFromSVOFile(_filename); if (persistantFileRead) { PerformanceWarning warn(true, "reaverageVoxelColors()", true); diff --git a/libraries/voxels/src/AABox.h b/libraries/voxels/src/AABox.h index c6ae5c98c3..0ad2878a88 100644 --- a/libraries/voxels/src/AABox.h +++ b/libraries/voxels/src/AABox.h @@ -78,5 +78,12 @@ private: float _scale; }; +class oldAABox { + glm::vec3 _corner; + glm::vec3 _size; + glm::vec3 _center; + glm::vec3 _topFarLeft; +}; + #endif From 9d0ff1595af462cfd08bce7584ac20e42d653f51 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 15 Oct 2013 13:33:38 -0700 Subject: [PATCH 04/22] make voxelnode population statistics static members instead of per node --- .../src/VoxelPersistThread.cpp | 7 +-- .../voxel-server-library/src/VoxelServer.cpp | 7 ++- libraries/voxels/src/VoxelNode.cpp | 47 +++++++++++-------- libraries/voxels/src/VoxelNode.h | 13 ++--- libraries/voxels/src/VoxelSceneStats.cpp | 7 +-- libraries/voxels/src/VoxelTree.cpp | 3 -- 6 files changed, 45 insertions(+), 39 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelPersistThread.cpp b/libraries/voxel-server-library/src/VoxelPersistThread.cpp index c77ff44755..ee8147eaad 100644 --- a/libraries/voxel-server-library/src/VoxelPersistThread.cpp +++ b/libraries/voxel-server-library/src/VoxelPersistThread.cpp @@ -42,9 +42,10 @@ bool VoxelPersistThread::process() { _tree->clearDirtyBit(); // the tree is clean since we just loaded it qDebug("DONE loading voxels from file... fileRead=%s\n", debug::valueOf(persistantFileRead)); - unsigned long nodeCount = _tree->rootNode->getSubTreeNodeCount(); - unsigned long internalNodeCount = _tree->rootNode->getSubTreeInternalNodeCount(); - unsigned long leafNodeCount = _tree->rootNode->getSubTreeLeafNodeCount(); + + unsigned long nodeCount = VoxelNode::getNodeCount(); + unsigned long internalNodeCount = VoxelNode::getInternalNodeCount(); + unsigned long leafNodeCount = VoxelNode::getLeafNodeCount(); qDebug("Nodes after loading scene %lu nodes %lu internal %lu leaves\n", nodeCount, internalNodeCount, leafNodeCount); } diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index f02069af2e..d261f0348f 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -139,10 +139,9 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { mg_printf(connection, "Voxel Node Memory Usage: %f MB\r\n", VoxelNode::getVoxelMemoryUsage() / 1000000.f); mg_printf(connection, "Octcode Memory Usage: %f MB\r\n", VoxelNode::getOctcodeMemoryUsage() / 1000000.f); - VoxelTree* theTree = VoxelServer::GetInstance()->getTree(); - unsigned long nodeCount = theTree->rootNode->getSubTreeNodeCount(); - unsigned long internalNodeCount = theTree->rootNode->getSubTreeInternalNodeCount(); - unsigned long leafNodeCount = theTree->rootNode->getSubTreeLeafNodeCount(); + unsigned long nodeCount = VoxelNode::getNodeCount(); + unsigned long internalNodeCount = VoxelNode::getInternalNodeCount(); + unsigned long leafNodeCount = VoxelNode::getLeafNodeCount(); mg_printf(connection, "%s", "Current Nodes in scene\r\n"); mg_printf(connection, " Total Nodes: %lu nodes\r\n", nodeCount); diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index c7b5c9e7e6..af9fa0a117 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -23,15 +23,22 @@ uint64_t VoxelNode::_voxelMemoryUsage = 0; uint64_t VoxelNode::_octcodeMemoryUsage = 0; +uint64_t VoxelNode::_voxelNodeCount = 0; +uint64_t VoxelNode::_voxelNodeLeafCount = 0; VoxelNode::VoxelNode() { unsigned char* rootCode = new unsigned char[1]; *rootCode = 0; init(rootCode); + + _voxelNodeCount++; + _voxelNodeLeafCount++; // all nodes start as leaf nodes } VoxelNode::VoxelNode(unsigned char * octalCode) { init(octalCode); + _voxelNodeCount++; + _voxelNodeLeafCount++; // all nodes start as leaf nodes } void VoxelNode::init(unsigned char * octalCode) { @@ -49,8 +56,6 @@ void VoxelNode::init(unsigned char * octalCode) { _children[i] = NULL; } _childCount = 0; - _subtreeNodeCount = 1; // that's me - _subtreeLeafNodeCount = 0; // that's me _glBufferIndex = GLBUFFER_INDEX_UNKNOWN; _voxelSystem = NULL; @@ -70,6 +75,11 @@ VoxelNode::~VoxelNode() { _voxelMemoryUsage -= sizeof(VoxelNode); _octcodeMemoryUsage -= bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(getOctalCode())); + _voxelNodeCount--; + if (isLeaf()) { + _voxelNodeLeafCount--; + } + delete[] _octalCode; // delete all of this node's children @@ -97,27 +107,9 @@ void VoxelNode::handleSubtreeChanged(VoxelTree* myTree) { setColorFromAverageOfChildren(); } - recalculateSubTreeNodeCount(); markWithChangedTime(); } -void VoxelNode::recalculateSubTreeNodeCount() { - // Assuming the tree below me as changed, I need to recalculate my node count - _subtreeNodeCount = 1; // that's me - if (isLeaf()) { - _subtreeLeafNodeCount = 1; - } else { - _subtreeLeafNodeCount = 0; - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - if (_children[i]) { - _subtreeNodeCount += _children[i]->_subtreeNodeCount; - _subtreeLeafNodeCount += _children[i]->_subtreeLeafNodeCount; - } - } - } -} - - void VoxelNode::setShouldRender(bool shouldRender) { // if shouldRender is changing, then consider ourselves dirty if (shouldRender != _shouldRender) { @@ -145,6 +137,11 @@ void VoxelNode::deleteChildAtIndex(int childIndex) { _isDirty = true; _childCount--; markWithChangedTime(); + + // after deleting the child, check to see if we're a leaf + if (isLeaf()) { + _voxelNodeLeafCount++; + } } } @@ -156,12 +153,22 @@ VoxelNode* VoxelNode::removeChildAtIndex(int childIndex) { _isDirty = true; _childCount--; markWithChangedTime(); + + // after removing the child, check to see if we're a leaf + if (isLeaf()) { + _voxelNodeLeafCount++; + } } return returnedChild; } VoxelNode* VoxelNode::addChildAtIndex(int childIndex) { if (!_children[childIndex]) { + // before adding a child, see if we're currently a leaf + if (isLeaf()) { + _voxelNodeLeafCount--; + } + _children[childIndex] = new VoxelNode(childOctalCode(getOctalCode(), childIndex)); _children[childIndex]->setVoxelSystem(_voxelSystem); // our child is always part of our voxel system NULL ok _isDirty = true; diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 2fe3507669..3b36b2d3e9 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -121,10 +121,9 @@ public: static void addUpdateHook(VoxelNodeUpdateHook* hook); static void removeUpdateHook(VoxelNodeUpdateHook* hook); - void recalculateSubTreeNodeCount(); - unsigned long getSubTreeNodeCount() const { return _subtreeNodeCount; } - unsigned long getSubTreeInternalNodeCount() const { return _subtreeNodeCount - _subtreeLeafNodeCount; } - unsigned long getSubTreeLeafNodeCount() const { return _subtreeLeafNodeCount; } + static unsigned long getNodeCount() { return _voxelNodeCount; } + static unsigned long getInternalNodeCount() { return _voxelNodeCount - _voxelNodeLeafCount; } + static unsigned long getLeafNodeCount() { return _voxelNodeLeafCount; } static uint64_t getVoxelMemoryUsage() { return _voxelMemoryUsage; } static uint64_t getOctcodeMemoryUsage() { return _octcodeMemoryUsage; } @@ -140,8 +139,6 @@ private: unsigned char* _octalCode; /// Client and server, pointer to octal code for this node, 8 bytes uint64_t _lastChanged; /// Client and server, timestamp this node was last changed, 8 bytes - unsigned long _subtreeNodeCount; /// Client and server, nodes below this node, 8 bytes - unsigned long _subtreeLeafNodeCount; /// Client and server, leaves below this node, 8 bytes glBufferIndex _glBufferIndex; /// Client only, vbo index for this voxel if being rendered, 8 bytes VoxelSystem* _voxelSystem; /// Client only, pointer to VoxelSystem rendering this voxel, 8 bytes @@ -162,6 +159,10 @@ private: static std::vector _deleteHooks; static std::vector _updateHooks; + + static uint64_t _voxelNodeCount; + static uint64_t _voxelNodeLeafCount; + static uint64_t _voxelMemoryUsage; static uint64_t _octcodeMemoryUsage; }; diff --git a/libraries/voxels/src/VoxelSceneStats.cpp b/libraries/voxels/src/VoxelSceneStats.cpp index 1ebc4015e0..f4570d93a2 100644 --- a/libraries/voxels/src/VoxelSceneStats.cpp +++ b/libraries/voxels/src/VoxelSceneStats.cpp @@ -33,9 +33,10 @@ void VoxelSceneStats::sceneStarted(bool isFullScene, bool isMoving, VoxelNode* r reset(); // resets packet and voxel stats _isStarted = true; _start = usecTimestampNow(); - _totalVoxels = root->getSubTreeNodeCount(); - _totalInternal = root->getSubTreeInternalNodeCount(); - _totalLeaves = root->getSubTreeLeafNodeCount(); + + _totalVoxels = VoxelNode::getNodeCount(); + _totalInternal = VoxelNode::getInternalNodeCount(); + _totalLeaves = VoxelNode::getLeafNodeCount(); _isFullScene = isFullScene; _isMoving = isMoving; diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 3b79722686..ff51cd3044 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -647,9 +647,6 @@ void VoxelTree::reaverageVoxelColors(VoxelNode *startNode) { if (hasChildren && !startNode->collapseIdenticalLeaves()) { startNode->setColorFromAverageOfChildren(); } - - // this is also a good time to recalculateSubTreeNodeCount() - startNode->recalculateSubTreeNodeCount(); } } From 05c9d4febc35d4f0d094925def4345741a977d2e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 15 Oct 2013 13:37:14 -0700 Subject: [PATCH 05/22] added old style voxelnode for size comparison --- .../src/VoxelPersistThread.cpp | 3 ++- libraries/voxels/src/VoxelNode.h | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/libraries/voxel-server-library/src/VoxelPersistThread.cpp b/libraries/voxel-server-library/src/VoxelPersistThread.cpp index ee8147eaad..d63601e5be 100644 --- a/libraries/voxel-server-library/src/VoxelPersistThread.cpp +++ b/libraries/voxel-server-library/src/VoxelPersistThread.cpp @@ -29,7 +29,8 @@ bool VoxelPersistThread::process() { _initialLoad = true; qDebug("loading voxels from file: %s...\n", _filename); - qDebug("sizeof(VoxelNode)=%d sizeof(AABox)=%d sizeof(oldAABox)=%d\n", sizeof(VoxelNode), sizeof(AABox), sizeof(oldAABox)); + qDebug("sizeof(oldVoxelNode)=%d sizeof(VoxelNode)=%d sizeof(AABox)=%d sizeof(oldAABox)=%d\n", + sizeof(oldVoxelNode), sizeof(VoxelNode), sizeof(AABox), sizeof(oldAABox)); bool persistantFileRead = _tree->readFromSVOFile(_filename); if (persistantFileRead) { diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 3b36b2d3e9..8432b7b06b 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -167,4 +167,30 @@ private: static uint64_t _octcodeMemoryUsage; }; + +class oldVoxelNode { +public: + + VoxelNode* _children[8]; /// Client and server, pointers to child nodes, 64 bytes + oldAABox _box; /// Client and server, axis aligned box for bounds of this voxel, 48 bytes + unsigned char* _octalCode; /// Client and server, pointer to octal code for this node, 8 bytes + + uint64_t _lastChanged; /// Client and server, timestamp this node was last changed, 8 bytes + unsigned long _subtreeNodeCount; /// Client and server, nodes below this node, 8 bytes + unsigned long _subtreeLeafNodeCount; /// Client and server, leaves below this node, 8 bytes + + glBufferIndex _glBufferIndex; /// Client only, vbo index for this voxel if being rendered, 8 bytes + VoxelSystem* _voxelSystem; /// Client only, pointer to VoxelSystem rendering this voxel, 8 bytes + + float _density; /// Client and server, If leaf: density = 1, if internal node: 0-1 density of voxels inside, 4 bytes + int _childCount; /// Client and server, current child nodes set to non-null in _children, 4 bytes + + nodeColor _trueColor; /// Client and server, true color of this voxel, 4 bytes + nodeColor _currentColor; /// Client only, false color of this voxel, 4 bytes + bool _falseColored; /// Client only, is this voxel false colored, 1 bytes + + bool _isDirty; /// Client only, has this voxel changed since being rendered, 1 byte + bool _shouldRender; /// Client only, should this voxel render at this time, 1 byte + uint16_t _sourceID; /// Client only, stores node id of voxel server that sent his voxel, 2 bytes +}; #endif /* defined(__hifi__VoxelNode__) */ \ No newline at end of file From 9800dc0fde4cf7f3ae0a1db8501a096bc4d55072 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 15 Oct 2013 13:40:55 -0700 Subject: [PATCH 06/22] removed dead code --- .../voxel-server-library/src/VoxelPersistThread.cpp | 2 +- libraries/voxels/src/VoxelNode.h | 12 ------------ 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelPersistThread.cpp b/libraries/voxel-server-library/src/VoxelPersistThread.cpp index d63601e5be..7caa83c2d8 100644 --- a/libraries/voxel-server-library/src/VoxelPersistThread.cpp +++ b/libraries/voxel-server-library/src/VoxelPersistThread.cpp @@ -29,7 +29,7 @@ bool VoxelPersistThread::process() { _initialLoad = true; qDebug("loading voxels from file: %s...\n", _filename); - qDebug("sizeof(oldVoxelNode)=%d sizeof(VoxelNode)=%d sizeof(AABox)=%d sizeof(oldAABox)=%d\n", + qDebug("sizeof(oldVoxelNode)=%ld sizeof(VoxelNode)=%ld sizeof(AABox)=%ld sizeof(oldAABox)=%ld\n", sizeof(oldVoxelNode), sizeof(VoxelNode), sizeof(AABox), sizeof(oldAABox)); bool persistantFileRead = _tree->readFromSVOFile(_filename); diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 8432b7b06b..884d79a632 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -93,22 +93,12 @@ public: void setShouldRender(bool shouldRender); bool getShouldRender() const { return _shouldRender; } -#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color void setFalseColor(colorPart red, colorPart green, colorPart blue); void setFalseColored(bool isFalseColored); bool getFalseColored() { return _falseColored; } void setColor(const nodeColor& color); const nodeColor& getTrueColor() const { return _trueColor; } const nodeColor& getColor() const { return _currentColor; } -#else - void setFalseColor(colorPart red, colorPart green, colorPart blue) { /* no op */ }; - void setFalseColored(bool isFalseColored) { /* no op */ }; - bool getFalseColored() { return false; }; - void setColor(const nodeColor& color) { memcpy(_trueColor,color,sizeof(nodeColor)); }; - void setDensity(const float density) { _density = density; }; - const nodeColor& getTrueColor() const { return _trueColor; }; - const nodeColor& getColor() const { return _trueColor; }; -#endif void setDensity(float density) { _density = density; } float getDensity() const { return _density; } @@ -147,10 +137,8 @@ private: int _childCount; /// Client and server, current child nodes set to non-null in _children, 4 bytes nodeColor _trueColor; /// Client and server, true color of this voxel, 4 bytes -#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color nodeColor _currentColor; /// Client only, false color of this voxel, 4 bytes bool _falseColored; /// Client only, is this voxel false colored, 1 bytes -#endif bool _isDirty; /// Client only, has this voxel changed since being rendered, 1 byte bool _shouldRender; /// Client only, should this voxel render at this time, 1 byte From 6fff53a2dc7ff8cbb13aeb08cbe6da84443e4f21 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 15 Oct 2013 14:43:51 -0700 Subject: [PATCH 07/22] next round of voxelnode size improvements --- interface/src/Application.cpp | 4 +- libraries/shared/src/OctalCode.cpp | 32 ++++---- libraries/shared/src/OctalCode.h | 25 +++--- .../src/VoxelPersistThread.cpp | 4 +- libraries/voxels/src/JurisdictionMap.cpp | 2 +- libraries/voxels/src/JurisdictionMap.h | 2 +- libraries/voxels/src/VoxelNode.cpp | 50 ++++++++++-- libraries/voxels/src/VoxelNode.h | 77 ++++++++++++++++--- libraries/voxels/src/VoxelTree.cpp | 6 +- libraries/voxels/src/VoxelTree.h | 4 +- 10 files changed, 149 insertions(+), 57 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6a6a9789a3..c1ef5d8ad9 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1392,13 +1392,13 @@ void Application::increaseVoxelSize() { const int MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE = 1500; struct SendVoxelsOperationArgs { - unsigned char* newBaseOctCode; + const unsigned char* newBaseOctCode; }; bool Application::sendVoxelsOperation(VoxelNode* node, void* extraData) { SendVoxelsOperationArgs* args = (SendVoxelsOperationArgs*)extraData; if (node->isColored()) { - unsigned char* nodeOctalCode = node->getOctalCode(); + const unsigned char* nodeOctalCode = node->getOctalCode(); unsigned char* codeColorBuffer = NULL; int codeLength = 0; diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index 8146924cf8..31eef196c4 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -16,7 +16,7 @@ #include "SharedUtil.h" #include "OctalCode.h" -int numberOfThreeBitSectionsInCode(unsigned char * octalCode) { +int numberOfThreeBitSectionsInCode(const unsigned char * octalCode) { assert(octalCode); if (*octalCode == 255) { return *octalCode + numberOfThreeBitSectionsInCode(octalCode + 1); @@ -25,7 +25,7 @@ int numberOfThreeBitSectionsInCode(unsigned char * octalCode) { } } -void printOctalCode(unsigned char * octalCode) { +void printOctalCode(const unsigned char * octalCode) { if (!octalCode) { qDebug("NULL\n"); } else { @@ -36,7 +36,7 @@ void printOctalCode(unsigned char * octalCode) { } } -char sectionValue(unsigned char * startByte, char startIndexInByte) { +char sectionValue(const unsigned char * startByte, char startIndexInByte) { char rightShift = 8 - startIndexInByte - 3; if (rightShift < 0) { @@ -54,14 +54,14 @@ int bytesRequiredForCodeLength(unsigned char threeBitCodes) { } } -int branchIndexWithDescendant(unsigned char * ancestorOctalCode, unsigned char * descendantOctalCode) { +int branchIndexWithDescendant(const unsigned char * ancestorOctalCode, const unsigned char * descendantOctalCode) { int parentSections = numberOfThreeBitSectionsInCode(ancestorOctalCode); int branchStartBit = parentSections * 3; return sectionValue(descendantOctalCode + 1 + (branchStartBit / 8), branchStartBit % 8); } -unsigned char * childOctalCode(unsigned char * parentOctalCode, char childNumber) { +unsigned char * childOctalCode(const unsigned char * parentOctalCode, char childNumber) { // find the length (in number of three bit code sequences) // in the parent @@ -115,7 +115,7 @@ unsigned char * childOctalCode(unsigned char * parentOctalCode, char childNumber return newCode; } -void voxelDetailsForCode(unsigned char * octalCode, VoxelPositionSize& voxelPositionSize) { +void voxelDetailsForCode(const unsigned char * octalCode, VoxelPositionSize& voxelPositionSize) { float output[3]; memset(&output[0], 0, 3 * sizeof(float)); float currentScale = 1.0; @@ -138,7 +138,7 @@ void voxelDetailsForCode(unsigned char * octalCode, VoxelPositionSize& voxelPosi voxelPositionSize.s = currentScale; } -void copyFirstVertexForCode(unsigned char * octalCode, float* output) { +void copyFirstVertexForCode(const unsigned char * octalCode, float* output) { memset(output, 0, 3 * sizeof(float)); float currentScale = 0.5; @@ -154,13 +154,13 @@ void copyFirstVertexForCode(unsigned char * octalCode, float* output) { } } -float * firstVertexForCode(unsigned char * octalCode) { +float * firstVertexForCode(const unsigned char * octalCode) { float * firstVertex = new float[3]; copyFirstVertexForCode(octalCode, firstVertex); return firstVertex; } -OctalCodeComparison compareOctalCodes(unsigned char* codeA, unsigned char* codeB) { +OctalCodeComparison compareOctalCodes(const unsigned char* codeA, const unsigned char* codeB) { if (!codeA || !codeB) { return ILLEGAL_CODE; } @@ -196,10 +196,10 @@ OctalCodeComparison compareOctalCodes(unsigned char* codeA, unsigned char* codeB } -char getOctalCodeSectionValue(unsigned char* octalCode, int section) { +char getOctalCodeSectionValue(const unsigned char* octalCode, int section) { int startAtByte = 1 + (BITS_IN_OCTAL * section / BITS_IN_BYTE); char startIndexInByte = (BITS_IN_OCTAL * section) % BITS_IN_BYTE; - unsigned char* startByte = octalCode + startAtByte; + const unsigned char* startByte = octalCode + startAtByte; return sectionValue(startByte, startIndexInByte); } @@ -243,7 +243,7 @@ void setOctalCodeSectionValue(unsigned char* octalCode, int section, char sectio } } -unsigned char* chopOctalCode(unsigned char* originalOctalCode, int chopLevels) { +unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLevels) { int codeLength = numberOfThreeBitSectionsInCode(originalOctalCode); unsigned char* newCode = NULL; if (codeLength > chopLevels) { @@ -259,7 +259,9 @@ unsigned char* chopOctalCode(unsigned char* originalOctalCode, int chopLevels) { return newCode; } -unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* newParentOctalCode, bool includeColorSpace) { +unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode, + bool includeColorSpace) { + int oldCodeLength = numberOfThreeBitSectionsInCode(originalOctalCode); int newParentCodeLength = numberOfThreeBitSectionsInCode(newParentOctalCode); int newCodeLength = newParentCodeLength + oldCodeLength; @@ -280,7 +282,7 @@ unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* return newCode; } -bool isAncestorOf(unsigned char* possibleAncestor, unsigned char* possibleDescendent, int descendentsChild) { +bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* possibleDescendent, int descendentsChild) { if (!possibleAncestor || !possibleDescendent) { return false; } @@ -350,7 +352,7 @@ unsigned char* hexStringToOctalCode(const QString& input) { return bytes; } -QString octalCodeToHexString(unsigned char* octalCode) { +QString octalCodeToHexString(const unsigned char* octalCode) { const int HEX_NUMBER_BASE = 16; const int HEX_BYTE_SIZE = 2; QString output; diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index 4a43142bb8..6fe6c66d91 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -20,27 +20,28 @@ const int RED_INDEX = 0; const int GREEN_INDEX = 1; const int BLUE_INDEX = 2; -void printOctalCode(unsigned char * octalCode); +void printOctalCode(const unsigned char * octalCode); int bytesRequiredForCodeLength(unsigned char threeBitCodes); -int branchIndexWithDescendant(unsigned char * ancestorOctalCode, unsigned char * descendantOctalCode); -unsigned char * childOctalCode(unsigned char * parentOctalCode, char childNumber); -int numberOfThreeBitSectionsInCode(unsigned char * octalCode); -unsigned char* chopOctalCode(unsigned char* originalOctalCode, int chopLevels); -unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* newParentOctalCode, +int branchIndexWithDescendant(const unsigned char * ancestorOctalCode, const unsigned char * descendantOctalCode); +unsigned char * childOctalCode(const unsigned char * parentOctalCode, char childNumber); +int numberOfThreeBitSectionsInCode(const unsigned char * octalCode); +unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLevels); +unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode, bool includeColorSpace = false); const int CHECK_NODE_ONLY = -1; -bool isAncestorOf(unsigned char* possibleAncestor, unsigned char* possibleDescendent, int descendentsChild = CHECK_NODE_ONLY); +bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* possibleDescendent, + int descendentsChild = CHECK_NODE_ONLY); // Note: copyFirstVertexForCode() is preferred because it doesn't allocate memory for the return // but other than that these do the same thing. -float * firstVertexForCode(unsigned char * octalCode); -void copyFirstVertexForCode(unsigned char * octalCode, float* output); +float * firstVertexForCode(const unsigned char * octalCode); +void copyFirstVertexForCode(const unsigned char * octalCode, float* output); struct VoxelPositionSize { float x, y, z, s; }; -void voxelDetailsForCode(unsigned char* octalCode, VoxelPositionSize& voxelPositionSize); +void voxelDetailsForCode(const unsigned char* octalCode, VoxelPositionSize& voxelPositionSize); typedef enum { ILLEGAL_CODE = -2, @@ -49,9 +50,9 @@ typedef enum { GREATER_THAN = 1 } OctalCodeComparison; -OctalCodeComparison compareOctalCodes(unsigned char* code1, unsigned char* code2); +OctalCodeComparison compareOctalCodes(const unsigned char* code1, const unsigned char* code2); -QString octalCodeToHexString(unsigned char* octalCode); +QString octalCodeToHexString(const unsigned char* octalCode); unsigned char* hexStringToOctalCode(const QString& input); #endif /* defined(__hifi__OctalCode__) */ diff --git a/libraries/voxel-server-library/src/VoxelPersistThread.cpp b/libraries/voxel-server-library/src/VoxelPersistThread.cpp index 7caa83c2d8..be530682c8 100644 --- a/libraries/voxel-server-library/src/VoxelPersistThread.cpp +++ b/libraries/voxel-server-library/src/VoxelPersistThread.cpp @@ -29,8 +29,8 @@ bool VoxelPersistThread::process() { _initialLoad = true; qDebug("loading voxels from file: %s...\n", _filename); - qDebug("sizeof(oldVoxelNode)=%ld sizeof(VoxelNode)=%ld sizeof(AABox)=%ld sizeof(oldAABox)=%ld\n", - sizeof(oldVoxelNode), sizeof(VoxelNode), sizeof(AABox), sizeof(oldAABox)); + qDebug("sizeof(oldVoxelNode)=%ld sizeof(VoxelNode)=%ld sizeof(smallerVoxelNodeTest1)=%ld sizeof(AABox)=%ld sizeof(oldAABox)=%ld\n", + sizeof(oldVoxelNode), sizeof(VoxelNode), sizeof(smallerVoxelNodeTest1), sizeof(AABox), sizeof(oldAABox)); bool persistantFileRead = _tree->readFromSVOFile(_filename); if (persistantFileRead) { diff --git a/libraries/voxels/src/JurisdictionMap.cpp b/libraries/voxels/src/JurisdictionMap.cpp index 94e589c801..3da1467f46 100644 --- a/libraries/voxels/src/JurisdictionMap.cpp +++ b/libraries/voxels/src/JurisdictionMap.cpp @@ -132,7 +132,7 @@ void JurisdictionMap::init(unsigned char* rootOctalCode, const std::vector sizeof(_octalCode)) { + _octalCode._octalCodePointer = octalCode; + _octcodePointer = true; + _octcodeMemoryUsage += octalCodeLength; + } else { + _octcodePointer = false; + memcpy(_octalCode._octalCodeBuffer, octalCode, octalCodeLength); + delete[] octalCode; + } #ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color _falseColored = false; // assume true color @@ -57,8 +66,9 @@ void VoxelNode::init(unsigned char * octalCode) { } _childCount = 0; - _glBufferIndex = GLBUFFER_INDEX_UNKNOWN; - _voxelSystem = NULL; + _unknownBufferIndex = true; + setBufferIndex(GLBUFFER_INDEX_UNKNOWN); + setVoxelSystem(NULL); _isDirty = true; _shouldRender = false; _sourceID = UNKNOWN_NODE_ID; @@ -66,21 +76,22 @@ void VoxelNode::init(unsigned char * octalCode) { markWithChangedTime(); _voxelMemoryUsage += sizeof(VoxelNode); - _octcodeMemoryUsage += bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(getOctalCode())); } VoxelNode::~VoxelNode() { notifyDeleteHooks(); _voxelMemoryUsage -= sizeof(VoxelNode); - _octcodeMemoryUsage -= bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(getOctalCode())); _voxelNodeCount--; if (isLeaf()) { _voxelNodeLeafCount--; } - delete[] _octalCode; + if (_octcodePointer) { + _octcodeMemoryUsage -= bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(getOctalCode())); + delete[] _octalCode._octalCodePointer; + } // delete all of this node's children for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { @@ -110,6 +121,31 @@ void VoxelNode::handleSubtreeChanged(VoxelTree* myTree) { markWithChangedTime(); } +uint8_t VoxelNode::_nextIndex = 0; +std::map VoxelNode::_mapVoxelSystemPointersToIndex; +std::map VoxelNode::_mapIndexToVoxelSystemPointers; + +VoxelSystem* VoxelNode::getVoxelSystem() const { + if (_mapIndexToVoxelSystemPointers.end() != _mapIndexToVoxelSystemPointers.find(_voxelSystemIndex)) { + return _mapIndexToVoxelSystemPointers[_voxelSystemIndex]; + } + return NULL; +} + +void VoxelNode::setVoxelSystem(VoxelSystem* voxelSystem) { + uint8_t index; + if (_mapVoxelSystemPointersToIndex.end() != _mapVoxelSystemPointersToIndex.find(voxelSystem)) { + index = _mapVoxelSystemPointersToIndex[voxelSystem]; + } else { + index = _nextIndex; + _nextIndex++; + _mapVoxelSystemPointersToIndex[voxelSystem] = index; + _mapIndexToVoxelSystemPointers[index] = voxelSystem; + } + _voxelSystemIndex = index; +} + + void VoxelNode::setShouldRender(bool shouldRender) { // if shouldRender is changing, then consider ourselves dirty if (shouldRender != _shouldRender) { @@ -170,7 +206,7 @@ VoxelNode* VoxelNode::addChildAtIndex(int childIndex) { } _children[childIndex] = new VoxelNode(childOctalCode(getOctalCode(), childIndex)); - _children[childIndex]->setVoxelSystem(_voxelSystem); // our child is always part of our voxel system NULL ok + _children[childIndex]->setVoxelSystem(getVoxelSystem()); // our child is always part of our voxel system NULL ok _isDirty = true; _childCount++; markWithChangedTime(); diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 884d79a632..4bfd75c692 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -41,7 +41,7 @@ public: VoxelNode(unsigned char * octalCode); // regular constructor ~VoxelNode(); - unsigned char* getOctalCode() const { return _octalCode; } + const unsigned char* getOctalCode() const { return (_octcodePointer) ? _octalCode._octalCodePointer : &_octalCode._octalCodeBuffer[0]; } VoxelNode* getChildAtIndex(int childIndex) const { return _children[childIndex]; } void deleteChildAtIndex(int childIndex); VoxelNode* removeChildAtIndex(int childIndex); @@ -83,11 +83,10 @@ public: void handleSubtreeChanged(VoxelTree* myTree); glBufferIndex getBufferIndex() const { return _glBufferIndex; } - bool isKnownBufferIndex() const { return (_glBufferIndex != GLBUFFER_INDEX_UNKNOWN); } - void setBufferIndex(glBufferIndex index) { _glBufferIndex = index; } - VoxelSystem* getVoxelSystem() const { return _voxelSystem; } - void setVoxelSystem(VoxelSystem* voxelSystem) { _voxelSystem = voxelSystem; } - + bool isKnownBufferIndex() const { return !_unknownBufferIndex; } + void setBufferIndex(glBufferIndex index) { _glBufferIndex = index; _unknownBufferIndex =(index == GLBUFFER_INDEX_UNKNOWN);} + VoxelSystem* getVoxelSystem() const; + void setVoxelSystem(VoxelSystem* voxelSystem); // Used by VoxelSystem for rendering in/out of view and LOD void setShouldRender(bool shouldRender); @@ -125,25 +124,37 @@ private: void notifyUpdateHooks(); VoxelNode* _children[8]; /// Client and server, pointers to child nodes, 64 bytes + AABox _box; /// Client and server, axis aligned box for bounds of this voxel, 48 bytes - unsigned char* _octalCode; /// Client and server, pointer to octal code for this node, 8 bytes + + /// Client and server, buffer containing the octal code or a pointer to octal code for this node, 8 bytes + union octalCode_t { + unsigned char _octalCodeBuffer[8]; + unsigned char* _octalCodePointer; + } _octalCode; uint64_t _lastChanged; /// Client and server, timestamp this node was last changed, 8 bytes - glBufferIndex _glBufferIndex; /// Client only, vbo index for this voxel if being rendered, 8 bytes - VoxelSystem* _voxelSystem; /// Client only, pointer to VoxelSystem rendering this voxel, 8 bytes + uint32_t _glBufferIndex : 24, /// Client only, vbo index for this voxel if being rendered, 3 bytes + _voxelSystemIndex : 8; /// Client only, index to the VoxelSystem rendering this voxel, 1 bytes + + static uint8_t _nextIndex; + static std::map _mapVoxelSystemPointersToIndex; + static std::map _mapIndexToVoxelSystemPointers; float _density; /// Client and server, If leaf: density = 1, if internal node: 0-1 density of voxels inside, 4 bytes int _childCount; /// Client and server, current child nodes set to non-null in _children, 4 bytes nodeColor _trueColor; /// Client and server, true color of this voxel, 4 bytes nodeColor _currentColor; /// Client only, false color of this voxel, 4 bytes - bool _falseColored; /// Client only, is this voxel false colored, 1 bytes - bool _isDirty; /// Client only, has this voxel changed since being rendered, 1 byte - bool _shouldRender; /// Client only, should this voxel render at this time, 1 byte uint16_t _sourceID; /// Client only, stores node id of voxel server that sent his voxel, 2 bytes + bool _falseColored : 1, /// Client only, is this voxel false colored, 1 bit + _isDirty : 1, /// Client only, has this voxel changed since being rendered, 1 bit + _shouldRender : 1, /// Client only, should this voxel render at this time, 1 bit + _octcodePointer : 1, /// Client and Server only, is this voxel's octal code a pointer or buffer, 1 bit + _unknownBufferIndex : 1; /// Client only, is this voxel's VBO buffer the unknown buffer index, 1 bit static std::vector _deleteHooks; static std::vector _updateHooks; @@ -181,4 +192,46 @@ public: bool _shouldRender; /// Client only, should this voxel render at this time, 1 byte uint16_t _sourceID; /// Client only, stores node id of voxel server that sent his voxel, 2 bytes }; + +class smallerVoxelNodeTest1 { +public: + AABox _box; // 48 bytes - 4x glm::vec3, 3 floats x 4 bytes = 48 bytes + // 16 bytes... 1x glm::vec3 + 1 float + + union octalCode_t { + unsigned char _octalCodeBuffer[8]; + unsigned char* _octalCodePointer; + } _octalCode; /// Client and server, buffer containing the octal code if it's smaller than 8 bytes or a + /// pointer to octal code for this node, 8 bytes + + + uint32_t _glBufferIndex : 24, /// Client only, vbo index for this voxel if being rendered, 3 bytes + _voxelSystemIndex : 8; /// Client only, index to the VoxelSystem rendering this voxel, 1 bytes + + + uint64_t _lastChanged; // 8 bytes, could be less? + + void* _children; // 8 bytes (for 0 or 1 children), or 8 bytes * count + 1 + + + nodeColor _trueColor; // 4 bytes, could be 3 bytes + 1 bit + nodeColor _currentColor; // 4 bytes ** CLIENT ONLY ** + + + float _density; // 4 bytes - If leaf: density = 1, if internal node: 0-1 density of voxels inside... 4 bytes? do we need this? + // could make this 1 or 2 byte linear ratio... + + + uint16_t _sourceID; // 2 bytes - only used to colorize and kill sources? ** CLIENT ONLY ** + + unsigned char _childBitmask; // 1 byte + + // Bitmask.... // 1 byte... made up of 5 bits so far... room for 3 more bools... + unsigned char _falseColored : 1, // 1 bit + _shouldRender : 1, // 1 bit + _isDirty : 1, // 1 bit + _octcodePointer : 1, // 1 bit + _unknownBufferIndex : 1; // 1 bit + +}; #endif /* defined(__hifi__VoxelNode__) */ \ No newline at end of file diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index ff51cd3044..6b247b70bf 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -134,7 +134,7 @@ void VoxelTree::recurseNodeWithOperationDistanceSorted(VoxelNode* node, RecurseV VoxelNode* VoxelTree::nodeForOctalCode(VoxelNode* ancestorNode, - unsigned char* needleCode, VoxelNode** parentOfFoundNode) const { + const unsigned char* needleCode, VoxelNode** parentOfFoundNode) const { // find the appropriate branch index based on this ancestorNode if (*needleCode > 0) { int branchForNeedle = branchIndexWithDescendant(ancestorNode->getOctalCode(), needleCode); @@ -1978,7 +1978,7 @@ bool VoxelTree::nudgeCheck(VoxelNode* node, void* extraData) { NodeChunkArgs* args = (NodeChunkArgs*)extraData; // get octal code of this node - unsigned char* octalCode = node->getOctalCode(); + const unsigned char* octalCode = node->getOctalCode(); // get voxel position/size VoxelPositionSize unNudgedDetails; @@ -2017,7 +2017,7 @@ void VoxelTree::nudgeLeaf(VoxelNode* node, void* extraData) { NodeChunkArgs* args = (NodeChunkArgs*)extraData; // get octal code of this node - unsigned char* octalCode = node->getOctalCode(); + const unsigned char* octalCode = node->getOctalCode(); // get voxel position/size VoxelPositionSize unNudgedDetails; diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 318b8fc5eb..9e9f972494 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -214,7 +214,7 @@ private: static bool countVoxelsOperation(VoxelNode* node, void* extraData); - VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode) const; + VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, const unsigned char* needleCode, VoxelNode** parentOfFoundNode) const; VoxelNode* createMissingNode(VoxelNode* lastParentNode, unsigned char* deepestCodeToCreate); int readNodeData(VoxelNode *destinationNode, unsigned char* nodeData, int bufferSizeBytes, ReadBitstreamToTreeParams& args); @@ -225,7 +225,7 @@ private: /// Octal Codes of any subtrees currently being encoded. While any of these codes is being encoded, ancestors and /// descendants of them can not be deleted. - std::set _codesBeingEncoded; + std::set _codesBeingEncoded; /// mutex lock to protect the encoding set pthread_mutex_t _encodeSetLock; From afcf6dd3e0cf1b6ebcfe774470a5076d464d9d0f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 15 Oct 2013 18:28:56 -0700 Subject: [PATCH 08/22] type squish --- libraries/shared/src/OctalCode.cpp | 20 ++++++++++---------- libraries/shared/src/OctalCode.h | 12 ++++++------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index 31eef196c4..80f6ba121f 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -16,7 +16,7 @@ #include "SharedUtil.h" #include "OctalCode.h" -int numberOfThreeBitSectionsInCode(const unsigned char * octalCode) { +int numberOfThreeBitSectionsInCode(const unsigned char* octalCode) { assert(octalCode); if (*octalCode == 255) { return *octalCode + numberOfThreeBitSectionsInCode(octalCode + 1); @@ -25,18 +25,18 @@ int numberOfThreeBitSectionsInCode(const unsigned char * octalCode) { } } -void printOctalCode(const unsigned char * octalCode) { +void printOctalCode(const unsigned char* octalCode) { if (!octalCode) { qDebug("NULL\n"); } else { - for (int i = 0; i < bytesRequiredForCodeLength(*octalCode); i++) { + for (int i = 0; i < bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(octalCode)); i++) { outputBits(octalCode[i],false); } qDebug("\n"); } } -char sectionValue(const unsigned char * startByte, char startIndexInByte) { +char sectionValue(const unsigned char* startByte, char startIndexInByte) { char rightShift = 8 - startIndexInByte - 3; if (rightShift < 0) { @@ -54,14 +54,14 @@ int bytesRequiredForCodeLength(unsigned char threeBitCodes) { } } -int branchIndexWithDescendant(const unsigned char * ancestorOctalCode, const unsigned char * descendantOctalCode) { +int branchIndexWithDescendant(const unsigned char* ancestorOctalCode, const unsigned char* descendantOctalCode) { int parentSections = numberOfThreeBitSectionsInCode(ancestorOctalCode); int branchStartBit = parentSections * 3; return sectionValue(descendantOctalCode + 1 + (branchStartBit / 8), branchStartBit % 8); } -unsigned char * childOctalCode(const unsigned char * parentOctalCode, char childNumber) { +unsigned char* childOctalCode(const unsigned char* parentOctalCode, char childNumber) { // find the length (in number of three bit code sequences) // in the parent @@ -76,7 +76,7 @@ unsigned char * childOctalCode(const unsigned char * parentOctalCode, char child int childCodeBytes = bytesRequiredForCodeLength(parentCodeSections + 1); // create a new buffer to hold the new octal code - unsigned char *newCode = new unsigned char[childCodeBytes]; + unsigned char* newCode = new unsigned char[childCodeBytes]; // copy the parent code to the child if (parentOctalCode != NULL) { @@ -115,7 +115,7 @@ unsigned char * childOctalCode(const unsigned char * parentOctalCode, char child return newCode; } -void voxelDetailsForCode(const unsigned char * octalCode, VoxelPositionSize& voxelPositionSize) { +void voxelDetailsForCode(const unsigned char* octalCode, VoxelPositionSize& voxelPositionSize) { float output[3]; memset(&output[0], 0, 3 * sizeof(float)); float currentScale = 1.0; @@ -138,7 +138,7 @@ void voxelDetailsForCode(const unsigned char * octalCode, VoxelPositionSize& vox voxelPositionSize.s = currentScale; } -void copyFirstVertexForCode(const unsigned char * octalCode, float* output) { +void copyFirstVertexForCode(const unsigned char* octalCode, float* output) { memset(output, 0, 3 * sizeof(float)); float currentScale = 0.5; @@ -154,7 +154,7 @@ void copyFirstVertexForCode(const unsigned char * octalCode, float* output) { } } -float * firstVertexForCode(const unsigned char * octalCode) { +float * firstVertexForCode(const unsigned char* octalCode) { float * firstVertex = new float[3]; copyFirstVertexForCode(octalCode, firstVertex); return firstVertex; diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index 6fe6c66d91..27746474eb 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -20,11 +20,11 @@ const int RED_INDEX = 0; const int GREEN_INDEX = 1; const int BLUE_INDEX = 2; -void printOctalCode(const unsigned char * octalCode); +void printOctalCode(const unsigned char* octalCode); int bytesRequiredForCodeLength(unsigned char threeBitCodes); -int branchIndexWithDescendant(const unsigned char * ancestorOctalCode, const unsigned char * descendantOctalCode); -unsigned char * childOctalCode(const unsigned char * parentOctalCode, char childNumber); -int numberOfThreeBitSectionsInCode(const unsigned char * octalCode); +int branchIndexWithDescendant(const unsigned char* ancestorOctalCode, const unsigned char* descendantOctalCode); +unsigned char* childOctalCode(const unsigned char* parentOctalCode, char childNumber); +int numberOfThreeBitSectionsInCode(const unsigned char* octalCode); unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLevels); unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode, bool includeColorSpace = false); @@ -35,8 +35,8 @@ bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* po // Note: copyFirstVertexForCode() is preferred because it doesn't allocate memory for the return // but other than that these do the same thing. -float * firstVertexForCode(const unsigned char * octalCode); -void copyFirstVertexForCode(const unsigned char * octalCode, float* output); +float * firstVertexForCode(const unsigned char* octalCode); +void copyFirstVertexForCode(const unsigned char* octalCode, float* output); struct VoxelPositionSize { float x, y, z, s; From 1e5ce8a7e5d642e85fde953f146f898100f7fa5a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 16 Oct 2013 12:54:37 -0700 Subject: [PATCH 09/22] first cut at really getting _children UNION to work --- libraries/shared/src/PerfStat.cpp | 3 + libraries/shared/src/PerfStat.h | 9 +- libraries/shared/src/SharedUtil.cpp | 37 ++ libraries/shared/src/SharedUtil.h | 6 +- .../src/VoxelSendThread.cpp | 13 + libraries/voxels/src/VoxelNode.cpp | 497 ++++++++++++++++-- libraries/voxels/src/VoxelNode.h | 48 +- voxel-edit/src/main.cpp | 44 +- 8 files changed, 597 insertions(+), 60 deletions(-) diff --git a/libraries/shared/src/PerfStat.cpp b/libraries/shared/src/PerfStat.cpp index 961e24744f..267108f87e 100644 --- a/libraries/shared/src/PerfStat.cpp +++ b/libraries/shared/src/PerfStat.cpp @@ -132,6 +132,9 @@ PerformanceWarning::~PerformanceWarning() { if (_runningTotal) { *_runningTotal += elapsedusec; } + if (_totalCalls) { + *_totalCalls += 1; + } }; diff --git a/libraries/shared/src/PerfStat.h b/libraries/shared/src/PerfStat.h index 3343c9fd62..e460548f1d 100644 --- a/libraries/shared/src/PerfStat.h +++ b/libraries/shared/src/PerfStat.h @@ -90,15 +90,18 @@ private: bool _renderWarningsOn; bool _alwaysDisplay; uint64_t* _runningTotal; + uint64_t* _totalCalls; static bool _suppressShortTimings; public: - PerformanceWarning(bool renderWarnings, const char* message, bool alwaysDisplay = false, uint64_t* runningTotal = NULL) : + + PerformanceWarning(bool renderWarnings, const char* message, bool alwaysDisplay = false, uint64_t* runningTotal = NULL, uint64_t* totalCalls = NULL) : _start(usecTimestampNow()), _message(message), _renderWarningsOn(renderWarnings), _alwaysDisplay(alwaysDisplay), - _runningTotal(runningTotal) { } - + _runningTotal(runningTotal), + _totalCalls(totalCalls) { } + ~PerformanceWarning(); static void setSuppressShortTimings(bool suppressShortTimings) { _suppressShortTimings = suppressShortTimings; } diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 359a154c4f..9708b0c95a 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -105,10 +105,47 @@ void setAtBit(unsigned char& byte, int bitIndex) { byte += (1 << (7 - bitIndex)); } +void clearAtBit(unsigned char& byte, int bitIndex) { + //printf("clearAtBit() bitIndex=%d byte=",bitIndex); + //outputBits(byte); + + if (oneAtBit(byte, bitIndex)) { + byte -= (1 << (7 - bitIndex)); + } + + //printf("... now byte="); + //outputBits(byte); +} + int getSemiNibbleAt(unsigned char& byte, int bitIndex) { return (byte >> (6 - bitIndex) & 3); // semi-nibbles store 00, 01, 10, or 11 } +int getNthBit(unsigned char byte, int ordinal) { + const int ERROR = -1; + const int MIN_ORDINAL = 1; + const int MAX_ORDINAL = 8; + if (ordinal < MIN_ORDINAL || ordinal > MAX_ORDINAL) { + return ERROR; + } + int bitsSet = 0; + for (int bitIndex = 0; bitIndex < MAX_ORDINAL; bitIndex++) { + if (oneAtBit(byte, bitIndex)) { + bitsSet++; + } + if (bitsSet == ordinal) { + return bitIndex; + } + } + return ERROR; +} + +bool isBetween(int64_t value, int64_t max, int64_t min) { + return ((value <= max) && (value >= min)); +} + + + void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value) { //assert(value <= 3 && value >= 0); byte += ((value & 3) << (6 - bitIndex)); // semi-nibbles store 00, 01, 10, or 11 diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 77c9cdd040..ece63d4737 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -55,10 +55,12 @@ void printVoxelCode(unsigned char* voxelCode); int numberOfOnes(unsigned char byte); bool oneAtBit(unsigned char byte, int bitIndex); void setAtBit(unsigned char& byte, int bitIndex); - +void clearAtBit(unsigned char& byte, int bitIndex); int getSemiNibbleAt(unsigned char& byte, int bitIndex); void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value); +int getNthBit(unsigned char byte, int ordinal); /// determines the bit placement 0-7 of the ordinal set bit + bool isInEnvironment(const char* environment); void switchToResourcesParentIfRequired(); @@ -109,4 +111,6 @@ public: static const char* valueOf(bool checkValue) { return checkValue ? "yes" : "no"; } }; +bool isBetween(int64_t value, int64_t max, int64_t min); + #endif /* defined(__hifi__SharedUtil__) */ diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 961712a46f..cb1b78134d 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -52,6 +52,19 @@ bool VoxelSendThread::process() { std::cout << "Last send took too much time, not sleeping!\n"; } } + + // debug some timing... + //uint64_t VoxelNode::_getChildAtIndexTime; + //uint64_t VoxelNode::_getChildAtIndexCalls; + //uint64_t VoxelNode::_setChildAtIndexTime; + //uint64_t VoxelNode::_setChildAtIndexCalls; + + double usecPerGet = (double)VoxelNode::_getChildAtIndexTime / (double)VoxelNode::_getChildAtIndexCalls; + double usecPerSet = (double)VoxelNode::_setChildAtIndexTime / (double)VoxelNode::_setChildAtIndexCalls; + + printf("_getChildAtIndexCalls=%llu, _getChildAtIndexTime=%llu, perGet=%lf ... _setChildAtIndexCalls=%llu _setChildAtIndexTime=%llu perSet=%lf\n", + VoxelNode::_getChildAtIndexCalls, VoxelNode::_getChildAtIndexTime, usecPerGet, + VoxelNode::_setChildAtIndexCalls, VoxelNode::_setChildAtIndexTime, usecPerSet); return isStillRunning(); // keep running till they terminate us } diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index b68334d4db..71d5a386de 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -13,6 +13,7 @@ #include #include +#include #include "AABox.h" #include "OctalCode.h" @@ -44,12 +45,12 @@ VoxelNode::VoxelNode(unsigned char * octalCode) { void VoxelNode::init(unsigned char * octalCode) { int octalCodeLength = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(octalCode)); if (octalCodeLength > sizeof(_octalCode)) { - _octalCode._octalCodePointer = octalCode; + _octalCode.pointer = octalCode; _octcodePointer = true; _octcodeMemoryUsage += octalCodeLength; } else { _octcodePointer = false; - memcpy(_octalCode._octalCodeBuffer, octalCode, octalCodeLength); + memcpy(_octalCode.buffer, octalCode, octalCodeLength); delete[] octalCode; } @@ -59,12 +60,17 @@ void VoxelNode::init(unsigned char * octalCode) { #endif _trueColor[0] = _trueColor[1] = _trueColor[2] = _trueColor[3] = 0; _density = 0.0f; + + // set up the _children union + _childBitmask = 0; + _childrenExternal = false; + _children.external = NULL; // default pointers to child nodes to NULL for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - _children[i] = NULL; + _childrenArray[i] = NULL; } - _childCount = 0; + _unknownBufferIndex = true; setBufferIndex(GLBUFFER_INDEX_UNKNOWN); @@ -90,13 +96,15 @@ VoxelNode::~VoxelNode() { if (_octcodePointer) { _octcodeMemoryUsage -= bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(getOctalCode())); - delete[] _octalCode._octalCodePointer; + delete[] _octalCode.pointer; } // delete all of this node's children for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - if (_children[i]) { - delete _children[i]; + VoxelNode* childAt = getChildAtIndex(i); + if (childAt) { + delete childAt; + setChildAtIndex(i, NULL); } } } @@ -121,28 +129,35 @@ void VoxelNode::handleSubtreeChanged(VoxelTree* myTree) { markWithChangedTime(); } -uint8_t VoxelNode::_nextIndex = 0; +const uint8_t INDEX_FOR_NULL = 0; +uint8_t VoxelNode::_nextIndex = INDEX_FOR_NULL + 1; // start at 1, 0 is reserved for NULL std::map VoxelNode::_mapVoxelSystemPointersToIndex; std::map VoxelNode::_mapIndexToVoxelSystemPointers; VoxelSystem* VoxelNode::getVoxelSystem() const { - if (_mapIndexToVoxelSystemPointers.end() != _mapIndexToVoxelSystemPointers.find(_voxelSystemIndex)) { - return _mapIndexToVoxelSystemPointers[_voxelSystemIndex]; + if (_voxelSystemIndex > INDEX_FOR_NULL) { + if (_mapIndexToVoxelSystemPointers.end() != _mapIndexToVoxelSystemPointers.find(_voxelSystemIndex)) { + return _mapIndexToVoxelSystemPointers[_voxelSystemIndex]; + } } return NULL; } void VoxelNode::setVoxelSystem(VoxelSystem* voxelSystem) { - uint8_t index; - if (_mapVoxelSystemPointersToIndex.end() != _mapVoxelSystemPointersToIndex.find(voxelSystem)) { - index = _mapVoxelSystemPointersToIndex[voxelSystem]; + if (voxelSystem == NULL) { + _voxelSystemIndex = INDEX_FOR_NULL; } else { - index = _nextIndex; - _nextIndex++; - _mapVoxelSystemPointersToIndex[voxelSystem] = index; - _mapIndexToVoxelSystemPointers[index] = voxelSystem; + uint8_t index; + if (_mapVoxelSystemPointersToIndex.end() != _mapVoxelSystemPointersToIndex.find(voxelSystem)) { + index = _mapVoxelSystemPointersToIndex[voxelSystem]; + } else { + index = _nextIndex; + _nextIndex++; + _mapVoxelSystemPointersToIndex[voxelSystem] = index; + _mapIndexToVoxelSystemPointers[index] = voxelSystem; + } + _voxelSystemIndex = index; } - _voxelSystemIndex = index; } @@ -167,11 +182,13 @@ void VoxelNode::calculateAABox() { } void VoxelNode::deleteChildAtIndex(int childIndex) { - if (_children[childIndex]) { - delete _children[childIndex]; - _children[childIndex] = NULL; + //printf("deleteChildAtIndex(%d)\n",childIndex); + + VoxelNode* childAt = getChildAtIndex(childIndex); + if (childAt) { + delete childAt; + setChildAtIndex(childIndex, NULL); _isDirty = true; - _childCount--; markWithChangedTime(); // after deleting the child, check to see if we're a leaf @@ -179,15 +196,16 @@ void VoxelNode::deleteChildAtIndex(int childIndex) { _voxelNodeLeafCount++; } } + + auditChildren("deleteChildAtIndex()"); } // does not delete the node! VoxelNode* VoxelNode::removeChildAtIndex(int childIndex) { - VoxelNode* returnedChild = _children[childIndex]; - if (_children[childIndex]) { - _children[childIndex] = NULL; + VoxelNode* returnedChild = getChildAtIndex(childIndex); + if (returnedChild) { + setChildAtIndex(childIndex, NULL); _isDirty = true; - _childCount--; markWithChangedTime(); // after removing the child, check to see if we're a leaf @@ -195,23 +213,409 @@ VoxelNode* VoxelNode::removeChildAtIndex(int childIndex) { _voxelNodeLeafCount++; } } + auditChildren("removeChildAtIndex()"); return returnedChild; } +void VoxelNode::auditChildren(const char* label) const { + return; + + bool auditFailed = false; + for (int childIndex = 0; childIndex < NUMBER_OF_CHILDREN; childIndex++) { + VoxelNode* testChildNew = __new__getChildAtIndex(childIndex); + VoxelNode* testChildOld = _childrenArray[childIndex]; + + if (testChildNew != testChildOld) { + auditFailed = true; + } + } + + if (auditFailed) { + printf("%s... auditChildren() FAILED <<<< \n", label); + for (int childIndex = 0; childIndex < NUMBER_OF_CHILDREN; childIndex++) { + VoxelNode* testChildNew = __new__getChildAtIndex(childIndex); + VoxelNode* testChildOld = _childrenArray[childIndex]; + + printf("child at index %d... testChildOld=%p testChildNew=%p %s \n", + childIndex, testChildOld, testChildNew , + ((testChildNew != testChildOld) ? " DOES NOT MATCH <<<< BAD <<<<" : " - OK ") + ); + } + printf("%s... auditChildren() <<<< DONE <<<< \n", label); + } + +} + +uint64_t VoxelNode::_getChildAtIndexTime = 0; +uint64_t VoxelNode::_getChildAtIndexCalls = 0; +uint64_t VoxelNode::_setChildAtIndexTime = 0; +uint64_t VoxelNode::_setChildAtIndexCalls = 0; + +VoxelNode* VoxelNode::getChildAtIndex(int childIndex) const { + PerformanceWarning warn(false,"getChildAtIndex",false,&_getChildAtIndexTime,&_getChildAtIndexCalls); + + VoxelNode* child = __new__getChildAtIndex(childIndex); + //VoxelNode* child = _childrenArray[childIndex]; /// *** OLD WAY **** + return child; +} + +VoxelNode* VoxelNode::__new__getChildAtIndex(int childIndex) const { + VoxelNode* result = NULL; + int childCount = getChildCount(); + switch (childCount) { + case 0: + break; + case 1: { + int indexOne = getNthBit(_childBitmask, 1); + if (indexOne == childIndex) { + result = _children.single; + } + } break; + case 2: { + int indexOne = getNthBit(_childBitmask, 1); + int indexTwo = getNthBit(_childBitmask, 2); + + if (_childrenExternal) { + if (indexOne == childIndex) { + result = _children.external[0]; + } else if (indexTwo == childIndex) { + result = _children.external[1]; + } + } else { + if (indexOne == childIndex) { + int32_t offset = _children.offsetsTwoChildren[0]; + result = (VoxelNode*)((uint8_t*)this + offset); + } else if (indexTwo == childIndex) { + int32_t offset = _children.offsetsTwoChildren[1]; + result = (VoxelNode*)((uint8_t*)this + offset); + } + } + } break; + default: { + // if we have 3 or more, we know we're in external mode, so we just need to figure out which + // slot in our external array this child is. + if (oneAtBit(_childBitmask, childIndex)) { + childCount = getChildCount(); + for (int ordinal = 1; ordinal <= childCount; ordinal++) { + int index = getNthBit(_childBitmask, ordinal); + if (index == childIndex) { + result = _children.external[ordinal-1]; + break; + } + } + } + } break; + } + return result; +} + +void VoxelNode::storeTwoChildren(VoxelNode* childOne, VoxelNode* childTwo) { + int64_t offsetOne = (uint8_t*)childOne - (uint8_t*)this; + int64_t offsetTwo = (uint8_t*)childTwo - (uint8_t*)this; + + if (isBetween(offsetOne, std::numeric_limits::max(), std::numeric_limits::min()) && + isBetween(offsetTwo, std::numeric_limits::max(), std::numeric_limits::min())) { + + // if previously external, then clean it up... + if (_childrenExternal) { + delete[] _children.external; + _children.external = NULL; // probably not needed! + _childrenExternal = false; + } + + // encode in union + _children.offsetsTwoChildren[0] = offsetOne; + _children.offsetsTwoChildren[1] = offsetTwo; + } else { + // encode in array + + // if not previously external, then allocate appropriately + if (!_childrenExternal) { + _childrenExternal = true; + _children.external = new VoxelNode*[2]; + } + _children.external[0] = childOne; + _children.external[1] = childTwo; + } +} + +void VoxelNode::retrieveTwoChildren(VoxelNode*& childOne, VoxelNode*& childTwo) { + // If we previously had an external array, then get the + if (_childrenExternal) { + childOne = _children.external[0]; + childTwo = _children.external[1]; + delete[] _children.external; + _children.external = NULL; // probably not needed! + _childrenExternal = false; + } else { + int64_t offsetOne = _children.offsetsTwoChildren[0]; + int64_t offsetTwo = _children.offsetsTwoChildren[1]; + + childOne = (VoxelNode*)((uint8_t*)this + offsetOne); + childTwo = (VoxelNode*)((uint8_t*)this + offsetTwo); + } +} + +void VoxelNode::setChildAtIndex(int childIndex, VoxelNode* child) { + PerformanceWarning warn(false,"setChildAtIndex",false,&_setChildAtIndexTime,&_setChildAtIndexCalls); + __new__setChildAtIndex(childIndex, child); + + /** OLD WAY **** + _childrenArray[childIndex] = child; + if (child) { + setAtBit(_childBitmask, childIndex); + } else { + clearAtBit(_childBitmask, childIndex); + } + **/ +} + +void VoxelNode::__new__setChildAtIndex(int childIndex, VoxelNode* child) { + // Here's how we store things... + // If we have 0 or 1 children, then we just store them in the _children.single; + // If we have 2 children, + // then if we can we store them as 32 bit signed offsets from our own this pointer, + // _children.offsetsTwoChildren[0]-[1] + // these are 32 bit offsets + + unsigned char previousChildMask = _childBitmask; + int previousChildCount = getChildCount(); + if (child) { + setAtBit(_childBitmask, childIndex); + } else { + clearAtBit(_childBitmask, childIndex); + } + int newChildCount = getChildCount(); + + // If we had 0 children and we still have 0 children, then there is nothing to do. + if (previousChildCount == 0 && newChildCount == 0) { + // nothing to do... + } else if ((previousChildCount == 0 || previousChildCount == 1) && newChildCount == 1) { + // If we had 0 children, and we're setting our first child or if we had 1 child, or we're resetting the same child, + // then we can just store it in _children.single + _children.single = child; + } else if (previousChildCount == 1 && newChildCount == 0) { + // If we had 1 child, and we've removed our last child, then we can just store NULL in _children.single + _children.single = NULL; + } else if (previousChildCount == 1 && newChildCount == 2) { + // If we had 1 child, and we're adding a second child, then we need to determine + // if we can use offsets to store them + + VoxelNode* childOne; + VoxelNode* childTwo; + + if (getNthBit(previousChildMask, 1) < childIndex) { + childOne = _children.single; + childTwo = child; + } else { + childOne = child; + childTwo = _children.single; + } + + storeTwoChildren(childOne, childTwo); + + } else if (previousChildCount == 2 && newChildCount == 1) { + // If we had 2 children, and we're removing one, then we know we can go down to single mode + assert(child == NULL); // this is the only logical case + + int indexTwo = getNthBit(previousChildMask, 2); + bool keepChildOne = indexTwo == childIndex; + + VoxelNode* childOne; + VoxelNode* childTwo; + + retrieveTwoChildren(childOne, childTwo); + + if (keepChildOne) { + _children.single = childOne; + } else { + _children.single = childTwo; + } + } else if (previousChildCount == 2 && newChildCount == 2) { + // If we had 2 children, and still have 2, then we know we are resetting one of our existing children + + int indexOne = getNthBit(previousChildMask, 1); + bool replaceChildOne = indexOne == childIndex; + + // If we previously had an external array, then just replace the right one... that's easy. + if (_childrenExternal) { + // technically, we could look to see if these are now in the offsets to handle be encoded, but + // we're going to go ahead and keep this as an array. + if (replaceChildOne) { + _children.external[0] = child; + } else { + _children.external[1] = child; + } + } else { + // If we were previously encoded as offsets, then we need to see if we can still encode as offsets + VoxelNode* childOne; + VoxelNode* childTwo; + + if (replaceChildOne) { + childOne = child; + childTwo = (VoxelNode*)((uint8_t*)this + _children.offsetsTwoChildren[1]); + } else { + childOne = (VoxelNode*)((uint8_t*)this + _children.offsetsTwoChildren[0]); + childTwo = child; + } + + storeTwoChildren(childOne, childTwo); + } + } else if (previousChildCount == 3 && newChildCount == 2) { + // If we had 3 children, and now have 2, then we know we are going from an external case to a potential internal case + assert(_childrenExternal); + + // We need to determine which children we had, and which one we got rid of... + int indexOne = getNthBit(previousChildMask, 1); + int indexTwo = getNthBit(previousChildMask, 2); + int indexThree = getNthBit(previousChildMask, 3); + + bool removeChildOne = indexOne == childIndex; + bool removeChildTwo = indexTwo == childIndex; + bool removeChildThree = indexThree == childIndex; + + VoxelNode* childOne = _children.external[0]; + VoxelNode* childTwo = _children.external[1]; + VoxelNode* childThree = _children.external[2]; + + if (removeChildOne) { + childOne = childTwo; + childTwo = childThree; + } else if (removeChildTwo) { + childTwo = childThree; + } else { + // removing child three, nothing to do. + } + + // clean up the external children... + _childrenExternal = false; + delete[] _children.external; + _children.external = NULL; + + storeTwoChildren(childOne, childTwo); + + } else if (previousChildCount == 2 && newChildCount == 3) { + // If we had 2 children, and now have 3, then we know we are going to an external case... + + // First, decode the children... + VoxelNode* childOne; + VoxelNode* childTwo; + VoxelNode* childThree; + + // Get the existing two children out of their encoding... + retrieveTwoChildren(childOne, childTwo); + + // now, allocate the external... + _childrenExternal = true; + _children.external = new VoxelNode*[3]; + + // determine order of the existing children + int indexOne = getNthBit(previousChildMask, 1); + int indexTwo = getNthBit(previousChildMask, 2); + + if (childIndex < indexOne) { + childThree = childTwo; + childTwo = childOne; + childOne = child; + } else if (childIndex < indexTwo) { + childThree = childTwo; + childTwo = child; + } else { + childThree = child; + } + + _children.external[0] = childOne; + _children.external[1] = childTwo; + _children.external[2] = childThree; + + } else if (previousChildCount == newChildCount) { + // 3 or more children, one item being replaced, we know we're stored externally, we just need to find the one + // that needs to be replaced and replace it. + for (int ordinal = 1; ordinal <= 8; ordinal++) { + int index = getNthBit(previousChildMask, ordinal); + if (index == childIndex) { + // this is our child to be replaced + int nthChild = ordinal-1; + _children.external[nthChild] = child; + break; + } + } + } else if (previousChildCount < newChildCount) { + // 3 or more children, one item being added, we know we're stored externally, we just figure out where to insert + // this child pointer into our external list + VoxelNode** newExternalList = new VoxelNode*[newChildCount]; + + int copiedCount = 0; + for (int ordinal = 1; ordinal <= newChildCount; ordinal++) { + int index = getNthBit(previousChildMask, ordinal); + if (index != -1 && index < childIndex) { + newExternalList[ordinal - 1] = _children.external[ordinal - 1]; + copiedCount++; + } else { + + // insert our new child here... + newExternalList[ordinal - 1] = child; + + // if we didn't copy all of our previous children, then we need to + if (copiedCount < previousChildCount) { + // our child needs to be inserted before this index, and everything else pushed out... + for (int oldOrdinal = ordinal; oldOrdinal <= previousChildCount; oldOrdinal++) { + newExternalList[oldOrdinal] = _children.external[oldOrdinal - 1]; + } + } + break; + } + } + delete[] _children.external; + _children.external = newExternalList; + } else if (previousChildCount > newChildCount) { + // 3 or more children, one item being removed, we know we're stored externally, we just figure out which + // item to remove from our external list + VoxelNode** newExternalList = new VoxelNode*[newChildCount]; + + for (int ordinal = 1; ordinal <= previousChildCount; ordinal++) { + int index = getNthBit(previousChildMask, ordinal); + assert(index != -1); + if (index < childIndex) { + newExternalList[ordinal - 1] = _children.external[ordinal - 1]; + } else { + // our child needs to be removed from here, and everything else pulled in... + for (int moveOrdinal = ordinal; moveOrdinal <= newChildCount; moveOrdinal++) { + newExternalList[moveOrdinal - 1] = _children.external[moveOrdinal]; + } + break; + } + } + delete[] _children.external; + _children.external = newExternalList; + } + + // to be deleted... + _childrenArray[childIndex] = child; + auditChildren("setChildAtIndex()"); +} + + VoxelNode* VoxelNode::addChildAtIndex(int childIndex) { - if (!_children[childIndex]) { + VoxelNode* childAt = getChildAtIndex(childIndex); + if (!childAt) { // before adding a child, see if we're currently a leaf if (isLeaf()) { _voxelNodeLeafCount--; } - _children[childIndex] = new VoxelNode(childOctalCode(getOctalCode(), childIndex)); - _children[childIndex]->setVoxelSystem(getVoxelSystem()); // our child is always part of our voxel system NULL ok + childAt = new VoxelNode(childOctalCode(getOctalCode(), childIndex)); + childAt->setVoxelSystem(getVoxelSystem()); // our child is always part of our voxel system NULL ok + + setChildAtIndex(childIndex, childAt); + _isDirty = true; - _childCount++; markWithChangedTime(); } - return _children[childIndex]; + + auditChildren("addChildAtIndex()"); + + return childAt; } // handles staging or deletion of all deep children @@ -236,14 +640,15 @@ void VoxelNode::setColorFromAverageOfChildren() { int colorArray[4] = {0,0,0,0}; float density = 0.0f; for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - if (_children[i] && _children[i]->isColored()) { + VoxelNode* childAt = getChildAtIndex(i); + if (childAt && childAt->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] += childAt->getTrueColor()[j]; // color averaging should always be based on true colors } colorArray[3]++; } - if (_children[i]) { - density += _children[i]->getDensity(); + if (childAt) { + density += childAt->getDensity(); } } density /= (float) NUMBER_OF_CHILDREN; @@ -323,18 +728,19 @@ bool VoxelNode::collapseIdenticalLeaves() { bool allChildrenMatch = true; // assume the best (ottimista) int red,green,blue; for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { + VoxelNode* childAt = getChildAtIndex(i); // if no child, child isn't a leaf, or child doesn't have a color - if (!_children[i] || !_children[i]->isLeaf() || !_children[i]->isColored()) { + if (!childAt || !childAt->isLeaf() || !childAt->isColored()) { allChildrenMatch=false; //qDebug("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 = childAt->getColor()[0]; + green = childAt->getColor()[1]; + blue = childAt->getColor()[2]; + } else if (red != childAt->getColor()[0] || + green != childAt->getColor()[1] || blue != childAt->getColor()[2]) { allChildrenMatch=false; break; } @@ -345,10 +751,10 @@ bool VoxelNode::collapseIdenticalLeaves() { if (allChildrenMatch) { //qDebug("allChildrenMatch: pruning tree\n"); for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - delete _children[i]; // delete all the child nodes - _children[i]=NULL; // set it to NULL + VoxelNode* childAt = getChildAtIndex(i); + delete childAt; // delete all the child nodes + setChildAtIndex(i, NULL); // set it to NULL } - _childCount = 0; nodeColor collapsedColor; collapsedColor[0]=red; collapsedColor[1]=green; @@ -372,7 +778,8 @@ void VoxelNode::setRandomColor(int minimumBrightness) { void VoxelNode::printDebugDetails(const char* label) const { unsigned char childBits = 0; for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - if (_children[i]) { + VoxelNode* childAt = getChildAtIndex(i); + if (childAt) { setAtBit(childBits,i); } } diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 4bfd75c692..7d41b7af23 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -41,8 +41,8 @@ public: VoxelNode(unsigned char * octalCode); // regular constructor ~VoxelNode(); - const unsigned char* getOctalCode() const { return (_octcodePointer) ? _octalCode._octalCodePointer : &_octalCode._octalCodeBuffer[0]; } - VoxelNode* getChildAtIndex(int childIndex) const { return _children[childIndex]; } + const unsigned char* getOctalCode() const { return (_octcodePointer) ? _octalCode.pointer : &_octalCode.buffer[0]; } + VoxelNode* getChildAtIndex(int childIndex) const; void deleteChildAtIndex(int childIndex); VoxelNode* removeChildAtIndex(int childIndex); VoxelNode* addChildAtIndex(int childIndex); @@ -71,8 +71,8 @@ public: float distanceSquareToPoint(const glm::vec3& point) const; // when you don't need the actual distance, use this. float distanceToPoint(const glm::vec3& point) const; - bool isLeaf() const { return _childCount == 0; } - int getChildCount() const { return _childCount; } + bool isLeaf() const { return getChildCount() == 0; } + int getChildCount() const { return numberOfOnes(_childBitmask); } void printDebugDetails(const char* label) const; bool isDirty() const { return _isDirty; } void clearDirtyBit() { _isDirty = false; } @@ -116,25 +116,51 @@ public: static uint64_t getVoxelMemoryUsage() { return _voxelMemoryUsage; } static uint64_t getOctcodeMemoryUsage() { return _octcodeMemoryUsage; } + + static uint64_t _getChildAtIndexTime; + static uint64_t _getChildAtIndexCalls; + static uint64_t _setChildAtIndexTime; + static uint64_t _setChildAtIndexCalls; private: + void setChildAtIndex(int childIndex, VoxelNode* child); + void storeTwoChildren(VoxelNode* childOne, VoxelNode* childTwo); + void retrieveTwoChildren(VoxelNode*& childOne, VoxelNode*& childTwo); + VoxelNode* __new__getChildAtIndex(int childIndex) const; + void __new__setChildAtIndex(int childIndex, VoxelNode* child); + void auditChildren(const char* label) const; + void calculateAABox(); void init(unsigned char * octalCode); void notifyDeleteHooks(); void notifyUpdateHooks(); - VoxelNode* _children[8]; /// Client and server, pointers to child nodes, 64 bytes - AABox _box; /// Client and server, axis aligned box for bounds of this voxel, 48 bytes /// Client and server, buffer containing the octal code or a pointer to octal code for this node, 8 bytes union octalCode_t { - unsigned char _octalCodeBuffer[8]; - unsigned char* _octalCodePointer; + unsigned char buffer[8]; + unsigned char* pointer; } _octalCode; uint64_t _lastChanged; /// Client and server, timestamp this node was last changed, 8 bytes + /// Client and server, pointers to child nodes, various encodings + union children_t { + VoxelNode* single; + int32_t offsetsTwoChildren[2]; + uint64_t offsetsThreeChildrenA : 21, offsetsThreeChildrenB : 21, offsetsThreeChildrenC : 21 ; + VoxelNode** external; + } _children; + + static int64_t _offsetMax; + static int64_t _offsetMin; + + //_offsetMax=4,184,812 + //_offsetMin=-5,828,062 + + VoxelNode* _childrenArray[8]; /// Client and server, pointers to child nodes, 64 bytes + uint32_t _glBufferIndex : 24, /// Client only, vbo index for this voxel if being rendered, 3 bytes _voxelSystemIndex : 8; /// Client only, index to the VoxelSystem rendering this voxel, 1 bytes @@ -143,18 +169,20 @@ private: static std::map _mapIndexToVoxelSystemPointers; float _density; /// Client and server, If leaf: density = 1, if internal node: 0-1 density of voxels inside, 4 bytes - int _childCount; /// Client and server, current child nodes set to non-null in _children, 4 bytes nodeColor _trueColor; /// Client and server, true color of this voxel, 4 bytes nodeColor _currentColor; /// Client only, false color of this voxel, 4 bytes uint16_t _sourceID; /// Client only, stores node id of voxel server that sent his voxel, 2 bytes + unsigned char _childBitmask; // 1 byte + bool _falseColored : 1, /// Client only, is this voxel false colored, 1 bit _isDirty : 1, /// Client only, has this voxel changed since being rendered, 1 bit _shouldRender : 1, /// Client only, should this voxel render at this time, 1 bit _octcodePointer : 1, /// Client and Server only, is this voxel's octal code a pointer or buffer, 1 bit - _unknownBufferIndex : 1; /// Client only, is this voxel's VBO buffer the unknown buffer index, 1 bit + _unknownBufferIndex : 1, + _childrenExternal : 1; /// Client only, is this voxel's VBO buffer the unknown buffer index, 1 bit static std::vector _deleteHooks; static std::vector _updateHooks; diff --git a/voxel-edit/src/main.cpp b/voxel-edit/src/main.cpp index 11242452dd..38375c1b0d 100644 --- a/voxel-edit/src/main.cpp +++ b/voxel-edit/src/main.cpp @@ -233,7 +233,7 @@ void processFillSVOFile(const char* fillSVOFile) { } -int main(int argc, const char * argv[]) +int old_main(int argc, const char * argv[]) { qInstallMessageHandler(sharedMessageHandler); @@ -294,4 +294,46 @@ int main(int argc, const char * argv[]) } return 0; +} + +void unitTest(VoxelTree * tree) { + printf("unit tests...\n"); + + // We want our corner voxels to be about 1/2 meter high, and our TREE_SCALE is in meters, so... + float voxelSize = 0.5f; + + // Here's an example of how to create a voxel. + printf("creating corner points...\n"); + tree->createVoxel(0, 0, 0, voxelSize, 255, 255 ,255); + + // Here's an example of how to test if a voxel exists + VoxelNode* node = tree->getVoxelAt(0, 0, 0, voxelSize); + if (node) { + // and how to access it's color + printf("corner point 0,0,0 exists... color is (%d,%d,%d) \n", + node->getColor()[0], node->getColor()[1], node->getColor()[2]); + } + + // here's an example of how to delete a voxel + printf("attempting to delete corner point 0,0,0\n"); + tree->deleteVoxelAt(0, 0, 0, voxelSize); + + // Test to see that the delete worked... it should be FALSE... + if (tree->getVoxelAt(0, 0, 0, voxelSize)) { + printf("corner point 0,0,0 exists...\n"); + } else { + printf("corner point 0,0,0 does not exists...\n"); + } + + tree->createVoxel(0, 0, 0, voxelSize, 255, 255 ,255); + tree->createVoxel(voxelSize, 0, 0, voxelSize, 255, 255 ,255); + tree->createVoxel(0, 0, voxelSize, voxelSize, 255, 255 ,255); + tree->createVoxel(voxelSize, 0, voxelSize, voxelSize, 255, 255 ,255); + +} + + +int main(int argc, const char * argv[]) { + unitTest(&myTree); + return 0; } \ No newline at end of file From d2bab77c88a36109c1bcae0a44ceaebe0e230062 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 16 Oct 2013 21:42:47 -0700 Subject: [PATCH 10/22] implement support for three children encoding --- .../src/VoxelPersistThread.cpp | 8 + .../src/VoxelSendThread.cpp | 7 +- .../voxel-server-library/src/VoxelServer.cpp | 17 + libraries/voxels/src/VoxelNode.cpp | 395 ++++++++++++++---- libraries/voxels/src/VoxelNode.h | 30 +- libraries/voxels/src/VoxelTree.cpp | 3 + 6 files changed, 370 insertions(+), 90 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelPersistThread.cpp b/libraries/voxel-server-library/src/VoxelPersistThread.cpp index be530682c8..93819cc758 100644 --- a/libraries/voxel-server-library/src/VoxelPersistThread.cpp +++ b/libraries/voxel-server-library/src/VoxelPersistThread.cpp @@ -48,6 +48,14 @@ bool VoxelPersistThread::process() { unsigned long internalNodeCount = VoxelNode::getInternalNodeCount(); unsigned long leafNodeCount = VoxelNode::getLeafNodeCount(); qDebug("Nodes after loading scene %lu nodes %lu internal %lu leaves\n", nodeCount, internalNodeCount, leafNodeCount); + + double usecPerGet = (double)VoxelNode::_getChildAtIndexTime / (double)VoxelNode::_getChildAtIndexCalls; + double usecPerSet = (double)VoxelNode::_setChildAtIndexTime / (double)VoxelNode::_setChildAtIndexCalls; + + printf("_getChildAtIndexCalls=%llu, _getChildAtIndexTime=%llu, perGet=%lf ... _setChildAtIndexCalls=%llu _setChildAtIndexTime=%llu perSet=%lf\n", + VoxelNode::_getChildAtIndexCalls, VoxelNode::_getChildAtIndexTime, usecPerGet, + VoxelNode::_setChildAtIndexCalls, VoxelNode::_setChildAtIndexTime, usecPerSet); + } uint64_t MSECS_TO_USECS = 1000; diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index cb1b78134d..0b9ba6b165 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -54,17 +54,14 @@ bool VoxelSendThread::process() { } // debug some timing... - //uint64_t VoxelNode::_getChildAtIndexTime; - //uint64_t VoxelNode::_getChildAtIndexCalls; - //uint64_t VoxelNode::_setChildAtIndexTime; - //uint64_t VoxelNode::_setChildAtIndexCalls; - + /*** double usecPerGet = (double)VoxelNode::_getChildAtIndexTime / (double)VoxelNode::_getChildAtIndexCalls; double usecPerSet = (double)VoxelNode::_setChildAtIndexTime / (double)VoxelNode::_setChildAtIndexCalls; printf("_getChildAtIndexCalls=%llu, _getChildAtIndexTime=%llu, perGet=%lf ... _setChildAtIndexCalls=%llu _setChildAtIndexTime=%llu perSet=%lf\n", VoxelNode::_getChildAtIndexCalls, VoxelNode::_getChildAtIndexTime, usecPerGet, VoxelNode::_setChildAtIndexCalls, VoxelNode::_setChildAtIndexTime, usecPerSet); + ***/ return isStillRunning(); // keep running till they terminate us } diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index d261f0348f..e2e1ab3534 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -148,6 +148,23 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { mg_printf(connection, " Internal Nodes: %lu nodes\r\n", internalNodeCount); mg_printf(connection, " Leaf Nodes: %lu leaves\r\n", leafNodeCount); + mg_printf(connection, "%s", "VoxelNode Children Encoding Statistics...\r\n"); + mg_printf(connection, " Single or No Children: %10.llu nodes\r\n", VoxelNode::_singleChildrenCount); + mg_printf(connection, " Two Children as Offset: %10.llu nodes\r\n", VoxelNode::_twoChildrenOffsetCount); + mg_printf(connection, " Two Children as External: %10.llu nodes\r\n", VoxelNode::_twoChildrenExternalCount); + mg_printf(connection, " Three Children as Offset: %10.llu nodes\r\n", VoxelNode::_threeChildrenOffsetCount); + mg_printf(connection, " Three Children as External: %10.llu nodes\r\n", VoxelNode::_threeChildrenExternalCount); + mg_printf(connection, " Children as External Array: %10.llu nodes\r\n", VoxelNode::_externalChildrenCount); + + uint64_t checkSum = VoxelNode::_singleChildrenCount + + VoxelNode::_twoChildrenOffsetCount + VoxelNode::_twoChildrenExternalCount + + VoxelNode::_threeChildrenOffsetCount + VoxelNode::_threeChildrenExternalCount + + VoxelNode::_externalChildrenCount; + + mg_printf(connection, "%s", " ----------------\r\n"); + mg_printf(connection, " Total: %10.llu nodes\r\n", checkSum); + mg_printf(connection, " Expected: %10.lu nodes\r\n", nodeCount); + return 1; } else { // have mongoose process this request from the document_root diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 71d5a386de..5d13befd5d 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -65,11 +65,14 @@ void VoxelNode::init(unsigned char * octalCode) { _childBitmask = 0; _childrenExternal = false; _children.external = NULL; + _singleChildrenCount++; // default pointers to child nodes to NULL + /**/ for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { _childrenArray[i] = NULL; } + /**/ _unknownBufferIndex = true; @@ -196,7 +199,6 @@ void VoxelNode::deleteChildAtIndex(int childIndex) { _voxelNodeLeafCount++; } } - auditChildren("deleteChildAtIndex()"); } @@ -213,16 +215,16 @@ VoxelNode* VoxelNode::removeChildAtIndex(int childIndex) { _voxelNodeLeafCount++; } } + auditChildren("removeChildAtIndex()"); return returnedChild; } void VoxelNode::auditChildren(const char* label) const { return; - bool auditFailed = false; for (int childIndex = 0; childIndex < NUMBER_OF_CHILDREN; childIndex++) { - VoxelNode* testChildNew = __new__getChildAtIndex(childIndex); + VoxelNode* testChildNew = getChildAtIndex(childIndex); VoxelNode* testChildOld = _childrenArray[childIndex]; if (testChildNew != testChildOld) { @@ -231,9 +233,15 @@ void VoxelNode::auditChildren(const char* label) const { } if (auditFailed) { - printf("%s... auditChildren() FAILED <<<< \n", label); + printf("%s... auditChildren() %s <<<< \n", label, (auditFailed ? "FAILED" : "PASSED")); + printf(" _childrenExternal=%s\n", debug::valueOf(_childrenExternal)); + printf(" childCount=%d\n", getChildCount()); + printf(" _childBitmask="); + outputBits(_childBitmask); + + for (int childIndex = 0; childIndex < NUMBER_OF_CHILDREN; childIndex++) { - VoxelNode* testChildNew = __new__getChildAtIndex(childIndex); + VoxelNode* testChildNew = getChildAtIndex(childIndex); VoxelNode* testChildOld = _childrenArray[childIndex]; printf("child at index %d... testChildOld=%p testChildNew=%p %s \n", @@ -243,7 +251,6 @@ void VoxelNode::auditChildren(const char* label) const { } printf("%s... auditChildren() <<<< DONE <<<< \n", label); } - } uint64_t VoxelNode::_getChildAtIndexTime = 0; @@ -251,27 +258,32 @@ uint64_t VoxelNode::_getChildAtIndexCalls = 0; uint64_t VoxelNode::_setChildAtIndexTime = 0; uint64_t VoxelNode::_setChildAtIndexCalls = 0; +uint64_t VoxelNode::_singleChildrenCount = 0; +uint64_t VoxelNode::_twoChildrenOffsetCount = 0; +uint64_t VoxelNode::_twoChildrenExternalCount = 0; +uint64_t VoxelNode::_threeChildrenOffsetCount = 0; +uint64_t VoxelNode::_threeChildrenExternalCount = 0; +uint64_t VoxelNode::_externalChildrenCount = 0; + VoxelNode* VoxelNode::getChildAtIndex(int childIndex) const { PerformanceWarning warn(false,"getChildAtIndex",false,&_getChildAtIndexTime,&_getChildAtIndexCalls); - - VoxelNode* child = __new__getChildAtIndex(childIndex); - //VoxelNode* child = _childrenArray[childIndex]; /// *** OLD WAY **** - return child; -} - -VoxelNode* VoxelNode::__new__getChildAtIndex(int childIndex) const { VoxelNode* result = NULL; int childCount = getChildCount(); + + const char* caseStr = NULL; switch (childCount) { case 0: + caseStr = "0 child case"; break; case 1: { + caseStr = "1 child case"; int indexOne = getNthBit(_childBitmask, 1); if (indexOne == childIndex) { result = _children.single; } } break; case 2: { + caseStr = "2 child case"; int indexOne = getNthBit(_childBitmask, 1); int indexTwo = getNthBit(_childBitmask, 2); @@ -291,8 +303,38 @@ VoxelNode* VoxelNode::__new__getChildAtIndex(int childIndex) const { } } } break; + case 3: { + caseStr = "3 child case"; + int indexOne = getNthBit(_childBitmask, 1); + int indexTwo = getNthBit(_childBitmask, 2); + int indexThree = getNthBit(_childBitmask, 3); + + if (_childrenExternal) { + if (indexOne == childIndex) { + result = _children.external[0]; + } else if (indexTwo == childIndex) { + result = _children.external[1]; + } else if (indexThree == childIndex) { + result = _children.external[2]; + } else { + } + } else { + int64_t offsetOne, offsetTwo, offsetThree; + decodeThreeOffsets(offsetOne, offsetTwo, offsetThree); + + if (indexOne == childIndex) { + result = (VoxelNode*)((uint8_t*)this + offsetOne); + } else if (indexTwo == childIndex) { + result = (VoxelNode*)((uint8_t*)this + offsetTwo); + } else if (indexThree == childIndex) { + result = (VoxelNode*)((uint8_t*)this + offsetThree); + } + } + } break; default: { - // if we have 3 or more, we know we're in external mode, so we just need to figure out which + caseStr = "default"; + //printf("default case...\n"); + // if we have 4 or more, we know we're in external mode, so we just need to figure out which // slot in our external array this child is. if (oneAtBit(_childBitmask, childIndex)) { childCount = getChildCount(); @@ -306,16 +348,21 @@ VoxelNode* VoxelNode::__new__getChildAtIndex(int childIndex) const { } } break; } + if (result != _childrenArray[childIndex]) { + printf("getChildAtIndex() case:%s result<%p> != _childrenArray[childIndex]<%p> <<<<<<<<<< WARNING!!! \n", + caseStr, result,_childrenArray[childIndex]); + } return result; } void VoxelNode::storeTwoChildren(VoxelNode* childOne, VoxelNode* childTwo) { int64_t offsetOne = (uint8_t*)childOne - (uint8_t*)this; int64_t offsetTwo = (uint8_t*)childTwo - (uint8_t*)this; - - if (isBetween(offsetOne, std::numeric_limits::max(), std::numeric_limits::min()) && - isBetween(offsetTwo, std::numeric_limits::max(), std::numeric_limits::min())) { + const int64_t minOffset = std::numeric_limits::min(); + const int64_t maxOffset = std::numeric_limits::max(); + + if (isBetween(offsetOne, maxOffset, minOffset) && isBetween(offsetTwo, maxOffset, minOffset)) { // if previously external, then clean it up... if (_childrenExternal) { delete[] _children.external; @@ -326,6 +373,8 @@ void VoxelNode::storeTwoChildren(VoxelNode* childOne, VoxelNode* childTwo) { // encode in union _children.offsetsTwoChildren[0] = offsetOne; _children.offsetsTwoChildren[1] = offsetTwo; + + _twoChildrenOffsetCount++; } else { // encode in array @@ -336,6 +385,7 @@ void VoxelNode::storeTwoChildren(VoxelNode* childOne, VoxelNode* childTwo) { } _children.external[0] = childOne; _children.external[1] = childTwo; + _twoChildrenExternalCount++; } } @@ -347,30 +397,124 @@ void VoxelNode::retrieveTwoChildren(VoxelNode*& childOne, VoxelNode*& childTwo) delete[] _children.external; _children.external = NULL; // probably not needed! _childrenExternal = false; + _twoChildrenExternalCount--; } else { int64_t offsetOne = _children.offsetsTwoChildren[0]; int64_t offsetTwo = _children.offsetsTwoChildren[1]; + childOne = (VoxelNode*)((uint8_t*)this + offsetOne); + childTwo = (VoxelNode*)((uint8_t*)this + offsetTwo); + _twoChildrenOffsetCount--; + } +} + +void VoxelNode::decodeThreeOffsets(int64_t& offsetOne, int64_t& offsetTwo, int64_t& offsetThree) const { + const uint64_t ENCODE_BITS = 21; + const uint64_t ENCODE_MASK = 0xFFFFF; + const uint64_t ENCODE_MASK_SIGN = 0x100000; + + uint64_t offsetEncodedOne = (_children.offsetsThreeChildrenEncoded >> (ENCODE_BITS * 2)) & ENCODE_MASK; + uint64_t offsetEncodedTwo = (_children.offsetsThreeChildrenEncoded >> (ENCODE_BITS * 1)) & ENCODE_MASK; + uint64_t offsetEncodedThree = (_children.offsetsThreeChildrenEncoded & ENCODE_MASK); + + uint64_t signEncodedOne = (_children.offsetsThreeChildrenEncoded >> (ENCODE_BITS * 2)) & ENCODE_MASK_SIGN; + uint64_t signEncodedTwo = (_children.offsetsThreeChildrenEncoded >> (ENCODE_BITS * 1)) & ENCODE_MASK_SIGN; + uint64_t signEncodedThree = (_children.offsetsThreeChildrenEncoded & ENCODE_MASK_SIGN); + + bool oneNegative = signEncodedOne == ENCODE_MASK_SIGN; + bool twoNegative = signEncodedTwo == ENCODE_MASK_SIGN; + bool threeNegative = signEncodedThree == ENCODE_MASK_SIGN; + + offsetOne = oneNegative ? -offsetEncodedOne : offsetEncodedOne; + offsetTwo = twoNegative ? -offsetEncodedTwo : offsetEncodedTwo; + offsetThree = threeNegative ? -offsetEncodedThree : offsetEncodedThree; +} + +void VoxelNode::encodeThreeOffsets(int64_t offsetOne, int64_t offsetTwo, int64_t offsetThree) { + const uint64_t ENCODE_BITS = 21; + const uint64_t ENCODE_MASK = 0xFFFFF; + const uint64_t ENCODE_MASK_SIGN = 0x100000; + + uint64_t offsetEncodedOne, offsetEncodedTwo, offsetEncodedThree; + if (offsetOne < 0) { + offsetEncodedOne = ((-offsetOne & ENCODE_MASK) | ENCODE_MASK_SIGN); + } else { + offsetEncodedOne = offsetOne & ENCODE_MASK; + } + offsetEncodedOne = offsetEncodedOne << (ENCODE_BITS * 2); + + if (offsetTwo < 0) { + offsetEncodedTwo = ((-offsetTwo & ENCODE_MASK) | ENCODE_MASK_SIGN); + } else { + offsetEncodedTwo = offsetTwo & ENCODE_MASK; + } + offsetEncodedTwo = offsetEncodedTwo << ENCODE_BITS; + + if (offsetThree < 0) { + offsetEncodedThree = ((-offsetThree & ENCODE_MASK) | ENCODE_MASK_SIGN); + } else { + offsetEncodedThree = offsetThree & ENCODE_MASK; + } + _children.offsetsThreeChildrenEncoded = offsetEncodedOne | offsetEncodedTwo | offsetEncodedThree; +} + +void VoxelNode::storeThreeChildren(VoxelNode* childOne, VoxelNode* childTwo, VoxelNode* childThree) { + int64_t offsetOne = (uint8_t*)childOne - (uint8_t*)this; + int64_t offsetTwo = (uint8_t*)childTwo - (uint8_t*)this; + int64_t offsetThree = (uint8_t*)childThree - (uint8_t*)this; + + const int64_t minOffset = std::numeric_limits::min(); // -1000000; // std::numeric_limits::min(); + const int64_t maxOffset = std::numeric_limits::max(); // 1000000; // std::numeric_limits::max(); + + if (isBetween(offsetOne, maxOffset, minOffset) && + isBetween(offsetTwo, maxOffset, minOffset) && + isBetween(offsetThree, maxOffset, minOffset)) { + // if previously external, then clean it up... + if (_childrenExternal) { + delete[] _children.external; + _children.external = NULL; // probably not needed! + _childrenExternal = false; + } + // encode in union + encodeThreeOffsets(offsetOne, offsetTwo, offsetThree); + _threeChildrenOffsetCount++; + } else { + // encode in array + + // if not previously external, then allocate appropriately + if (!_childrenExternal) { + _childrenExternal = true; + _children.external = new VoxelNode*[3]; + } + _children.external[0] = childOne; + _children.external[1] = childTwo; + _children.external[2] = childThree; + _threeChildrenExternalCount++; + } +} + +void VoxelNode::retrieveThreeChildren(VoxelNode*& childOne, VoxelNode*& childTwo, VoxelNode*& childThree) { + // If we previously had an external array, then get the + if (_childrenExternal) { + childOne = _children.external[0]; + childTwo = _children.external[1]; + childThree = _children.external[2]; + delete[] _children.external; + _children.external = NULL; // probably not needed! + _childrenExternal = false; + _threeChildrenExternalCount--; + } else { + int64_t offsetOne, offsetTwo, offsetThree; + decodeThreeOffsets(offsetOne, offsetTwo, offsetThree); childOne = (VoxelNode*)((uint8_t*)this + offsetOne); childTwo = (VoxelNode*)((uint8_t*)this + offsetTwo); + childThree = (VoxelNode*)((uint8_t*)this + offsetThree); + _threeChildrenOffsetCount--; } } - void VoxelNode::setChildAtIndex(int childIndex, VoxelNode* child) { PerformanceWarning warn(false,"setChildAtIndex",false,&_setChildAtIndexTime,&_setChildAtIndexCalls); - __new__setChildAtIndex(childIndex, child); - - /** OLD WAY **** - _childrenArray[childIndex] = child; - if (child) { - setAtBit(_childBitmask, childIndex); - } else { - clearAtBit(_childBitmask, childIndex); - } - **/ -} -void VoxelNode::__new__setChildAtIndex(int childIndex, VoxelNode* child) { // Here's how we store things... // If we have 0 or 1 children, then we just store them in the _children.single; // If we have 2 children, @@ -412,8 +556,8 @@ void VoxelNode::__new__setChildAtIndex(int childIndex, VoxelNode* child) { childTwo = _children.single; } + _singleChildrenCount--; storeTwoChildren(childOne, childTwo); - } else if (previousChildCount == 2 && newChildCount == 1) { // If we had 2 children, and we're removing one, then we know we can go down to single mode assert(child == NULL); // this is the only logical case @@ -425,6 +569,8 @@ void VoxelNode::__new__setChildAtIndex(int childIndex, VoxelNode* child) { VoxelNode* childTwo; retrieveTwoChildren(childOne, childTwo); + + _singleChildrenCount++; if (keepChildOne) { _children.single = childOne; @@ -459,41 +605,9 @@ void VoxelNode::__new__setChildAtIndex(int childIndex, VoxelNode* child) { childTwo = child; } + _twoChildrenOffsetCount--; // will end up one or the other storeTwoChildren(childOne, childTwo); } - } else if (previousChildCount == 3 && newChildCount == 2) { - // If we had 3 children, and now have 2, then we know we are going from an external case to a potential internal case - assert(_childrenExternal); - - // We need to determine which children we had, and which one we got rid of... - int indexOne = getNthBit(previousChildMask, 1); - int indexTwo = getNthBit(previousChildMask, 2); - int indexThree = getNthBit(previousChildMask, 3); - - bool removeChildOne = indexOne == childIndex; - bool removeChildTwo = indexTwo == childIndex; - bool removeChildThree = indexThree == childIndex; - - VoxelNode* childOne = _children.external[0]; - VoxelNode* childTwo = _children.external[1]; - VoxelNode* childThree = _children.external[2]; - - if (removeChildOne) { - childOne = childTwo; - childTwo = childThree; - } else if (removeChildTwo) { - childTwo = childThree; - } else { - // removing child three, nothing to do. - } - - // clean up the external children... - _childrenExternal = false; - delete[] _children.external; - _children.external = NULL; - - storeTwoChildren(childOne, childTwo); - } else if (previousChildCount == 2 && newChildCount == 3) { // If we had 2 children, and now have 3, then we know we are going to an external case... @@ -505,10 +619,6 @@ void VoxelNode::__new__setChildAtIndex(int childIndex, VoxelNode* child) { // Get the existing two children out of their encoding... retrieveTwoChildren(childOne, childTwo); - // now, allocate the external... - _childrenExternal = true; - _children.external = new VoxelNode*[3]; - // determine order of the existing children int indexOne = getNthBit(previousChildMask, 1); int indexTwo = getNthBit(previousChildMask, 2); @@ -523,13 +633,148 @@ void VoxelNode::__new__setChildAtIndex(int childIndex, VoxelNode* child) { } else { childThree = child; } + storeThreeChildren(childOne, childTwo, childThree); + } else if (previousChildCount == 3 && newChildCount == 2) { + // If we had 3 children, and now have 2, then we know we are going from an external case to a potential internal case + + // We need to determine which children we had, and which one we got rid of... + int indexOne = getNthBit(previousChildMask, 1); + int indexTwo = getNthBit(previousChildMask, 2); + int indexThree = getNthBit(previousChildMask, 3); + + bool removeChildOne = indexOne == childIndex; + bool removeChildTwo = indexTwo == childIndex; + bool removeChildThree = indexThree == childIndex; + + VoxelNode* childOne; + VoxelNode* childTwo; + VoxelNode* childThree; + + // Get the existing two children out of their encoding... + retrieveThreeChildren(childOne, childTwo, childThree); + + if (removeChildOne) { + childOne = childTwo; + childTwo = childThree; + } else if (removeChildTwo) { + childTwo = childThree; + } else { + // removing child three, nothing to do. + } + + storeTwoChildren(childOne, childTwo); + } else if (previousChildCount == 3 && newChildCount == 3) { + // If we had 3 children, and now have 3, then we need to determine which item we're replacing... + + // We need to determine which children we had, and which one we got rid of... + int indexOne = getNthBit(previousChildMask, 1); + int indexTwo = getNthBit(previousChildMask, 2); + int indexThree = getNthBit(previousChildMask, 3); + + bool replaceChildOne = indexOne == childIndex; + bool replaceChildTwo = indexTwo == childIndex; + bool replaceChildThree = indexThree == childIndex; + + VoxelNode* childOne; + VoxelNode* childTwo; + VoxelNode* childThree; + + // Get the existing two children out of their encoding... + retrieveThreeChildren(childOne, childTwo, childThree); + + if (replaceChildOne) { + childOne = child; + } else if (replaceChildTwo) { + childTwo = child; + } else { + childThree = child; + } + + storeThreeChildren(childOne, childTwo, childThree); + } else if (previousChildCount == 3 && newChildCount == 4) { + // If we had 3 children, and now have 4, then we know we are going to an external case... + + // First, decode the children... + VoxelNode* childOne; + VoxelNode* childTwo; + VoxelNode* childThree; + VoxelNode* childFour; + + // Get the existing two children out of their encoding... + retrieveThreeChildren(childOne, childTwo, childThree); + + // determine order of the existing children + int indexOne = getNthBit(previousChildMask, 1); + int indexTwo = getNthBit(previousChildMask, 2); + int indexThree = getNthBit(previousChildMask, 3); + + if (childIndex < indexOne) { + childFour = childThree; + childThree = childTwo; + childTwo = childOne; + childOne = child; + } else if (childIndex < indexTwo) { + childFour = childThree; + childThree = childTwo; + childTwo = child; + } else if (childIndex < indexThree) { + childFour = childThree; + childThree = child; + } else { + childFour = child; + } + + // now, allocate the external... + _childrenExternal = true; + _children.external = new VoxelNode*[4]; _children.external[0] = childOne; _children.external[1] = childTwo; _children.external[2] = childThree; + _children.external[3] = childFour; + _externalChildrenCount++; + } else if (previousChildCount == 4 && newChildCount == 3) { + // If we had 4 children, and now have 3, then we know we are going from an external case to a potential internal case + assert(_childrenExternal); + // We need to determine which children we had, and which one we got rid of... + int indexOne = getNthBit(previousChildMask, 1); + int indexTwo = getNthBit(previousChildMask, 2); + int indexThree = getNthBit(previousChildMask, 3); + int indexFour = getNthBit(previousChildMask, 4); + + bool removeChildOne = indexOne == childIndex; + bool removeChildTwo = indexTwo == childIndex; + bool removeChildThree = indexThree == childIndex; + bool removeChildFour = indexFour == childIndex; + + VoxelNode* childOne = _children.external[0]; + VoxelNode* childTwo = _children.external[1]; + VoxelNode* childThree = _children.external[2]; + VoxelNode* childFour = _children.external[3]; + + if (removeChildOne) { + childOne = childTwo; + childTwo = childThree; + childThree = childFour; + } else if (removeChildTwo) { + childTwo = childThree; + childThree = childFour; + } else if (removeChildThree) { + childThree = childFour; + } else { + // removing child four, nothing to do. + } + + // clean up the external children... + _childrenExternal = false; + delete[] _children.external; + _children.external = NULL; + _externalChildrenCount--; + + storeThreeChildren(childOne, childTwo, childThree); } else if (previousChildCount == newChildCount) { - // 3 or more children, one item being replaced, we know we're stored externally, we just need to find the one + // 4 or more children, one item being replaced, we know we're stored externally, we just need to find the one // that needs to be replaced and replace it. for (int ordinal = 1; ordinal <= 8; ordinal++) { int index = getNthBit(previousChildMask, ordinal); @@ -541,7 +786,7 @@ void VoxelNode::__new__setChildAtIndex(int childIndex, VoxelNode* child) { } } } else if (previousChildCount < newChildCount) { - // 3 or more children, one item being added, we know we're stored externally, we just figure out where to insert + // 4 or more children, one item being added, we know we're stored externally, we just figure out where to insert // this child pointer into our external list VoxelNode** newExternalList = new VoxelNode*[newChildCount]; @@ -569,7 +814,7 @@ void VoxelNode::__new__setChildAtIndex(int childIndex, VoxelNode* child) { delete[] _children.external; _children.external = newExternalList; } else if (previousChildCount > newChildCount) { - // 3 or more children, one item being removed, we know we're stored externally, we just figure out which + // 4 or more children, one item being removed, we know we're stored externally, we just figure out which // item to remove from our external list VoxelNode** newExternalList = new VoxelNode*[newChildCount]; @@ -588,9 +833,10 @@ void VoxelNode::__new__setChildAtIndex(int childIndex, VoxelNode* child) { } delete[] _children.external; _children.external = newExternalList; + } else { + assert(false); + printf("THIS SHOULD NOT HAPPEN previousChildCount == %d && newChildCount == %d\n",previousChildCount, newChildCount); } - - // to be deleted... _childrenArray[childIndex] = child; auditChildren("setChildAtIndex()"); } @@ -612,9 +858,6 @@ VoxelNode* VoxelNode::addChildAtIndex(int childIndex) { _isDirty = true; markWithChangedTime(); } - - auditChildren("addChildAtIndex()"); - return childAt; } diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 7d41b7af23..fc0aa44e47 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -122,13 +122,28 @@ public: static uint64_t _setChildAtIndexTime; static uint64_t _setChildAtIndexCalls; + static uint64_t _singleChildrenCount; + static uint64_t _twoChildrenOffsetCount; + static uint64_t _twoChildrenExternalCount; + static uint64_t _threeChildrenOffsetCount; + static uint64_t _threeChildrenExternalCount; + static uint64_t _externalChildrenCount; + + void auditChildren(const char* label) const; + private: void setChildAtIndex(int childIndex, VoxelNode* child); void storeTwoChildren(VoxelNode* childOne, VoxelNode* childTwo); void retrieveTwoChildren(VoxelNode*& childOne, VoxelNode*& childTwo); + void storeThreeChildren(VoxelNode* childOne, VoxelNode* childTwo, VoxelNode* childThree); + void retrieveThreeChildren(VoxelNode*& childOne, VoxelNode*& childTwo, VoxelNode*& childThree); + void decodeThreeOffsets(int64_t& offsetOne, int64_t& offsetTwo, int64_t& offsetThree) const; + void encodeThreeOffsets(int64_t offsetOne, int64_t offsetTwo, int64_t offsetThree); + + /** VoxelNode* __new__getChildAtIndex(int childIndex) const; void __new__setChildAtIndex(int childIndex, VoxelNode* child); - void auditChildren(const char* label) const; + **/ void calculateAABox(); void init(unsigned char * octalCode); @@ -149,21 +164,18 @@ private: union children_t { VoxelNode* single; int32_t offsetsTwoChildren[2]; - uint64_t offsetsThreeChildrenA : 21, offsetsThreeChildrenB : 21, offsetsThreeChildrenC : 21 ; + uint64_t offsetsThreeChildrenEncoded; VoxelNode** external; - } _children; + } _children; - static int64_t _offsetMax; - static int64_t _offsetMin; - - //_offsetMax=4,184,812 - //_offsetMin=-5,828,062 - VoxelNode* _childrenArray[8]; /// Client and server, pointers to child nodes, 64 bytes uint32_t _glBufferIndex : 24, /// Client only, vbo index for this voxel if being rendered, 3 bytes _voxelSystemIndex : 8; /// Client only, index to the VoxelSystem rendering this voxel, 1 bytes + // Support for _voxelSystemIndex, we use these static member variables to track the VoxelSystems that are + // in use by various voxel nodes. We map the VoxelSystem pointers into an 1 byte key, this limits us to at + // most 255 voxel systems in use at a time within the client. Which is far more than we need. static uint8_t _nextIndex; static std::map _mapVoxelSystemPointersToIndex; static std::map _mapIndexToVoxelSystemPointers; diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 6b247b70bf..5961904aee 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -710,6 +710,9 @@ VoxelNode* VoxelTree::getVoxelAt(float x, float y, float z, float s) const { node = NULL; } delete[] octalCode; // cleanup memory + if (node) { + node->auditChildren("VoxelTree::getVoxelAt()"); + } return node; } From e8ce60d275c8450bf7740c2558de46279edf69d1 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 16 Oct 2013 21:42:55 -0700 Subject: [PATCH 11/22] implement support for three children encoding --- voxel-edit/src/main.cpp | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/voxel-edit/src/main.cpp b/voxel-edit/src/main.cpp index 38375c1b0d..244db390df 100644 --- a/voxel-edit/src/main.cpp +++ b/voxel-edit/src/main.cpp @@ -1,4 +1,4 @@ -// + // // main.cpp // Voxel Edit // @@ -326,9 +326,39 @@ void unitTest(VoxelTree * tree) { } tree->createVoxel(0, 0, 0, voxelSize, 255, 255 ,255); + if (tree->getVoxelAt(0, 0, 0, voxelSize)) { + printf("corner point 0,0,0 exists...\n"); + } else { + printf("corner point 0,0,0 does not exists...\n"); + } + tree->createVoxel(voxelSize, 0, 0, voxelSize, 255, 255 ,255); + if (tree->getVoxelAt(voxelSize, 0, 0, voxelSize)) { + printf("corner point voxelSize,0,0 exists...\n"); + } else { + printf("corner point voxelSize,0,0 does not exists...\n"); + } + tree->createVoxel(0, 0, voxelSize, voxelSize, 255, 255 ,255); + if (tree->getVoxelAt(0, 0, voxelSize, voxelSize)) { + printf("corner point 0, 0, voxelSize exists...\n"); + } else { + printf("corner point 0, 0, voxelSize does not exists...\n"); + } + tree->createVoxel(voxelSize, 0, voxelSize, voxelSize, 255, 255 ,255); + if (tree->getVoxelAt(voxelSize, 0, voxelSize, voxelSize)) { + printf("corner point voxelSize, 0, voxelSize exists...\n"); + } else { + printf("corner point voxelSize, 0, voxelSize does not exists...\n"); + } + + printf("check root voxel exists...\n"); + if (tree->getVoxelAt(0,0,0,1.0)) { + printf("of course it does\n"); + } else { + printf("WTH!?!\n"); + } } From 296f18a84471f51d3b5b189da8119c21812e1e08 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 17 Oct 2013 09:58:28 -0700 Subject: [PATCH 12/22] make offset bounds match 20 bit storage --- 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 5d13befd5d..b8f8a28dfa 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -462,8 +462,8 @@ void VoxelNode::storeThreeChildren(VoxelNode* childOne, VoxelNode* childTwo, Vox int64_t offsetTwo = (uint8_t*)childTwo - (uint8_t*)this; int64_t offsetThree = (uint8_t*)childThree - (uint8_t*)this; - const int64_t minOffset = std::numeric_limits::min(); // -1000000; // std::numeric_limits::min(); - const int64_t maxOffset = std::numeric_limits::max(); // 1000000; // std::numeric_limits::max(); + const int64_t minOffset = -1048576; // what can fit in 20 bits // std::numeric_limits::min(); + const int64_t maxOffset = 1048576; // what can fit in 20 bits // std::numeric_limits::max(); if (isBetween(offsetOne, maxOffset, minOffset) && isBetween(offsetTwo, maxOffset, minOffset) && From b25020b84af7ed9b094dce02fe9aea25df608fc8 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 17 Oct 2013 10:58:33 -0700 Subject: [PATCH 13/22] Need to halve the target angle, because both participants will be moving. Use randomness to resolve cases where two participants are on top of one another. --- interface/src/avatar/MyAvatar.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 120ee2c09b..bbdd414494 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1178,8 +1178,13 @@ void MyAvatar::updateChatCircle(float deltaTime) { } } + // if we're on top of a neighbor, we need to randomize so that they don't both go in the same direction + if (rightDistance == 0.0f && randomBoolean()) { + swap(leftDistance, rightDistance); + } + // split the difference between our neighbors - float targetAngle = myAngle + (rightDistance - leftDistance) / 2.0f; + float targetAngle = myAngle + (rightDistance - leftDistance) / 4.0f; glm::vec3 targetPosition = center + (front * sinf(targetAngle) + right * cosf(targetAngle)) * radius; // approach the target position From 9643c1262cfbab5fd83b19aba8cd7a6092ce7f11 Mon Sep 17 00:00:00 2001 From: PhilipRosedale Date: Thu, 17 Oct 2013 11:03:12 -0700 Subject: [PATCH 14/22] Fix mute button, visualize gaze direction when showing headMouse --- interface/src/Application.cpp | 44 ++++++++++++++++++++++++----------- interface/src/Audio.cpp | 30 +++++++++++++----------- 2 files changed, 46 insertions(+), 28 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f9424500a7..730c17cd14 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2804,24 +2804,40 @@ void Application::displayOverlay() { if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse) && !Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && USING_INVENSENSE_MPU9150) { - // Display small target box at center or head mouse target that can also be used to measure LOD - glColor3f(1.0, 1.0, 1.0); + // Display small target box at center or head mouse target that can also be used to measure LOD + glColor3f(1.0, 1.0, 1.0); + glDisable(GL_LINE_SMOOTH); + const int PIXEL_BOX = 16; + glBegin(GL_LINES); + glVertex2f(_headMouseX - PIXEL_BOX/2, _headMouseY); + glVertex2f(_headMouseX + PIXEL_BOX/2, _headMouseY); + glVertex2f(_headMouseX, _headMouseY - PIXEL_BOX/2); + glVertex2f(_headMouseX, _headMouseY + PIXEL_BOX/2); + glEnd(); + glEnable(GL_LINE_SMOOTH); + glColor3f(1.f, 0.f, 0.f); + glPointSize(3.0f); + glDisable(GL_POINT_SMOOTH); + glBegin(GL_POINTS); + glVertex2f(_headMouseX - 1, _headMouseY + 1); + glEnd(); + // If Faceshift is active, show eye pitch and yaw as separate pointer + if (_faceshift.isActive()) { + const float EYE_TARGET_PIXELS_PER_DEGREE = 40.0; + int eyeTargetX = (_glWidget->width() / 2) - _faceshift.getEstimatedEyeYaw() * EYE_TARGET_PIXELS_PER_DEGREE; + int eyeTargetY = (_glWidget->height() / 2) - _faceshift.getEstimatedEyePitch() * EYE_TARGET_PIXELS_PER_DEGREE; + + glColor3f(0.0, 1.0, 1.0); glDisable(GL_LINE_SMOOTH); - const int PIXEL_BOX = 16; glBegin(GL_LINES); - glVertex2f(_headMouseX - PIXEL_BOX/2, _headMouseY); - glVertex2f(_headMouseX + PIXEL_BOX/2, _headMouseY); - glVertex2f(_headMouseX, _headMouseY - PIXEL_BOX/2); - glVertex2f(_headMouseX, _headMouseY + PIXEL_BOX/2); - glEnd(); - glEnable(GL_LINE_SMOOTH); - glColor3f(1.f, 0.f, 0.f); - glPointSize(3.0f); - glDisable(GL_POINT_SMOOTH); - glBegin(GL_POINTS); - glVertex2f(_headMouseX - 1, _headMouseY + 1); + glVertex2f(eyeTargetX - PIXEL_BOX/2, eyeTargetY); + glVertex2f(eyeTargetX + PIXEL_BOX/2, eyeTargetY); + glVertex2f(eyeTargetX, eyeTargetY - PIXEL_BOX/2); + glVertex2f(eyeTargetX, eyeTargetY + PIXEL_BOX/2); glEnd(); + } + } // Show detected levels from the serial I/O ADC channel sensors if (_displayLevels) _serialHeadSensor.renderLevels(_glWidget->width(), _glWidget->height()); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index bea12af25e..f5034c2832 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -84,24 +84,27 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o memset(outputLeft, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); memset(outputRight, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); + // If Mute button is pressed, clear the input buffer + if (_muted) { + memset(inputLeft, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); + } + // Add Procedural effects to input samples addProceduralSounds(inputLeft, outputLeft, outputRight, BUFFER_LENGTH_SAMPLES_PER_CHANNEL); if (nodeList && inputLeft) { - if (!_muted) { - // Measure the loudness of the signal from the microphone and store in audio object - float loudness = 0; - for (int i = 0; i < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) { - loudness += abs(inputLeft[i]); - } - - loudness /= BUFFER_LENGTH_SAMPLES_PER_CHANNEL; - _lastInputLoudness = loudness; - - // add input (@microphone) data to the scope - _scope->addSamples(0, inputLeft, BUFFER_LENGTH_SAMPLES_PER_CHANNEL); + // Measure the loudness of the signal from the microphone and store in audio object + float loudness = 0; + for (int i = 0; i < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) { + loudness += abs(inputLeft[i]); } + + loudness /= BUFFER_LENGTH_SAMPLES_PER_CHANNEL; + _lastInputLoudness = loudness; + + // add input (@microphone) data to the scope + _scope->addSamples(0, inputLeft, BUFFER_LENGTH_SAMPLES_PER_CHANNEL); Node* audioMixer = nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER); @@ -168,8 +171,7 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o dataPacket, BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes); - interface->getBandwidthMeter()->outputStream(BandwidthMeter::AUDIO).updateValue(BUFFER_LENGTH_BYTES_PER_CHANNEL - + leadingBytes); + interface->getBandwidthMeter()->outputStream(BandwidthMeter::AUDIO).updateValue(BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes); } } From 36d4be4e3b9ad28a93d878dea3106c850babc7ee Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 17 Oct 2013 11:05:52 -0700 Subject: [PATCH 15/22] These should actually start at two pi (that's the maximum distance). --- interface/src/avatar/MyAvatar.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index bbdd414494..e1c18089fd 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1162,8 +1162,8 @@ void MyAvatar::updateChatCircle(float deltaTime) { glm::vec3 delta = _position - center; glm::vec3 projected = glm::vec3(glm::dot(right, delta), glm::dot(front, delta), 0.0f); float myAngle = glm::length(projected) > EPSILON ? atan2f(projected.y, projected.x) : 0.0f; - float leftDistance = PIf; - float rightDistance = PIf; + float leftDistance = PI_TIMES_TWO; + float rightDistance = PI_TIMES_TWO; foreach (const SortedAvatar& sortedAvatar, sortedAvatars) { delta = sortedAvatar.avatar->getPosition() - center; projected = glm::vec3(glm::dot(right, delta), glm::dot(front, delta), 0.0f); From c5deed36b0372262fb40e0b4517e7b9515b39982 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 17 Oct 2013 11:56:18 -0700 Subject: [PATCH 16/22] added ifdefs for HAS_AUDIT_CHILDREN and added more memory tracking stats --- .../voxel-server-library/src/VoxelServer.cpp | 55 +++++++++++++----- libraries/voxels/src/VoxelNode.cpp | 58 +++++++++++++++---- libraries/voxels/src/VoxelNode.h | 15 +++-- libraries/voxels/src/VoxelTree.cpp | 2 + 4 files changed, 99 insertions(+), 31 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index e2e1ab3534..b1a0e46074 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -136,26 +136,44 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { mg_printf(connection, "%s", "HTTP/1.0 200 OK\r\n\r\n"); mg_printf(connection, "%s", "Your Voxel Server is running.\r\n"); mg_printf(connection, "%s", "Current Statistics\r\n"); - mg_printf(connection, "Voxel Node Memory Usage: %f MB\r\n", VoxelNode::getVoxelMemoryUsage() / 1000000.f); - mg_printf(connection, "Octcode Memory Usage: %f MB\r\n", VoxelNode::getOctcodeMemoryUsage() / 1000000.f); + mg_printf(connection, "%s", "\r\n"); + mg_printf(connection, "Voxel Node Memory Usage: %8.2f MB\r\n", VoxelNode::getVoxelMemoryUsage() / 1000000.f); + mg_printf(connection, "Octcode Memory Usage: %8.2f MB\r\n", VoxelNode::getOctcodeMemoryUsage() / 1000000.f); + mg_printf(connection, "External Children Memory Usage: %8.2f MB\r\n", + VoxelNode::getExternalChildrenMemoryUsage() / 1000000.f); + mg_printf(connection, "%s", " -----------\r\n"); + mg_printf(connection, " Total: %8.2f MB\r\n", VoxelNode::getTotalMemoryUsage() / 1000000.f); unsigned long nodeCount = VoxelNode::getNodeCount(); unsigned long internalNodeCount = VoxelNode::getInternalNodeCount(); unsigned long leafNodeCount = VoxelNode::getLeafNodeCount(); - mg_printf(connection, "%s", "Current Nodes in scene\r\n"); - mg_printf(connection, " Total Nodes: %lu nodes\r\n", nodeCount); - mg_printf(connection, " Internal Nodes: %lu nodes\r\n", internalNodeCount); - mg_printf(connection, " Leaf Nodes: %lu leaves\r\n", leafNodeCount); + const float AS_PERCENT = 100.0; + mg_printf(connection, "%s", "\r\n"); + mg_printf(connection, "%s", "Current Nodes in scene\r\n"); + mg_printf(connection, " Total Nodes: %10.lu nodes\r\n", nodeCount); + mg_printf(connection, " Internal Nodes: %10.lu nodes (%5.2f%%)\r\n", + internalNodeCount, ((float)internalNodeCount/(float)nodeCount) * AS_PERCENT); + mg_printf(connection, " Leaf Nodes: %10.lu nodes (%5.2f%%)\r\n", + leafNodeCount, ((float)leafNodeCount/(float)nodeCount) * AS_PERCENT); + + mg_printf(connection, "%s", "\r\n"); mg_printf(connection, "%s", "VoxelNode Children Encoding Statistics...\r\n"); - mg_printf(connection, " Single or No Children: %10.llu nodes\r\n", VoxelNode::_singleChildrenCount); - mg_printf(connection, " Two Children as Offset: %10.llu nodes\r\n", VoxelNode::_twoChildrenOffsetCount); - mg_printf(connection, " Two Children as External: %10.llu nodes\r\n", VoxelNode::_twoChildrenExternalCount); - mg_printf(connection, " Three Children as Offset: %10.llu nodes\r\n", VoxelNode::_threeChildrenOffsetCount); - mg_printf(connection, " Three Children as External: %10.llu nodes\r\n", VoxelNode::_threeChildrenExternalCount); - mg_printf(connection, " Children as External Array: %10.llu nodes\r\n", VoxelNode::_externalChildrenCount); - + mg_printf(connection, " Single or No Children: %10.llu nodes (%5.2f%%)\r\n", + VoxelNode::_singleChildrenCount, ((float)VoxelNode::_singleChildrenCount/(float)nodeCount) * AS_PERCENT); + mg_printf(connection, " Two Children as Offset: %10.llu nodes (%5.2f%%)\r\n", + VoxelNode::_twoChildrenOffsetCount, ((float)VoxelNode::_twoChildrenOffsetCount/(float)nodeCount) * AS_PERCENT); + mg_printf(connection, " Two Children as External: %10.llu nodes (%5.2f%%)\r\n", + VoxelNode::_twoChildrenExternalCount, ((float)VoxelNode::_twoChildrenExternalCount/(float)nodeCount) * AS_PERCENT); + mg_printf(connection, " Three Children as Offset: %10.llu nodes (%5.2f%%)\r\n", + VoxelNode::_threeChildrenOffsetCount, ((float)VoxelNode::_threeChildrenOffsetCount/(float)nodeCount) * AS_PERCENT); + mg_printf(connection, " Three Children as External: %10.llu nodes (%5.2f%%)\r\n", + VoxelNode::_threeChildrenExternalCount, + ((float)VoxelNode::_threeChildrenExternalCount/(float)nodeCount) * AS_PERCENT); + mg_printf(connection, " Children as External Array: %10.llu nodes (%5.2f%%)\r\n", + VoxelNode::_externalChildrenCount, ((float)VoxelNode::_externalChildrenCount/(float)nodeCount) * AS_PERCENT); + uint64_t checkSum = VoxelNode::_singleChildrenCount + VoxelNode::_twoChildrenOffsetCount + VoxelNode::_twoChildrenExternalCount + VoxelNode::_threeChildrenOffsetCount + VoxelNode::_threeChildrenExternalCount + @@ -165,6 +183,17 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { mg_printf(connection, " Total: %10.llu nodes\r\n", checkSum); mg_printf(connection, " Expected: %10.lu nodes\r\n", nodeCount); + mg_printf(connection, "%s", "\r\n"); + mg_printf(connection, "%s", "VoxelNode Children Population Statistics...\r\n"); + checkSum = 0; + for (int i=0; i <= NUMBER_OF_CHILDREN; i++) { + checkSum += VoxelNode::_childrenCount[i]; + mg_printf(connection, " Nodes with %d children: %10.llu nodes (%5.2f%%)\r\n", i, + VoxelNode::_childrenCount[i], ((float)VoxelNode::_childrenCount[i]/(float)nodeCount) * AS_PERCENT); + } + mg_printf(connection, "%s", " ----------------\r\n"); + mg_printf(connection, " Total: %10.llu nodes\r\n", checkSum); + return 1; } else { // have mongoose process this request from the document_root diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index b8f8a28dfa..9654572ec1 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -24,6 +24,7 @@ uint64_t VoxelNode::_voxelMemoryUsage = 0; uint64_t VoxelNode::_octcodeMemoryUsage = 0; +uint64_t VoxelNode::_externalChildrenMemoryUsage = 0; uint64_t VoxelNode::_voxelNodeCount = 0; uint64_t VoxelNode::_voxelNodeLeafCount = 0; @@ -66,13 +67,14 @@ void VoxelNode::init(unsigned char * octalCode) { _childrenExternal = false; _children.external = NULL; _singleChildrenCount++; + _childrenCount[0]++; // default pointers to child nodes to NULL - /**/ +#ifdef HAS_AUDIT_CHILDREN for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { _childrenArray[i] = NULL; } - /**/ +#endif // def HAS_AUDIT_CHILDREN _unknownBufferIndex = true; @@ -199,7 +201,9 @@ void VoxelNode::deleteChildAtIndex(int childIndex) { _voxelNodeLeafCount++; } } +#ifdef HAS_AUDIT_CHILDREN auditChildren("deleteChildAtIndex()"); +#endif // def HAS_AUDIT_CHILDREN } // does not delete the node! @@ -216,12 +220,14 @@ VoxelNode* VoxelNode::removeChildAtIndex(int childIndex) { } } +#ifdef HAS_AUDIT_CHILDREN auditChildren("removeChildAtIndex()"); +#endif // def HAS_AUDIT_CHILDREN return returnedChild; } +#ifdef HAS_AUDIT_CHILDREN void VoxelNode::auditChildren(const char* label) const { - return; bool auditFailed = false; for (int childIndex = 0; childIndex < NUMBER_OF_CHILDREN; childIndex++) { VoxelNode* testChildNew = getChildAtIndex(childIndex); @@ -252,6 +258,8 @@ void VoxelNode::auditChildren(const char* label) const { printf("%s... auditChildren() <<<< DONE <<<< \n", label); } } +#endif // def HAS_AUDIT_CHILDREN + uint64_t VoxelNode::_getChildAtIndexTime = 0; uint64_t VoxelNode::_getChildAtIndexCalls = 0; @@ -264,6 +272,7 @@ uint64_t VoxelNode::_twoChildrenExternalCount = 0; uint64_t VoxelNode::_threeChildrenOffsetCount = 0; uint64_t VoxelNode::_threeChildrenExternalCount = 0; uint64_t VoxelNode::_externalChildrenCount = 0; +uint64_t VoxelNode::_childrenCount[NUMBER_OF_CHILDREN + 1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; VoxelNode* VoxelNode::getChildAtIndex(int childIndex) const { PerformanceWarning warn(false,"getChildAtIndex",false,&_getChildAtIndexTime,&_getChildAtIndexCalls); @@ -348,10 +357,12 @@ VoxelNode* VoxelNode::getChildAtIndex(int childIndex) const { } } break; } +#ifdef HAS_AUDIT_CHILDREN if (result != _childrenArray[childIndex]) { printf("getChildAtIndex() case:%s result<%p> != _childrenArray[childIndex]<%p> <<<<<<<<<< WARNING!!! \n", caseStr, result,_childrenArray[childIndex]); } +#endif // def HAS_AUDIT_CHILDREN return result; } @@ -365,6 +376,8 @@ void VoxelNode::storeTwoChildren(VoxelNode* childOne, VoxelNode* childTwo) { if (isBetween(offsetOne, maxOffset, minOffset) && isBetween(offsetTwo, maxOffset, minOffset)) { // if previously external, then clean it up... if (_childrenExternal) { + const int previousChildCount = 2; + _externalChildrenMemoryUsage -= previousChildCount * sizeof(VoxelNode*); delete[] _children.external; _children.external = NULL; // probably not needed! _childrenExternal = false; @@ -381,7 +394,9 @@ void VoxelNode::storeTwoChildren(VoxelNode* childOne, VoxelNode* childTwo) { // if not previously external, then allocate appropriately if (!_childrenExternal) { _childrenExternal = true; - _children.external = new VoxelNode*[2]; + const int newChildCount = 2; + _externalChildrenMemoryUsage += newChildCount * sizeof(VoxelNode*); + _children.external = new VoxelNode*[newChildCount]; } _children.external[0] = childOne; _children.external[1] = childTwo; @@ -398,6 +413,8 @@ void VoxelNode::retrieveTwoChildren(VoxelNode*& childOne, VoxelNode*& childTwo) _children.external = NULL; // probably not needed! _childrenExternal = false; _twoChildrenExternalCount--; + const int newChildCount = 2; + _externalChildrenMemoryUsage -= newChildCount * sizeof(VoxelNode*); } else { int64_t offsetOne = _children.offsetsTwoChildren[0]; int64_t offsetTwo = _children.offsetsTwoChildren[1]; @@ -473,6 +490,8 @@ void VoxelNode::storeThreeChildren(VoxelNode* childOne, VoxelNode* childTwo, Vox delete[] _children.external; _children.external = NULL; // probably not needed! _childrenExternal = false; + const int previousChildCount = 3; + _externalChildrenMemoryUsage -= previousChildCount * sizeof(VoxelNode*); } // encode in union encodeThreeOffsets(offsetOne, offsetTwo, offsetThree); @@ -483,7 +502,9 @@ void VoxelNode::storeThreeChildren(VoxelNode* childOne, VoxelNode* childTwo, Vox // if not previously external, then allocate appropriately if (!_childrenExternal) { _childrenExternal = true; - _children.external = new VoxelNode*[3]; + const int newChildCount = 3; + _externalChildrenMemoryUsage += newChildCount * sizeof(VoxelNode*); + _children.external = new VoxelNode*[newChildCount]; } _children.external[0] = childOne; _children.external[1] = childTwo; @@ -502,6 +523,7 @@ void VoxelNode::retrieveThreeChildren(VoxelNode*& childOne, VoxelNode*& childTwo _children.external = NULL; // probably not needed! _childrenExternal = false; _threeChildrenExternalCount--; + _externalChildrenMemoryUsage -= 3 * sizeof(VoxelNode*); } else { int64_t offsetOne, offsetTwo, offsetThree; decodeThreeOffsets(offsetOne, offsetTwo, offsetThree); @@ -530,6 +552,12 @@ void VoxelNode::setChildAtIndex(int childIndex, VoxelNode* child) { clearAtBit(_childBitmask, childIndex); } int newChildCount = getChildCount(); + + // track our population data + if (previousChildCount != newChildCount) { + _childrenCount[previousChildCount]--; + _childrenCount[newChildCount]++; + } // If we had 0 children and we still have 0 children, then there is nothing to do. if (previousChildCount == 0 && newChildCount == 0) { @@ -640,11 +668,9 @@ void VoxelNode::setChildAtIndex(int childIndex, VoxelNode* child) { // We need to determine which children we had, and which one we got rid of... int indexOne = getNthBit(previousChildMask, 1); int indexTwo = getNthBit(previousChildMask, 2); - int indexThree = getNthBit(previousChildMask, 3); bool removeChildOne = indexOne == childIndex; bool removeChildTwo = indexTwo == childIndex; - bool removeChildThree = indexThree == childIndex; VoxelNode* childOne; VoxelNode* childTwo; @@ -669,11 +695,9 @@ void VoxelNode::setChildAtIndex(int childIndex, VoxelNode* child) { // We need to determine which children we had, and which one we got rid of... int indexOne = getNthBit(previousChildMask, 1); int indexTwo = getNthBit(previousChildMask, 2); - int indexThree = getNthBit(previousChildMask, 3); bool replaceChildOne = indexOne == childIndex; bool replaceChildTwo = indexTwo == childIndex; - bool replaceChildThree = indexThree == childIndex; VoxelNode* childOne; VoxelNode* childTwo; @@ -726,7 +750,9 @@ void VoxelNode::setChildAtIndex(int childIndex, VoxelNode* child) { // now, allocate the external... _childrenExternal = true; - _children.external = new VoxelNode*[4]; + const int newChildCount = 4; + _children.external = new VoxelNode*[newChildCount]; + _externalChildrenMemoryUsage += newChildCount * sizeof(VoxelNode*); _children.external[0] = childOne; _children.external[1] = childTwo; @@ -741,12 +767,10 @@ void VoxelNode::setChildAtIndex(int childIndex, VoxelNode* child) { int indexOne = getNthBit(previousChildMask, 1); int indexTwo = getNthBit(previousChildMask, 2); int indexThree = getNthBit(previousChildMask, 3); - int indexFour = getNthBit(previousChildMask, 4); bool removeChildOne = indexOne == childIndex; bool removeChildTwo = indexTwo == childIndex; bool removeChildThree = indexThree == childIndex; - bool removeChildFour = indexFour == childIndex; VoxelNode* childOne = _children.external[0]; VoxelNode* childTwo = _children.external[1]; @@ -771,6 +795,8 @@ void VoxelNode::setChildAtIndex(int childIndex, VoxelNode* child) { delete[] _children.external; _children.external = NULL; _externalChildrenCount--; + _externalChildrenMemoryUsage -= previousChildCount * sizeof(VoxelNode*); + storeThreeChildren(childOne, childTwo, childThree); } else if (previousChildCount == newChildCount) { @@ -813,6 +839,9 @@ void VoxelNode::setChildAtIndex(int childIndex, VoxelNode* child) { } delete[] _children.external; _children.external = newExternalList; + _externalChildrenMemoryUsage -= previousChildCount * sizeof(VoxelNode*); + _externalChildrenMemoryUsage += newChildCount * sizeof(VoxelNode*); + } else if (previousChildCount > newChildCount) { // 4 or more children, one item being removed, we know we're stored externally, we just figure out which // item to remove from our external list @@ -833,12 +862,17 @@ void VoxelNode::setChildAtIndex(int childIndex, VoxelNode* child) { } delete[] _children.external; _children.external = newExternalList; + _externalChildrenMemoryUsage -= previousChildCount * sizeof(VoxelNode*); + _externalChildrenMemoryUsage += newChildCount * sizeof(VoxelNode*); } else { assert(false); printf("THIS SHOULD NOT HAPPEN previousChildCount == %d && newChildCount == %d\n",previousChildCount, newChildCount); } + +#ifdef HAS_AUDIT_CHILDREN _childrenArray[childIndex] = child; auditChildren("setChildAtIndex()"); +#endif // def HAS_AUDIT_CHILDREN } diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index fc0aa44e47..a82b39e93d 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -116,6 +116,8 @@ public: static uint64_t getVoxelMemoryUsage() { return _voxelMemoryUsage; } static uint64_t getOctcodeMemoryUsage() { return _octcodeMemoryUsage; } + static uint64_t getExternalChildrenMemoryUsage() { return _externalChildrenMemoryUsage; } + static uint64_t getTotalMemoryUsage() { return _voxelMemoryUsage + _octcodeMemoryUsage + _externalChildrenMemoryUsage; } static uint64_t _getChildAtIndexTime; static uint64_t _getChildAtIndexCalls; @@ -128,8 +130,11 @@ public: static uint64_t _threeChildrenOffsetCount; static uint64_t _threeChildrenExternalCount; static uint64_t _externalChildrenCount; + static uint64_t _childrenCount[NUMBER_OF_CHILDREN + 1]; +#ifdef HAS_AUDIT_CHILDREN void auditChildren(const char* label) const; +#endif // def HAS_AUDIT_CHILDREN private: void setChildAtIndex(int childIndex, VoxelNode* child); @@ -140,11 +145,6 @@ private: void decodeThreeOffsets(int64_t& offsetOne, int64_t& offsetTwo, int64_t& offsetThree) const; void encodeThreeOffsets(int64_t offsetOne, int64_t offsetTwo, int64_t offsetThree); - /** - VoxelNode* __new__getChildAtIndex(int childIndex) const; - void __new__setChildAtIndex(int childIndex, VoxelNode* child); - **/ - void calculateAABox(); void init(unsigned char * octalCode); void notifyDeleteHooks(); @@ -168,7 +168,9 @@ private: VoxelNode** external; } _children; - VoxelNode* _childrenArray[8]; /// Client and server, pointers to child nodes, 64 bytes +#ifdef HAS_AUDIT_CHILDREN + VoxelNode* _childrenArray[8]; /// Only used when HAS_AUDIT_CHILDREN is enabled to help debug children encoding +#endif // def HAS_AUDIT_CHILDREN uint32_t _glBufferIndex : 24, /// Client only, vbo index for this voxel if being rendered, 3 bytes _voxelSystemIndex : 8; /// Client only, index to the VoxelSystem rendering this voxel, 1 bytes @@ -204,6 +206,7 @@ private: static uint64_t _voxelMemoryUsage; static uint64_t _octcodeMemoryUsage; + static uint64_t _externalChildrenMemoryUsage; }; diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 5961904aee..e4a142306d 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -710,9 +710,11 @@ VoxelNode* VoxelTree::getVoxelAt(float x, float y, float z, float s) const { node = NULL; } delete[] octalCode; // cleanup memory +#ifdef HAS_AUDIT_CHILDREN if (node) { node->auditChildren("VoxelTree::getVoxelAt()"); } +#endif // def HAS_AUDIT_CHILDREN return node; } From 095b71636619be42332c43d9bec8b018bd1689b0 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 17 Oct 2013 12:16:03 -0700 Subject: [PATCH 17/22] make population stats use public getters and private member variables --- .../src/VoxelPersistThread.cpp | 16 ++- .../voxel-server-library/src/VoxelServer.cpp | 30 ++--- libraries/voxels/src/VoxelNode.h | 108 +++++------------- 3 files changed, 51 insertions(+), 103 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelPersistThread.cpp b/libraries/voxel-server-library/src/VoxelPersistThread.cpp index 93819cc758..55dce2ed9b 100644 --- a/libraries/voxel-server-library/src/VoxelPersistThread.cpp +++ b/libraries/voxel-server-library/src/VoxelPersistThread.cpp @@ -29,9 +29,6 @@ bool VoxelPersistThread::process() { _initialLoad = true; qDebug("loading voxels from file: %s...\n", _filename); - qDebug("sizeof(oldVoxelNode)=%ld sizeof(VoxelNode)=%ld sizeof(smallerVoxelNodeTest1)=%ld sizeof(AABox)=%ld sizeof(oldAABox)=%ld\n", - sizeof(oldVoxelNode), sizeof(VoxelNode), sizeof(smallerVoxelNodeTest1), sizeof(AABox), sizeof(oldAABox)); - bool persistantFileRead = _tree->readFromSVOFile(_filename); if (persistantFileRead) { PerformanceWarning warn(true, "reaverageVoxelColors()", true); @@ -49,12 +46,13 @@ bool VoxelPersistThread::process() { unsigned long leafNodeCount = VoxelNode::getLeafNodeCount(); qDebug("Nodes after loading scene %lu nodes %lu internal %lu leaves\n", nodeCount, internalNodeCount, leafNodeCount); - double usecPerGet = (double)VoxelNode::_getChildAtIndexTime / (double)VoxelNode::_getChildAtIndexCalls; - double usecPerSet = (double)VoxelNode::_setChildAtIndexTime / (double)VoxelNode::_setChildAtIndexCalls; - - printf("_getChildAtIndexCalls=%llu, _getChildAtIndexTime=%llu, perGet=%lf ... _setChildAtIndexCalls=%llu _setChildAtIndexTime=%llu perSet=%lf\n", - VoxelNode::_getChildAtIndexCalls, VoxelNode::_getChildAtIndexTime, usecPerGet, - VoxelNode::_setChildAtIndexCalls, VoxelNode::_setChildAtIndexTime, usecPerSet); + double usecPerGet = (double)VoxelNode::getGetChildAtIndexTime() / (double)VoxelNode::getGetChildAtIndexCalls(); + qDebug("getChildAtIndexCalls=%llu getChildAtIndexTime=%llu perGet=%lf \n", + VoxelNode::getGetChildAtIndexTime(), VoxelNode::getGetChildAtIndexCalls(), usecPerGet); + + double usecPerSet = (double)VoxelNode::getSetChildAtIndexTime() / (double)VoxelNode::getSetChildAtIndexCalls(); + qDebug("setChildAtIndexCalls=%llu setChildAtIndexTime=%llu perSet=%lf\n", + VoxelNode::getSetChildAtIndexTime(), VoxelNode::getSetChildAtIndexCalls(), usecPerSet); } diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index b1a0e46074..e3c120d0bb 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -161,23 +161,27 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { mg_printf(connection, "%s", "\r\n"); mg_printf(connection, "%s", "VoxelNode Children Encoding Statistics...\r\n"); mg_printf(connection, " Single or No Children: %10.llu nodes (%5.2f%%)\r\n", - VoxelNode::_singleChildrenCount, ((float)VoxelNode::_singleChildrenCount/(float)nodeCount) * AS_PERCENT); + VoxelNode::getSingleChildrenCount(), ((float)VoxelNode::getSingleChildrenCount()/(float)nodeCount) * AS_PERCENT); mg_printf(connection, " Two Children as Offset: %10.llu nodes (%5.2f%%)\r\n", - VoxelNode::_twoChildrenOffsetCount, ((float)VoxelNode::_twoChildrenOffsetCount/(float)nodeCount) * AS_PERCENT); + VoxelNode::getTwoChildrenOffsetCount(), + ((float)VoxelNode::getTwoChildrenOffsetCount()/(float)nodeCount) * AS_PERCENT); mg_printf(connection, " Two Children as External: %10.llu nodes (%5.2f%%)\r\n", - VoxelNode::_twoChildrenExternalCount, ((float)VoxelNode::_twoChildrenExternalCount/(float)nodeCount) * AS_PERCENT); + VoxelNode::getTwoChildrenExternalCount(), + ((float)VoxelNode::getTwoChildrenExternalCount()/(float)nodeCount) * AS_PERCENT); mg_printf(connection, " Three Children as Offset: %10.llu nodes (%5.2f%%)\r\n", - VoxelNode::_threeChildrenOffsetCount, ((float)VoxelNode::_threeChildrenOffsetCount/(float)nodeCount) * AS_PERCENT); + VoxelNode::getThreeChildrenOffsetCount(), + ((float)VoxelNode::getThreeChildrenOffsetCount()/(float)nodeCount) * AS_PERCENT); mg_printf(connection, " Three Children as External: %10.llu nodes (%5.2f%%)\r\n", - VoxelNode::_threeChildrenExternalCount, - ((float)VoxelNode::_threeChildrenExternalCount/(float)nodeCount) * AS_PERCENT); + VoxelNode::getThreeChildrenExternalCount(), + ((float)VoxelNode::getThreeChildrenExternalCount()/(float)nodeCount) * AS_PERCENT); mg_printf(connection, " Children as External Array: %10.llu nodes (%5.2f%%)\r\n", - VoxelNode::_externalChildrenCount, ((float)VoxelNode::_externalChildrenCount/(float)nodeCount) * AS_PERCENT); + VoxelNode::getExternalChildrenCount(), + ((float)VoxelNode::getExternalChildrenCount()/(float)nodeCount) * AS_PERCENT); - uint64_t checkSum = VoxelNode::_singleChildrenCount + - VoxelNode::_twoChildrenOffsetCount + VoxelNode::_twoChildrenExternalCount + - VoxelNode::_threeChildrenOffsetCount + VoxelNode::_threeChildrenExternalCount + - VoxelNode::_externalChildrenCount; + uint64_t checkSum = VoxelNode::getSingleChildrenCount() + + VoxelNode::getTwoChildrenOffsetCount() + VoxelNode::getTwoChildrenExternalCount() + + VoxelNode::getThreeChildrenOffsetCount() + VoxelNode::getThreeChildrenExternalCount() + + VoxelNode::getExternalChildrenCount(); mg_printf(connection, "%s", " ----------------\r\n"); mg_printf(connection, " Total: %10.llu nodes\r\n", checkSum); @@ -187,9 +191,9 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { mg_printf(connection, "%s", "VoxelNode Children Population Statistics...\r\n"); checkSum = 0; for (int i=0; i <= NUMBER_OF_CHILDREN; i++) { - checkSum += VoxelNode::_childrenCount[i]; + checkSum += VoxelNode::getChildrenCount(i); mg_printf(connection, " Nodes with %d children: %10.llu nodes (%5.2f%%)\r\n", i, - VoxelNode::_childrenCount[i], ((float)VoxelNode::_childrenCount[i]/(float)nodeCount) * AS_PERCENT); + VoxelNode::getChildrenCount(i), ((float)VoxelNode::getChildrenCount(i)/(float)nodeCount) * AS_PERCENT); } mg_printf(connection, "%s", " ----------------\r\n"); mg_printf(connection, " Total: %10.llu nodes\r\n", checkSum); diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index a82b39e93d..847d74e550 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -118,20 +118,21 @@ public: static uint64_t getOctcodeMemoryUsage() { return _octcodeMemoryUsage; } static uint64_t getExternalChildrenMemoryUsage() { return _externalChildrenMemoryUsage; } static uint64_t getTotalMemoryUsage() { return _voxelMemoryUsage + _octcodeMemoryUsage + _externalChildrenMemoryUsage; } + + static uint64_t getGetChildAtIndexTime() { return _getChildAtIndexTime; } + static uint64_t getGetChildAtIndexCalls() { return _getChildAtIndexCalls; } + static uint64_t getSetChildAtIndexTime() { return _setChildAtIndexTime; } + static uint64_t getSetChildAtIndexCalls() { return _setChildAtIndexCalls; } + + static uint64_t getSingleChildrenCount() { return _singleChildrenCount; } + static uint64_t getTwoChildrenOffsetCount() { return _twoChildrenOffsetCount; } + static uint64_t getTwoChildrenExternalCount() { return _twoChildrenExternalCount; } + static uint64_t getThreeChildrenOffsetCount() { return _threeChildrenOffsetCount; } + static uint64_t getThreeChildrenExternalCount() { return _threeChildrenExternalCount; } + static uint64_t getExternalChildrenCount() { return _externalChildrenCount; } + static uint64_t getChildrenCount(int childCount) { return _childrenCount[childCount]; } + - static uint64_t _getChildAtIndexTime; - static uint64_t _getChildAtIndexCalls; - static uint64_t _setChildAtIndexTime; - static uint64_t _setChildAtIndexCalls; - - static uint64_t _singleChildrenCount; - static uint64_t _twoChildrenOffsetCount; - static uint64_t _twoChildrenExternalCount; - static uint64_t _threeChildrenOffsetCount; - static uint64_t _threeChildrenExternalCount; - static uint64_t _externalChildrenCount; - static uint64_t _childrenCount[NUMBER_OF_CHILDREN + 1]; - #ifdef HAS_AUDIT_CHILDREN void auditChildren(const char* label) const; #endif // def HAS_AUDIT_CHILDREN @@ -207,74 +208,19 @@ private: static uint64_t _voxelMemoryUsage; static uint64_t _octcodeMemoryUsage; static uint64_t _externalChildrenMemoryUsage; + + static uint64_t _getChildAtIndexTime; + static uint64_t _getChildAtIndexCalls; + static uint64_t _setChildAtIndexTime; + static uint64_t _setChildAtIndexCalls; + + static uint64_t _singleChildrenCount; + static uint64_t _twoChildrenOffsetCount; + static uint64_t _twoChildrenExternalCount; + static uint64_t _threeChildrenOffsetCount; + static uint64_t _threeChildrenExternalCount; + static uint64_t _externalChildrenCount; + static uint64_t _childrenCount[NUMBER_OF_CHILDREN + 1]; }; - -class oldVoxelNode { -public: - - VoxelNode* _children[8]; /// Client and server, pointers to child nodes, 64 bytes - oldAABox _box; /// Client and server, axis aligned box for bounds of this voxel, 48 bytes - unsigned char* _octalCode; /// Client and server, pointer to octal code for this node, 8 bytes - - uint64_t _lastChanged; /// Client and server, timestamp this node was last changed, 8 bytes - unsigned long _subtreeNodeCount; /// Client and server, nodes below this node, 8 bytes - unsigned long _subtreeLeafNodeCount; /// Client and server, leaves below this node, 8 bytes - - glBufferIndex _glBufferIndex; /// Client only, vbo index for this voxel if being rendered, 8 bytes - VoxelSystem* _voxelSystem; /// Client only, pointer to VoxelSystem rendering this voxel, 8 bytes - - float _density; /// Client and server, If leaf: density = 1, if internal node: 0-1 density of voxels inside, 4 bytes - int _childCount; /// Client and server, current child nodes set to non-null in _children, 4 bytes - - nodeColor _trueColor; /// Client and server, true color of this voxel, 4 bytes - nodeColor _currentColor; /// Client only, false color of this voxel, 4 bytes - bool _falseColored; /// Client only, is this voxel false colored, 1 bytes - - bool _isDirty; /// Client only, has this voxel changed since being rendered, 1 byte - bool _shouldRender; /// Client only, should this voxel render at this time, 1 byte - uint16_t _sourceID; /// Client only, stores node id of voxel server that sent his voxel, 2 bytes -}; - -class smallerVoxelNodeTest1 { -public: - AABox _box; // 48 bytes - 4x glm::vec3, 3 floats x 4 bytes = 48 bytes - // 16 bytes... 1x glm::vec3 + 1 float - - union octalCode_t { - unsigned char _octalCodeBuffer[8]; - unsigned char* _octalCodePointer; - } _octalCode; /// Client and server, buffer containing the octal code if it's smaller than 8 bytes or a - /// pointer to octal code for this node, 8 bytes - - - uint32_t _glBufferIndex : 24, /// Client only, vbo index for this voxel if being rendered, 3 bytes - _voxelSystemIndex : 8; /// Client only, index to the VoxelSystem rendering this voxel, 1 bytes - - - uint64_t _lastChanged; // 8 bytes, could be less? - - void* _children; // 8 bytes (for 0 or 1 children), or 8 bytes * count + 1 - - - nodeColor _trueColor; // 4 bytes, could be 3 bytes + 1 bit - nodeColor _currentColor; // 4 bytes ** CLIENT ONLY ** - - - float _density; // 4 bytes - If leaf: density = 1, if internal node: 0-1 density of voxels inside... 4 bytes? do we need this? - // could make this 1 or 2 byte linear ratio... - - - uint16_t _sourceID; // 2 bytes - only used to colorize and kill sources? ** CLIENT ONLY ** - - unsigned char _childBitmask; // 1 byte - - // Bitmask.... // 1 byte... made up of 5 bits so far... room for 3 more bools... - unsigned char _falseColored : 1, // 1 bit - _shouldRender : 1, // 1 bit - _isDirty : 1, // 1 bit - _octcodePointer : 1, // 1 bit - _unknownBufferIndex : 1; // 1 bit - -}; #endif /* defined(__hifi__VoxelNode__) */ \ No newline at end of file From fbf1a75d07690903d1e307504bd842305ac43e35 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 17 Oct 2013 12:24:53 -0700 Subject: [PATCH 18/22] cleanup dead code --- libraries/shared/src/SharedUtil.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 9708b0c95a..3d4759c98a 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -106,15 +106,9 @@ void setAtBit(unsigned char& byte, int bitIndex) { } void clearAtBit(unsigned char& byte, int bitIndex) { - //printf("clearAtBit() bitIndex=%d byte=",bitIndex); - //outputBits(byte); - if (oneAtBit(byte, bitIndex)) { byte -= (1 << (7 - bitIndex)); } - - //printf("... now byte="); - //outputBits(byte); } int getSemiNibbleAt(unsigned char& byte, int bitIndex) { From 515dc657fbbf4b5f555ccb72fe929659654a64ea Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 17 Oct 2013 12:26:01 -0700 Subject: [PATCH 19/22] cleanup dead code --- libraries/voxel-server-library/src/VoxelSendThread.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 0b9ba6b165..ac2c56d2d3 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -53,16 +53,6 @@ bool VoxelSendThread::process() { } } - // debug some timing... - /*** - double usecPerGet = (double)VoxelNode::_getChildAtIndexTime / (double)VoxelNode::_getChildAtIndexCalls; - double usecPerSet = (double)VoxelNode::_setChildAtIndexTime / (double)VoxelNode::_setChildAtIndexCalls; - - printf("_getChildAtIndexCalls=%llu, _getChildAtIndexTime=%llu, perGet=%lf ... _setChildAtIndexCalls=%llu _setChildAtIndexTime=%llu perSet=%lf\n", - VoxelNode::_getChildAtIndexCalls, VoxelNode::_getChildAtIndexTime, usecPerGet, - VoxelNode::_setChildAtIndexCalls, VoxelNode::_setChildAtIndexTime, usecPerSet); - ***/ - return isStillRunning(); // keep running till they terminate us } From 8448e47df82b2fddaa955d8781755b9dae6ad05f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 17 Oct 2013 12:27:23 -0700 Subject: [PATCH 20/22] cleanup dead code --- libraries/voxels/src/AABox.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/libraries/voxels/src/AABox.h b/libraries/voxels/src/AABox.h index 0ad2878a88..aec0fff450 100644 --- a/libraries/voxels/src/AABox.h +++ b/libraries/voxels/src/AABox.h @@ -78,12 +78,4 @@ private: float _scale; }; -class oldAABox { - glm::vec3 _corner; - glm::vec3 _size; - glm::vec3 _center; - glm::vec3 _topFarLeft; -}; - - #endif From 6688b450c514a5ce72676c90cf9e866194a18fc3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 17 Oct 2013 12:31:18 -0700 Subject: [PATCH 21/22] cleaned up some printf's to qDebug's --- libraries/voxels/src/VoxelNode.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 9654572ec1..dc29c57f19 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -187,8 +187,6 @@ void VoxelNode::calculateAABox() { } void VoxelNode::deleteChildAtIndex(int childIndex) { - //printf("deleteChildAtIndex(%d)\n",childIndex); - VoxelNode* childAt = getChildAtIndex(childIndex); if (childAt) { delete childAt; @@ -239,10 +237,10 @@ void VoxelNode::auditChildren(const char* label) const { } if (auditFailed) { - printf("%s... auditChildren() %s <<<< \n", label, (auditFailed ? "FAILED" : "PASSED")); - printf(" _childrenExternal=%s\n", debug::valueOf(_childrenExternal)); - printf(" childCount=%d\n", getChildCount()); - printf(" _childBitmask="); + qDebug("%s... auditChildren() %s <<<< \n", label, (auditFailed ? "FAILED" : "PASSED")); + qDebug(" _childrenExternal=%s\n", debug::valueOf(_childrenExternal)); + qDebug(" childCount=%d\n", getChildCount()); + qDebug(" _childBitmask="); outputBits(_childBitmask); @@ -250,12 +248,12 @@ void VoxelNode::auditChildren(const char* label) const { VoxelNode* testChildNew = getChildAtIndex(childIndex); VoxelNode* testChildOld = _childrenArray[childIndex]; - printf("child at index %d... testChildOld=%p testChildNew=%p %s \n", + qDebug("child at index %d... testChildOld=%p testChildNew=%p %s \n", childIndex, testChildOld, testChildNew , ((testChildNew != testChildOld) ? " DOES NOT MATCH <<<< BAD <<<<" : " - OK ") ); } - printf("%s... auditChildren() <<<< DONE <<<< \n", label); + qDebug("%s... auditChildren() <<<< DONE <<<< \n", label); } } #endif // def HAS_AUDIT_CHILDREN @@ -342,7 +340,6 @@ VoxelNode* VoxelNode::getChildAtIndex(int childIndex) const { } break; default: { caseStr = "default"; - //printf("default case...\n"); // if we have 4 or more, we know we're in external mode, so we just need to figure out which // slot in our external array this child is. if (oneAtBit(_childBitmask, childIndex)) { @@ -359,7 +356,7 @@ VoxelNode* VoxelNode::getChildAtIndex(int childIndex) const { } #ifdef HAS_AUDIT_CHILDREN if (result != _childrenArray[childIndex]) { - printf("getChildAtIndex() case:%s result<%p> != _childrenArray[childIndex]<%p> <<<<<<<<<< WARNING!!! \n", + qDebug("getChildAtIndex() case:%s result<%p> != _childrenArray[childIndex]<%p> <<<<<<<<<< WARNING!!! \n", caseStr, result,_childrenArray[childIndex]); } #endif // def HAS_AUDIT_CHILDREN @@ -866,7 +863,7 @@ void VoxelNode::setChildAtIndex(int childIndex, VoxelNode* child) { _externalChildrenMemoryUsage += newChildCount * sizeof(VoxelNode*); } else { assert(false); - printf("THIS SHOULD NOT HAPPEN previousChildCount == %d && newChildCount == %d\n",previousChildCount, newChildCount); + qDebug("THIS SHOULD NOT HAPPEN previousChildCount == %d && newChildCount == %d\n",previousChildCount, newChildCount); } #ifdef HAS_AUDIT_CHILDREN From 8d7874b01bc4a1201303698f7489c9239f680f41 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 17 Oct 2013 13:47:18 -0700 Subject: [PATCH 22/22] add guards to prevent runaway reaverageVoxels(), added stats to see if 4 children could be packed internally --- .../src/VoxelPersistThread.cpp | 13 ++++++-- .../voxel-server-library/src/VoxelServer.cpp | 9 +++++- libraries/voxels/src/VoxelNode.cpp | 31 ++++++++++++++++++- libraries/voxels/src/VoxelNode.h | 8 ++++- libraries/voxels/src/VoxelTree.cpp | 16 +++++++++- 5 files changed, 70 insertions(+), 7 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelPersistThread.cpp b/libraries/voxel-server-library/src/VoxelPersistThread.cpp index 55dce2ed9b..75954aacec 100644 --- a/libraries/voxel-server-library/src/VoxelPersistThread.cpp +++ b/libraries/voxel-server-library/src/VoxelPersistThread.cpp @@ -29,13 +29,20 @@ bool VoxelPersistThread::process() { _initialLoad = true; qDebug("loading voxels from file: %s...\n", _filename); - bool persistantFileRead = _tree->readFromSVOFile(_filename); + bool persistantFileRead; + + { + PerformanceWarning warn(true, "Loading Voxel File", true); + persistantFileRead = _tree->readFromSVOFile(_filename); + } + if (persistantFileRead) { - PerformanceWarning warn(true, "reaverageVoxelColors()", true); + PerformanceWarning warn(true, "Voxels Re-Averaging", true); // after done inserting all these voxels, then reaverage colors + qDebug("BEGIN Voxels Re-Averaging\n"); _tree->reaverageVoxelColors(_tree->rootNode); - qDebug("Voxels reAveraged\n"); + qDebug("DONE WITH Voxels Re-Averaging\n"); } _tree->clearDirtyBit(); // the tree is clean since we just loaded it diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index e3c120d0bb..0983abffb8 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -186,7 +186,7 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { mg_printf(connection, "%s", " ----------------\r\n"); mg_printf(connection, " Total: %10.llu nodes\r\n", checkSum); mg_printf(connection, " Expected: %10.lu nodes\r\n", nodeCount); - + mg_printf(connection, "%s", "\r\n"); mg_printf(connection, "%s", "VoxelNode Children Population Statistics...\r\n"); checkSum = 0; @@ -198,6 +198,13 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { mg_printf(connection, "%s", " ----------------\r\n"); mg_printf(connection, " Total: %10.llu nodes\r\n", checkSum); + mg_printf(connection, "%s", "\r\n"); + mg_printf(connection, "%s", "In other news....\r\n"); + mg_printf(connection, "could store 4 children internally: %10.llu nodes\r\n", + VoxelNode::getCouldStoreFourChildrenInternally()); + mg_printf(connection, "could NOT store 4 children internally: %10.llu nodes\r\n", + VoxelNode::getCouldNotStoreFourChildrenInternally()); + return 1; } else { // have mongoose process this request from the document_root diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index dc29c57f19..39099b44ba 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -271,6 +271,8 @@ uint64_t VoxelNode::_threeChildrenOffsetCount = 0; uint64_t VoxelNode::_threeChildrenExternalCount = 0; uint64_t VoxelNode::_externalChildrenCount = 0; uint64_t VoxelNode::_childrenCount[NUMBER_OF_CHILDREN + 1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +uint64_t VoxelNode::_couldStoreFourChildrenInternally = 0; +uint64_t VoxelNode::_couldNotStoreFourChildrenInternally = 0; VoxelNode* VoxelNode::getChildAtIndex(int childIndex) const { PerformanceWarning warn(false,"getChildAtIndex",false,&_getChildAtIndexTime,&_getChildAtIndexCalls); @@ -531,6 +533,27 @@ void VoxelNode::retrieveThreeChildren(VoxelNode*& childOne, VoxelNode*& childTwo _threeChildrenOffsetCount--; } } + +void VoxelNode::checkStoreFourChildren(VoxelNode* childOne, VoxelNode* childTwo, VoxelNode* childThree, VoxelNode* childFour) { + int64_t offsetOne = (uint8_t*)childOne - (uint8_t*)this; + int64_t offsetTwo = (uint8_t*)childTwo - (uint8_t*)this; + int64_t offsetThree = (uint8_t*)childThree - (uint8_t*)this; + int64_t offsetFour = (uint8_t*)childFour - (uint8_t*)this; + + const int64_t minOffset = std::numeric_limits::min(); + const int64_t maxOffset = std::numeric_limits::max(); + + if (isBetween(offsetOne, maxOffset, minOffset) && + isBetween(offsetTwo, maxOffset, minOffset) && + isBetween(offsetThree, maxOffset, minOffset) && + isBetween(offsetFour, maxOffset, minOffset) + ) { + _couldStoreFourChildrenInternally++; + } else { + _couldNotStoreFourChildrenInternally++; + } +} + void VoxelNode::setChildAtIndex(int childIndex, VoxelNode* child) { PerformanceWarning warn(false,"setChildAtIndex",false,&_setChildAtIndexTime,&_setChildAtIndexCalls); @@ -750,7 +773,7 @@ void VoxelNode::setChildAtIndex(int childIndex, VoxelNode* child) { const int newChildCount = 4; _children.external = new VoxelNode*[newChildCount]; _externalChildrenMemoryUsage += newChildCount * sizeof(VoxelNode*); - + _children.external[0] = childOne; _children.external[1] = childTwo; _children.external[2] = childThree; @@ -866,6 +889,12 @@ void VoxelNode::setChildAtIndex(int childIndex, VoxelNode* child) { qDebug("THIS SHOULD NOT HAPPEN previousChildCount == %d && newChildCount == %d\n",previousChildCount, newChildCount); } + // check to see if we could store these 4 children locally + if (getChildCount() == 4 && _childrenExternal && _children.external) { + checkStoreFourChildren(_children.external[0], _children.external[1], _children.external[2], _children.external[3]); + } + + #ifdef HAS_AUDIT_CHILDREN _childrenArray[childIndex] = child; auditChildren("setChildAtIndex()"); diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 847d74e550..1734bb5c87 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -131,7 +131,9 @@ public: static uint64_t getThreeChildrenExternalCount() { return _threeChildrenExternalCount; } static uint64_t getExternalChildrenCount() { return _externalChildrenCount; } static uint64_t getChildrenCount(int childCount) { return _childrenCount[childCount]; } - + + static uint64_t getCouldStoreFourChildrenInternally() { return _couldStoreFourChildrenInternally; } + static uint64_t getCouldNotStoreFourChildrenInternally() { return _couldNotStoreFourChildrenInternally; } #ifdef HAS_AUDIT_CHILDREN void auditChildren(const char* label) const; @@ -145,6 +147,7 @@ private: void retrieveThreeChildren(VoxelNode*& childOne, VoxelNode*& childTwo, VoxelNode*& childThree); void decodeThreeOffsets(int64_t& offsetOne, int64_t& offsetTwo, int64_t& offsetThree) const; void encodeThreeOffsets(int64_t offsetOne, int64_t offsetTwo, int64_t offsetThree); + void checkStoreFourChildren(VoxelNode* childOne, VoxelNode* childTwo, VoxelNode* childThree, VoxelNode* childFour); void calculateAABox(); void init(unsigned char * octalCode); @@ -221,6 +224,9 @@ private: static uint64_t _threeChildrenExternalCount; static uint64_t _externalChildrenCount; static uint64_t _childrenCount[NUMBER_OF_CHILDREN + 1]; + + static uint64_t _couldStoreFourChildrenInternally; + static uint64_t _couldNotStoreFourChildrenInternally; }; #endif /* defined(__hifi__VoxelNode__) */ \ No newline at end of file diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index e4a142306d..3911560f66 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -630,9 +630,22 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { } // Note: this is an expensive call. Don't call it unless you really need to reaverage the entire tree (from startNode) -void VoxelTree::reaverageVoxelColors(VoxelNode *startNode) { +void VoxelTree::reaverageVoxelColors(VoxelNode* startNode) { // if our tree is a reaveraging tree, then we do this, otherwise we don't do anything if (_shouldReaverage) { + static int recursionCount; + if (startNode == rootNode) { + recursionCount = 0; + } else { + recursionCount++; + } + const int UNREASONABLY_DEEP_RECURSION = 20; + if (recursionCount > UNREASONABLY_DEEP_RECURSION) { + qDebug("VoxelTree::reaverageVoxelColors()... bailing out of UNREASONABLY_DEEP_RECURSION\n"); + recursionCount--; + return; + } + bool hasChildren = false; for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { @@ -647,6 +660,7 @@ void VoxelTree::reaverageVoxelColors(VoxelNode *startNode) { if (hasChildren && !startNode->collapseIdenticalLeaves()) { startNode->setColorFromAverageOfChildren(); } + recursionCount--; } }