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); +}