From 2bfbf1b5fd848ed548492a30504c2ec6523d4a4b Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 18 Feb 2016 11:30:03 -0800 Subject: [PATCH 01/25] Reimplement renderGrid to use frag shader --- libraries/render-utils/src/GeometryCache.cpp | 216 ++++--------------- libraries/render-utils/src/GeometryCache.h | 28 ++- libraries/render-utils/src/grid.slf | 58 +++++ 3 files changed, 123 insertions(+), 179 deletions(-) create mode 100644 libraries/render-utils/src/grid.slf diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index ed6b8f2f5b..b5e09d0539 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -22,17 +22,19 @@ #include "TextureCache.h" #include "RenderUtilsLogging.h" -#include "standardTransformPNTC_vert.h" -#include "standardDrawTexture_frag.h" - #include "gpu/StandardShaderLib.h" #include "model/TextureMap.h" +#include "standardTransformPNTC_vert.h" +#include "standardDrawTexture_frag.h" + #include "simple_vert.h" #include "simple_textured_frag.h" #include "simple_textured_emisive_frag.h" +#include "grid_frag.h" + //#define WANT_DEBUG const int GeometryCache::UNKNOWN_ID = -1; @@ -564,186 +566,42 @@ void GeometryCache::renderWireSphere(gpu::Batch& batch) { renderWireShape(batch, Sphere); } +void GeometryCache::renderGrid(gpu::Batch& batch, + const glm::vec2& minCorner, const glm::vec2& maxCorner, + int rows, int cols, const glm::vec4& color, float edge, int id) { + static const glm::vec2 minTexCoord(0.0f, 1.0f); + static const glm::vec2 maxTexCoord(1.0f, 0.0f); -void GeometryCache::renderGrid(gpu::Batch& batch, int xDivisions, int yDivisions, const glm::vec4& color) { - IntPair key(xDivisions, yDivisions); - Vec3Pair colorKey(glm::vec3(color.x, color.y, yDivisions), glm::vec3(color.z, color.y, xDivisions)); - - int vertices = (xDivisions + 1 + yDivisions + 1) * 2; - if (!_gridBuffers.contains(key)) { - auto verticesBuffer = std::make_shared(); - - float* vertexData = new float[vertices * 2]; - float* vertex = vertexData; - - for (int i = 0; i <= xDivisions; i++) { - float x = (float)i / xDivisions; - - *(vertex++) = x; - *(vertex++) = 0.0f; - - *(vertex++) = x; - *(vertex++) = 1.0f; - } - for (int i = 0; i <= yDivisions; i++) { - float y = (float)i / yDivisions; - - *(vertex++) = 0.0f; - *(vertex++) = y; - - *(vertex++) = 1.0f; - *(vertex++) = y; - } - - verticesBuffer->append(sizeof(float) * vertices * 2, (gpu::Byte*) vertexData); - delete[] vertexData; - - _gridBuffers[key] = verticesBuffer; - } - - if (!_gridColors.contains(colorKey)) { - auto colorBuffer = std::make_shared(); - _gridColors[colorKey] = colorBuffer; - - int compactColor = ((int(color.x * 255.0f) & 0xFF)) | - ((int(color.y * 255.0f) & 0xFF) << 8) | - ((int(color.z * 255.0f) & 0xFF) << 16) | - ((int(color.w * 255.0f) & 0xFF) << 24); - - int* colorData = new int[vertices]; - int* colorDataAt = colorData; - - for(int v = 0; v < vertices; v++) { - *(colorDataAt++) = compactColor; - } - - colorBuffer->append(sizeof(int) * vertices, (gpu::Byte*) colorData); - delete[] colorData; - } - gpu::BufferPointer verticesBuffer = _gridBuffers[key]; - gpu::BufferPointer colorBuffer = _gridColors[colorKey]; - - const int VERTICES_SLOT = 0; - const int COLOR_SLOT = 1; - auto streamFormat = std::make_shared(); // 1 for everyone - - streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0); - streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); - - gpu::BufferView verticesView(verticesBuffer, 0, verticesBuffer->getSize(), streamFormat->getAttributes().at(gpu::Stream::POSITION)._element); - gpu::BufferView colorView(colorBuffer, streamFormat->getAttributes().at(gpu::Stream::COLOR)._element); - - batch.setInputFormat(streamFormat); - batch.setInputBuffer(VERTICES_SLOT, verticesView); - batch.setInputBuffer(COLOR_SLOT, colorView); - batch.draw(gpu::LINES, vertices, 0); -} - -// TODO: why do we seem to create extra BatchItemDetails when we resize the window?? what's that?? -void GeometryCache::renderGrid(gpu::Batch& batch, int x, int y, int width, int height, int rows, int cols, const glm::vec4& color, int id) { - #ifdef WANT_DEBUG - qCDebug(renderutils) << "GeometryCache::renderGrid(x["<(sizeof(GridSchema), (const gpu::Byte*) &gridSchema); - if (registered && _registeredAlternateGridBuffers.contains(id)) { - _registeredAlternateGridBuffers[id].reset(); - #ifdef WANT_DEBUG - qCDebug(renderutils) << "renderGrid()... RELEASING REGISTERED VERTICES BUFFER"; - #endif + if (registered && _registeredGridBuffers.contains(id)) { + gridBuffer = _registeredGridBuffers[id]; } - auto verticesBuffer = std::make_shared(); if (registered) { - _registeredAlternateGridBuffers[id] = verticesBuffer; - _lastRegisteredAlternateGridBuffers[id] = key; + _registeredGridBuffers[id] = gridBuffer; + _lastRegisteredGridBuffer[id] = key; } else { - _alternateGridBuffers[key] = verticesBuffer; + _gridBuffers[key] = gridBuffer; } - float* vertexData = new float[vertices * 2]; - float* vertex = vertexData; - - int dx = width / cols; - int dy = height / rows; - int tx = x; - int ty = y; - - // Draw horizontal grid lines - for (int i = rows + 1; --i >= 0; ) { - *(vertex++) = x; - *(vertex++) = ty; - - *(vertex++) = x + width; - *(vertex++) = ty; - - ty += dy; - } - // Draw vertical grid lines - for (int i = cols + 1; --i >= 0; ) { - *(vertex++) = tx; - *(vertex++) = y; - - *(vertex++) = tx; - *(vertex++) = y + height; - tx += dx; - } - - verticesBuffer->append(sizeof(float) * vertices * 2, (gpu::Byte*) vertexData); - delete[] vertexData; + gridBuffer.edit().period = glm::vec2(cols, rows); + gridBuffer.edit().offset.x = -(edge / cols) / 2; + gridBuffer.edit().offset.y = -(edge / rows) / 2; + gridBuffer.edit().balance = glm::vec2(1 - edge); } - if (!_gridColors.contains(colorKey)) { - auto colorBuffer = std::make_shared(); - _gridColors[colorKey] = colorBuffer; + // Set the grid pipeline + useGridPipeline(batch, registered ? _registeredGridBuffers[id] : _gridBuffers[key]); - int compactColor = ((int(color.x * 255.0f) & 0xFF)) | - ((int(color.y * 255.0f) & 0xFF) << 8) | - ((int(color.z * 255.0f) & 0xFF) << 16) | - ((int(color.w * 255.0f) & 0xFF) << 24); - - int* colorData = new int[vertices]; - int* colorDataAt = colorData; - - - for(int v = 0; v < vertices; v++) { - *(colorDataAt++) = compactColor; - } - - colorBuffer->append(sizeof(int) * vertices, (gpu::Byte*) colorData); - delete[] colorData; - } - gpu::BufferPointer verticesBuffer = registered ? _registeredAlternateGridBuffers[id] : _alternateGridBuffers[key]; - - gpu::BufferPointer colorBuffer = _gridColors[colorKey]; - - const int VERTICES_SLOT = 0; - const int COLOR_SLOT = 1; - auto streamFormat = std::make_shared(); // 1 for everyone - - streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0); - streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); - - gpu::BufferView verticesView(verticesBuffer, 0, verticesBuffer->getSize(), streamFormat->getAttributes().at(gpu::Stream::POSITION)._element); - gpu::BufferView colorView(colorBuffer, streamFormat->getAttributes().at(gpu::Stream::COLOR)._element); - - batch.setInputFormat(streamFormat); - batch.setInputBuffer(VERTICES_SLOT, verticesView); - batch.setInputBuffer(COLOR_SLOT, colorView); - batch.draw(gpu::LINES, vertices, 0); + renderQuad(batch, minCorner, maxCorner, minTexCoord, maxTexCoord, color, id); } void GeometryCache::updateVertices(int id, const QVector& points, const glm::vec4& color) { @@ -1772,7 +1630,6 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) { auto state = std::make_shared(); - // enable decal blend state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); @@ -1792,6 +1649,23 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) { } } +void GeometryCache::useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer) { + if (!_gridPipeline) { + auto vs = gpu::Shader::createVertex(std::string(standardTransformPNTC_vert)); + auto ps = gpu::Shader::createPixel(std::string(grid_frag)); + auto program = gpu::Shader::createProgram(vs, ps); + gpu::Shader::makeProgram((*program)); + + auto state = std::make_shared(); + state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); + + _gridPipeline = gpu::Pipeline::create(program, state); + _gridSlot = program->getBuffers().findLocation("gridBuffer"); + } + batch.setPipeline(_gridPipeline); + batch.setUniformBuffer(_gridSlot, gridBuffer); +} + class SimpleProgramKey { diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index 32cdec56bf..1eddb62253 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -32,7 +32,7 @@ class SimpleProgramKey; typedef glm::vec3 Vec3Key; - +typedef QPair Vec2FloatPair; typedef QPair Vec2Pair; typedef QPair Vec2PairPair; typedef QPair Vec3Pair; @@ -203,8 +203,10 @@ public: void renderWireSphere(gpu::Batch& batch); size_t getSphereTriangleCount(); - void renderGrid(gpu::Batch& batch, int xDivisions, int yDivisions, const glm::vec4& color); - void renderGrid(gpu::Batch& batch, int x, int y, int width, int height, int rows, int cols, const glm::vec4& color, int id = UNKNOWN_ID); + void renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner, int rows, int cols, const glm::vec4& color, float edge = 0.01f, int id = UNKNOWN_ID); + void renderGrid(gpu::Batch& batch, int x, int y, int width, int height, int rows, int cols, const glm::vec4& color, float edge = 0.01f, int id = UNKNOWN_ID) { + renderGrid(batch, glm::vec2(x, y), glm::vec2(x + width, y + height), rows, cols, color, edge, id); + } void renderBevelCornersRect(gpu::Batch& batch, int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id = UNKNOWN_ID); @@ -310,6 +312,18 @@ private: gpu::BufferPointer _shapeVertices{ std::make_shared() }; gpu::BufferPointer _shapeIndices{ std::make_shared() }; + class GridSchema { + public: + glm::vec2 period; + glm::vec2 offset; + glm::vec2 balance; + glm::vec2 _; + }; + using GridBuffer = gpu::BufferView; + void useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer); + gpu::PipelinePointer _gridPipeline; + int _gridSlot; + class BatchItemDetails { public: static int population; @@ -366,11 +380,9 @@ private: QHash _dashedLines; QHash _registeredDashedLines; - QHash _gridBuffers; - QHash _alternateGridBuffers; - QHash _registeredAlternateGridBuffers; - QHash _lastRegisteredAlternateGridBuffers; - QHash _gridColors; + QHash _lastRegisteredGridBuffer; + QHash _gridBuffers; + QHash _registeredGridBuffers; QHash > _networkGeometry; diff --git a/libraries/render-utils/src/grid.slf b/libraries/render-utils/src/grid.slf new file mode 100644 index 0000000000..d835d4bbde --- /dev/null +++ b/libraries/render-utils/src/grid.slf @@ -0,0 +1,58 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// grid.slf +// fragment shader +// +// Created by Zach Pomerantz on 2/16/2016. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +float paintStripe(float value, float offset, float scale, float balance) { + float width = fwidth(value); + float normalizedWidth = width * scale; + + float x0 = (value + offset) * scale - normalizedWidth / 2; + float x1 = x0 + normalizedWidth; + + float i0 = balance * floor(x0) + max(0.0, fract(x0) - balance); + float i1 = balance * floor(x1) + max(0.0, fract(x1) - balance); + float strip = (i1 - i0) / normalizedWidth; + + return clamp(strip, 0.0, 1.0); +} + +float paintGrid(vec2 value, vec2 offset, vec2 scale, vec2 balance) { + return max( + paintStripe(value.x, offset.x, scale.x, balance.x), + paintStripe(value.y, offset.y, scale.y, balance.y)); +} + +struct Grid { + vec2 period; + vec2 offset; + vec2 balance; + vec2 _; +}; + +uniform gridBuffer { Grid grid; }; +Grid getGrid() { return grid; }; + +in vec2 varTexCoord0; +in vec4 varColor; + +out vec4 outFragColor; + +void main(void) { + Grid grid = getGrid(); + + float alpha = paintGrid(varTexCoord0, grid.offset, grid.period, grid.balance); + if (alpha == 0.0) { + discard; + } + + outFragColor = vec4(varColor.xyz, varColor.w * alpha); +} From f79fc30b835637d8bc9472f5397be5277f307422 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 18 Feb 2016 11:30:53 -0800 Subject: [PATCH 02/25] Update audioscope to use new renderGrid --- interface/src/audio/AudioScope.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/interface/src/audio/AudioScope.cpp b/interface/src/audio/AudioScope.cpp index d0567c55d7..b62dcf5f28 100644 --- a/interface/src/audio/AudioScope.cpp +++ b/interface/src/audio/AudioScope.cpp @@ -127,6 +127,10 @@ void AudioScope::render(RenderArgs* renderArgs, int width, int height) { gpu::Batch& batch = *renderArgs->_batch; auto geometryCache = DependencyManager::get(); + + // Grid uses its own pipeline + geometryCache->renderGrid(batch, x, y, w, h, gridRows, gridCols, gridColor, 0.005f, _audioScopeGrid); + geometryCache->useSimpleDrawPipeline(batch); auto textureCache = DependencyManager::get(); batch.setResourceTexture(0, textureCache->getWhiteTexture()); @@ -139,7 +143,6 @@ void AudioScope::render(RenderArgs* renderArgs, int width, int height) { batch.setViewTransform(Transform()); geometryCache->renderQuad(batch, x, y, w, h, backgroundColor, _audioScopeBackground); - geometryCache->renderGrid(batch, x, y, w, h, gridRows, gridCols, gridColor, _audioScopeGrid); renderLineStrip(batch, _inputID, inputColor, x, y, _samplesPerScope, _scopeInputOffset, _scopeInput); renderLineStrip(batch, _outputLeftID, outputLeftColor, x, y, _samplesPerScope, _scopeOutputOffset, _scopeOutputLeft); renderLineStrip(batch, _outputRightD, outputRightColor, x, y, _samplesPerScope, _scopeOutputOffset, _scopeOutputRight); From 0c1353e6cc665c6a855b12d2cd01dfe9f45ad8d6 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 18 Feb 2016 14:37:35 -0800 Subject: [PATCH 03/25] Update grid overlay to use new renderGrid, sane properties --- interface/src/ui/overlays/Grid3DOverlay.cpp | 111 +++++++++++--------- interface/src/ui/overlays/Grid3DOverlay.h | 13 ++- 2 files changed, 70 insertions(+), 54 deletions(-) diff --git a/interface/src/ui/overlays/Grid3DOverlay.cpp b/interface/src/ui/overlays/Grid3DOverlay.cpp index fca6a3796a..282595907e 100644 --- a/interface/src/ui/overlays/Grid3DOverlay.cpp +++ b/interface/src/ui/overlays/Grid3DOverlay.cpp @@ -13,6 +13,9 @@ #include +#include +#include + #include #include #include @@ -20,17 +23,19 @@ QString const Grid3DOverlay::TYPE = "grid"; +const float DEFAULT_SCALE = 100.0f; -Grid3DOverlay::Grid3DOverlay() : - _minorGridWidth(1.0), - _majorGridEvery(5) { +Grid3DOverlay::Grid3DOverlay() { + setDimensions(DEFAULT_SCALE); + updateGrid(); } Grid3DOverlay::Grid3DOverlay(const Grid3DOverlay* grid3DOverlay) : Planar3DOverlay(grid3DOverlay), - _minorGridWidth(grid3DOverlay->_minorGridWidth), - _majorGridEvery(grid3DOverlay->_majorGridEvery) + _majorGridEvery(grid3DOverlay->_majorGridEvery), + _minorGridEvery(grid3DOverlay->_minorGridEvery) { + updateGrid(); } void Grid3DOverlay::render(RenderArgs* args) { @@ -38,15 +43,8 @@ void Grid3DOverlay::render(RenderArgs* args) { return; // do nothing if we're not visible } - const int MINOR_GRID_DIVISIONS = 200; - const int MAJOR_GRID_DIVISIONS = 100; const float MAX_COLOR = 255.0f; - // center the grid around the camera position on the plane - glm::vec3 rotated = glm::inverse(getRotation()) * args->_viewFrustum->getPosition(); - - float spacing = _minorGridWidth; - float alpha = getAlpha(); xColor color = getColor(); glm::vec4 gridColor(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha); @@ -54,72 +52,68 @@ void Grid3DOverlay::render(RenderArgs* args) { auto batch = args->_batch; if (batch) { + auto minCorner = glm::vec2(-0.5f, -0.5f); + auto maxCorner = glm::vec2(0.5f, 0.5f); + + auto position = getPosition(); + if (_followCamera) { + auto avatar = DependencyManager::get()->getMyAvatar(); + + // Add the camera position at the plane of the avatar's base (the floor) + auto cameraPosition = args->_viewFrustum->getPosition(); + auto avatarBaseHeight = avatar->getPosition().y - avatar->getUniformScale(); + position += glm::vec3(cameraPosition.x, avatarBaseHeight, cameraPosition.z); + } + Transform transform; transform.setRotation(getRotation()); - + transform.setScale(glm::vec3(getDimensions(), 1.0f)); + transform.setTranslation(position); + batch->setModelTransform(transform); // Minor grid - { - auto position = glm::vec3(_minorGridWidth * (floorf(rotated.x / spacing) - MINOR_GRID_DIVISIONS / 2), - spacing * (floorf(rotated.y / spacing) - MINOR_GRID_DIVISIONS / 2), - getPosition().z); - float scale = MINOR_GRID_DIVISIONS * spacing; - - transform.setTranslation(position); - transform.setScale(scale); - - batch->setModelTransform(transform); - - DependencyManager::get()->renderGrid(*batch, MINOR_GRID_DIVISIONS, MINOR_GRID_DIVISIONS, gridColor); - } + const float MINOR_GRID_EDGE = 0.0025f; + DependencyManager::get()->renderGrid(*batch, + minCorner, maxCorner, _minorGridRowDivisions, _minorGridColDivisions, gridColor, MINOR_GRID_EDGE); // Major grid - { - spacing *= _majorGridEvery; - auto position = glm::vec3(spacing * (floorf(rotated.x / spacing) - MAJOR_GRID_DIVISIONS / 2), - spacing * (floorf(rotated.y / spacing) - MAJOR_GRID_DIVISIONS / 2), - getPosition().z); - float scale = MAJOR_GRID_DIVISIONS * spacing; - - transform.setTranslation(position); - transform.setScale(scale); - - // FIXME: THe line width of 4.0f is not supported anymore, we ll need a workaround - - batch->setModelTransform(transform); - - DependencyManager::get()->renderGrid(*batch, MAJOR_GRID_DIVISIONS, MAJOR_GRID_DIVISIONS, gridColor); - } + const float MAJOR_GRID_EDGE = 0.01f; + DependencyManager::get()->renderGrid(*batch, + minCorner, maxCorner, _majorGridRowDivisions, _majorGridColDivisions, gridColor, MAJOR_GRID_EDGE); } } const render::ShapeKey Grid3DOverlay::getShapeKey() { - auto builder = render::ShapeKey::Builder(); - if (getAlpha() != 1.0f) { - builder.withTranslucent(); - } - return builder.build(); + return render::ShapeKey::Builder().withTranslucent(); } void Grid3DOverlay::setProperties(const QScriptValue& properties) { Planar3DOverlay::setProperties(properties); - - if (properties.property("minorGridWidth").isValid()) { - _minorGridWidth = properties.property("minorGridWidth").toVariant().toFloat(); + if (properties.property("followCamera").isValid()) { + _followCamera = properties.property("followCamera").toVariant().toBool(); } if (properties.property("majorGridEvery").isValid()) { _majorGridEvery = properties.property("majorGridEvery").toVariant().toInt(); } + + if (properties.property("minorGridEvery").isValid()) { + _minorGridEvery = properties.property("minorGridEvery").toVariant().toFloat(); + } + + updateGrid(); } QScriptValue Grid3DOverlay::getProperty(const QString& property) { - if (property == "minorGridWidth") { - return _minorGridWidth; + if (property == "followCamera") { + return _followCamera; } if (property == "majorGridEvery") { return _majorGridEvery; } + if (property == "minorGridEvery") { + return _minorGridEvery; + } return Planar3DOverlay::getProperty(property); } @@ -128,3 +122,16 @@ Grid3DOverlay* Grid3DOverlay::createClone() const { return new Grid3DOverlay(this); } +void Grid3DOverlay::updateGrid() { + const int MAJOR_GRID_EVERY_MIN = 5; + const float MINOR_GRID_EVERY_MIN = 0.2f; + + _majorGridEvery = std::max(_majorGridEvery, MAJOR_GRID_EVERY_MIN); + _minorGridEvery = std::max(_minorGridEvery, MINOR_GRID_EVERY_MIN); + + _majorGridRowDivisions = getDimensions().x / _majorGridEvery; + _majorGridColDivisions = getDimensions().y / _majorGridEvery; + + _minorGridRowDivisions = getDimensions().x / _minorGridEvery; + _minorGridColDivisions = getDimensions().y / _minorGridEvery; +} diff --git a/interface/src/ui/overlays/Grid3DOverlay.h b/interface/src/ui/overlays/Grid3DOverlay.h index f9744f3954..146fe79621 100644 --- a/interface/src/ui/overlays/Grid3DOverlay.h +++ b/interface/src/ui/overlays/Grid3DOverlay.h @@ -32,8 +32,17 @@ public: virtual Grid3DOverlay* createClone() const; private: - float _minorGridWidth; - int _majorGridEvery; + void updateGrid(); + + bool _followCamera { true }; + + int _majorGridEvery { 5 }; + float _majorGridRowDivisions; + float _majorGridColDivisions; + + float _minorGridEvery { 1.0f }; + float _minorGridRowDivisions; + float _minorGridColDivisions; }; #endif // hifi_Grid3DOverlay_h From b68213f9bf7637eea226ad17668770813c33ed15 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 18 Feb 2016 14:44:15 -0800 Subject: [PATCH 04/25] Reintroduce grid to edit.js --- examples/edit.js | 8 ++++-- examples/html/gridControls.html | 10 ++++---- examples/libraries/gridTool.js | 45 +++++++++++++++------------------ 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index b2e52eee20..50a66ea31f 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -38,6 +38,10 @@ var lightOverlayManager = new LightOverlayManager(); var cameraManager = new CameraManager(); var grid = Grid(); +gridTool = GridTool({ + horizontalGrid: grid +}); +gridTool.setVisible(false); var entityListTool = EntityListTool(); @@ -341,7 +345,7 @@ var toolBar = (function() { isActive = active; if (!isActive) { entityListTool.setVisible(false); - // gridTool.setVisible(false); + gridTool.setVisible(false); grid.setEnabled(false); propertiesTool.setVisible(false); selectionManager.clearSelections(); @@ -349,7 +353,7 @@ var toolBar = (function() { } else { hasShownPropertiesTool = false; entityListTool.setVisible(true); - // gridTool.setVisible(true); + gridTool.setVisible(true); grid.setEnabled(true); propertiesTool.setVisible(true); Window.setFocus(); diff --git a/examples/html/gridControls.html b/examples/html/gridControls.html index 1a3e949446..204e50c1a7 100644 --- a/examples/html/gridControls.html +++ b/examples/html/gridControls.html @@ -33,8 +33,8 @@ elPosY.value = origin.y.toFixed(2); } - if (data.minorGridWidth !== undefined) { - elMinorSpacing.value = data.minorGridWidth; + if (data.minorGridEvery !== undefined) { + elMinorSpacing.value = data.minorGridEvery; } if (data.majorGridEvery !== undefined) { @@ -60,7 +60,7 @@ origin: { y: elPosY.value, }, - minorGridWidth: elMinorSpacing.value, + minorGridEvery: elMinorSpacing.value, majorGridEvery: elMajorSpacing.value, gridColor: gridColor, colorIndex: gridColorIndex, @@ -132,14 +132,14 @@
- +
- +
diff --git a/examples/libraries/gridTool.js b/examples/libraries/gridTool.js index 54f80e9c96..04e8b48f1d 100644 --- a/examples/libraries/gridTool.js +++ b/examples/libraries/gridTool.js @@ -13,23 +13,24 @@ Grid = function(opts) { var colorIndex = 0; var gridAlpha = 0.6; var origin = { x: 0, y: 0, z: 0 }; + var scale = 500; + var minorGridEvery = 1.0; var majorGridEvery = 5; - var minorGridWidth = 0.2; var halfSize = 40; - var yOffset = 0.001; var worldSize = 16384; var snapToGrid = false; var gridOverlay = Overlays.addOverlay("grid", { - position: { x: 0 , y: 0, z: 0 }, - visible: true, + dimensions: { x: scale, y: scale, z: scale }, + visible: false, + drawInFront: true, color: colors[0], alpha: gridAlpha, rotation: Quat.fromPitchYawRollDegrees(90, 0, 0), - minorGridWidth: 0.1, - majorGridEvery: 2, + minorGridEvery: minorGridEvery, + majorGridEvery: majorGridEvery, }); that.visible = false; @@ -39,17 +40,13 @@ Grid = function(opts) { return origin; } - that.getMinorIncrement = function() { return minorGridWidth; }; - that.getMajorIncrement = function() { return minorGridWidth * majorGridEvery; }; - - that.getMinorGridWidth = function() { return minorGridWidth; }; - that.setMinorGridWidth = function(value) { - minorGridWidth = value; + that.getMinorIncrement = function() { return minorGridEvery; }; + that.setMinorIncrement = function(value) { + minorGridEvery = value; updateGrid(); - }; - - that.getMajorGridEvery = function() { return majorGridEvery; }; - that.setMajorGridEvery = function(value) { + } + that.getMajorIncrement = function() { return majorGridEvery; }; + that.setMajorIncrement = function(value) { majorGridEvery = value; updateGrid(); }; @@ -106,7 +103,7 @@ Grid = function(opts) { dimensions = { x: 0, y: 0, z: 0 }; } - var spacing = majorOnly ? (minorGridWidth * majorGridEvery) : minorGridWidth; + var spacing = majorOnly ? majorGridEvery : minorGridEvery; position = Vec3.subtract(position, origin); @@ -122,7 +119,7 @@ Grid = function(opts) { return delta; } - var spacing = majorOnly ? (minorGridWidth * majorGridEvery) : minorGridWidth; + var spacing = majorOnly ? majorGridEvery : minorGridEvery; var snappedDelta = { x: Math.round(delta.x / spacing) * spacing, @@ -135,7 +132,7 @@ Grid = function(opts) { that.setPosition = function(newPosition, noUpdate) { - origin = Vec3.subtract(newPosition, { x: 0, y: yOffset, z: 0 }); + origin = newPosition; origin.x = 0; origin.z = 0; updateGrid(); @@ -149,7 +146,7 @@ Grid = function(opts) { if (that.onUpdate) { that.onUpdate({ origin: origin, - minorGridWidth: minorGridWidth, + minorGridEvery: minorGridEvery, majorGridEvery: majorGridEvery, gridSize: halfSize, visible: that.visible, @@ -171,8 +168,8 @@ Grid = function(opts) { that.setPosition(pos, true); } - if (data.minorGridWidth) { - minorGridWidth = data.minorGridWidth; + if (data.minorGridEvery) { + minorGridEvery = data.minorGridEvery; } if (data.majorGridEvery) { @@ -196,9 +193,9 @@ Grid = function(opts) { function updateGrid() { Overlays.editOverlay(gridOverlay, { - position: { x: origin.y, y: origin.y, z: -origin.y }, + position: { x: 0, y: origin.y, z: 0 }, visible: that.visible && that.enabled, - minorGridWidth: minorGridWidth, + minorGridEvery: minorGridEvery, majorGridEvery: majorGridEvery, color: colors[colorIndex], alpha: gridAlpha, From af791e8f726a7ee9a6baa5d382fb444568628bf1 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 18 Feb 2016 14:59:31 -0800 Subject: [PATCH 05/25] Make grid overlays unpickable --- interface/src/ui/overlays/Grid3DOverlay.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/ui/overlays/Grid3DOverlay.h b/interface/src/ui/overlays/Grid3DOverlay.h index 146fe79621..2a4b487e1b 100644 --- a/interface/src/ui/overlays/Grid3DOverlay.h +++ b/interface/src/ui/overlays/Grid3DOverlay.h @@ -31,6 +31,9 @@ public: virtual Grid3DOverlay* createClone() const; + // Grids are UI tools, and may not be intersected (pickable) + virtual bool findRayIntersection(const glm::vec3&, const glm::vec3&, float&, BoxFace&, glm::vec3&) { return false; } + private: void updateGrid(); From 2d1c676a8b943ff521a084e8e745b4f79a801711 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 18 Feb 2016 16:17:24 -0800 Subject: [PATCH 06/25] Add qHash for Vec2FloatPair --- libraries/render-utils/src/GeometryCache.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index 1eddb62253..51ec86f3fa 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -31,7 +31,6 @@ class SimpleProgramKey; -typedef glm::vec3 Vec3Key; typedef QPair Vec2FloatPair; typedef QPair Vec2Pair; typedef QPair Vec2PairPair; @@ -48,6 +47,11 @@ inline uint qHash(const glm::vec2& v, uint seed) { return qHash(v.x + 5009 * v.y, seed); } +inline uint qHash(const Vec2FloatPair& v, uint seed) { + // multiply by prime numbers greater than the possible size + return qHash(v.first.x + 5009 * v.first.y + 5011 * v.second); +} + inline uint qHash(const Vec2Pair& v, uint seed) { // multiply by prime numbers greater than the possible size return qHash(v.first.x + 5009 * v.first.y + 5011 * v.second.x + 5021 * v.second.y, seed); From 07a5c7bd161b1b8ece0b5685afc44876c48afc25 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 19 Feb 2016 11:22:01 -0800 Subject: [PATCH 07/25] Update grid shader for major/minor lines --- interface/src/audio/AudioScope.cpp | 10 +++--- interface/src/ui/overlays/Grid3DOverlay.cpp | 13 +++----- libraries/render-utils/src/GeometryCache.cpp | 29 ++++++++++------- libraries/render-utils/src/GeometryCache.h | 33 ++++++++++---------- libraries/render-utils/src/grid.slf | 20 +++++++++--- 5 files changed, 61 insertions(+), 44 deletions(-) diff --git a/interface/src/audio/AudioScope.cpp b/interface/src/audio/AudioScope.cpp index b62dcf5f28..75abe0c4ca 100644 --- a/interface/src/audio/AudioScope.cpp +++ b/interface/src/audio/AudioScope.cpp @@ -117,8 +117,8 @@ void AudioScope::render(RenderArgs* renderArgs, int width, int height) { static const glm::vec4 inputColor = { 0.3f, 1.0f, 0.3f, 1.0f }; static const glm::vec4 outputLeftColor = { 1.0f, 0.3f, 0.3f, 1.0f }; static const glm::vec4 outputRightColor = { 0.3f, 0.3f, 1.0f, 1.0f }; - static const int gridRows = 2; - int gridCols = _framesPerScope; + static const int gridCols = 2; + int gridRows = _framesPerScope; int x = (width - (int)SCOPE_WIDTH) / 2; int y = (height - (int)SCOPE_HEIGHT) / 2; @@ -128,8 +128,10 @@ void AudioScope::render(RenderArgs* renderArgs, int width, int height) { gpu::Batch& batch = *renderArgs->_batch; auto geometryCache = DependencyManager::get(); - // Grid uses its own pipeline - geometryCache->renderGrid(batch, x, y, w, h, gridRows, gridCols, gridColor, 0.005f, _audioScopeGrid); + // Grid uses its own pipeline, so draw it before setting another + const float GRID_EDGE = 0.005f; + geometryCache->renderGrid(batch, glm::vec2(x, y), glm::vec2(x + w, y + h), + gridRows, gridCols, GRID_EDGE, gridColor, _audioScopeGrid); geometryCache->useSimpleDrawPipeline(batch); auto textureCache = DependencyManager::get(); diff --git a/interface/src/ui/overlays/Grid3DOverlay.cpp b/interface/src/ui/overlays/Grid3DOverlay.cpp index 282595907e..d02219bcb6 100644 --- a/interface/src/ui/overlays/Grid3DOverlay.cpp +++ b/interface/src/ui/overlays/Grid3DOverlay.cpp @@ -71,15 +71,12 @@ void Grid3DOverlay::render(RenderArgs* args) { transform.setTranslation(position); batch->setModelTransform(transform); - // Minor grid const float MINOR_GRID_EDGE = 0.0025f; - DependencyManager::get()->renderGrid(*batch, - minCorner, maxCorner, _minorGridRowDivisions, _minorGridColDivisions, gridColor, MINOR_GRID_EDGE); - - // Major grid - const float MAJOR_GRID_EDGE = 0.01f; - DependencyManager::get()->renderGrid(*batch, - minCorner, maxCorner, _majorGridRowDivisions, _majorGridColDivisions, gridColor, MAJOR_GRID_EDGE); + const float MAJOR_GRID_EDGE = 0.005f; + DependencyManager::get()->renderGrid(*batch, minCorner, maxCorner, + _minorGridRowDivisions, _minorGridColDivisions, MINOR_GRID_EDGE, + _majorGridRowDivisions, _majorGridColDivisions, MAJOR_GRID_EDGE, + gridColor); } } diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index b5e09d0539..e1f5ce67ba 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -566,14 +566,17 @@ void GeometryCache::renderWireSphere(gpu::Batch& batch) { renderWireShape(batch, Sphere); } -void GeometryCache::renderGrid(gpu::Batch& batch, - const glm::vec2& minCorner, const glm::vec2& maxCorner, - int rows, int cols, const glm::vec4& color, float edge, int id) { - static const glm::vec2 minTexCoord(0.0f, 1.0f); - static const glm::vec2 maxTexCoord(1.0f, 0.0f); +void GeometryCache::renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner, + int majorRows, int majorCols, float majorEdge, + int minorRows, int minorCols, float minorEdge, + const glm::vec4& color, int id) { + static const glm::vec2 MIN_TEX_COORD(0.0f, 0.0f); + static const glm::vec2 MAX_TEX_COORD(1.0f, 1.0f); bool registered = (id != UNKNOWN_ID); - Vec2FloatPair key(glm::vec2(rows, cols), edge); + Vec2FloatPair majorKey(glm::vec2(majorRows, majorCols), majorEdge); + Vec2FloatPair minorKey(glm::vec2(minorRows, minorCols), minorEdge); + Vec2FloatPairPair key(majorKey, minorKey); // Make the gridbuffer if ((registered && (!_registeredGridBuffers.contains(id) || _lastRegisteredGridBuffer[id] != key)) || @@ -592,16 +595,20 @@ void GeometryCache::renderGrid(gpu::Batch& batch, _gridBuffers[key] = gridBuffer; } - gridBuffer.edit().period = glm::vec2(cols, rows); - gridBuffer.edit().offset.x = -(edge / cols) / 2; - gridBuffer.edit().offset.y = -(edge / rows) / 2; - gridBuffer.edit().balance = glm::vec2(1 - edge); + gridBuffer.edit().period = glm::vec4(majorRows, majorCols, minorRows, minorCols); + gridBuffer.edit().offset.x = -(majorEdge / majorRows) / 2; + gridBuffer.edit().offset.y = -(majorEdge / majorCols) / 2; + gridBuffer.edit().offset.z = -(minorEdge / minorRows) / 2; + gridBuffer.edit().offset.w = -(minorEdge / minorCols) / 2; + gridBuffer.edit().balance = glm::vec4(glm::vec2(1.0f - majorEdge), + // If rows or columns are not set, do not draw minor gridlines + glm::vec2((minorRows != 0 && minorCols != 0) ? 1.0f - minorEdge : 0.0f)); } // Set the grid pipeline useGridPipeline(batch, registered ? _registeredGridBuffers[id] : _gridBuffers[key]); - renderQuad(batch, minCorner, maxCorner, minTexCoord, maxTexCoord, color, id); + renderQuad(batch, minCorner, maxCorner, MIN_TEX_COORD, MAX_TEX_COORD, color, id); } void GeometryCache::updateVertices(int id, const QVector& points, const glm::vec4& color) { diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index 51ec86f3fa..a10ec84db5 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -32,6 +32,7 @@ class SimpleProgramKey; typedef QPair Vec2FloatPair; +typedef QPair Vec2FloatPairPair; typedef QPair Vec2Pair; typedef QPair Vec2PairPair; typedef QPair Vec3Pair; @@ -42,14 +43,10 @@ typedef QPair Vec3PairVec4Pair; typedef QPair Vec4PairVec4; typedef QPair Vec4PairVec4Pair; -inline uint qHash(const glm::vec2& v, uint seed) { +inline uint qHash(const Vec2FloatPairPair& v, uint seed) { // multiply by prime numbers greater than the possible size - return qHash(v.x + 5009 * v.y, seed); -} - -inline uint qHash(const Vec2FloatPair& v, uint seed) { - // multiply by prime numbers greater than the possible size - return qHash(v.first.x + 5009 * v.first.y + 5011 * v.second); + return qHash(v.first.first.x + 5009 * v.first.first.y + 5011 * v.first.second + + 5021 * v.second.first.x + 5023 * v.second.first.y + 5039 * v.second.second); } inline uint qHash(const Vec2Pair& v, uint seed) { @@ -207,9 +204,13 @@ public: void renderWireSphere(gpu::Batch& batch); size_t getSphereTriangleCount(); - void renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner, int rows, int cols, const glm::vec4& color, float edge = 0.01f, int id = UNKNOWN_ID); - void renderGrid(gpu::Batch& batch, int x, int y, int width, int height, int rows, int cols, const glm::vec4& color, float edge = 0.01f, int id = UNKNOWN_ID) { - renderGrid(batch, glm::vec2(x, y), glm::vec2(x + width, y + height), rows, cols, color, edge, id); + void renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner, + int majorRows, int majorCols, float majorEdge, + int minorRows, int minorCols, float minorEdge, + const glm::vec4& color, int id = UNKNOWN_ID); + void renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner, + int rows, int cols, float edge, const glm::vec4& color, int id = UNKNOWN_ID) { + renderGrid(batch, minCorner, maxCorner, rows, cols, edge, 0, 0, 0.0f, color, id); } void renderBevelCornersRect(gpu::Batch& batch, int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id = UNKNOWN_ID); @@ -318,10 +319,10 @@ private: class GridSchema { public: - glm::vec2 period; - glm::vec2 offset; - glm::vec2 balance; - glm::vec2 _; + // data is arranged as majorRow, majorCol, minorRow, minorCol + glm::vec4 period; + glm::vec4 offset; + glm::vec4 balance; }; using GridBuffer = gpu::BufferView; void useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer); @@ -384,8 +385,8 @@ private: QHash _dashedLines; QHash _registeredDashedLines; - QHash _lastRegisteredGridBuffer; - QHash _gridBuffers; + QHash _lastRegisteredGridBuffer; + QHash _gridBuffers; QHash _registeredGridBuffers; QHash > _networkGeometry; diff --git a/libraries/render-utils/src/grid.slf b/libraries/render-utils/src/grid.slf index d835d4bbde..0c2b00b3b0 100644 --- a/libraries/render-utils/src/grid.slf +++ b/libraries/render-utils/src/grid.slf @@ -31,11 +31,16 @@ float paintGrid(vec2 value, vec2 offset, vec2 scale, vec2 balance) { paintStripe(value.y, offset.y, scale.y, balance.y)); } +float paintGridMajorMinor(vec2 value, vec4 offset, vec4 scale, vec4 balance) { + return max( + paintGrid(value, offset.xy, scale.xy, balance.xy), + paintGrid(value, offset.zw, scale.zw, balance.zw)); +} + struct Grid { - vec2 period; - vec2 offset; - vec2 balance; - vec2 _; + vec4 period; + vec4 offset; + vec4 balance; }; uniform gridBuffer { Grid grid; }; @@ -49,7 +54,12 @@ out vec4 outFragColor; void main(void) { Grid grid = getGrid(); - float alpha = paintGrid(varTexCoord0, grid.offset, grid.period, grid.balance); + float alpha; + if (grid.balance.z == 0.0) { + alpha = paintGrid(varTexCoord0, grid.offset.xy, grid.period.xy, grid.balance.xy); + } else { + alpha = paintGridMajorMinor(varTexCoord0, grid.offset, grid.period, grid.balance); + } if (alpha == 0.0) { discard; } From 9daefbdb94822ca94b78eb2d8ada27aebcc5db82 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 19 Feb 2016 11:39:11 -0800 Subject: [PATCH 08/25] Fix grid antialiasing --- interface/src/ui/overlays/Grid3DOverlay.cpp | 2 +- libraries/render-utils/src/GeometryCache.cpp | 4 +-- libraries/render-utils/src/GeometryCache.h | 2 +- libraries/render-utils/src/grid.slf | 27 ++++++++++---------- 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/interface/src/ui/overlays/Grid3DOverlay.cpp b/interface/src/ui/overlays/Grid3DOverlay.cpp index d02219bcb6..b47ecdbd6c 100644 --- a/interface/src/ui/overlays/Grid3DOverlay.cpp +++ b/interface/src/ui/overlays/Grid3DOverlay.cpp @@ -81,7 +81,7 @@ void Grid3DOverlay::render(RenderArgs* args) { } const render::ShapeKey Grid3DOverlay::getShapeKey() { - return render::ShapeKey::Builder().withTranslucent(); + return render::ShapeKey::Builder().withOwnPipeline(); } void Grid3DOverlay::setProperties(const QScriptValue& properties) { diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index e1f5ce67ba..0a7ca2a450 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -600,9 +600,9 @@ void GeometryCache::renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, co gridBuffer.edit().offset.y = -(majorEdge / majorCols) / 2; gridBuffer.edit().offset.z = -(minorEdge / minorRows) / 2; gridBuffer.edit().offset.w = -(minorEdge / minorCols) / 2; - gridBuffer.edit().balance = glm::vec4(glm::vec2(1.0f - majorEdge), + gridBuffer.edit().edge = glm::vec4(glm::vec2(majorEdge), // If rows or columns are not set, do not draw minor gridlines - glm::vec2((minorRows != 0 && minorCols != 0) ? 1.0f - minorEdge : 0.0f)); + glm::vec2((minorRows != 0 && minorCols != 0) ? minorEdge : 0.0f)); } // Set the grid pipeline diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index a10ec84db5..b4b933ecdb 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -322,7 +322,7 @@ private: // data is arranged as majorRow, majorCol, minorRow, minorCol glm::vec4 period; glm::vec4 offset; - glm::vec4 balance; + glm::vec4 edge; }; using GridBuffer = gpu::BufferView; void useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer); diff --git a/libraries/render-utils/src/grid.slf b/libraries/render-utils/src/grid.slf index 0c2b00b3b0..04e35ac5ca 100644 --- a/libraries/render-utils/src/grid.slf +++ b/libraries/render-utils/src/grid.slf @@ -11,36 +11,37 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -float paintStripe(float value, float offset, float scale, float balance) { +float paintStripe(float value, float offset, float scale, float edge) { float width = fwidth(value); float normalizedWidth = width * scale; float x0 = (value + offset) * scale - normalizedWidth / 2; float x1 = x0 + normalizedWidth; - float i0 = balance * floor(x0) + max(0.0, fract(x0) - balance); - float i1 = balance * floor(x1) + max(0.0, fract(x1) - balance); + float balance = 1.0 - edge; + float i0 = edge * floor(x0) + max(0.0, fract(x0) - balance); + float i1 = edge * floor(x1) + max(0.0, fract(x1) - balance); float strip = (i1 - i0) / normalizedWidth; return clamp(strip, 0.0, 1.0); } -float paintGrid(vec2 value, vec2 offset, vec2 scale, vec2 balance) { +float paintGrid(vec2 value, vec2 offset, vec2 scale, vec2 edge) { return max( - paintStripe(value.x, offset.x, scale.x, balance.x), - paintStripe(value.y, offset.y, scale.y, balance.y)); + paintStripe(value.x, offset.x, scale.x, edge.x), + paintStripe(value.y, offset.y, scale.y, edge.y)); } -float paintGridMajorMinor(vec2 value, vec4 offset, vec4 scale, vec4 balance) { +float paintGridMajorMinor(vec2 value, vec4 offset, vec4 scale, vec4 edge) { return max( - paintGrid(value, offset.xy, scale.xy, balance.xy), - paintGrid(value, offset.zw, scale.zw, balance.zw)); + paintGrid(value, offset.xy, scale.xy, edge.xy), + paintGrid(value, offset.zw, scale.zw, edge.zw)); } struct Grid { vec4 period; vec4 offset; - vec4 balance; + vec4 edge; }; uniform gridBuffer { Grid grid; }; @@ -55,10 +56,10 @@ void main(void) { Grid grid = getGrid(); float alpha; - if (grid.balance.z == 0.0) { - alpha = paintGrid(varTexCoord0, grid.offset.xy, grid.period.xy, grid.balance.xy); + if (grid.edge.z == 0.0) { + alpha = paintGrid(varTexCoord0, grid.offset.xy, grid.period.xy, grid.edge.xy); } else { - alpha = paintGridMajorMinor(varTexCoord0, grid.offset, grid.period, grid.balance); + alpha = paintGridMajorMinor(varTexCoord0, grid.offset, grid.period, grid.edge); } if (alpha == 0.0) { discard; From 791d2955783df61150473b3f1f46a6874e43bca4 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 19 Feb 2016 11:48:44 -0800 Subject: [PATCH 09/25] Move paint shader functions to Paint.slh --- libraries/gpu/src/gpu/Paint.slh | 47 +++++++++++++++++++++++++++++ libraries/render-utils/src/grid.slf | 27 +---------------- 2 files changed, 48 insertions(+), 26 deletions(-) create mode 100644 libraries/gpu/src/gpu/Paint.slh diff --git a/libraries/gpu/src/gpu/Paint.slh b/libraries/gpu/src/gpu/Paint.slh new file mode 100644 index 0000000000..5f49b20b30 --- /dev/null +++ b/libraries/gpu/src/gpu/Paint.slh @@ -0,0 +1,47 @@ + +<@if not GPU_PAINT_SLH@> +<@def GPU_PAINT_SLH@> + +float paintStripe(float value, float offset, float scale, float edge) { + float width = fwidth(value); + float normalizedWidth = width * scale; + + float x0 = (value + offset) * scale - normalizedWidth / 2; + float x1 = x0 + normalizedWidth; + + float balance = 1.0 - edge; + float i0 = edge * floor(x0) + max(0.0, fract(x0) - balance); + float i1 = edge * floor(x1) + max(0.0, fract(x1) - balance); + float strip = (i1 - i0) / normalizedWidth; + + return clamp(strip, 0.0, 1.0); +} + +float paintGrid(vec2 value, vec2 offset, vec2 scale, vec2 edge) { + return max( + paintStripe(value.x, offset.x, scale.x, edge.x), + paintStripe(value.y, offset.y, scale.y, edge.y)); +} + +float paintGridMajor(vec2 value, vec2 offset, vec2 scale, vec2 edge) { + return paintGrid(value, offset, scale, edge); +} + +float paintGridMajorMinor(vec2 value, vec4 offset, vec4 scale, vec4 edge) { + return max( + paintGrid(value, offset.xy, scale.xy, edge.xy), + paintGrid(value, offset.zw, scale.zw, edge.zw)); +} + +<@endif@> diff --git a/libraries/render-utils/src/grid.slf b/libraries/render-utils/src/grid.slf index 04e35ac5ca..901d343268 100644 --- a/libraries/render-utils/src/grid.slf +++ b/libraries/render-utils/src/grid.slf @@ -11,32 +11,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -float paintStripe(float value, float offset, float scale, float edge) { - float width = fwidth(value); - float normalizedWidth = width * scale; - - float x0 = (value + offset) * scale - normalizedWidth / 2; - float x1 = x0 + normalizedWidth; - - float balance = 1.0 - edge; - float i0 = edge * floor(x0) + max(0.0, fract(x0) - balance); - float i1 = edge * floor(x1) + max(0.0, fract(x1) - balance); - float strip = (i1 - i0) / normalizedWidth; - - return clamp(strip, 0.0, 1.0); -} - -float paintGrid(vec2 value, vec2 offset, vec2 scale, vec2 edge) { - return max( - paintStripe(value.x, offset.x, scale.x, edge.x), - paintStripe(value.y, offset.y, scale.y, edge.y)); -} - -float paintGridMajorMinor(vec2 value, vec4 offset, vec4 scale, vec4 edge) { - return max( - paintGrid(value, offset.xy, scale.xy, edge.xy), - paintGrid(value, offset.zw, scale.zw, edge.zw)); -} +<@include gpu/Paint.slh@> struct Grid { vec4 period; From fd6aa9a78b8abeb33d5d01ee0e0aa8293f610ba2 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 19 Feb 2016 11:52:41 -0800 Subject: [PATCH 10/25] Add layering to renderGrid, draw edit grid not layered --- examples/libraries/gridTool.js | 6 ++--- interface/src/audio/AudioScope.cpp | 2 +- interface/src/ui/overlays/Grid3DOverlay.cpp | 2 +- libraries/render-utils/src/GeometryCache.cpp | 25 +++++++++++++------- libraries/render-utils/src/GeometryCache.h | 9 +++---- 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/examples/libraries/gridTool.js b/examples/libraries/gridTool.js index 04e8b48f1d..6d762c94d2 100644 --- a/examples/libraries/gridTool.js +++ b/examples/libraries/gridTool.js @@ -25,7 +25,7 @@ Grid = function(opts) { var gridOverlay = Overlays.addOverlay("grid", { dimensions: { x: scale, y: scale, z: scale }, visible: false, - drawInFront: true, + drawInFront: false, color: colors[0], alpha: gridAlpha, rotation: Quat.fromPitchYawRollDegrees(90, 0, 0), @@ -132,9 +132,7 @@ Grid = function(opts) { that.setPosition = function(newPosition, noUpdate) { - origin = newPosition; - origin.x = 0; - origin.z = 0; + origin = { x: 0, y: newPosition.y, z: 0 }; updateGrid(); if (!noUpdate) { diff --git a/interface/src/audio/AudioScope.cpp b/interface/src/audio/AudioScope.cpp index 75abe0c4ca..d92c5a2fda 100644 --- a/interface/src/audio/AudioScope.cpp +++ b/interface/src/audio/AudioScope.cpp @@ -131,7 +131,7 @@ void AudioScope::render(RenderArgs* renderArgs, int width, int height) { // Grid uses its own pipeline, so draw it before setting another const float GRID_EDGE = 0.005f; geometryCache->renderGrid(batch, glm::vec2(x, y), glm::vec2(x + w, y + h), - gridRows, gridCols, GRID_EDGE, gridColor, _audioScopeGrid); + gridRows, gridCols, GRID_EDGE, gridColor, true, _audioScopeGrid); geometryCache->useSimpleDrawPipeline(batch); auto textureCache = DependencyManager::get(); diff --git a/interface/src/ui/overlays/Grid3DOverlay.cpp b/interface/src/ui/overlays/Grid3DOverlay.cpp index b47ecdbd6c..2d82e9e179 100644 --- a/interface/src/ui/overlays/Grid3DOverlay.cpp +++ b/interface/src/ui/overlays/Grid3DOverlay.cpp @@ -76,7 +76,7 @@ void Grid3DOverlay::render(RenderArgs* args) { DependencyManager::get()->renderGrid(*batch, minCorner, maxCorner, _minorGridRowDivisions, _minorGridColDivisions, MINOR_GRID_EDGE, _majorGridRowDivisions, _majorGridColDivisions, MAJOR_GRID_EDGE, - gridColor); + gridColor, _drawInFront); } } diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 0a7ca2a450..756e18dc8b 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -569,7 +569,7 @@ void GeometryCache::renderWireSphere(gpu::Batch& batch) { void GeometryCache::renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner, int majorRows, int majorCols, float majorEdge, int minorRows, int minorCols, float minorEdge, - const glm::vec4& color, int id) { + const glm::vec4& color, bool isLayered, int id) { static const glm::vec2 MIN_TEX_COORD(0.0f, 0.0f); static const glm::vec2 MAX_TEX_COORD(1.0f, 1.0f); @@ -606,7 +606,7 @@ void GeometryCache::renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, co } // Set the grid pipeline - useGridPipeline(batch, registered ? _registeredGridBuffers[id] : _gridBuffers[key]); + useGridPipeline(batch, registered ? _registeredGridBuffers[id] : _gridBuffers[key], isLayered); renderQuad(batch, minCorner, maxCorner, MIN_TEX_COORD, MAX_TEX_COORD, color, id); } @@ -1656,20 +1656,27 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) { } } -void GeometryCache::useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer) { +void GeometryCache::useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer, bool isLayered) { if (!_gridPipeline) { auto vs = gpu::Shader::createVertex(std::string(standardTransformPNTC_vert)); auto ps = gpu::Shader::createPixel(std::string(grid_frag)); auto program = gpu::Shader::createProgram(vs, ps); gpu::Shader::makeProgram((*program)); - - auto state = std::make_shared(); - state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); - - _gridPipeline = gpu::Pipeline::create(program, state); _gridSlot = program->getBuffers().findLocation("gridBuffer"); + + auto stateLayered = std::make_shared(); + stateLayered->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); + _gridPipelineLayered = gpu::Pipeline::create(program, stateLayered); + + auto state = std::make_shared(stateLayered->getValues()); + const float DEPTH_BIAS = 0.001f; + state->setDepthBias(DEPTH_BIAS); + state->setDepthTest(true, false, gpu::LESS_EQUAL); + _gridPipeline = gpu::Pipeline::create(program, state); } - batch.setPipeline(_gridPipeline); + + gpu::PipelinePointer pipeline = isLayered ? _gridPipelineLayered : _gridPipeline; + batch.setPipeline(pipeline); batch.setUniformBuffer(_gridSlot, gridBuffer); } diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index b4b933ecdb..b69ebf8531 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -207,10 +207,10 @@ public: void renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner, int majorRows, int majorCols, float majorEdge, int minorRows, int minorCols, float minorEdge, - const glm::vec4& color, int id = UNKNOWN_ID); + const glm::vec4& color, bool isLayered, int id = UNKNOWN_ID); void renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner, - int rows, int cols, float edge, const glm::vec4& color, int id = UNKNOWN_ID) { - renderGrid(batch, minCorner, maxCorner, rows, cols, edge, 0, 0, 0.0f, color, id); + int rows, int cols, float edge, const glm::vec4& color, bool isLayered, int id = UNKNOWN_ID) { + renderGrid(batch, minCorner, maxCorner, rows, cols, edge, 0, 0, 0.0f, color, isLayered, id); } void renderBevelCornersRect(gpu::Batch& batch, int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id = UNKNOWN_ID); @@ -325,8 +325,9 @@ private: glm::vec4 edge; }; using GridBuffer = gpu::BufferView; - void useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer); + void useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer, bool isLayered); gpu::PipelinePointer _gridPipeline; + gpu::PipelinePointer _gridPipelineLayered; int _gridSlot; class BatchItemDetails { From 0b4e82405f4bde23bbe5b485117af923167cfc3b Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 19 Feb 2016 13:46:59 -0800 Subject: [PATCH 11/25] Snap grid overlay to major worldlines --- interface/src/ui/overlays/Grid3DOverlay.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/overlays/Grid3DOverlay.cpp b/interface/src/ui/overlays/Grid3DOverlay.cpp index 2d82e9e179..8246960110 100644 --- a/interface/src/ui/overlays/Grid3DOverlay.cpp +++ b/interface/src/ui/overlays/Grid3DOverlay.cpp @@ -59,9 +59,14 @@ void Grid3DOverlay::render(RenderArgs* args) { if (_followCamera) { auto avatar = DependencyManager::get()->getMyAvatar(); - // Add the camera position at the plane of the avatar's base (the floor) - auto cameraPosition = args->_viewFrustum->getPosition(); + // Get the camera position rounded to the nearest major grid line + // This grid is for UI and should lie on worldlines + auto cameraPosition = + (float)_majorGridEvery * glm::round(args->_viewFrustum->getPosition() / (float)_majorGridEvery); + + // Get the plane of the avatar's feet (or collision ground) auto avatarBaseHeight = avatar->getPosition().y - avatar->getUniformScale(); + position += glm::vec3(cameraPosition.x, avatarBaseHeight, cameraPosition.z); } From 3418488c2f65ae8cf92514cea74df9b5188071a5 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 19 Feb 2016 14:44:33 -0800 Subject: [PATCH 12/25] Fool octree to avoid ui grid overlay culling --- interface/src/ui/overlays/Grid3DOverlay.cpp | 11 +++++++++++ interface/src/ui/overlays/Grid3DOverlay.h | 2 ++ interface/src/ui/overlays/Planar3DOverlay.h | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/overlays/Grid3DOverlay.cpp b/interface/src/ui/overlays/Grid3DOverlay.cpp index 8246960110..e73520e973 100644 --- a/interface/src/ui/overlays/Grid3DOverlay.cpp +++ b/interface/src/ui/overlays/Grid3DOverlay.cpp @@ -13,6 +13,8 @@ #include +#include + #include #include @@ -38,6 +40,15 @@ Grid3DOverlay::Grid3DOverlay(const Grid3DOverlay* grid3DOverlay) : updateGrid(); } +AABox Grid3DOverlay::getBounds() const { + if (_followCamera) { + // This is a UI element that should always be in view, lie to the octree to avoid culling + const AABox DOMAIN_BOX = AABox(glm::vec3(-TREE_SCALE / 2), TREE_SCALE); + return DOMAIN_BOX; + } + return Planar3DOverlay::getBounds(); +} + void Grid3DOverlay::render(RenderArgs* args) { if (!_visible) { return; // do nothing if we're not visible diff --git a/interface/src/ui/overlays/Grid3DOverlay.h b/interface/src/ui/overlays/Grid3DOverlay.h index 2a4b487e1b..3614a13000 100644 --- a/interface/src/ui/overlays/Grid3DOverlay.h +++ b/interface/src/ui/overlays/Grid3DOverlay.h @@ -24,6 +24,8 @@ public: Grid3DOverlay(); Grid3DOverlay(const Grid3DOverlay* grid3DOverlay); + virtual AABox getBounds() const; + virtual void render(RenderArgs* args); virtual const render::ShapeKey getShapeKey() override; virtual void setProperties(const QScriptValue& properties); diff --git a/interface/src/ui/overlays/Planar3DOverlay.h b/interface/src/ui/overlays/Planar3DOverlay.h index 63de15a8f8..0542a8b491 100644 --- a/interface/src/ui/overlays/Planar3DOverlay.h +++ b/interface/src/ui/overlays/Planar3DOverlay.h @@ -20,7 +20,7 @@ public: Planar3DOverlay(); Planar3DOverlay(const Planar3DOverlay* planar3DOverlay); - AABox getBounds() const; + virtual AABox getBounds() const; glm::vec2 getDimensions() const { return _dimensions; } void setDimensions(float value) { _dimensions = glm::vec2(value); } From d74aa4f14d75211d82fd9692115ccdd7b4a940fc Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 19 Feb 2016 14:54:19 -0800 Subject: [PATCH 13/25] Rm extra , in gridControls --- examples/html/gridControls.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/html/gridControls.html b/examples/html/gridControls.html index 204e50c1a7..0724f1fc6b 100644 --- a/examples/html/gridControls.html +++ b/examples/html/gridControls.html @@ -139,7 +139,7 @@
- +
From 5d78867197dd37074cd626e2ecdfd489736542f1 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 19 Feb 2016 15:23:54 -0800 Subject: [PATCH 14/25] Set grid height via global y-coord --- examples/html/gridControls.html | 2 +- examples/libraries/gridTool.js | 5 +++-- interface/src/ui/overlays/Grid3DOverlay.cpp | 5 +---- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/examples/html/gridControls.html b/examples/html/gridControls.html index 0724f1fc6b..f8a7db4a50 100644 --- a/examples/html/gridControls.html +++ b/examples/html/gridControls.html @@ -132,7 +132,7 @@
- +
diff --git a/examples/libraries/gridTool.js b/examples/libraries/gridTool.js index 6d762c94d2..f5c8b4d90b 100644 --- a/examples/libraries/gridTool.js +++ b/examples/libraries/gridTool.js @@ -12,7 +12,7 @@ Grid = function(opts) { ]; var colorIndex = 0; var gridAlpha = 0.6; - var origin = { x: 0, y: 0, z: 0 }; + var origin = { x: 0, y: +MyAvatar.getJointPosition('LeftToeBase').y.toFixed(1) + 0.1, z: 0 }; var scale = 500; var minorGridEvery = 1.0; var majorGridEvery = 5; @@ -23,12 +23,13 @@ Grid = function(opts) { var snapToGrid = false; var gridOverlay = Overlays.addOverlay("grid", { + rotation: Quat.fromPitchYawRollDegrees(90, 0, 0), dimensions: { x: scale, y: scale, z: scale }, + position: origin, visible: false, drawInFront: false, color: colors[0], alpha: gridAlpha, - rotation: Quat.fromPitchYawRollDegrees(90, 0, 0), minorGridEvery: minorGridEvery, majorGridEvery: majorGridEvery, }); diff --git a/interface/src/ui/overlays/Grid3DOverlay.cpp b/interface/src/ui/overlays/Grid3DOverlay.cpp index e73520e973..eef238e267 100644 --- a/interface/src/ui/overlays/Grid3DOverlay.cpp +++ b/interface/src/ui/overlays/Grid3DOverlay.cpp @@ -75,10 +75,7 @@ void Grid3DOverlay::render(RenderArgs* args) { auto cameraPosition = (float)_majorGridEvery * glm::round(args->_viewFrustum->getPosition() / (float)_majorGridEvery); - // Get the plane of the avatar's feet (or collision ground) - auto avatarBaseHeight = avatar->getPosition().y - avatar->getUniformScale(); - - position += glm::vec3(cameraPosition.x, avatarBaseHeight, cameraPosition.z); + position += glm::vec3(cameraPosition.x, 0.0f, cameraPosition.z); } Transform transform; From c9362a4073a90969eb5bd481c30227ccf24e7b25 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 19 Feb 2016 15:58:08 -0800 Subject: [PATCH 15/25] Set grid major div min to 1 --- examples/html/gridControls.html | 2 +- examples/libraries/gridTool.js | 10 ++++++---- interface/src/ui/overlays/Grid3DOverlay.cpp | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/examples/html/gridControls.html b/examples/html/gridControls.html index f8a7db4a50..dd41125de4 100644 --- a/examples/html/gridControls.html +++ b/examples/html/gridControls.html @@ -146,7 +146,7 @@
- +
diff --git a/examples/libraries/gridTool.js b/examples/libraries/gridTool.js index f5c8b4d90b..fbd2ec7ea0 100644 --- a/examples/libraries/gridTool.js +++ b/examples/libraries/gridTool.js @@ -187,10 +187,10 @@ Grid = function(opts) { that.setVisible(data.visible, true); } - updateGrid(); + updateGrid(true); } - function updateGrid() { + function updateGrid(noUpdate) { Overlays.editOverlay(gridOverlay, { position: { x: 0, y: origin.y, z: 0 }, visible: that.visible && that.enabled, @@ -200,7 +200,9 @@ Grid = function(opts) { alpha: gridAlpha, }); - that.emitUpdate(); + if (!noUpdate) { + that.emitUpdate(); + } } function cleanup() { @@ -243,7 +245,7 @@ GridTool = function(opts) { } else if (data.type == "update") { horizontalGrid.update(data); for (var i = 0; i < listeners.length; i++) { - listeners[i](data); + listeners[i] && listeners[i](data); } } else if (data.type == "action") { var action = data.action; diff --git a/interface/src/ui/overlays/Grid3DOverlay.cpp b/interface/src/ui/overlays/Grid3DOverlay.cpp index eef238e267..b654d5fe2f 100644 --- a/interface/src/ui/overlays/Grid3DOverlay.cpp +++ b/interface/src/ui/overlays/Grid3DOverlay.cpp @@ -133,7 +133,7 @@ Grid3DOverlay* Grid3DOverlay::createClone() const { } void Grid3DOverlay::updateGrid() { - const int MAJOR_GRID_EVERY_MIN = 5; + const int MAJOR_GRID_EVERY_MIN = 1; const float MINOR_GRID_EVERY_MIN = 0.2f; _majorGridEvery = std::max(_majorGridEvery, MAJOR_GRID_EVERY_MIN); From 665ef17fce57c514bfd3e5ec87573254b42635d0 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 19 Feb 2016 16:38:53 -0800 Subject: [PATCH 16/25] Remove avatar usage from grid3d --- interface/src/ui/overlays/Grid3DOverlay.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/interface/src/ui/overlays/Grid3DOverlay.cpp b/interface/src/ui/overlays/Grid3DOverlay.cpp index b654d5fe2f..e5e93aa0ce 100644 --- a/interface/src/ui/overlays/Grid3DOverlay.cpp +++ b/interface/src/ui/overlays/Grid3DOverlay.cpp @@ -15,9 +15,6 @@ #include -#include -#include - #include #include #include @@ -68,8 +65,6 @@ void Grid3DOverlay::render(RenderArgs* args) { auto position = getPosition(); if (_followCamera) { - auto avatar = DependencyManager::get()->getMyAvatar(); - // Get the camera position rounded to the nearest major grid line // This grid is for UI and should lie on worldlines auto cameraPosition = From 5f79500e4d0b8485fe6f6e73c62adfa45452ba4d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 21 Feb 2016 09:37:43 -0800 Subject: [PATCH 17/25] fix grab-script touch --- examples/controllers/handControllerGrab.js | 49 ++++++++++------------ 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index e53e2ad59c..ffca3117c1 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1587,48 +1587,43 @@ function MyController(hand) { } ids.forEach(function(id) { - var props = Entities.getEntityProperties(id, ["boundingBox", "name"]); if (props.name === 'pointer') { return; - } else { - var entityMinPoint = props.boundingBox.brn; - var entityMaxPoint = props.boundingBox.tfl; - var leftIsTouching = pointInExtents(leftHandPosition, entityMinPoint, entityMaxPoint); - var rightIsTouching = pointInExtents(rightHandPosition, entityMinPoint, entityMaxPoint); - - if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id] === undefined) { - // we haven't been touched before, but either right or left is touching us now - _this.allTouchedIDs[id] = true; - _this.startTouch(id); - } else if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id]) { - // we have been touched before and are still being touched - // continue touch - _this.continueTouch(id); - } else if (_this.allTouchedIDs[id]) { - delete _this.allTouchedIDs[id]; - _this.stopTouch(id); - - } else { - //we are in another state - return; - } } + var entityMinPoint = props.boundingBox.brn; + var entityMaxPoint = props.boundingBox.tfl; + var leftIsTouching = pointInExtents(leftHandPosition, entityMinPoint, entityMaxPoint); + var rightIsTouching = pointInExtents(rightHandPosition, entityMinPoint, entityMaxPoint); + if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id] === undefined) { + // we haven't been touched before, but either right or left is touching us now + _this.allTouchedIDs[id] = true; + _this.startTouch(id); + } else if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id]) { + // we have been touched before and are still being touched + // continue touch + _this.continueTouch(id); + } else if (_this.allTouchedIDs[id]) { + delete _this.allTouchedIDs[id]; + _this.stopTouch(id); + } }); - }; this.startTouch = function(entityID) { - this.callEntityMethodOnGrabbed("startTouch"); + var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; + Entities.callEntityMethod(entityID, "startTouch", args); }; this.continueTouch = function(entityID) { - this.callEntityMethodOnGrabbed("continueTouch"); + var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; + Entities.callEntityMethod(entityID, "continueTouch", args); }; this.stopTouch = function(entityID) { - this.callEntityMethodOnGrabbed("stopTouch"); + var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; + Entities.callEntityMethod(entityID, "stopTouch", args); }; this.release = function() { From 9f602a938d7a9e17c9bbc328057f55ecc0a26aba Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Sun, 21 Feb 2016 12:42:02 -0800 Subject: [PATCH 18/25] don't move mouse on reset sensors --- interface/src/Application.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7c1fd9279b..64cd586e13 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3906,16 +3906,8 @@ void Application::resetSensors(bool andReload) { DependencyManager::get()->reset(); DependencyManager::get()->reset(); DependencyManager::get()->reset(); - getActiveDisplayPlugin()->resetSensors(); - - QScreen* currentScreen = _window->windowHandle()->screen(); - QWindow* mainWindow = _window->windowHandle(); - QPoint windowCenter = mainWindow->geometry().center(); - _glWidget->cursor().setPos(currentScreen, windowCenter); - getMyAvatar()->reset(andReload); - QMetaObject::invokeMethod(DependencyManager::get().data(), "reset", Qt::QueuedConnection); } From cbe80bffd679ca6ba211fee45c03cf0bc53f3070 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Sun, 21 Feb 2016 12:57:14 -0800 Subject: [PATCH 19/25] go into away mode if you the HMD loses mouse capture --- examples/away.js | 12 ++++++++++++ interface/src/ui/ApplicationCompositor.h | 5 ++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/examples/away.js b/examples/away.js index 861c642b8d..18a3fddfce 100644 --- a/examples/away.js +++ b/examples/away.js @@ -132,6 +132,7 @@ function maybeGoActive(event) { } } var wasHmdActive = false; +var wasMouseCaptured = false; function maybeGoAway() { if (HMD.active !== wasHmdActive) { wasHmdActive = !wasHmdActive; @@ -139,6 +140,17 @@ function maybeGoAway() { goAway(); } } + + // If the mouse has gone from captured, to non-captured state, + // then it likely means the person is still in the HMD, but has + // tabbed away from the application (meaning they don't have mouse + // control) and they likely want to go into an away state + if (Reticle.mouseCaptured !== wasMouseCaptured) { + wasMouseCaptured = !wasMouseCaptured; + if (!wasMouseCaptured) { + goAway(); + } + } } Script.update.connect(maybeGoAway); diff --git a/interface/src/ui/ApplicationCompositor.h b/interface/src/ui/ApplicationCompositor.h index 94244e5586..32a30c6fc6 100644 --- a/interface/src/ui/ApplicationCompositor.h +++ b/interface/src/ui/ApplicationCompositor.h @@ -101,9 +101,9 @@ public: void handleLeaveEvent(); QPointF getMouseEventPosition(QMouseEvent* event); + bool shouldCaptureMouse() const; private: - bool shouldCaptureMouse() const; void displayOverlayTextureStereo(RenderArgs* renderArgs, float aspectRatio, float fov); void bindCursorTexture(gpu::Batch& batch, uint8_t cursorId = 0); @@ -162,10 +162,13 @@ class ReticleInterface : public QObject { Q_PROPERTY(bool visible READ getVisible WRITE setVisible) Q_PROPERTY(float depth READ getDepth WRITE setDepth) Q_PROPERTY(glm::vec2 maximumPosition READ getMaximumPosition) + Q_PROPERTY(bool mouseCaptured READ isMouseCaptured) public: ReticleInterface(ApplicationCompositor* outer) : QObject(outer), _compositor(outer) {} + Q_INVOKABLE bool isMouseCaptured() { return _compositor->shouldCaptureMouse(); } + Q_INVOKABLE bool getVisible() { return _compositor->getReticleVisible(); } Q_INVOKABLE void setVisible(bool visible) { _compositor->setReticleVisible(visible); } From bb1ed2147f1054e1798f2c63f54fcb9442ad45be Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 22 Feb 2016 11:22:03 -0800 Subject: [PATCH 20/25] revert change that trusted Qt's claim that it supports the format --- libraries/audio-client/src/AudioClient.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 01ceb73941..4d44a771f7 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -279,9 +279,10 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) { bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice, const QAudioFormat& desiredAudioFormat, QAudioFormat& adjustedAudioFormat) { - // There had been a note here that 2khz was swapping channels. That doesn't seem to be happening - // any more for me. If it does, then we'll want to always resample. - if (!audioDevice.isFormatSupported(desiredAudioFormat)) { + + // FIXME: directly using 24khz has a bug somewhere that causes channels to be swapped. + // Continue using our internal resampler, for now. + if (true || !audioDevice.isFormatSupported(desiredAudioFormat)) { qCDebug(audioclient) << "The desired format for audio I/O is" << desiredAudioFormat; qCDebug(audioclient, "The desired audio format is not supported by this device"); @@ -289,7 +290,7 @@ bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice, adjustedAudioFormat = desiredAudioFormat; adjustedAudioFormat.setChannelCount(2); - if (audioDevice.isFormatSupported(adjustedAudioFormat)) { + if (false && audioDevice.isFormatSupported(adjustedAudioFormat)) { return true; } else { adjustedAudioFormat.setChannelCount(1); From 5bf9b8bc76315f7b1b268ed2093286f7d230ac5f Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 22 Feb 2016 11:59:15 -0800 Subject: [PATCH 21/25] Set grid minor div min to 0.01 --- interface/src/ui/overlays/Grid3DOverlay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/overlays/Grid3DOverlay.cpp b/interface/src/ui/overlays/Grid3DOverlay.cpp index e5e93aa0ce..817e71a4da 100644 --- a/interface/src/ui/overlays/Grid3DOverlay.cpp +++ b/interface/src/ui/overlays/Grid3DOverlay.cpp @@ -129,7 +129,7 @@ Grid3DOverlay* Grid3DOverlay::createClone() const { void Grid3DOverlay::updateGrid() { const int MAJOR_GRID_EVERY_MIN = 1; - const float MINOR_GRID_EVERY_MIN = 0.2f; + const float MINOR_GRID_EVERY_MIN = 0.01f; _majorGridEvery = std::max(_majorGridEvery, MAJOR_GRID_EVERY_MIN); _minorGridEvery = std::max(_minorGridEvery, MINOR_GRID_EVERY_MIN); From 4169e9be9d163977a303ef5042c8fcd5be1db9d9 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 22 Feb 2016 14:24:31 -0800 Subject: [PATCH 22/25] Don't deadlock objreader on shutdown --- libraries/fbx/src/OBJReader.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 11164afbbb..ff33246b3f 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -260,10 +260,22 @@ QNetworkReply* OBJReader::request(QUrl& url, bool isTest) { QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest netRequest(url); QNetworkReply* netReply = isTest ? networkAccessManager.head(netRequest) : networkAccessManager.get(netRequest); + if (!qApp) { + return netReply; + } QEventLoop loop; // Create an event loop that will quit when we get the finished signal QObject::connect(netReply, SIGNAL(finished()), &loop, SLOT(quit())); loop.exec(); // Nothing is going to happen on this whole run thread until we get this - netReply->waitForReadyRead(-1); // so we might as well block this thread waiting for the response, rather than + + bool aboutToQuit { false }; + auto connection = QObject::connect(qApp, &QCoreApplication::aboutToQuit, [&] { + aboutToQuit = true; + }); + static const int WAIT_TIMEOUT_MS = 500; + while (qApp && !aboutToQuit && !netReply->isReadable()) { + netReply->waitForReadyRead(WAIT_TIMEOUT_MS); // so we might as well block this thread waiting for the response, rather than + } + QObject::disconnect(connection); return netReply; // trying to sync later on. } From b4a7dc113eac8dd6173ab8e8c640554b1e3be90d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 22 Feb 2016 14:25:30 -0800 Subject: [PATCH 23/25] Safer shutdown behavior in QML surfaces --- libraries/gl/src/gl/OffscreenQmlSurface.cpp | 13 ++++++++----- libraries/gl/src/gl/OffscreenQmlSurface.h | 1 + 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index e22feb694d..6ec162585b 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -315,6 +315,8 @@ OffscreenQmlSurface::OffscreenQmlSurface() { } OffscreenQmlSurface::~OffscreenQmlSurface() { + QObject::disconnect(&_updateTimer); + QObject::disconnect(qApp); _renderer->stop(); delete _rootItem; delete _renderer; @@ -322,6 +324,10 @@ OffscreenQmlSurface::~OffscreenQmlSurface() { delete _qmlEngine; } +void OffscreenQmlSurface::onAboutToQuit() { + QObject::disconnect(&_updateTimer); +} + void OffscreenQmlSurface::create(QOpenGLContext* shareContext) { _renderer = new OffscreenQmlRenderer(this, shareContext); _renderer->_renderControl->_renderWindow = _proxyWindow; @@ -334,12 +340,9 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) { // When Quick says there is a need to render, we will not render immediately. Instead, // a timer with a small interval is used to get better performance. _updateTimer.setInterval(MIN_TIMER_MS); - connect(&_updateTimer, &QTimer::timeout, this, &OffscreenQmlSurface::updateQuick); - QObject::connect(qApp, &QCoreApplication::aboutToQuit, [this]{ - disconnect(&_updateTimer, &QTimer::timeout, this, &OffscreenQmlSurface::updateQuick); - }); + QObject::connect(&_updateTimer, &QTimer::timeout, this, &OffscreenQmlSurface::updateQuick); + QObject::connect(qApp, &QCoreApplication::aboutToQuit, this, &OffscreenQmlSurface::onAboutToQuit); _updateTimer.start(); - _qmlComponent = new QQmlComponent(_qmlEngine); _qmlEngine->rootContext()->setContextProperty("offscreenWindow", QVariant::fromValue(getWindow())); } diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.h b/libraries/gl/src/gl/OffscreenQmlSurface.h index 5641d16a30..9142e7f2ef 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.h +++ b/libraries/gl/src/gl/OffscreenQmlSurface.h @@ -74,6 +74,7 @@ signals: public slots: void requestUpdate(); void requestRender(); + void onAboutToQuit(); private: QObject* finishQmlLoad(std::function f); From c07f3789e4e1d954225bd91f3e38ec33e43accc8 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 22 Feb 2016 14:26:33 -0800 Subject: [PATCH 24/25] Don't crash on script destructor --- libraries/script-engine/src/ScriptEngine.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index a65fe7417d..738e313f8f 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -144,7 +144,12 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam ScriptEngine::~ScriptEngine() { qCDebug(scriptengine) << "Script Engine shutting down (destructor) for script:" << getFilename(); - DependencyManager::get()->removeScriptEngine(this); + auto scriptEngines = DependencyManager::get(); + if (scriptEngines) { + scriptEngines->removeScriptEngine(this); + } else { + qCWarning(scriptengine) << "Script destroyed after ScriptEngines!"; + } } void ScriptEngine::disconnectNonEssentialSignals() { From 160a107bbd079af69a4b521afa550c68f4e07f05 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 22 Feb 2016 19:36:00 -0800 Subject: [PATCH 25/25] Auto-unhide the desktop when showing or raising a window --- interface/resources/qml/desktop/Desktop.qml | 13 +++++++++++-- interface/src/Application.cpp | 9 ++++++++- interface/src/Application.h | 1 + libraries/ui/src/OffscreenUi.cpp | 5 +++++ libraries/ui/src/OffscreenUi.h | 3 +++ 5 files changed, 28 insertions(+), 3 deletions(-) diff --git a/interface/resources/qml/desktop/Desktop.qml b/interface/resources/qml/desktop/Desktop.qml index 0286c45ac3..e2aecdfd18 100644 --- a/interface/resources/qml/desktop/Desktop.qml +++ b/interface/resources/qml/desktop/Desktop.qml @@ -10,12 +10,19 @@ import "../js/Utils.js" as Utils // windows will be childed. FocusScope { id: desktop - anchors.fill: parent; objectName: "desktop" + // Allow the scale of the desktop to be changed without screwing up the size relative to the parent. + height: parent.height / scale + width: parent.width / scale + onHeightChanged: d.repositionAll(); onWidthChanged: d.repositionAll(); + // Controls and windows can trigger this signal to ensure the desktop becomes visible + // when they're opened. + signal showDesktop(); + // Allows QML/JS to find the desktop through the parent chain property bool desktopRoot: true @@ -217,6 +224,8 @@ FocusScope { } reposition(targetWindow); + + showDesktop(); } function reposition(item) { @@ -314,7 +323,7 @@ FocusScope { enabled: DebugQML onTriggered: focusDebugger.visible = !focusDebugger.visible } - + } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 64cd586e13..704940433a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1198,7 +1198,8 @@ void Application::initializeUi() { // OffscreenUi is a subclass of OffscreenQmlSurface specifically designed to // support the window management and scripting proxies for VR use offscreenUi->createDesktop(QString("hifi/Desktop.qml")); - + connect(offscreenUi.data(), &OffscreenUi::showDesktop, this, &Application::showDesktop); + // FIXME either expose so that dialogs can set this themselves or // do better detection in the offscreen UI of what has focus offscreenUi->setNavigationFocused(false); @@ -5128,3 +5129,9 @@ void Application::readArgumentsFromLocalSocket() { qApp->openUrl(QString::fromUtf8(message)); } } + +void Application::showDesktop() { + if (!_overlayConductor.getEnabled()) { + _overlayConductor.setEnabled(true); + } +} \ No newline at end of file diff --git a/interface/src/Application.h b/interface/src/Application.h index 96bafce23f..8cc2a33038 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -280,6 +280,7 @@ public slots: void runTests(); private slots: + void showDesktop(); void clearDomainOctreeDetails(); void idle(uint64_t now); void aboutToQuit(); diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index fa40fedb9b..7e84836c86 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -112,6 +112,7 @@ void OffscreenUi::create(QOpenGLContext* context) { } void OffscreenUi::show(const QUrl& url, const QString& name, std::function f) { + emit showDesktop(); QQuickItem* item = getRootItem()->findChild(name); // First load? if (!item) { @@ -127,6 +128,7 @@ void OffscreenUi::toggle(const QUrl& url, const QString& name, std::functionfindChild(name); // Already loaded? if (item) { + emit showDesktop(); item->setVisible(!item->isVisible()); return; } @@ -134,6 +136,7 @@ void OffscreenUi::toggle(const QUrl& url, const QString& name, std::functionfindChild(name); if (item && !item->isVisible()) { + emit showDesktop(); item->setVisible(true); } } @@ -439,6 +442,8 @@ void OffscreenUi::createDesktop(const QUrl& url) { new VrMenu(this); new KeyboardFocusHack(); + + connect(_desktop, SIGNAL(showDesktop()), this, SLOT(showDesktop())); } QQuickItem* OffscreenUi::getDesktop() { diff --git a/libraries/ui/src/OffscreenUi.h b/libraries/ui/src/OffscreenUi.h index de479853f3..8b00180d43 100644 --- a/libraries/ui/src/OffscreenUi.h +++ b/libraries/ui/src/OffscreenUi.h @@ -106,6 +106,9 @@ public: // Compatibility with QInputDialog::getItem static QString getItem(void *ignored, const QString & title, const QString & label, const QStringList & items, int current = 0, bool editable = true, bool * ok = 0, Qt::WindowFlags flags = 0, Qt::InputMethodHints inputMethodHints = Qt::ImhNone); +signals: + void showDesktop(); + private: QString fileDialog(const QVariantMap& properties);