From 53a6992728ec2f200b67123dd212b16e5e341a80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Wed, 21 May 2014 18:34:41 +0200 Subject: [PATCH] fix alpha blending + add depth/stencil buffers --- common/glfw_view.cpp | 4 + include/llmr/map/map.hpp | 16 +--- include/llmr/map/source.hpp | 4 +- include/llmr/renderer/painter.hpp | 26 ++++- src/geometry/sprite_atlas.cpp | 16 +++- src/map/map.cpp | 133 ++++++-------------------- src/map/source.cpp | 22 +++-- src/renderer/painter.cpp | 14 ++- src/renderer/painter_clipping.cpp | 41 ++++---- src/renderer/painter_composite.cpp | 17 +++- src/renderer/painter_framebuffers.cpp | 111 +++++++++++++++++++++ src/shader/composite.fragment.glsl | 3 +- src/shader/composite.vertex.glsl | 2 +- src/shader/shaders_gl.cpp | 4 +- src/shader/shaders_gles2.cpp | 4 +- 15 files changed, 252 insertions(+), 165 deletions(-) create mode 100644 src/renderer/painter_framebuffers.cpp diff --git a/common/glfw_view.cpp b/common/glfw_view.cpp index dcfaf6591..9590cc5e7 100644 --- a/common/glfw_view.cpp +++ b/common/glfw_view.cpp @@ -261,6 +261,10 @@ void show_color_debug_image(std::string name, const char *data, size_t logical_w float x_scale = (float)fb_width / (float)width; float y_scale = (float)fb_height / (float)height; + glClear(GL_COLOR_BUFFER_BIT); + glEnable(GL_BLEND); + glBlendFunc(GL_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glPixelZoom(x_scale, -y_scale); glRasterPos2f(-1.0f, 1.0f); glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, data); diff --git a/include/llmr/map/map.hpp b/include/llmr/map/map.hpp index 3f294cf8c..8dc1e0f71 100644 --- a/include/llmr/map/map.hpp +++ b/include/llmr/map/map.hpp @@ -22,6 +22,8 @@ namespace llmr { class Source; +typedef std::map> Sources; + class Map : private util::noncopyable { public: explicit Map(View &view); @@ -96,6 +98,7 @@ public: inline uv_loop_t *getLoop() { return loop; } inline time getAnimationTime() const { return animationTime; } inline Texturepool &getTexturepool() { return texturepool; } + inline const Sources &getSources() { return sources; } private: // uv async callbacks @@ -108,7 +111,7 @@ private: void loadStyle(const uint8_t *const data, uint32_t bytes); void updateTiles(); - void updateClippingIDs(); + void updateRenderState(); size_t countLayers(const std::vector& layers); @@ -123,11 +126,6 @@ private: void renderLayers(const std::vector& layers); void renderLayer(const LayerDescription& layer_desc, RenderPass pass); - void clearFramebuffers(); - void bindFramebuffer(); - void pushFramebuffer(); - GLuint popFramebuffer(); - private: // If cleared, the next time the render thread attempts to render the map, it will *actually* // render the map. @@ -152,17 +150,13 @@ private: SpriteAtlas spriteAtlas; Painter painter; - std::map> sources; + Sources sources; bool debug = false; time animationTime = 0; int indent = 0; - std::vector fbos; - std::vector fbos_color; - int fbo_level = -1; - private: bool async = false; uv_loop_t *loop = nullptr; diff --git a/include/llmr/map/source.hpp b/include/llmr/map/source.hpp index 40b3bf4cf..7ce6aa632 100644 --- a/include/llmr/map/source.hpp +++ b/include/llmr/map/source.hpp @@ -36,7 +36,9 @@ public: bool update(); - size_t prepareRender(const TransformState &transform); + void updateMatrices(const TransformState &transform); + void drawClippingMasks(); + size_t getTileCount() const; void render(const LayerDescription& layer_desc, const BucketDescription &bucket_desc); void finishRender(); diff --git a/include/llmr/renderer/painter.hpp b/include/llmr/renderer/painter.hpp index 1adc32be1..585958648 100644 --- a/include/llmr/renderer/painter.hpp +++ b/include/llmr/renderer/painter.hpp @@ -22,12 +22,15 @@ #include +#include + namespace llmr { class Transform; class Style; class Tile; class GlyphAtlas; +class Source; class FillBucket; class LineBucket; @@ -38,9 +41,12 @@ class RasterBucket; class LayerDescription; class RasterTileData; +typedef std::map> Sources; + class Painter : private util::noncopyable { public: Painter(Map &map); + ~Painter(); void setup(); @@ -76,17 +82,20 @@ public: void setDebug(bool enabled); // Opaque/Translucent pass setting - void startOpaquePass(); - void startTranslucentPass(); - void endPass(); + void setOpaque(); + void setTranslucent(); // Configures the painter strata that is used for early z-culling of fragments. void setStrata(float strata); - void prepareClippingMask(); + void drawClippingMasks(const Sources &sources); void drawClippingMask(const mat4& matrix, const ClipID& clip); - void finishClippingMask(); + void clearFramebuffers(); + void resetFramebuffer(); + void bindFramebuffer(); + void pushFramebuffer(); + GLuint popFramebuffer(); void drawComposite(GLuint texture, const CompositeProperties &properties); bool needsAnimation() const; @@ -163,6 +172,13 @@ private: VertexArrayObject tileBorderArray; + // Framebuffer management + std::vector fbos; + std::vector fbos_color; + GLuint fbo_depth_stencil; + int fbo_level = -1; + bool fbo_depth_stencil_valid = false; + }; } diff --git a/src/geometry/sprite_atlas.cpp b/src/geometry/sprite_atlas.cpp index 431aad973..eb5de3cfd 100644 --- a/src/geometry/sprite_atlas.cpp +++ b/src/geometry/sprite_atlas.cpp @@ -55,11 +55,23 @@ bool SpriteAtlas::resize(const float newRatio) { void copy_bitmap(const uint32_t *src, const int src_stride, const int src_x, const int src_y, uint32_t *dst, const int dst_stride, const int dst_x, const int dst_y, const int width, const int height) { - const int stride = width * sizeof(uint32_t); src += src_y * src_stride + src_x; dst += dst_y * dst_stride + dst_x; for (int y = 0; y < height; y++, src += src_stride, dst += dst_stride) { - memcpy(dst, src, stride); + for (int x = 0; x < width; x++) { + const uint8_t *s = reinterpret_cast(src + x); + uint8_t *d = reinterpret_cast(dst + x); + + // Premultiply the bitmap. + // Note: We don't need to clamp the component values to 0..255, since + // the source value is already 0..255 and the operation means they will + // stay within the range of 0..255 and won't overflow. + const uint8_t a = s[3]; + d[0] = s[0] * a / 255; + d[1] = s[1] * a / 255; + d[2] = s[2] * a / 255; + d[3] = a; + } } } diff --git a/src/map/map.cpp b/src/map/map.cpp index d929c1adc..cb2d27dfb 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -35,8 +35,6 @@ Map::Map(View& view) } Map::~Map() { - clearFramebuffers(); - uv_loop_delete(loop); loop = nullptr; } @@ -185,10 +183,15 @@ void Map::resize(uint16_t width, uint16_t height, float ratio, uint16_t fb_width if (transform.resize(width, height, ratio, fb_width, fb_height)) { changed = true; } + + // TODO: Make sure we're not currently rendering anything if (spriteAtlas.resize(ratio)) { changed = true; } + // TODO: Make sure we're not currently rendering anything + painter.clearFramebuffers(); + if (changed) { update(); } @@ -369,24 +372,23 @@ void Map::updateTiles() { } } - - -void Map::updateClippingIDs() { +void Map::updateRenderState() { std::forward_list ids; - for (auto &pair : sources) { - const std::unique_ptr &source = pair.second; - if (source->enabled) { - ids.splice_after(ids.before_begin(), source->getIDs()); + for (const auto &pair : sources) { + Source &source = *pair.second; + if (source.enabled) { + ids.splice_after(ids.before_begin(), source.getIDs()); + source.updateMatrices(state); } } const std::map clipIDs = computeClipIDs(ids); - for (auto &pair : sources) { - const std::unique_ptr &source = pair.second; - if (source->enabled) { - source->updateClipIDs(clipIDs); + for (const auto &pair : sources) { + Source &source = *pair.second; + if (source.enabled) { + source.updateClipIDs(clipIDs); } } } @@ -413,8 +415,6 @@ void Map::prepare() { } updateTiles(); - - updateClippingIDs(); } void Map::render() { @@ -422,26 +422,25 @@ void Map::render() { painter.clear(); + painter.resetFramebuffer(); + painter.resize(); painter.changeMatrix(); - // First, update the sources' tile matrices with the new - // transform and render into the stencil buffer, including - // drawing the background. + updateRenderState(); - painter.prepareClippingMask(); + painter.drawClippingMasks(sources); + // Generate debug information size_t source_id = 0; - for (auto &pair : sources) { - Source &source = *pair.second; - size_t count = source.prepareRender(state); + for (const auto &pair : sources) { + const Source &source = *pair.second; + size_t count = source.getTileCount(); debug.emplace_back(util::sprintf<100>("source %d: %d\n", source_id, count)); source_id++; } - painter.finishClippingMask(); - // Actually render the layers if (debug::renderTree) { std::cout << "{" << std::endl; indent++; } renderLayers(style.layers); @@ -451,7 +450,7 @@ void Map::render() { // This guarantees that we have at least one function per tile called. // When only rendering layers via the stylesheet, it's possible that we don't // ever visit a tile during rendering. - for (auto &pair : sources) { + for (const auto &pair : sources) { Source &source = *pair.second; const std::string &name = pair.first; gl::group group(std::string("debug ") + name); @@ -481,14 +480,14 @@ void Map::renderLayers(const std::vector& layers) { if (debug::renderTree) { std::cout << std::string(indent++ * 4, ' ') << "OPAQUE {" << std::endl; } - painter.startOpaquePass(); typedef std::vector::const_reverse_iterator riterator; int i = 0; for (riterator it = layers.rbegin(), end = layers.rend(); it != end; ++it, ++i) { + painter.setOpaque(); painter.setStrata(i * strata_thickness); renderLayer(*it, Opaque); } - painter.endPass(); + // painter.endPass(); if (debug::renderTree) { std::cout << std::string(--indent * 4, ' ') << "}" << std::endl; } @@ -499,14 +498,14 @@ void Map::renderLayers(const std::vector& layers) { if (debug::renderTree) { std::cout << std::string(indent++ * 4, ' ') << "TRANSLUCENT {" << std::endl; } - painter.startTranslucentPass(); typedef std::vector::const_iterator iterator; --i; for (iterator it = layers.begin(), end = layers.end(); it != end; ++it, --i) { + painter.setTranslucent(); painter.setStrata(i * strata_thickness); renderLayer(*it, Translucent); } - painter.endPass(); + // painter.endPass(); if (debug::renderTree) { std::cout << std::string(--indent * 4, ' ') << "}" << std::endl; } @@ -554,13 +553,11 @@ void Map::renderLayer(const LayerDescription& layer_desc, RenderPass pass) { << " (Composite) {" << std::endl; } - pushFramebuffer(); - - glClear(GL_COLOR_BUFFER_BIT); + painter.pushFramebuffer(); renderLayers(layer_desc.child_layer); - GLuint texture = popFramebuffer(); + GLuint texture = painter.popFramebuffer(); // Render the previous texture onto the screen. painter.drawComposite(texture, properties); @@ -630,73 +627,3 @@ void Map::renderLayer(const LayerDescription& layer_desc, RenderPass pass) { } } } - -void Map::clearFramebuffers() { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - - // Delete any framebuffers that we might have allocated - glDeleteTextures(fbos_color.size(), fbos.data()); - fbos_color.clear(); - - glDeleteFramebuffersEXT(fbos.size(), fbos.data()); - fbos.clear(); -} - -void Map::bindFramebuffer() { - if (fbo_level < 0) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - } else if (fbos.size() > (size_t)fbo_level) { - GLuint fbo = fbos[fbo_level]; - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); - } else { - // TODO: Convert this to textures so we can composite them and use them in blend operations - - GLuint fbo_color; - glGenTextures(1, &fbo_color); - glBindTexture(GL_TEXTURE_2D, fbo_color); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - 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_RGBA8, state.getFramebufferWidth(), state.getFramebufferHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - glBindTexture(GL_TEXTURE_2D, 0); - fbos_color.emplace_back(fbo_color); - - // TODO: Stencil/Depth buffer - - // Allocate new framebuffer - GLuint fbo = 0; - glGenFramebuffersEXT(1, &fbo); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); - fbos.emplace_back(fbo); - - // Assemble the FBO - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo_color, 0); - // TODO: Stencil/Depth buffer - - GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { - fprintf(stderr, "Couldn't create framebuffer: "); - switch (status) { - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: fprintf(stderr, "incomplete attachment\n"); break; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: fprintf(stderr, "incomplete missing attachment\n"); break; - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: fprintf(stderr, "incomplete draw buffer\n"); break; - case GL_FRAMEBUFFER_UNSUPPORTED: fprintf(stderr, "unsupported\n"); break; - default: fprintf(stderr, "other\n"); break; - } - return; - } - } -} - -void Map::pushFramebuffer() { - fbo_level++; - bindFramebuffer(); -} - -GLuint Map::popFramebuffer() { - GLuint texture = fbos_color[fbo_level]; - fbo_level--; - bindFramebuffer(); - return texture; -} diff --git a/src/map/source.cpp b/src/map/source.cpp index 91ccdbc9c..2491e083e 100644 --- a/src/map/source.cpp +++ b/src/map/source.cpp @@ -45,27 +45,31 @@ void Source::updateClipIDs(const std::map &mapping) { }); } -size_t Source::prepareRender(const TransformState &transform) { - if (!enabled) return 0; +void Source::updateMatrices(const TransformState &transform) { + for (std::pair> &pair : tiles) { + Tile &tile = *pair.second; + transform.matrixFor(tile.matrix, tile.id); + matrix::multiply(tile.matrix, painter.projMatrix, tile.matrix); + } +} - size_t masks = 0; +size_t Source::getTileCount() const { + return tiles.size(); +} + +void Source::drawClippingMasks() { for (std::pair> &pair : tiles) { Tile &tile = *pair.second; gl::group group(util::sprintf<32>("mask %d/%d/%d", tile.id.z, tile.id.y, tile.id.z)); - transform.matrixFor(tile.matrix, tile.id); - matrix::multiply(tile.matrix, painter.projMatrix, tile.matrix); painter.drawClippingMask(tile.matrix, tile.clip); - masks++; } - - return masks; } void Source::render(const LayerDescription& layer_desc, const BucketDescription &bucket_desc) { if (!enabled) return; gl::group group(std::string("layer: ") + layer_desc.name); - for (std::pair> &pair : tiles) { + for (const std::pair> &pair : tiles) { Tile &tile = *pair.second; if (tile.data && tile.data->state == TileData::State::parsed) { painter.renderTileLayer(tile, layer_desc); diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp index 9927cb285..9a390765c 100644 --- a/src/renderer/painter.cpp +++ b/src/renderer/painter.cpp @@ -20,6 +20,10 @@ Painter::Painter(Map &map) : map(map) { } +Painter::~Painter() { + clearFramebuffers(); +} + bool Painter::needsAnimation() const { return frameHistory.needsAnimation(300); } @@ -133,24 +137,18 @@ void Painter::clear() { #endif } -void Painter::startOpaquePass() { - gl::start_group("opaque pass"); +void Painter::setOpaque() { pass = Opaque; glDisable(GL_BLEND); depthMask(true); } -void Painter::startTranslucentPass() { - gl::start_group("translucent pass"); +void Painter::setTranslucent() { pass = Translucent; glEnable(GL_BLEND); depthMask(false); } -void Painter::endPass() { - gl::end_group(); -} - void Painter::setStrata(float value) { strata = value; } diff --git a/src/renderer/painter_clipping.cpp b/src/renderer/painter_clipping.cpp index 140555237..bb41eb0ec 100644 --- a/src/renderer/painter_clipping.cpp +++ b/src/renderer/painter_clipping.cpp @@ -1,18 +1,39 @@ #include #include #include +#include #include using namespace llmr; -void Painter::prepareClippingMask() { - gl::start_group("clipping masks"); +void Painter::drawClippingMasks(const Sources &sources) { + gl::group group("clipping masks"); + useProgram(plainShader->program); glDisable(GL_DEPTH_TEST); depthMask(false); glDepthRange(1.0f, 1.0f); + glStencilMask(0xFF); + + Color background = map.getStyle().computed.background.color; + background[0] *= map.getStyle().computed.background.opacity; + background[1] *= map.getStyle().computed.background.opacity; + background[2] *= map.getStyle().computed.background.opacity; + background[3] *= map.getStyle().computed.background.opacity; + plainShader->setColor(background); coveringPlainArray.bind(*plainShader, tileStencilBuffer, BUFFER_OFFSET(0)); + + for (const auto &pair : sources) { + Source &source = *pair.second; + if (source.enabled) { + source.drawClippingMasks(); + } + } + + glEnable(GL_DEPTH_TEST); + depthMask(true); + glStencilMask(0x0); } void Painter::drawClippingMask(const mat4& matrix, const ClipID &clip) { @@ -21,22 +42,6 @@ void Painter::drawClippingMask(const mat4& matrix, const ClipID &clip) { GLint id = clip.mask.to_ulong(); GLuint mask = clipMask[clip.length]; glStencilFunc(GL_ALWAYS, id, mask); - glStencilMask(0xFF); - - Color background = map.getStyle().computed.background.color; - background[0] *= map.getStyle().computed.background.opacity; - background[1] *= map.getStyle().computed.background.opacity; - background[2] *= map.getStyle().computed.background.opacity; - background[3] *= map.getStyle().computed.background.opacity; - - plainShader->setColor(background); glDrawArrays(GL_TRIANGLES, 0, (GLsizei)tileStencilBuffer.index()); } - -void Painter::finishClippingMask() { - glEnable(GL_DEPTH_TEST); - depthMask(true); - glStencilMask(0x0); - gl::end_group(); -} diff --git a/src/renderer/painter_composite.cpp b/src/renderer/painter_composite.cpp index 43a3deb40..ac73bc80c 100644 --- a/src/renderer/painter_composite.cpp +++ b/src/renderer/painter_composite.cpp @@ -5,8 +5,14 @@ using namespace llmr; void Painter::drawComposite(GLuint texture, const CompositeProperties &properties) { + // We're doing full-screen framebuffer blending, so no need to do stencil testing here. glDisable(GL_STENCIL_TEST); + // Normally, we're using premultiplied alpha, but the resulting image we've + // just drawn is non-premultiplied. That means when blending, we have to make + // sure that we account for that. + glBlendFunc(GL_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + useProgram(compositeShader->program); compositeShader->setMatrix(nativeMatrix); @@ -14,12 +20,19 @@ void Painter::drawComposite(GLuint texture, const CompositeProperties &propertie glBindTexture(GL_TEXTURE_2D, texture); compositeShader->setImage(0); - // TODO: layerstyle + // TODO: translate compositeShader->setOpacity(properties.opacity); - // Draw the clipping mask + // Draw the full screen texture. + // TODO: Do more blend effects like multiply + blur compositeArray.bind(*compositeShader, tileStencilBuffer, BUFFER_OFFSET(0)); glDrawArrays(GL_TRIANGLES, 0, (GLsizei)tileStencilBuffer.index()); + glBindTexture(GL_TEXTURE_2D, 0); + + // Reset back. glEnable(GL_STENCIL_TEST); + + // Reset back to use premultiplied alpha blending. + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } diff --git a/src/renderer/painter_framebuffers.cpp b/src/renderer/painter_framebuffers.cpp new file mode 100644 index 000000000..7f4c7ca48 --- /dev/null +++ b/src/renderer/painter_framebuffers.cpp @@ -0,0 +1,111 @@ +#include +#include +#include +#include + +using namespace llmr; + + +void Painter::clearFramebuffers() { + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + + // Delete any framebuffers that we might have allocated + glDeleteTextures(fbos_color.size(), fbos.data()); + fbos_color.clear(); + + if (fbo_depth_stencil != 0) { + glDeleteRenderbuffersEXT(1, &fbo_depth_stencil); + fbo_depth_stencil = 0; + } + + glDeleteFramebuffersEXT(fbos.size(), fbos.data()); + fbos.clear(); +} + +void Painter::bindFramebuffer() { + if (fbo_level < 0) { + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + } else if (fbos.size() > (size_t)fbo_level) { + GLuint fbo = fbos[fbo_level]; + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); + } else { + // TODO: Convert this to textures so we can composite them and use them in blend operations + + GLuint fbo_color; + glGenTextures(1, &fbo_color); + glBindTexture(GL_TEXTURE_2D, fbo_color); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + 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_RGBA8, map.getState().getFramebufferWidth(), map.getState().getFramebufferHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glBindTexture(GL_TEXTURE_2D, 0); + fbos_color.emplace_back(fbo_color); + + // Use a shared depth/stencil buffer for all framebuffer objects + if (fbo_depth_stencil == 0) { + // Create depth/stencil buffer + glGenRenderbuffersEXT(1, &fbo_depth_stencil); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo_depth_stencil); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, map.getState().getFramebufferWidth(), map.getState().getFramebufferHeight()); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); + } + + // Allocate new framebuffer + GLuint fbo = 0; + glGenFramebuffersEXT(1, &fbo); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); + fbos.emplace_back(fbo); + + // Assemble the FBO + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo_color, 0); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER_EXT, fbo_depth_stencil); + + GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + fprintf(stderr, "Couldn't create framebuffer: "); + switch (status) { + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: fprintf(stderr, "incomplete attachment\n"); break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: fprintf(stderr, "incomplete missing attachment\n"); break; + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: fprintf(stderr, "incomplete draw buffer\n"); break; + case GL_FRAMEBUFFER_UNSUPPORTED: fprintf(stderr, "unsupported\n"); break; + default: fprintf(stderr, "other\n"); break; + } + return; + } + } +} + +void Painter::resetFramebuffer() { + if (fbo_level >= 0) { + fbo_level = -1; + bindFramebuffer(); + } + + fbo_depth_stencil_valid = false; +} + +void Painter::pushFramebuffer() { + fbo_level++; + bindFramebuffer(); + + if (fbo_depth_stencil_valid) { + glClear(GL_COLOR_BUFFER_BIT); + } else { + depthMask(true); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + glColorMask(false, false, false, false); + + drawClippingMasks(map.getSources()); + + glColorMask(true, true, true, true); + fbo_depth_stencil_valid = true; + } +} + +GLuint Painter::popFramebuffer() { + GLuint texture = fbos_color[fbo_level]; + fbo_level--; + bindFramebuffer(); + return texture; +} diff --git a/src/shader/composite.fragment.glsl b/src/shader/composite.fragment.glsl index 71263537e..d5adc402e 100644 --- a/src/shader/composite.fragment.glsl +++ b/src/shader/composite.fragment.glsl @@ -4,5 +4,6 @@ uniform float u_opacity; varying vec2 v_pos; void main() { - gl_FragColor = texture2D(u_image, v_pos / 2.0 + 0.5) * u_opacity; + vec4 color = texture2D(u_image, v_pos); + gl_FragColor = color * u_opacity; } diff --git a/src/shader/composite.vertex.glsl b/src/shader/composite.vertex.glsl index bae03f8fb..d7e8f0a8a 100644 --- a/src/shader/composite.vertex.glsl +++ b/src/shader/composite.vertex.glsl @@ -5,5 +5,5 @@ varying vec2 v_pos; void main() { gl_Position = u_matrix * vec4(a_pos, 0, 1); - v_pos = gl_Position.xy; + v_pos = (gl_Position.xy + 1.0) / 2.0; } diff --git a/src/shader/shaders_gl.cpp b/src/shader/shaders_gl.cpp index 9832bab72..1cd6da1b1 100644 --- a/src/shader/shaders_gl.cpp +++ b/src/shader/shaders_gl.cpp @@ -7,8 +7,8 @@ using namespace llmr; const shader_source llmr::shaders[SHADER_COUNT] = { { - "#version 120\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nvarying vec2 v_pos;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n vec4 tmpvar_2;\n tmpvar_2 = (u_matrix * tmpvar_1);\n gl_Position = tmpvar_2;\n v_pos = tmpvar_2.xy;\n}\n\n", - "#version 120\nuniform sampler2D u_image;\nuniform float u_opacity;\nvarying vec2 v_pos;\nvoid main ()\n{\n gl_FragColor = (texture2D (u_image, ((v_pos / 2.0) + 0.5)) * u_opacity);\n}\n\n", + "#version 120\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nvarying vec2 v_pos;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n vec4 tmpvar_2;\n tmpvar_2 = (u_matrix * tmpvar_1);\n gl_Position = tmpvar_2;\n v_pos = ((tmpvar_2.xy + 1.0) / 2.0);\n}\n\n", + "#version 120\nuniform sampler2D u_image;\nuniform float u_opacity;\nvarying vec2 v_pos;\nvoid main ()\n{\n gl_FragColor = (texture2D (u_image, v_pos) * u_opacity);\n}\n\n", }, { "#version 120\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nuniform float u_size;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n}\n\n", diff --git a/src/shader/shaders_gles2.cpp b/src/shader/shaders_gles2.cpp index fc55fd19e..5dd8df43d 100644 --- a/src/shader/shaders_gles2.cpp +++ b/src/shader/shaders_gles2.cpp @@ -7,8 +7,8 @@ using namespace llmr; const shader_source llmr::shaders[SHADER_COUNT] = { { - "precision highp float;\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nvarying highp vec2 v_pos;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n vec4 tmpvar_2;\n tmpvar_2 = (u_matrix * tmpvar_1);\n gl_Position = tmpvar_2;\n v_pos = tmpvar_2.xy;\n}\n\n", - "precision highp float;\nuniform sampler2D u_image;\nuniform float u_opacity;\nvarying vec2 v_pos;\nvoid main ()\n{\n lowp vec4 tmpvar_1;\n tmpvar_1 = (texture2D (u_image, ((v_pos / 2.0) + 0.5)) * u_opacity);\n gl_FragColor = tmpvar_1;\n}\n\n", + "precision highp float;\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nvarying highp vec2 v_pos;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n vec4 tmpvar_2;\n tmpvar_2 = (u_matrix * tmpvar_1);\n gl_Position = tmpvar_2;\n v_pos = ((tmpvar_2.xy + 1.0) / 2.0);\n}\n\n", + "precision highp float;\nuniform sampler2D u_image;\nuniform float u_opacity;\nvarying vec2 v_pos;\nvoid main ()\n{\n lowp vec4 tmpvar_1;\n tmpvar_1 = (texture2D (u_image, v_pos) * u_opacity);\n gl_FragColor = tmpvar_1;\n}\n\n", }, { "precision highp float;\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nuniform float u_size;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n}\n\n",