From 13939b26d9dd270294f3491759362f62a52a8a13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Tue, 20 May 2014 17:38:52 +0200 Subject: [PATCH] first shot at composited blending still missing: - stencil+depth mask - alpha compositing --- include/llmr/geometry/buffer.hpp | 17 +++- include/llmr/map/map.hpp | 9 ++ include/llmr/renderer/painter.hpp | 6 ++ include/llmr/shader/composite_shader.hpp | 29 ++++++ include/llmr/shader/raster_shader.hpp | 7 +- include/llmr/style/class_description.hpp | 1 + include/llmr/style/properties.hpp | 10 ++ include/llmr/style/style.hpp | 1 + include/llmr/style/style_parser.hpp | 1 + include/llmr/util/constants.hpp | 6 +- src/map/map.cpp | 119 ++++++++++++++++++++--- src/renderer/line_bucket.cpp | 6 ++ src/renderer/painter.cpp | 2 + src/renderer/painter_composite.cpp | 25 +++++ src/shader/composite.fragment.glsl | 8 ++ src/shader/composite.vertex.glsl | 9 ++ src/shader/composite_shader.cpp | 48 +++++++++ src/shader/raster_shader.cpp | 1 + src/shader/shaders_gl.cpp | 4 + src/shader/shaders_gles2.cpp | 4 + src/style/style.cpp | 14 +++ src/style/style_parser.cpp | 17 ++++ src/util/constants.cpp | 4 + 23 files changed, 325 insertions(+), 23 deletions(-) create mode 100644 include/llmr/shader/composite_shader.hpp create mode 100644 src/renderer/painter_composite.cpp create mode 100644 src/shader/composite.fragment.glsl create mode 100644 src/shader/composite.vertex.glsl create mode 100644 src/shader/composite_shader.cpp diff --git a/include/llmr/geometry/buffer.hpp b/include/llmr/geometry/buffer.hpp index 6f43774e5..27807c809 100644 --- a/include/llmr/geometry/buffer.hpp +++ b/include/llmr/geometry/buffer.hpp @@ -40,7 +40,10 @@ public: } glBindBuffer(bufferType, buffer); if (force) { - assert("Buffer was already deleted" && array != nullptr); + if (array == nullptr) { + throw std::runtime_error("Buffer was already deleted or doesn't contain elements"); + } + glBufferData(bufferType, pos, array, GL_STATIC_DRAW); if (!retainAfterUpload) { cleanup(); @@ -58,11 +61,15 @@ public: protected: // increase the buffer size by at least /required/ bytes. inline void *addElement() { - assert("Buffer is already bound to GPU" && buffer == 0); + if (buffer != 0) { + throw std::runtime_error("Can't add elements after buffer was bound to GPU"); + } if (length < pos + itemSize) { while (length < pos + itemSize) length += defaultLength; array = realloc(array, length); - assert("Buffer reallocation failed" && array != nullptr); + if (array == nullptr) { + throw std::runtime_error("Buffer reallocation failed¯"); + } } pos += itemSize; return static_cast(array) + (pos - itemSize); @@ -70,7 +77,9 @@ protected: // Get a pointer to the item at a given index. inline void *getElement(size_t index) { - assert("Buffer was deleted" && array != nullptr); + if (array == nullptr) { + throw std::runtime_error("Buffer was already deleted or doesn't contain elements"); + } if (index * itemSize >= pos) { throw new std::runtime_error("Can't get element after array bounds"); diff --git a/include/llmr/map/map.hpp b/include/llmr/map/map.hpp index a7965500d..3f294cf8c 100644 --- a/include/llmr/map/map.hpp +++ b/include/llmr/map/map.hpp @@ -123,6 +123,11 @@ 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. @@ -154,6 +159,10 @@ private: 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/renderer/painter.hpp b/include/llmr/renderer/painter.hpp index 09ee8e42f..1adc32be1 100644 --- a/include/llmr/renderer/painter.hpp +++ b/include/llmr/renderer/painter.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -86,6 +87,8 @@ public: void drawClippingMask(const mat4& matrix, const ClipID& clip); void finishClippingMask(); + void drawComposite(GLuint texture, const CompositeProperties &properties); + bool needsAnimation() const; private: void setupShaders(); @@ -127,6 +130,7 @@ private: std::unique_ptr rasterShader; std::unique_ptr textShader; std::unique_ptr dotShader; + std::unique_ptr compositeShader; // Set up the stencil quad we're using to generate the stencil mask. VertexBuffer tileStencilBuffer = { @@ -144,6 +148,8 @@ private: VertexArrayObject coveringPlainArray; VertexArrayObject coveringPatternArray; VertexArrayObject coveringRasterArray; + + VertexArrayObject compositeArray; VertexArrayObject matteArray; // Set up the tile boundary lines we're using to draw the tile outlines. diff --git a/include/llmr/shader/composite_shader.hpp b/include/llmr/shader/composite_shader.hpp new file mode 100644 index 000000000..31156485c --- /dev/null +++ b/include/llmr/shader/composite_shader.hpp @@ -0,0 +1,29 @@ +#ifndef LLMR_SHADER_COMPOSITE_SHADER +#define LLMR_SHADER_COMPOSITE_SHADER + +#include + +namespace llmr { + +class CompositeShader : public Shader { +public: + CompositeShader(); + + void bind(char *offset); + + void setImage(int32_t image); + void setOpacity(float opacity); + +private: + int32_t a_pos = -1; + + int32_t image = 0; + int32_t u_image = -1; + + float opacity = 0; + int32_t u_opacity = -1; +}; + +} + +#endif diff --git a/include/llmr/shader/raster_shader.hpp b/include/llmr/shader/raster_shader.hpp index 00f423cbf..d037b6e80 100644 --- a/include/llmr/shader/raster_shader.hpp +++ b/include/llmr/shader/raster_shader.hpp @@ -17,10 +17,11 @@ public: private: int32_t a_pos = -1; - int32_t image = -1; + int32_t image = 0; int32_t u_image = -1; - float opacity = 0.0f; - float u_opacity = 0.0f; + + float opacity = 0; + int32_t u_opacity = -1; }; } diff --git a/include/llmr/style/class_description.hpp b/include/llmr/style/class_description.hpp index 782f5da4f..216ddeb70 100644 --- a/include/llmr/style/class_description.hpp +++ b/include/llmr/style/class_description.hpp @@ -16,6 +16,7 @@ public: std::map icon; std::map text; std::map raster; + std::map composite; }; diff --git a/include/llmr/style/properties.hpp b/include/llmr/style/properties.hpp index 978b4be15..b4e134d65 100644 --- a/include/llmr/style/properties.hpp +++ b/include/llmr/style/properties.hpp @@ -180,6 +180,16 @@ struct RasterProperties { float opacity = 1.0; }; +struct CompositeClass { + FunctionProperty enabled = true; + FunctionProperty opacity = 1; +}; + +struct CompositeProperties { + bool enabled = true; + float opacity = 1.0; +}; + } #endif diff --git a/include/llmr/style/style.hpp b/include/llmr/style/style.hpp index d9c8c22bd..920d0c6c1 100644 --- a/include/llmr/style/style.hpp +++ b/include/llmr/style/style.hpp @@ -50,6 +50,7 @@ public: std::map icons; std::map texts; std::map rasters; + std::map composites; } computed; }; diff --git a/include/llmr/style/style_parser.hpp b/include/llmr/style/style_parser.hpp index 21a16177d..82dd7e9b5 100644 --- a/include/llmr/style/style_parser.hpp +++ b/include/llmr/style/style_parser.hpp @@ -36,6 +36,7 @@ private: TextClass parseTextClass(JSVal value); BackgroundClass parseBackgroundClass(JSVal value); RasterClass parseRasterClass(JSVal value); + CompositeClass parseCompositeClass(JSVal value); bool parseBoolean(JSVal value); std::string parseString(JSVal value); diff --git a/include/llmr/util/constants.hpp b/include/llmr/util/constants.hpp index 3cdcd7c16..9df24eb6b 100644 --- a/include/llmr/util/constants.hpp +++ b/include/llmr/util/constants.hpp @@ -14,9 +14,9 @@ extern const float tileSize; namespace debug { -const bool styleParseWarnings = true; -const bool renderWarnings = true; -const bool renderTree = true; +extern const bool styleParseWarnings; +extern const bool renderWarnings; +extern const bool renderTree; } diff --git a/src/map/map.cpp b/src/map/map.cpp index 7b2330256..18a53be2b 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -35,6 +35,8 @@ Map::Map(View& view) } Map::~Map() { + clearFramebuffers(); + uv_loop_delete(loop); loop = nullptr; } @@ -513,38 +515,59 @@ void Map::renderLayers(const std::vector& layers) { } template -bool is_invisible(const Styles &styles, const LayerDescription &layer_desc) { +typename Styles::const_iterator find_style(const Styles &styles, const LayerDescription &layer_desc) { auto it = styles.find(layer_desc.name); if (it == styles.end()) { if (debug::renderWarnings) { fprintf(stderr, "[WARNING] can't find class named '%s' in style\n", layer_desc.name.c_str()); } - return true; } - const auto &properties = it->second; + return it; +} + +template +bool is_invisible(const Properties &properties) { if (!properties.enabled) { return true; } if (properties.opacity <= 0) { return true; } return false; } +template +bool is_invisible(const Styles &styles, const LayerDescription &layer_desc) { + auto it = find_style(styles, layer_desc); + if (it == styles.end()) { return true; } + return is_invisible(it->second); +} + void Map::renderLayer(const LayerDescription& layer_desc, RenderPass pass) { if (layer_desc.child_layer.size()) { // This is a layer group. We render them during our translucent render pass. if (pass == Translucent) { - gl::group group(std::string("group: ") + layer_desc.name); + auto it = find_style(style.computed.composites, layer_desc); + if (it != style.computed.composites.end() && !is_invisible(it->second)) { + const CompositeProperties &properties = it->second; + gl::group group(std::string("group: ") + layer_desc.name); - if (debug::renderTree) { - std::cout << std::string(indent++ * 4, ' ') << "+ " << layer_desc.name - << " (Composite) {" << std::endl; - } + if (debug::renderTree) { + std::cout << std::string(indent++ * 4, ' ') << "+ " << layer_desc.name + << " (Composite) {" << std::endl; + } - // TODO: create framebuffer - renderLayers(layer_desc.child_layer); - // TODO: render framebuffer on previous framebuffer + pushFramebuffer(); - if (debug::renderTree) { - std::cout << std::string(--indent * 4, ' ') << "}" << std::endl; + glClear(GL_COLOR_BUFFER_BIT); + + renderLayers(layer_desc.child_layer); + + GLuint texture = popFramebuffer(); + + // Render the previous texture onto the screen. + painter.drawComposite(texture, properties); + + if (debug::renderTree) { + std::cout << std::string(--indent * 4, ' ') << "}" << std::endl; + } } } } else if (layer_desc.bucket_name == "background") { @@ -607,3 +630,73 @@ 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/renderer/line_bucket.cpp b/src/renderer/line_bucket.cpp index a253d495d..48ccc096f 100644 --- a/src/renderer/line_bucket.cpp +++ b/src/renderer/line_bucket.cpp @@ -360,6 +360,9 @@ void LineBucket::drawLines(LineShader& shader) { char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize); char *elements_index = BUFFER_OFFSET(triangle_elements_start * triangleElementsBuffer.itemSize); for (triangle_group_type& group : triangleGroups) { + if (!group.elements_length) { + continue; + } group.array.bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index); glDrawElements(GL_TRIANGLES, group.elements_length * 3, GL_UNSIGNED_SHORT, elements_index); vertex_index += group.vertex_length * vertexBuffer.itemSize; @@ -371,6 +374,9 @@ void LineBucket::drawPoints(LinejoinShader& shader) { char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize); char *elements_index = BUFFER_OFFSET(point_elements_start * pointElementsBuffer.itemSize); for (point_group_type& group : pointGroups) { + if (!group.elements_length) { + continue; + } group.array.bind(shader, vertexBuffer, pointElementsBuffer, vertex_index); glDrawElements(GL_POINTS, group.elements_length, GL_UNSIGNED_SHORT, elements_index); vertex_index += group.vertex_length * vertexBuffer.itemSize; diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp index a172b8151..9927cb285 100644 --- a/src/renderer/painter.cpp +++ b/src/renderer/painter.cpp @@ -38,6 +38,7 @@ void Painter::setup() { assert(rasterShader); assert(textShader); assert(dotShader); + assert(compositeShader); // Blending @@ -67,6 +68,7 @@ void Painter::setupShaders() { rasterShader = std::make_unique(); textShader = std::make_unique(); dotShader = std::make_unique(); + compositeShader = std::make_unique(); } void Painter::resize() { diff --git a/src/renderer/painter_composite.cpp b/src/renderer/painter_composite.cpp new file mode 100644 index 000000000..43a3deb40 --- /dev/null +++ b/src/renderer/painter_composite.cpp @@ -0,0 +1,25 @@ +#include + +#include + +using namespace llmr; + +void Painter::drawComposite(GLuint texture, const CompositeProperties &properties) { + glDisable(GL_STENCIL_TEST); + + useProgram(compositeShader->program); + compositeShader->setMatrix(nativeMatrix); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture); + compositeShader->setImage(0); + + // TODO: layerstyle + compositeShader->setOpacity(properties.opacity); + + // Draw the clipping mask + compositeArray.bind(*compositeShader, tileStencilBuffer, BUFFER_OFFSET(0)); + glDrawArrays(GL_TRIANGLES, 0, (GLsizei)tileStencilBuffer.index()); + + glEnable(GL_STENCIL_TEST); +} diff --git a/src/shader/composite.fragment.glsl b/src/shader/composite.fragment.glsl new file mode 100644 index 000000000..71263537e --- /dev/null +++ b/src/shader/composite.fragment.glsl @@ -0,0 +1,8 @@ +uniform sampler2D u_image; +uniform float u_opacity; + +varying vec2 v_pos; + +void main() { + gl_FragColor = texture2D(u_image, v_pos / 2.0 + 0.5) * u_opacity; +} diff --git a/src/shader/composite.vertex.glsl b/src/shader/composite.vertex.glsl new file mode 100644 index 000000000..bae03f8fb --- /dev/null +++ b/src/shader/composite.vertex.glsl @@ -0,0 +1,9 @@ +attribute vec2 a_pos; + +uniform mat4 u_matrix; +varying vec2 v_pos; + +void main() { + gl_Position = u_matrix * vec4(a_pos, 0, 1); + v_pos = gl_Position.xy; +} diff --git a/src/shader/composite_shader.cpp b/src/shader/composite_shader.cpp new file mode 100644 index 000000000..eb86b1c88 --- /dev/null +++ b/src/shader/composite_shader.cpp @@ -0,0 +1,48 @@ +#include +#include +#include + +#include + +using namespace llmr; + +CompositeShader::CompositeShader() + : Shader( + shaders[COMPOSITE_SHADER].vertex, + shaders[COMPOSITE_SHADER].fragment + ) { + if (!valid) { + fprintf(stderr, "invalid composite shader\n"); + return; + } + + a_pos = glGetAttribLocation(program, "a_pos"); + + u_matrix = glGetUniformLocation(program, "u_matrix"); + u_image = glGetUniformLocation(program, "u_image"); + u_opacity = glGetUniformLocation(program, "u_opacity"); + + // fprintf(stderr, "CompositeShader:\n"); + // fprintf(stderr, " - u_matrix: %d\n", u_matrix); + // fprintf(stderr, " - u_image: %d\n", u_image); + // fprintf(stderr, " - u_opacity: %f\n", u_opacity); +} + +void CompositeShader::bind(char *offset) { + glEnableVertexAttribArray(a_pos); + glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 0, offset); +} + +void CompositeShader::setImage(int32_t new_image) { + if (image != new_image) { + glUniform1i(u_image, new_image); + image = new_image; + } +} + +void CompositeShader::setOpacity(float new_opacity) { + if (opacity != new_opacity) { + glUniform1f(u_opacity, new_opacity); + opacity = new_opacity; + } +} diff --git a/src/shader/raster_shader.cpp b/src/shader/raster_shader.cpp index 5852c45c7..718fa9c35 100644 --- a/src/shader/raster_shader.cpp +++ b/src/shader/raster_shader.cpp @@ -19,6 +19,7 @@ RasterShader::RasterShader() a_pos = glGetAttribLocation(program, "a_pos"); u_matrix = glGetUniformLocation(program, "u_matrix"); + u_image = glGetUniformLocation(program, "u_image"); u_opacity = glGetUniformLocation(program, "u_opacity"); // fprintf(stderr, "RasterShader:\n"); diff --git a/src/shader/shaders_gl.cpp b/src/shader/shaders_gl.cpp index b053c3761..9832bab72 100644 --- a/src/shader/shaders_gl.cpp +++ b/src/shader/shaders_gl.cpp @@ -6,6 +6,10 @@ 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;\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", "#version 120\nuniform vec4 u_color;\nuniform float u_blur;\nvoid main ()\n{\n vec2 x_1;\n x_1 = (gl_PointCoord - 0.5);\n float tmpvar_2;\n tmpvar_2 = clamp (((\n sqrt(dot (x_1, x_1))\n - 0.5) / (\n (0.5 - u_blur)\n - 0.5)), 0.0, 1.0);\n gl_FragColor = (u_color * (tmpvar_2 * (tmpvar_2 * \n (3.0 - (2.0 * tmpvar_2))\n )));\n}\n\n", diff --git a/src/shader/shaders_gles2.cpp b/src/shader/shaders_gles2.cpp index 6baf95066..fc55fd19e 100644 --- a/src/shader/shaders_gles2.cpp +++ b/src/shader/shaders_gles2.cpp @@ -6,6 +6,10 @@ 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;\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", "precision highp float;\nuniform vec4 u_color;\nuniform float u_blur;\nvoid main ()\n{\n mediump vec2 x_1;\n x_1 = (gl_PointCoord - 0.5);\n mediump float tmpvar_2;\n tmpvar_2 = clamp (((\n sqrt(dot (x_1, x_1))\n - 0.5) / (\n (0.5 - u_blur)\n - 0.5)), 0.0, 1.0);\n gl_FragColor = (u_color * (tmpvar_2 * (tmpvar_2 * \n (3.0 - (2.0 * tmpvar_2))\n )));\n}\n\n", diff --git a/src/style/style.cpp b/src/style/style.cpp index 578b2c013..54528f527 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -18,6 +18,7 @@ void Style::reset() { computed.icons.clear(); computed.texts.clear(); computed.rasters.clear(); + computed.composites.clear(); } void Style::cascade(float z) { @@ -130,6 +131,19 @@ void Style::cascade(float z) { raster.opacity = layer.opacity.evaluate(z); } + // Cascade composite classes + for (const auto& composite_pair : sheetClass.composite) { + const std::string& layer_name = composite_pair.first; + const llmr::CompositeClass& layer = composite_pair.second; + + // TODO: This should be restricted to composite styles that have actual + // values so as to not override with default values. + llmr::CompositeProperties& composite = computed.composites[layer_name]; + composite.enabled = layer.enabled.evaluate(z); + composite.opacity = layer.opacity.evaluate(z); + } + + // Cascade background computed.background.color = sheetClass.background.color; computed.background.opacity = sheetClass.background.opacity.evaluate(z); diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 18ffafe58..2198d5c36 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -297,6 +297,9 @@ void StyleParser::parseClass(const std::string &name, JSVal value, ClassDescript if (bucket_name == "background") { // background buckets are fake class_desc.background = parseBackgroundClass(value); + } else if (bucket_name.length() == 0) { + // no bucket name == composite bucket. + class_desc.composite.insert({ name, std::forward(parseCompositeClass(value)) }); } else { auto bucket_it = buckets.find(bucket_name); if (bucket_it == buckets.end()) { @@ -655,6 +658,20 @@ RasterClass StyleParser::parseRasterClass(JSVal value) { return klass; } +CompositeClass StyleParser::parseCompositeClass(JSVal value) { + CompositeClass klass; + + if (value.HasMember("enabled")) { + klass.enabled = parseFunction(value["enabled"]); + } + + if (value.HasMember("opacity")) { + klass.opacity = parseFunction(value["opacity"]); + } + + return klass; +} + BackgroundClass StyleParser::parseBackgroundClass(JSVal value) { BackgroundClass klass; diff --git a/src/util/constants.cpp b/src/util/constants.cpp index 9fc4a4544..4ed363709 100644 --- a/src/util/constants.cpp +++ b/src/util/constants.cpp @@ -1,3 +1,7 @@ #include const float llmr::util::tileSize = 512.0f; + +const bool llmr::debug::styleParseWarnings = true; +const bool llmr::debug::renderWarnings = true; +const bool llmr::debug::renderTree = false;