From f6981feacf78e37c0728bd6735f9eb3121abfb51 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 7 Oct 2013 17:46:22 -0700 Subject: [PATCH] added various render mode options, including voxels as points --- interface/src/Application.cpp | 1 + interface/src/Menu.cpp | 17 ++-- interface/src/Menu.h | 9 +- interface/src/VoxelSystem.cpp | 187 ++++++++++++++++++++++++---------- interface/src/VoxelSystem.h | 7 +- 5 files changed, 153 insertions(+), 68 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6d7686328f..46a2b9afde 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1589,6 +1589,7 @@ void Application::init() { // Set up VoxelSystem after loading preferences so we can get the desired max voxel count _voxels.setMaxVoxels(Menu::getInstance()->getMaxVoxels()); _voxels.setUseVoxelShader(Menu::getInstance()->isOptionChecked(MenuOption::UseVoxelShader)); + _voxels.setVoxelsAsPoints(Menu::getInstance()->isOptionChecked(MenuOption::VoxelsAsPoints)); _voxels.setUseFastVoxelPipeline(Menu::getInstance()->isOptionChecked(MenuOption::FastVoxelPipeline)); _voxels.init(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index ededcbccd0..8b92448e71 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -240,12 +240,18 @@ Menu::Menu() : appInstance, SLOT(setRenderVoxels(bool))); addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontRenderVoxels); - addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelTextures); - addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::AmbientOcclusion); - addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::UseVoxelShader, 0, - false, this, SLOT(switchVoxelShader())); + addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontCallOpenGLForVoxels); + + _useVoxelShader = addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::UseVoxelShader, 0, + false, appInstance->getVoxels(), SLOT(setUseVoxelShader(bool))); + + addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelsAsPoints, 0, + false, appInstance->getVoxels(), SLOT(setVoxelsAsPoints(bool))); + addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::FastVoxelPipeline, 0, false, appInstance->getVoxels(), SLOT(setUseFastVoxelPipeline(bool))); + addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelTextures); + addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::AmbientOcclusion); QMenu* avatarOptionsMenu = developerMenu->addMenu("Avatar Options"); @@ -1005,7 +1011,4 @@ void Menu::updateFrustumRenderModeAction() { } } -void Menu::switchVoxelShader() { - Application::getInstance()->getVoxels()->setUseVoxelShader(isOptionChecked(MenuOption::UseVoxelShader)); -} diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 5c21a35b35..f54d3767a1 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -54,6 +54,7 @@ public: ViewFrustumOffset getViewFrustumOffset() const { return _viewFrustumOffset; } VoxelStatsDialog* getVoxelStatsDialog() const { return _voxelStatsDialog; } int getMaxVoxels() const { return _maxVoxels; } + QAction* getUseVoxelShader() const { return _useVoxelShader; } void handleViewFrustumOffsetKeyModifier(int key); @@ -78,7 +79,6 @@ private slots: void chooseVoxelPaintColor(); void runTests(); void resetSwatchColors(); - void switchVoxelShader(); private: static Menu* _instance; @@ -116,6 +116,7 @@ private: QActionGroup* _voxelModeActionsGroup; VoxelStatsDialog* _voxelStatsDialog; int _maxVoxels; + QAction* _useVoxelShader; }; namespace MenuOption { @@ -138,7 +139,8 @@ namespace MenuOption { const QString DestructiveAddVoxel = "Create Voxel is Destructive"; const QString DeltaSending = "Delta Sending"; const QString DisplayFrustum = "Display Frustum"; - const QString DontRenderVoxels = "Don't Render Voxels"; + const QString DontRenderVoxels = "Don't call _voxels.render()"; + const QString DontCallOpenGLForVoxels = "Don't call glDrawElements()/glDrawRangeElementsEXT() for Voxels"; const QString EchoAudio = "Echo Audio"; const QString ExportVoxels = "Export Voxels"; const QString HeadMouse = "Head Mouse"; @@ -205,8 +207,7 @@ namespace MenuOption { const QString UsePerlinFace = "Use Perlin's Face"; const QString Quit = "Quit"; const QString UseVoxelShader = "Use Voxel Shader"; - const QString UseByteNormals = "Use Byte Normals"; - const QString UseGlobalNormals = "Use Global Normals"; + const QString VoxelsAsPoints = "Draw Voxels as Points"; const QString Voxels = "Voxels"; const QString VoxelAddMode = "Add Voxel Mode"; const QString VoxelColorMode = "Color Voxel Mode"; diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index f0d6777053..634486d8dc 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -90,6 +90,8 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) connect(_tree, SIGNAL(importProgress(int)), SIGNAL(importProgress(int))); _useVoxelShader = false; + _voxelsAsPoints = false; + _voxelShaderModeWhenVoxelsAsPointsEnabled = false; _writeVoxelShaderData = NULL; _readVoxelShaderData = NULL; @@ -219,7 +221,6 @@ void VoxelSystem::setMaxVoxels(int maxVoxels) { if (maxVoxels == _maxVoxels) { return; } - pthread_mutex_lock(&_bufferWriteLock); bool wasInitialized = _initialized; if (wasInitialized) { clearAllNodesBufferIndex(); @@ -227,9 +228,8 @@ void VoxelSystem::setMaxVoxels(int maxVoxels) { } _maxVoxels = maxVoxels; if (wasInitialized) { - init(); + initVoxelMemory(); } - pthread_mutex_unlock(&_bufferWriteLock); if (wasInitialized) { forceRedrawEntireTree(); } @@ -240,7 +240,6 @@ void VoxelSystem::setUseVoxelShader(bool useVoxelShader) { return; } - pthread_mutex_lock(&_bufferWriteLock); bool wasInitialized = _initialized; if (wasInitialized) { clearAllNodesBufferIndex(); @@ -248,17 +247,59 @@ void VoxelSystem::setUseVoxelShader(bool useVoxelShader) { } _useVoxelShader = useVoxelShader; if (wasInitialized) { - init(); + initVoxelMemory(); } - pthread_mutex_unlock(&_bufferWriteLock); if (wasInitialized) { forceRedrawEntireTree(); } } +void VoxelSystem::setVoxelsAsPoints(bool voxelsAsPoints) { + if (_voxelsAsPoints == voxelsAsPoints) { + return; + } + + bool wasInitialized = _initialized; + + // If we're "turning on" Voxels as points, we need to double check that we're in voxel shader mode. + // Voxels as points uses the VoxelShader memory model, so if we're not in voxel shader mode, + // then set it to voxel shader mode. + if (voxelsAsPoints) { + Menu::getInstance()->getUseVoxelShader()->setEnabled(false); + + // If enabling this... then do it before checking voxel shader status, that way, if voxel + // shader is already enabled, we just start drawing as points. + _voxelsAsPoints = true; + + if (!_useVoxelShader) { + setUseVoxelShader(true); + _voxelShaderModeWhenVoxelsAsPointsEnabled = false; + } else { + _voxelShaderModeWhenVoxelsAsPointsEnabled = true; + } + } else { + Menu::getInstance()->getUseVoxelShader()->setEnabled(true); + // if we're turning OFF voxels as point mode, then we check what the state of voxel shader was when we enabled + // voxels as points, if it was OFF, then we return it to that value. + if (_voxelShaderModeWhenVoxelsAsPointsEnabled == false) { + setUseVoxelShader(false); + } + // If disabling this... then do it AFTER checking previous voxel shader status, that way, if voxel + // shader is was not enabled, we switch back to normal mode before turning off points. + _voxelsAsPoints = false; + } + + // Set our voxels as points + if (wasInitialized) { + forceRedrawEntireTree(); + } +} + void VoxelSystem::cleanupVoxelMemory() { if (_initialized) { + pthread_mutex_lock(&_bufferWriteLock); + _initialized = false; // no longer initialized if (_useVoxelShader) { // these are used when in VoxelShader mode. glDeleteBuffers(1, &_vboVoxelsID); @@ -266,6 +307,9 @@ void VoxelSystem::cleanupVoxelMemory() { delete[] _writeVoxelShaderData; delete[] _readVoxelShaderData; + + _writeVoxelShaderData = _readVoxelShaderData = NULL; + } else { // Destroy glBuffers glDeleteBuffers(1, &_vboVerticesID); @@ -282,11 +326,18 @@ void VoxelSystem::cleanupVoxelMemory() { delete[] _writeVerticesArray; delete[] _readColorsArray; delete[] _writeColorsArray; + + _readVerticesArray = NULL; + _writeVerticesArray = NULL; + _readColorsArray = NULL; + _writeColorsArray = NULL; + } delete[] _writeVoxelDirtyArray; delete[] _readVoxelDirtyArray; + _writeVoxelDirtyArray = _readVoxelDirtyArray = NULL; + pthread_mutex_unlock(&_bufferWriteLock); } - _initialized = false; // no longer initialized } void VoxelSystem::setupFaceIndices(GLuint& faceVBOID, GLubyte faceIdentityIndices[]) { @@ -318,11 +369,11 @@ void VoxelSystem::setupFaceIndices(GLuint& faceVBOID, GLubyte faceIdentityIndice } void VoxelSystem::initVoxelMemory() { - _initialMemoryUsageGPU = getFreeMemoryGPU(); + pthread_mutex_lock(&_bufferWriteLock); + _memoryUsageRAM = 0; _memoryUsageVBO = 0; // our VBO allocations as we know them if (_useVoxelShader) { - qDebug("Using Voxel Shader...\n"); GLuint* indicesArray = new GLuint[_maxVoxels]; // populate the indicesArray @@ -418,6 +469,10 @@ void VoxelSystem::initVoxelMemory() { _perlinModulateProgram.release(); } } + + _initialized = true; + + pthread_mutex_unlock(&_bufferWriteLock); } void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) { @@ -544,7 +599,12 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { void VoxelSystem::setupNewVoxelsForDrawing() { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "setupNewVoxelsForDrawing()"); // would like to include _voxelsInArrays, _voxelsUpdated + "setupNewVoxelsForDrawing()"); + + if (!_initialized) { + return; // bail early if we're not initialized + } + uint64_t start = usecTimestampNow(); uint64_t sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000; @@ -587,7 +647,11 @@ void VoxelSystem::setupNewVoxelsForDrawing() { } // lock on the buffer write lock so we can't modify the data when the GPU is reading it - pthread_mutex_lock(&_bufferWriteLock); + { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "setupNewVoxelsForDrawing()... pthread_mutex_lock(&_bufferWriteLock)"); + pthread_mutex_lock(&_bufferWriteLock); + } if (_voxelsUpdated) { _voxelsDirty=true; @@ -957,14 +1021,13 @@ void VoxelSystem::init() { _setupNewVoxelsForDrawingLastElapsed = 0; _lastViewCullingElapsed = _lastViewCulling = 0; - // When we change voxels representations in the arrays, we'll update this _voxelsDirty = false; _voxelsInWriteArrays = 0; _voxelsInReadArrays = 0; // VBO for the verticesArray + _initialMemoryUsageGPU = getFreeMemoryGPU(); initVoxelMemory(); - _initialized = true; // our own _removedVoxels doesn't need to be notified of voxel deletes VoxelNode::removeDeleteHook(&_removedVoxels); @@ -1071,16 +1134,14 @@ void VoxelSystem::render(bool texture) { return; } - // get the lock so that the update thread won't change anything - pthread_mutex_lock(&_bufferWriteLock); - updateVBOs(); - + + bool dontCallOpenGLDraw = Menu::getInstance()->isOptionChecked(MenuOption::DontCallOpenGLForVoxels); + // if not don't... then do... if (_useVoxelShader) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "render().. _useVoxelShader openGL.."); - - Application::getInstance()->getVoxelShader().begin(); + //Define this somewhere in your header file #define BUFFER_OFFSET(i) ((void*)(i)) @@ -1088,14 +1149,29 @@ void VoxelSystem::render(bool texture) { glBindBuffer(GL_ARRAY_BUFFER, _vboVoxelsID); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(0)); //The starting point of the VBO, for the vertices - int loc = Application::getInstance()->getVoxelShader().attributeLocation("voxelSizeIn"); - glEnableVertexAttribArray(loc); - glVertexAttribPointer(loc, 1, GL_FLOAT, false, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(3*sizeof(float))); + + int attributeLocation; + + if (!_voxelsAsPoints) { + Application::getInstance()->getVoxelShader().begin(); + + attributeLocation = Application::getInstance()->getVoxelShader().attributeLocation("voxelSizeIn"); + glEnableVertexAttribArray(attributeLocation); + glVertexAttribPointer(attributeLocation, 1, GL_FLOAT, false, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(3*sizeof(float))); + } else { + const float POINT_SIZE = 4.0; + glPointSize(POINT_SIZE); + } + + glEnableClientState(GL_COLOR_ARRAY); glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(4*sizeof(float)));//The starting point of colors glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboVoxelsIndicesID); - glDrawElements(GL_POINTS, _voxelsInReadArrays, GL_UNSIGNED_INT, BUFFER_OFFSET(0)); //The starting point of the IBO + + if (!dontCallOpenGLDraw) { + glDrawElements(GL_POINTS, _voxelsInReadArrays, GL_UNSIGNED_INT, BUFFER_OFFSET(0)); //The starting point of the IBO + } // deactivate vertex and color arrays after drawing glDisableClientState(GL_VERTEX_ARRAY); @@ -1105,11 +1181,13 @@ void VoxelSystem::render(bool texture) { glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - Application::getInstance()->getVoxelShader().end(); - + if (!_voxelsAsPoints) { + Application::getInstance()->getVoxelShader().end(); + glDisableVertexAttribArray(attributeLocation); + } } else { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "render().. openGL..."); - + // tell OpenGL where to find vertex and color information glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); @@ -1121,47 +1199,48 @@ void VoxelSystem::render(bool texture) { glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0); applyScaleAndBindProgram(texture); - + // for performance, enable backface culling glEnable(GL_CULL_FACE); // draw voxels in 6 passes - glNormal3f(0,1.0f,0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesTop); - glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, - INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); + if (!dontCallOpenGLDraw) { + glNormal3f(0,1.0f,0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesTop); + glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, + INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); - glNormal3f(0,-1.0f,0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesBottom); - glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, - INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); + glNormal3f(0,-1.0f,0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesBottom); + glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, + INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); - glNormal3f(-1.0f,0,0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesLeft); - glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, - INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); + glNormal3f(-1.0f,0,0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesLeft); + glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, + INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); - glNormal3f(1.0f,0,0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesRight); - glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, - INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); + glNormal3f(1.0f,0,0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesRight); + glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, + INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); - glNormal3f(0,0,-1.0f); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesFront); - glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, - INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); - - glNormal3f(0,0,1.0f); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesBack); - glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, - INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); + glNormal3f(0,0,-1.0f); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesFront); + glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, + INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); + glNormal3f(0,0,1.0f); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesBack); + glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, + INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); + } glDisable(GL_CULL_FACE); removeScaleAndReleaseProgram(texture); - + // deactivate vertex and color arrays after drawing glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); @@ -1170,8 +1249,6 @@ void VoxelSystem::render(bool texture) { glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } - - pthread_mutex_unlock(&_bufferWriteLock); } void VoxelSystem::applyScaleAndBindProgram(bool texture) { diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 4def28cfd2..456a9bc8c6 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -65,8 +65,6 @@ public: bool readFromSquareARGB32Pixels(const char* filename); bool readFromSchematicFile(const char* filename); - void setUseVoxelShader(bool useVoxelShader); - void setMaxVoxels(int maxVoxels); long int getMaxVoxels() const { return _maxVoxels; } unsigned long getVoxelMemoryUsageRAM() const { return _memoryUsageRAM; } @@ -137,6 +135,8 @@ public slots: void cancelImport(); void setUseFastVoxelPipeline(bool useFastVoxelPipeline); + void setUseVoxelShader(bool useVoxelShader); + void setVoxelsAsPoints(bool voxelsAsPoints); protected: float _treeScale; @@ -224,6 +224,9 @@ private: void cleanupVoxelMemory(); bool _useVoxelShader; + bool _voxelsAsPoints; + bool _voxelShaderModeWhenVoxelsAsPointsEnabled; + GLuint _vboVoxelsID; /// when using voxel shader, we'll use this VBO GLuint _vboVoxelsIndicesID; /// when using voxel shader, we'll use this VBO for our indexes VoxelShaderVBOData* _writeVoxelShaderData;