diff --git a/include/llmr/map/map.hpp b/include/llmr/map/map.hpp index 87d64b073..a7965500d 100644 --- a/include/llmr/map/map.hpp +++ b/include/llmr/map/map.hpp @@ -120,7 +120,7 @@ private: // Unconditionally performs a render with the current map state. void render(); - void renderLayers(const std::vector& layers, RenderPass pass); + void renderLayers(const std::vector& layers); void renderLayer(const LayerDescription& layer_desc, RenderPass pass); private: @@ -151,8 +151,8 @@ private: bool debug = false; time animationTime = 0; - float strata_thickness = 0.0f; - int strata = 0; + + int indent = 0; private: bool async = false; diff --git a/include/llmr/style/bucket_description.hpp b/include/llmr/style/bucket_description.hpp index 54593eec7..3cdc8ea4d 100644 --- a/include/llmr/style/bucket_description.hpp +++ b/include/llmr/style/bucket_description.hpp @@ -102,6 +102,7 @@ public: }; std::ostream& operator<<(std::ostream&, const BucketDescription& bucket); +std::ostream& operator<<(std::ostream&, BucketType type); } diff --git a/include/llmr/util/constants.hpp b/include/llmr/util/constants.hpp index 1419410df..3cdcd7c16 100644 --- a/include/llmr/util/constants.hpp +++ b/include/llmr/util/constants.hpp @@ -14,7 +14,9 @@ extern const float tileSize; namespace debug { -extern const bool styleParseWarnings; +const bool styleParseWarnings = true; +const bool renderWarnings = true; +const bool renderTree = true; } diff --git a/src/map/map.cpp b/src/map/map.cpp index 28c403ff3..7b2330256 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -8,9 +8,11 @@ #include #include #include +#include #include #include +#include using namespace llmr; @@ -438,27 +440,10 @@ void Map::render() { painter.finishClippingMask(); - - - // Render per layer in the stylesheet. - strata_thickness = 1.0f / (style.layerCount() + 1); - strata = 0; - - // - FIRST PASS ------------------------------------------------------------ - // Render everything top-to-bottom by using reverse iterators. Render opaque - // objects first. - painter.startOpaquePass(); - renderLayers(style.layers, Opaque); - painter.endPass(); - - // - SECOND PASS ----------------------------------------------------------- - // Make a second pass, rendering translucent objects. This time, we render - // bottom-to-top. - --strata; - painter.startTranslucentPass(); - renderLayers(style.layers, Translucent); - painter.endPass(); - + // Actually render the layers + if (debug::renderTree) { std::cout << "{" << std::endl; indent++; } + renderLayers(style.layers); + if (debug::renderTree) { std::cout << "}" << std::endl; indent--; } // Finalize the rendering, e.g. by calling debug render calls per tile. // This guarantees that we have at least one function per tile called. @@ -483,21 +468,45 @@ void Map::render() { glFlush(); } -void Map::renderLayers(const std::vector& layers, RenderPass pass) { - if (pass == Opaque) { - typedef std::vector::const_reverse_iterator riterator; - for (riterator it = layers.rbegin(), end = layers.rend(); it != end; ++it, ++strata) { - painter.setStrata(strata * strata_thickness); - renderLayer(*it, pass); - } - } else if (pass == Translucent) { - typedef std::vector::const_iterator iterator; - for (iterator it = layers.begin(), end = layers.end(); it != end; ++it, --strata) { - painter.setStrata(strata * strata_thickness); - renderLayer(*it, pass); - } - } else { - throw std::runtime_error("unknown render pass"); +void Map::renderLayers(const std::vector& layers) { + // TODO: Correctly compute the number of layers recursively beforehand. + float strata_thickness = 1.0f / (layers.size() + 1); + + // - FIRST PASS ------------------------------------------------------------ + // Render everything top-to-bottom by using reverse iterators. Render opaque + // objects first. + + 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.setStrata(i * strata_thickness); + renderLayer(*it, Opaque); + } + painter.endPass(); + if (debug::renderTree) { + std::cout << std::string(--indent * 4, ' ') << "}" << std::endl; + } + + // - SECOND PASS ----------------------------------------------------------- + // Make a second pass, rendering translucent objects. This time, we render + // bottom-to-top. + 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.setStrata(i * strata_thickness); + renderLayer(*it, Translucent); + } + painter.endPass(); + if (debug::renderTree) { + std::cout << std::string(--indent * 4, ' ') << "}" << std::endl; } glFlush(); @@ -506,23 +515,44 @@ void Map::renderLayers(const std::vector& layers, RenderPass p template bool is_invisible(const Styles &styles, const LayerDescription &layer_desc) { auto it = styles.find(layer_desc.name); - if (it == styles.end()) return true; + 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; - if (!properties.enabled) return true; - if (properties.opacity <= 0) return true; + if (!properties.enabled) { return true; } + if (properties.opacity <= 0) { return true; } return false; } void Map::renderLayer(const LayerDescription& layer_desc, RenderPass pass) { if (layer_desc.child_layer.size()) { - gl::group group(std::string("group: ") + layer_desc.name); - // This is a layer group. - // TODO: create framebuffer - renderLayers(layer_desc.child_layer, pass); - // TODO: render framebuffer on previous framebuffer + // 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); + + 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 + + if (debug::renderTree) { + std::cout << std::string(--indent * 4, ' ') << "}" << std::endl; + } + } + } else if (layer_desc.bucket_name == "background") { + // This layer defines the background color. } else { // This is a singular layer. Try to find the bucket associated with // this layer and render it. + auto bucket_it = style.buckets.find(layer_desc.bucket_name); if (bucket_it != style.buckets.end()) { const BucketDescription &bucket_desc = bucket_it->second; @@ -556,8 +586,23 @@ void Map::renderLayer(const LayerDescription& layer_desc, RenderPass pass) { // Find the source and render all tiles in it. auto source_it = sources.find(bucket_desc.source_name); if (source_it != sources.end()) { + if (debug::renderTree) { + std::cout << std::string(indent * 4, ' ') << "- " << layer_desc.name << " (" + << bucket_desc.type << ")" << std::endl; + } + const std::unique_ptr &source = source_it->second; source->render(layer_desc, bucket_desc); + } else { + if (debug::renderWarnings) { + fprintf(stderr, "[WARNING] can't find source '%s' required for bucket '%s'\n", + bucket_desc.source_name.c_str(), layer_desc.bucket_name.c_str()); + } + } + } else { + if (debug::renderWarnings) { + fprintf(stderr, "[WARNING] can't find bucket '%s' required for layer '%s'\n", + layer_desc.bucket_name.c_str(), layer_desc.name.c_str()); } } } diff --git a/src/style/bucket_description.cpp b/src/style/bucket_description.cpp index 0dc1a111d..864603e31 100644 --- a/src/style/bucket_description.cpp +++ b/src/style/bucket_description.cpp @@ -17,3 +17,15 @@ std::ostream& llmr::operator<<(std::ostream& os, const BucketDescription& bucket os << " - size: " << bucket.geometry.size << std::endl; return os; } + +std::ostream& llmr::operator<<(std::ostream& os, BucketType type) { + switch (type) { + case BucketType::None: os << "None"; return os; + case BucketType::Fill: os << "Fill"; return os; + case BucketType::Line: os << "Line"; return os; + case BucketType::Icon: os << "Icon"; return os; + case BucketType::Text: os << "Text"; return os; + case BucketType::Raster: os << "Raster"; return os; + default: os << ""; return os; + } +} \ No newline at end of file diff --git a/src/util/constants.cpp b/src/util/constants.cpp index e74f95f24..9fc4a4544 100644 --- a/src/util/constants.cpp +++ b/src/util/constants.cpp @@ -1,6 +1,3 @@ #include const float llmr::util::tileSize = 512.0f; - -// Debug flags -const bool llmr::debug::styleParseWarnings = true;