diff --git a/README.md b/README.md index fd15f0197..c2af76b08 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,8 @@ Because `libpng` isn't included in the iOS SDK, you will need to build a cross-a yourself. Run `./setup-libraries.sh`, which is derived from Mapnik's cross-architecture build scripts. This will also run `./configure`. +Then, `make iproj` to create and open an Xcode project with an iOS-specific view controller housing and basic gesture support. + Target devices: iPhone 4 and above (4S, 5, 5c, 5s) and iPad 2 and above (3, 4, mini and/or retina). ## Ubuntu diff --git a/include/llmr/map/map.hpp b/include/llmr/map/map.hpp index e82ef42b5..4600e1a96 100644 --- a/include/llmr/map/map.hpp +++ b/include/llmr/map/map.hpp @@ -109,14 +109,18 @@ private: void updateTiles(); void updateClippingIDs(); + size_t countLayers(const std::vector& layers); + // Prepares a map render by updating the tiles we need for the current view, as well as updating // the stylesheet. void prepare(); + enum RenderPass { Opaque, Translucent }; + // Unconditionally performs a render with the current map state. void render(); - void renderLayers(const std::vector& layers); - void renderLayer(const LayerDescription& layer_desc); + void renderLayers(const std::vector& layers, RenderPass pass); + void renderLayer(const LayerDescription& layer_desc, RenderPass pass); private: // If cleared, the next time the render thread attempts to render the map, it will *actually* @@ -145,6 +149,8 @@ private: bool debug = false; time animationTime = 0; + float strata_thickness = 0.0f; + int strata = 0; private: bool async = false; diff --git a/include/llmr/style/layer_description.hpp b/include/llmr/style/layer_description.hpp index 405c884e5..97cb7d6f2 100644 --- a/include/llmr/style/layer_description.hpp +++ b/include/llmr/style/layer_description.hpp @@ -11,6 +11,8 @@ public: std::string name; std::string bucket_name; std::vector child_layer; + + size_t size() const; }; std::ostream& operator<<(std::ostream&, const LayerDescription& layer); diff --git a/include/llmr/style/style.hpp b/include/llmr/style/style.hpp index 2f1e42c4f..213a0b94c 100644 --- a/include/llmr/style/style.hpp +++ b/include/llmr/style/style.hpp @@ -28,6 +28,7 @@ public: void loadJSON(const uint8_t *const data, size_t bytes); + size_t layerCount() const; void cascade(float z); public: diff --git a/setup-libraries.sh b/setup-libraries.sh index cd5dd4385..d43461111 100755 --- a/setup-libraries.sh +++ b/setup-libraries.sh @@ -3,7 +3,7 @@ set -e -u UNAME=$(uname -s); -MISSING_DEPS=false +MISSING_DEPS="" function ensure_dep { if [[ ! `which $1` ]]; then @@ -15,6 +15,7 @@ ensure_dep aclocal ensure_dep cmake ensure_dep automake ensure_dep autoconf +ensure_dep pkg-config if [ ${UNAME} = 'Darwin' ]; then ensure_dep makedepend ensure_dep glibtool @@ -23,11 +24,13 @@ elif [ ${UNAME} = 'Linux' ]; then ensure_dep gccmakedep fi -if [[ $MISSING_DEPS != false ]]; then +if [[ $MISSING_DEPS != "" ]]; then if [ ${UNAME} = 'Darwin' ]; then - echo 'Please run "brew install autoconf automake libtool makedepend cmake" and then re-run ./setup-libraries.sh' + echo "Missing build deps: ${MISSING_DEPS}" + echo 'Please run "brew install autoconf automake libtool makedepend cmake pkg-config" and then re-run ./setup-libraries.sh' elif [ ${UNAME} = 'Linux' ]; then - echo 'Please run "sudo apt-get install automake libtool xutils-dev cmake" and then re-run ./setup-libraries.sh' + echo "Missing build deps: ${MISSING_DEPS}" + echo 'Please run "sudo apt-get install automake libtool xutils-dev cmake pkg-config" and then re-run ./setup-libraries.sh' fi exit 1 fi diff --git a/src/map/map.cpp b/src/map/map.cpp index 5476f21d3..6775f4721 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -423,8 +423,27 @@ void Map::render() { painter.finishClippingMask(); + + // Render per layer in the stylesheet. - renderLayers(style.layers); + 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(); + // Finalize the rendering, e.g. by calling debug render calls per tile. // This guarantees that we have at least one function per tile called. @@ -447,42 +466,30 @@ void Map::render() { } } -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. - 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); +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"); } - painter.endPass(); - - // - SECOND PASS ----------------------------------------------------------- - // Make a second pass, rendering translucent objects. This time, we render - // bottom-to-top. - 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); - } - painter.endPass(); } -void Map::renderLayer(const LayerDescription& layer_desc) { - gl::group group(std::string("layer: ") + layer_desc.name); - +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); + renderLayers(layer_desc.child_layer, pass); // TODO: render framebuffer on previous framebuffer } else { // This is a singular layer. Try to find the bucket associated with @@ -491,6 +498,20 @@ void Map::renderLayer(const LayerDescription& layer_desc) { if (bucket_it != style.buckets.end()) { const BucketDescription &bucket_desc = bucket_it->second; + // Abort early if we can already deduce from the bucket type that + // we're not going to render anything anyway during this pass. + switch (bucket_desc.type) { + case BucketType::Line: + case BucketType::Point: + case BucketType::Text: + if (pass == Opaque) return; + break; + case BucketType::Raster: + if (pass == Translucent) return; + default: + break; + } + // Find the source and render all tiles in it. auto source_it = sources.find(bucket_desc.source_name); if (source_it != sources.end()) { diff --git a/src/map/source.cpp b/src/map/source.cpp index 2f2668e7b..384cb0a62 100644 --- a/src/map/source.cpp +++ b/src/map/source.cpp @@ -61,6 +61,7 @@ size_t Source::prepareRender(const TransformState &transform) { void Source::render(const LayerDescription& layer_desc, const BucketDescription &bucket_desc) { if (!enabled) return; + gl::group group(std::string("layer: ") + layer_desc.name); for (const Tile& tile : tiles) { if (tile.data && tile.data->state == TileData::State::parsed) { painter.renderTileLayer(tile, layer_desc); diff --git a/src/style/layer_description.cpp b/src/style/layer_description.cpp index d4b8b7d67..53c6230cb 100644 --- a/src/style/layer_description.cpp +++ b/src/style/layer_description.cpp @@ -2,6 +2,16 @@ #include +using namespace llmr; + +size_t LayerDescription::size() const { + size_t count = 1; + for (const LayerDescription &layer : child_layer) { + count += layer.size(); + } + return count; +} + std::ostream& llmr::operator<<(std::ostream& os, const LayerDescription& layer) { os << "Structure: " << layer.name << std::endl; os << " - bucket_name: " << layer.bucket_name << std::endl; diff --git a/src/style/style.cpp b/src/style/style.cpp index 9c766419b..18fe0f416 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -123,6 +123,14 @@ void Style::cascade(float z) { } } +size_t Style::layerCount() const { + size_t count = 0; + for (const LayerDescription &layer : layers) { + count += layer.size(); + } + return count; +} + void Style::loadJSON(const uint8_t *const data, size_t bytes) { rapidjson::Document doc;