From 0eb89efb343cf5fdb61988ebf8c1ce95e26f33b7 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 2 Jul 2015 12:31:18 -0700 Subject: [PATCH 01/14] Fix text entity billboarding --- .../src/RenderableTextEntityItem.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index 7603187e94..5ff7b781a4 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -36,10 +36,6 @@ void RenderableTextEntityItem::render(RenderArgs* args) { glm::vec4 backgroundColor = glm::vec4(toGlm(getBackgroundColorX()), 1.0f); glm::vec3 dimensions = getDimensions(); - Transform transformToTopLeft = getTransformToCenter(); - transformToTopLeft.postTranslate(glm::vec3(-0.5f, 0.5f, 0.0f)); // Go to the top left - transformToTopLeft.setScale(1.0f); // Use a scale of one so that the text is not deformed - // Render background glm::vec3 minCorner = glm::vec3(0.0f, -dimensions.y, SLIGHTLY_BEHIND); glm::vec3 maxCorner = glm::vec3(dimensions.x, 0.0f, SLIGHTLY_BEHIND); @@ -48,13 +44,20 @@ void RenderableTextEntityItem::render(RenderArgs* args) { // Batch render calls Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; - batch.setModelTransform(transformToTopLeft); - //rotate about vertical to face the camera + Transform transformToTopLeft = getTransformToCenter(); if (getFaceCamera()) { - transformToTopLeft.postRotate(args->_viewFrustum->getOrientation()); - batch.setModelTransform(transformToTopLeft); + //rotate about vertical to face the camera + glm::vec3 dPosition = args->_viewFrustum->getPosition() - getPosition(); + // If x and z are 0, atan(x, z) is undefined, so default to 0 degrees + float yawRotation = dPosition.x == 0.0f && dPosition.z == 0.0f ? 0.0f : glm::atan(dPosition.x, dPosition.z); + glm::quat orientation = glm::quat(glm::vec3(0.0f, yawRotation, 0.0f)); + transformToTopLeft.setRotation(orientation); } + transformToTopLeft.postTranslate(glm::vec3(-0.5f, 0.5f, 0.0f)); // Go to the top left + transformToTopLeft.setScale(1.0f); // Use a scale of one so that the text is not deformed + + batch.setModelTransform(transformToTopLeft); DependencyManager::get()->bindSimpleProgram(batch, false, false); DependencyManager::get()->renderQuad(batch, minCorner, maxCorner, backgroundColor); From 32cf4dac78c21c8097d0f8e02d0f7481eca98813 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 2 Jul 2015 13:22:59 -0700 Subject: [PATCH 02/14] Fix displayname z-fighting --- interface/src/avatar/Avatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 748ef7c5a5..a14eeace6d 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -767,7 +767,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum) co auto textTransform = calculateDisplayNameTransform(frustum, renderer->getFontSize()); // Render background slightly behind to avoid z-fighting - auto backgroundTransform = textTransform; + auto backgroundTransform(textTransform); backgroundTransform.postTranslate(glm::vec3(0.0f, 0.0f, SLIGHTLY_BEHIND)); batch.setModelTransform(backgroundTransform); DependencyManager::get()->bindSimpleProgram(batch); From d243190cafbaa0caf2682ce8e709c742141ab7e0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 2 Jul 2015 13:23:19 -0700 Subject: [PATCH 03/14] Coding standard --- libraries/gpu/src/gpu/GLBackendState.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/gpu/src/gpu/GLBackendState.cpp b/libraries/gpu/src/gpu/GLBackendState.cpp index ef272bb708..274e33a049 100644 --- a/libraries/gpu/src/gpu/GLBackendState.cpp +++ b/libraries/gpu/src/gpu/GLBackendState.cpp @@ -589,7 +589,7 @@ void GLBackend::do_setStateAntialiasedLineEnable(bool enable) { void GLBackend::do_setStateDepthBias(Vec2 bias) { if ( (bias.x != _pipeline._stateCache.depthBias) || (bias.y != _pipeline._stateCache.depthBiasSlopeScale)) { - if ((bias.x != 0.f) || (bias.y != 0.f)) { + if ((bias.x != 0.0f) || (bias.y != 0.0f)) { glEnable(GL_POLYGON_OFFSET_FILL); glEnable(GL_POLYGON_OFFSET_LINE); glEnable(GL_POLYGON_OFFSET_POINT); From 0093403bba095edaa1636b7e2449d83740f4054a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Sat, 4 Jul 2015 18:33:03 -0700 Subject: [PATCH 04/14] Add depth bias option to simple programs Simple programs are now lazily generated and stored in a hash --- .../src/DeferredLightingEffect.cpp | 76 +++++++++---------- .../render-utils/src/DeferredLightingEffect.h | 61 +++++++++++++-- 2 files changed, 93 insertions(+), 44 deletions(-) diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index a44f1f053c..cc3ced93db 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -50,37 +50,44 @@ static const std::string glowIntensityShaderHandle = "glowIntensity"; +gpu::PipelinePointer DeferredLightingEffect::getPipeline(SimpleProgramKey config) { + auto it = _simplePrograms.find(config); + if (it != _simplePrograms.end()) { + return it.value(); + } + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + if (config.isCulled()) { + state->setCullMode(gpu::State::CULL_BACK); + } else { + state->setCullMode(gpu::State::CULL_NONE); + } + state->setDepthTest(true, true, gpu::LESS_EQUAL); + if (config.hasDepthBias()) { + state->setDepthBias(1.0f); + state->setDepthBiasSlopeScale(1.0f); + } + state->setBlendFunction(false, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + + gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader; + gpu::PipelinePointer pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + _simplePrograms.insert(config, pipeline); + return pipeline; +} + void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { auto VS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(simple_vert))); auto PS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(simple_textured_frag))); auto PSEmissive = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(simple_textured_emisive_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PS)); - gpu::ShaderPointer programEmissive = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PSEmissive)); + _simpleShader = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PS)); + _emissiveShader = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PSEmissive)); gpu::Shader::BindingSet slotBindings; - gpu::Shader::makeProgram(*program, slotBindings); - gpu::Shader::makeProgram(*programEmissive, slotBindings); - - gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - state->setCullMode(gpu::State::CULL_BACK); - state->setDepthTest(true, true, gpu::LESS_EQUAL); - state->setBlendFunction(false, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - - - gpu::StatePointer stateCullNone = gpu::StatePointer(new gpu::State()); - stateCullNone->setCullMode(gpu::State::CULL_NONE); - stateCullNone->setDepthTest(true, true, gpu::LESS_EQUAL); - stateCullNone->setBlendFunction(false, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - - _simpleProgram = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); - _simpleProgramCullNone = gpu::PipelinePointer(gpu::Pipeline::create(program, stateCullNone)); - _simpleProgramEmissive = gpu::PipelinePointer(gpu::Pipeline::create(programEmissive, state)); - _simpleProgramEmissiveCullNone = gpu::PipelinePointer(gpu::Pipeline::create(programEmissive, stateCullNone)); + gpu::Shader::makeProgram(*_simpleShader, slotBindings); + gpu::Shader::makeProgram(*_emissiveShader, slotBindings); _viewState = viewState; loadLightProgram(directional_light_frag, false, _directionalLight, _directionalLightLocations); @@ -117,21 +124,12 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset(_ambientLightMode % gpu::SphericalHarmonics::NUM_PRESET)); } -void DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled, bool emmisive) { - if (emmisive) { - if (culled) { - batch.setPipeline(_simpleProgramEmissive); - } else { - batch.setPipeline(_simpleProgramEmissiveCullNone); - } - } else { - if (culled) { - batch.setPipeline(_simpleProgram); - } else { - batch.setPipeline(_simpleProgramCullNone); - } - } - if (!textured) { +void DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled, + bool emmisive, bool depthBias) { + SimpleProgramKey config{textured, culled, emmisive, depthBias}; + batch.setPipeline(getPipeline(config)); + + if (!config.isTextured()) { // If it is not textured, bind white texture and keep using textured pipeline batch.setUniformTexture(0, DependencyManager::get()->getWhiteTexture()); } diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index d948f2c305..53aac7ee93 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -24,6 +24,7 @@ class AbstractViewStateInterface; class RenderArgs; +class SimpleProgramKey; /// Handles deferred lighting for the bits that require it (voxels...) class DeferredLightingEffect : public Dependency { @@ -34,7 +35,8 @@ public: void init(AbstractViewStateInterface* viewState); /// Sets up the state necessary to render static untextured geometry with the simple program. - void bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true, bool emmisive = false); + void bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true, + bool emmisive = false, bool depthBias = false); //// Renders a solid sphere with the simple program. void renderSolidSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec4& color); @@ -95,11 +97,11 @@ private: }; static void loadLightProgram(const char* fragSource, bool limited, ProgramObject& program, LightLocations& locations); + gpu::PipelinePointer getPipeline(SimpleProgramKey config); - gpu::PipelinePointer _simpleProgram; - gpu::PipelinePointer _simpleProgramCullNone; - gpu::PipelinePointer _simpleProgramEmissive; - gpu::PipelinePointer _simpleProgramEmissiveCullNone; + gpu::ShaderPointer _simpleShader; + gpu::ShaderPointer _emissiveShader; + QHash _simplePrograms; ProgramObject _directionalSkyboxLight; LightLocations _directionalSkyboxLightLocations; @@ -160,4 +162,53 @@ private: model::SkyboxPointer _skybox; }; +class SimpleProgramKey { +public: + enum FlagBit { + IS_TEXTURED_FLAG = 0, + IS_CULLED_FLAG, + IS_EMISSIVE_FLAG, + HAS_DEPTH_BIAS_FLAG, + + NUM_FLAGS, + }; + + enum Flag { + IS_TEXTURED = (1 << IS_TEXTURED_FLAG), + IS_CULLED = (1 << IS_CULLED_FLAG), + IS_EMISSIVE = (1 << IS_EMISSIVE_FLAG), + HAS_DEPTH_BIAS = (1 << HAS_DEPTH_BIAS_FLAG), + }; + typedef unsigned short Flags; + + bool isFlag(short flagNum) const { return bool((_flags & flagNum) != 0); } + + bool isTextured() const { return isFlag(IS_TEXTURED); } + bool isCulled() const { return isFlag(IS_CULLED); } + bool isEmissive() const { return isFlag(IS_EMISSIVE); } + bool hasDepthBias() const { return isFlag(HAS_DEPTH_BIAS); } + + Flags _flags = 0; + short _spare = 0; + + int getRaw() const { return *reinterpret_cast(this); } + + + SimpleProgramKey(bool textured = false, bool culled = true, + bool emissive = false, bool depthBias = false) { + _flags = (textured ? IS_TEXTURED : 0) | (culled ? IS_CULLED : 0) | + (emissive ? IS_EMISSIVE : 0) | (depthBias ? HAS_DEPTH_BIAS : 0); + } + + SimpleProgramKey(int bitmask) : _flags(bitmask) {} +}; + +inline uint qHash(const SimpleProgramKey& key, uint seed) { + return qHash(key.getRaw(), seed); +} + +inline bool operator==(const SimpleProgramKey& a, const SimpleProgramKey& b) { + return a.getRaw() == b.getRaw(); +} + #endif // hifi_DeferredLightingEffect_h From 9bf6c439aaecc8eac228aebbe48ec743510c3adc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Sat, 4 Jul 2015 18:34:19 -0700 Subject: [PATCH 05/14] Use depth bias to avoid z-fighting on display name --- interface/src/avatar/Avatar.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index a14eeace6d..a5fa7d3c82 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -750,7 +750,6 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum) co const int text_y = -nameDynamicRect.height() / 2; // Compute background position/size - static const float SLIGHTLY_BEHIND = -0.05f; const int border = 0.1f * nameDynamicRect.height(); const int left = text_x - border; const int bottom = text_y - border; @@ -765,17 +764,13 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum) co // Compute display name transform auto textTransform = calculateDisplayNameTransform(frustum, renderer->getFontSize()); + batch.setModelTransform(textTransform); - // Render background slightly behind to avoid z-fighting - auto backgroundTransform(textTransform); - backgroundTransform.postTranslate(glm::vec3(0.0f, 0.0f, SLIGHTLY_BEHIND)); - batch.setModelTransform(backgroundTransform); - DependencyManager::get()->bindSimpleProgram(batch); + DependencyManager::get()->bindSimpleProgram(batch, false, true, true, true); DependencyManager::get()->renderBevelCornersRect(batch, left, bottom, width, height, bevelDistance, backgroundColor); // Render actual name QByteArray nameUTF8 = renderedDisplayName.toLocal8Bit(); - batch.setModelTransform(textTransform); renderer->draw(batch, text_x, -text_y, nameUTF8.data(), textColor); } From c61bf342007fe3c57aa43aaf28effc48103df421 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Sat, 4 Jul 2015 18:35:00 -0700 Subject: [PATCH 06/14] Use depth bias to avoid z-fighting on text entities --- .../entities-renderer/src/RenderableTextEntityItem.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index 5ff7b781a4..c768bc521c 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -31,14 +31,13 @@ void RenderableTextEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RenderableTextEntityItem::render"); Q_ASSERT(getType() == EntityTypes::Text); - static const float SLIGHTLY_BEHIND = -0.005f; glm::vec4 textColor = glm::vec4(toGlm(getTextColorX()), 1.0f); glm::vec4 backgroundColor = glm::vec4(toGlm(getBackgroundColorX()), 1.0f); glm::vec3 dimensions = getDimensions(); // Render background - glm::vec3 minCorner = glm::vec3(0.0f, -dimensions.y, SLIGHTLY_BEHIND); - glm::vec3 maxCorner = glm::vec3(dimensions.x, 0.0f, SLIGHTLY_BEHIND); + glm::vec3 minCorner = glm::vec3(0.0f, -dimensions.y, 0.0f); + glm::vec3 maxCorner = glm::vec3(dimensions.x, 0.0f, 0.0f); // Batch render calls @@ -59,7 +58,7 @@ void RenderableTextEntityItem::render(RenderArgs* args) { batch.setModelTransform(transformToTopLeft); - DependencyManager::get()->bindSimpleProgram(batch, false, false); + DependencyManager::get()->bindSimpleProgram(batch, false, false, false, true); DependencyManager::get()->renderQuad(batch, minCorner, maxCorner, backgroundColor); float scale = _lineHeight / _textRenderer->getFontSize(); From 85df510b4b75f05f4d5115c7d959c8a3894fc337 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Sat, 4 Jul 2015 18:40:37 -0700 Subject: [PATCH 07/14] Use depth bias to avoid z-fighting on text3d overlays --- interface/src/ui/overlays/Text3DOverlay.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/ui/overlays/Text3DOverlay.cpp b/interface/src/ui/overlays/Text3DOverlay.cpp index 37774094de..9ee0a90a89 100644 --- a/interface/src/ui/overlays/Text3DOverlay.cpp +++ b/interface/src/ui/overlays/Text3DOverlay.cpp @@ -13,6 +13,7 @@ #include "Text3DOverlay.h" +#include #include #include @@ -110,10 +111,9 @@ void Text3DOverlay::render(RenderArgs* args) { glm::vec2 dimensions = getDimensions(); glm::vec2 halfDimensions = dimensions * 0.5f; - const float SLIGHTLY_BEHIND = -0.005f; - - glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, SLIGHTLY_BEHIND); - glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, SLIGHTLY_BEHIND); + glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, 0.0f); + glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, 0.0f); + DependencyManager::get()->bindSimpleProgram(batch, false, true, false, true); DependencyManager::get()->renderQuad(batch, topLeft, bottomRight, quadColor); // Same font properties as textSize() From 93fbfcbff796f9baeb285ff7d102ab5d2702db1b Mon Sep 17 00:00:00 2001 From: bwent Date: Mon, 6 Jul 2015 12:09:08 -0700 Subject: [PATCH 08/14] Added checkbox functionality, double-click to reset panel --- examples/utilities/tools/cookies.js | 1320 ++++++++++++++------------- 1 file changed, 669 insertions(+), 651 deletions(-) mode change 100755 => 100644 examples/utilities/tools/cookies.js diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js old mode 100755 new mode 100644 index 2ec34fcec8..f217b28aae --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -1,651 +1,669 @@ -// -// cookies.js -// -// version 1.0 -// -// Created by Sam Gateau, 4/1/2015 -// A simple ui panel that present a list of porperties and the proper widget to edit it -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -// The Slider class -Slider = function(x,y,width,thumbSize) { - this.background = Overlays.addOverlay("text", { - backgroundColor: { red: 125, green: 125, blue: 255 }, - x: x, - y: y, - width: width, - height: thumbSize, - alpha: 1.0, - backgroundAlpha: 0.5, - visible: true - }); - this.thumb = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, - x: x, - y: y, - width: thumbSize, - height: thumbSize, - alpha: 1.0, - backgroundAlpha: 1.0, - visible: true - }); - - - this.thumbSize = thumbSize; - this.thumbHalfSize = 0.5 * thumbSize; - - this.minThumbX = x + this.thumbHalfSize; - this.maxThumbX = x + width - this.thumbHalfSize; - this.thumbX = this.minThumbX; - - this.minValue = 0.0; - this.maxValue = 1.0; - - this.clickOffsetX = 0; - this.isMoving = false; - - this.updateThumb = function() { - thumbTruePos = this.thumbX - 0.5 * this.thumbSize; - Overlays.editOverlay(this.thumb, { x: thumbTruePos } ); - }; - - this.isClickableOverlayItem = function(item) { - return (item == this.thumb) || (item == this.background); - }; - - this.onMouseMoveEvent = function(event) { - if (this.isMoving) { - newThumbX = event.x - this.clickOffsetX; - if (newThumbX < this.minThumbX) { - newThumbX = this.minThumbX; - } - if (newThumbX > this.maxThumbX) { - newThumbX = this.maxThumbX; - } - this.thumbX = newThumbX; - this.updateThumb(); - this.onValueChanged(this.getValue()); - } - }; - - this.onMousePressEvent = function(event, clickedOverlay) { - if (!this.isClickableOverlayItem(clickedOverlay)) { - this.isMoving = false; - return; - } - this.isMoving = true; - var clickOffset = event.x - this.thumbX; - if ((clickOffset > -this.thumbHalfSize) && (clickOffset < this.thumbHalfSize)) { - this.clickOffsetX = clickOffset; - } else { - this.clickOffsetX = 0; - this.thumbX = event.x; - this.updateThumb(); - this.onValueChanged(this.getValue()); - } - - }; - - this.onMouseReleaseEvent = function(event) { - this.isMoving = false; - }; - - // Public members: - - this.setNormalizedValue = function(value) { - if (value < 0.0) { - this.thumbX = this.minThumbX; - } else if (value > 1.0) { - this.thumbX = this.maxThumbX; - } else { - this.thumbX = value * (this.maxThumbX - this.minThumbX) + this.minThumbX; - } - this.updateThumb(); - }; - this.getNormalizedValue = function() { - return (this.thumbX - this.minThumbX) / (this.maxThumbX - this.minThumbX); - }; - - this.setValue = function(value) { - var normValue = (value - this.minValue) / (this.maxValue - this.minValue); - this.setNormalizedValue(normValue); - }; - - this.getValue = function() { - return this.getNormalizedValue() * (this.maxValue - this.minValue) + this.minValue; - }; - - this.onValueChanged = function(value) {}; - - this.setMaxValue = function(maxValue) { - if (this.maxValue == maxValue) { - return; - } - var currentVal = this.getValue(); - this.maxValue = maxValue; - this.setValue(currentVal); - } - this.setMinValue = function(minValue) { - if (this.minValue == minValue) { - return; - } - var currentVal = this.getValue(); - this.minValue = minValue; - this.setValue(currentVal); - } - - this.destroy = function() { - Overlays.deleteOverlay(this.background); - Overlays.deleteOverlay(this.thumb); - }; - - this.setThumbColor = function(color) { - Overlays.editOverlay(this.thumb, {backgroundColor: { red: color.x*255, green: color.y*255, blue: color.z*255 }}); - }; - this.setBackgroundColor = function(color) { - Overlays.editOverlay(this.background, {backgroundColor: { red: color.x*255, green: color.y*255, blue: color.z*255 }}); - }; -} - -// The Checkbox class -Checkbox = function(x,y,thumbSize) { - - this.thumb = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, - x: x, - y: y, - width: thumbSize, - height: thumbSize, - alpha: 1.0, - backgroundAlpha: 1.0, - visible: true - }); - this.background = Overlays.addOverlay("text", { - backgroundColor: { red: 125, green: 125, blue: 255 }, - x: x, - y: y, - width: thumbSize * 2, - height: thumbSize, - alpha: 1.0, - backgroundAlpha: 0.5, - visible: true - }); - - this.thumbSize = thumbSize; - this.thumbHalfSize = 0.5 * thumbSize; - - this.minThumbX = x + this.thumbHalfSize; - this.maxThumbX = x + thumbSize * 2 - this.thumbHalfSize; - this.thumbX = this.minThumbX; - - this.minValue = 0.0; - this.maxValue = 1.0; - - this.clickOffsetX = 0; - this.isMoving = false; - - this.updateThumb = function() { - thumbTruePos = this.thumbX - 0.5 * this.thumbSize; - Overlays.editOverlay(this.thumb, { x: thumbTruePos } ); - }; - - this.isClickableOverlayItem = function(item) { - return item == this.background; - }; - - this.onMouseMoveEvent = function(event) { - if (this.isMoving) { - newThumbX = event.x - this.clickOffsetX; - if (newThumbX < this.minThumbX) { - newThumbX = this.minThumbX; - } - if (newThumbX > this.maxThumbX) { - newThumbX = this.maxThumbX; - } - this.thumbX = newThumbX; - this.updateThumb(); - this.onValueChanged(this.getValue()); - } - }; - - this.onMousePressEvent = function(event, clickedOverlay) { - if (this.background != clickedOverlay) { - this.isMoving = false; - return; - } - this.isMoving = true; - var clickOffset = event.x - this.thumbX; - if ((clickOffset > -this.thumbHalfSize) && (clickOffset < this.thumbHalfSize)) { - this.clickOffsetX = clickOffset; - } else { - this.clickOffsetX = 0; - this.thumbX = event.x; - this.updateThumb(); - this.onValueChanged(this.getValue()); - } - - }; - - this.onMouseReleaseEvent = function(event) { - this.isMoving = false; - }; - - // Public members: - - this.setNormalizedValue = function(value) { - if (value < 0.0) { - this.thumbX = this.minThumbX; - } else if (value > 1.0) { - this.thumbX = this.maxThumbX; - } else { - this.thumbX = value * (this.maxThumbX - this.minThumbX) + this.minThumbX; - } - this.updateThumb(); - }; - this.getNormalizedValue = function() { - return (this.thumbX - this.minThumbX) / (this.maxThumbX - this.minThumbX); - }; - - this.setValue = function(value) { - var normValue = (value - this.minValue) / (this.maxValue - this.minValue); - this.setNormalizedValue(normValue); - }; - - this.getValue = function() { - return this.getNormalizedValue() * (this.maxValue - this.minValue) + this.minValue; - }; - - this.onValueChanged = function(value) {}; - - this.destroy = function() { - Overlays.deleteOverlay(this.background); - Overlays.deleteOverlay(this.thumb); - }; -} - -// The ColorBox class -ColorBox = function(x,y,width,thumbSize) { - var self = this; - - var slideHeight = thumbSize / 3; - var sliderWidth = width; - this.red = new Slider(x, y, width, slideHeight); - this.green = new Slider(x, y + slideHeight, width, slideHeight); - this.blue = new Slider(x, y + 2 * slideHeight, width, slideHeight); - this.red.setBackgroundColor({x: 1, y: 0, z: 0}); - this.green.setBackgroundColor({x: 0, y: 1, z: 0}); - this.blue.setBackgroundColor({x: 0, y: 0, z: 1}); - - this.isClickableOverlayItem = function(item) { - return this.red.isClickableOverlayItem(item) - || this.green.isClickableOverlayItem(item) - || this.blue.isClickableOverlayItem(item); - }; - - this.onMouseMoveEvent = function(event) { - this.red.onMouseMoveEvent(event); - this.green.onMouseMoveEvent(event); - this.blue.onMouseMoveEvent(event); - }; - - this.onMousePressEvent = function(event, clickedOverlay) { - this.red.onMousePressEvent(event, clickedOverlay); - if (this.red.isMoving) { - return; - } - - this.green.onMousePressEvent(event, clickedOverlay); - if (this.green.isMoving) { - return; - } - - this.blue.onMousePressEvent(event, clickedOverlay); - }; - - this.onMouseReleaseEvent = function(event) { - this.red.onMouseReleaseEvent(event); - this.green.onMouseReleaseEvent(event); - this.blue.onMouseReleaseEvent(event); - }; - - this.setterFromWidget = function(value) { - var color = self.getValue(); - self.onValueChanged(color); - self.updateRGBSliders(color); - }; - - this.red.onValueChanged = this.setterFromWidget; - this.green.onValueChanged = this.setterFromWidget; - this.blue.onValueChanged = this.setterFromWidget; - - this.updateRGBSliders = function(color) { - this.red.setThumbColor({x: color.x, y: 0, z: 0}); - this.green.setThumbColor({x: 0, y: color.y, z: 0}); - this.blue.setThumbColor({x: 0, y: 0, z: color.z}); - }; - - // Public members: - this.setValue = function(value) { - this.red.setValue(value.x); - this.green.setValue(value.y); - this.blue.setValue(value.z); - this.updateRGBSliders(value); - }; - - this.getValue = function() { - var value = {x:this.red.getValue(), y:this.green.getValue(),z:this.blue.getValue()}; - return value; - }; - - this.destroy = function() { - this.red.destroy(); - this.green.destroy(); - this.blue.destroy(); - }; - - this.onValueChanged = function(value) {}; -} - -// The DirectionBox class -DirectionBox = function(x,y,width,thumbSize) { - var self = this; - - var slideHeight = thumbSize / 2; - var sliderWidth = width; - this.yaw = new Slider(x, y, width, slideHeight); - this.pitch = new Slider(x, y + slideHeight, width, slideHeight); - - this.yaw.setThumbColor({x: 1, y: 0, z: 0}); - this.yaw.minValue = -180; - this.yaw.maxValue = +180; - - this.pitch.setThumbColor({x: 0, y: 0, z: 1}); - this.pitch.minValue = -1; - this.pitch.maxValue = +1; - - this.isClickableOverlayItem = function(item) { - return this.yaw.isClickableOverlayItem(item) - || this.pitch.isClickableOverlayItem(item); - }; - - this.onMouseMoveEvent = function(event) { - this.yaw.onMouseMoveEvent(event); - this.pitch.onMouseMoveEvent(event); - }; - - this.onMousePressEvent = function(event, clickedOverlay) { - this.yaw.onMousePressEvent(event, clickedOverlay); - if (this.yaw.isMoving) { - return; - } - this.pitch.onMousePressEvent(event, clickedOverlay); - }; - - this.onMouseReleaseEvent = function(event) { - this.yaw.onMouseReleaseEvent(event); - this.pitch.onMouseReleaseEvent(event); - }; - - this.setterFromWidget = function(value) { - var yawPitch = self.getValue(); - self.onValueChanged(yawPitch); - }; - - this.yaw.onValueChanged = this.setterFromWidget; - this.pitch.onValueChanged = this.setterFromWidget; - - // Public members: - this.setValue = function(direction) { - var flatXZ = Math.sqrt(direction.x * direction.x + direction.z * direction.z); - if (flatXZ > 0.0) { - var flatX = direction.x / flatXZ; - var flatZ = direction.z / flatXZ; - var yaw = Math.acos(flatX) * 180 / Math.PI; - if (flatZ < 0) { - yaw = -yaw; - } - this.yaw.setValue(yaw); - } - this.pitch.setValue(direction.y); - }; - - this.getValue = function() { - var dirZ = this.pitch.getValue(); - var yaw = this.yaw.getValue() * Math.PI / 180; - var cosY = Math.sqrt(1 - dirZ*dirZ); - var value = {x:cosY * Math.cos(yaw), y:dirZ, z: cosY * Math.sin(yaw)}; - return value; - }; - - this.destroy = function() { - this.yaw.destroy(); - this.pitch.destroy(); - }; - - this.onValueChanged = function(value) {}; -} - -var textFontSize = 16; - -function PanelItem(name, setter, getter, displayer, x, y, textWidth, valueWidth, height) { - this.name = name; - - - this.displayer = typeof displayer !== 'undefined' ? displayer : function(value) { return value.toFixed(2); }; - - var topMargin = (height - textFontSize); - this.title = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, - x: x, - y: y, - width: textWidth, - height: height, - alpha: 1.0, - backgroundAlpha: 0.5, - visible: true, - text: name, - font: {size: textFontSize}, - topMargin: topMargin, - }); - - this.value = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, - x: x + textWidth, - y: y, - width: valueWidth, - height: height, - alpha: 1.0, - backgroundAlpha: 0.5, - visible: true, - text: this.displayer(getter()), - font: {size: textFontSize}, - topMargin: topMargin - - }); - this.getter = getter; - - this.setter = function(value) { - setter(value); - Overlays.editOverlay(this.value, {text: this.displayer(getter())}); - if (this.widget) { - this.widget.setValue(value); - } - }; - this.setterFromWidget = function(value) { - setter(value); - // ANd loop back the value after the final setter has been called - var value = getter(); - if (this.widget) { - this.widget.setValue(value); - } - Overlays.editOverlay(this.value, {text: this.displayer(value)}); - }; - - - this.widget = null; - - this.destroy = function() { - Overlays.deleteOverlay(this.title); - Overlays.deleteOverlay(this.value); - if (this.widget != null) { - this.widget.destroy(); - } - } -} - -var textWidth = 180; -var valueWidth = 100; -var widgetWidth = 300; -var rawHeight = 20; -var rawYDelta = rawHeight * 1.5; - -Panel = function(x, y) { - - this.x = x; - this.y = y; - this.nextY = y; - - this.widgetX = x + textWidth + valueWidth; - - this.items = new Array(); - this.activeWidget = null; - - this.mouseMoveEvent = function(event) { - if (this.activeWidget) { - this.activeWidget.onMouseMoveEvent(event); - } - }; - - // we also handle click detection in our mousePressEvent() - this.mousePressEvent = function(event) { - // Make sure we quitted previous widget - if (this.activeWidget) { - this.activeWidget.onMouseReleaseEvent(event); - } - this.activeWidget = null; - - var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); - - // If the user clicked any of the slider background then... - for (var i in this.items) { - var widget = this.items[i].widget; - - if (widget.isClickableOverlayItem(clickedOverlay)) { - this.activeWidget = widget; - this.activeWidget.onMousePressEvent(event, clickedOverlay); - // print("clicked... widget=" + i); - break; - } - } - }; - - this.mouseReleaseEvent = function(event) { - if (this.activeWidget) { - this.activeWidget.onMouseReleaseEvent(event); - } - this.activeWidget = null; - }; - - this.newSlider = function(name, minValue, maxValue, setValue, getValue, displayValue) { - - var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); - - var slider = new Slider(this.widgetX, this.nextY, widgetWidth, rawHeight); - slider.minValue = minValue; - slider.maxValue = maxValue; - - - item.widget = slider; - item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; - item.setter(getValue()); - this.items[name] = item; - this.nextY += rawYDelta; - // print("created Item... slider=" + name); - }; - - this.newCheckbox = function(name, setValue, getValue, displayValue) { - - var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); - - var checkbox = new Checkbox(this.widgetX, this.nextY, rawHeight); - - item.widget = checkbox; - item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; - item.setter(getValue()); - this.items[name] = item; - this.nextY += rawYDelta; - // print("created Item... slider=" + name); - }; - - this.newColorBox = function(name, setValue, getValue, displayValue) { - - var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); - - var colorBox = new ColorBox(this.widgetX, this.nextY, widgetWidth, rawHeight); - - item.widget = colorBox; - item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; - item.setter(getValue()); - this.items[name] = item; - this.nextY += rawYDelta; - // print("created Item... colorBox=" + name); - }; - - this.newDirectionBox= function(name, setValue, getValue, displayValue) { - - var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); - - var directionBox = new DirectionBox(this.widgetX, this.nextY, widgetWidth, rawHeight); - - item.widget = directionBox; - item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; - item.setter(getValue()); - this.items[name] = item; - this.nextY += rawYDelta; - // print("created Item... directionBox=" + name); - }; - - this.destroy = function() { - for (var i in this.items) { - this.items[i].destroy(); - } - } - - this.set = function(name, value) { - var item = this.items[name]; - if (item != null) { - return item.setter(value); - } - return null; - } - - this.get = function(name) { - var item = this.items[name]; - if (item != null) { - return item.getter(); - } - return null; - } - - this.getWidget = function(name) { - var item = this.items[name]; - if (item != null) { - return item.widget; - } - return null; - } - - this.update = function(name) { - var item = this.items[name]; - if (item != null) { - return item.setter(item.getter()); - } - return null; - } - -}; - - + +// +// cookies.js +// +// version 2.0 +// +// Created by Sam Gateau, 4/1/2015 +// A simple ui panel that present a list of porperties and the proper widget to edit it +// +// Modified by Bridget Went, June 2015 +// Fixed checkBox class functionality, enabled mouseDoublePressEvent to reset panel items +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +// The Slider class +Slider = function(x,y,width,thumbSize) { + this.background = Overlays.addOverlay("text", { + backgroundColor: { red: 200, green: 200, blue: 255 }, + x: x, + y: y, + width: width, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true + }); + this.thumb = Overlays.addOverlay("text", { + backgroundColor: { red: 255, green: 255, blue: 255 }, + x: x, + y: y, + width: thumbSize, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 1.0, + visible: true + }); + + + this.thumbSize = thumbSize; + this.thumbHalfSize = 0.5 * thumbSize; + + this.minThumbX = x + this.thumbHalfSize; + this.maxThumbX = x + width - this.thumbHalfSize; + this.thumbX = this.minThumbX; + + this.minValue = 0.0; + this.maxValue = 1.0; + + this.clickOffsetX = 0; + this.isMoving = false; + + this.updateThumb = function() { + thumbTruePos = this.thumbX - 0.5 * this.thumbSize; + Overlays.editOverlay(this.thumb, { x: thumbTruePos } ); + }; + + this.isClickableOverlayItem = function(item) { + return (item == this.thumb) || (item == this.background); + }; + + this.onMouseMoveEvent = function(event) { + if (this.isMoving) { + newThumbX = event.x - this.clickOffsetX; + if (newThumbX < this.minThumbX) { + newThumbX = this.minThumbX; + } + if (newThumbX > this.maxThumbX) { + newThumbX = this.maxThumbX; + } + this.thumbX = newThumbX; + this.updateThumb(); + this.onValueChanged(this.getValue()); + } + }; + + this.onMousePressEvent = function(event, clickedOverlay) { + if (!this.isClickableOverlayItem(clickedOverlay)) { + this.isMoving = false; + return; + } + this.isMoving = true; + var clickOffset = event.x - this.thumbX; + if ((clickOffset > -this.thumbHalfSize) && (clickOffset < this.thumbHalfSize)) { + this.clickOffsetX = clickOffset; + } else { + this.clickOffsetX = 0; + this.thumbX = event.x; + this.updateThumb(); + this.onValueChanged(this.getValue()); + } + + }; + + this.onMouseReleaseEvent = function(event) { + this.isMoving = false; + }; + + + // Public members: + this.setNormalizedValue = function(value) { + if (value < 0.0) { + this.thumbX = this.minThumbX; + } else if (value > 1.0) { + this.thumbX = this.maxThumbX; + } else { + this.thumbX = value * (this.maxThumbX - this.minThumbX) + this.minThumbX; + } + this.updateThumb(); + }; + this.getNormalizedValue = function() { + return (this.thumbX - this.minThumbX) / (this.maxThumbX - this.minThumbX); + }; + + this.setValue = function(value) { + var normValue = (value - this.minValue) / (this.maxValue - this.minValue); + this.setNormalizedValue(normValue); + }; + + this.getValue = function() { + return this.getNormalizedValue() * (this.maxValue - this.minValue) + this.minValue; + }; + + this.onValueChanged = function(value) {}; + + this.destroy = function() { + Overlays.deleteOverlay(this.background); + Overlays.deleteOverlay(this.thumb); + }; + + this.setThumbColor = function(color) { + Overlays.editOverlay(this.thumb, {backgroundColor: { red: color.x*255, green: color.y*255, blue: color.z*255 }}); + }; + this.setBackgroundColor = function(color) { + Overlays.editOverlay(this.background, {backgroundColor: { red: color.x*255, green: color.y*255, blue: color.z*255 }}); + }; +} + +// The Checkbox class +Checkbox = function(x,y,width,thumbSize) { + + this.background = Overlays.addOverlay("text", { + backgroundColor: { red: 125, green: 125, blue: 255 }, + x: x, + y: y, + width: width, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true + }); + + this.thumb = Overlays.addOverlay("text", { + backgroundColor: { red: 255, green: 255, blue: 255 }, + textFontSize: 10, + x: x, + y: y, + width: thumbSize, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 1.0, + visible: true + }); + + + this.thumbSize = thumbSize; + var checkX = x + (0.25 * thumbSize); + var checkY = y + (0.25 * thumbSize); + + + var checkMark = Overlays.addOverlay("text", { + backgroundColor: { red: 0, green: 255, blue: 0 }, + x: checkX, + y: checkY, + width: thumbSize / 2.0, + height: thumbSize / 2.0, + alpha: 1.0, + visible: true + }); + + var unCheckMark = Overlays.addOverlay("image", { + backgroundColor: { red: 255, green: 255, blue: 255 }, + x: checkX + 1.0, + y: checkY + 1.0, + width: thumbSize / 2.5, + height: thumbSize / 2.5, + alpha: 1.0, + visible: boxCheckStatus + }); + + + var boxCheckStatus; + var clickedBox = false; + + this.updateThumb = function() { + if (clickedBox) { + boxCheckStatus = !boxCheckStatus; + if (boxCheckStatus) { + Overlays.editOverlay(unCheckMark, { visible: false }); + } else { + Overlays.editOverlay(unCheckMark, { visible: true }); + } + } + }; + + this.isClickableOverlayItem = function(item) { + return (item == this.thumb) || (item == checkMark) || (item == unCheckMark); + }; + + this.onMousePressEvent = function(event, clickedOverlay) { + if (!this.isClickableOverlayItem(clickedOverlay)) { + this.isMoving = false; + clickedBox = false; + return; + } + + clickedBox = true; + this.updateThumb(); + this.onValueChanged(this.getValue()); + }; + + this.onMouseReleaseEvent = function(event) { + this.clickedBox = false; + }; + + // Public members: + this.setNormalizedValue = function(value) { + boxCheckStatus = value; + }; + + this.getNormalizedValue = function() { + return boxCheckStatus; + }; + + this.setValue = function(value) { + this.setNormalizedValue(value); + }; + + this.getValue = function() { + return boxCheckStatus; + }; + + this.onValueChanged = function(value) {}; + + this.destroy = function() { + Overlays.deleteOverlay(this.background); + Overlays.deleteOverlay(this.thumb); + Overlays.deleteOverlay(checkMark); + Overlays.deleteOverlay(unCheckMark); + }; + + this.setThumbColor = function(color) { + Overlays.editOverlay(this.thumb, { red: 255, green: 255, blue: 255 } ); + }; + this.setBackgroundColor = function(color) { + Overlays.editOverlay(this.background, { red: 125, green: 125, blue: 255 }); + }; + +} + +// The ColorBox class +ColorBox = function(x,y,width,thumbSize) { + var self = this; + + var slideHeight = thumbSize / 3; + var sliderWidth = width; + this.red = new Slider(x, y, width, slideHeight); + this.green = new Slider(x, y + slideHeight, width, slideHeight); + this.blue = new Slider(x, y + 2 * slideHeight, width, slideHeight); + this.red.setBackgroundColor({x: 1, y: 0, z: 0}); + this.green.setBackgroundColor({x: 0, y: 1, z: 0}); + this.blue.setBackgroundColor({x: 0, y: 0, z: 1}); + + this.isClickableOverlayItem = function(item) { + return this.red.isClickableOverlayItem(item) + || this.green.isClickableOverlayItem(item) + || this.blue.isClickableOverlayItem(item); + }; + + this.onMouseMoveEvent = function(event) { + this.red.onMouseMoveEvent(event); + this.green.onMouseMoveEvent(event); + this.blue.onMouseMoveEvent(event); + }; + + this.onMousePressEvent = function(event, clickedOverlay) { + this.red.onMousePressEvent(event, clickedOverlay); + if (this.red.isMoving) { + return; + } + + this.green.onMousePressEvent(event, clickedOverlay); + if (this.green.isMoving) { + return; + } + + this.blue.onMousePressEvent(event, clickedOverlay); + }; + + this.onMouseReleaseEvent = function(event) { + this.red.onMouseReleaseEvent(event); + this.green.onMouseReleaseEvent(event); + this.blue.onMouseReleaseEvent(event); + }; + + this.setterFromWidget = function(value) { + var color = self.getValue(); + self.onValueChanged(color); + self.updateRGBSliders(color); + }; + + this.red.onValueChanged = this.setterFromWidget; + this.green.onValueChanged = this.setterFromWidget; + this.blue.onValueChanged = this.setterFromWidget; + + this.updateRGBSliders = function(color) { + this.red.setThumbColor({x: color.x, y: 0, z: 0}); + this.green.setThumbColor({x: 0, y: color.y, z: 0}); + this.blue.setThumbColor({x: 0, y: 0, z: color.z}); + }; + + // Public members: + this.setValue = function(value) { + this.red.setValue(value.x); + this.green.setValue(value.y); + this.blue.setValue(value.z); + this.updateRGBSliders(value); + }; + + this.getValue = function() { + var value = {x:this.red.getValue(), y:this.green.getValue(),z:this.blue.getValue()}; + return value; + }; + + this.destroy = function() { + this.red.destroy(); + this.green.destroy(); + this.blue.destroy(); + }; + + this.onValueChanged = function(value) {}; +} + +// The DirectionBox class +DirectionBox = function(x,y,width,thumbSize) { + var self = this; + + var slideHeight = thumbSize / 2; + var sliderWidth = width; + this.yaw = new Slider(x, y, width, slideHeight); + this.pitch = new Slider(x, y + slideHeight, width, slideHeight); + + this.yaw.setThumbColor({x: 1, y: 0, z: 0}); + this.yaw.minValue = -180; + this.yaw.maxValue = +180; + + this.pitch.setThumbColor({x: 0, y: 0, z: 1}); + this.pitch.minValue = -1; + this.pitch.maxValue = +1; + + this.isClickableOverlayItem = function(item) { + return this.yaw.isClickableOverlayItem(item) + || this.pitch.isClickableOverlayItem(item); + }; + + this.onMouseMoveEvent = function(event) { + this.yaw.onMouseMoveEvent(event); + this.pitch.onMouseMoveEvent(event); + }; + + this.onMousePressEvent = function(event, clickedOverlay) { + this.yaw.onMousePressEvent(event, clickedOverlay); + if (this.yaw.isMoving) { + return; + } + this.pitch.onMousePressEvent(event, clickedOverlay); + }; + + this.onMouseReleaseEvent = function(event) { + this.yaw.onMouseReleaseEvent(event); + this.pitch.onMouseReleaseEvent(event); + }; + + this.setterFromWidget = function(value) { + var yawPitch = self.getValue(); + self.onValueChanged(yawPitch); + }; + + this.yaw.onValueChanged = this.setterFromWidget; + this.pitch.onValueChanged = this.setterFromWidget; + + // Public members: + this.setValue = function(direction) { + var flatXZ = Math.sqrt(direction.x * direction.x + direction.z * direction.z); + if (flatXZ > 0.0) { + var flatX = direction.x / flatXZ; + var flatZ = direction.z / flatXZ; + var yaw = Math.acos(flatX) * 180 / Math.PI; + if (flatZ < 0) { + yaw = -yaw; + } + this.yaw.setValue(yaw); + } + this.pitch.setValue(direction.y); + }; + + this.getValue = function() { + var dirZ = this.pitch.getValue(); + var yaw = this.yaw.getValue() * Math.PI / 180; + var cosY = Math.sqrt(1 - dirZ*dirZ); + var value = {x:cosY * Math.cos(yaw), y:dirZ, z: cosY * Math.sin(yaw)}; + return value; + }; + + this.destroy = function() { + this.yaw.destroy(); + this.pitch.destroy(); + }; + + this.onValueChanged = function(value) {}; +} + +var textFontSize = 12; + +function PanelItem(name, setter, getter, displayer, x, y, textWidth, valueWidth, height) { + //print("creating panel item: " + name); + + this.name = name; + + this.displayer = typeof displayer !== 'undefined' ? displayer : function(value) { + if(value == true) { + return "On"; + } else if (value == false) { + return "Off"; + } + return value.toFixed(2); + }; + + var topMargin = (height - textFontSize); + this.title = Overlays.addOverlay("text", { + backgroundColor: { red: 255, green: 255, blue: 255 }, + x: x, + y: y, + width: textWidth, + height: height, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true, + text: name, + font: {size: textFontSize}, + topMargin: topMargin, + }); + + this.value = Overlays.addOverlay("text", { + backgroundColor: { red: 255, green: 255, blue: 255 }, + x: x + textWidth, + y: y, + width: valueWidth, + height: height, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true, + text: this.displayer(getter()), + font: {size: textFontSize}, + topMargin: topMargin + }); + + this.getter = getter; + this.resetValue = getter(); + + this.setter = function(value) { + + setter(value); + + Overlays.editOverlay(this.value, {text: this.displayer(getter())}); + + if (this.widget) { + this.widget.setValue(value); + } + + //print("successfully set value of widget to " + value); + }; + this.setterFromWidget = function(value) { + setter(value); + // ANd loop back the value after the final setter has been called + var value = getter(); + + if (this.widget) { + this.widget.setValue(value); + } + Overlays.editOverlay(this.value, {text: this.displayer(value)}); + }; + + + this.widget = null; + + this.destroy = function() { + Overlays.deleteOverlay(this.title); + Overlays.deleteOverlay(this.value); + if (this.widget != null) { + this.widget.destroy(); + } + } +} + +var textWidth = 180; +var valueWidth = 100; +var widgetWidth = 300; +var rawHeight = 20; +var rawYDelta = rawHeight * 1.5; + +Panel = function(x, y) { + + this.x = x; + this.y = y; + this.nextY = y; + + this.widgetX = x + textWidth + valueWidth; + + this.items = new Array(); + this.activeWidget = null; + + this.mouseMoveEvent = function(event) { + if (this.activeWidget) { + this.activeWidget.onMouseMoveEvent(event); + } + }; + + this.mousePressEvent = function(event) { + // Make sure we quitted previous widget + if (this.activeWidget) { + this.activeWidget.onMouseReleaseEvent(event); + } + this.activeWidget = null; + + var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + + // If the user clicked any of the slider background then... + for (var i in this.items) { + var widget = this.items[i].widget; + + if (widget.isClickableOverlayItem(clickedOverlay)) { + this.activeWidget = widget; + this.activeWidget.onMousePressEvent(event, clickedOverlay); + + break; + } + } + }; + + // Reset panel item upon double-clicking + this.mouseDoublePressEvent = function(event) { + var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + for (var i in this.items) { + + var item = this.items[i]; + var widget = item.widget; + + if (item.title == clickedOverlay || item.value == clickedOverlay) { + widget.updateThumb(); + widget.onValueChanged(item.resetValue); + break; + } + } + } + + this.mouseReleaseEvent = function(event) { + if (this.activeWidget) { + this.activeWidget.onMouseReleaseEvent(event); + } + this.activeWidget = null; + }; + + this.newSlider = function(name, minValue, maxValue, setValue, getValue, displayValue) { + + var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); + + var slider = new Slider(this.widgetX, this.nextY, widgetWidth, rawHeight); + slider.minValue = minValue; + slider.maxValue = maxValue; + + item.widget = slider; + item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; + item.setter(getValue()); + this.items[name] = item; + this.nextY += rawYDelta; + }; + + this.newCheckbox = function(name, setValue, getValue, displayValue) { + var display; + if (displayValue == true) { + display = function() {return "On";}; + } else if (displayValue == false) { + display = function() {return "Off";}; + } + + var item = new PanelItem(name, setValue, getValue, display, this.x, this.nextY, textWidth, valueWidth, rawHeight); + + var checkbox = new Checkbox(this.widgetX, this.nextY, widgetWidth, rawHeight); + + item.widget = checkbox; + item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; + item.setter(getValue()); + this.items[name] = item; + this.nextY += rawYDelta; + //print("created Item... checkbox=" + name); + }; + + this.newColorBox = function(name, setValue, getValue, displayValue) { + + var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); + + var colorBox = new ColorBox(this.widgetX, this.nextY, widgetWidth, rawHeight); + + item.widget = colorBox; + item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; + item.setter(getValue()); + this.items[name] = item; + this.nextY += rawYDelta; + // print("created Item... colorBox=" + name); + }; + + this.newDirectionBox= function(name, setValue, getValue, displayValue) { + + var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); + + var directionBox = new DirectionBox(this.widgetX, this.nextY, widgetWidth, rawHeight); + + item.widget = directionBox; + item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; + item.setter(getValue()); + this.items[name] = item; + this.nextY += rawYDelta; + // print("created Item... directionBox=" + name); + }; + + this.destroy = function() { + for (var i in this.items) { + this.items[i].destroy(); + } + } + + this.set = function(name, value) { + var item = this.items[name]; + if (item != null) { + return item.setter(value); + } + return null; + } + + this.get = function(name) { + var item = this.items[name]; + if (item != null) { + return item.getter(); + } + return null; + } + + this.update = function(name) { + var item = this.items[name]; + if (item != null) { + return item.setter(item.getter()); + } + return null; + } + +}; + + From 5d91f1be834ce46555a1831847623df0e5df7fa0 Mon Sep 17 00:00:00 2001 From: bwent Date: Mon, 6 Jul 2015 13:26:16 -0700 Subject: [PATCH 09/14] Removed header comments --- examples/utilities/tools/cookies.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index f217b28aae..7433475cdb 100644 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -7,8 +7,6 @@ // Created by Sam Gateau, 4/1/2015 // A simple ui panel that present a list of porperties and the proper widget to edit it // -// Modified by Bridget Went, June 2015 -// Fixed checkBox class functionality, enabled mouseDoublePressEvent to reset panel items // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html From 2bdd2b8c2cc3e7c264ae2d15cbb8fa0683c57b09 Mon Sep 17 00:00:00 2001 From: bwent Date: Mon, 6 Jul 2015 15:02:51 -0700 Subject: [PATCH 10/14] Update cookies.js --- examples/utilities/tools/cookies.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index 7433475cdb..c3930e18c5 100644 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -1,4 +1,3 @@ - // // cookies.js // @@ -7,7 +6,6 @@ // Created by Sam Gateau, 4/1/2015 // A simple ui panel that present a list of porperties and the proper widget to edit it // -// // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html From 8b4398cd5a626067346a96e8aded574b67489653 Mon Sep 17 00:00:00 2001 From: bwent Date: Mon, 6 Jul 2015 15:03:21 -0700 Subject: [PATCH 11/14] Update cookies.js --- examples/utilities/tools/cookies.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index c3930e18c5..0fdae01c5e 100644 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -8,7 +8,7 @@ // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - +// // The Slider class Slider = function(x,y,width,thumbSize) { this.background = Overlays.addOverlay("text", { From 05f28064bf26366ab6581bdda7334b997a7bdf08 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 Jul 2015 16:03:42 -0700 Subject: [PATCH 12/14] add stats for PPS for inbound from network into OctreePacketProcessor and processing out of OctreePacketProcessor --- interface/src/ui/OctreeStatsDialog.cpp | 31 +++++++++++++------ .../src/ReceivedPacketProcessor.cpp | 27 ++++++++++++++++ .../networking/src/ReceivedPacketProcessor.h | 11 ++++++- 3 files changed, 59 insertions(+), 10 deletions(-) diff --git a/interface/src/ui/OctreeStatsDialog.cpp b/interface/src/ui/OctreeStatsDialog.cpp index 94f91a5ab7..fbfc3ea662 100644 --- a/interface/src/ui/OctreeStatsDialog.cpp +++ b/interface/src/ui/OctreeStatsDialog.cpp @@ -21,6 +21,7 @@ #include "Application.h" +#include "../octree/OctreePacketProcessor.h" #include "ui/OctreeStatsDialog.h" OctreeStatsDialog::OctreeStatsDialog(QWidget* parent, NodeToOctreeSceneStats* model) : @@ -53,7 +54,7 @@ OctreeStatsDialog::OctreeStatsDialog(QWidget* parent, NodeToOctreeSceneStats* mo _localElementsMemory = AddStatItem("Elements Memory"); _sendingMode = AddStatItem("Sending Mode"); - _processedPackets = AddStatItem("Processed Packets"); + _processedPackets = AddStatItem("Entity Packets"); _processedPacketsElements = AddStatItem("Processed Packets Elements"); _processedPacketsEntities = AddStatItem("Processed Packets Entities"); _processedPacketsTiming = AddStatItem("Processed Packets Timing"); @@ -155,6 +156,8 @@ void OctreeStatsDialog::paintEvent(QPaintEvent* event) { if (sinceLastRefresh < REFRESH_AFTER) { return QDialog::paintEvent(event); } + const int FLOATING_POINT_PRECISION = 3; + _lastRefresh = now; // Update labels @@ -245,7 +248,6 @@ void OctreeStatsDialog::paintEvent(QPaintEvent* event) { auto averageElementsPerPacket = entities->getAverageElementsPerPacket(); auto averageEntitiesPerPacket = entities->getAverageEntitiesPerPacket(); - auto averagePacketsPerSecond = entities->getAveragePacketsPerSecond(); auto averageElementsPerSecond = entities->getAverageElementsPerSecond(); auto averageEntitiesPerSecond = entities->getAverageEntitiesPerSecond(); @@ -253,21 +255,32 @@ void OctreeStatsDialog::paintEvent(QPaintEvent* event) { auto averageUncompressPerPacket = entities->getAverageUncompressPerPacket(); auto averageReadBitstreamPerPacket = entities->getAverageReadBitstreamPerPacket(); - QString averageElementsPerPacketString = locale.toString(averageElementsPerPacket); - QString averageEntitiesPerPacketString = locale.toString(averageEntitiesPerPacket); + QString averageElementsPerPacketString = locale.toString(averageElementsPerPacket, 'f', FLOATING_POINT_PRECISION); + QString averageEntitiesPerPacketString = locale.toString(averageEntitiesPerPacket, 'f', FLOATING_POINT_PRECISION); - QString averagePacketsPerSecondString = locale.toString(averagePacketsPerSecond); - QString averageElementsPerSecondString = locale.toString(averageElementsPerSecond); - QString averageEntitiesPerSecondString = locale.toString(averageEntitiesPerSecond); + QString averageElementsPerSecondString = locale.toString(averageElementsPerSecond, 'f', FLOATING_POINT_PRECISION); + QString averageEntitiesPerSecondString = locale.toString(averageEntitiesPerSecond, 'f', FLOATING_POINT_PRECISION); QString averageWaitLockPerPacketString = locale.toString(averageWaitLockPerPacket); QString averageUncompressPerPacketString = locale.toString(averageUncompressPerPacket); QString averageReadBitstreamPerPacketString = locale.toString(averageReadBitstreamPerPacket); label = _labels[_processedPackets]; + const OctreePacketProcessor& entitiesPacketProcessor = Application::getInstance()->getOctreePacketProcessor(); + + auto incomingPPS = entitiesPacketProcessor.getIncomingPPS(); + auto processedPPS = entitiesPacketProcessor.getProcessedPPS(); + auto treeProcessedPPS = entities->getAveragePacketsPerSecond(); + + QString incomingPPSString = locale.toString(incomingPPS, 'f', FLOATING_POINT_PRECISION); + QString processedPPSString = locale.toString(processedPPS, 'f', FLOATING_POINT_PRECISION); + QString treeProcessedPPSString = locale.toString(treeProcessedPPS, 'f', FLOATING_POINT_PRECISION); + statsValue.str(""); statsValue << - "" << qPrintable(averagePacketsPerSecondString) << " per second"; + "Network IN: " << qPrintable(incomingPPSString) << " PPS / " << + "Queue OUT: " << qPrintable(processedPPSString) << " PPS / " << + "Tree IN: " << qPrintable(treeProcessedPPSString) << " PPS"; label->setText(statsValue.str().c_str()); @@ -321,7 +334,7 @@ void OctreeStatsDialog::paintEvent(QPaintEvent* event) { } QString totalTrackedEditsString = locale.toString((uint)totalTrackedEdits); - QString updatesPerSecondString = locale.toString(updatesPerSecond); + QString updatesPerSecondString = locale.toString(updatesPerSecond, 'f', FLOATING_POINT_PRECISION); QString bytesPerEditString = locale.toString(bytesPerEdit); statsValue.str(""); diff --git a/libraries/networking/src/ReceivedPacketProcessor.cpp b/libraries/networking/src/ReceivedPacketProcessor.cpp index 3c4b32b4ec..94dd04d44b 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.cpp +++ b/libraries/networking/src/ReceivedPacketProcessor.cpp @@ -9,10 +9,17 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "NodeList.h" #include "ReceivedPacketProcessor.h" #include "SharedUtil.h" +ReceivedPacketProcessor::ReceivedPacketProcessor() { + _lastWindowAt = usecTimestampNow(); +} + + void ReceivedPacketProcessor::terminating() { _hasPackets.wakeAll(); } @@ -25,6 +32,7 @@ void ReceivedPacketProcessor::queueReceivedPacket(const SharedNodePointer& sendi lock(); _packets.push_back(networkPacket); _nodePacketCounts[sendingNode->getUUID()]++; + _lastWindowIncomingPackets++; unlock(); // Make sure to wake our actual processing thread because we now have packets for it to process. @@ -32,6 +40,24 @@ void ReceivedPacketProcessor::queueReceivedPacket(const SharedNodePointer& sendi } bool ReceivedPacketProcessor::process() { + quint64 now = usecTimestampNow(); + quint64 sinceLastWindow = now - _lastWindowAt; + + + if (sinceLastWindow > USECS_PER_SECOND) { + lock(); + float secondsSinceLastWindow = sinceLastWindow / USECS_PER_SECOND; + float incomingPacketsPerSecondInWindow = (float)_lastWindowIncomingPackets / secondsSinceLastWindow; + _incomingPPS.updateAverage(incomingPacketsPerSecondInWindow); + + float processedPacketsPerSecondInWindow = (float)_lastWindowIncomingPackets / secondsSinceLastWindow; + _processedPPS.updateAverage(processedPacketsPerSecondInWindow); + + _lastWindowAt = now; + _lastWindowIncomingPackets = 0; + _lastWindowProcessedPackets = 0; + unlock(); + } if (_packets.size() == 0) { _waitingOnPacketsMutex.lock(); @@ -51,6 +77,7 @@ bool ReceivedPacketProcessor::process() { foreach(auto& packet, currentPackets) { processPacket(packet.getNode(), packet.getByteArray()); + _lastWindowProcessedPackets++; midProcess(); } diff --git a/libraries/networking/src/ReceivedPacketProcessor.h b/libraries/networking/src/ReceivedPacketProcessor.h index bcc9f9a1f5..84a954760c 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.h +++ b/libraries/networking/src/ReceivedPacketProcessor.h @@ -21,7 +21,7 @@ class ReceivedPacketProcessor : public GenericThread { Q_OBJECT public: - ReceivedPacketProcessor() { } + ReceivedPacketProcessor(); /// Add packet from network receive thread to the processing queue. void queueReceivedPacket(const SharedNodePointer& sendingNode, const QByteArray& packet); @@ -47,6 +47,9 @@ public: /// How many received packets waiting are to be processed int packetsToProcessCount() const { return _packets.size(); } + float getIncomingPPS() const { return _incomingPPS.getAverage(); } + float getProcessedPPS() const { return _processedPPS.getAverage(); } + virtual void terminating(); public slots: @@ -80,6 +83,12 @@ protected: QWaitCondition _hasPackets; QMutex _waitingOnPacketsMutex; + + quint64 _lastWindowAt = 0; + int _lastWindowIncomingPackets = 0; + int _lastWindowProcessedPackets = 0; + SimpleMovingAverage _incomingPPS; + SimpleMovingAverage _processedPPS; }; #endif // hifi_ReceivedPacketProcessor_h From 687f9dda4a20c2d3041f1e8a6fbe6b08cc3c78c4 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 6 Jul 2015 18:21:17 -0700 Subject: [PATCH 13/14] Restore old offset behaviors --- interface/src/avatar/Avatar.cpp | 7 ++++++- interface/src/ui/overlays/Text3DOverlay.cpp | 6 ++++-- .../entities-renderer/src/RenderableTextEntityItem.cpp | 5 +++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index a5fa7d3c82..3525109766 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -750,6 +750,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum) co const int text_y = -nameDynamicRect.height() / 2; // Compute background position/size + static const float SLIGHTLY_IN_FRONT = 0.05f; const int border = 0.1f * nameDynamicRect.height(); const int left = text_x - border; const int bottom = text_y - border; @@ -765,12 +766,16 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum) co // Compute display name transform auto textTransform = calculateDisplayNameTransform(frustum, renderer->getFontSize()); batch.setModelTransform(textTransform); - + DependencyManager::get()->bindSimpleProgram(batch, false, true, true, true); DependencyManager::get()->renderBevelCornersRect(batch, left, bottom, width, height, bevelDistance, backgroundColor); // Render actual name QByteArray nameUTF8 = renderedDisplayName.toLocal8Bit(); + + // Render text slightly in front to avoid z-fighting + textTransform.postTranslate(glm::vec3(0.0f, 0.0f, SLIGHTLY_IN_FRONT * renderer->getFontSize())); + batch.setModelTransform(textTransform); renderer->draw(batch, text_x, -text_y, nameUTF8.data(), textColor); } diff --git a/interface/src/ui/overlays/Text3DOverlay.cpp b/interface/src/ui/overlays/Text3DOverlay.cpp index 9ee0a90a89..17dc8d03a8 100644 --- a/interface/src/ui/overlays/Text3DOverlay.cpp +++ b/interface/src/ui/overlays/Text3DOverlay.cpp @@ -111,8 +111,10 @@ void Text3DOverlay::render(RenderArgs* args) { glm::vec2 dimensions = getDimensions(); glm::vec2 halfDimensions = dimensions * 0.5f; - glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, 0.0f); - glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, 0.0f); + const float SLIGHTLY_BEHIND = -0.005f; + + glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, SLIGHTLY_BEHIND); + glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, SLIGHTLY_BEHIND); DependencyManager::get()->bindSimpleProgram(batch, false, true, false, true); DependencyManager::get()->renderQuad(batch, topLeft, bottomRight, quadColor); diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index c768bc521c..0c9b36dd87 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -31,13 +31,14 @@ void RenderableTextEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RenderableTextEntityItem::render"); Q_ASSERT(getType() == EntityTypes::Text); + static const float SLIGHTLY_BEHIND = -0.005f; glm::vec4 textColor = glm::vec4(toGlm(getTextColorX()), 1.0f); glm::vec4 backgroundColor = glm::vec4(toGlm(getBackgroundColorX()), 1.0f); glm::vec3 dimensions = getDimensions(); // Render background - glm::vec3 minCorner = glm::vec3(0.0f, -dimensions.y, 0.0f); - glm::vec3 maxCorner = glm::vec3(dimensions.x, 0.0f, 0.0f); + glm::vec3 minCorner = glm::vec3(0.0f, -dimensions.y, SLIGHTLY_BEHIND); + glm::vec3 maxCorner = glm::vec3(dimensions.x, 0.0f, SLIGHTLY_BEHIND); // Batch render calls From 2ba6bd3afcb873d81488c5103d9fc48336f05580 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 6 Jul 2015 18:39:43 -0700 Subject: [PATCH 14/14] Double display name offset --- interface/src/avatar/Avatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 3525109766..3d4c158a0b 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -750,7 +750,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum) co const int text_y = -nameDynamicRect.height() / 2; // Compute background position/size - static const float SLIGHTLY_IN_FRONT = 0.05f; + static const float SLIGHTLY_IN_FRONT = 0.1f; const int border = 0.1f * nameDynamicRect.height(); const int left = text_x - border; const int bottom = text_y - border;