From 2f3ba6bc13cfae2bf41a3b4ce97cfcf8672398a0 Mon Sep 17 00:00:00 2001 From: Lord Waymaster Date: Tue, 29 Oct 2013 15:22:41 -0700 Subject: [PATCH 01/21] Starfield fix and Milky Way Fixed bug where more stars were generated at the poles. Added 'Milky Way' band in sky, customisable with MILKY_WAY_WIDTH, MILKY_WAY_INCLINATION and MILKY_WAY_RATIO consts in Generator.cpp. --- interface/src/starfield/Generator.cpp | 43 +++++++++++++++++----- interface/src/starfield/data/GpuVertex.cpp | 1 - 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/interface/src/starfield/Generator.cpp b/interface/src/starfield/Generator.cpp index 1e161a19cf..63a11f8f11 100644 --- a/interface/src/starfield/Generator.cpp +++ b/interface/src/starfield/Generator.cpp @@ -15,26 +15,51 @@ const float Generator::STAR_COLORIZATION = 0.1; void Generator::computeStarPositions(InputVertices& destination, unsigned limit, unsigned seed) { InputVertices* vertices = & destination; //_limit = limit; - + timeval startTime; gettimeofday(&startTime, NULL); - + srand(seed); - + vertices->clear(); vertices->reserve(limit); + const unsigned MILKY_WAY_WIDTH = 16.0; // width in degrees of one half of the Milky Way + const float MILKY_WAY_INCLINATION = 30.0f; // angle of Milky Way from horizontal in degrees + const float MILKY_WAY_RATIO = 0.6; const unsigned NUM_DEGREES = 360; - - for(int star = 0; star < limit; ++star) { + for(int star = 0; star < floor(limit * (1 - MILKY_WAY_RATIO)); ++star) { float azimuth, altitude; - azimuth = ((float)rand() / (float) RAND_MAX) * NUM_DEGREES; - altitude = (((float)rand() / (float) RAND_MAX) * NUM_DEGREES / 2) - NUM_DEGREES / 4; - + azimuth = (((float)rand() / (float) RAND_MAX) * NUM_DEGREES) - (NUM_DEGREES / 2); + altitude = (acos((2.0f * ((float)rand() / (float)RAND_MAX)) - 1.0f) / PI_OVER_180) + 90; + vertices->push_back(InputVertex(azimuth, altitude, computeStarColor(STAR_COLORIZATION))); } - + + for(int star = 0; star < ceil(limit * MILKY_WAY_RATIO); ++star) { + float azimuth = ((float)rand() / (float) RAND_MAX) * NUM_DEGREES; + float altitude = asin((float)rand() / (float) RAND_MAX * 2 - 1) * MILKY_WAY_WIDTH; + + // we need to rotate the Milky Way band to the correct orientation in the sky + // convert from spherical coordinates to cartesian, rotate the point and then convert back. + // An improvement would be to convert all stars to cartesian at this point and not have to convert back. + + float tempX = sin(azimuth * PI_OVER_180) * cos(altitude * PI_OVER_180); + float tempY = sin(altitude * PI_OVER_180); + float tempZ = -cos(azimuth * PI_OVER_180) * cos(altitude * PI_OVER_180); + + float xangle = MILKY_WAY_INCLINATION * PI_OVER_180; + float newX = (tempX * cos(xangle)) - (tempY * sin(xangle)); + float newY = (tempX * sin(xangle)) + (tempY * cos(xangle)); + float newZ = tempZ; + + azimuth = (atan2(newX,-newZ) + Radians::pi()) / PI_OVER_180; + altitude = atan2(-newY, hypotf(newX, newZ)) / PI_OVER_180; + + vertices->push_back(InputVertex(azimuth, altitude, computeStarColor(STAR_COLORIZATION))); + } + qDebug("Took %llu msec to generate stars.\n", (usecTimestampNow() - usecTimestamp(&startTime)) / 1000); } diff --git a/interface/src/starfield/data/GpuVertex.cpp b/interface/src/starfield/data/GpuVertex.cpp index fdec1b85d2..58db1d499a 100755 --- a/interface/src/starfield/data/GpuVertex.cpp +++ b/interface/src/starfield/data/GpuVertex.cpp @@ -7,7 +7,6 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // #include "starfield/data/GpuVertex.h" -#include "starfield/data/InputVertex.h" using namespace starfield; From fbc3a4d2c13df29502f3c544c480f356d63ba0f3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 29 Oct 2013 16:16:58 -0700 Subject: [PATCH 02/21] first cut at user adjustable LOD --- interface/src/Application.cpp | 8 +- interface/src/Application.h | 1 + interface/src/Menu.cpp | 26 ++++- interface/src/Menu.h | 8 ++ interface/src/VoxelSystem.cpp | 14 ++- libraries/shared/src/PacketHeaders.cpp | 5 +- .../src/VoxelSendThread.cpp | 4 +- libraries/voxels/src/VoxelConstants.h | 2 +- libraries/voxels/src/VoxelNode.cpp | 6 +- libraries/voxels/src/VoxelNode.h | 3 +- libraries/voxels/src/VoxelQuery.cpp | 13 ++- libraries/voxels/src/VoxelQuery.h | 3 + libraries/voxels/src/VoxelTree.cpp | 18 ++-- libraries/voxels/src/VoxelTree.h | 94 ++++++++++--------- 14 files changed, 133 insertions(+), 72 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c05ebaa56e..0f4e1c74ba 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -611,7 +611,13 @@ void Application::keyPressEvent(QKeyEvent* event) { _audioScope.inputPaused = !_audioScope.inputPaused; break; case Qt::Key_L: - _displayLevels = !_displayLevels; + if (!isShifted && !isMeta) { + _displayLevels = !_displayLevels; + } else if (isShifted) { + Menu::getInstance()->triggerOption(MenuOption::LodTools); + } else if (isMeta) { + Menu::getInstance()->triggerOption(MenuOption::Log); + } break; case Qt::Key_E: diff --git a/interface/src/Application.h b/interface/src/Application.h index 531ff1813b..6cc973edac 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -60,6 +60,7 @@ #include "ui/ChatEntry.h" #include "ui/VoxelStatsDialog.h" #include "ui/RearMirrorTools.h" +#include "ui/LodToolsDialog.h" class QAction; class QActionGroup; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index a31ff61ae8..5435738ecd 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -53,6 +53,7 @@ Menu::Menu() : _viewFrustumOffset(DEFAULT_FRUSTUM_OFFSET), _voxelModeActionsGroup(NULL), _voxelStatsDialog(NULL), + _lodToolsDialog(NULL), _maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM) { Application *appInstance = Application::getInstance(); @@ -278,6 +279,7 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelTextures); addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::AmbientOcclusion); + addActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::LodTools, Qt::SHIFT | Qt::Key_L, this, SLOT(lodTools())); QMenu* cullingOptionsMenu = voxelOptionsMenu->addMenu("Culling Options"); addDisabledActionAndSeparator(cullingOptionsMenu, "Standard Settings"); @@ -1023,7 +1025,6 @@ void Menu::goToUser() { } void Menu::bandwidthDetails() { - if (! _bandwidthDialog) { _bandwidthDialog = new BandwidthDialog(Application::getInstance()->getGLWidget(), Application::getInstance()->getBandwidthMeter()); @@ -1058,6 +1059,29 @@ void Menu::voxelStatsDetailsClosed() { } } +float Menu::getVoxelSizeScale() { + if (_lodToolsDialog) { + return _lodToolsDialog->getVoxelSizeScale(); + } + return DEFAULT_FIELD_OF_VIEW_DEGREES; +} + +void Menu::lodTools() { + if (!_lodToolsDialog) { + _lodToolsDialog = new LodToolsDialog(Application::getInstance()->getGLWidget()); + connect(_lodToolsDialog, SIGNAL(closed()), SLOT(lodToolsClosed())); + _lodToolsDialog->show(); + } + _lodToolsDialog->raise(); +} + +void Menu::lodToolsClosed() { + if (_lodToolsDialog) { + delete _lodToolsDialog; + _lodToolsDialog = NULL; + } +} + void Menu::cycleFrustumRenderMode() { _frustumDrawMode = (FrustumDrawMode)((_frustumDrawMode + 1) % FRUSTUM_DRAW_MODE_COUNT); updateFrustumRenderModeAction(); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 0b5f6fcdce..82cf994bc8 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -35,6 +35,7 @@ class QSettings; class BandwidthDialog; class VoxelStatsDialog; +class LodToolsDialog; class Menu : public QMenuBar { Q_OBJECT @@ -53,15 +54,19 @@ public: FrustumDrawMode getFrustumDrawMode() const { return _frustumDrawMode; } ViewFrustumOffset getViewFrustumOffset() const { return _viewFrustumOffset; } VoxelStatsDialog* getVoxelStatsDialog() const { return _voxelStatsDialog; } + LodToolsDialog* getLodToolsDialog() const { return _lodToolsDialog; } int getMaxVoxels() const { return _maxVoxels; } QAction* getUseVoxelShader() const { return _useVoxelShader; } void handleViewFrustumOffsetKeyModifier(int key); + + float getVoxelSizeScale(); public slots: void bandwidthDetails(); void voxelStatsDetails(); + void lodTools(); void loadSettings(QSettings* settings = NULL); void saveSettings(QSettings* settings = NULL); void importSettings(); @@ -76,6 +81,7 @@ private slots: void goToLocation(); void bandwidthDetailsClosed(); void voxelStatsDetailsClosed(); + void lodToolsClosed(); void cycleFrustumRenderMode(); void updateVoxelModeActions(); void chooseVoxelPaintColor(); @@ -120,6 +126,7 @@ private: ViewFrustumOffset _viewFrustumOffset; QActionGroup* _voxelModeActionsGroup; VoxelStatsDialog* _voxelStatsDialog; + LodToolsDialog* _lodToolsDialog; int _maxVoxels; QAction* _useVoxelShader; }; @@ -179,6 +186,7 @@ namespace MenuOption { const QString Gravity = "Use Gravity"; const QString GroundPlane = "Ground Plane"; const QString ParticleCloud = "Particle Cloud"; + const QString LodTools = "LOD Tools"; const QString Log = "Log"; const QString Login = "Login"; const QString LookAtIndicator = "Look-at Indicator"; diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index b7afd67947..b84304e6c5 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -139,7 +139,8 @@ void VoxelSystem::voxelUpdated(VoxelNode* node) { if (node->getVoxelSystem() == this) { bool shouldRender = false; // assume we don't need to render it // if it's colored, we might need to render it! - shouldRender = node->calculateShouldRender(_viewFrustum); + float voxelSizeScale = DEFAULT_VOXEL_SIZE_SCALE; + shouldRender = node->calculateShouldRender(_viewFrustum, voxelSizeScale); if (node->getShouldRender() != shouldRender) { node->setShouldRender(shouldRender); @@ -155,7 +156,7 @@ void VoxelSystem::voxelUpdated(VoxelNode* node) { VoxelNode* childNode = node->getChildAtIndex(i); if (childNode) { bool wasShouldRender = childNode->getShouldRender(); - bool isShouldRender = childNode->calculateShouldRender(_viewFrustum); + bool isShouldRender = childNode->calculateShouldRender(_viewFrustum, voxelSizeScale); if (wasShouldRender && !isShouldRender) { childrenGotHiddenCount++; } @@ -923,7 +924,8 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) { int voxelsUpdated = 0; bool shouldRender = false; // assume we don't need to render it // if it's colored, we might need to render it! - shouldRender = node->calculateShouldRender(_viewFrustum); + float voxelSizeScale = DEFAULT_VOXEL_SIZE_SCALE; + shouldRender = node->calculateShouldRender(_viewFrustum, voxelSizeScale); node->setShouldRender(shouldRender); // let children figure out their renderness @@ -1771,7 +1773,8 @@ bool VoxelSystem::showAllLocalVoxelsOperation(VoxelNode* node, void* extraData) args->nodesScanned++; - bool shouldRender = true; // node->calculateShouldRender(&args->thisViewFrustum); + float voxelSizeScale = DEFAULT_VOXEL_SIZE_SCALE; + bool shouldRender = node->calculateShouldRender(&args->thisViewFrustum, voxelSizeScale); node->setShouldRender(shouldRender); if (shouldRender) { @@ -1947,7 +1950,8 @@ bool VoxelSystem::showAllSubTreeOperation(VoxelNode* node, void* extraData) { args->nodesInside++; - bool shouldRender = node->calculateShouldRender(&args->thisViewFrustum); + float voxelSizeScale = DEFAULT_VOXEL_SIZE_SCALE; + bool shouldRender = node->calculateShouldRender(&args->thisViewFrustum, voxelSizeScale); node->setShouldRender(shouldRender); if (shouldRender && !node->isKnownBufferIndex()) { diff --git a/libraries/shared/src/PacketHeaders.cpp b/libraries/shared/src/PacketHeaders.cpp index 70544f536b..dc953b6b80 100644 --- a/libraries/shared/src/PacketHeaders.cpp +++ b/libraries/shared/src/PacketHeaders.cpp @@ -35,7 +35,10 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) { case PACKET_TYPE_DOMAIN_LIST_REQUEST: case PACKET_TYPE_DOMAIN_REPORT_FOR_DUTY: return 1; - + + case PACKET_TYPE_VOXEL_QUERY: + return 1; + default: return 0; } diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 3a3904e218..38ed5742a9 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -253,12 +253,14 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no int boundaryLevelAdjust = viewFrustumChanged && nodeData->getWantLowResMoving() ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST; + float voxelSizeScale = nodeData->getVoxelSizeScale(); + bool isFullScene = (!viewFrustumChanged || !nodeData->getWantDelta()) && nodeData->getViewFrustumJustStoppedChanging(); EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor, WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum, - wantOcclusionCulling, coverageMap, boundaryLevelAdjust, + wantOcclusionCulling, coverageMap, boundaryLevelAdjust, voxelSizeScale, nodeData->getLastTimeBagEmpty(), isFullScene, &nodeData->stats, _myServer->getJurisdiction()); diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index e6773ceaa0..26c6032a89 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -27,7 +27,7 @@ const uint64_t CHANGE_FUDGE = 1000 * 200; // useconds of fudge in determining if const int TREE_SCALE = 16384; // ~10 miles.. This is the number of meters of the 0.0 to 1.0 voxel universe // This controls the LOD. Larger number will make smaller voxels visible at greater distance. -const float VOXEL_SIZE_SCALE = TREE_SCALE * 400.0f; +const float DEFAULT_VOXEL_SIZE_SCALE = TREE_SCALE * 400.0f; const int NUMBER_OF_CHILDREN = 8; const int MAX_VOXEL_PACKET_SIZE = 1492; diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 4ba90c87c0..d10b02b193 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -1371,12 +1371,12 @@ ViewFrustum::location VoxelNode::inFrustum(const ViewFrustum& viewFrustum) const // Since, if we know the camera position and orientation, we can know which of the corners is the "furthest" // corner. We can use we can use this corner as our "voxel position" to do our distance calculations off of. // By doing this, we don't need to test each child voxel's position vs the LOD boundary -bool VoxelNode::calculateShouldRender(const ViewFrustum* viewFrustum, int boundaryLevelAdjust) const { +bool VoxelNode::calculateShouldRender(const ViewFrustum* viewFrustum, float voxelScaleSize, int boundaryLevelAdjust) const { bool shouldRender = false; if (isColored()) { float furthestDistance = furthestDistanceToCamera(*viewFrustum); - float boundary = boundaryDistanceForRenderLevel(getLevel() + boundaryLevelAdjust); - float childBoundary = boundaryDistanceForRenderLevel(getLevel() + 1 + boundaryLevelAdjust); + float boundary = boundaryDistanceForRenderLevel(getLevel() + boundaryLevelAdjust, voxelScaleSize); + float childBoundary = boundaryDistanceForRenderLevel(getLevel() + 1 + boundaryLevelAdjust, voxelScaleSize); bool inBoundary = (furthestDistance <= boundary); bool inChildBoundary = (furthestDistance <= childBoundary); shouldRender = (isLeaf() && inChildBoundary) || (inBoundary && !inChildBoundary); diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 17760f0514..53af7ab602 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -69,7 +69,8 @@ public: float distanceToCamera(const ViewFrustum& viewFrustum) const; float furthestDistanceToCamera(const ViewFrustum& viewFrustum) const; - bool calculateShouldRender(const ViewFrustum* viewFrustum, int boundaryLevelAdjust = 0) const; + bool calculateShouldRender(const ViewFrustum* viewFrustum, + float voxelSizeScale = DEFAULT_VOXEL_SIZE_SCALE, int boundaryLevelAdjust = 0) const; // points are assumed to be in Voxel Coordinates (not TREE_SCALE'd) float distanceSquareToPoint(const glm::vec3& point) const; // when you don't need the actual distance, use this. diff --git a/libraries/voxels/src/VoxelQuery.cpp b/libraries/voxels/src/VoxelQuery.cpp index 507c086619..1b293eeeb5 100644 --- a/libraries/voxels/src/VoxelQuery.cpp +++ b/libraries/voxels/src/VoxelQuery.cpp @@ -35,7 +35,8 @@ VoxelQuery::VoxelQuery(Node* owningNode) : _wantDelta(true), _wantLowResMoving(true), _wantOcclusionCulling(true), - _maxVoxelPPS(DEFAULT_MAX_VOXEL_PPS) + _maxVoxelPPS(DEFAULT_MAX_VOXEL_PPS), + _voxelSizeScale(DEFAULT_VOXEL_SIZE_SCALE) { } @@ -78,6 +79,10 @@ int VoxelQuery::getBroadcastData(unsigned char* destinationBuffer) { // desired Max Voxel PPS memcpy(destinationBuffer, &_maxVoxelPPS, sizeof(_maxVoxelPPS)); destinationBuffer += sizeof(_maxVoxelPPS); + + // desired voxelSizeScale + memcpy(destinationBuffer, &_voxelSizeScale, sizeof(_voxelSizeScale)); + destinationBuffer += sizeof(_voxelSizeScale); return destinationBuffer - bufferStart; } @@ -120,7 +125,11 @@ int VoxelQuery::parseData(unsigned char* sourceBuffer, int numBytes) { // desired Max Voxel PPS memcpy(&_maxVoxelPPS, sourceBuffer, sizeof(_maxVoxelPPS)); sourceBuffer += sizeof(_maxVoxelPPS); - + + // desired voxelSizeScale + memcpy(&_voxelSizeScale, sourceBuffer, sizeof(_voxelSizeScale)); + sourceBuffer += sizeof(_voxelSizeScale); + return sourceBuffer - startPosition; } diff --git a/libraries/voxels/src/VoxelQuery.h b/libraries/voxels/src/VoxelQuery.h index 1573e54061..701b3e399d 100644 --- a/libraries/voxels/src/VoxelQuery.h +++ b/libraries/voxels/src/VoxelQuery.h @@ -69,6 +69,7 @@ public: bool getWantLowResMoving() const { return _wantLowResMoving; } bool getWantOcclusionCulling() const { return _wantOcclusionCulling; } int getMaxVoxelPacketsPerSecond() const { return _maxVoxelPPS; } + float getVoxelSizeScale() const { return _voxelSizeScale; } public slots: void setWantLowResMoving(bool wantLowResMoving) { _wantLowResMoving = wantLowResMoving; } @@ -76,6 +77,7 @@ public slots: void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; } void setWantOcclusionCulling(bool wantOcclusionCulling) { _wantOcclusionCulling = wantOcclusionCulling; } void setMaxVoxelPacketsPerSecond(int maxVoxelPPS) { _maxVoxelPPS = maxVoxelPPS; } + void setVoxelSizeScale(float voxelSizeScale) { _voxelSizeScale = voxelSizeScale; } protected: QUuid _uuid; @@ -95,6 +97,7 @@ protected: bool _wantLowResMoving; bool _wantOcclusionCulling; int _maxVoxelPPS; + float _voxelSizeScale; /// used for LOD calculations private: // privatize the copy constructor and assignment operator so they cannot be called diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index ac14f0dc58..aca539f9d3 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -33,13 +33,8 @@ #include "VoxelTree.h" #include -float boundaryDistanceForRenderLevel(unsigned int renderLevel) { - return ::VOXEL_SIZE_SCALE / powf(2, renderLevel); -} - -float boundaryDistanceSquaredForRenderLevel(unsigned int renderLevel) { - const float voxelSizeScale = (::VOXEL_SIZE_SCALE/TREE_SCALE) * (::VOXEL_SIZE_SCALE/TREE_SCALE); - return voxelSizeScale / powf(2, (2 * renderLevel)); +float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeScale) { + return voxelSizeScale / powf(2, renderLevel); } VoxelTree::VoxelTree(bool shouldReaverage) : @@ -1114,7 +1109,8 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp // caller can pass NULL as viewFrustum if they want everything if (params.viewFrustum) { float distance = node->distanceToCamera(*params.viewFrustum); - float boundaryDistance = boundaryDistanceForRenderLevel(node->getLevel() + params.boundaryLevelAdjust); + float boundaryDistance = boundaryDistanceForRenderLevel(node->getLevel() + params.boundaryLevelAdjust, + params.voxelSizeScale); // If we're too far away for our render level, then just return if (distance >= boundaryDistance) { @@ -1288,7 +1284,8 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp // Before we determine consider this further, let's see if it's in our LOD scope... float distance = distancesToChildren[i]; // params.viewFrustum ? childNode->distanceToCamera(*params.viewFrustum) : 0; float boundaryDistance = !params.viewFrustum ? 1 : - boundaryDistanceForRenderLevel(childNode->getLevel() + params.boundaryLevelAdjust); + boundaryDistanceForRenderLevel(childNode->getLevel() + params.boundaryLevelAdjust, + params.voxelSizeScale); if (!(distance < boundaryDistance)) { // don't need to check childNode here, because we can't get here with no childNode @@ -1341,7 +1338,8 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp bool shouldRender = !params.viewFrustum ? true - : childNode->calculateShouldRender(params.viewFrustum, params.boundaryLevelAdjust); + : childNode->calculateShouldRender(params.viewFrustum, + params.voxelSizeScale, params.boundaryLevelAdjust); // track some stats if (params.stats) { diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 465c1a54aa..933a1f436e 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -47,52 +47,55 @@ const uint64_t IGNORE_LAST_SENT = 0; class EncodeBitstreamParams { public: - int maxEncodeLevel; - int maxLevelReached; - const ViewFrustum* viewFrustum; - bool includeColor; - bool includeExistsBits; - int chopLevels; - bool deltaViewFrustum; - const ViewFrustum* lastViewFrustum; - bool wantOcclusionCulling; - int boundaryLevelAdjust; - uint64_t lastViewFrustumSent; - bool forceSendScene; - VoxelSceneStats* stats; - CoverageMap* map; - JurisdictionMap* jurisdictionMap; + int maxEncodeLevel; + int maxLevelReached; + const ViewFrustum* viewFrustum; + bool includeColor; + bool includeExistsBits; + int chopLevels; + bool deltaViewFrustum; + const ViewFrustum* lastViewFrustum; + bool wantOcclusionCulling; + int boundaryLevelAdjust; + float voxelSizeScale; + uint64_t lastViewFrustumSent; + bool forceSendScene; + VoxelSceneStats* stats; + CoverageMap* map; + JurisdictionMap* jurisdictionMap; EncodeBitstreamParams( - int maxEncodeLevel = INT_MAX, - const ViewFrustum* viewFrustum = IGNORE_VIEW_FRUSTUM, - bool includeColor = WANT_COLOR, - bool includeExistsBits = WANT_EXISTS_BITS, - int chopLevels = 0, - bool deltaViewFrustum = false, - const ViewFrustum* lastViewFrustum = IGNORE_VIEW_FRUSTUM, - bool wantOcclusionCulling= NO_OCCLUSION_CULLING, - CoverageMap* map = IGNORE_COVERAGE_MAP, - int boundaryLevelAdjust = NO_BOUNDARY_ADJUST, - uint64_t lastViewFrustumSent = IGNORE_LAST_SENT, - bool forceSendScene = true, - VoxelSceneStats* stats = IGNORE_SCENE_STATS, - JurisdictionMap* jurisdictionMap = IGNORE_JURISDICTION_MAP) : - maxEncodeLevel (maxEncodeLevel), - maxLevelReached (0), - viewFrustum (viewFrustum), - includeColor (includeColor), - includeExistsBits (includeExistsBits), - chopLevels (chopLevels), - deltaViewFrustum (deltaViewFrustum), - lastViewFrustum (lastViewFrustum), - wantOcclusionCulling (wantOcclusionCulling), - boundaryLevelAdjust (boundaryLevelAdjust), - lastViewFrustumSent (lastViewFrustumSent), - forceSendScene (forceSendScene), - stats (stats), - map (map), - jurisdictionMap (jurisdictionMap) + int maxEncodeLevel = INT_MAX, + const ViewFrustum* viewFrustum = IGNORE_VIEW_FRUSTUM, + bool includeColor = WANT_COLOR, + bool includeExistsBits = WANT_EXISTS_BITS, + int chopLevels = 0, + bool deltaViewFrustum = false, + const ViewFrustum* lastViewFrustum = IGNORE_VIEW_FRUSTUM, + bool wantOcclusionCulling = NO_OCCLUSION_CULLING, + CoverageMap* map = IGNORE_COVERAGE_MAP, + int boundaryLevelAdjust = NO_BOUNDARY_ADJUST, + float voxelSizeScale = DEFAULT_VOXEL_SIZE_SCALE, + uint64_t lastViewFrustumSent = IGNORE_LAST_SENT, + bool forceSendScene = true, + VoxelSceneStats* stats = IGNORE_SCENE_STATS, + JurisdictionMap* jurisdictionMap = IGNORE_JURISDICTION_MAP) : + maxEncodeLevel(maxEncodeLevel), + maxLevelReached(0), + viewFrustum(viewFrustum), + includeColor(includeColor), + includeExistsBits(includeExistsBits), + chopLevels(chopLevels), + deltaViewFrustum(deltaViewFrustum), + lastViewFrustum(lastViewFrustum), + wantOcclusionCulling(wantOcclusionCulling), + boundaryLevelAdjust(boundaryLevelAdjust), + voxelSizeScale(voxelSizeScale), + lastViewFrustumSent(lastViewFrustumSent), + forceSendScene(forceSendScene), + stats(stats), + map(map), + jurisdictionMap(jurisdictionMap) {} }; @@ -265,7 +268,6 @@ private: void chunkifyLeaf(VoxelNode* node); }; -float boundaryDistanceForRenderLevel(unsigned int renderLevel); -float boundaryDistanceSquaredForRenderLevel(unsigned int renderLevel); +float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeScale); #endif /* defined(__hifi__VoxelTree__) */ From 75721eb7ba2e218ab89db5fdea91df190a3d52c9 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 29 Oct 2013 16:17:11 -0700 Subject: [PATCH 03/21] first cut at user adjustable LOD --- interface/src/ui/LodToolsDialog.cpp | 58 +++++++++++++++++++++++++++++ interface/src/ui/LodToolsDialog.h | 42 +++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 interface/src/ui/LodToolsDialog.cpp create mode 100644 interface/src/ui/LodToolsDialog.h diff --git a/interface/src/ui/LodToolsDialog.cpp b/interface/src/ui/LodToolsDialog.cpp new file mode 100644 index 0000000000..5d9ecb45c3 --- /dev/null +++ b/interface/src/ui/LodToolsDialog.cpp @@ -0,0 +1,58 @@ +// +// LodToolsDialog.cpp +// interface +// +// Created by Brad Hefta-Gaub on 7/19/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#include +#include + +#include +#include +#include + +#include + +#include "ui/LodToolsDialog.h" + + +LodToolsDialog::LodToolsDialog(QWidget* parent) : + QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint) +{ + this->setWindowTitle("LOD Tools"); + + // Create layouter + QFormLayout* form = new QFormLayout(); + + QSlider* lodSize = new QSlider(Qt::Horizontal); + lodSize->setValue(0); + form->addRow("LOD Size Scale:", lodSize); + + this->QDialog::setLayout(form); +} + +LodToolsDialog::~LodToolsDialog() { +} + +float LodToolsDialog::getVoxelSizeScale() { + return DEFAULT_VOXEL_SIZE_SCALE; +} + +void LodToolsDialog::paintEvent(QPaintEvent* event) { + this->QDialog::paintEvent(event); + this->setFixedSize(this->width(), this->height()); +} + +void LodToolsDialog::reject() { + // Just regularly close upon ESC + this->QDialog::close(); +} + +void LodToolsDialog::closeEvent(QCloseEvent* event) { + this->QDialog::closeEvent(event); + emit closed(); +} + + diff --git a/interface/src/ui/LodToolsDialog.h b/interface/src/ui/LodToolsDialog.h new file mode 100644 index 0000000000..3f69a33a4a --- /dev/null +++ b/interface/src/ui/LodToolsDialog.h @@ -0,0 +1,42 @@ +// +// LodToolsDialog.h +// interface +// +// Created by Brad Hefta-Gaub on 7/19/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __hifi__LodToolsDialog__ +#define __hifi__LodToolsDialog__ + +#include +#include + +#include + +class LodToolsDialog : public QDialog { + Q_OBJECT +public: + // Sets up the UI + LodToolsDialog(QWidget* parent); + ~LodToolsDialog(); + + float getVoxelSizeScale(); + +signals: + void closed(); + +public slots: + void reject(); + +protected: + void paintEvent(QPaintEvent*); + + // Emits a 'closed' signal when this dialog is closed. + void closeEvent(QCloseEvent*); + +private: +}; + +#endif /* defined(__interface__LodToolsDialog__) */ + From 580102bb386ab49a883a91901415a6b9e0bc4760 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 30 Oct 2013 11:01:37 -0700 Subject: [PATCH 04/21] more work on LOD slider --- interface/src/Application.cpp | 2 + interface/src/Menu.cpp | 21 +++- interface/src/Menu.h | 8 +- interface/src/VoxelSystem.cpp | 24 ++-- interface/src/VoxelSystem.h | 1 + interface/src/ui/LodToolsDialog.cpp | 114 ++++++++++++++++-- interface/src/ui/LodToolsDialog.h | 12 +- .../src/VoxelSendThread.cpp | 10 +- libraries/voxels/src/VoxelConstants.h | 1 + libraries/voxels/src/VoxelQuery.cpp | 8 ++ libraries/voxels/src/VoxelQuery.h | 3 + 11 files changed, 176 insertions(+), 28 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0f4e1c74ba..6d6ccdd1d6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2369,6 +2369,8 @@ void Application::queryVoxels() { _voxelQuery.setCameraNearClip(_viewFrustum.getNearClip()); _voxelQuery.setCameraFarClip(_viewFrustum.getFarClip()); _voxelQuery.setCameraEyeOffsetPosition(_viewFrustum.getEyeOffsetPosition()); + _voxelQuery.setVoxelSizeScale(Menu::getInstance()->getVoxelSizeScale()); + _voxelQuery.setBoundaryLevelAdjust(Menu::getInstance()->getBoundaryLevelAdjust()); unsigned char voxelQueryPacket[MAX_PACKET_SIZE]; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 5435738ecd..a0c336bcc8 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -54,7 +54,9 @@ Menu::Menu() : _voxelModeActionsGroup(NULL), _voxelStatsDialog(NULL), _lodToolsDialog(NULL), - _maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM) + _maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM), + _voxelSizeScale(DEFAULT_VOXEL_SIZE_SCALE), + _boundaryLevelAdjust(0) { Application *appInstance = Application::getInstance(); @@ -520,6 +522,8 @@ void Menu::loadSettings(QSettings* settings) { _audioJitterBufferSamples = loadSetting(settings, "audioJitterBufferSamples", 0); _fieldOfView = loadSetting(settings, "fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES); _maxVoxels = loadSetting(settings, "maxVoxels", DEFAULT_MAX_VOXELS_PER_SYSTEM); + _voxelSizeScale = loadSetting(settings, "voxelSizeScale", DEFAULT_VOXEL_SIZE_SCALE); + _boundaryLevelAdjust = loadSetting(settings, "boundaryLevelAdjust", 0); settings->beginGroup("View Frustum Offset Camera"); // in case settings is corrupt or missing loadSetting() will check for NaN @@ -546,6 +550,8 @@ void Menu::saveSettings(QSettings* settings) { settings->setValue("audioJitterBufferSamples", _audioJitterBufferSamples); settings->setValue("fieldOfView", _fieldOfView); settings->setValue("maxVoxels", _maxVoxels); + settings->setValue("voxelSizeScale", _voxelSizeScale); + settings->setValue("boundaryLevelAdjust", _boundaryLevelAdjust); settings->beginGroup("View Frustum Offset Camera"); settings->setValue("viewFrustumOffsetYaw", _viewFrustumOffset.yaw); settings->setValue("viewFrustumOffsetPitch", _viewFrustumOffset.pitch); @@ -1059,11 +1065,14 @@ void Menu::voxelStatsDetailsClosed() { } } -float Menu::getVoxelSizeScale() { - if (_lodToolsDialog) { - return _lodToolsDialog->getVoxelSizeScale(); - } - return DEFAULT_FIELD_OF_VIEW_DEGREES; +void Menu::setVoxelSizeScale(float sizeScale) { + _voxelSizeScale = sizeScale; + Application::getInstance()->getVoxels()->redrawInViewVoxels(); +} + +void Menu::setBoundaryLevelAdjust(int boundaryLevelAdjust) { + _boundaryLevelAdjust = boundaryLevelAdjust; + Application::getInstance()->getVoxels()->redrawInViewVoxels(); } void Menu::lodTools() { diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 82cf994bc8..8f5b90aa52 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -61,7 +61,11 @@ public: void handleViewFrustumOffsetKeyModifier(int key); - float getVoxelSizeScale(); + // User Tweakable LOD Items + void setVoxelSizeScale(float sizeScale); + float getVoxelSizeScale() const { return _voxelSizeScale; } + void setBoundaryLevelAdjust(int boundaryLevelAdjust); + int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } public slots: void bandwidthDetails(); @@ -128,6 +132,8 @@ private: VoxelStatsDialog* _voxelStatsDialog; LodToolsDialog* _lodToolsDialog; int _maxVoxels; + float _voxelSizeScale; + int _boundaryLevelAdjust; QAction* _useVoxelShader; }; diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index b84304e6c5..2db9a961d4 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -139,8 +139,9 @@ void VoxelSystem::voxelUpdated(VoxelNode* node) { if (node->getVoxelSystem() == this) { bool shouldRender = false; // assume we don't need to render it // if it's colored, we might need to render it! - float voxelSizeScale = DEFAULT_VOXEL_SIZE_SCALE; - shouldRender = node->calculateShouldRender(_viewFrustum, voxelSizeScale); + float voxelSizeScale = Menu::getInstance()->getVoxelSizeScale(); + int boundaryLevelAdjust = Menu::getInstance()->getBoundaryLevelAdjust(); + shouldRender = node->calculateShouldRender(_viewFrustum, voxelSizeScale, boundaryLevelAdjust); if (node->getShouldRender() != shouldRender) { node->setShouldRender(shouldRender); @@ -924,8 +925,9 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) { int voxelsUpdated = 0; bool shouldRender = false; // assume we don't need to render it // if it's colored, we might need to render it! - float voxelSizeScale = DEFAULT_VOXEL_SIZE_SCALE; - shouldRender = node->calculateShouldRender(_viewFrustum, voxelSizeScale); + float voxelSizeScale = Menu::getInstance()->getVoxelSizeScale();; + int boundaryLevelAdjust = Menu::getInstance()->getBoundaryLevelAdjust(); + shouldRender = node->calculateShouldRender(_viewFrustum, voxelSizeScale, boundaryLevelAdjust); node->setShouldRender(shouldRender); // let children figure out their renderness @@ -1386,6 +1388,10 @@ void VoxelSystem::killLocalVoxels() { setupNewVoxelsForDrawing(); } +void VoxelSystem::redrawInViewVoxels() { + hideOutOfView(true); +} + bool VoxelSystem::clearAllNodesBufferIndexOperation(VoxelNode* node, void* extraData) { _nodeCount++; @@ -1773,8 +1779,9 @@ bool VoxelSystem::showAllLocalVoxelsOperation(VoxelNode* node, void* extraData) args->nodesScanned++; - float voxelSizeScale = DEFAULT_VOXEL_SIZE_SCALE; - bool shouldRender = node->calculateShouldRender(&args->thisViewFrustum, voxelSizeScale); + float voxelSizeScale = Menu::getInstance()->getVoxelSizeScale();; + int boundaryLevelAdjust = Menu::getInstance()->getBoundaryLevelAdjust(); + bool shouldRender = node->calculateShouldRender(&args->thisViewFrustum, voxelSizeScale, boundaryLevelAdjust); node->setShouldRender(shouldRender); if (shouldRender) { @@ -1950,8 +1957,9 @@ bool VoxelSystem::showAllSubTreeOperation(VoxelNode* node, void* extraData) { args->nodesInside++; - float voxelSizeScale = DEFAULT_VOXEL_SIZE_SCALE; - bool shouldRender = node->calculateShouldRender(&args->thisViewFrustum, voxelSizeScale); + float voxelSizeScale = Menu::getInstance()->getVoxelSizeScale(); + int boundaryLevelAdjust = Menu::getInstance()->getBoundaryLevelAdjust(); + bool shouldRender = node->calculateShouldRender(&args->thisViewFrustum, voxelSizeScale, boundaryLevelAdjust); node->setShouldRender(shouldRender); if (shouldRender && !node->isKnownBufferIndex()) { diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index d5434ec7f7..de48c34d22 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -83,6 +83,7 @@ public: float getVoxelsBytesReadPerSecondAverage(); void killLocalVoxels(); + void redrawInViewVoxels(); virtual void removeOutOfView(); virtual void hideOutOfView(bool forceFullFrustum = false); diff --git a/interface/src/ui/LodToolsDialog.cpp b/interface/src/ui/LodToolsDialog.cpp index 5d9ecb45c3..d2e9eaf7e0 100644 --- a/interface/src/ui/LodToolsDialog.cpp +++ b/interface/src/ui/LodToolsDialog.cpp @@ -12,9 +12,12 @@ #include #include #include +#include +#include #include +#include "Menu.h" #include "ui/LodToolsDialog.h" @@ -26,23 +29,118 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) : // Create layouter QFormLayout* form = new QFormLayout(); - QSlider* lodSize = new QSlider(Qt::Horizontal); - lodSize->setValue(0); - form->addRow("LOD Size Scale:", lodSize); + _lodSize = new QSlider(Qt::Horizontal); + const int MAX_LOD_SIZE = MAX_LOD_SIZE_MULTIPLIER; + const int MIN_LOD_SIZE = 0; + const int STEP_LOD_SIZE = 1; + const int PAGE_STEP_LOD_SIZE = 100; + const int SLIDER_WIDTH = 300; + _lodSize->setMaximum(MAX_LOD_SIZE); + _lodSize->setMinimum(MIN_LOD_SIZE); + _lodSize->setSingleStep(STEP_LOD_SIZE); + _lodSize->setTickInterval(PAGE_STEP_LOD_SIZE); + _lodSize->setTickPosition(QSlider::TicksBelow); + _lodSize->setFixedWidth(SLIDER_WIDTH); + _lodSize->setPageStep(PAGE_STEP_LOD_SIZE); + int sliderValue = Menu::getInstance()->getVoxelSizeScale() / TREE_SCALE; + _lodSize->setValue(sliderValue); + form->addRow("LOD Size Scale:", _lodSize); + connect(_lodSize,SIGNAL(valueChanged(int)),this,SLOT(sizeScaleValueChanged(int))); + + _boundaryLevelAdjust = new QSlider(Qt::Horizontal); + const int MAX_ADJUST = 10; + const int MIN_ADJUST = 0; + const int STEP_ADJUST = 1; + _boundaryLevelAdjust->setMaximum(MAX_ADJUST); + _boundaryLevelAdjust->setMinimum(MIN_ADJUST); + _boundaryLevelAdjust->setSingleStep(STEP_ADJUST); + _boundaryLevelAdjust->setTickInterval(STEP_ADJUST); + _boundaryLevelAdjust->setTickPosition(QSlider::TicksBelow); + _boundaryLevelAdjust->setFixedWidth(SLIDER_WIDTH); + sliderValue = Menu::getInstance()->getBoundaryLevelAdjust(); + _boundaryLevelAdjust->setValue(sliderValue); + form->addRow("Boundary Level Adjust:", _boundaryLevelAdjust); + connect(_boundaryLevelAdjust,SIGNAL(valueChanged(int)),this,SLOT(boundaryLevelValueChanged(int))); + + // Create a label with feedback... + _feedback = new QLabel(); + QPalette palette = _feedback->palette(); + const unsigned redish = 0xfff00000; + palette.setColor(QPalette::WindowText, QColor::fromRgb(redish)); + _feedback->setPalette(palette); + _feedback->setText(getFeedbackText()); + const int FEEDBACK_WIDTH = 350; + _feedback->setFixedWidth(FEEDBACK_WIDTH); + form->addRow("You can see... ", _feedback); + // Add a button to reset + QPushButton* resetButton = new QPushButton("Reset"); + form->addRow("", resetButton); + connect(resetButton,SIGNAL(clicked(bool)),this,SLOT(resetClicked(bool))); + this->QDialog::setLayout(form); + //int width = 600; + //int height = 200; + //this->setFixedSize(width, height); +} + +QString LodToolsDialog::getFeedbackText() { + // determine granularity feedback + int boundaryLevelAdjust = Menu::getInstance()->getBoundaryLevelAdjust(); + QString granularityFeedback; + + switch (boundaryLevelAdjust) { + case 0: { + granularityFeedback = QString("at standard granularity."); + } break; + case 1: { + granularityFeedback = QString("at half of standard granularity."); + } break; + case 2: { + granularityFeedback = QString("at a third of standard granularity."); + } break; + default: { + granularityFeedback = QString("at 1/%1th of standard granularity.").arg(boundaryLevelAdjust + 1); + } break; + } + + // distance feedback + float voxelSizeScale = Menu::getInstance()->getVoxelSizeScale(); + float relativeToDefault = voxelSizeScale / DEFAULT_VOXEL_SIZE_SCALE; + QString result; + if (relativeToDefault > 1.01) { + result = QString("%1 further %2").arg(relativeToDefault,8,'f',2).arg(granularityFeedback); + } else if (relativeToDefault > 0.99) { + result = QString("the default distance %1").arg(granularityFeedback); + } else { + result = QString("%1 of default %2").arg(relativeToDefault,8,'f',3).arg(granularityFeedback); + } + return result; } LodToolsDialog::~LodToolsDialog() { + delete _feedback; + delete _lodSize; + delete _boundaryLevelAdjust; } -float LodToolsDialog::getVoxelSizeScale() { - return DEFAULT_VOXEL_SIZE_SCALE; +void LodToolsDialog::sizeScaleValueChanged(int value) { + float realValue = value * TREE_SCALE; + Menu::getInstance()->setVoxelSizeScale(realValue); + + _feedback->setText(getFeedbackText()); } -void LodToolsDialog::paintEvent(QPaintEvent* event) { - this->QDialog::paintEvent(event); - this->setFixedSize(this->width(), this->height()); +void LodToolsDialog::boundaryLevelValueChanged(int value) { + Menu::getInstance()->setBoundaryLevelAdjust(value); + _feedback->setText(getFeedbackText()); +} + +void LodToolsDialog::resetClicked(bool checked) { + int sliderValue = DEFAULT_VOXEL_SIZE_SCALE / TREE_SCALE; + //sizeScaleValueChanged(sliderValue); + _lodSize->setValue(sliderValue); + _boundaryLevelAdjust->setValue(0); } void LodToolsDialog::reject() { diff --git a/interface/src/ui/LodToolsDialog.h b/interface/src/ui/LodToolsDialog.h index 3f69a33a4a..fad9749776 100644 --- a/interface/src/ui/LodToolsDialog.h +++ b/interface/src/ui/LodToolsDialog.h @@ -11,6 +11,7 @@ #include #include +#include #include @@ -21,21 +22,26 @@ public: LodToolsDialog(QWidget* parent); ~LodToolsDialog(); - float getVoxelSizeScale(); - signals: void closed(); public slots: void reject(); + void sizeScaleValueChanged(int value); + void boundaryLevelValueChanged(int value); + void resetClicked(bool checked); protected: - void paintEvent(QPaintEvent*); // Emits a 'closed' signal when this dialog is closed. void closeEvent(QCloseEvent*); private: + QString getFeedbackText(); + + QSlider* _lodSize; + QSlider* _boundaryLevelAdjust; + QLabel* _feedback; }; #endif /* defined(__interface__LodToolsDialog__) */ diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 38ed5742a9..e3705643b7 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -250,10 +250,16 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no VoxelNode* subTree = nodeData->nodeBag.extract(); bool wantOcclusionCulling = nodeData->getWantOcclusionCulling(); CoverageMap* coverageMap = wantOcclusionCulling ? &nodeData->map : IGNORE_COVERAGE_MAP; - int boundaryLevelAdjust = viewFrustumChanged && nodeData->getWantLowResMoving() - ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST; float voxelSizeScale = nodeData->getVoxelSizeScale(); + int boundaryLevelAdjustClient = nodeData->getBoundaryLevelAdjust(); + + int boundaryLevelAdjust = boundaryLevelAdjustClient + (viewFrustumChanged && nodeData->getWantLowResMoving() + ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST); + + + printf("packetLoop() voxelSizeScale=%f boundaryLevelAdjustClient=%d boundaryLevelAdjust=%d\n", + voxelSizeScale, boundaryLevelAdjustClient, boundaryLevelAdjust); bool isFullScene = (!viewFrustumChanged || !nodeData->getWantDelta()) && nodeData->getViewFrustumJustStoppedChanging(); diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index 26c6032a89..c3c0568300 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -28,6 +28,7 @@ const int TREE_SCALE = 16384; // ~10 miles.. This is the number of meters of t // This controls the LOD. Larger number will make smaller voxels visible at greater distance. const float DEFAULT_VOXEL_SIZE_SCALE = TREE_SCALE * 400.0f; +const float MAX_LOD_SIZE_MULTIPLIER = 2000.0f; const int NUMBER_OF_CHILDREN = 8; const int MAX_VOXEL_PACKET_SIZE = 1492; diff --git a/libraries/voxels/src/VoxelQuery.cpp b/libraries/voxels/src/VoxelQuery.cpp index 1b293eeeb5..463b806eba 100644 --- a/libraries/voxels/src/VoxelQuery.cpp +++ b/libraries/voxels/src/VoxelQuery.cpp @@ -83,6 +83,10 @@ int VoxelQuery::getBroadcastData(unsigned char* destinationBuffer) { // desired voxelSizeScale memcpy(destinationBuffer, &_voxelSizeScale, sizeof(_voxelSizeScale)); destinationBuffer += sizeof(_voxelSizeScale); + + // desired boundaryLevelAdjust + memcpy(destinationBuffer, &_boundaryLevelAdjust, sizeof(_boundaryLevelAdjust)); + destinationBuffer += sizeof(_boundaryLevelAdjust); return destinationBuffer - bufferStart; } @@ -130,6 +134,10 @@ int VoxelQuery::parseData(unsigned char* sourceBuffer, int numBytes) { memcpy(&_voxelSizeScale, sourceBuffer, sizeof(_voxelSizeScale)); sourceBuffer += sizeof(_voxelSizeScale); + // desired boundaryLevelAdjust + memcpy(&_boundaryLevelAdjust, sourceBuffer, sizeof(_boundaryLevelAdjust)); + sourceBuffer += sizeof(_boundaryLevelAdjust); + return sourceBuffer - startPosition; } diff --git a/libraries/voxels/src/VoxelQuery.h b/libraries/voxels/src/VoxelQuery.h index 701b3e399d..bedbfdac4e 100644 --- a/libraries/voxels/src/VoxelQuery.h +++ b/libraries/voxels/src/VoxelQuery.h @@ -70,6 +70,7 @@ public: bool getWantOcclusionCulling() const { return _wantOcclusionCulling; } int getMaxVoxelPacketsPerSecond() const { return _maxVoxelPPS; } float getVoxelSizeScale() const { return _voxelSizeScale; } + int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } public slots: void setWantLowResMoving(bool wantLowResMoving) { _wantLowResMoving = wantLowResMoving; } @@ -78,6 +79,7 @@ public slots: void setWantOcclusionCulling(bool wantOcclusionCulling) { _wantOcclusionCulling = wantOcclusionCulling; } void setMaxVoxelPacketsPerSecond(int maxVoxelPPS) { _maxVoxelPPS = maxVoxelPPS; } void setVoxelSizeScale(float voxelSizeScale) { _voxelSizeScale = voxelSizeScale; } + void setBoundaryLevelAdjust(int boundaryLevelAdjust) { _boundaryLevelAdjust = boundaryLevelAdjust; } protected: QUuid _uuid; @@ -98,6 +100,7 @@ protected: bool _wantOcclusionCulling; int _maxVoxelPPS; float _voxelSizeScale; /// used for LOD calculations + int _boundaryLevelAdjust; /// used for LOD calculations private: // privatize the copy constructor and assignment operator so they cannot be called From baafea05af93b122a94aafa7c8cb48405b72da1d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 30 Oct 2013 11:22:38 -0700 Subject: [PATCH 05/21] make server resend scene when LOD changes --- .../src/VoxelNodeData.cpp | 17 ++++++++++++++++- .../voxel-server-library/src/VoxelNodeData.h | 19 +++++++++++++------ .../src/VoxelSendThread.cpp | 10 ++++------ 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index 705ea8b2e7..57e42b634a 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -23,7 +23,10 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) : _viewFrustumChanging(false), _viewFrustumJustStoppedChanging(true), _currentPacketIsColor(true), - _voxelSendThread(NULL) + _voxelSendThread(NULL), + _lastClientBoundaryLevelAdjust(0), + _lastClientVoxelSizeScale(DEFAULT_VOXEL_SIZE_SCALE), + _lodChanged(false) { _voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE]; _voxelPacketAt = _voxelPacket; @@ -140,6 +143,17 @@ bool VoxelNodeData::updateCurrentViewFrustum() { currentViewFrustumChanged = true; } + // Also check for LOD changes from the client + if (_lastClientBoundaryLevelAdjust != getBoundaryLevelAdjust()) { + _lastClientBoundaryLevelAdjust = getBoundaryLevelAdjust(); + _lodChanged = true; + } + if (_lastClientVoxelSizeScale != getVoxelSizeScale()) { + _lastClientVoxelSizeScale = getVoxelSizeScale(); + _lodChanged = true; + } + + // When we first detect that the view stopped changing, we record this. // but we don't change it back to false until we've completely sent this // scene. @@ -154,6 +168,7 @@ void VoxelNodeData::setViewSent(bool viewSent) { _viewSent = viewSent; if (viewSent) { _viewFrustumJustStoppedChanging = false; + _lodChanged = false; } } diff --git a/libraries/voxel-server-library/src/VoxelNodeData.h b/libraries/voxel-server-library/src/VoxelNodeData.h index 4049cdda36..ef5b32a894 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.h +++ b/libraries/voxel-server-library/src/VoxelNodeData.h @@ -48,25 +48,27 @@ public: VoxelNodeBag nodeBag; CoverageMap map; - ViewFrustum& getCurrentViewFrustum() { return _currentViewFrustum; }; - ViewFrustum& getLastKnownViewFrustum() { return _lastKnownViewFrustum; }; + ViewFrustum& getCurrentViewFrustum() { return _currentViewFrustum; }; + ViewFrustum& getLastKnownViewFrustum() { return _lastKnownViewFrustum; }; // These are not classic setters because they are calculating and maintaining state // which is set asynchronously through the network receive bool updateCurrentViewFrustum(); void updateLastKnownViewFrustum(); - bool getViewSent() const { return _viewSent; }; + bool getViewSent() const { return _viewSent; }; void setViewSent(bool viewSent); - bool getViewFrustumChanging() const { return _viewFrustumChanging; }; + bool getViewFrustumChanging() const { return _viewFrustumChanging; }; bool getViewFrustumJustStoppedChanging() const { return _viewFrustumJustStoppedChanging; }; - uint64_t getLastTimeBagEmpty() const { return _lastTimeBagEmpty; }; - void setLastTimeBagEmpty(uint64_t lastTimeBagEmpty) { _lastTimeBagEmpty = lastTimeBagEmpty; }; + uint64_t getLastTimeBagEmpty() const { return _lastTimeBagEmpty; }; + void setLastTimeBagEmpty(uint64_t lastTimeBagEmpty) { _lastTimeBagEmpty = lastTimeBagEmpty; }; bool getCurrentPacketIsColor() const { return _currentPacketIsColor; }; + + bool hasLodChanged() const { return _lodChanged; }; VoxelSceneStats stats; @@ -98,6 +100,11 @@ private: bool _currentPacketIsColor; VoxelSendThread* _voxelSendThread; + + // watch for LOD changes + int _lastClientBoundaryLevelAdjust; + float _lastClientVoxelSizeScale; + bool _lodChanged; }; #endif /* defined(__hifi__VoxelNodeData__) */ diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index e3705643b7..2cfb72a246 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -194,7 +194,8 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no } // start tracking our stats - bool isFullScene = (!viewFrustumChanged || !nodeData->getWantDelta()) && nodeData->getViewFrustumJustStoppedChanging(); + bool isFullScene = ((!viewFrustumChanged || !nodeData->getWantDelta()) + && nodeData->getViewFrustumJustStoppedChanging()) || nodeData->hasLodChanged(); // If we're starting a full scene, then definitely we want to empty the nodeBag if (isFullScene) { @@ -258,11 +259,8 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST); - printf("packetLoop() voxelSizeScale=%f boundaryLevelAdjustClient=%d boundaryLevelAdjust=%d\n", - voxelSizeScale, boundaryLevelAdjustClient, boundaryLevelAdjust); - - bool isFullScene = (!viewFrustumChanged || !nodeData->getWantDelta()) && - nodeData->getViewFrustumJustStoppedChanging(); + bool isFullScene = ((!viewFrustumChanged || !nodeData->getWantDelta()) && + nodeData->getViewFrustumJustStoppedChanging()) || nodeData->hasLodChanged(); EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor, WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum, From dd7eb66ceca902cd9a22abb800a793e404411b90 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 30 Oct 2013 11:53:16 -0700 Subject: [PATCH 06/21] adjustable LOD tweaks --- interface/src/VoxelSystem.cpp | 15 +++++++++++- interface/src/VoxelSystem.h | 2 ++ .../src/VoxelNodeData.cpp | 23 ++++++++++++------- .../voxel-server-library/src/VoxelNodeData.h | 1 + .../src/VoxelSendThread.cpp | 4 +++- 5 files changed, 35 insertions(+), 10 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 2db9a961d4..4b543ed13c 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -109,6 +109,7 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) _useFastVoxelPipeline = false; _culledOnce = false; + _inhideOutOfView = false; } void VoxelSystem::voxelDeleted(VoxelNode* node) { @@ -1848,6 +1849,14 @@ public: }; void VoxelSystem::hideOutOfView(bool forceFullFrustum) { + + // don't re-enter... + if (_inhideOutOfView) { + return; + } + + _inhideOutOfView = true; + bool showDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showDebugDetails, "hideOutOfView()", showDebugDetails); bool widenFrustum = true; @@ -1879,10 +1888,13 @@ void VoxelSystem::hideOutOfView(bool forceFullFrustum) { if (!forceFullFrustum && _culledOnce && args.lastViewFrustum.isVerySimilar(args.thisViewFrustum)) { //printf("view frustum hasn't changed BAIL!!!\n"); + _inhideOutOfView = false; return; } - + + pthread_mutex_lock(&_treeLock); _tree->recurseTreeWithOperation(hideOutOfViewOperation,(void*)&args); + pthread_mutex_unlock(&_treeLock); _lastCulledViewFrustum = args.thisViewFrustum; // save last stable _culledOnce = true; @@ -1900,6 +1912,7 @@ void VoxelSystem::hideOutOfView(bool forceFullFrustum) { args.nodesInsideInside, args.nodesIntersectInside, args.nodesOutsideOutside ); } + _inhideOutOfView = false; } bool VoxelSystem::hideAllSubTreeOperation(VoxelNode* node, void* extraData) { diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index de48c34d22..f99e487a07 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -299,6 +299,8 @@ private: bool _inSetupNewVoxelsForDrawing; bool _useFastVoxelPipeline; + + bool _inhideOutOfView; }; #endif diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index 57e42b634a..ced0669283 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -26,7 +26,8 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) : _voxelSendThread(NULL), _lastClientBoundaryLevelAdjust(0), _lastClientVoxelSizeScale(DEFAULT_VOXEL_SIZE_SCALE), - _lodChanged(false) + _lodChanged(false), + _lodInitialized(false) { _voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE]; _voxelPacketAt = _voxelPacket; @@ -144,16 +145,22 @@ bool VoxelNodeData::updateCurrentViewFrustum() { } // Also check for LOD changes from the client - if (_lastClientBoundaryLevelAdjust != getBoundaryLevelAdjust()) { - _lastClientBoundaryLevelAdjust = getBoundaryLevelAdjust(); - _lodChanged = true; - } - if (_lastClientVoxelSizeScale != getVoxelSizeScale()) { + if (_lodInitialized) { + if (_lastClientBoundaryLevelAdjust != getBoundaryLevelAdjust()) { + _lastClientBoundaryLevelAdjust = getBoundaryLevelAdjust(); + _lodChanged = true; + } + if (_lastClientVoxelSizeScale != getVoxelSizeScale()) { + _lastClientVoxelSizeScale = getVoxelSizeScale(); + _lodChanged = true; + } + } else { + _lodInitialized = true; _lastClientVoxelSizeScale = getVoxelSizeScale(); - _lodChanged = true; + _lastClientBoundaryLevelAdjust = getBoundaryLevelAdjust(); + _lodChanged = false; } - // When we first detect that the view stopped changing, we record this. // but we don't change it back to false until we've completely sent this // scene. diff --git a/libraries/voxel-server-library/src/VoxelNodeData.h b/libraries/voxel-server-library/src/VoxelNodeData.h index ef5b32a894..9f871b72ab 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.h +++ b/libraries/voxel-server-library/src/VoxelNodeData.h @@ -105,6 +105,7 @@ private: int _lastClientBoundaryLevelAdjust; float _lastClientVoxelSizeScale; bool _lodChanged; + bool _lodInitialized; }; #endif /* defined(__hifi__VoxelNodeData__) */ diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 2cfb72a246..220fbfaad3 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -175,7 +175,8 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no // if our view has changed, we need to reset these things... if (viewFrustumChanged) { - if (_myServer->wantDumpVoxelsOnMove()) { + if (_myServer->wantDumpVoxelsOnMove() || nodeData->hasLodChanged()) { +printf("viewFrustumChanged AND (_myServer->wantDumpVoxelsOnMove() || nodeData->hasLodChanged())... nodeData->nodeBag.deleteAll();\n"); nodeData->nodeBag.deleteAll(); } nodeData->map.erase(); @@ -199,6 +200,7 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no // If we're starting a full scene, then definitely we want to empty the nodeBag if (isFullScene) { +printf("isFullScene... nodeData->nodeBag.deleteAll();\n"); nodeData->nodeBag.deleteAll(); } nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, _myServer->getServerTree().rootNode, _myServer->getJurisdiction()); From 96870f5d663854debbc8f5ad52045e940140135d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 30 Oct 2013 12:15:16 -0700 Subject: [PATCH 07/21] removed debug --- libraries/voxel-server-library/src/VoxelSendThread.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 220fbfaad3..fcb6e19955 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -176,7 +176,6 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no // if our view has changed, we need to reset these things... if (viewFrustumChanged) { if (_myServer->wantDumpVoxelsOnMove() || nodeData->hasLodChanged()) { -printf("viewFrustumChanged AND (_myServer->wantDumpVoxelsOnMove() || nodeData->hasLodChanged())... nodeData->nodeBag.deleteAll();\n"); nodeData->nodeBag.deleteAll(); } nodeData->map.erase(); @@ -200,7 +199,6 @@ printf("viewFrustumChanged AND (_myServer->wantDumpVoxelsOnMove() || nodeData->h // If we're starting a full scene, then definitely we want to empty the nodeBag if (isFullScene) { -printf("isFullScene... nodeData->nodeBag.deleteAll();\n"); nodeData->nodeBag.deleteAll(); } nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, _myServer->getServerTree().rootNode, _myServer->getJurisdiction()); From e8f5c86c7340d1878e133ad8f12b5a569752f4a9 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 30 Oct 2013 12:19:47 -0700 Subject: [PATCH 08/21] fix one call to calculateShouldRender() --- interface/src/VoxelSystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 4b543ed13c..7581dcc8db 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -158,7 +158,7 @@ void VoxelSystem::voxelUpdated(VoxelNode* node) { VoxelNode* childNode = node->getChildAtIndex(i); if (childNode) { bool wasShouldRender = childNode->getShouldRender(); - bool isShouldRender = childNode->calculateShouldRender(_viewFrustum, voxelSizeScale); + bool isShouldRender = childNode->calculateShouldRender(_viewFrustum, voxelSizeScale, boundaryLevelAdjust); if (wasShouldRender && !isShouldRender) { childrenGotHiddenCount++; } From 98f09d70619f1f7a5c4e6da8e5894c4b272517ba Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 30 Oct 2013 12:21:05 -0700 Subject: [PATCH 09/21] removed dead code --- interface/src/ui/LodToolsDialog.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/interface/src/ui/LodToolsDialog.cpp b/interface/src/ui/LodToolsDialog.cpp index d2e9eaf7e0..44cd66d0b6 100644 --- a/interface/src/ui/LodToolsDialog.cpp +++ b/interface/src/ui/LodToolsDialog.cpp @@ -79,9 +79,6 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) : connect(resetButton,SIGNAL(clicked(bool)),this,SLOT(resetClicked(bool))); this->QDialog::setLayout(form); - //int width = 600; - //int height = 200; - //this->setFixedSize(width, height); } QString LodToolsDialog::getFeedbackText() { From 3445a15d61a14f24e0fd370ffc035fec09dc45ea Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 30 Oct 2013 12:35:42 -0700 Subject: [PATCH 10/21] fix build buster --- libraries/voxels/src/VoxelConstants.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index c3c0568300..e0cd514214 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -13,6 +13,7 @@ #define __hifi_VoxelConstants_h__ #include +#include #include #include From 0bbbd7efce5e7381d565ed4738cceaf2eb5488ea Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 30 Oct 2013 14:00:56 -0700 Subject: [PATCH 11/21] fix Voxel Server Protocol menu options to work again --- interface/src/Application.cpp | 5 +++++ interface/src/Menu.cpp | 32 ++++---------------------------- 2 files changed, 9 insertions(+), 28 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6c76f589da..885aa230bf 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2365,6 +2365,11 @@ void Application::queryVoxels() { } // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. + _voxelQuery.setWantLowResMoving(Menu::getInstance()->isOptionChecked(MenuOption::LowRes)); + _voxelQuery.setWantColor(Menu::getInstance()->isOptionChecked(MenuOption::SendVoxelColors)); + _voxelQuery.setWantDelta(Menu::getInstance()->isOptionChecked(MenuOption::DeltaSending)); + _voxelQuery.setWantOcclusionCulling(Menu::getInstance()->isOptionChecked(MenuOption::OcclusionCulling)); + _voxelQuery.setCameraPosition(_viewFrustum.getPosition()); _voxelQuery.setCameraOrientation(_viewFrustum.getOrientation()); _voxelQuery.setCameraFov(_viewFrustum.getFieldOfView()); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index a431b4b457..953c3238d0 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -466,34 +466,10 @@ Menu::Menu() : QMenu* voxelProtoOptionsMenu = developerMenu->addMenu("Voxel Server Protocol Options"); - addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, - MenuOption::SendVoxelColors, - 0, - true, - appInstance->getAvatar(), - SLOT(setWantColor(bool))); - - addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, - MenuOption::LowRes, - 0, - true, - appInstance->getAvatar(), - SLOT(setWantLowResMoving(bool))); - - addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, - MenuOption::DeltaSending, - 0, - true, - appInstance->getAvatar(), - SLOT(setWantDelta(bool))); - - addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, - MenuOption::OcclusionCulling, - Qt::SHIFT | Qt::Key_C, - true, - appInstance->getAvatar(), - SLOT(setWantOcclusionCulling(bool))); - + addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::SendVoxelColors); + addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::LowRes); + addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::DeltaSending); + addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::OcclusionCulling); addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::DestructiveAddVoxel); #ifndef Q_OS_MAC From 3f9631dd53e647b7f34d36be7e20dbbee0dd261b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 30 Oct 2013 14:14:34 -0700 Subject: [PATCH 12/21] fix voxels as points menu to work correctly on startup --- interface/src/VoxelSystem.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index b7afd67947..dfe0126949 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -416,6 +416,12 @@ void VoxelSystem::initVoxelMemory() { _memoryUsageRAM = 0; _memoryUsageVBO = 0; // our VBO allocations as we know them + + // if _voxelsAsPoints then we must have _useVoxelShader + if (_voxelsAsPoints && !_useVoxelShader) { + _useVoxelShader = true; + } + if (_useVoxelShader) { GLuint* indicesArray = new GLuint[_maxVoxels]; From 14ddb8934159cde302b9c84ee5d576a7a03b3865 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 30 Oct 2013 14:28:32 -0700 Subject: [PATCH 13/21] improve behavior of too more than _maxVoxels --- interface/src/VoxelSystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index dfe0126949..7f0e3d798f 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -991,7 +991,7 @@ int VoxelSystem::forceRemoveNodeFromArrays(VoxelNode* node) { int VoxelSystem::updateNodeInArrays(VoxelNode* node, bool reuseIndex, bool forceDraw) { // If we've run out of room, then just bail... - if (_voxelsInWriteArrays >= _maxVoxels) { + if (_voxelsInWriteArrays >= _maxVoxels && (_freeIndexes.size() == 0)) { // We need to think about what else we can do in this case. This basically means that all of our available // VBO slots are used up, but we're trying to render more voxels. At this point, if this happens we'll just // not render these Voxels. We need to think about ways to keep the entire scene intact but maybe lower quality From 2f1ecd8d1b2c918506349ba542e63985b90b8222 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 30 Oct 2013 15:12:04 -0700 Subject: [PATCH 14/21] improve voxel server's behavior when client is moving, dump out of view pending voxels --- .../src/VoxelNodeData.cpp | 35 +++++++++++++++++++ .../voxel-server-library/src/VoxelNodeData.h | 5 ++- .../src/VoxelSendThread.cpp | 4 +-- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index 705ea8b2e7..a0889e9fd5 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -171,3 +171,38 @@ void VoxelNodeData::updateLastKnownViewFrustum() { setLastTimeBagEmpty(now); // is this what we want? poor names } + +bool VoxelNodeData::moveShouldDump() const { + glm::vec3 oldPosition = _lastKnownViewFrustum.getPosition(); + glm::vec3 newPosition = _currentViewFrustum.getPosition(); + + const float MAXIMUM_MOVE_WITHOUT_DUMP = 0.10f; + if (glm::distance(newPosition, oldPosition) > MAXIMUM_MOVE_WITHOUT_DUMP) { + return true; + } + return false; +} + +void VoxelNodeData::dumpOutOfView() { + int stillInView = 0; + int outOfView = 0; + VoxelNodeBag tempBag; + while (!nodeBag.isEmpty()) { + VoxelNode* node = nodeBag.extract(); + if (node->isInView(_currentViewFrustum)) { + tempBag.insert(node); + stillInView++; + } else { + outOfView++; + } + } + if (stillInView > 0) { + while (!tempBag.isEmpty()) { + VoxelNode* node = tempBag.extract(); + if (node->isInView(_currentViewFrustum)) { + nodeBag.insert(node); + } + } + } +} + diff --git a/libraries/voxel-server-library/src/VoxelNodeData.h b/libraries/voxel-server-library/src/VoxelNodeData.h index 4049cdda36..cf59f8e84e 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.h +++ b/libraries/voxel-server-library/src/VoxelNodeData.h @@ -61,7 +61,8 @@ public: bool getViewFrustumChanging() const { return _viewFrustumChanging; }; bool getViewFrustumJustStoppedChanging() const { return _viewFrustumJustStoppedChanging; }; - + + bool moveShouldDump() const; uint64_t getLastTimeBagEmpty() const { return _lastTimeBagEmpty; }; void setLastTimeBagEmpty(uint64_t lastTimeBagEmpty) { _lastTimeBagEmpty = lastTimeBagEmpty; }; @@ -73,6 +74,8 @@ public: void initializeVoxelSendThread(VoxelServer* voxelServer); bool isVoxelSendThreadInitalized() { return _voxelSendThread; } + void dumpOutOfView(); + private: VoxelNodeData(const VoxelNodeData &); VoxelNodeData& operator= (const VoxelNodeData&); diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 3a3904e218..119b4263ff 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -175,8 +175,8 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no // if our view has changed, we need to reset these things... if (viewFrustumChanged) { - if (_myServer->wantDumpVoxelsOnMove()) { - nodeData->nodeBag.deleteAll(); + if (_myServer->wantDumpVoxelsOnMove() || nodeData->moveShouldDump()) { + nodeData->dumpOutOfView(); } nodeData->map.erase(); } From 606a6349c767ac9e881d7103b5a817cb551b279b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 30 Oct 2013 15:28:44 -0700 Subject: [PATCH 15/21] added abandoned voxels to stats, improved sizing behavior of voxel stats dialog --- interface/src/Application.cpp | 8 +++++--- interface/src/VoxelSystem.h | 1 + interface/src/ui/VoxelStatsDialog.cpp | 5 ++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 885aa230bf..43540f35ff 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3178,10 +3178,12 @@ void Application::displayStats() { std::stringstream voxelStats; voxelStats.precision(4); - voxelStats << "Voxels Rendered: " << _voxels.getVoxelsRendered() / 1000.f << "K " << + voxelStats << "Voxels " << + "Max: " << _voxels.getMaxVoxels()/1000.f << "K " << + "Rendered: " << _voxels.getVoxelsRendered() / 1000.f << "K " << "Written: " << _voxels.getVoxelsWritten()/1000.f << "K " << - "Updated: " << _voxels.getVoxelsUpdated()/1000.f << "K " << - "Max: " << _voxels.getMaxVoxels()/1000.f << "K "; + "Abandoned: " << _voxels.getAbandonedVoxels()/1000.f << "K " << + "Updated: " << _voxels.getVoxelsUpdated()/1000.f << "K "; statsVerticalOffset += PELS_PER_LINE; drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str()); diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index d5434ec7f7..93d0c9cbce 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -60,6 +60,7 @@ public: unsigned long getVoxelsUpdated() const { return _voxelsUpdated; } unsigned long getVoxelsRendered() const { return _voxelsInReadArrays; } unsigned long getVoxelsWritten() const { return _voxelsInWriteArrays; } + unsigned long getAbandonedVoxels() const { return _freeIndexes.size(); } ViewFrustum* getLastCulledViewFrustum() { return &_lastCulledViewFrustum; } diff --git a/interface/src/ui/VoxelStatsDialog.cpp b/interface/src/ui/VoxelStatsDialog.cpp index 2fa9ff8cd3..0f2ed3e36d 100644 --- a/interface/src/ui/VoxelStatsDialog.cpp +++ b/interface/src/ui/VoxelStatsDialog.cpp @@ -34,7 +34,6 @@ VoxelStatsDialog::VoxelStatsDialog(QWidget* parent, VoxelSceneStats* model) : VoxelSceneStats::Item item = (VoxelSceneStats::Item)(i); VoxelSceneStats::ItemInfo& itemInfo = _model->getItemInfo(item); QLabel* label = _labels[item] = new QLabel(); - label->setAlignment(Qt::AlignRight); // Set foreground color to 62.5% brightness of the meter (otherwise will be hard to read on the bright background) QPalette palette = label->palette(); @@ -45,8 +44,8 @@ VoxelStatsDialog::VoxelStatsDialog(QWidget* parent, VoxelSceneStats* model) : palette.setColor(QPalette::WindowText, QColor::fromRgb(rgb)); label->setPalette(palette); - // This is my hackery attempt at making QDialog auto-size to a width that will hold our info. It kinda works. - label->setText("123456789012345678901234567890123456789012345678901234567890"); + const int STATS_LABLE_WIDTH = 550; + label->setFixedWidth(STATS_LABLE_WIDTH); snprintf(strBuf, sizeof(strBuf), " %s:", itemInfo.caption); form->addRow(strBuf, label); From ac236b9ed8febc8eda93a6d3255de37149f2ed30 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 30 Oct 2013 16:26:42 -0700 Subject: [PATCH 16/21] if LOD changes than don't consider WasInView on server --- libraries/voxels/src/VoxelTree.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index ac14f0dc58..fb6a04ebc2 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1147,6 +1147,19 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp } else { wasInView = location == ViewFrustum::INSIDE; } + + // If we were in view, double check that we didn't switch LOD visibility... namely, the was in view doesn't + // tell us if it was so small we wouldn't have rendered it. Which may be the case. And we may have moved closer + // to it, and so therefore it may now be visible from an LOD perspective, in which case we don't consider it + // as "was in view"... + if (wasInView) { + float distance = node->distanceToCamera(*params.lastViewFrustum); + float boundaryDistance = boundaryDistanceForRenderLevel(node->getLevel() + params.boundaryLevelAdjust); + if (distance >= boundaryDistance) { + // This would have been invisible... but now should be visible (we wouldn't be here otherwise)... + wasInView = false; + } + } } // If we were previously in the view, then we normally will return out of here and stop recursing. But From 9c5ebfcf7777e83abc038240c252088f994936c4 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 30 Oct 2013 16:44:40 -0700 Subject: [PATCH 17/21] If the skeleton has meshes, don't render the balls and sticks. --- interface/src/avatar/SkeletonModel.cpp | 67 ++++++++++++++------------ interface/src/renderer/Model.h | 19 ++++---- 2 files changed, 45 insertions(+), 41 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index c6381eea08..efea1d867c 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -35,41 +35,44 @@ bool SkeletonModel::render(float alpha) { return false; } - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - - glm::vec3 skinColor, darkSkinColor; - _owningAvatar->getSkinColors(skinColor, darkSkinColor); - - for (int i = 0; i < _jointStates.size(); i++) { - glPushMatrix(); + // only render the balls and sticks if the skeleton has no meshes + if (_meshStates.isEmpty()) { + const FBXGeometry& geometry = _geometry->getFBXGeometry(); - glm::vec3 position; - getJointPosition(i, position); - glTranslatef(position.x, position.y, position.z); + glm::vec3 skinColor, darkSkinColor; + _owningAvatar->getSkinColors(skinColor, darkSkinColor); - glm::quat rotation; - getJointRotation(i, rotation); - glm::vec3 axis = glm::axis(rotation); - glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z); - - glColor4f(skinColor.r, skinColor.g, skinColor.b, alpha); - const float BALL_RADIUS = 0.02f; - const int BALL_SUBDIVISIONS = 10; - glutSolidSphere(BALL_RADIUS * _owningAvatar->getScale(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS); - - glPopMatrix(); - - int parentIndex = geometry.joints[i].parentIndex; - if (parentIndex == -1) { - continue; + for (int i = 0; i < _jointStates.size(); i++) { + glPushMatrix(); + + glm::vec3 position; + getJointPosition(i, position); + glTranslatef(position.x, position.y, position.z); + + glm::quat rotation; + getJointRotation(i, rotation); + glm::vec3 axis = glm::axis(rotation); + glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z); + + glColor4f(skinColor.r, skinColor.g, skinColor.b, alpha); + const float BALL_RADIUS = 0.02f; + const int BALL_SUBDIVISIONS = 10; + glutSolidSphere(BALL_RADIUS * _owningAvatar->getScale(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS); + + glPopMatrix(); + + int parentIndex = geometry.joints[i].parentIndex; + if (parentIndex == -1) { + continue; + } + glColor4f(darkSkinColor.r, darkSkinColor.g, darkSkinColor.b, alpha); + + glm::vec3 parentPosition; + getJointPosition(parentIndex, parentPosition); + const float STICK_RADIUS = BALL_RADIUS * 0.5f; + Avatar::renderJointConnectingCone(parentPosition, position, STICK_RADIUS * _owningAvatar->getScale(), + STICK_RADIUS * _owningAvatar->getScale()); } - glColor4f(darkSkinColor.r, darkSkinColor.g, darkSkinColor.b, alpha); - - glm::vec3 parentPosition; - getJointPosition(parentIndex, parentPosition); - const float STICK_RADIUS = BALL_RADIUS * 0.5f; - Avatar::renderJointConnectingCone(parentPosition, position, STICK_RADIUS * _owningAvatar->getScale(), - STICK_RADIUS * _owningAvatar->getScale()); } Model::render(alpha); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index f485a35da0..2c0c553719 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -107,6 +107,16 @@ protected: QVector _jointStates; + class MeshState { + public: + QVector clusterMatrices; + QVector worldSpaceVertices; + QVector vertexVelocities; + QVector worldSpaceNormals; + }; + + QVector _meshStates; + /// Updates the state of the joint at the specified index. virtual void updateJointState(int index); @@ -129,15 +139,6 @@ private: QUrl _url; - class MeshState { - public: - QVector clusterMatrices; - QVector worldSpaceVertices; - QVector vertexVelocities; - QVector worldSpaceNormals; - }; - - QVector _meshStates; QVector _blendedVertexBufferIDs; QVector > > _dilatedTextures; bool _resetStates; From 256428c6aefb42ba0795b7f0da1576917fbfe160 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 30 Oct 2013 16:55:39 -0700 Subject: [PATCH 18/21] CR feedback --- interface/src/Application.cpp | 8 ++++---- interface/src/ui/VoxelStatsDialog.cpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b5ef0413fe..c6220600df 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3187,11 +3187,11 @@ void Application::displayStats() { std::stringstream voxelStats; voxelStats.precision(4); voxelStats << "Voxels " << - "Max: " << _voxels.getMaxVoxels()/1000.f << "K " << + "Max: " << _voxels.getMaxVoxels() / 1000.f << "K " << "Rendered: " << _voxels.getVoxelsRendered() / 1000.f << "K " << - "Written: " << _voxels.getVoxelsWritten()/1000.f << "K " << - "Abandoned: " << _voxels.getAbandonedVoxels()/1000.f << "K " << - "Updated: " << _voxels.getVoxelsUpdated()/1000.f << "K "; + "Written: " << _voxels.getVoxelsWritten() / 1000.f << "K " << + "Abandoned: " << _voxels.getAbandonedVoxels() / 1000.f << "K " << + "Updated: " << _voxels.getVoxelsUpdated() / 1000.f << "K "; statsVerticalOffset += PELS_PER_LINE; drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str()); diff --git a/interface/src/ui/VoxelStatsDialog.cpp b/interface/src/ui/VoxelStatsDialog.cpp index 0f2ed3e36d..cdc39fc69c 100644 --- a/interface/src/ui/VoxelStatsDialog.cpp +++ b/interface/src/ui/VoxelStatsDialog.cpp @@ -44,8 +44,8 @@ VoxelStatsDialog::VoxelStatsDialog(QWidget* parent, VoxelSceneStats* model) : palette.setColor(QPalette::WindowText, QColor::fromRgb(rgb)); label->setPalette(palette); - const int STATS_LABLE_WIDTH = 550; - label->setFixedWidth(STATS_LABLE_WIDTH); + const int STATS_LABEL_WIDTH = 550; + label->setFixedWidth(STATS_LABEL_WIDTH); snprintf(strBuf, sizeof(strBuf), " %s:", itemInfo.caption); form->addRow(strBuf, label); From 9a5cc596b3c91ae4928aed9bc8825c794f93d0de Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 30 Oct 2013 16:57:32 -0700 Subject: [PATCH 19/21] CR feedback --- libraries/voxel-server-library/src/VoxelNodeData.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index bb58e07784..73f0987d97 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -197,8 +197,9 @@ void VoxelNodeData::updateLastKnownViewFrustum() { bool VoxelNodeData::moveShouldDump() const { glm::vec3 oldPosition = _lastKnownViewFrustum.getPosition(); glm::vec3 newPosition = _currentViewFrustum.getPosition(); - - const float MAXIMUM_MOVE_WITHOUT_DUMP = 0.10f; + + // theoretically we could make this slightly larger but relative to avatar scale. + const float MAXIMUM_MOVE_WITHOUT_DUMP = 0.0f; if (glm::distance(newPosition, oldPosition) > MAXIMUM_MOVE_WITHOUT_DUMP) { return true; } From 5814f9ea8110bbd3e88271d0e591b3970a5f1e34 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 30 Oct 2013 18:02:13 -0700 Subject: [PATCH 20/21] add debug to see document root on DS relaunch --- domain-server/src/DomainServer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index d91d020a22..66925e32fe 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -326,6 +326,7 @@ DomainServer::DomainServer(int argc, char* argv[]) : struct mg_callbacks callbacks = {}; QString documentRoot = QString("%1/resources/web").arg(QCoreApplication::applicationDirPath()); + qDebug("The document root is %s\n", documentRoot.toStdString()); // list of options. Last element must be NULL. const char* options[] = {"listening_ports", "8080", From 6014c833edd2b0d407a6dae9c514b4828b06f6b6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 30 Oct 2013 18:11:32 -0700 Subject: [PATCH 21/21] fix a broken build in the domain-server --- domain-server/src/DomainServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 66925e32fe..d404d4d39d 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -326,7 +326,7 @@ DomainServer::DomainServer(int argc, char* argv[]) : struct mg_callbacks callbacks = {}; QString documentRoot = QString("%1/resources/web").arg(QCoreApplication::applicationDirPath()); - qDebug("The document root is %s\n", documentRoot.toStdString()); + qDebug("The document root is %s\n", documentRoot.toLocal8Bit().constData()); // list of options. Last element must be NULL. const char* options[] = {"listening_ports", "8080",