From 02d0dbbfba0f85849dc086e96c2c6ea6bfc51acb Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 13 May 2013 15:40:27 -0700 Subject: [PATCH 01/13] move view frustum management to VoxelAgentData class --- voxel-server/src/VoxelAgentData.cpp | 21 +++++++++++++++++++++ voxel-server/src/VoxelAgentData.h | 6 ++++++ voxel-server/src/main.cpp | 22 +++------------------- 3 files changed, 30 insertions(+), 19 deletions(-) diff --git a/voxel-server/src/VoxelAgentData.cpp b/voxel-server/src/VoxelAgentData.cpp index 32526be383..07bf2a6593 100644 --- a/voxel-server/src/VoxelAgentData.cpp +++ b/voxel-server/src/VoxelAgentData.cpp @@ -50,3 +50,24 @@ VoxelAgentData::VoxelAgentData(const VoxelAgentData &otherAgentData) { VoxelAgentData* VoxelAgentData::clone() const { return new VoxelAgentData(*this); } + +void VoxelAgentData::updateViewFrustum() { + // save our currentViewFrustum into our lastKnownViewFrustum + lastKnownViewFrustum = currentViewFrustum; + + // get position and orientation details from the camera + currentViewFrustum.setPosition(getCameraPosition()); + currentViewFrustum.setOrientation(getCameraDirection(), getCameraUp(), getCameraRight()); + + // Also make sure it's got the correct lens details from the camera + currentViewFrustum.setFieldOfView(getCameraFov()); + currentViewFrustum.setAspectRatio(getCameraAspectRatio()); + currentViewFrustum.setNearClip(getCameraNearClip()); + currentViewFrustum.setFarClip(getCameraFarClip()); + + // if there has been a change, then recalculate + if (!lastKnownViewFrustum.matches(currentViewFrustum)) { + currentViewFrustum.calculate(); + } +} + diff --git a/voxel-server/src/VoxelAgentData.h b/voxel-server/src/VoxelAgentData.h index 74a402bb78..ee8b2dd660 100644 --- a/voxel-server/src/VoxelAgentData.h +++ b/voxel-server/src/VoxelAgentData.h @@ -40,6 +40,12 @@ public: void setMaxLevelReached(int maxLevelReached) { _maxLevelReachedInLastSearch = maxLevelReached; } VoxelNodeBag nodeBag; + + ViewFrustum currentViewFrustum; + ViewFrustum lastKnownViewFrustum; + + void updateViewFrustum(); + private: unsigned char* _voxelPacket; unsigned char* _voxelPacketAt; diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 29b211e44f..76941d9bc2 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -109,8 +109,6 @@ void resInVoxelDistributor(AgentList* agentList, AgentList::iterator& agent, VoxelAgentData* agentData, ViewFrustum& viewFrustum) { - - printf("resInVoxelDistributor()\n"); bool searchReset = false; int searchLoops = 0; int searchLevelWas = agentData->getMaxSearchLevel(); @@ -228,9 +226,6 @@ void deepestLevelVoxelDistributor(AgentList* agentList, AgentList::iterator& agent, VoxelAgentData* agentData, ViewFrustum& viewFrustum) { - - printf("deepestLevelVoxelDistributor()\n"); - int maxLevelReached = 0; double start = usecTimestampNow(); if (agentData->nodeBag.isEmpty()) { @@ -340,23 +335,12 @@ void *distributeVoxelsToListeners(void *args) { // Sometimes the agent data has not yet been linked, in which case we can't really do anything if (agentData) { - ViewFrustum viewFrustum; - // get position and orientation details from the camera - viewFrustum.setPosition(agentData->getCameraPosition()); - viewFrustum.setOrientation(agentData->getCameraDirection(), agentData->getCameraUp(), agentData->getCameraRight()); - - // Also make sure it's got the correct lens details from the camera - viewFrustum.setFieldOfView(agentData->getCameraFov()); - viewFrustum.setAspectRatio(agentData->getCameraAspectRatio()); - viewFrustum.setNearClip(agentData->getCameraNearClip()); - viewFrustum.setFarClip(agentData->getCameraFarClip()); - - viewFrustum.calculate(); + agentData->updateViewFrustum(); if (agentData->getWantResIn()) { - resInVoxelDistributor(agentList, agent, agentData, viewFrustum); + resInVoxelDistributor(agentList, agent, agentData, agentData->currentViewFrustum); } else { - deepestLevelVoxelDistributor(agentList, agent, agentData, viewFrustum); + deepestLevelVoxelDistributor(agentList, agent, agentData, agentData->currentViewFrustum); } } } From f63407aea5f2641c138475de4316930053344819 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 14 May 2013 08:57:49 -0700 Subject: [PATCH 02/13] added printDebugDetails() --- libraries/voxels/src/ViewFrustum.cpp | 14 ++++++++++++++ libraries/voxels/src/ViewFrustum.h | 2 ++ 2 files changed, 16 insertions(+) diff --git a/libraries/voxels/src/ViewFrustum.cpp b/libraries/voxels/src/ViewFrustum.cpp index a107e2f869..25022ae521 100644 --- a/libraries/voxels/src/ViewFrustum.cpp +++ b/libraries/voxels/src/ViewFrustum.cpp @@ -276,3 +276,17 @@ void ViewFrustum::computePickRay(float x, float y, glm::vec3& origin, glm::vec3& origin = _nearTopLeft + x*(_nearTopRight - _nearTopLeft) + y*(_nearBottomLeft - _nearTopLeft); direction = glm::normalize(origin - _position); } + + +void ViewFrustum::printDebugDetails() const { + printLog("ViewFrustum::printDebugDetails()... \n"); + printLog("_position=%f,%f,%f\n", _position.x, _position.y, _position.z ); + printLog("_direction=%f,%f,%f\n", _direction.x, _direction.y, _direction.z ); + printLog("_up=%f,%f,%f\n", _up.x, _up.y, _up.z ); + printLog("_right=%f,%f,%f\n", _right.x, _right.y, _right.z ); + printLog("_fieldOfView=%f\n", _fieldOfView); + printLog("_aspectRatio=%f\n", _aspectRatio); + printLog("_nearClip=%f\n", _nearClip); + printLog("_farClip=%f\n", _farClip); +} + diff --git a/libraries/voxels/src/ViewFrustum.h b/libraries/voxels/src/ViewFrustum.h index 007654fcf4..aadb1f86e8 100644 --- a/libraries/voxels/src/ViewFrustum.h +++ b/libraries/voxels/src/ViewFrustum.h @@ -102,6 +102,8 @@ public: bool matches(const ViewFrustum& compareTo) const; bool matches(const ViewFrustum* compareTo) const { return matches(*compareTo); }; void computePickRay(float x, float y, glm::vec3& origin, glm::vec3& direction) const; + + void printDebugDetails() const; }; From fa37b88fa84c704d84fa1e43ac3462b118baa642 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 14 May 2013 09:02:01 -0700 Subject: [PATCH 03/13] first cut at delta view frustum encoding --- libraries/voxels/src/VoxelTree.cpp | 31 ++++++++++++++++++++---------- libraries/voxels/src/VoxelTree.h | 12 ++++++++---- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 5df39140ec..0476ca0d40 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -617,12 +617,14 @@ void VoxelTree::createSphere(float radius, float xc, float yc, float zc, float v this->reaverageVoxelColors(this->rootNode); } -int VoxelTree::searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag) { +int VoxelTree::searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag, + bool deltaViewFrustum, const ViewFrustum* lastViewFrustum) { // call the recursive version, this will add all found colored node roots to the bag int currentSearchLevel = 0; - int levelReached = searchForColoredNodesRecursion(maxSearchLevel, currentSearchLevel, rootNode, viewFrustum, bag); + int levelReached = searchForColoredNodesRecursion(maxSearchLevel, currentSearchLevel, rootNode, + viewFrustum, bag, deltaViewFrustum, lastViewFrustum); return levelReached; } @@ -667,7 +669,8 @@ bool VoxelTree::findRayIntersection(const glm::vec3& origin, const glm::vec3& di } int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSearchLevel, - VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag) { + VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag, + bool deltaViewFrustum, const ViewFrustum* lastViewFrustum) { // Keep track of how deep we've searched. currentSearchLevel++; @@ -702,7 +705,7 @@ int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSe bool childIsColored = (childNode && childNode->isColored()); bool childIsInView = (childNode && childNode->isInView(viewFrustum)); bool childIsLeaf = (childNode && childNode->isLeaf()); - + if (childIsInView) { // track children in view as existing and not a leaf @@ -739,7 +742,8 @@ int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSe for (int i = 0; i < inViewCount; i++) { VoxelNode* childNode = inViewChildren[i]; thisLevel = currentSearchLevel; // reset this, since the children will munge it up - int childLevelReached = searchForColoredNodesRecursion(maxSearchLevel, thisLevel, childNode, viewFrustum, bag); + int childLevelReached = searchForColoredNodesRecursion(maxSearchLevel, thisLevel, childNode, viewFrustum, bag, + deltaViewFrustum, lastViewFrustum); maxChildLevel = std::max(maxChildLevel, childLevelReached); } } @@ -747,7 +751,8 @@ int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSe } int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, - VoxelNodeBag& bag, const ViewFrustum* viewFrustum, bool includeColor) const { + VoxelNodeBag& bag, const ViewFrustum* viewFrustum, bool includeColor, + bool deltaViewFrustum, const ViewFrustum* lastViewFrustum) const { // How many bytes have we written so far at this level; int bytesWritten = 0; @@ -767,7 +772,8 @@ int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned int currentEncodeLevel = 0; int childBytesWritten = encodeTreeBitstreamRecursion(maxEncodeLevel, currentEncodeLevel, - node, outputBuffer, availableBytes, bag, viewFrustum, includeColor); + node, outputBuffer, availableBytes, bag, viewFrustum, includeColor, + deltaViewFrustum, lastViewFrustum); // if childBytesWritten == 1 then something went wrong... that's not possible assert(childBytesWritten != 1); @@ -790,7 +796,8 @@ int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, - VoxelNodeBag& bag, const ViewFrustum* viewFrustum, bool includeColor) const { + VoxelNodeBag& bag, const ViewFrustum* viewFrustum, bool includeColor, + bool deltaViewFrustum, const ViewFrustum* lastViewFrustum) const { // How many bytes have we written so far at this level; int bytesAtThisLevel = 0; @@ -846,7 +853,10 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { VoxelNode* childNode = node->getChildAtIndex(i); bool childIsInView = (childNode && (!viewFrustum || childNode->isInView(*viewFrustum))); - if (childIsInView) { + bool childWasInView = (childNode && deltaViewFrustum && + (lastViewFrustum && ViewFrustum::INSIDE == childNode->inFrustum(*lastViewFrustum))); + + if (childIsInView && !childWasInView) { // Before we determine consider this further, let's see if it's in our LOD scope... float distance = viewFrustum ? childNode->distanceToCamera(*viewFrustum) : 0; float boundaryDistance = viewFrustum ? boundaryDistanceForRenderLevel(*childNode->getOctalCode() + 1) : 1; @@ -925,7 +935,8 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco int thisLevel = currentEncodeLevel; int childTreeBytesOut = encodeTreeBitstreamRecursion(maxEncodeLevel, thisLevel, childNode, outputBuffer, availableBytes, bag, - viewFrustum, includeColor); + viewFrustum, includeColor, + deltaViewFrustum, lastViewFrustum); // if the child wrote 0 bytes, it means that nothing below exists or was in view, or we ran out of space, // basically, the children below don't contain any info. diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 649bbfc92d..3c33c7b02c 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -55,9 +55,11 @@ public: void recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData=NULL); int encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, - VoxelNodeBag& bag, const ViewFrustum* viewFrustum, bool includeColor = true) const; + VoxelNodeBag& bag, const ViewFrustum* viewFrustum, bool includeColor = true, + bool deltaViewFrustum = false, const ViewFrustum* lastViewFrustum = NULL) const; - int searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag); + int searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag, + bool deltaViewFrustum = false, const ViewFrustum* lastViewFrustum = NULL); bool isDirty() const { return _isDirty; }; void clearDirtyBit() { _isDirty = false; }; @@ -79,10 +81,12 @@ public: private: int encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, - VoxelNodeBag& bag, const ViewFrustum* viewFrustum, bool includeColor) const; + VoxelNodeBag& bag, const ViewFrustum* viewFrustum, bool includeColor, + bool deltaViewFrustum, const ViewFrustum* lastViewFrustum) const; int searchForColoredNodesRecursion(int maxSearchLevel, int& currentSearchLevel, - VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag); + VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag, + bool deltaViewFrustum, const ViewFrustum* lastViewFrustum); static bool countVoxelsOperation(VoxelNode* node, void* extraData); From 2ff8da2b46b00b1942b3d0c4099008f1dc99401c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 14 May 2013 09:03:38 -0700 Subject: [PATCH 04/13] move view frustum calculation into VoxelAgentData, added last known and current --- voxel-server/src/VoxelAgentData.cpp | 18 +++++++++--------- voxel-server/src/VoxelAgentData.h | 7 +++++-- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/voxel-server/src/VoxelAgentData.cpp b/voxel-server/src/VoxelAgentData.cpp index 07bf2a6593..df61a0d6f8 100644 --- a/voxel-server/src/VoxelAgentData.cpp +++ b/voxel-server/src/VoxelAgentData.cpp @@ -53,21 +53,21 @@ VoxelAgentData* VoxelAgentData::clone() const { void VoxelAgentData::updateViewFrustum() { // save our currentViewFrustum into our lastKnownViewFrustum - lastKnownViewFrustum = currentViewFrustum; + _lastKnownViewFrustum = _currentViewFrustum; // get position and orientation details from the camera - currentViewFrustum.setPosition(getCameraPosition()); - currentViewFrustum.setOrientation(getCameraDirection(), getCameraUp(), getCameraRight()); + _currentViewFrustum.setPosition(getCameraPosition()); + _currentViewFrustum.setOrientation(getCameraDirection(), getCameraUp(), getCameraRight()); // Also make sure it's got the correct lens details from the camera - currentViewFrustum.setFieldOfView(getCameraFov()); - currentViewFrustum.setAspectRatio(getCameraAspectRatio()); - currentViewFrustum.setNearClip(getCameraNearClip()); - currentViewFrustum.setFarClip(getCameraFarClip()); + _currentViewFrustum.setFieldOfView(getCameraFov()); + _currentViewFrustum.setAspectRatio(getCameraAspectRatio()); + _currentViewFrustum.setNearClip(getCameraNearClip()); + _currentViewFrustum.setFarClip(getCameraFarClip()); // if there has been a change, then recalculate - if (!lastKnownViewFrustum.matches(currentViewFrustum)) { - currentViewFrustum.calculate(); + if (!_lastKnownViewFrustum.matches(_currentViewFrustum)) { + _currentViewFrustum.calculate(); } } diff --git a/voxel-server/src/VoxelAgentData.h b/voxel-server/src/VoxelAgentData.h index ee8b2dd660..cb88c05574 100644 --- a/voxel-server/src/VoxelAgentData.h +++ b/voxel-server/src/VoxelAgentData.h @@ -41,8 +41,8 @@ public: VoxelNodeBag nodeBag; - ViewFrustum currentViewFrustum; - ViewFrustum lastKnownViewFrustum; + ViewFrustum& getCurrentViewFrustum() { return _currentViewFrustum; }; + ViewFrustum& getLastKnownViewFrustum() { return _lastKnownViewFrustum; }; void updateViewFrustum(); @@ -53,6 +53,9 @@ private: bool _voxelPacketWaiting; int _maxSearchLevel; int _maxLevelReachedInLastSearch; + ViewFrustum _currentViewFrustum; + ViewFrustum _lastKnownViewFrustum; + }; #endif /* defined(__hifi__VoxelAgentData__) */ From 294367a417258c8ea8286a3a27e0f29c8f51439c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 14 May 2013 09:04:35 -0700 Subject: [PATCH 05/13] first cut at delata view frustum encoding --- voxel-server/src/main.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 76941d9bc2..e1293b1cdf 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -107,8 +107,8 @@ void eraseVoxelTreeAndCleanupAgentVisitData() { // Version of voxel distributor that sends each LOD level at a time void resInVoxelDistributor(AgentList* agentList, AgentList::iterator& agent, - VoxelAgentData* agentData, - ViewFrustum& viewFrustum) { + VoxelAgentData* agentData) { + ViewFrustum viewFrustum = agentData->getCurrentViewFrustum(); bool searchReset = false; int searchLoops = 0; int searchLevelWas = agentData->getMaxSearchLevel(); @@ -224,12 +224,13 @@ void resInVoxelDistributor(AgentList* agentList, // Version of voxel distributor that sends the deepest LOD level at once void deepestLevelVoxelDistributor(AgentList* agentList, AgentList::iterator& agent, - VoxelAgentData* agentData, - ViewFrustum& viewFrustum) { + VoxelAgentData* agentData) { + int maxLevelReached = 0; double start = usecTimestampNow(); if (agentData->nodeBag.isEmpty()) { - maxLevelReached = randomTree.searchForColoredNodes(INT_MAX, randomTree.rootNode, viewFrustum, agentData->nodeBag); + maxLevelReached = randomTree.searchForColoredNodes(INT_MAX, randomTree.rootNode, agentData->getCurrentViewFrustum(), + agentData->nodeBag, true, &agentData->getLastKnownViewFrustum()); } double end = usecTimestampNow(); double elapsedmsec = (end - start)/1000.0; @@ -261,8 +262,9 @@ void deepestLevelVoxelDistributor(AgentList* agentList, VoxelNode* subTree = agentData->nodeBag.extract(); bytesWritten = randomTree.encodeTreeBitstream(INT_MAX, subTree, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, - agentData->nodeBag, &viewFrustum, - agentData->getWantColor()); + agentData->nodeBag, &agentData->getCurrentViewFrustum(), + agentData->getWantColor(), true, + &agentData->getLastKnownViewFrustum()); if (agentData->getAvailable() >= bytesWritten) { agentData->writeToPacket(&tempOutputBuffer[0], bytesWritten); @@ -338,9 +340,9 @@ void *distributeVoxelsToListeners(void *args) { agentData->updateViewFrustum(); if (agentData->getWantResIn()) { - resInVoxelDistributor(agentList, agent, agentData, agentData->currentViewFrustum); + resInVoxelDistributor(agentList, agent, agentData); } else { - deepestLevelVoxelDistributor(agentList, agent, agentData, agentData->currentViewFrustum); + deepestLevelVoxelDistributor(agentList, agent, agentData); } } } From a95549da2ec84274e5253bd38ab6a20d2cfd2aa4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 14 May 2013 11:08:12 -0700 Subject: [PATCH 06/13] added new menu items for view delta --- interface/src/main.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 3b665f1455..725e6a9f95 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -165,6 +165,7 @@ unsigned char dominantColor = 0; // The dominant color of the voxel we're bool perfStatsOn = false; // Do we want to display perfStats? bool wantMonochrome = false; // ask server to send us in monochrome bool wantResIn = false; // ask server to res in +bool wantDelta = false; // ask server to send delta only bool logOn = true; // Whether to show on-screen log @@ -1296,6 +1297,15 @@ int setWantMonochrome(int state) { return value; } +int setWantDelta(int state) { + int value = setValue(state, &::wantDelta); + if (state == MENU_ROW_PICKED) { + ::myAvatar.setWantDelta(::wantDelta); + } + return value; +} + + int setDisplayFrustum(int state) { return setValue(state, &::frustumOn); } @@ -1463,6 +1473,7 @@ void initMenu() { menuColumnDebug->addRow("Calculate Tree Stats", doTreeStats); menuColumnDebug->addRow("Wants Res-In", setWantResIn); menuColumnDebug->addRow("Wants Monochrome", setWantMonochrome); + menuColumnDebug->addRow("Wants View-Delta Only", setWantDelta); } void testPointToVoxel() { From d59a8143d7ecd6bd9b79a024c30dc0e6bf42d46b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 14 May 2013 11:08:59 -0700 Subject: [PATCH 07/13] added wantDelta, made want bools a bit mask --- libraries/avatars/src/AvatarData.cpp | 16 ++++++++++++---- libraries/avatars/src/AvatarData.h | 8 ++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 60d28ce6fb..4ca7a7bd7f 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -108,8 +108,12 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { destinationBuffer += _chatMessage.size() * sizeof(char); // voxel sending features... - *destinationBuffer++ = _wantResIn; - *destinationBuffer++ = _wantColor; + // voxel sending features... + unsigned char wantItems = 0; + if (_wantResIn) { setAtBit(wantItems,WANT_RESIN_AT_BIT); } + if (_wantColor) { setAtBit(wantItems,WANT_COLOR_AT_BIT); } + if (_wantDelta) { setAtBit(wantItems,WANT_DELTA_AT_BIT); } + *destinationBuffer++ = wantItems; return destinationBuffer - bufferStart; } @@ -184,8 +188,12 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { sourceBuffer += chatMessageSize * sizeof(char); // voxel sending features... - _wantResIn = (bool)*sourceBuffer++; - _wantColor = (bool)*sourceBuffer++; + unsigned char wantItems = 0; + wantItems = (unsigned char)*sourceBuffer++; + + _wantResIn = oneAtBit(wantItems,WANT_RESIN_AT_BIT); + _wantColor = oneAtBit(wantItems,WANT_COLOR_AT_BIT); + _wantDelta = oneAtBit(wantItems,WANT_DELTA_AT_BIT); return sourceBuffer - startPosition; } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index dd1b6b970e..0b6c3157d1 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -15,6 +15,10 @@ #include +const int WANT_RESIN_AT_BIT = 0; +const int WANT_COLOR_AT_BIT = 1; +const int WANT_DELTA_AT_BIT = 2; + enum KeyState { NO_KEY_DOWN, @@ -123,8 +127,10 @@ public: // related to Voxel Sending strategies bool getWantResIn() const { return _wantResIn; } bool getWantColor() const { return _wantColor; } + bool getWantDelta() const { return _wantDelta; } void setWantResIn(bool wantResIn) { _wantResIn = wantResIn; } void setWantColor(bool wantColor) { _wantColor = wantColor; } + void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; } protected: glm::vec3 _position; @@ -167,8 +173,10 @@ protected: // chat message std::string _chatMessage; + // voxel server sending items bool _wantResIn; bool _wantColor; + bool _wantDelta; }; #endif /* defined(__hifi__AvatarData__) */ From 2c1518144ad7fb819acd0fe35bd48650d6f58705 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 14 May 2013 11:09:53 -0700 Subject: [PATCH 08/13] added setAtBit() utility --- libraries/shared/src/SharedUtil.cpp | 5 +++++ libraries/shared/src/SharedUtil.h | 1 + 2 files changed, 6 insertions(+) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 0c399faf6c..d6820897b8 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -94,6 +94,11 @@ bool oneAtBit(unsigned char byte, int bitIndex) { return (byte >> (7 - bitIndex) & 1); } +void setAtBit(unsigned char& byte, int bitIndex) { + byte += (1 << (7 - bitIndex)); +} + + void switchToResourcesParentIfRequired() { #ifdef __APPLE__ CFBundleRef mainBundle = CFBundleGetMainBundle(); diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 9d2fcb8799..98baa5488a 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -49,6 +49,7 @@ void outputBits(unsigned char byte, bool withNewLine = true); 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 switchToResourcesParentIfRequired(); From 062c1b4c640cab42c445411873e5032eee2a2b7c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 14 May 2013 11:10:40 -0700 Subject: [PATCH 09/13] tweaks to view frustum delta code --- voxel-server/src/VoxelAgentData.cpp | 29 ++++++++++++++++++----------- voxel-server/src/VoxelAgentData.h | 5 ++++- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/voxel-server/src/VoxelAgentData.cpp b/voxel-server/src/VoxelAgentData.cpp index df61a0d6f8..b265ccb2ba 100644 --- a/voxel-server/src/VoxelAgentData.cpp +++ b/voxel-server/src/VoxelAgentData.cpp @@ -51,23 +51,30 @@ VoxelAgentData* VoxelAgentData::clone() const { return new VoxelAgentData(*this); } -void VoxelAgentData::updateViewFrustum() { - // save our currentViewFrustum into our lastKnownViewFrustum - _lastKnownViewFrustum = _currentViewFrustum; - +bool VoxelAgentData::updateCurrentViewFrustum() { + bool currentViewFrustumChanged = false; + ViewFrustum newestViewFrustum; // get position and orientation details from the camera - _currentViewFrustum.setPosition(getCameraPosition()); - _currentViewFrustum.setOrientation(getCameraDirection(), getCameraUp(), getCameraRight()); + newestViewFrustum.setPosition(getCameraPosition()); + newestViewFrustum.setOrientation(getCameraDirection(), getCameraUp(), getCameraRight()); // Also make sure it's got the correct lens details from the camera - _currentViewFrustum.setFieldOfView(getCameraFov()); - _currentViewFrustum.setAspectRatio(getCameraAspectRatio()); - _currentViewFrustum.setNearClip(getCameraNearClip()); - _currentViewFrustum.setFarClip(getCameraFarClip()); + newestViewFrustum.setFieldOfView(getCameraFov()); + newestViewFrustum.setAspectRatio(getCameraAspectRatio()); + newestViewFrustum.setNearClip(getCameraNearClip()); + newestViewFrustum.setFarClip(getCameraFarClip()); // if there has been a change, then recalculate - if (!_lastKnownViewFrustum.matches(_currentViewFrustum)) { + if (!newestViewFrustum.matches(_currentViewFrustum)) { + _currentViewFrustum = newestViewFrustum; _currentViewFrustum.calculate(); + currentViewFrustumChanged = true; } + return currentViewFrustumChanged; +} + +void VoxelAgentData::updateLastKnownViewFrustum() { + // save our currentViewFrustum into our lastKnownViewFrustum + _lastKnownViewFrustum = _currentViewFrustum; } diff --git a/voxel-server/src/VoxelAgentData.h b/voxel-server/src/VoxelAgentData.h index cb88c05574..4bdbb6069d 100644 --- a/voxel-server/src/VoxelAgentData.h +++ b/voxel-server/src/VoxelAgentData.h @@ -44,7 +44,10 @@ public: ViewFrustum& getCurrentViewFrustum() { return _currentViewFrustum; }; ViewFrustum& getLastKnownViewFrustum() { return _lastKnownViewFrustum; }; - void updateViewFrustum(); + // These are not classic setters because they are calculating and maintaining state + // which is set asynchronously through the network receive + bool updateCurrentViewFrustum(); + void updateLastKnownViewFrustum(); private: unsigned char* _voxelPacket; From 1e0a575d908e84506b159dbb552b74a23f59c354 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 14 May 2013 11:11:34 -0700 Subject: [PATCH 10/13] tweaks to view frustum delta code --- voxel-server/src/main.cpp | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index e1293b1cdf..88ad060cf9 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -224,13 +224,22 @@ void resInVoxelDistributor(AgentList* agentList, // Version of voxel distributor that sends the deepest LOD level at once void deepestLevelVoxelDistributor(AgentList* agentList, AgentList::iterator& agent, - VoxelAgentData* agentData) { + VoxelAgentData* agentData, + bool viewFrustumChanged) { int maxLevelReached = 0; double start = usecTimestampNow(); - if (agentData->nodeBag.isEmpty()) { + + // FOR NOW... agent tells us if it wants to receive only view frustum deltas + bool wantDelta = agentData->getWantDelta(); + const ViewFrustum* lastViewFrustum = wantDelta ? &agentData->getLastKnownViewFrustum() : NULL; + + // If the current view frustum has changed OR we have nothing to send, then search against + // the current view frustum for things to send. + if (viewFrustumChanged || agentData->nodeBag.isEmpty()) { + // If the bag was empty, then send everything in view, not just the delta maxLevelReached = randomTree.searchForColoredNodes(INT_MAX, randomTree.rootNode, agentData->getCurrentViewFrustum(), - agentData->nodeBag, true, &agentData->getLastKnownViewFrustum()); + agentData->nodeBag, wantDelta, lastViewFrustum); } double end = usecTimestampNow(); double elapsedmsec = (end - start)/1000.0; @@ -263,8 +272,7 @@ void deepestLevelVoxelDistributor(AgentList* agentList, bytesWritten = randomTree.encodeTreeBitstream(INT_MAX, subTree, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, agentData->nodeBag, &agentData->getCurrentViewFrustum(), - agentData->getWantColor(), true, - &agentData->getLastKnownViewFrustum()); + agentData->getWantColor(), wantDelta, lastViewFrustum); if (agentData->getAvailable() >= bytesWritten) { agentData->writeToPacket(&tempOutputBuffer[0], bytesWritten); @@ -310,7 +318,15 @@ void deepestLevelVoxelDistributor(AgentList* agentList, printf("packetLoop() took %lf milliseconds to generate %d bytes in %d packets, %d nodes still to send\n", elapsedmsec, trueBytesSent, truePacketsSent, agentData->nodeBag.count()); } - } + + // if after sending packets we've emptied our bag, then we want to remember that we've sent all + // the voxels from the current view frustum + if (agentData->nodeBag.isEmpty()) { + agentData->updateLastKnownViewFrustum(); + } + + + } // end if bag wasn't empty, and so we sent stuff... } void persistVoxelsWhenDirty() { @@ -337,12 +353,12 @@ void *distributeVoxelsToListeners(void *args) { // Sometimes the agent data has not yet been linked, in which case we can't really do anything if (agentData) { - agentData->updateViewFrustum(); + bool viewFrustumChanged = agentData->updateCurrentViewFrustum(); if (agentData->getWantResIn()) { resInVoxelDistributor(agentList, agent, agentData); } else { - deepestLevelVoxelDistributor(agentList, agent, agentData); + deepestLevelVoxelDistributor(agentList, agent, agentData, viewFrustumChanged); } } } From 4e92f5d3d81a94dcc5ed441ec51aa6fc11f7f817 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 14 May 2013 12:11:32 -0700 Subject: [PATCH 11/13] tweaks to delta sending --- libraries/avatars/src/AvatarData.cpp | 2 ++ libraries/voxels/src/VoxelTree.cpp | 11 ++++++----- voxel-server/src/VoxelAgentData.cpp | 1 + voxel-server/src/VoxelAgentData.h | 4 ++++ voxel-server/src/main.cpp | 11 +++++++++++ 5 files changed, 24 insertions(+), 5 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 4ca7a7bd7f..1f4856abf7 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -121,6 +121,8 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { // called on the other agents - assigns it to my views of the others int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { +//printf("AvatarData::parseData()\n"); + // increment to push past the packet header sourceBuffer += sizeof(PACKET_HEADER_HEAD_DATA); diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 0476ca0d40..d22073a54b 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -853,10 +853,8 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { VoxelNode* childNode = node->getChildAtIndex(i); bool childIsInView = (childNode && (!viewFrustum || childNode->isInView(*viewFrustum))); - bool childWasInView = (childNode && deltaViewFrustum && - (lastViewFrustum && ViewFrustum::INSIDE == childNode->inFrustum(*lastViewFrustum))); - if (childIsInView && !childWasInView) { + if (childIsInView) { // Before we determine consider this further, let's see if it's in our LOD scope... float distance = viewFrustum ? childNode->distanceToCamera(*viewFrustum) : 0; float boundaryDistance = viewFrustum ? boundaryDistanceForRenderLevel(*childNode->getOctalCode() + 1) : 1; @@ -871,9 +869,12 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco childrenExistBits += (1 << (7 - i)); inViewNotLeafCount++; } + + bool childWasInView = (childNode && deltaViewFrustum && + (lastViewFrustum && ViewFrustum::INSIDE == childNode->inFrustum(*lastViewFrustum))); - // track children with actual color - if (childNode && childNode->isColored()) { + // track children with actual color, only if the child wasn't previously in view! + if (childNode && childNode->isColored() && !childWasInView) { childrenColoredBits += (1 << (7 - i)); inViewWithColorCount++; } diff --git a/voxel-server/src/VoxelAgentData.cpp b/voxel-server/src/VoxelAgentData.cpp index b265ccb2ba..4eb971f275 100644 --- a/voxel-server/src/VoxelAgentData.cpp +++ b/voxel-server/src/VoxelAgentData.cpp @@ -22,6 +22,7 @@ void VoxelAgentData::init() { _maxSearchLevel = 1; _maxLevelReachedInLastSearch = 1; resetVoxelPacket(); + _viewSent = false; } void VoxelAgentData::resetVoxelPacket() { diff --git a/voxel-server/src/VoxelAgentData.h b/voxel-server/src/VoxelAgentData.h index 4bdbb6069d..99be7e6042 100644 --- a/voxel-server/src/VoxelAgentData.h +++ b/voxel-server/src/VoxelAgentData.h @@ -49,7 +49,11 @@ public: bool updateCurrentViewFrustum(); void updateLastKnownViewFrustum(); + bool getViewSent() const { return _viewSent; }; + void setViewSent(bool viewSent) { _viewSent = viewSent; } + private: + bool _viewSent; unsigned char* _voxelPacket; unsigned char* _voxelPacketAt; int _voxelPacketAvailableBytes; diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 88ad060cf9..d15a5325f6 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -234,12 +234,21 @@ void deepestLevelVoxelDistributor(AgentList* agentList, bool wantDelta = agentData->getWantDelta(); const ViewFrustum* lastViewFrustum = wantDelta ? &agentData->getLastKnownViewFrustum() : NULL; +printf("deepestLevelVoxelDistributor() viewFrustumChanged=%s, nodeBag.isEmpty=%s, viewSent=%s\n", + viewFrustumChanged ? "yes" : "no", + agentData->nodeBag.isEmpty() ? "yes" : "no", + agentData->getViewSent() ? "yes" : "no" + ); + // If the current view frustum has changed OR we have nothing to send, then search against // the current view frustum for things to send. if (viewFrustumChanged || agentData->nodeBag.isEmpty()) { // If the bag was empty, then send everything in view, not just the delta maxLevelReached = randomTree.searchForColoredNodes(INT_MAX, randomTree.rootNode, agentData->getCurrentViewFrustum(), agentData->nodeBag, wantDelta, lastViewFrustum); + + agentData->setViewSent(false); + } double end = usecTimestampNow(); double elapsedmsec = (end - start)/1000.0; @@ -323,6 +332,7 @@ void deepestLevelVoxelDistributor(AgentList* agentList, // the voxels from the current view frustum if (agentData->nodeBag.isEmpty()) { agentData->updateLastKnownViewFrustum(); + agentData->setViewSent(true); } @@ -354,6 +364,7 @@ void *distributeVoxelsToListeners(void *args) { // Sometimes the agent data has not yet been linked, in which case we can't really do anything if (agentData) { bool viewFrustumChanged = agentData->updateCurrentViewFrustum(); + printf("agentData->updateCurrentViewFrustum() viewFrustumChanged=%s\n", (viewFrustumChanged ? "yes" : "no")); if (agentData->getWantResIn()) { resInVoxelDistributor(agentList, agent, agentData); From 43e190fe3ceb0024827cac555d5dc9263327eb36 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 14 May 2013 12:19:23 -0700 Subject: [PATCH 12/13] switched Want Delta menu to use new Qt menus --- interface/src/Application.cpp | 6 ++++++ interface/src/Application.h | 1 + 2 files changed, 7 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7844f08686..eaebaee9ff 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1035,6 +1035,10 @@ void Application::setWantsMonochrome(bool wantsMonochrome) { void Application::setWantsResIn(bool wantsResIn) { _myAvatar.setWantResIn(wantsResIn); } + +void Application::setWantsDelta(bool wantsDelta) { + _myAvatar.setWantDelta(wantsDelta); +} void Application::initMenu() { QMenuBar* menuBar = new QMenuBar(); @@ -1096,10 +1100,12 @@ void Application::initMenu() { debugMenu->addAction("Calculate Tree Stats", this, SLOT(doTreeStats()), Qt::SHIFT | Qt::Key_S); debugMenu->addAction("Wants Res-In", this, SLOT(setWantsResIn(bool)))->setCheckable(true); debugMenu->addAction("Wants Monochrome", this, SLOT(setWantsMonochrome(bool)))->setCheckable(true); + debugMenu->addAction("Wants View Delta Sending", this, SLOT(setWantsDelta(bool)))->setCheckable(true); } void Application::updateFrustumRenderModeAction() { switch (_frustumDrawingMode) { + default: case FRUSTUM_DRAW_MODE_ALL: _frustumRenderModeAction->setText("Render Mode - All"); break; diff --git a/interface/src/Application.h b/interface/src/Application.h index 035f705b41..1b1eb69fb3 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -87,6 +87,7 @@ private slots: void doTreeStats(); void setWantsMonochrome(bool wantsMonochrome); void setWantsResIn(bool wantsResIn); + void setWantsDelta(bool wantsDelta); private: From b3f6d40935fd88e7d524d4d361871c0a81db7ea6 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 14 May 2013 12:22:26 -0700 Subject: [PATCH 13/13] hide debug messages unless requested --- voxel-server/src/main.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index d15a5325f6..74a2ca73ca 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -233,12 +233,14 @@ void deepestLevelVoxelDistributor(AgentList* agentList, // FOR NOW... agent tells us if it wants to receive only view frustum deltas bool wantDelta = agentData->getWantDelta(); const ViewFrustum* lastViewFrustum = wantDelta ? &agentData->getLastKnownViewFrustum() : NULL; - -printf("deepestLevelVoxelDistributor() viewFrustumChanged=%s, nodeBag.isEmpty=%s, viewSent=%s\n", - viewFrustumChanged ? "yes" : "no", - agentData->nodeBag.isEmpty() ? "yes" : "no", - agentData->getViewSent() ? "yes" : "no" - ); + + if (::debugVoxelSending) { + printf("deepestLevelVoxelDistributor() viewFrustumChanged=%s, nodeBag.isEmpty=%s, viewSent=%s\n", + viewFrustumChanged ? "yes" : "no", + agentData->nodeBag.isEmpty() ? "yes" : "no", + agentData->getViewSent() ? "yes" : "no" + ); + } // If the current view frustum has changed OR we have nothing to send, then search against // the current view frustum for things to send. @@ -364,7 +366,9 @@ void *distributeVoxelsToListeners(void *args) { // Sometimes the agent data has not yet been linked, in which case we can't really do anything if (agentData) { bool viewFrustumChanged = agentData->updateCurrentViewFrustum(); - printf("agentData->updateCurrentViewFrustum() viewFrustumChanged=%s\n", (viewFrustumChanged ? "yes" : "no")); + if (::debugVoxelSending) { + printf("agentData->updateCurrentViewFrustum() changed=%s\n", (viewFrustumChanged ? "yes" : "no")); + } if (agentData->getWantResIn()) { resInVoxelDistributor(agentList, agent, agentData);