diff --git a/include/llmr/renderer/painter.hpp b/include/llmr/renderer/painter.hpp index 10f706880..f93250236 100644 --- a/include/llmr/renderer/painter.hpp +++ b/include/llmr/renderer/painter.hpp @@ -84,6 +84,7 @@ public: void renderIcon(IconBucket& bucket, const std::string& layer_name, const Tile::ID& id); void renderText(TextBucket& bucket, const std::string& layer_name, const Tile::ID& id); void renderRaster(RasterBucket& bucket, const std::string& layer_name, const Tile::ID& id); + void renderPrerenderedTexture(Bucket &bucket, const GenericProperties &properties); void resize(); @@ -114,6 +115,8 @@ private: const mat4 &translatedMatrix(const std::array &translation, const Tile::ID &id, TranslateAnchor anchor = TranslateAnchor::Map); void prepareTile(const Tile& tile); + +public: void useProgram(uint32_t program); void lineWidth(float lineWidth); void depthMask(bool value); @@ -125,6 +128,14 @@ public: mat4 nativeMatrix; mat4 extrudeMatrix; + // used to composite images and flips the geometry upside down + const mat4 flipMatrix = []{ + mat4 flipMatrix; + matrix::ortho(flipMatrix, 0, 4096, -4096, 0, 0, 1); + matrix::translate(flipMatrix, flipMatrix, 0, -4096, 0); + return flipMatrix; + }(); + private: Map& map; @@ -140,6 +151,7 @@ private: enum { Opaque, Translucent } pass = Opaque; const float strata_epsilon = 1.0f / (1 << 16); +public: std::unique_ptr plainShader; std::unique_ptr outlineShader; std::unique_ptr lineShader; diff --git a/include/llmr/renderer/prerendered_texture.hpp b/include/llmr/renderer/prerendered_texture.hpp index f74fe1d11..e35cc0321 100644 --- a/include/llmr/renderer/prerendered_texture.hpp +++ b/include/llmr/renderer/prerendered_texture.hpp @@ -6,8 +6,11 @@ namespace llmr { +class Painter; + class PrerenderedTexture : private util::noncopyable { public: + PrerenderedTexture(uint16_t size); ~PrerenderedTexture(); void bindTexture(); @@ -16,7 +19,10 @@ public: inline GLuint getTexture() const { return texture; } + void blur(Painter& painter, uint16_t passes); + private: + const uint16_t size; GLint previous_fbo = 0; GLuint fbo = 0; GLuint texture = 0; diff --git a/src/renderer/painter_fill.cpp b/src/renderer/painter_fill.cpp index 858377047..8d86716aa 100644 --- a/src/renderer/painter_fill.cpp +++ b/src/renderer/painter_fill.cpp @@ -157,10 +157,9 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons // Buffer value around the 0..4096 extent that will be drawn into the 256x256 pixel // texture. We later scale the texture so that the actual bounds will align with this // tile's bounds. The reason we do this is so that the - const int buffer = 4096 * properties.prerenderBuffer; if (!bucket.prerendered) { - bucket.prerendered = std::make_unique(); + bucket.prerendered = std::make_unique(properties.prerenderSize); glDisable(GL_DEPTH_TEST); glDisable(GL_STENCIL_TEST); @@ -179,6 +178,7 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons // essentially downscale everyting, and then upscale it later when rendering. mat4 vtxMatrix; + const int buffer = 4096 * properties.prerenderBuffer; matrix::ortho(vtxMatrix, -buffer, 4096 + buffer, -4096 - buffer, buffer, 0, 1); matrix::translate(vtxMatrix, vtxMatrix, 0, -4096, 0); @@ -188,63 +188,7 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons renderFill(bucket, properties, id, vtxMatrix); - - mat4 regularMatrix; - matrix::ortho(regularMatrix, 0, 4096, -4096, 0, 0, 1); - matrix::translate(regularMatrix, regularMatrix, 0, -4096, 0); - - - // BLUR - - GLuint original_texture = bucket.prerendered->getTexture(); - - GLuint secondary_texture; - glGenTextures(1, &secondary_texture); - glBindTexture(GL_TEXTURE_2D, secondary_texture); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, properties.prerenderSize, properties.prerenderSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - glBindTexture(GL_TEXTURE_2D, 0); - - - useProgram(gaussianShader->program); - gaussianShader->setMatrix(regularMatrix); - gaussianShader->setImage(0); - glActiveTexture(GL_TEXTURE0); - - - for (int i = 0; i < properties.prerenderBlur; i++) { - // Render horizontal - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, secondary_texture, 0); -#if GL_EXT_discard_framebuffer - const GLenum discards[] = { GL_COLOR_ATTACHMENT0 }; - glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards); -#endif - glClear(GL_COLOR_BUFFER_BIT); - - gaussianShader->setOffset({{ 1.0f / float(properties.prerenderSize), 0 }}); - glBindTexture(GL_TEXTURE_2D, original_texture); - coveringGaussianArray.bind(*gaussianShader, tileStencilBuffer, BUFFER_OFFSET(0)); - glDrawArrays(GL_TRIANGLES, 0, (GLsizei)tileStencilBuffer.index()); - - - - // Render vertical - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, original_texture, 0); -#if GL_EXT_discard_framebuffer - glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards); -#endif - glClear(GL_COLOR_BUFFER_BIT); - - gaussianShader->setOffset({{ 0, 1.0f / float(properties.prerenderSize) }}); - glBindTexture(GL_TEXTURE_2D, secondary_texture); - coveringGaussianArray.bind(*gaussianShader, tileStencilBuffer, BUFFER_OFFSET(0)); - glDrawArrays(GL_TRIANGLES, 0, (GLsizei)tileStencilBuffer.index()); - } - - glDeleteTextures(1, &secondary_texture); + bucket.prerendered->blur(*this, properties.prerenderBlur); // RESET STATE @@ -257,23 +201,7 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons glViewport(0, 0, gl_viewport[0], gl_viewport[1]); } - // draw the texture on a quad - depthMask(false); - - useProgram(rasterShader->program); - rasterShader->setMatrix(matrix); - rasterShader->setOpacity(1); - - glDepthRange(strata, 1.0f); - - glActiveTexture(GL_TEXTURE0); - rasterShader->setImage(0); - rasterShader->setBuffer(buffer); - bucket.prerendered->bindTexture(); - coveringRasterArray.bind(*rasterShader, tileStencilBuffer, BUFFER_OFFSET(0)); - glDrawArrays(GL_TRIANGLES, 0, (GLsizei)tileStencilBuffer.index()); - - depthMask(true); + renderPrerenderedTexture(bucket, properties); } } else { const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor); diff --git a/src/renderer/painter_prerender.cpp b/src/renderer/painter_prerender.cpp new file mode 100644 index 000000000..7d6abcb35 --- /dev/null +++ b/src/renderer/painter_prerender.cpp @@ -0,0 +1,25 @@ +#include + +using namespace llmr; + +void Painter::renderPrerenderedTexture(Bucket &bucket, const GenericProperties &properties) { + const int buffer = 4096 * properties.prerenderBuffer; + + // draw the texture on a quad + depthMask(false); + + useProgram(rasterShader->program); + rasterShader->setMatrix(matrix); + rasterShader->setOpacity(1); + + glDepthRange(strata, 1.0f); + + glActiveTexture(GL_TEXTURE0); + rasterShader->setImage(0); + rasterShader->setBuffer(buffer); + bucket.prerendered->bindTexture(); + coveringRasterArray.bind(*rasterShader, tileStencilBuffer, BUFFER_OFFSET(0)); + glDrawArrays(GL_TRIANGLES, 0, (GLsizei)tileStencilBuffer.index()); + + depthMask(true); +} diff --git a/src/renderer/prerendered_texture.cpp b/src/renderer/prerendered_texture.cpp index 3fd81ccdf..408f433be 100644 --- a/src/renderer/prerendered_texture.cpp +++ b/src/renderer/prerendered_texture.cpp @@ -1,8 +1,13 @@ #include +#include using namespace llmr; +PrerenderedTexture::PrerenderedTexture(uint16_t size) + : size(size) { +} + PrerenderedTexture::~PrerenderedTexture() { if (texture != 0) { glDeleteTextures(1, &texture); @@ -40,7 +45,7 @@ void PrerenderedTexture::bindFramebuffer() { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glBindTexture(GL_TEXTURE_2D, 0); } @@ -78,3 +83,55 @@ void PrerenderedTexture::unbindFramebuffer() { fbo = 0; } } + +void PrerenderedTexture::blur(Painter& painter, uint16_t passes) { + const GLuint original_texture = texture; + + // Create a secondary texture + GLuint secondary_texture; + glGenTextures(1, &secondary_texture); + glBindTexture(GL_TEXTURE_2D, secondary_texture); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glBindTexture(GL_TEXTURE_2D, 0); + + + painter.useProgram(painter.gaussianShader->program); + painter.gaussianShader->setMatrix(painter.flipMatrix); + painter.gaussianShader->setImage(0); + glActiveTexture(GL_TEXTURE0); + + for (int i = 0; i < passes; i++) { + // Render horizontal + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, secondary_texture, 0); +#if GL_EXT_discard_framebuffer + const GLenum discards[] = { GL_COLOR_ATTACHMENT0 }; + glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards); +#endif + glClear(GL_COLOR_BUFFER_BIT); + + painter.gaussianShader->setOffset({{ 1.0f / float(size), 0 }}); + glBindTexture(GL_TEXTURE_2D, original_texture); + painter.coveringGaussianArray.bind(*painter.gaussianShader, painter.tileStencilBuffer, BUFFER_OFFSET(0)); + glDrawArrays(GL_TRIANGLES, 0, (GLsizei)painter.tileStencilBuffer.index()); + + + + // Render vertical + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, original_texture, 0); +#if GL_EXT_discard_framebuffer + glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards); +#endif + glClear(GL_COLOR_BUFFER_BIT); + + painter.gaussianShader->setOffset({{ 0, 1.0f / float(size) }}); + glBindTexture(GL_TEXTURE_2D, secondary_texture); + painter.coveringGaussianArray.bind(*painter.gaussianShader, painter.tileStencilBuffer, BUFFER_OFFSET(0)); + glDrawArrays(GL_TRIANGLES, 0, (GLsizei)painter.tileStencilBuffer.index()); + } + + glDeleteTextures(1, &secondary_texture); +}