From b3aac56d2938b9743ad9036ab92654c987c83420 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Nov 2013 14:33:06 -0700 Subject: [PATCH 01/13] first cut a variable point size point rendering --- interface/resources/shaders/point_size.vert | 32 +++++++++ interface/src/Application.cpp | 1 + interface/src/Application.h | 6 +- interface/src/Menu.cpp | 1 + interface/src/VoxelSystem.cpp | 25 ++++++- interface/src/renderer/PointShader.cpp | 73 +++++++++++++++++++++ interface/src/renderer/PointShader.h | 48 ++++++++++++++ 7 files changed, 182 insertions(+), 4 deletions(-) create mode 100644 interface/resources/shaders/point_size.vert create mode 100644 interface/src/renderer/PointShader.cpp create mode 100644 interface/src/renderer/PointShader.h diff --git a/interface/resources/shaders/point_size.vert b/interface/resources/shaders/point_size.vert new file mode 100644 index 0000000000..98da0b85d6 --- /dev/null +++ b/interface/resources/shaders/point_size.vert @@ -0,0 +1,32 @@ +#version 120 + +attribute float voxelSizeIn; +varying float voxelSize; +uniform float viewportWidth; +uniform float viewportHeight; + +void main(void) { + gl_FrontColor = gl_Color; + vec4 cornerOriginal = gl_Vertex; + vec4 corner = gl_ModelViewProjectionMatrix * gl_Vertex; + + vec4 farCornerVertex = gl_Vertex; + farCornerVertex[0] += voxelSizeIn; + farCornerVertex[1] += voxelSizeIn; + farCornerVertex[2] += voxelSizeIn; + vec4 farCorner = gl_ModelViewProjectionMatrix * farCornerVertex; + + float voxelScreenWidth = abs((farCorner.x / farCorner.w) - (corner.x / corner.w)) * viewportWidth / 2.0; + float voxelScreenHeight = abs((farCorner.y / farCorner.w) - (corner.y / corner.w)) * viewportHeight / 2.0; + float voxelScreenLength = sqrt(voxelScreenHeight * voxelScreenHeight + voxelScreenWidth * voxelScreenWidth); + + vec4 centerVertex = gl_Vertex; + float halfSizeIn = voxelSizeIn / 2; + centerVertex[0] += halfSizeIn; + centerVertex[1] += halfSizeIn; + centerVertex[2] += halfSizeIn; + vec4 center = gl_ModelViewProjectionMatrix * centerVertex; + + gl_Position = center; + gl_PointSize = voxelScreenLength; +} \ No newline at end of file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d1d48a15e2..82fccf7d6d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1665,6 +1665,7 @@ void Application::init() { _glowEffect.init(); _ambientOcclusionEffect.init(); _voxelShader.init(); + _pointShader.init(); _handControl.setScreenDimensions(_glWidget->width(), _glWidget->height()); diff --git a/interface/src/Application.h b/interface/src/Application.h index f888442dbd..226756ab0f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -55,12 +55,12 @@ #include "renderer/GeometryCache.h" #include "renderer/GlowEffect.h" #include "renderer/VoxelShader.h" +#include "renderer/PointShader.h" #include "renderer/TextureCache.h" #include "ui/BandwidthDialog.h" #include "ui/ChatEntry.h" #include "ui/VoxelStatsDialog.h" #include "ui/RearMirrorTools.h" -#include "ui/LodToolsDialog.h" class QAction; class QActionGroup; @@ -162,6 +162,9 @@ public: virtual void domainChanged(QString domain); VoxelShader& getVoxelShader() { return _voxelShader; } + PointShader& getPointShader() { return _pointShader; } + + glm::vec2 getViewportDimensions() const{ return glm::vec2(_glWidget->width(),_glWidget->height()); } public slots: void sendAvatarFaceVideoMessage(int frameCount, const QByteArray& data); @@ -383,6 +386,7 @@ private: GlowEffect _glowEffect; AmbientOcclusionEffect _ambientOcclusionEffect; VoxelShader _voxelShader; + PointShader _pointShader; #ifndef _WIN32 Audio _audio; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index a1f83007fd..ac207e8812 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -29,6 +29,7 @@ #include "Menu.h" #include "Util.h" #include "InfoView.h" +#include "ui/LodToolsDialog.h" Menu* Menu::_instance = NULL; diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 9e2c6ec63e..5c836eb3e2 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -1257,13 +1257,28 @@ void VoxelSystem::render(bool texture) { 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); + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + + glm::vec2 viewDimensions = Application::getInstance()->getViewportDimensions(); + float viewportWidth = viewDimensions.x; + float viewportHeight = viewDimensions.y; + + Application::getInstance()->getPointShader().begin(); + + int uniformLocation = Application::getInstance()->getPointShader().uniformLocation("viewportWidth"); + Application::getInstance()->getPointShader().setUniformValue(uniformLocation, viewportWidth); + + uniformLocation = Application::getInstance()->getPointShader().uniformLocation("viewportHeight"); + Application::getInstance()->getPointShader().setUniformValue(uniformLocation, viewportHeight); + + attributeLocation = Application::getInstance()->getVoxelShader().attributeLocation("voxelSizeIn"); + //printf("attributeLocation=%d\n", attributeLocation); + glEnableVertexAttribArray(attributeLocation); + glVertexAttribPointer(attributeLocation, 1, GL_FLOAT, false, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(3*sizeof(float))); } @@ -1287,6 +1302,10 @@ void VoxelSystem::render(bool texture) { if (!_voxelsAsPoints) { Application::getInstance()->getVoxelShader().end(); glDisableVertexAttribArray(attributeLocation); + } else { + Application::getInstance()->getPointShader().end(); + glDisableVertexAttribArray(attributeLocation); + glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); } } else { PerformanceWarning warn(showWarnings, "render().. TRIANGLES..."); diff --git a/interface/src/renderer/PointShader.cpp b/interface/src/renderer/PointShader.cpp new file mode 100644 index 0000000000..8ebccc8d08 --- /dev/null +++ b/interface/src/renderer/PointShader.cpp @@ -0,0 +1,73 @@ +// +// PointShader.cpp +// interface +// +// Created by Brad Hefta-Gaub on 9/22/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. + +// include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL +#include "InterfaceConfig.h" + +#include + +#include "Application.h" +#include "PointShader.h" +#include "ProgramObject.h" +#include "RenderUtil.h" + +PointShader::PointShader() + : _initialized(false) +{ + _program = NULL; +} + +PointShader::~PointShader() { + if (_initialized) { + delete _program; + } +} + +ProgramObject* PointShader::createPointShaderProgram(const QString& name) { + ProgramObject* program = new ProgramObject(); + program->addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/" + name + ".vert" ); + program->link(); + return program; +} + +void PointShader::init() { + if (_initialized) { + qDebug("[ERROR] PointShader is already initialized.\n"); + return; + } + switchToResourcesParentIfRequired(); + _program = createPointShaderProgram("point_size"); + _initialized = true; +} + +void PointShader::begin() { + _program->bind(); +} + +void PointShader::end() { + _program->release(); +} + +int PointShader::attributeLocation(const char * name) const { + if (_program) { + return _program->attributeLocation(name); + } else { + return -1; + } +} + +int PointShader::uniformLocation(const char * name) const { + if (_program) { + return _program->uniformLocation(name); + } else { + return -1; + } +} + +void PointShader::setUniformValue(int attributeLocation, float value) { + _program->setUniformValue(attributeLocation, value); +} diff --git a/interface/src/renderer/PointShader.h b/interface/src/renderer/PointShader.h new file mode 100644 index 0000000000..f5ef54af5e --- /dev/null +++ b/interface/src/renderer/PointShader.h @@ -0,0 +1,48 @@ +// +// PointShader.h +// interface +// +// Created by Brad Hefta-Gaub on 9/23/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__PointShader__ +#define __interface__PointShader__ + +#include + +class ProgramObject; + +/// A generic full screen glow effect. +class PointShader : public QObject { + Q_OBJECT + +public: + PointShader(); + ~PointShader(); + + void init(); + + /// Starts using the voxel geometry shader effect. + void begin(); + + /// Stops using the voxel geometry shader effect. + void end(); + + /// Gets access to attributes from the shader program + int attributeLocation(const char * name) const; + int uniformLocation(const char * name) const; + void setUniformValue(int attributeLocation, float value); + + static ProgramObject* createPointShaderProgram(const QString& name); + +public slots: + +private: + + bool _initialized; + + ProgramObject* _program; +}; + +#endif /* defined(__interface__PointShader__) */ From f5d09c0218645fe9767281b2a610c5ebe74815b3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Nov 2013 14:36:20 -0700 Subject: [PATCH 02/13] fix comments and style --- interface/src/renderer/PointShader.h | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/interface/src/renderer/PointShader.h b/interface/src/renderer/PointShader.h index f5ef54af5e..b707de39ff 100644 --- a/interface/src/renderer/PointShader.h +++ b/interface/src/renderer/PointShader.h @@ -13,7 +13,7 @@ class ProgramObject; -/// A generic full screen glow effect. +/// A shader program that draws voxels as points with variable sizes class PointShader : public QObject { Q_OBJECT @@ -23,25 +23,21 @@ public: void init(); - /// Starts using the voxel geometry shader effect. + /// Starts using the voxel point shader program. void begin(); - /// Stops using the voxel geometry shader effect. + /// Stops using the voxel point shader program. void end(); /// Gets access to attributes from the shader program - int attributeLocation(const char * name) const; - int uniformLocation(const char * name) const; + int attributeLocation(const char* name) const; + int uniformLocation(const char* name) const; void setUniformValue(int attributeLocation, float value); static ProgramObject* createPointShaderProgram(const QString& name); -public slots: - private: - bool _initialized; - ProgramObject* _program; }; From 6fd3c9714f07747199ea8f7f9fa269f0745bee72 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Nov 2013 14:37:46 -0700 Subject: [PATCH 03/13] fixed header file merge conflict --- interface/src/Application.h | 1 + interface/src/Menu.cpp | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.h b/interface/src/Application.h index 226756ab0f..4154720419 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -61,6 +61,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 ac207e8812..a1f83007fd 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -29,7 +29,6 @@ #include "Menu.h" #include "Util.h" #include "InfoView.h" -#include "ui/LodToolsDialog.h" Menu* Menu::_instance = NULL; From 56aafabacd8c036b0825dab0653a31847182ebfc Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Nov 2013 14:39:55 -0700 Subject: [PATCH 04/13] fixed up comments and style guide items --- interface/src/renderer/PointShader.cpp | 6 +++--- interface/src/renderer/PointShader.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/renderer/PointShader.cpp b/interface/src/renderer/PointShader.cpp index 8ebccc8d08..1c2de3ecc3 100644 --- a/interface/src/renderer/PointShader.cpp +++ b/interface/src/renderer/PointShader.cpp @@ -2,7 +2,7 @@ // PointShader.cpp // interface // -// Created by Brad Hefta-Gaub on 9/22/13. +// Created by Brad Hefta-Gaub on 10/30/13. // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL @@ -52,7 +52,7 @@ void PointShader::end() { _program->release(); } -int PointShader::attributeLocation(const char * name) const { +int PointShader::attributeLocation(const char* name) const { if (_program) { return _program->attributeLocation(name); } else { @@ -60,7 +60,7 @@ int PointShader::attributeLocation(const char * name) const { } } -int PointShader::uniformLocation(const char * name) const { +int PointShader::uniformLocation(const char* name) const { if (_program) { return _program->uniformLocation(name); } else { diff --git a/interface/src/renderer/PointShader.h b/interface/src/renderer/PointShader.h index b707de39ff..34bc0e55db 100644 --- a/interface/src/renderer/PointShader.h +++ b/interface/src/renderer/PointShader.h @@ -2,7 +2,7 @@ // PointShader.h // interface // -// Created by Brad Hefta-Gaub on 9/23/13. +// Created by Brad Hefta-Gaub on 10/30/13. // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // From 13b558c0339aef9f95c8a7dbbaaab38ebb3d52c3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Nov 2013 14:40:58 -0700 Subject: [PATCH 05/13] removed dead code --- interface/src/VoxelSystem.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 5c836eb3e2..2443d73415 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -1276,7 +1276,6 @@ void VoxelSystem::render(bool texture) { Application::getInstance()->getPointShader().setUniformValue(uniformLocation, viewportHeight); attributeLocation = Application::getInstance()->getVoxelShader().attributeLocation("voxelSizeIn"); - //printf("attributeLocation=%d\n", attributeLocation); glEnableVertexAttribArray(attributeLocation); glVertexAttribPointer(attributeLocation, 1, GL_FLOAT, false, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(3*sizeof(float))); } From cab87c3a97fcd12295d8d7a528fc84cd0635d0e1 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Nov 2013 15:27:25 -0700 Subject: [PATCH 06/13] added comment about fixing point selection --- interface/resources/shaders/point_size.vert | 23 +++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/interface/resources/shaders/point_size.vert b/interface/resources/shaders/point_size.vert index 98da0b85d6..19240c3104 100644 --- a/interface/resources/shaders/point_size.vert +++ b/interface/resources/shaders/point_size.vert @@ -10,14 +10,33 @@ void main(void) { vec4 cornerOriginal = gl_Vertex; vec4 corner = gl_ModelViewProjectionMatrix * gl_Vertex; + // I'm currently using the distance between the near bottom left corner and the far top right corner. That's not + // idea for all possible angles of viewing of the voxel. I really should be using a lookup table to determine which + // corners to be using. The effect with this approach is that some "projections" are smaller than they should be, and + // we get a thinning effect. + // + // However, this may not matter when we actually switch to using cubes and points in concert. vec4 farCornerVertex = gl_Vertex; farCornerVertex[0] += voxelSizeIn; farCornerVertex[1] += voxelSizeIn; farCornerVertex[2] += voxelSizeIn; vec4 farCorner = gl_ModelViewProjectionMatrix * farCornerVertex; + + // math! If the w result is negative then the point is behind the viewer + vec2 cornerOnScreen = vec2(corner.x / corner.w, corner.y / corner.w); + if (corner.w < 0) { + cornerOnScreen.x = -cornerOnScreen.x; + cornerOnScreen.y = -cornerOnScreen.y; + } - float voxelScreenWidth = abs((farCorner.x / farCorner.w) - (corner.x / corner.w)) * viewportWidth / 2.0; - float voxelScreenHeight = abs((farCorner.y / farCorner.w) - (corner.y / corner.w)) * viewportHeight / 2.0; + vec2 farCornerOnScreen = vec2(farCorner.x / farCorner.w, farCorner.y / farCorner.w); + if (farCorner.w < 0) { + farCornerOnScreen.x = -farCornerOnScreen.x; + farCornerOnScreen.y = -farCornerOnScreen.y; + } + + float voxelScreenWidth = abs(farCornerOnScreen.x - cornerOnScreen.x) * viewportWidth / 2.0; + float voxelScreenHeight = abs(farCornerOnScreen.y - cornerOnScreen.y) * viewportHeight / 2.0; float voxelScreenLength = sqrt(voxelScreenHeight * voxelScreenHeight + voxelScreenWidth * voxelScreenWidth); vec4 centerVertex = gl_Vertex; From 61b6d6a4a4316548bf36e0b328c1088c3d7e5f94 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Nov 2013 15:27:57 -0700 Subject: [PATCH 07/13] added comment about fixing point selection --- interface/resources/shaders/point_size.vert | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/shaders/point_size.vert b/interface/resources/shaders/point_size.vert index 19240c3104..a4a89d094b 100644 --- a/interface/resources/shaders/point_size.vert +++ b/interface/resources/shaders/point_size.vert @@ -11,7 +11,7 @@ void main(void) { vec4 corner = gl_ModelViewProjectionMatrix * gl_Vertex; // I'm currently using the distance between the near bottom left corner and the far top right corner. That's not - // idea for all possible angles of viewing of the voxel. I really should be using a lookup table to determine which + // ideal for all possible angles of viewing of the voxel. I really should be using a lookup table to determine which // corners to be using. The effect with this approach is that some "projections" are smaller than they should be, and // we get a thinning effect. // From e62322b8054989160c57993a0beb3c17f35711b4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Nov 2013 15:28:54 -0700 Subject: [PATCH 08/13] clean up comment --- interface/resources/shaders/point_size.vert | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/interface/resources/shaders/point_size.vert b/interface/resources/shaders/point_size.vert index a4a89d094b..ae4ef3e2cf 100644 --- a/interface/resources/shaders/point_size.vert +++ b/interface/resources/shaders/point_size.vert @@ -12,10 +12,11 @@ void main(void) { // I'm currently using the distance between the near bottom left corner and the far top right corner. That's not // ideal for all possible angles of viewing of the voxel. I really should be using a lookup table to determine which - // corners to be using. The effect with this approach is that some "projections" are smaller than they should be, and - // we get a thinning effect. + // corners to use. // - // However, this may not matter when we actually switch to using cubes and points in concert. + // The effect with the current approach is that some "projections" are smaller than they should be, and we get a + // thinning effect. However, this may not matter when we actually switch to using cubes and points in concert. + vec4 farCornerVertex = gl_Vertex; farCornerVertex[0] += voxelSizeIn; farCornerVertex[1] += voxelSizeIn; From b103f9dacf31fd4bad6bdb64f3d9cdcdfd8033c8 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Nov 2013 15:32:17 -0700 Subject: [PATCH 09/13] clean up --- interface/resources/shaders/point_size.vert | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/interface/resources/shaders/point_size.vert b/interface/resources/shaders/point_size.vert index ae4ef3e2cf..e8fd812694 100644 --- a/interface/resources/shaders/point_size.vert +++ b/interface/resources/shaders/point_size.vert @@ -18,9 +18,7 @@ void main(void) { // thinning effect. However, this may not matter when we actually switch to using cubes and points in concert. vec4 farCornerVertex = gl_Vertex; - farCornerVertex[0] += voxelSizeIn; - farCornerVertex[1] += voxelSizeIn; - farCornerVertex[2] += voxelSizeIn; + farCornerVertex += vec4(voxelSizeIn, voxelSizeIn, voxelSizeIn, 0.0); vec4 farCorner = gl_ModelViewProjectionMatrix * farCornerVertex; // math! If the w result is negative then the point is behind the viewer @@ -42,9 +40,7 @@ void main(void) { vec4 centerVertex = gl_Vertex; float halfSizeIn = voxelSizeIn / 2; - centerVertex[0] += halfSizeIn; - centerVertex[1] += halfSizeIn; - centerVertex[2] += halfSizeIn; + centerVertex += vec4(halfSizeIn, halfSizeIn, halfSizeIn, 0.0); vec4 center = gl_ModelViewProjectionMatrix * centerVertex; gl_Position = center; From 508b8f46780ae8130654af5993efef91435876b5 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Nov 2013 16:29:49 -0700 Subject: [PATCH 10/13] change in comment to kick off build --- interface/resources/shaders/point_size.vert | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/resources/shaders/point_size.vert b/interface/resources/shaders/point_size.vert index e8fd812694..06146cdf88 100644 --- a/interface/resources/shaders/point_size.vert +++ b/interface/resources/shaders/point_size.vert @@ -16,6 +16,7 @@ void main(void) { // // The effect with the current approach is that some "projections" are smaller than they should be, and we get a // thinning effect. However, this may not matter when we actually switch to using cubes and points in concert. + // vec4 farCornerVertex = gl_Vertex; farCornerVertex += vec4(voxelSizeIn, voxelSizeIn, voxelSizeIn, 0.0); From c4a2b3c49b73137967e6554315361deeeee398fa Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 3 Nov 2013 11:10:00 -0800 Subject: [PATCH 11/13] fix thinning in voxels as points by using correct points to calculate width of voxel based on camera position relative to voxel --- interface/resources/shaders/point_size.vert | 165 +++++++++++++++++--- interface/src/VoxelSystem.cpp | 14 +- interface/src/renderer/PointShader.cpp | 8 +- interface/src/renderer/PointShader.h | 3 +- 4 files changed, 155 insertions(+), 35 deletions(-) diff --git a/interface/resources/shaders/point_size.vert b/interface/resources/shaders/point_size.vert index 06146cdf88..9c93385768 100644 --- a/interface/resources/shaders/point_size.vert +++ b/interface/resources/shaders/point_size.vert @@ -2,48 +2,163 @@ attribute float voxelSizeIn; varying float voxelSize; + uniform float viewportWidth; uniform float viewportHeight; +uniform vec3 cameraPosition; + +// Bit codes for faces +const int NONE = 0; +const int RIGHT = 1; +const int LEFT = 2; +const int BOTTOM = 4; +const int BOTTOM_RIGHT = BOTTOM + RIGHT; +const int BOTTOM_LEFT = BOTTOM + LEFT; +const int TOP = 8; +const int TOP_RIGHT = TOP + RIGHT; +const int TOP_LEFT = TOP + LEFT; +const int NEAR = 16; +const int NEAR_RIGHT = NEAR + RIGHT; +const int NEAR_LEFT = NEAR + LEFT; +const int NEAR_BOTTOM = NEAR + BOTTOM; +const int NEAR_BOTTOM_RIGHT = NEAR + BOTTOM + RIGHT; +const int NEAR_BOTTOM_LEFT = NEAR + BOTTOM + LEFT; +const int NEAR_TOP = NEAR + TOP; +const int NEAR_TOP_RIGHT = NEAR + TOP + RIGHT; +const int NEAR_TOP_LEFT = NEAR + TOP + LEFT; +const int FAR = 32; +const int FAR_RIGHT = FAR + RIGHT; +const int FAR_LEFT = FAR + LEFT; +const int FAR_BOTTOM = FAR + BOTTOM; +const int FAR_BOTTOM_RIGHT = FAR + BOTTOM + RIGHT; +const int FAR_BOTTOM_LEFT = FAR + BOTTOM + LEFT; +const int FAR_TOP = FAR + TOP; +const int FAR_TOP_RIGHT = FAR + TOP + RIGHT; +const int FAR_TOP_LEFT = FAR + TOP + LEFT; + +// If we know the position of the camera relative to the voxel, we can a priori know the vertices that make the visible hull +// polygon. This also tells us which two vertices are known to make the longest possible distance between any pair of these +// vertices for the projected polygon. This is a visibleFaces table based on this knowledge. void main(void) { - gl_FrontColor = gl_Color; - vec4 cornerOriginal = gl_Vertex; - vec4 corner = gl_ModelViewProjectionMatrix * gl_Vertex; + // Note: the gl_Vertex in this case are in "world coordinates" meaning they've already been scaled to TREE_SCALE + // this is also true for voxelSizeIn. + vec4 bottomNearRight = gl_Vertex; + vec4 topFarLeft = (gl_Vertex + vec4(voxelSizeIn, voxelSizeIn, voxelSizeIn, 0.0)); - // I'm currently using the distance between the near bottom left corner and the far top right corner. That's not - // ideal for all possible angles of viewing of the voxel. I really should be using a lookup table to determine which - // corners to use. - // - // The effect with the current approach is that some "projections" are smaller than they should be, and we get a - // thinning effect. However, this may not matter when we actually switch to using cubes and points in concert. - // + int visibleFaces = NONE; + + // In order to use our visibleFaces "table" (implemented as if statements) below, we need to encode the 6-bit code to + // orient camera relative to the 6 defining faces of the voxel. Based on camera position relative to the bottomNearRight + // corner and the topFarLeft corner, we can calculate which hull and therefore which two vertices are furthest apart + // linearly once projected + if (cameraPosition.x < bottomNearRight.x) { + visibleFaces += RIGHT; + } + if (cameraPosition.x > topFarLeft.x) { + visibleFaces += LEFT; + } + if (cameraPosition.y < bottomNearRight.y) { + visibleFaces += BOTTOM; + } + if (cameraPosition.y > topFarLeft.y) { + visibleFaces += TOP; + } + if (cameraPosition.z < bottomNearRight.z) { + visibleFaces += NEAR; + } + if (cameraPosition.z > topFarLeft.z) { + visibleFaces += FAR; + } - vec4 farCornerVertex = gl_Vertex; - farCornerVertex += vec4(voxelSizeIn, voxelSizeIn, voxelSizeIn, 0.0); - vec4 farCorner = gl_ModelViewProjectionMatrix * farCornerVertex; + vec4 cornerAdjustOne; + vec4 cornerAdjustTwo; - // math! If the w result is negative then the point is behind the viewer - vec2 cornerOnScreen = vec2(corner.x / corner.w, corner.y / corner.w); - if (corner.w < 0) { - cornerOnScreen.x = -cornerOnScreen.x; - cornerOnScreen.y = -cornerOnScreen.y; + if (visibleFaces == RIGHT) { + cornerAdjustOne = vec4(0,0,0,0) * voxelSizeIn; + cornerAdjustTwo = vec4(0,1,1,0) * voxelSizeIn; + } else if (visibleFaces == LEFT) { + cornerAdjustOne = vec4(1,0,0,0) * voxelSizeIn; + cornerAdjustTwo = vec4(1,1,1,0) * voxelSizeIn; + } else if (visibleFaces == BOTTOM) { + cornerAdjustOne = vec4(0,0,0,0) * voxelSizeIn; + cornerAdjustTwo = vec4(1,0,1,0) * voxelSizeIn; + } else if (visibleFaces == TOP) { + cornerAdjustOne = vec4(0,1,0,0) * voxelSizeIn; + cornerAdjustTwo = vec4(1,1,1,0) * voxelSizeIn; + } else if (visibleFaces == NEAR) { + cornerAdjustOne = vec4(0,0,0,0) * voxelSizeIn; + cornerAdjustTwo = vec4(1,1,0,0) * voxelSizeIn; + } else if (visibleFaces == FAR) { + cornerAdjustOne = vec4(0,0,1,0) * voxelSizeIn; + cornerAdjustTwo = vec4(1,1,1,0) * voxelSizeIn; + } else if (visibleFaces == NEAR_BOTTOM_LEFT || + visibleFaces == FAR_TOP || + visibleFaces == FAR_TOP_RIGHT) { + cornerAdjustOne = vec4(0,1,0,0) * voxelSizeIn; + cornerAdjustTwo = vec4(1,0,1,0) * voxelSizeIn; + } else if (visibleFaces == FAR_TOP_LEFT || + visibleFaces == NEAR_RIGHT || + visibleFaces == NEAR_BOTTOM || + visibleFaces == NEAR_BOTTOM_RIGHT) { + cornerAdjustOne = vec4(0,0,1,0) * voxelSizeIn; + cornerAdjustTwo = vec4(1,1,0,0) * voxelSizeIn; + } else if (visibleFaces == NEAR_TOP_RIGHT || + visibleFaces == FAR_LEFT || + visibleFaces == FAR_BOTTOM_LEFT || + visibleFaces == BOTTOM_RIGHT || + visibleFaces == TOP_LEFT) { + cornerAdjustOne = vec4(1,0,0,0) * voxelSizeIn; + cornerAdjustTwo = vec4(0,1,1,0) * voxelSizeIn; + + // Everything else... + //} else if (visibleFaces == BOTTOM_LEFT || + // visibleFaces == TOP_RIGHT || + // visibleFaces == NEAR_LEFT || + // visibleFaces == FAR_RIGHT || + // visibleFaces == NEAR_TOP || + // visibleFaces == NEAR_TOP_LEFT || + // visibleFaces == FAR_BOTTOM || + // visibleFaces == FAR_BOTTOM_RIGHT) { + } else { + cornerAdjustOne = vec4(0,0,0,0) * voxelSizeIn; + cornerAdjustTwo = vec4(1,1,1,0) * voxelSizeIn; } - vec2 farCornerOnScreen = vec2(farCorner.x / farCorner.w, farCorner.y / farCorner.w); - if (farCorner.w < 0) { - farCornerOnScreen.x = -farCornerOnScreen.x; - farCornerOnScreen.y = -farCornerOnScreen.y; + // Determine our corners + vec4 cornerOne = gl_Vertex + cornerAdjustOne; + vec4 cornerTwo = gl_Vertex + cornerAdjustTwo; + + // Find their model view projections + vec4 cornerOneMVP = gl_ModelViewProjectionMatrix * cornerOne; + vec4 cornerTwoMVP = gl_ModelViewProjectionMatrix * cornerTwo; + + // Map to x, y screen coordinates + vec2 cornerOneScreen = vec2(cornerOneMVP.x / cornerOneMVP.w, cornerOneMVP.y / cornerOneMVP.w); + if (cornerOneMVP.w < 0) { + cornerOneScreen.x = -cornerOneScreen.x; + cornerOneScreen.y = -cornerOneScreen.y; } - float voxelScreenWidth = abs(farCornerOnScreen.x - cornerOnScreen.x) * viewportWidth / 2.0; - float voxelScreenHeight = abs(farCornerOnScreen.y - cornerOnScreen.y) * viewportHeight / 2.0; + vec2 cornerTwoScreen = vec2(cornerTwoMVP.x / cornerTwoMVP.w, cornerTwoMVP.y / cornerTwoMVP.w); + if (cornerTwoMVP.w < 0) { + cornerTwoScreen.x = -cornerTwoScreen.x; + cornerTwoScreen.y = -cornerTwoScreen.y; + } + + // Find the distance between them in pixels + float voxelScreenWidth = abs(cornerOneScreen.x - cornerTwoScreen.x) * viewportWidth / 2.0; + float voxelScreenHeight = abs(cornerOneScreen.y - cornerTwoScreen.y) * viewportHeight / 2.0; float voxelScreenLength = sqrt(voxelScreenHeight * voxelScreenHeight + voxelScreenWidth * voxelScreenWidth); + // Find the center of the voxel vec4 centerVertex = gl_Vertex; float halfSizeIn = voxelSizeIn / 2; centerVertex += vec4(halfSizeIn, halfSizeIn, halfSizeIn, 0.0); vec4 center = gl_ModelViewProjectionMatrix * centerVertex; - + + // Finally place the point at the center of the voxel, with a size equal to the maximum screen length gl_Position = center; gl_PointSize = voxelScreenLength; + gl_FrontColor = gl_Color; } \ No newline at end of file diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 2443d73415..541d7983d2 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -1266,16 +1266,16 @@ void VoxelSystem::render(bool texture) { glm::vec2 viewDimensions = Application::getInstance()->getViewportDimensions(); float viewportWidth = viewDimensions.x; float viewportHeight = viewDimensions.y; + glm::vec3 cameraPosition = Application::getInstance()->getViewFrustum()->getPosition(); + PointShader& pointShader = Application::getInstance()->getPointShader(); - Application::getInstance()->getPointShader().begin(); + pointShader.begin(); - int uniformLocation = Application::getInstance()->getPointShader().uniformLocation("viewportWidth"); - Application::getInstance()->getPointShader().setUniformValue(uniformLocation, viewportWidth); + pointShader.setUniformValue(pointShader.uniformLocation("viewportWidth"), viewportWidth); + pointShader.setUniformValue(pointShader.uniformLocation("viewportHeight"), viewportHeight); + pointShader.setUniformValue(pointShader.uniformLocation("cameraPosition"), cameraPosition); - uniformLocation = Application::getInstance()->getPointShader().uniformLocation("viewportHeight"); - Application::getInstance()->getPointShader().setUniformValue(uniformLocation, viewportHeight); - - attributeLocation = Application::getInstance()->getVoxelShader().attributeLocation("voxelSizeIn"); + attributeLocation = pointShader.attributeLocation("voxelSizeIn"); glEnableVertexAttribArray(attributeLocation); glVertexAttribPointer(attributeLocation, 1, GL_FLOAT, false, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(3*sizeof(float))); } diff --git a/interface/src/renderer/PointShader.cpp b/interface/src/renderer/PointShader.cpp index 1c2de3ecc3..32139903be 100644 --- a/interface/src/renderer/PointShader.cpp +++ b/interface/src/renderer/PointShader.cpp @@ -68,6 +68,10 @@ int PointShader::uniformLocation(const char* name) const { } } -void PointShader::setUniformValue(int attributeLocation, float value) { - _program->setUniformValue(attributeLocation, value); +void PointShader::setUniformValue(int uniformLocation, float value) { + _program->setUniformValue(uniformLocation, value); +} + +void PointShader::setUniformValue(int uniformLocation, const glm::vec3& value) { + _program->setUniformValue(uniformLocation, value.x, value.y, value.z); } diff --git a/interface/src/renderer/PointShader.h b/interface/src/renderer/PointShader.h index 34bc0e55db..b7e1b8c008 100644 --- a/interface/src/renderer/PointShader.h +++ b/interface/src/renderer/PointShader.h @@ -32,7 +32,8 @@ public: /// Gets access to attributes from the shader program int attributeLocation(const char* name) const; int uniformLocation(const char* name) const; - void setUniformValue(int attributeLocation, float value); + void setUniformValue(int uniformLocation, float value); + void setUniformValue(int uniformLocation, const glm::vec3& value); static ProgramObject* createPointShaderProgram(const QString& name); From c18de72dd4103e63d3b1e033cb27ecfcf43c751f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 3 Nov 2013 19:06:06 -0800 Subject: [PATCH 12/13] work on debugging stutter behavior, mostly debugging and cleanup --- interface/src/Application.cpp | 259 ++++++++++++++---- interface/src/Application.h | 26 +- interface/src/VoxelPacketProcessor.cpp | 2 +- interface/src/VoxelSystem.cpp | 5 +- .../shared/src/ReceivedPacketProcessor.h | 12 +- 5 files changed, 236 insertions(+), 68 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 82fccf7d6d..30548d19cc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -144,6 +144,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _packetsPerSecond(0), _bytesPerSecond(0), _bytesCount(0), + _recentMaxPackets(0), + _resetRecentMaxPacketsSoon(true), _swatch(NULL), _pasteMode(false) { @@ -1314,22 +1316,30 @@ void Application::idle() { double timeSinceLastUpdate = diffclock(&_lastTimeUpdated, &check); if (timeSinceLastUpdate > IDLE_SIMULATE_MSECS) { - - const float BIGGEST_DELTA_TIME_SECS = 0.25f; - update(glm::clamp((float)timeSinceLastUpdate / 1000.f, 0.f, BIGGEST_DELTA_TIME_SECS)); - _glWidget->updateGL(); - _lastTimeUpdated = check; - _idleLoopStdev.addValue(timeSinceLastUpdate); - - // Record standard deviation and reset counter if needed - const int STDEV_SAMPLES = 500; - if (_idleLoopStdev.getSamples() > STDEV_SAMPLES) { - _idleLoopMeasuredJitter = _idleLoopStdev.getStDev(); - _idleLoopStdev.reset(); + { + PerformanceWarning warn(showWarnings, "Application::idle()... update()"); + const float BIGGEST_DELTA_TIME_SECS = 0.25f; + update(glm::clamp((float)timeSinceLastUpdate / 1000.f, 0.f, BIGGEST_DELTA_TIME_SECS)); } + { + PerformanceWarning warn(showWarnings, "Application::idle()... updateGL()"); + _glWidget->updateGL(); + } + { + PerformanceWarning warn(showWarnings, "Application::idle()... rest of it"); + _lastTimeUpdated = check; + _idleLoopStdev.addValue(timeSinceLastUpdate); + + // Record standard deviation and reset counter if needed + const int STDEV_SAMPLES = 500; + if (_idleLoopStdev.getSamples() > STDEV_SAMPLES) { + _idleLoopMeasuredJitter = _idleLoopStdev.getStDev(); + _idleLoopStdev.reset(); + } - // After finishing all of the above work, restart the idle timer, allowing 2ms to process events. - idleTimer->start(2); + // After finishing all of the above work, restart the idle timer, allowing 2ms to process events. + idleTimer->start(2); + } } } void Application::terminate() { @@ -1776,6 +1786,8 @@ static QUuid DEFAULT_NODE_ID_REF; void Application::updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection, glm::vec3& eyePosition) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateLookatTargetAvatar()"); _lookatTargetAvatar = findLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, eyePosition, DEFAULT_NODE_ID_REF); } @@ -1907,17 +1919,13 @@ void Application::updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm:: } } -void Application::update(float deltaTime) { +void Application::updateMouseRay(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showWarnings, "Application::update()"); - - // tell my avatar if the mouse is being pressed... - _myAvatar.setMousePressed(_mousePressed); - - // check what's under the mouse and update the mouse voxel - glm::vec3 mouseRayOrigin, mouseRayDirection; - _viewFrustum.computePickRay(_mouseX / (float)_glWidget->width(), - _mouseY / (float)_glWidget->height(), mouseRayOrigin, mouseRayDirection); + PerformanceWarning warn(showWarnings, "Application::updateMouseRay()"); + + _viewFrustum.computePickRay(_mouseX / (float)_glWidget->width(), _mouseY / (float)_glWidget->height(), + mouseRayOrigin, mouseRayDirection); // adjust for mirroring if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { @@ -1928,12 +1936,19 @@ void Application::update(float deltaTime) { _viewFrustum.getRight() * glm::dot(_viewFrustum.getRight(), mouseRayDirection)); } + // tell my avatar if the mouse is being pressed... + _myAvatar.setMousePressed(_mousePressed); + // tell my avatar the posiion and direction of the ray projected ino the world based on the mouse position _myAvatar.setMouseRay(mouseRayOrigin, mouseRayDirection); - - // Set where I am looking based on my mouse ray (so that other people can see) - glm::vec3 lookAtSpot; +} +void Application::updateFaceshift(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection, + glm::vec3& lookAtRayOrigin, glm::vec3& lookAtRayDirection) { + + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateFaceshift()"); + // Update faceshift _faceshift.update(); @@ -1943,14 +1958,19 @@ void Application::update(float deltaTime) { } // if we have faceshift, use that to compute the lookat direction - glm::vec3 lookAtRayOrigin = mouseRayOrigin, lookAtRayDirection = mouseRayDirection; if (_faceshift.isActive()) { lookAtRayOrigin = _myAvatar.getHead().calculateAverageEyePosition(); lookAtRayDirection = _myAvatar.getHead().getOrientation() * glm::quat(glm::radians(glm::vec3( _faceshift.getEstimatedEyePitch(), _faceshift.getEstimatedEyeYaw(), 0.0f))) * glm::vec3(0.0f, 0.0f, -1.0f); } +} - updateLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, lookAtSpot); +void Application::updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot, glm::vec3& lookAtRayOrigin, + glm::vec3& lookAtRayDirection) { + + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateMyAvatarLookAtPosition()"); + if (_lookatTargetAvatar && !_faceshift.isActive()) { // If the mouse is over another avatar's head... _myAvatar.getHead().setLookAtPosition(lookAtSpot); @@ -1969,11 +1989,14 @@ void Application::update(float deltaTime) { lookAtSpot = lookAtRayOrigin + lookAtRayDirection * FAR_AWAY_STARE; _myAvatar.getHead().setLookAtPosition(lookAtSpot); } +} - // Find the voxel we are hovering over, and respond if clicked - float distance; - BoxFace face; - +void Application::updateHoverVoxels(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection, + float& distance, BoxFace& face) { + + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels()"); + // If we have clicked on a voxel, update it's color if (_isHoverVoxelSounding) { VoxelNode* hoveredNode = _voxels.getVoxelAt(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s); @@ -2005,13 +2028,19 @@ void Application::update(float deltaTime) { _isHoverVoxelSounding = true; } } - +} + +void Application::updateMouseVoxels(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection, + float& distance, BoxFace& face) { + + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateMouseVoxels()"); + _mouseVoxel.s = 0.0f; if (Menu::getInstance()->isVoxelModeActionChecked() && (fabs(_myAvatar.getVelocity().x) + fabs(_myAvatar.getVelocity().y) + fabs(_myAvatar.getVelocity().z)) / 3 < MAX_AVATAR_EDIT_VELOCITY) { - PerformanceWarning warn(showWarnings, "Application::update()... findRayIntersection()"); if (_voxels.findRayIntersection(mouseRayOrigin, mouseRayDirection, _mouseVoxel, distance, face)) { if (distance < MAX_VOXEL_EDIT_DISTANCE) { @@ -2080,12 +2109,17 @@ void Application::update(float deltaTime) { _justEditedVoxel = false; } } - +} + +void Application::updateHandAndTouch(float deltaTime) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateHandAndTouch()"); + // walking triggers the handControl to stop if (_myAvatar.getMode() == AVATAR_MODE_WALKING) { _handControl.stop(); } - + // Update from Touch if (_isTouchPressed) { float TOUCH_YAW_SCALE = -0.25f; @@ -2096,19 +2130,29 @@ void Application::update(float deltaTime) { _lastTouchAvgX = _touchAvgX; _lastTouchAvgY = _touchAvgY; } - - // Leap finger-sensing device +} + +void Application::updateLeap(float deltaTime) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateLeap()"); + LeapManager::enableFakeFingers(Menu::getInstance()->isOptionChecked(MenuOption::SimulateLeapHand)); _myAvatar.getHand().setRaveGloveActive(Menu::getInstance()->isOptionChecked(MenuOption::TestRaveGlove)); LeapManager::nextFrame(_myAvatar); - - // Read serial port interface devices +} + +void Application::updateSerialDevices(float deltaTime) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateSerialDevices()"); + if (_serialHeadSensor.isActive()) { _serialHeadSensor.readData(deltaTime); } - - // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes - updateAvatar(deltaTime); +} + +void Application::updateThreads(float deltaTime) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateThreads()"); // read incoming packets from network if (!_enableNetworkThread) { @@ -2120,12 +2164,12 @@ void Application::update(float deltaTime) { _voxelProcessor.threadRoutine(); _voxelEditSender.threadRoutine(); } +} + +void Application::updateMyAvatarSimulation(float deltaTime) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateMyAvatarSimulation()"); - - //loop through all the other avatars and simulate them... - updateAvatars(deltaTime, mouseRayOrigin, mouseRayDirection); - - // Simulate myself if (Menu::getInstance()->isOptionChecked(MenuOption::Gravity)) { _myAvatar.setGravity(_environment.getGravity(_myAvatar.getPosition())); } @@ -2138,12 +2182,21 @@ void Application::update(float deltaTime) { } else { _myAvatar.simulate(deltaTime, NULL); } - - // Simulate particle cloud movements +} + +void Application::updateParticles(float deltaTime) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateParticles()"); + if (Menu::getInstance()->isOptionChecked(MenuOption::ParticleCloud)) { _cloud.simulate(deltaTime); } - +} + +void Application::updateTransmitter(float deltaTime) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateTransmitter()"); + // no transmitter drive implies transmitter pick if (!Menu::getInstance()->isOptionChecked(MenuOption::TransmitterDrive) && _myTransmitter.isConnected()) { _transmitterPickStart = _myAvatar.getSkeleton().joint[AVATAR_JOINT_CHEST].position; @@ -2178,7 +2231,12 @@ void Application::update(float deltaTime) { } else { _transmitterPickStart = _transmitterPickEnd = glm::vec3(); } - +} + +void Application::updateCamera(float deltaTime) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateCamera()"); + if (!OculusManager::isConnected()) { if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) { if (_myCamera.getMode() != CAMERA_MODE_MIRROR) { @@ -2213,7 +2271,12 @@ void Application::update(float deltaTime) { } } } - +} + +void Application::updateDialogs(float deltaTime) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateDialogs()"); + // Update bandwidth dialog, if any BandwidthDialog* bandwidthDialog = Menu::getInstance()->getBandwidthDialog(); if (bandwidthDialog) { @@ -2224,6 +2287,11 @@ void Application::update(float deltaTime) { if (voxelStatsDialog) { voxelStatsDialog->update(); } +} + +void Application::updateAudio(float deltaTime) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateAudio()"); // Update audio stats for procedural sounds #ifndef _WIN32 @@ -2231,7 +2299,12 @@ void Application::update(float deltaTime) { _audio.setLastVelocity(_myAvatar.getVelocity()); _audio.eventuallyAnalyzePing(); #endif - +} + +void Application::updateCursor(float deltaTime) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateCursor()"); + // watch mouse position, if it hasn't moved, hide the cursor bool underMouse = _glWidget->underMouse(); if (!_mouseHidden) { @@ -2252,6 +2325,43 @@ void Application::update(float deltaTime) { } } +void Application::update(float deltaTime) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::update()"); + + // check what's under the mouse and update the mouse voxel + glm::vec3 mouseRayOrigin, mouseRayDirection; + updateMouseRay(deltaTime, mouseRayOrigin, mouseRayDirection); + + // Set where I am looking based on my mouse ray (so that other people can see) + glm::vec3 lookAtSpot; + glm::vec3 lookAtRayOrigin = mouseRayOrigin, lookAtRayDirection = mouseRayDirection; + + updateFaceshift(deltaTime, mouseRayOrigin, mouseRayDirection, lookAtRayOrigin, lookAtRayDirection); + updateLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, lookAtSpot); + updateMyAvatarLookAtPosition(lookAtSpot, lookAtRayOrigin, lookAtRayDirection); + + // Find the voxel we are hovering over, and respond if clicked + float distance; + BoxFace face; + + updateHoverVoxels(deltaTime, mouseRayOrigin, mouseRayDirection, distance, face); // clicking on voxels and making sounds + updateMouseVoxels(deltaTime, mouseRayOrigin, mouseRayDirection, distance, face); // UI/UX related to voxels + updateHandAndTouch(deltaTime); // Update state for touch sensors + updateLeap(deltaTime); // Leap finger-sensing device + updateSerialDevices(deltaTime); // Read serial port interface devices + updateAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes + updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... + updateAvatars(deltaTime, mouseRayOrigin, mouseRayDirection); //loop through all the other avatars and simulate them... + updateMyAvatarSimulation(deltaTime); // Simulate myself + updateParticles(deltaTime); // Simulate particle cloud movements + updateTransmitter(deltaTime); // transmitter drive or pick + updateCamera(deltaTime); // handle various camera tweaks like off axis projection + updateDialogs(deltaTime); // update various stats dialogs if present + updateAudio(deltaTime); // Update audio stats for procedural sounds + updateCursor(deltaTime); // Handle cursor updates +} + void Application::updateAvatar(float deltaTime) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateAvatar()"); @@ -3258,6 +3368,8 @@ void Application::displayStats() { drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, avatarStats); + QLocale locale(QLocale::English); + std::stringstream voxelStats; voxelStats.precision(4); voxelStats << "Voxels " << @@ -3280,11 +3392,19 @@ void Application::displayStats() { statsVerticalOffset += PELS_PER_LINE; drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str()); + unsigned long localTotal = VoxelNode::getNodeCount(); + unsigned long localInternal = VoxelNode::getInternalNodeCount(); + unsigned long localLeaves = VoxelNode::getLeafNodeCount(); + QString localTotalString = locale.toString((uint)localTotal); // consider adding: .rightJustified(10, ' '); + QString localInternalString = locale.toString((uint)localInternal); + QString localLeavesString = locale.toString((uint)localLeaves); + + voxelStats.str(""); voxelStats << - "Local Voxels Total: " << VoxelNode::getNodeCount() << ", " << - "Internal: " << VoxelNode::getInternalNodeCount() << " , " << - "Leaves: " << VoxelNode::getLeafNodeCount() << ""; + "Local Voxels Total: " << localTotalString.toLocal8Bit().constData() << " / " << + "Internal: " << localInternalString.toLocal8Bit().constData() << " / " << + "Leaves: " << localLeavesString.toLocal8Bit().constData() << ""; statsVerticalOffset += PELS_PER_LINE; drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str()); @@ -3311,6 +3431,29 @@ void Application::displayStats() { voxelStats << "Sending Mode: " << voxelDetails; statsVerticalOffset += PELS_PER_LINE; drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str()); + + voxelStats.str(""); + int voxelPacketsToProcess = _voxelProcessor.packetsToProcessCount(); + QString packetsString = locale.toString((int)voxelPacketsToProcess); + QString maxString = locale.toString((int)_recentMaxPackets); + + voxelStats << "Voxel Packets to Process: " << packetsString.toLocal8Bit().constData() + << " [Recent Max: " << maxString.toLocal8Bit().constData() << "]"; + + if (_resetRecentMaxPacketsSoon && voxelPacketsToProcess > 0) { + _recentMaxPackets = 0; + _resetRecentMaxPacketsSoon = false; + } + if (voxelPacketsToProcess == 0) { + _resetRecentMaxPacketsSoon = true; + } else { + if (voxelPacketsToProcess > _recentMaxPackets) { + _recentMaxPackets = voxelPacketsToProcess; + } + } + statsVerticalOffset += PELS_PER_LINE; + drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str()); + Node *avatarMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER); char avatarMixerStats[200]; diff --git a/interface/src/Application.h b/interface/src/Application.h index 4154720419..ff8ae2f882 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -223,9 +223,30 @@ private: void init(); void update(float deltaTime); - + + // Various helper functions called during update() + void updateMouseRay(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection); + void updateFaceshift(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection, + glm::vec3& lookAtRayOrigin, glm::vec3& lookAtRayDirection); + void updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot, glm::vec3& lookAtRayOrigin, glm::vec3& lookAtRayDirection); + void updateHoverVoxels(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection, + float& distance, BoxFace& face); + void updateMouseVoxels(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection, + float& distance, BoxFace& face); void updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection, glm::vec3& eyePosition); + void updateHandAndTouch(float deltaTime); + void updateLeap(float deltaTime); + void updateSerialDevices(float deltaTime); + void updateThreads(float deltaTime); + void updateMyAvatarSimulation(float deltaTime); + void updateParticles(float deltaTime); + void updateTransmitter(float deltaTime); + void updateCamera(float deltaTime); + void updateDialogs(float deltaTime); + void updateAudio(float deltaTime); + void updateCursor(float deltaTime); + Avatar* findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection, glm::vec3& eyePosition, QUuid &nodeUUID); bool isLookingAtMyAvatar(Avatar* avatar); @@ -407,6 +428,9 @@ private: int _bytesPerSecond; int _bytesCount; + int _recentMaxPackets; // recent max incoming voxel packets to process + bool _resetRecentMaxPacketsSoon; + StDev _idleLoopStdev; float _idleLoopMeasuredJitter; diff --git a/interface/src/VoxelPacketProcessor.cpp b/interface/src/VoxelPacketProcessor.cpp index 76075c6fa5..9087a5a545 100644 --- a/interface/src/VoxelPacketProcessor.cpp +++ b/interface/src/VoxelPacketProcessor.cpp @@ -19,7 +19,7 @@ void VoxelPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* "VoxelPacketProcessor::processPacket()"); const int WAY_BEHIND = 300; - if (packetsToProcessCount() > WAY_BEHIND && Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { + if (packetsToProcessCount() > WAY_BEHIND && Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)) { qDebug("VoxelPacketProcessor::processPacket() packets to process=%d\n", packetsToProcessCount()); } ssize_t messageLength = packetLength; diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 541d7983d2..5e30141054 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -1882,7 +1882,7 @@ void VoxelSystem::hideOutOfView(bool forceFullFrustum) { _inhideOutOfView = true; bool showDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showDebugDetails, "hideOutOfView()", showDebugDetails); + PerformanceWarning warn(showDebugDetails, "hideOutOfView()"); bool widenFrustum = true; // When using "delta" view frustums and only hide/show items that are in the difference @@ -1927,7 +1927,8 @@ void VoxelSystem::hideOutOfView(bool forceFullFrustum) { setupNewVoxelsForDrawingSingleNode(DONT_BAIL_EARLY); } - if (showDebugDetails) { + bool extraDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging); + if (extraDebugDetails) { qDebug("hideOutOfView() scanned=%ld removed=%ld inside=%ld intersect=%ld outside=%ld\n", args.nodesScanned, args.nodesRemoved, args.nodesInside, args.nodesIntersect, args.nodesOutside diff --git a/libraries/shared/src/ReceivedPacketProcessor.h b/libraries/shared/src/ReceivedPacketProcessor.h index f6d49cbb09..78017bffd7 100644 --- a/libraries/shared/src/ReceivedPacketProcessor.h +++ b/libraries/shared/src/ReceivedPacketProcessor.h @@ -24,6 +24,12 @@ public: /// \param ssize_t packetLength size of received data /// \thread network receive thread void queueReceivedPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength); + + /// Are there received packets waiting to be processed + bool hasPacketsToProcess() const { return _packets.size() > 0; } + + /// How many received packets waiting are to be processed + int packetsToProcessCount() const { return _packets.size(); } protected: /// Callback for processing of recieved packets. Implement this to process the incoming packets. @@ -36,12 +42,6 @@ protected: /// Implements generic processing behavior for this thread. virtual bool process(); - /// Are there received packets waiting to be processed - bool hasPacketsToProcess() const { return _packets.size() > 0; } - - /// How many received packets waiting are to be processed - int packetsToProcessCount() const { return _packets.size(); } - private: std::vector _packets; From 9bd27e2b2a5ba057280d3a27eb2815553a1401e4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 3 Nov 2013 21:11:08 -0800 Subject: [PATCH 13/13] fix stutter on rotating --- interface/src/Application.cpp | 32 ++++++++++++------ interface/src/VoxelSystem.cpp | 61 +++++++++++++++++++++-------------- interface/src/VoxelSystem.h | 6 ++++ 3 files changed, 65 insertions(+), 34 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 30548d19cc..994239cf56 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1306,7 +1306,10 @@ static glm::vec3 getFaceVector(BoxFace face) { } void Application::idle() { - bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + // Normally we check PipelineWarnings, but since idle will often take more than 10ms we only show these idle timing + // details if we're in ExtraDebugging mode. However, the ::update() and it's subcomponents will show their timing + // details normally. + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging); PerformanceWarning warn(showWarnings, "Application::idle()"); timeval check; @@ -1996,7 +1999,7 @@ void Application::updateHoverVoxels(float deltaTime, glm::vec3& mouseRayOrigin, bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels()"); - + // If we have clicked on a voxel, update it's color if (_isHoverVoxelSounding) { VoxelNode* hoveredNode = _voxels.getVoxelAt(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s); @@ -2018,14 +2021,23 @@ void Application::updateHoverVoxels(float deltaTime, glm::vec3& mouseRayOrigin, } else { // Check for a new hover voxel glm::vec4 oldVoxel(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s); - _isHoverVoxel = _voxels.findRayIntersection(mouseRayOrigin, mouseRayDirection, _hoverVoxel, distance, face); - if (MAKE_SOUND_ON_VOXEL_HOVER && _isHoverVoxel && glm::vec4(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s) != oldVoxel) { - _hoverVoxelOriginalColor[0] = _hoverVoxel.red; - _hoverVoxelOriginalColor[1] = _hoverVoxel.green; - _hoverVoxelOriginalColor[2] = _hoverVoxel.blue; - _hoverVoxelOriginalColor[3] = 1; - _audio.startCollisionSound(1.0, HOVER_VOXEL_FREQUENCY * _hoverVoxel.s * TREE_SCALE, 0.0, HOVER_VOXEL_DECAY); - _isHoverVoxelSounding = true; + // only do this work if MAKE_SOUND_ON_VOXEL_HOVER or MAKE_SOUND_ON_VOXEL_CLICK is enabled, + // and make sure the tree is not already busy... because otherwise you'll have to wait. + if (!_voxels.treeIsBusy()) { + { + PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels() _voxels.findRayIntersection()"); + _isHoverVoxel = _voxels.findRayIntersection(mouseRayOrigin, mouseRayDirection, _hoverVoxel, distance, face); + } + if (MAKE_SOUND_ON_VOXEL_HOVER && _isHoverVoxel && + glm::vec4(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s) != oldVoxel) { + + _hoverVoxelOriginalColor[0] = _hoverVoxel.red; + _hoverVoxelOriginalColor[1] = _hoverVoxel.green; + _hoverVoxelOriginalColor[2] = _hoverVoxel.blue; + _hoverVoxelOriginalColor[3] = 1; + _audio.startCollisionSound(1.0, HOVER_VOXEL_FREQUENCY * _hoverVoxel.s * TREE_SCALE, 0.0, HOVER_VOXEL_DECAY); + _isHoverVoxelSounding = true; + } } } } diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 5e30141054..1219548b4d 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -110,6 +110,7 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) _culledOnce = false; _inhideOutOfView = false; + _treeIsBusy = false; } void VoxelSystem::voxelDeleted(VoxelNode* node) { @@ -595,9 +596,9 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { "readBitstreamToTree()"); // ask the VoxelTree to read the bitstream into the tree ReadBitstreamToTreeParams args(WANT_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); - pthread_mutex_lock(&_treeLock); + lockTree(); _tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args); - pthread_mutex_unlock(&_treeLock); + unlockTree(); } break; case PACKET_TYPE_VOXEL_DATA_MONOCHROME: { @@ -605,9 +606,9 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { "readBitstreamToTree()"); // ask the VoxelTree to read the MONOCHROME bitstream into the tree ReadBitstreamToTreeParams args(NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); - pthread_mutex_lock(&_treeLock); + lockTree(); _tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args); - pthread_mutex_unlock(&_treeLock); + unlockTree(); } break; case PACKET_TYPE_Z_COMMAND: @@ -1002,7 +1003,9 @@ int VoxelSystem::updateNodeInArrays(VoxelNode* node, bool reuseIndex, bool force // not render these Voxels. We need to think about ways to keep the entire scene intact but maybe lower quality // possibly shifting down to lower LOD or something. This debug message is to help identify, if/when/how this // state actually occurs. - qDebug("OHHHH NOOOOOO!!!! updateNodeInArrays() BAILING (_voxelsInWriteArrays >= _maxVoxels)\n"); + if (Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)) { + qDebug("OHHHH NOOOOOO!!!! updateNodeInArrays() BAILING (_voxelsInWriteArrays >= _maxVoxels)\n"); + } return 0; } @@ -1405,9 +1408,9 @@ void VoxelSystem::removeScaleAndReleaseProgram(bool texture) { int VoxelSystem::_nodeCount = 0; void VoxelSystem::killLocalVoxels() { - pthread_mutex_lock(&_treeLock); + lockTree(); _tree->eraseAllVoxels(); - pthread_mutex_unlock(&_treeLock); + unlockTree(); clearFreeBufferIndexes(); _voxelsInReadArrays = 0; // do we need to do this? setupNewVoxelsForDrawing(); @@ -1426,9 +1429,9 @@ bool VoxelSystem::clearAllNodesBufferIndexOperation(VoxelNode* node, void* extra void VoxelSystem::clearAllNodesBufferIndex() { _nodeCount = 0; - pthread_mutex_lock(&_treeLock); + lockTree(); _tree->recurseTreeWithOperation(clearAllNodesBufferIndexOperation); - pthread_mutex_unlock(&_treeLock); + unlockTree(); if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { qDebug("clearing buffer index of %d nodes\n", _nodeCount); } @@ -1916,9 +1919,9 @@ void VoxelSystem::hideOutOfView(bool forceFullFrustum) { return; } - pthread_mutex_lock(&_treeLock); + lockTree(); _tree->recurseTreeWithOperation(hideOutOfViewOperation,(void*)&args); - pthread_mutex_unlock(&_treeLock); + unlockTree(); _lastCulledViewFrustum = args.thisViewFrustum; // save last stable _culledOnce = true; @@ -2107,10 +2110,10 @@ bool VoxelSystem::hideOutOfViewOperation(VoxelNode* node, void* extraData) { bool VoxelSystem::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, VoxelDetail& detail, float& distance, BoxFace& face) { - pthread_mutex_lock(&_treeLock); + lockTree(); VoxelNode* node; if (!_tree->findRayIntersection(origin, direction, node, distance, face)) { - pthread_mutex_unlock(&_treeLock); + unlockTree(); return false; } detail.x = node->getCorner().x; @@ -2120,21 +2123,21 @@ bool VoxelSystem::findRayIntersection(const glm::vec3& origin, const glm::vec3& detail.red = node->getColor()[0]; detail.green = node->getColor()[1]; detail.blue = node->getColor()[2]; - pthread_mutex_unlock(&_treeLock); + unlockTree(); return true; } bool VoxelSystem::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) { - pthread_mutex_lock(&_treeLock); + lockTree(); bool result = _tree->findSpherePenetration(center, radius, penetration); - pthread_mutex_unlock(&_treeLock); + unlockTree(); return result; } bool VoxelSystem::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) { - pthread_mutex_lock(&_treeLock); + lockTree(); bool result = _tree->findCapsulePenetration(start, end, radius, penetration); - pthread_mutex_unlock(&_treeLock); + unlockTree(); return result; } @@ -2308,9 +2311,9 @@ void VoxelSystem::collectStatsForTreesAndVBOs() { void VoxelSystem::deleteVoxelAt(float x, float y, float z, float s) { - pthread_mutex_lock(&_treeLock); + lockTree(); _tree->deleteVoxelAt(x, y, z, s); - pthread_mutex_unlock(&_treeLock); + unlockTree(); // redraw! setupNewVoxelsForDrawing(); // do we even need to do this? Or will the next network receive kick in? @@ -2325,9 +2328,9 @@ void VoxelSystem::createVoxel(float x, float y, float z, float s, unsigned char red, unsigned char green, unsigned char blue, bool destructive) { //qDebug("VoxelSystem::createVoxel(%f,%f,%f,%f)\n",x,y,z,s); - pthread_mutex_lock(&_treeLock); + lockTree(); _tree->createVoxel(x, y, z, s, red, green, blue, destructive); - pthread_mutex_unlock(&_treeLock); + unlockTree(); setupNewVoxelsForDrawing(); }; @@ -2650,9 +2653,9 @@ void VoxelSystem::nodeKilled(Node* node) { if (_voxelServerCount > 0) { // Kill any voxels from the local tree that match this nodeID // commenting out for removal of 16 bit node IDs - pthread_mutex_lock(&_treeLock); + lockTree(); _tree->recurseTreeWithOperation(killSourceVoxelsOperation, &nodeUUID); - pthread_mutex_unlock(&_treeLock); + unlockTree(); _tree->setDirtyBit(); setupNewVoxelsForDrawing(); } else { @@ -2720,5 +2723,15 @@ unsigned long VoxelSystem::getVoxelMemoryUsageGPU() { return (_initialMemoryUsageGPU - currentFreeMemory); } +void VoxelSystem::lockTree() { + pthread_mutex_lock(&_treeLock); + _treeIsBusy = true; +} + +void VoxelSystem::unlockTree() { + _treeIsBusy = false; + pthread_mutex_unlock(&_treeLock); +} + diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 303c7dfb49..0fdbb5b884 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -120,6 +120,8 @@ public: virtual void nodeKilled(Node* node); virtual void domainChanged(QString domain); + bool treeIsBusy() const { return _treeIsBusy; } + signals: void importSize(float x, float y, float z); void importProgress(int progress); @@ -302,6 +304,10 @@ private: bool _useFastVoxelPipeline; bool _inhideOutOfView; + bool _treeIsBusy; // is the tree mutex locked? if so, it's busy, and if you can avoid it, don't access the tree + + void lockTree(); + void unlockTree(); }; #endif