diff options
Diffstat (limited to 'src')
53 files changed, 2020 insertions, 1044 deletions
diff --git a/src/core-files.json b/src/core-files.json index d881e6259d..c25e8273d4 100644 --- a/src/core-files.json +++ b/src/core-files.json @@ -17,20 +17,24 @@ "src/mbgl/geometry/line_atlas.cpp", "src/mbgl/gfx/attribute.cpp", "src/mbgl/gfx/renderer_backend.cpp", + "src/mbgl/gfx/rendering_stats.cpp", "src/mbgl/gl/attribute.cpp", "src/mbgl/gl/command_encoder.cpp", "src/mbgl/gl/context.cpp", "src/mbgl/gl/debugging_extension.cpp", "src/mbgl/gl/enum.cpp", + "src/mbgl/gl/index_buffer_resource.cpp", "src/mbgl/gl/object.cpp", "src/mbgl/gl/offscreen_texture.cpp", "src/mbgl/gl/render_pass.cpp", "src/mbgl/gl/renderer_backend.cpp", "src/mbgl/gl/texture.cpp", + "src/mbgl/gl/texture_resource.cpp", "src/mbgl/gl/uniform.cpp", "src/mbgl/gl/upload_pass.cpp", "src/mbgl/gl/value.cpp", "src/mbgl/gl/vertex_array.cpp", + "src/mbgl/gl/vertex_buffer_resource.cpp", "src/mbgl/layermanager/background_layer_factory.cpp", "src/mbgl/layermanager/circle_layer_factory.cpp", "src/mbgl/layermanager/custom_layer_factory.cpp", @@ -178,6 +182,7 @@ "src/mbgl/style/expression/check_subtype.cpp", "src/mbgl/style/expression/coalesce.cpp", "src/mbgl/style/expression/coercion.cpp", + "src/mbgl/style/expression/collator.cpp", "src/mbgl/style/expression/collator_expression.cpp", "src/mbgl/style/expression/comparison.cpp", "src/mbgl/style/expression/compound_expression.cpp", @@ -330,8 +335,11 @@ "mbgl/gfx/backend_scope.hpp": "include/mbgl/gfx/backend_scope.hpp", "mbgl/gfx/renderable.hpp": "include/mbgl/gfx/renderable.hpp", "mbgl/gfx/renderer_backend.hpp": "include/mbgl/gfx/renderer_backend.hpp", + "mbgl/gfx/rendering_stats.hpp": "include/mbgl/gfx/rendering_stats.hpp", "mbgl/gl/renderable_resource.hpp": "include/mbgl/gl/renderable_resource.hpp", "mbgl/gl/renderer_backend.hpp": "include/mbgl/gl/renderer_backend.hpp", + "mbgl/i18n/collator.hpp": "include/mbgl/i18n/collator.hpp", + "mbgl/i18n/number_format.hpp": "include/mbgl/i18n/number_format.hpp", "mbgl/layermanager/background_layer_factory.hpp": "include/mbgl/layermanager/background_layer_factory.hpp", "mbgl/layermanager/circle_layer_factory.hpp": "include/mbgl/layermanager/circle_layer_factory.hpp", "mbgl/layermanager/custom_layer_factory.hpp": "include/mbgl/layermanager/custom_layer_factory.hpp", @@ -449,6 +457,7 @@ "mbgl/style/sources/raster_source.hpp": "include/mbgl/style/sources/raster_source.hpp", "mbgl/style/sources/vector_source.hpp": "include/mbgl/style/sources/vector_source.hpp", "mbgl/style/style.hpp": "include/mbgl/style/style.hpp", + "mbgl/style/style_property.hpp": "include/mbgl/style/style_property.hpp", "mbgl/style/transition_options.hpp": "include/mbgl/style/transition_options.hpp", "mbgl/style/types.hpp": "include/mbgl/style/types.hpp", "mbgl/style/undefined.hpp": "include/mbgl/style/undefined.hpp", @@ -479,6 +488,7 @@ "mbgl/util/indexed_tuple.hpp": "include/mbgl/util/indexed_tuple.hpp", "mbgl/util/interpolate.hpp": "include/mbgl/util/interpolate.hpp", "mbgl/util/logging.hpp": "include/mbgl/util/logging.hpp", + "mbgl/util/monotonic_timer.hpp": "include/mbgl/util/monotonic_timer.hpp", "mbgl/util/noncopyable.hpp": "include/mbgl/util/noncopyable.hpp", "mbgl/util/optional.hpp": "include/mbgl/util/optional.hpp", "mbgl/util/platform.hpp": "include/mbgl/util/platform.hpp", diff --git a/src/mbgl/actor/mailbox.cpp b/src/mbgl/actor/mailbox.cpp index dfe0520790..070e14bdb0 100644 --- a/src/mbgl/actor/mailbox.cpp +++ b/src/mbgl/actor/mailbox.cpp @@ -27,7 +27,7 @@ void Mailbox::open(Scheduler& scheduler_) { } if (!queue.empty()) { - (*scheduler)->schedule(shared_from_this()); + (*scheduler)->schedule(makeClosure(shared_from_this())); } } @@ -57,7 +57,7 @@ void Mailbox::push(std::unique_ptr<Message> message) { bool wasEmpty = queue.empty(); queue.push(std::move(message)); if (wasEmpty && scheduler) { - (*scheduler)->schedule(shared_from_this()); + (*scheduler)->schedule(makeClosure(shared_from_this())); } } @@ -84,14 +84,20 @@ void Mailbox::receive() { (*message)(); if (!wasEmpty) { - (*scheduler)->schedule(shared_from_this()); + (*scheduler)->schedule(makeClosure(shared_from_this())); } } +// static void Mailbox::maybeReceive(std::weak_ptr<Mailbox> mailbox) { if (auto locked = mailbox.lock()) { locked->receive(); } } +// static +std::function<void()> Mailbox::makeClosure(std::weak_ptr<Mailbox> mailbox) { + return [mailbox]() { maybeReceive(mailbox); }; +} + } // namespace mbgl diff --git a/src/mbgl/actor/scheduler.cpp b/src/mbgl/actor/scheduler.cpp index cb0c7728ec..81e259fe1f 100644 --- a/src/mbgl/actor/scheduler.cpp +++ b/src/mbgl/actor/scheduler.cpp @@ -4,7 +4,14 @@ namespace mbgl { -util::ThreadLocal<Scheduler> g_currentScheduler; +std::function<void()> Scheduler::bindOnce(std::function<void()> fn) { + assert(fn); + return [scheduler = makeWeakPtr(), scheduled = std::move(fn)]() mutable { + if (!scheduled) return; // Repeated call. + auto schedulerGuard = scheduler.lock(); + if (scheduler) scheduler->schedule(std::move(scheduled)); + }; +} static auto& current() { static util::ThreadLocal<Scheduler> scheduler; @@ -28,7 +35,7 @@ std::shared_ptr<Scheduler> Scheduler::GetBackground() { std::shared_ptr<Scheduler> scheduler = weak.lock(); if (!scheduler) { - weak = scheduler = std::make_shared<ThreadPool>(4); + weak = scheduler = std::make_shared<ThreadPool>(); } return scheduler; diff --git a/src/mbgl/geometry/line_atlas.cpp b/src/mbgl/geometry/line_atlas.cpp index 106a24d015..2e4de3edbe 100644 --- a/src/mbgl/geometry/line_atlas.cpp +++ b/src/mbgl/geometry/line_atlas.cpp @@ -1,50 +1,33 @@ #include <mbgl/geometry/line_atlas.hpp> #include <mbgl/gfx/upload_pass.hpp> +#include <mbgl/math/minmax.hpp> +#include <mbgl/util/hash.hpp> #include <mbgl/util/logging.hpp> #include <mbgl/util/platform.hpp> -#include <mbgl/util/hash.hpp> #include <cmath> namespace mbgl { +namespace { -LineAtlas::LineAtlas(const Size size) - : image(size), - dirty(true) { -} - -LineAtlas::~LineAtlas() = default; - -LinePatternPos LineAtlas::getDashPosition(const std::vector<float>& dasharray, - LinePatternCap patternCap) { - size_t key = patternCap == LinePatternCap::Round ? std::numeric_limits<size_t>::min() - : std::numeric_limits<size_t>::max(); +size_t getDashPatternHash(const std::vector<float>& dasharray, const LinePatternCap patternCap) { + size_t key = + patternCap == LinePatternCap::Round ? std::numeric_limits<size_t>::min() : std::numeric_limits<size_t>::max(); for (const float part : dasharray) { util::hash_combine<float>(key, part); } - - // Note: We're not handling hash collisions here. - const auto it = positions.find(key); - if (it == positions.end()) { - auto inserted = positions.emplace(key, addDash(dasharray, patternCap)); - assert(inserted.second); - return inserted.first->second; - } else { - return it->second; - } + return key; } -LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatternCap patternCap) { +LinePatternPos addDashPattern(AlphaImage& image, + const int32_t yOffset, + const std::vector<float>& dasharray, + const LinePatternCap patternCap) { const uint8_t n = patternCap == LinePatternCap::Round ? 7 : 0; - const uint8_t dashheight = 2 * n + 1; - const uint8_t offset = 128; + constexpr const uint8_t offset = 128; if (dasharray.size() < 2) { - return LinePatternPos(); - } - - if (nextRow + dashheight > image.size.height) { - Log::Warning(Event::OpenGL, "line atlas bitmap overflow"); + Log::Warning(Event::ParseStyle, "line dasharray requires at least two elements"); return LinePatternPos(); } @@ -60,7 +43,7 @@ LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatte bool oddLength = dasharray.size() % 2 == 1; for (int y = -n; y <= n; y++) { - int row = nextRow + n + y; + int row = yOffset + n + y; int index = image.size.width * row; float left = 0; @@ -72,7 +55,6 @@ LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatte } for (uint32_t x = 0; x < image.size.width; x++) { - while (right < x / stretch) { left = right; if (partIndex >= dasharray.size()) { @@ -111,37 +93,79 @@ LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatte } LinePatternPos position; - position.y = (0.5 + nextRow + n) / image.size.height; - position.height = (2.0 * n) / image.size.height; + position.y = (0.5 + yOffset + n) / image.size.height; + position.height = (2.0 * n + 1) / image.size.height; position.width = length; - nextRow += dashheight; - - dirty = true; - return position; } -Size LineAtlas::getSize() const { - return image.size; +} // namespace + +DashPatternTexture::DashPatternTexture(const std::vector<float>& from_, + const std::vector<float>& to_, + const LinePatternCap cap) { + const bool patternsIdentical = from_ == to_; + const int32_t patternHeight = cap == LinePatternCap::Round ? 15 : 1; + + AlphaImage image({256, static_cast<uint32_t>((patternsIdentical ? 1 : 2) * patternHeight)}); + + from = addDashPattern(image, 0, from_, cap); + to = patternsIdentical ? from : addDashPattern(image, patternHeight, to_, cap); + + texture = std::move(image); } -void LineAtlas::upload(gfx::UploadPass& uploadPass) { - if (!texture) { - texture = uploadPass.createTexture(image); - } else if (dirty) { - uploadPass.updateTexture(*texture, image); +void DashPatternTexture::upload(gfx::UploadPass& uploadPass) { + if (texture.is<AlphaImage>()) { + texture = uploadPass.createTexture(texture.get<AlphaImage>()); } +} + +gfx::TextureBinding DashPatternTexture::textureBinding() const { + // The texture needs to have been uploaded already. + assert(texture.is<gfx::Texture>()); + return {texture.get<gfx::Texture>().getResource(), + gfx::TextureFilterType::Linear, + gfx::TextureMipMapType::No, + gfx::TextureWrapType::Repeat, + gfx::TextureWrapType::Clamp}; +} - dirty = false; +Size DashPatternTexture::getSize() const { + return texture.match([](const auto& obj) { return obj.size; }); } -gfx::TextureBinding LineAtlas::textureBinding() { - assert(texture); - // All _changes_ to the texture should've been made and uploaded already. - assert(!dirty); - return { texture->getResource(), gfx::TextureFilterType::Linear, gfx::TextureMipMapType::No, - gfx::TextureWrapType::Repeat, gfx::TextureWrapType::Clamp }; +LineAtlas::LineAtlas() = default; + +LineAtlas::~LineAtlas() = default; + +DashPatternTexture& LineAtlas::getDashPatternTexture(const std::vector<float>& from, + const std::vector<float>& to, + const LinePatternCap cap) { + const size_t hash = util::hash(getDashPatternHash(from, cap), getDashPatternHash(to, cap)); + + // Note: We're not handling hash collisions here. + const auto it = textures.find(hash); + if (it == textures.end()) { + auto inserted = textures.emplace( + std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(from, to, cap)); + assert(inserted.second); + needsUpload.emplace_back(hash); + return inserted.first->second; + } else { + return it->second; + } +} + +void LineAtlas::upload(gfx::UploadPass& uploadPass) { + for (const size_t hash : needsUpload) { + const auto it = textures.find(hash); + if (it != textures.end()) { + it->second.upload(uploadPass); + } + } + needsUpload.clear(); } } // namespace mbgl diff --git a/src/mbgl/geometry/line_atlas.hpp b/src/mbgl/geometry/line_atlas.hpp index b43583c9c8..853305d138 100644 --- a/src/mbgl/geometry/line_atlas.hpp +++ b/src/mbgl/geometry/line_atlas.hpp @@ -3,10 +3,11 @@ #include <mbgl/gfx/texture.hpp> #include <mbgl/util/image.hpp> #include <mbgl/util/optional.hpp> +#include <mbgl/util/variant.hpp> -#include <vector> -#include <unordered_map> +#include <map> #include <memory> +#include <vector> namespace mbgl { @@ -26,29 +27,46 @@ enum class LinePatternCap : bool { Round = true, }; -class LineAtlas { +class DashPatternTexture { public: - LineAtlas(Size); - ~LineAtlas(); - - // Binds the atlas texture to the GPU, and uploads data if it is out of date. - gfx::TextureBinding textureBinding(); + DashPatternTexture(const std::vector<float>& from, const std::vector<float>& to, LinePatternCap); // Uploads the texture to the GPU to be available when we need it. This is a lazy operation; - // the texture is only bound when the data is out of date (=dirty). + // the texture is only bound when the data is uploaded for the first time. void upload(gfx::UploadPass&); - LinePatternPos getDashPosition(const std::vector<float>&, LinePatternCap); - LinePatternPos addDash(const std::vector<float>& dasharray, LinePatternCap); + // Binds the atlas texture to the GPU, and uploads data if it is out of date. + gfx::TextureBinding textureBinding() const; + // Returns the size of the texture image. Size getSize() const; + const LinePatternPos& getFrom() const { return from; } + const LinePatternPos& getTo() const { return to; } + private: - const AlphaImage image; - bool dirty; - optional<gfx::Texture> texture; - uint32_t nextRow = 0; - std::unordered_map<size_t, LinePatternPos> positions; + LinePatternPos from, to; + variant<AlphaImage, gfx::Texture> texture; +}; + +class LineAtlas { +public: + LineAtlas(); + ~LineAtlas(); + + // Obtains or creates a texture that has both line patterns in it + DashPatternTexture& getDashPatternTexture(const std::vector<float>& from, + const std::vector<float>& to, + LinePatternCap); + + // Uploads the textures to the GPU to be available when we need it. + void upload(gfx::UploadPass&); + +private: + std::map<size_t, DashPatternTexture> textures; + + // Stores a list of hashes of texture objcts that need uploading. + std::vector<size_t> needsUpload; }; } // namespace mbgl diff --git a/src/mbgl/gfx/context.hpp b/src/mbgl/gfx/context.hpp index 2c7cb14899..fe0851be11 100644 --- a/src/mbgl/gfx/context.hpp +++ b/src/mbgl/gfx/context.hpp @@ -1,12 +1,13 @@ #pragma once #include <mbgl/gfx/backend.hpp> -#include <mbgl/gfx/renderbuffer.hpp> #include <mbgl/gfx/command_encoder.hpp> #include <mbgl/gfx/draw_scope.hpp> #include <mbgl/gfx/program.hpp> -#include <mbgl/gfx/types.hpp> +#include <mbgl/gfx/renderbuffer.hpp> +#include <mbgl/gfx/rendering_stats.hpp> #include <mbgl/gfx/texture.hpp> +#include <mbgl/gfx/types.hpp> namespace mbgl { @@ -85,6 +86,8 @@ public: public: virtual std::unique_ptr<CommandEncoder> createCommandEncoder() = 0; + virtual const RenderingStats& renderingStats() const = 0; + #if not defined(NDEBUG) public: virtual void visualizeStencilBuffer() = 0; diff --git a/src/mbgl/gfx/rendering_stats.cpp b/src/mbgl/gfx/rendering_stats.cpp new file mode 100644 index 0000000000..0a239ebd11 --- /dev/null +++ b/src/mbgl/gfx/rendering_stats.cpp @@ -0,0 +1,12 @@ +#include <mbgl/gfx/rendering_stats.hpp> + +namespace mbgl { +namespace gfx { + +bool RenderingStats::isZero() const { + return numActiveTextures == 0 && numCreatedTextures == 0 && numBuffers == 0 && numFrameBuffers == 0 && + memTextures == 0 && memIndexBuffers == 0 && memVertexBuffers == 0; +} + +} // namespace gfx +} // namespace mbgl
\ No newline at end of file diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index 18b376e3dc..e2bcc7fadc 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -54,13 +54,15 @@ Context::Context(RendererBackend& backend_) GLint value; MBGL_CHECK_ERROR(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &value)); return value; - }()), backend(backend_) { -} + }()), + backend(backend_), + stats() {} Context::~Context() { if (cleanupOnDestruction) { reset(); } + assert(stats.isZero()); } void Context::initializeExtensions(const std::function<gl::ProcAddress(const char*)>& getProcAddress) { @@ -206,10 +208,12 @@ UniqueTexture Context::createUniqueTexture() { if (pooledTextures.empty()) { pooledTextures.resize(TextureMax); MBGL_CHECK_ERROR(glGenTextures(TextureMax, pooledTextures.data())); + stats.numCreatedTextures += TextureMax; } TextureID id = pooledTextures.back(); pooledTextures.pop_back(); + stats.numActiveTextures++; // NOLINTNEXTLINE(performance-move-const-arg) return UniqueTexture{std::move(id), {this}}; } @@ -238,6 +242,7 @@ VertexArray Context::createVertexArray() { UniqueFramebuffer Context::createFramebuffer() { FramebufferID id = 0; MBGL_CHECK_ERROR(glGenFramebuffers(1, &id)); + stats.numFrameBuffers++; // NOLINTNEXTLINE(performance-move-const-arg) return UniqueFramebuffer{ std::move(id), { this } }; } @@ -245,8 +250,10 @@ UniqueFramebuffer Context::createFramebuffer() { std::unique_ptr<gfx::TextureResource> Context::createTextureResource( const Size size, const gfx::TexturePixelType format, const gfx::TextureChannelDataType type) { auto obj = createUniqueTexture(); + int textureByteSize = gl::TextureResource::getStorageSize(size, format, type); + stats.memTextures += textureByteSize; std::unique_ptr<gfx::TextureResource> resource = - std::make_unique<gl::TextureResource>(std::move(obj)); + std::make_unique<gl::TextureResource>(std::move(obj), textureByteSize); // Always use texture unit 0 for manipulating it. activeTextureUnit = 0; @@ -517,6 +524,8 @@ void Context::clear(optional<mbgl::Color> color, } MBGL_CHECK_ERROR(glClear(mask)); + + stats.numDrawCalls = 0; } void Context::setCullFaceMode(const gfx::CullFaceMode& mode) { @@ -583,6 +592,18 @@ std::unique_ptr<gfx::CommandEncoder> Context::createCommandEncoder() { return std::make_unique<gl::CommandEncoder>(*this); } +gfx::RenderingStats& Context::renderingStats() { + return stats; +} + +const gfx::RenderingStats& Context::renderingStats() const { + return stats; +} + +void Context::finish() { + MBGL_CHECK_ERROR(glFinish()); +} + void Context::draw(const gfx::DrawMode& drawMode, std::size_t indexOffset, std::size_t indexLength) { @@ -607,6 +628,8 @@ void Context::draw(const gfx::DrawMode& drawMode, static_cast<GLsizei>(indexLength), GL_UNSIGNED_SHORT, reinterpret_cast<GLvoid*>(sizeof(uint16_t) * indexOffset))); + + stats.numDrawCalls++; } void Context::performCleanup() { @@ -643,6 +666,7 @@ void Context::performCleanup() { } } MBGL_CHECK_ERROR(glDeleteBuffers(int(abandonedBuffers.size()), abandonedBuffers.data())); + stats.numBuffers -= int(abandonedBuffers.size()); abandonedBuffers.clear(); } @@ -655,6 +679,8 @@ void Context::performCleanup() { } } MBGL_CHECK_ERROR(glDeleteTextures(int(abandonedTextures.size()), abandonedTextures.data())); + stats.numCreatedTextures -= int(abandonedTextures.size()); + assert(stats.numCreatedTextures >= 0); abandonedTextures.clear(); } @@ -678,6 +704,8 @@ void Context::performCleanup() { } MBGL_CHECK_ERROR( glDeleteFramebuffers(int(abandonedFramebuffers.size()), abandonedFramebuffers.data())); + stats.numFrameBuffers -= int(abandonedFramebuffers.size()); + assert(stats.numFrameBuffers >= 0); abandonedFramebuffers.clear(); } diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index 70f12e5a8d..b0d043ff9f 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -43,6 +43,9 @@ public: std::unique_ptr<gfx::CommandEncoder> createCommandEncoder() override; + gfx::RenderingStats& renderingStats(); + const gfx::RenderingStats& renderingStats() const override; + void initializeExtensions(const std::function<gl::ProcAddress(const char*)>&); void enableDebugging(); @@ -92,6 +95,8 @@ public: std::size_t indexOffset, std::size_t indexLength); + void finish(); + // Actually remove the objects we marked as abandoned with the above methods. // Only call this while the OpenGL context is exclusive to this thread. void performCleanup() override; @@ -130,6 +135,7 @@ private: RendererBackend& backend; bool cleanupOnDestruction = true; + gfx::RenderingStats stats; std::unique_ptr<extension::Debugging> debugging; std::unique_ptr<extension::VertexArray> vertexArray; diff --git a/src/mbgl/gl/index_buffer_resource.cpp b/src/mbgl/gl/index_buffer_resource.cpp new file mode 100644 index 0000000000..2ef178846b --- /dev/null +++ b/src/mbgl/gl/index_buffer_resource.cpp @@ -0,0 +1,14 @@ +#include <mbgl/gl/context.hpp> +#include <mbgl/gl/index_buffer_resource.hpp> + +namespace mbgl { +namespace gl { + +IndexBufferResource::~IndexBufferResource() { + auto& stats = buffer.get_deleter().context.renderingStats(); + stats.memIndexBuffers -= byteSize; + assert(stats.memIndexBuffers >= 0); +} + +} // namespace gl +} // namespace mbgl
\ No newline at end of file diff --git a/src/mbgl/gl/index_buffer_resource.hpp b/src/mbgl/gl/index_buffer_resource.hpp index 2da25fdb96..00c66be5b5 100644 --- a/src/mbgl/gl/index_buffer_resource.hpp +++ b/src/mbgl/gl/index_buffer_resource.hpp @@ -8,10 +8,11 @@ namespace gl { class IndexBufferResource : public gfx::IndexBufferResource { public: - IndexBufferResource(UniqueBuffer&& buffer_) : buffer(std::move(buffer_)) { - } + IndexBufferResource(UniqueBuffer&& buffer_, int byteSize_) : buffer(std::move(buffer_)), byteSize(byteSize_) {} + ~IndexBufferResource(); UniqueBuffer buffer; + int byteSize; }; } // namespace gl diff --git a/src/mbgl/gl/object.cpp b/src/mbgl/gl/object.cpp index ec2998a27d..c075aa8f13 100644 --- a/src/mbgl/gl/object.cpp +++ b/src/mbgl/gl/object.cpp @@ -28,6 +28,8 @@ void TextureDeleter::operator()(TextureID id) const { } else { context->pooledTextures.push_back(id); } + context->renderingStats().numActiveTextures--; + assert(context->renderingStats().numActiveTextures >= 0); } void VertexArrayDeleter::operator()(VertexArrayID id) const { diff --git a/src/mbgl/gl/texture_resource.cpp b/src/mbgl/gl/texture_resource.cpp new file mode 100644 index 0000000000..b9bf620eea --- /dev/null +++ b/src/mbgl/gl/texture_resource.cpp @@ -0,0 +1,45 @@ +#include <mbgl/gl/context.hpp> +#include <mbgl/gl/texture_resource.hpp> + +namespace mbgl { +namespace gl { + +static int channelCount(gfx::TexturePixelType format) { + switch (format) { + case gfx::TexturePixelType::Alpha: + case gfx::TexturePixelType::Depth: + case gfx::TexturePixelType::Luminance: + case gfx::TexturePixelType::Stencil: + return 1; + case gfx::TexturePixelType::RGBA: + return 4; + default: + assert(!"Unknown texture pixel type"); + return 0; + } +} + +static int channelStorageSize(gfx::TextureChannelDataType type) { + switch (type) { + case gfx::TextureChannelDataType::HalfFloat: + return 2; + case gfx::TextureChannelDataType::UnsignedByte: + return 1; + default: + assert(!"Unknown texture channel data type"); + return 0; + } +} + +TextureResource::~TextureResource() { + auto& stats = texture.get_deleter().context->renderingStats(); + stats.memTextures -= byteSize; + assert(stats.memTextures >= 0); +} + +int TextureResource::getStorageSize(const Size& size, gfx::TexturePixelType format, gfx::TextureChannelDataType type) { + return size.width * size.height * channelCount(format) * channelStorageSize(type); +} + +} // namespace gl +} // namespace mbgl
\ No newline at end of file diff --git a/src/mbgl/gl/texture_resource.hpp b/src/mbgl/gl/texture_resource.hpp index ed742e75b7..494e5ae8a3 100644 --- a/src/mbgl/gl/texture_resource.hpp +++ b/src/mbgl/gl/texture_resource.hpp @@ -8,14 +8,17 @@ namespace gl { class TextureResource : public gfx::TextureResource { public: - TextureResource(UniqueTexture&& texture_) : texture(std::move(texture_)) { - } + TextureResource(UniqueTexture&& texture_, int byteSize_) : texture(std::move(texture_)), byteSize(byteSize_) {} + ~TextureResource(); + + static int getStorageSize(const Size& size, gfx::TexturePixelType format, gfx::TextureChannelDataType type); UniqueTexture texture; gfx::TextureFilterType filter = gfx::TextureFilterType::Nearest; gfx::TextureMipMapType mipmap = gfx::TextureMipMapType::No; gfx::TextureWrapType wrapX = gfx::TextureWrapType::Clamp; gfx::TextureWrapType wrapY = gfx::TextureWrapType::Clamp; + int byteSize; }; } // namespace gl diff --git a/src/mbgl/gl/upload_pass.cpp b/src/mbgl/gl/upload_pass.cpp index 4312488fb4..962bc72239 100644 --- a/src/mbgl/gl/upload_pass.cpp +++ b/src/mbgl/gl/upload_pass.cpp @@ -20,12 +20,14 @@ std::unique_ptr<gfx::VertexBufferResource> UploadPass::createVertexBufferResourc const void* data, std::size_t size, const gfx::BufferUsageType usage) { BufferID id = 0; MBGL_CHECK_ERROR(glGenBuffers(1, &id)); + commandEncoder.context.renderingStats().numBuffers++; + commandEncoder.context.renderingStats().memVertexBuffers += size; // NOLINTNEXTLINE(performance-move-const-arg) UniqueBuffer result{ std::move(id), { commandEncoder.context } }; commandEncoder.context.vertexBuffer = result; MBGL_CHECK_ERROR( glBufferData(GL_ARRAY_BUFFER, size, data, Enum<gfx::BufferUsageType>::to(usage))); - return std::make_unique<gl::VertexBufferResource>(std::move(result)); + return std::make_unique<gl::VertexBufferResource>(std::move(result), size); } void UploadPass::updateVertexBufferResource(gfx::VertexBufferResource& resource, @@ -39,13 +41,15 @@ std::unique_ptr<gfx::IndexBufferResource> UploadPass::createIndexBufferResource( const void* data, std::size_t size, const gfx::BufferUsageType usage) { BufferID id = 0; MBGL_CHECK_ERROR(glGenBuffers(1, &id)); + commandEncoder.context.renderingStats().numBuffers++; + commandEncoder.context.renderingStats().memIndexBuffers += size; // NOLINTNEXTLINE(performance-move-const-arg) UniqueBuffer result{ std::move(id), { commandEncoder.context } }; commandEncoder.context.bindVertexArray = 0; commandEncoder.context.globalVertexArrayState.indexBuffer = result; MBGL_CHECK_ERROR( glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, Enum<gfx::BufferUsageType>::to(usage))); - return std::make_unique<gl::IndexBufferResource>(std::move(result)); + return std::make_unique<gl::IndexBufferResource>(std::move(result), size); } void UploadPass::updateIndexBufferResource(gfx::IndexBufferResource& resource, @@ -65,8 +69,10 @@ UploadPass::createTextureResource(const Size size, gfx::TexturePixelType format, gfx::TextureChannelDataType type) { auto obj = commandEncoder.context.createUniqueTexture(); + int textureByteSize = gl::TextureResource::getStorageSize(size, format, type); + commandEncoder.context.renderingStats().memTextures += textureByteSize; std::unique_ptr<gfx::TextureResource> resource = - std::make_unique<gl::TextureResource>(std::move(obj)); + std::make_unique<gl::TextureResource>(std::move(obj), textureByteSize); commandEncoder.context.pixelStoreUnpack = { 1 }; updateTextureResource(*resource, size, data, format, type); // We are using clamp to edge here since OpenGL ES doesn't allow GL_REPEAT on NPOT textures. diff --git a/src/mbgl/gl/vertex_buffer_resource.cpp b/src/mbgl/gl/vertex_buffer_resource.cpp new file mode 100644 index 0000000000..cddbdd43d0 --- /dev/null +++ b/src/mbgl/gl/vertex_buffer_resource.cpp @@ -0,0 +1,14 @@ +#include <mbgl/gl/context.hpp> +#include <mbgl/gl/vertex_buffer_resource.hpp> + +namespace mbgl { +namespace gl { + +VertexBufferResource::~VertexBufferResource() { + auto& stats = buffer.get_deleter().context.renderingStats(); + stats.memVertexBuffers -= byteSize; + assert(stats.memVertexBuffers >= 0); +} + +} // namespace gl +} // namespace mbgl
\ No newline at end of file diff --git a/src/mbgl/gl/vertex_buffer_resource.hpp b/src/mbgl/gl/vertex_buffer_resource.hpp index 95e5e75d45..f9c599c757 100644 --- a/src/mbgl/gl/vertex_buffer_resource.hpp +++ b/src/mbgl/gl/vertex_buffer_resource.hpp @@ -8,10 +8,11 @@ namespace gl { class VertexBufferResource : public gfx::VertexBufferResource { public: - VertexBufferResource(UniqueBuffer&& buffer_) : buffer(std::move(buffer_)) { - } + VertexBufferResource(UniqueBuffer&& buffer_, int byteSize_) : buffer(std::move(buffer_)), byteSize(byteSize_) {} + ~VertexBufferResource(); UniqueBuffer buffer; + int byteSize; }; } // namespace gl diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index 81d1d9a5b6..d0227c36c5 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -121,7 +121,7 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, allowVerticalPlacement = allowVerticalPlacement || placementMode == style::TextWritingModeType::Vertical; return !seen.insert(placementMode).second; }); - modes.erase(end, modes.end()); + modes.erase(end, modes.end()); placementModes = std::move(modes); } @@ -525,21 +525,22 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, const float textRepeatDistance = symbolSpacing / 2; const auto evaluatedLayoutProperties = layout->evaluate(zoom, feature); IndexedSubfeature indexedFeature(feature.index, sourceLayer->getName(), bucketLeaderID, symbolInstances.size()); - const bool hasIconTextFit = evaluatedLayoutProperties.get<style::IconTextFit>() != IconTextFitType::None; + const auto iconTextFit = evaluatedLayoutProperties.get<style::IconTextFit>(); // Adjust shaped icon size when icon-text-fit is used. optional<PositionedIcon> verticallyShapedIcon; - if (shapedIcon && hasIconTextFit) { + if (shapedIcon && iconTextFit != IconTextFitType::None) { // Create vertically shaped icon for vertical writing mode if needed. if (allowVerticalPlacement && shapedTextOrientations.vertical) { verticallyShapedIcon = shapedIcon; - verticallyShapedIcon->fitIconToText(evaluatedLayoutProperties, - shapedTextOrientations.vertical, - layoutTextSize); + verticallyShapedIcon->fitIconToText( + shapedTextOrientations.vertical, iconTextFit, layout->get<IconTextFitPadding>(), iconOffset, fontScale); + } + const auto shapedText = getDefaultHorizontalShaping(shapedTextOrientations); + if (shapedText) { + shapedIcon->fitIconToText( + shapedText, iconTextFit, layout->get<IconTextFitPadding>(), iconOffset, fontScale); } - shapedIcon->fitIconToText(evaluatedLayoutProperties, - getDefaultHorizontalShaping(shapedTextOrientations), - layoutTextSize); } auto addSymbolInstance = [&] (Anchor& anchor, std::shared_ptr<SymbolInstanceSharedData> sharedData) { diff --git a/src/mbgl/renderer/image_manager.cpp b/src/mbgl/renderer/image_manager.cpp index d001084f92..2ea753d8aa 100644 --- a/src/mbgl/renderer/image_manager.cpp +++ b/src/mbgl/renderer/image_manager.cpp @@ -138,8 +138,9 @@ void ImageManager::removeRequestor(ImageRequestor& requestor) { void ImageManager::notifyIfMissingImageAdded() { for (auto it = missingImageRequestors.begin(); it != missingImageRequestors.end();) { - if (it->second.callbacks.empty()) { - notify(*it->first, it->second.pair); + ImageRequestor& requestor = *it->first; + if (!requestor.hasPendingRequests()) { + notify(requestor, it->second); it = missingImageRequestors.erase(it); } else { ++it; @@ -169,38 +170,56 @@ void ImageManager::reduceMemoryUseIfCacheSizeExceedsLimit() { } void ImageManager::checkMissingAndNotify(ImageRequestor& requestor, const ImageRequestPair& pair) { - std::vector<std::string> missingImages; - missingImages.reserve(pair.first.size()); + ImageDependencies missingDependencies; + for (const auto& dependency : pair.first) { if (images.find(dependency.first) == images.end()) { - missingImages.push_back(dependency.first); + missingDependencies.emplace(dependency); } } - if (!missingImages.empty()) { + if (!missingDependencies.empty()) { ImageRequestor* requestorPtr = &requestor; + assert(!missingImageRequestors.count(requestorPtr)); + missingImageRequestors.emplace(requestorPtr, pair); - auto emplaced = missingImageRequestors.emplace(requestorPtr, MissingImageRequestPair { pair, {} }); - assert(emplaced.second); - - for (const auto& missingImage : missingImages) { + for (const auto& dependency : missingDependencies) { + const std::string& missingImage = dependency.first; assert(observer != nullptr); - requestedImages[missingImage].emplace(&requestor); - auto callback = std::make_unique<ActorCallback>( - *Scheduler::GetCurrent(), - [this, requestorPtr, missingImage] { - auto requestorIt = missingImageRequestors.find(requestorPtr); - if (requestorIt != missingImageRequestors.end()) { - assert(requestorIt->second.callbacks.find(missingImage) != requestorIt->second.callbacks.end()); - requestorIt->second.callbacks.erase(missingImage); - } - }); - - auto actorRef = callback->self(); - emplaced.first->second.callbacks.emplace(missingImage, std::move(callback)); - observer->onStyleImageMissing(missingImage, [actorRef] { - actorRef.invoke(&Callback::operator()); - }); + + auto existingRequestorsIt = requestedImages.find(missingImage); + if (existingRequestorsIt != requestedImages.end()) { // Already asked client about this image. + std::set<ImageRequestor*>& existingRequestors = existingRequestorsIt->second; + // existingRequestors is empty if all the previous requestors are deleted. + if (!existingRequestors.empty() && + (*existingRequestors.begin()) + ->hasPendingRequest(missingImage)) { // Still waiting for the client response for this image. + requestorPtr->addPendingRequest(missingImage); + existingRequestors.emplace(requestorPtr); + continue; + } + // The request for this image has been already delivered + // to the client, so we do not treat it as pending. + existingRequestors.emplace(requestorPtr); + // TODO: we could `continue;` here, but we need to call `observer->onStyleImageMissing`, + // so that rendering is re-launched from the handler at Map::Impl. + } else { + requestedImages[missingImage].emplace(requestorPtr); + requestor.addPendingRequest(missingImage); + } + + auto removePendingRequests = [this, missingImage] { + auto existingRequest = requestedImages.find(missingImage); + if (existingRequest == requestedImages.end()) { + return; + } + + for (auto* req : existingRequest->second) { + req->removePendingRequest(missingImage); + } + }; + observer->onStyleImageMissing(missingImage, + Scheduler::GetCurrent()->bindOnce(std::move(removePendingRequests))); } } else { // Associate requestor with an image that was provided by the client. @@ -230,7 +249,7 @@ void ImageManager::notify(ImageRequestor& requestor, const ImageRequestPair& pai } } - requestor.onImagesAvailable(iconMap, patternMap, std::move(versionMap), pair.second); + requestor.onImagesAvailable(std::move(iconMap), std::move(patternMap), std::move(versionMap), pair.second); } void ImageManager::dumpDebugLogs() const { diff --git a/src/mbgl/renderer/image_manager.hpp b/src/mbgl/renderer/image_manager.hpp index 9097418681..5ed6e237f0 100644 --- a/src/mbgl/renderer/image_manager.hpp +++ b/src/mbgl/renderer/image_manager.hpp @@ -58,13 +58,7 @@ private: bool loaded = false; std::map<ImageRequestor*, ImageRequestPair> requestors; - using Callback = std::function<void()>; - using ActorCallback = Actor<Callback>; - struct MissingImageRequestPair { - ImageRequestPair pair; - std::map<std::string, std::unique_ptr<ActorCallback>> callbacks; - }; - std::map<ImageRequestor*, MissingImageRequestPair> missingImageRequestors; + std::map<ImageRequestor*, ImageRequestPair> missingImageRequestors; std::map<std::string, std::set<ImageRequestor*>> requestedImages; std::size_t requestedImagesCacheSize = 0ul; ImageMap images; @@ -77,8 +71,17 @@ public: explicit ImageRequestor(ImageManager&); virtual ~ImageRequestor(); virtual void onImagesAvailable(ImageMap icons, ImageMap patterns, ImageVersionMap versionMap, uint64_t imageCorrelationID) = 0; + + void addPendingRequest(const std::string& imageId) { pendingRequests.insert(imageId); } + bool hasPendingRequest(const std::string& imageId) const { return pendingRequests.count(imageId); } + bool hasPendingRequests() const { return !pendingRequests.empty(); } + void removePendingRequest(const std::string& imageId) { pendingRequests.erase(imageId); } + private: ImageManager& imageManager; + + // Pending requests are image requests that are waiting to be dispatched to the client. + std::set<std::string> pendingRequests; }; } // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp index 36665c1db4..e5bbe74bf9 100644 --- a/src/mbgl/renderer/layers/render_line_layer.cpp +++ b/src/mbgl/renderer/layers/render_line_layer.cpp @@ -78,8 +78,8 @@ void RenderLineLayer::prepare(const LayerPrepareParameters& params) { const LinePatternCap cap = bucket.layout.get<LineCap>() == LineCapType::Round ? LinePatternCap::Round : LinePatternCap::Square; // Ensures that the dash data gets added to the atlas. - params.lineAtlas.getDashPosition(evaluated.get<LineDasharray>().from, cap); - params.lineAtlas.getDashPosition(evaluated.get<LineDasharray>().to, cap); + params.lineAtlas.getDashPatternTexture( + evaluated.get<LineDasharray>().from, evaluated.get<LineDasharray>().to, cap); } } @@ -146,27 +146,26 @@ void RenderLineLayer::render(PaintParameters& parameters) { }; if (!evaluated.get<LineDasharray>().from.empty()) { - const LinePatternCap cap = bucket.layout.get<LineCap>() == LineCapType::Round - ? LinePatternCap::Round : LinePatternCap::Square; - LinePatternPos posA = parameters.lineAtlas.getDashPosition(evaluated.get<LineDasharray>().from, cap); - LinePatternPos posB = parameters.lineAtlas.getDashPosition(evaluated.get<LineDasharray>().to, cap); + const LinePatternCap cap = + bucket.layout.get<LineCap>() == LineCapType::Round ? LinePatternCap::Round : LinePatternCap::Square; + const auto& dashPatternTexture = parameters.lineAtlas.getDashPatternTexture( + evaluated.get<LineDasharray>().from, evaluated.get<LineDasharray>().to, cap); draw(parameters.programs.getLineLayerPrograms().lineSDF, - LineSDFProgram::layoutUniformValues( - evaluated, - parameters.pixelRatio, - tile, - parameters.state, - parameters.pixelsToGLUnits, - posA, - posB, - crossfade, - parameters.lineAtlas.getSize().width), - {}, - {}, - LineSDFProgram::TextureBindings{ - parameters.lineAtlas.textureBinding(), - }); + LineSDFProgram::layoutUniformValues(evaluated, + parameters.pixelRatio, + tile, + parameters.state, + parameters.pixelsToGLUnits, + dashPatternTexture.getFrom(), + dashPatternTexture.getTo(), + crossfade, + dashPatternTexture.getSize().width), + {}, + {}, + LineSDFProgram::TextureBindings{ + dashPatternTexture.textureBinding(), + }); } else if (!unevaluated.get<LinePattern>().isUndefined()) { const auto& linePatternValue = evaluated.get<LinePattern>().constantOr(Faded<std::basic_string<char>>{ "", ""}); diff --git a/src/mbgl/renderer/paint_property_binder.hpp b/src/mbgl/renderer/paint_property_binder.hpp index 1a36f8a2e5..db9f61411a 100644 --- a/src/mbgl/renderer/paint_property_binder.hpp +++ b/src/mbgl/renderer/paint_property_binder.hpp @@ -370,11 +370,10 @@ public: } std::tuple<float> interpolationFactor(float currentZoom) const override { - if (expression.useIntegerZoom) { - return std::tuple<float> { expression.interpolationFactor(zoomRange, std::floor(currentZoom)) }; - } else { - return std::tuple<float> { expression.interpolationFactor(zoomRange, currentZoom) }; - } + const float possiblyRoundedZoom = expression.useIntegerZoom ? std::floor(currentZoom) : currentZoom; + + return std::tuple<float>{ + ::fmax(0.0, ::fmin(1.0, expression.interpolationFactor(zoomRange, possiblyRoundedZoom)))}; } std::tuple<T> uniformValue(const PossiblyEvaluatedPropertyValue<T>& currentValue) const override { diff --git a/src/mbgl/renderer/render_orchestrator.cpp b/src/mbgl/renderer/render_orchestrator.cpp index 28f6ab3199..e13a439ae4 100644 --- a/src/mbgl/renderer/render_orchestrator.cpp +++ b/src/mbgl/renderer/render_orchestrator.cpp @@ -103,19 +103,17 @@ public: } // namespace -RenderOrchestrator::RenderOrchestrator( - bool backgroundLayerAsColor_, - optional<std::string> localFontFamily_) - : observer(&nullObserver()) - , glyphManager(std::make_unique<GlyphManager>(std::make_unique<LocalGlyphRasterizer>(std::move(localFontFamily_)))) - , imageManager(std::make_unique<ImageManager>()) - , lineAtlas(std::make_unique<LineAtlas>(Size{ 256, 512 })) - , patternAtlas(std::make_unique<PatternAtlas>()) - , imageImpls(makeMutable<std::vector<Immutable<style::Image::Impl>>>()) - , sourceImpls(makeMutable<std::vector<Immutable<style::Source::Impl>>>()) - , layerImpls(makeMutable<std::vector<Immutable<style::Layer::Impl>>>()) - , renderLight(makeMutable<Light::Impl>()) - , backgroundLayerAsColor(backgroundLayerAsColor_) { +RenderOrchestrator::RenderOrchestrator(bool backgroundLayerAsColor_, optional<std::string> localFontFamily_) + : observer(&nullObserver()), + glyphManager(std::make_unique<GlyphManager>(std::make_unique<LocalGlyphRasterizer>(std::move(localFontFamily_)))), + imageManager(std::make_unique<ImageManager>()), + lineAtlas(std::make_unique<LineAtlas>()), + patternAtlas(std::make_unique<PatternAtlas>()), + imageImpls(makeMutable<std::vector<Immutable<style::Image::Impl>>>()), + sourceImpls(makeMutable<std::vector<Immutable<style::Source::Impl>>>()), + layerImpls(makeMutable<std::vector<Immutable<style::Layer::Impl>>>()), + renderLight(makeMutable<Light::Impl>()), + backgroundLayerAsColor(backgroundLayerAsColor_) { glyphManager->setObserver(this); imageManager->setObserver(this); } @@ -220,6 +218,7 @@ std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(const UpdatePar const LayerDifference layerDiff = diffLayers(layerImpls, updateParameters.layers); layerImpls = updateParameters.layers; + const bool layersAddedOrRemoved = !layerDiff.added.empty() || !layerDiff.removed.empty(); // Remove render layers for removed layers. for (const auto& entry : layerDiff.removed) { @@ -238,20 +237,31 @@ std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(const UpdatePar renderLayers.at(entry.first)->transition(transitionParameters, entry.second.after); } - if (!layerDiff.removed.empty() || !layerDiff.added.empty() || !layerDiff.changed.empty()) { - glyphManager->evict(fontStacks(*updateParameters.layers)); + if (layersAddedOrRemoved) { + orderedLayers.clear(); + orderedLayers.reserve(layerImpls->size()); + for (const auto& layerImpl : *layerImpls) { + RenderLayer* layer = renderLayers.at(layerImpl->id).get(); + assert(layer); + orderedLayers.emplace_back(*layer); + } + } + assert(orderedLayers.size() == renderLayers.size()); + + if (layersAddedOrRemoved || !layerDiff.changed.empty()) { + glyphManager->evict(fontStacks(*layerImpls)); } // Update layers for class and zoom changes. std::unordered_set<std::string> constantsMaskChanged; - for (const auto& entry : renderLayers) { - RenderLayer& layer = *entry.second; - const bool layerAddedOrChanged = layerDiff.added.count(entry.first) || layerDiff.changed.count(entry.first); + for (RenderLayer& layer : orderedLayers) { + const std::string& id = layer.getID(); + const bool layerAddedOrChanged = layerDiff.added.count(id) || layerDiff.changed.count(id); if (layerAddedOrChanged || zoomChanged || layer.hasTransition() || layer.hasCrossfade()) { auto previousMask = layer.evaluatedProperties->constantsMask(); layer.evaluate(evaluationParameters); if (previousMask != layer.evaluatedProperties->constantsMask()) { - constantsMaskChanged.insert(layer.getID()); + constantsMaskChanged.insert(id); } } } @@ -281,7 +291,7 @@ std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(const UpdatePar renderLight.getEvaluated()); std::set<LayerRenderItem> layerRenderItems; - std::vector<std::reference_wrapper<RenderLayer>> layersNeedPlacement; + layersNeedPlacement.clear(); auto renderItemsEmplaceHint = layerRenderItems.begin(); // Reserve size for filteredLayersForSource if there are sources. @@ -293,27 +303,26 @@ std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(const UpdatePar for (const auto& sourceImpl : *sourceImpls) { RenderSource* source = renderSources.at(sourceImpl->id).get(); bool sourceNeedsRendering = false; - bool sourceNeedsRelayout = false; - - uint32_t index = 0u; - const auto begin = layerImpls->begin(); - const auto end = layerImpls->end(); - for (auto it = begin; it != end; ++it, ++index) { - const Immutable<Layer::Impl>& layerImpl = *it; - RenderLayer* layer = getRenderLayer(layerImpl->id); - const auto* layerInfo = layerImpl->getTypeInfo(); - const bool layerIsVisible = layer->baseImpl->visibility != style::VisibilityType::None; - const bool zoomFitsLayer = layer->supportsZoom(zoomHistory.lastZoom); + bool sourceNeedsRelayout = false; + + for (uint32_t index = 0u; index < orderedLayers.size(); ++index) { + RenderLayer& layer = orderedLayers[index]; + const auto* layerInfo = layer.baseImpl->getTypeInfo(); + const bool layerIsVisible = layer.baseImpl->visibility != style::VisibilityType::None; + const bool zoomFitsLayer = layer.supportsZoom(zoomHistory.lastZoom); renderTreeParameters->has3D |= (layerInfo->pass3d == LayerTypeInfo::Pass3D::Required); if (layerInfo->source != LayerTypeInfo::Source::NotRequired) { - if (layerImpl->source == sourceImpl->id) { - sourceNeedsRelayout = (sourceNeedsRelayout || hasImageDiff || constantsMaskChanged.count(layerImpl->id) || hasLayoutDifference(layerDiff, layerImpl->id)); + if (layer.baseImpl->source == sourceImpl->id) { + const std::string& layerId = layer.getID(); + sourceNeedsRelayout = (sourceNeedsRelayout || hasImageDiff || constantsMaskChanged.count(layerId) || + hasLayoutDifference(layerDiff, layerId)); if (layerIsVisible) { - filteredLayersForSource.push_back(layer->evaluatedProperties); + filteredLayersForSource.push_back(layer.evaluatedProperties); if (zoomFitsLayer) { sourceNeedsRendering = true; - renderItemsEmplaceHint = layerRenderItems.emplace_hint(renderItemsEmplaceHint, *layer, source, index); + renderItemsEmplaceHint = + layerRenderItems.emplace_hint(renderItemsEmplaceHint, layer, source, index); } } } @@ -322,14 +331,14 @@ std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(const UpdatePar // Handle layers without source. if (layerIsVisible && zoomFitsLayer && sourceImpl.get() == sourceImpls->at(0).get()) { - if (backgroundLayerAsColor && layerImpl.get() == layerImpls->at(0).get()) { - const auto& solidBackground = layer->getSolidBackground(); + if (backgroundLayerAsColor && layer.baseImpl == layerImpls->front()) { + const auto& solidBackground = layer.getSolidBackground(); if (solidBackground) { renderTreeParameters->backgroundColor = *solidBackground; continue; // This layer is shown with background color, and it shall not be added to render items. } } - renderItemsEmplaceHint = layerRenderItems.emplace_hint(renderItemsEmplaceHint, *layer, nullptr, index); + renderItemsEmplaceHint = layerRenderItems.emplace_hint(renderItemsEmplaceHint, layer, nullptr, index); } } source->update(sourceImpl, diff --git a/src/mbgl/renderer/render_orchestrator.hpp b/src/mbgl/renderer/render_orchestrator.hpp index 9b63498a2a..c2b44c2792 100644 --- a/src/mbgl/renderer/render_orchestrator.hpp +++ b/src/mbgl/renderer/render_orchestrator.hpp @@ -127,9 +127,11 @@ private: const bool backgroundLayerAsColor; bool contextLost = false; - // Vector with reserved capacity of layerImpls->size() to avoid reallocation + // Vectors with reserved capacity of layerImpls->size() to avoid reallocation // on each frame. std::vector<Immutable<style::LayerProperties>> filteredLayersForSource; + std::vector<std::reference_wrapper<RenderLayer>> orderedLayers; + std::vector<std::reference_wrapper<RenderLayer>> layersNeedPlacement; }; } // namespace mbgl diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp index 2bf6e2e1a9..586d3b5a8a 100644 --- a/src/mbgl/renderer/tile_pyramid.cpp +++ b/src/mbgl/renderer/tile_pyramid.cpp @@ -68,6 +68,10 @@ void TilePyramid::update(const std::vector<Immutable<style::LayerProperties>>& l if (!needsRendering) { if (!needsRelayout) { for (auto& entry : tiles) { + // These tiles are invisible, we set optional necessity + // for them and thus suppress network requests on + // tiles expiration (see `OnlineFileRequest`). + entry.second->setNecessity(TileNecessity::Optional); cache.add(entry.first, std::move(entry.second)); } } diff --git a/src/mbgl/style/expression/assertion.cpp b/src/mbgl/style/expression/assertion.cpp index 8e5a8b555d..17f8925511 100644 --- a/src/mbgl/style/expression/assertion.cpp +++ b/src/mbgl/style/expression/assertion.cpp @@ -16,12 +16,12 @@ Assertion::Assertion(type::Type type_, std::vector<std::unique_ptr<Expression>> } ParseResult Assertion::parse(const Convertible& value, ParsingContext& ctx) { - static std::unordered_map<std::string, type::Type> types { + static std::unordered_map<std::string, type::Type> types{ {"string", type::String}, + {"image", type::String}, // TODO: replace once we implement image expressions {"number", type::Number}, {"boolean", type::Boolean}, - {"object", type::Object} - }; + {"object", type::Object}}; std::size_t length = arrayLength(value); diff --git a/src/mbgl/style/expression/collator.cpp b/src/mbgl/style/expression/collator.cpp new file mode 100644 index 0000000000..185d713150 --- /dev/null +++ b/src/mbgl/style/expression/collator.cpp @@ -0,0 +1,24 @@ +#include <mbgl/style/expression/collator.hpp> + +namespace mbgl { +namespace style { +namespace expression { + +Collator::Collator(bool caseSensitive, bool diacriticSensitive, optional<std::string> locale) + : collator(platform::Collator(caseSensitive, diacriticSensitive, std::move(locale))) {} + +bool Collator::operator==(const Collator& other) const { + return collator == other.collator; +} + +int Collator::compare(const std::string& lhs, const std::string& rhs) const { + return collator.compare(lhs, rhs); +} + +std::string Collator::resolvedLocale() const { + return collator.resolvedLocale(); +} + +} // namespace expression +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/expression/formatted.cpp b/src/mbgl/style/expression/formatted.cpp index 5d45806ecb..4591a50ed1 100644 --- a/src/mbgl/style/expression/formatted.cpp +++ b/src/mbgl/style/expression/formatted.cpp @@ -35,6 +35,35 @@ std::string Formatted::toString() const { return result; } +mbgl::Value Formatted::toObject() const { + mapbox::base::ValueObject result; + mapbox::base::ValueArray sectionValues; + sectionValues.reserve(sections.size()); + for (const auto& section : sections) { + mapbox::base::ValueObject serializedSection; + serializedSection.emplace("text", section.text); + if (section.fontScale) { + serializedSection.emplace("scale", *section.fontScale); + } else { + serializedSection.emplace("scale", NullValue()); + } + if (section.fontStack) { + std::string fontStackString; + serializedSection.emplace("fontStack", fontStackToString(*section.fontStack)); + } else { + serializedSection.emplace("fontStack", NullValue()); + } + if (section.textColor) { + serializedSection.emplace("textColor", section.textColor->toObject()); + } else { + serializedSection.emplace("textColor", NullValue()); + } + sectionValues.emplace_back(serializedSection); + } + result.emplace("sections", std::move(sectionValues)); + return result; +} + } // namespace expression namespace conversion { diff --git a/src/mbgl/style/expression/number_format.cpp b/src/mbgl/style/expression/number_format.cpp index e31a9ce398..c2de032ff4 100644 --- a/src/mbgl/style/expression/number_format.cpp +++ b/src/mbgl/style/expression/number_format.cpp @@ -1,6 +1,6 @@ -#include <mbgl/style/expression/number_format.hpp> +#include <mbgl/i18n/number_format.hpp> #include <mbgl/style/conversion_impl.hpp> -#include <mbgl/util/platform.hpp> +#include <mbgl/style/expression/number_format.hpp> namespace mbgl { namespace style { diff --git a/src/mbgl/style/expression/parsing_context.cpp b/src/mbgl/style/expression/parsing_context.cpp index 6ce3a9bfaa..699190608b 100644 --- a/src/mbgl/style/expression/parsing_context.cpp +++ b/src/mbgl/style/expression/parsing_context.cpp @@ -100,38 +100,40 @@ ParseResult ParsingContext::parse(const Convertible& value, std::size_t index_, } using ParseFunction = ParseResult (*)(const conversion::Convertible&, ParsingContext&); -MAPBOX_ETERNAL_CONSTEXPR const auto expressionRegistry = mapbox::eternal::hash_map<mapbox::eternal::string, ParseFunction>({ - {"==", parseComparison}, - {"!=", parseComparison}, - {">", parseComparison}, - {"<", parseComparison}, - {">=", parseComparison}, - {"<=", parseComparison}, - {"all", All::parse}, - {"any", Any::parse}, - {"array", Assertion::parse}, - {"at", At::parse}, - {"boolean", Assertion::parse}, - {"case", Case::parse}, - {"coalesce", Coalesce::parse}, - {"collator", CollatorExpression::parse}, - {"format", FormatExpression::parse}, - {"interpolate", parseInterpolate}, - {"length", Length::parse}, - {"let", Let::parse}, - {"literal", Literal::parse}, - {"match", parseMatch}, - {"number", Assertion::parse}, - {"number-format", NumberFormat::parse}, - {"object", Assertion::parse}, - {"step", Step::parse}, - {"string", Assertion::parse}, - {"to-boolean", Coercion::parse}, - {"to-color", Coercion::parse}, - {"to-number", Coercion::parse}, - {"to-string", Coercion::parse}, - {"var", Var::parse}, -}); +MAPBOX_ETERNAL_CONSTEXPR const auto expressionRegistry = + mapbox::eternal::hash_map<mapbox::eternal::string, ParseFunction>({ + {"==", parseComparison}, + {"!=", parseComparison}, + {">", parseComparison}, + {"<", parseComparison}, + {">=", parseComparison}, + {"<=", parseComparison}, + {"all", All::parse}, + {"any", Any::parse}, + {"array", Assertion::parse}, + {"at", At::parse}, + {"boolean", Assertion::parse}, + {"case", Case::parse}, + {"coalesce", Coalesce::parse}, + {"collator", CollatorExpression::parse}, + {"format", FormatExpression::parse}, + {"image", Assertion::parse}, // TODO: replace once we implement image expressions + {"interpolate", parseInterpolate}, + {"length", Length::parse}, + {"let", Let::parse}, + {"literal", Literal::parse}, + {"match", parseMatch}, + {"number", Assertion::parse}, + {"number-format", NumberFormat::parse}, + {"object", Assertion::parse}, + {"step", Step::parse}, + {"string", Assertion::parse}, + {"to-boolean", Coercion::parse}, + {"to-color", Coercion::parse}, + {"to-number", Coercion::parse}, + {"to-string", Coercion::parse}, + {"var", Var::parse}, + }); bool isExpression(const std::string& name) { return expressionRegistry.contains(name.c_str()); diff --git a/src/mbgl/style/layers/background_layer.cpp b/src/mbgl/style/layers/background_layer.cpp index 7a186a3354..9187784452 100644 --- a/src/mbgl/style/layers/background_layer.cpp +++ b/src/mbgl/style/layers/background_layer.cpp @@ -1,5 +1,3 @@ -// clang-format off - // This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include <mbgl/style/layers/background_layer.hpp> @@ -148,28 +146,37 @@ TransitionOptions BackgroundLayer::getBackgroundPatternTransition() const { using namespace conversion; +namespace { + +enum class Property : uint8_t { + BackgroundColor, + BackgroundOpacity, + BackgroundPattern, + BackgroundColorTransition, + BackgroundOpacityTransition, + BackgroundPatternTransition, +}; + +template <typename T> +constexpr uint8_t toUint8(T t) noexcept { + return uint8_t(mbgl::underlying_type(t)); +} + +MAPBOX_ETERNAL_CONSTEXPR const auto layerProperties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>( + {{"background-color", toUint8(Property::BackgroundColor)}, + {"background-opacity", toUint8(Property::BackgroundOpacity)}, + {"background-pattern", toUint8(Property::BackgroundPattern)}, + {"background-color-transition", toUint8(Property::BackgroundColorTransition)}, + {"background-opacity-transition", toUint8(Property::BackgroundOpacityTransition)}, + {"background-pattern-transition", toUint8(Property::BackgroundPatternTransition)}}); + +constexpr uint8_t lastPaintPropertyIndex = toUint8(Property::BackgroundPatternTransition); +} // namespace + optional<Error> BackgroundLayer::setPaintProperty(const std::string& name, const Convertible& value) { - enum class Property { - BackgroundColor, - BackgroundOpacity, - BackgroundPattern, - BackgroundColorTransition, - BackgroundOpacityTransition, - BackgroundPatternTransition, - }; - - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({ - { "background-color", mbgl::underlying_type(Property::BackgroundColor) }, - { "background-opacity", mbgl::underlying_type(Property::BackgroundOpacity) }, - { "background-pattern", mbgl::underlying_type(Property::BackgroundPattern) }, - { "background-color-transition", mbgl::underlying_type(Property::BackgroundColorTransition) }, - { "background-opacity-transition", mbgl::underlying_type(Property::BackgroundOpacityTransition) }, - { "background-pattern-transition", mbgl::underlying_type(Property::BackgroundPatternTransition) } - }); - - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { - return Error { "layer doesn't support this property" }; + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second > lastPaintPropertyIndex) { + return Error{"layer doesn't support this property"}; } auto property = static_cast<Property>(it->second); @@ -217,24 +224,46 @@ optional<Error> BackgroundLayer::setPaintProperty(const std::string& name, const if (!transition) { return error; } - + if (property == Property::BackgroundColorTransition) { setBackgroundColorTransition(*transition); return nullopt; } - + if (property == Property::BackgroundOpacityTransition) { setBackgroundOpacityTransition(*transition); return nullopt; } - + if (property == Property::BackgroundPatternTransition) { setBackgroundPatternTransition(*transition); return nullopt; } - - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; +} + +StyleProperty BackgroundLayer::getProperty(const std::string& name) const { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end()) { + return {}; + } + + switch (static_cast<Property>(it->second)) { + case Property::BackgroundColor: + return makeStyleProperty(getBackgroundColor()); + case Property::BackgroundOpacity: + return makeStyleProperty(getBackgroundOpacity()); + case Property::BackgroundPattern: + return makeStyleProperty(getBackgroundPattern()); + case Property::BackgroundColorTransition: + return makeStyleProperty(getBackgroundColorTransition()); + case Property::BackgroundOpacityTransition: + return makeStyleProperty(getBackgroundOpacityTransition()); + case Property::BackgroundPatternTransition: + return makeStyleProperty(getBackgroundPatternTransition()); + } + return {}; } optional<Error> BackgroundLayer::setLayoutProperty(const std::string& name, const Convertible& value) { @@ -251,5 +280,3 @@ Mutable<Layer::Impl> BackgroundLayer::mutableBaseImpl() const { } // namespace style } // namespace mbgl - -// clang-format on diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp index 2f68bcccf3..145d76a9a8 100644 --- a/src/mbgl/style/layers/circle_layer.cpp +++ b/src/mbgl/style/layers/circle_layer.cpp @@ -1,5 +1,3 @@ -// clang-format off - // This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include <mbgl/style/layers/circle_layer.hpp> @@ -364,60 +362,69 @@ TransitionOptions CircleLayer::getCircleTranslateAnchorTransition() const { using namespace conversion; +namespace { + +enum class Property : uint8_t { + CircleBlur, + CircleColor, + CircleOpacity, + CirclePitchAlignment, + CirclePitchScale, + CircleRadius, + CircleStrokeColor, + CircleStrokeOpacity, + CircleStrokeWidth, + CircleTranslate, + CircleTranslateAnchor, + CircleBlurTransition, + CircleColorTransition, + CircleOpacityTransition, + CirclePitchAlignmentTransition, + CirclePitchScaleTransition, + CircleRadiusTransition, + CircleStrokeColorTransition, + CircleStrokeOpacityTransition, + CircleStrokeWidthTransition, + CircleTranslateTransition, + CircleTranslateAnchorTransition, +}; + +template <typename T> +constexpr uint8_t toUint8(T t) noexcept { + return uint8_t(mbgl::underlying_type(t)); +} + +MAPBOX_ETERNAL_CONSTEXPR const auto layerProperties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>( + {{"circle-blur", toUint8(Property::CircleBlur)}, + {"circle-color", toUint8(Property::CircleColor)}, + {"circle-opacity", toUint8(Property::CircleOpacity)}, + {"circle-pitch-alignment", toUint8(Property::CirclePitchAlignment)}, + {"circle-pitch-scale", toUint8(Property::CirclePitchScale)}, + {"circle-radius", toUint8(Property::CircleRadius)}, + {"circle-stroke-color", toUint8(Property::CircleStrokeColor)}, + {"circle-stroke-opacity", toUint8(Property::CircleStrokeOpacity)}, + {"circle-stroke-width", toUint8(Property::CircleStrokeWidth)}, + {"circle-translate", toUint8(Property::CircleTranslate)}, + {"circle-translate-anchor", toUint8(Property::CircleTranslateAnchor)}, + {"circle-blur-transition", toUint8(Property::CircleBlurTransition)}, + {"circle-color-transition", toUint8(Property::CircleColorTransition)}, + {"circle-opacity-transition", toUint8(Property::CircleOpacityTransition)}, + {"circle-pitch-alignment-transition", toUint8(Property::CirclePitchAlignmentTransition)}, + {"circle-pitch-scale-transition", toUint8(Property::CirclePitchScaleTransition)}, + {"circle-radius-transition", toUint8(Property::CircleRadiusTransition)}, + {"circle-stroke-color-transition", toUint8(Property::CircleStrokeColorTransition)}, + {"circle-stroke-opacity-transition", toUint8(Property::CircleStrokeOpacityTransition)}, + {"circle-stroke-width-transition", toUint8(Property::CircleStrokeWidthTransition)}, + {"circle-translate-transition", toUint8(Property::CircleTranslateTransition)}, + {"circle-translate-anchor-transition", toUint8(Property::CircleTranslateAnchorTransition)}}); + +constexpr uint8_t lastPaintPropertyIndex = toUint8(Property::CircleTranslateAnchorTransition); +} // namespace + optional<Error> CircleLayer::setPaintProperty(const std::string& name, const Convertible& value) { - enum class Property { - CircleBlur, - CircleColor, - CircleOpacity, - CirclePitchAlignment, - CirclePitchScale, - CircleRadius, - CircleStrokeColor, - CircleStrokeOpacity, - CircleStrokeWidth, - CircleTranslate, - CircleTranslateAnchor, - CircleBlurTransition, - CircleColorTransition, - CircleOpacityTransition, - CirclePitchAlignmentTransition, - CirclePitchScaleTransition, - CircleRadiusTransition, - CircleStrokeColorTransition, - CircleStrokeOpacityTransition, - CircleStrokeWidthTransition, - CircleTranslateTransition, - CircleTranslateAnchorTransition, - }; - - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({ - { "circle-blur", mbgl::underlying_type(Property::CircleBlur) }, - { "circle-color", mbgl::underlying_type(Property::CircleColor) }, - { "circle-opacity", mbgl::underlying_type(Property::CircleOpacity) }, - { "circle-pitch-alignment", mbgl::underlying_type(Property::CirclePitchAlignment) }, - { "circle-pitch-scale", mbgl::underlying_type(Property::CirclePitchScale) }, - { "circle-radius", mbgl::underlying_type(Property::CircleRadius) }, - { "circle-stroke-color", mbgl::underlying_type(Property::CircleStrokeColor) }, - { "circle-stroke-opacity", mbgl::underlying_type(Property::CircleStrokeOpacity) }, - { "circle-stroke-width", mbgl::underlying_type(Property::CircleStrokeWidth) }, - { "circle-translate", mbgl::underlying_type(Property::CircleTranslate) }, - { "circle-translate-anchor", mbgl::underlying_type(Property::CircleTranslateAnchor) }, - { "circle-blur-transition", mbgl::underlying_type(Property::CircleBlurTransition) }, - { "circle-color-transition", mbgl::underlying_type(Property::CircleColorTransition) }, - { "circle-opacity-transition", mbgl::underlying_type(Property::CircleOpacityTransition) }, - { "circle-pitch-alignment-transition", mbgl::underlying_type(Property::CirclePitchAlignmentTransition) }, - { "circle-pitch-scale-transition", mbgl::underlying_type(Property::CirclePitchScaleTransition) }, - { "circle-radius-transition", mbgl::underlying_type(Property::CircleRadiusTransition) }, - { "circle-stroke-color-transition", mbgl::underlying_type(Property::CircleStrokeColorTransition) }, - { "circle-stroke-opacity-transition", mbgl::underlying_type(Property::CircleStrokeOpacityTransition) }, - { "circle-stroke-width-transition", mbgl::underlying_type(Property::CircleStrokeWidthTransition) }, - { "circle-translate-transition", mbgl::underlying_type(Property::CircleTranslateTransition) }, - { "circle-translate-anchor-transition", mbgl::underlying_type(Property::CircleTranslateAnchorTransition) } - }); - - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { - return Error { "layer doesn't support this property" }; + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second > lastPaintPropertyIndex) { + return Error{"layer doesn't support this property"}; } auto property = static_cast<Property>(it->second); @@ -530,64 +537,118 @@ optional<Error> CircleLayer::setPaintProperty(const std::string& name, const Con if (!transition) { return error; } - + if (property == Property::CircleBlurTransition) { setCircleBlurTransition(*transition); return nullopt; } - + if (property == Property::CircleColorTransition) { setCircleColorTransition(*transition); return nullopt; } - + if (property == Property::CircleOpacityTransition) { setCircleOpacityTransition(*transition); return nullopt; } - + if (property == Property::CirclePitchAlignmentTransition) { setCirclePitchAlignmentTransition(*transition); return nullopt; } - + if (property == Property::CirclePitchScaleTransition) { setCirclePitchScaleTransition(*transition); return nullopt; } - + if (property == Property::CircleRadiusTransition) { setCircleRadiusTransition(*transition); return nullopt; } - + if (property == Property::CircleStrokeColorTransition) { setCircleStrokeColorTransition(*transition); return nullopt; } - + if (property == Property::CircleStrokeOpacityTransition) { setCircleStrokeOpacityTransition(*transition); return nullopt; } - + if (property == Property::CircleStrokeWidthTransition) { setCircleStrokeWidthTransition(*transition); return nullopt; } - + if (property == Property::CircleTranslateTransition) { setCircleTranslateTransition(*transition); return nullopt; } - + if (property == Property::CircleTranslateAnchorTransition) { setCircleTranslateAnchorTransition(*transition); return nullopt; } - - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; +} + +StyleProperty CircleLayer::getProperty(const std::string& name) const { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end()) { + return {}; + } + + switch (static_cast<Property>(it->second)) { + case Property::CircleBlur: + return makeStyleProperty(getCircleBlur()); + case Property::CircleColor: + return makeStyleProperty(getCircleColor()); + case Property::CircleOpacity: + return makeStyleProperty(getCircleOpacity()); + case Property::CirclePitchAlignment: + return makeStyleProperty(getCirclePitchAlignment()); + case Property::CirclePitchScale: + return makeStyleProperty(getCirclePitchScale()); + case Property::CircleRadius: + return makeStyleProperty(getCircleRadius()); + case Property::CircleStrokeColor: + return makeStyleProperty(getCircleStrokeColor()); + case Property::CircleStrokeOpacity: + return makeStyleProperty(getCircleStrokeOpacity()); + case Property::CircleStrokeWidth: + return makeStyleProperty(getCircleStrokeWidth()); + case Property::CircleTranslate: + return makeStyleProperty(getCircleTranslate()); + case Property::CircleTranslateAnchor: + return makeStyleProperty(getCircleTranslateAnchor()); + case Property::CircleBlurTransition: + return makeStyleProperty(getCircleBlurTransition()); + case Property::CircleColorTransition: + return makeStyleProperty(getCircleColorTransition()); + case Property::CircleOpacityTransition: + return makeStyleProperty(getCircleOpacityTransition()); + case Property::CirclePitchAlignmentTransition: + return makeStyleProperty(getCirclePitchAlignmentTransition()); + case Property::CirclePitchScaleTransition: + return makeStyleProperty(getCirclePitchScaleTransition()); + case Property::CircleRadiusTransition: + return makeStyleProperty(getCircleRadiusTransition()); + case Property::CircleStrokeColorTransition: + return makeStyleProperty(getCircleStrokeColorTransition()); + case Property::CircleStrokeOpacityTransition: + return makeStyleProperty(getCircleStrokeOpacityTransition()); + case Property::CircleStrokeWidthTransition: + return makeStyleProperty(getCircleStrokeWidthTransition()); + case Property::CircleTranslateTransition: + return makeStyleProperty(getCircleTranslateTransition()); + case Property::CircleTranslateAnchorTransition: + return makeStyleProperty(getCircleTranslateAnchorTransition()); + } + return {}; } optional<Error> CircleLayer::setLayoutProperty(const std::string& name, const Convertible& value) { @@ -604,5 +665,3 @@ Mutable<Layer::Impl> CircleLayer::mutableBaseImpl() const { } // namespace style } // namespace mbgl - -// clang-format on diff --git a/src/mbgl/style/layers/custom_layer.cpp b/src/mbgl/style/layers/custom_layer.cpp index 8b9e17ea25..e13cf0069a 100644 --- a/src/mbgl/style/layers/custom_layer.cpp +++ b/src/mbgl/style/layers/custom_layer.cpp @@ -47,6 +47,10 @@ optional<Error> CustomLayer::setLayoutProperty(const std::string&, const Convert return Error { "layer doesn't support this property" }; } +StyleProperty CustomLayer::getProperty(const std::string&) const { + return {}; +} + Mutable<Layer::Impl> CustomLayer::mutableBaseImpl() const { return staticMutableCast<Layer::Impl>(mutableImpl()); } diff --git a/src/mbgl/style/layers/fill_extrusion_layer.cpp b/src/mbgl/style/layers/fill_extrusion_layer.cpp index 2686f7d044..87e196926f 100644 --- a/src/mbgl/style/layers/fill_extrusion_layer.cpp +++ b/src/mbgl/style/layers/fill_extrusion_layer.cpp @@ -1,5 +1,3 @@ -// clang-format off - // This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include <mbgl/style/layers/fill_extrusion_layer.hpp> @@ -283,48 +281,57 @@ TransitionOptions FillExtrusionLayer::getFillExtrusionVerticalGradientTransition using namespace conversion; +namespace { + +enum class Property : uint8_t { + FillExtrusionBase, + FillExtrusionColor, + FillExtrusionHeight, + FillExtrusionOpacity, + FillExtrusionPattern, + FillExtrusionTranslate, + FillExtrusionTranslateAnchor, + FillExtrusionVerticalGradient, + FillExtrusionBaseTransition, + FillExtrusionColorTransition, + FillExtrusionHeightTransition, + FillExtrusionOpacityTransition, + FillExtrusionPatternTransition, + FillExtrusionTranslateTransition, + FillExtrusionTranslateAnchorTransition, + FillExtrusionVerticalGradientTransition, +}; + +template <typename T> +constexpr uint8_t toUint8(T t) noexcept { + return uint8_t(mbgl::underlying_type(t)); +} + +MAPBOX_ETERNAL_CONSTEXPR const auto layerProperties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>( + {{"fill-extrusion-base", toUint8(Property::FillExtrusionBase)}, + {"fill-extrusion-color", toUint8(Property::FillExtrusionColor)}, + {"fill-extrusion-height", toUint8(Property::FillExtrusionHeight)}, + {"fill-extrusion-opacity", toUint8(Property::FillExtrusionOpacity)}, + {"fill-extrusion-pattern", toUint8(Property::FillExtrusionPattern)}, + {"fill-extrusion-translate", toUint8(Property::FillExtrusionTranslate)}, + {"fill-extrusion-translate-anchor", toUint8(Property::FillExtrusionTranslateAnchor)}, + {"fill-extrusion-vertical-gradient", toUint8(Property::FillExtrusionVerticalGradient)}, + {"fill-extrusion-base-transition", toUint8(Property::FillExtrusionBaseTransition)}, + {"fill-extrusion-color-transition", toUint8(Property::FillExtrusionColorTransition)}, + {"fill-extrusion-height-transition", toUint8(Property::FillExtrusionHeightTransition)}, + {"fill-extrusion-opacity-transition", toUint8(Property::FillExtrusionOpacityTransition)}, + {"fill-extrusion-pattern-transition", toUint8(Property::FillExtrusionPatternTransition)}, + {"fill-extrusion-translate-transition", toUint8(Property::FillExtrusionTranslateTransition)}, + {"fill-extrusion-translate-anchor-transition", toUint8(Property::FillExtrusionTranslateAnchorTransition)}, + {"fill-extrusion-vertical-gradient-transition", toUint8(Property::FillExtrusionVerticalGradientTransition)}}); + +constexpr uint8_t lastPaintPropertyIndex = toUint8(Property::FillExtrusionVerticalGradientTransition); +} // namespace + optional<Error> FillExtrusionLayer::setPaintProperty(const std::string& name, const Convertible& value) { - enum class Property { - FillExtrusionBase, - FillExtrusionColor, - FillExtrusionHeight, - FillExtrusionOpacity, - FillExtrusionPattern, - FillExtrusionTranslate, - FillExtrusionTranslateAnchor, - FillExtrusionVerticalGradient, - FillExtrusionBaseTransition, - FillExtrusionColorTransition, - FillExtrusionHeightTransition, - FillExtrusionOpacityTransition, - FillExtrusionPatternTransition, - FillExtrusionTranslateTransition, - FillExtrusionTranslateAnchorTransition, - FillExtrusionVerticalGradientTransition, - }; - - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({ - { "fill-extrusion-base", mbgl::underlying_type(Property::FillExtrusionBase) }, - { "fill-extrusion-color", mbgl::underlying_type(Property::FillExtrusionColor) }, - { "fill-extrusion-height", mbgl::underlying_type(Property::FillExtrusionHeight) }, - { "fill-extrusion-opacity", mbgl::underlying_type(Property::FillExtrusionOpacity) }, - { "fill-extrusion-pattern", mbgl::underlying_type(Property::FillExtrusionPattern) }, - { "fill-extrusion-translate", mbgl::underlying_type(Property::FillExtrusionTranslate) }, - { "fill-extrusion-translate-anchor", mbgl::underlying_type(Property::FillExtrusionTranslateAnchor) }, - { "fill-extrusion-vertical-gradient", mbgl::underlying_type(Property::FillExtrusionVerticalGradient) }, - { "fill-extrusion-base-transition", mbgl::underlying_type(Property::FillExtrusionBaseTransition) }, - { "fill-extrusion-color-transition", mbgl::underlying_type(Property::FillExtrusionColorTransition) }, - { "fill-extrusion-height-transition", mbgl::underlying_type(Property::FillExtrusionHeightTransition) }, - { "fill-extrusion-opacity-transition", mbgl::underlying_type(Property::FillExtrusionOpacityTransition) }, - { "fill-extrusion-pattern-transition", mbgl::underlying_type(Property::FillExtrusionPatternTransition) }, - { "fill-extrusion-translate-transition", mbgl::underlying_type(Property::FillExtrusionTranslateTransition) }, - { "fill-extrusion-translate-anchor-transition", mbgl::underlying_type(Property::FillExtrusionTranslateAnchorTransition) }, - { "fill-extrusion-vertical-gradient-transition", mbgl::underlying_type(Property::FillExtrusionVerticalGradientTransition) } - }); - - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { - return Error { "layer doesn't support this property" }; + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second > lastPaintPropertyIndex) { + return Error{"layer doesn't support this property"}; } auto property = static_cast<Property>(it->second); @@ -427,49 +434,91 @@ optional<Error> FillExtrusionLayer::setPaintProperty(const std::string& name, co if (!transition) { return error; } - + if (property == Property::FillExtrusionBaseTransition) { setFillExtrusionBaseTransition(*transition); return nullopt; } - + if (property == Property::FillExtrusionColorTransition) { setFillExtrusionColorTransition(*transition); return nullopt; } - + if (property == Property::FillExtrusionHeightTransition) { setFillExtrusionHeightTransition(*transition); return nullopt; } - + if (property == Property::FillExtrusionOpacityTransition) { setFillExtrusionOpacityTransition(*transition); return nullopt; } - + if (property == Property::FillExtrusionPatternTransition) { setFillExtrusionPatternTransition(*transition); return nullopt; } - + if (property == Property::FillExtrusionTranslateTransition) { setFillExtrusionTranslateTransition(*transition); return nullopt; } - + if (property == Property::FillExtrusionTranslateAnchorTransition) { setFillExtrusionTranslateAnchorTransition(*transition); return nullopt; } - + if (property == Property::FillExtrusionVerticalGradientTransition) { setFillExtrusionVerticalGradientTransition(*transition); return nullopt; } - - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; +} + +StyleProperty FillExtrusionLayer::getProperty(const std::string& name) const { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end()) { + return {}; + } + + switch (static_cast<Property>(it->second)) { + case Property::FillExtrusionBase: + return makeStyleProperty(getFillExtrusionBase()); + case Property::FillExtrusionColor: + return makeStyleProperty(getFillExtrusionColor()); + case Property::FillExtrusionHeight: + return makeStyleProperty(getFillExtrusionHeight()); + case Property::FillExtrusionOpacity: + return makeStyleProperty(getFillExtrusionOpacity()); + case Property::FillExtrusionPattern: + return makeStyleProperty(getFillExtrusionPattern()); + case Property::FillExtrusionTranslate: + return makeStyleProperty(getFillExtrusionTranslate()); + case Property::FillExtrusionTranslateAnchor: + return makeStyleProperty(getFillExtrusionTranslateAnchor()); + case Property::FillExtrusionVerticalGradient: + return makeStyleProperty(getFillExtrusionVerticalGradient()); + case Property::FillExtrusionBaseTransition: + return makeStyleProperty(getFillExtrusionBaseTransition()); + case Property::FillExtrusionColorTransition: + return makeStyleProperty(getFillExtrusionColorTransition()); + case Property::FillExtrusionHeightTransition: + return makeStyleProperty(getFillExtrusionHeightTransition()); + case Property::FillExtrusionOpacityTransition: + return makeStyleProperty(getFillExtrusionOpacityTransition()); + case Property::FillExtrusionPatternTransition: + return makeStyleProperty(getFillExtrusionPatternTransition()); + case Property::FillExtrusionTranslateTransition: + return makeStyleProperty(getFillExtrusionTranslateTransition()); + case Property::FillExtrusionTranslateAnchorTransition: + return makeStyleProperty(getFillExtrusionTranslateAnchorTransition()); + case Property::FillExtrusionVerticalGradientTransition: + return makeStyleProperty(getFillExtrusionVerticalGradientTransition()); + } + return {}; } optional<Error> FillExtrusionLayer::setLayoutProperty(const std::string& name, const Convertible& value) { @@ -486,5 +535,3 @@ Mutable<Layer::Impl> FillExtrusionLayer::mutableBaseImpl() const { } // namespace style } // namespace mbgl - -// clang-format on diff --git a/src/mbgl/style/layers/fill_layer.cpp b/src/mbgl/style/layers/fill_layer.cpp index 52f2b166b3..e3d6c6c708 100644 --- a/src/mbgl/style/layers/fill_layer.cpp +++ b/src/mbgl/style/layers/fill_layer.cpp @@ -1,5 +1,3 @@ -// clang-format off - // This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include <mbgl/style/layers/fill_layer.hpp> @@ -256,44 +254,53 @@ TransitionOptions FillLayer::getFillTranslateAnchorTransition() const { using namespace conversion; +namespace { + +enum class Property : uint8_t { + FillAntialias, + FillColor, + FillOpacity, + FillOutlineColor, + FillPattern, + FillTranslate, + FillTranslateAnchor, + FillAntialiasTransition, + FillColorTransition, + FillOpacityTransition, + FillOutlineColorTransition, + FillPatternTransition, + FillTranslateTransition, + FillTranslateAnchorTransition, +}; + +template <typename T> +constexpr uint8_t toUint8(T t) noexcept { + return uint8_t(mbgl::underlying_type(t)); +} + +MAPBOX_ETERNAL_CONSTEXPR const auto layerProperties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>( + {{"fill-antialias", toUint8(Property::FillAntialias)}, + {"fill-color", toUint8(Property::FillColor)}, + {"fill-opacity", toUint8(Property::FillOpacity)}, + {"fill-outline-color", toUint8(Property::FillOutlineColor)}, + {"fill-pattern", toUint8(Property::FillPattern)}, + {"fill-translate", toUint8(Property::FillTranslate)}, + {"fill-translate-anchor", toUint8(Property::FillTranslateAnchor)}, + {"fill-antialias-transition", toUint8(Property::FillAntialiasTransition)}, + {"fill-color-transition", toUint8(Property::FillColorTransition)}, + {"fill-opacity-transition", toUint8(Property::FillOpacityTransition)}, + {"fill-outline-color-transition", toUint8(Property::FillOutlineColorTransition)}, + {"fill-pattern-transition", toUint8(Property::FillPatternTransition)}, + {"fill-translate-transition", toUint8(Property::FillTranslateTransition)}, + {"fill-translate-anchor-transition", toUint8(Property::FillTranslateAnchorTransition)}}); + +constexpr uint8_t lastPaintPropertyIndex = toUint8(Property::FillTranslateAnchorTransition); +} // namespace + optional<Error> FillLayer::setPaintProperty(const std::string& name, const Convertible& value) { - enum class Property { - FillAntialias, - FillColor, - FillOpacity, - FillOutlineColor, - FillPattern, - FillTranslate, - FillTranslateAnchor, - FillAntialiasTransition, - FillColorTransition, - FillOpacityTransition, - FillOutlineColorTransition, - FillPatternTransition, - FillTranslateTransition, - FillTranslateAnchorTransition, - }; - - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({ - { "fill-antialias", mbgl::underlying_type(Property::FillAntialias) }, - { "fill-color", mbgl::underlying_type(Property::FillColor) }, - { "fill-opacity", mbgl::underlying_type(Property::FillOpacity) }, - { "fill-outline-color", mbgl::underlying_type(Property::FillOutlineColor) }, - { "fill-pattern", mbgl::underlying_type(Property::FillPattern) }, - { "fill-translate", mbgl::underlying_type(Property::FillTranslate) }, - { "fill-translate-anchor", mbgl::underlying_type(Property::FillTranslateAnchor) }, - { "fill-antialias-transition", mbgl::underlying_type(Property::FillAntialiasTransition) }, - { "fill-color-transition", mbgl::underlying_type(Property::FillColorTransition) }, - { "fill-opacity-transition", mbgl::underlying_type(Property::FillOpacityTransition) }, - { "fill-outline-color-transition", mbgl::underlying_type(Property::FillOutlineColorTransition) }, - { "fill-pattern-transition", mbgl::underlying_type(Property::FillPatternTransition) }, - { "fill-translate-transition", mbgl::underlying_type(Property::FillTranslateTransition) }, - { "fill-translate-anchor-transition", mbgl::underlying_type(Property::FillTranslateAnchorTransition) } - }); - - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { - return Error { "layer doesn't support this property" }; + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second > lastPaintPropertyIndex) { + return Error{"layer doesn't support this property"}; } auto property = static_cast<Property>(it->second); @@ -384,44 +391,82 @@ optional<Error> FillLayer::setPaintProperty(const std::string& name, const Conve if (!transition) { return error; } - + if (property == Property::FillAntialiasTransition) { setFillAntialiasTransition(*transition); return nullopt; } - + if (property == Property::FillColorTransition) { setFillColorTransition(*transition); return nullopt; } - + if (property == Property::FillOpacityTransition) { setFillOpacityTransition(*transition); return nullopt; } - + if (property == Property::FillOutlineColorTransition) { setFillOutlineColorTransition(*transition); return nullopt; } - + if (property == Property::FillPatternTransition) { setFillPatternTransition(*transition); return nullopt; } - + if (property == Property::FillTranslateTransition) { setFillTranslateTransition(*transition); return nullopt; } - + if (property == Property::FillTranslateAnchorTransition) { setFillTranslateAnchorTransition(*transition); return nullopt; } - - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; +} + +StyleProperty FillLayer::getProperty(const std::string& name) const { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end()) { + return {}; + } + + switch (static_cast<Property>(it->second)) { + case Property::FillAntialias: + return makeStyleProperty(getFillAntialias()); + case Property::FillColor: + return makeStyleProperty(getFillColor()); + case Property::FillOpacity: + return makeStyleProperty(getFillOpacity()); + case Property::FillOutlineColor: + return makeStyleProperty(getFillOutlineColor()); + case Property::FillPattern: + return makeStyleProperty(getFillPattern()); + case Property::FillTranslate: + return makeStyleProperty(getFillTranslate()); + case Property::FillTranslateAnchor: + return makeStyleProperty(getFillTranslateAnchor()); + case Property::FillAntialiasTransition: + return makeStyleProperty(getFillAntialiasTransition()); + case Property::FillColorTransition: + return makeStyleProperty(getFillColorTransition()); + case Property::FillOpacityTransition: + return makeStyleProperty(getFillOpacityTransition()); + case Property::FillOutlineColorTransition: + return makeStyleProperty(getFillOutlineColorTransition()); + case Property::FillPatternTransition: + return makeStyleProperty(getFillPatternTransition()); + case Property::FillTranslateTransition: + return makeStyleProperty(getFillTranslateTransition()); + case Property::FillTranslateAnchorTransition: + return makeStyleProperty(getFillTranslateAnchorTransition()); + } + return {}; } optional<Error> FillLayer::setLayoutProperty(const std::string& name, const Convertible& value) { @@ -438,5 +483,3 @@ Mutable<Layer::Impl> FillLayer::mutableBaseImpl() const { } // namespace style } // namespace mbgl - -// clang-format on diff --git a/src/mbgl/style/layers/heatmap_layer.cpp b/src/mbgl/style/layers/heatmap_layer.cpp index 86bb2d6de1..332c65c6b4 100644 --- a/src/mbgl/style/layers/heatmap_layer.cpp +++ b/src/mbgl/style/layers/heatmap_layer.cpp @@ -1,5 +1,3 @@ -// clang-format off - // This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include <mbgl/style/layers/heatmap_layer.hpp> @@ -204,36 +202,45 @@ TransitionOptions HeatmapLayer::getHeatmapWeightTransition() const { using namespace conversion; +namespace { + +enum class Property : uint8_t { + HeatmapColor, + HeatmapIntensity, + HeatmapOpacity, + HeatmapRadius, + HeatmapWeight, + HeatmapColorTransition, + HeatmapIntensityTransition, + HeatmapOpacityTransition, + HeatmapRadiusTransition, + HeatmapWeightTransition, +}; + +template <typename T> +constexpr uint8_t toUint8(T t) noexcept { + return uint8_t(mbgl::underlying_type(t)); +} + +MAPBOX_ETERNAL_CONSTEXPR const auto layerProperties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>( + {{"heatmap-color", toUint8(Property::HeatmapColor)}, + {"heatmap-intensity", toUint8(Property::HeatmapIntensity)}, + {"heatmap-opacity", toUint8(Property::HeatmapOpacity)}, + {"heatmap-radius", toUint8(Property::HeatmapRadius)}, + {"heatmap-weight", toUint8(Property::HeatmapWeight)}, + {"heatmap-color-transition", toUint8(Property::HeatmapColorTransition)}, + {"heatmap-intensity-transition", toUint8(Property::HeatmapIntensityTransition)}, + {"heatmap-opacity-transition", toUint8(Property::HeatmapOpacityTransition)}, + {"heatmap-radius-transition", toUint8(Property::HeatmapRadiusTransition)}, + {"heatmap-weight-transition", toUint8(Property::HeatmapWeightTransition)}}); + +constexpr uint8_t lastPaintPropertyIndex = toUint8(Property::HeatmapWeightTransition); +} // namespace + optional<Error> HeatmapLayer::setPaintProperty(const std::string& name, const Convertible& value) { - enum class Property { - HeatmapColor, - HeatmapIntensity, - HeatmapOpacity, - HeatmapRadius, - HeatmapWeight, - HeatmapColorTransition, - HeatmapIntensityTransition, - HeatmapOpacityTransition, - HeatmapRadiusTransition, - HeatmapWeightTransition, - }; - - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({ - { "heatmap-color", mbgl::underlying_type(Property::HeatmapColor) }, - { "heatmap-intensity", mbgl::underlying_type(Property::HeatmapIntensity) }, - { "heatmap-opacity", mbgl::underlying_type(Property::HeatmapOpacity) }, - { "heatmap-radius", mbgl::underlying_type(Property::HeatmapRadius) }, - { "heatmap-weight", mbgl::underlying_type(Property::HeatmapWeight) }, - { "heatmap-color-transition", mbgl::underlying_type(Property::HeatmapColorTransition) }, - { "heatmap-intensity-transition", mbgl::underlying_type(Property::HeatmapIntensityTransition) }, - { "heatmap-opacity-transition", mbgl::underlying_type(Property::HeatmapOpacityTransition) }, - { "heatmap-radius-transition", mbgl::underlying_type(Property::HeatmapRadiusTransition) }, - { "heatmap-weight-transition", mbgl::underlying_type(Property::HeatmapWeightTransition) } - }); - - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { - return Error { "layer doesn't support this property" }; + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second > lastPaintPropertyIndex) { + return Error{"layer doesn't support this property"}; } auto property = static_cast<Property>(it->second); @@ -295,34 +302,64 @@ optional<Error> HeatmapLayer::setPaintProperty(const std::string& name, const Co if (!transition) { return error; } - + if (property == Property::HeatmapColorTransition) { setHeatmapColorTransition(*transition); return nullopt; } - + if (property == Property::HeatmapIntensityTransition) { setHeatmapIntensityTransition(*transition); return nullopt; } - + if (property == Property::HeatmapOpacityTransition) { setHeatmapOpacityTransition(*transition); return nullopt; } - + if (property == Property::HeatmapRadiusTransition) { setHeatmapRadiusTransition(*transition); return nullopt; } - + if (property == Property::HeatmapWeightTransition) { setHeatmapWeightTransition(*transition); return nullopt; } - - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; +} + +StyleProperty HeatmapLayer::getProperty(const std::string& name) const { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end()) { + return {}; + } + + switch (static_cast<Property>(it->second)) { + case Property::HeatmapColor: + return makeStyleProperty(getHeatmapColor()); + case Property::HeatmapIntensity: + return makeStyleProperty(getHeatmapIntensity()); + case Property::HeatmapOpacity: + return makeStyleProperty(getHeatmapOpacity()); + case Property::HeatmapRadius: + return makeStyleProperty(getHeatmapRadius()); + case Property::HeatmapWeight: + return makeStyleProperty(getHeatmapWeight()); + case Property::HeatmapColorTransition: + return makeStyleProperty(getHeatmapColorTransition()); + case Property::HeatmapIntensityTransition: + return makeStyleProperty(getHeatmapIntensityTransition()); + case Property::HeatmapOpacityTransition: + return makeStyleProperty(getHeatmapOpacityTransition()); + case Property::HeatmapRadiusTransition: + return makeStyleProperty(getHeatmapRadiusTransition()); + case Property::HeatmapWeightTransition: + return makeStyleProperty(getHeatmapWeightTransition()); + } + return {}; } optional<Error> HeatmapLayer::setLayoutProperty(const std::string& name, const Convertible& value) { @@ -339,5 +376,3 @@ Mutable<Layer::Impl> HeatmapLayer::mutableBaseImpl() const { } // namespace style } // namespace mbgl - -// clang-format on diff --git a/src/mbgl/style/layers/hillshade_layer.cpp b/src/mbgl/style/layers/hillshade_layer.cpp index 710efe5844..a55c079c49 100644 --- a/src/mbgl/style/layers/hillshade_layer.cpp +++ b/src/mbgl/style/layers/hillshade_layer.cpp @@ -1,5 +1,3 @@ -// clang-format off - // This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include <mbgl/style/layers/hillshade_layer.hpp> @@ -229,40 +227,49 @@ TransitionOptions HillshadeLayer::getHillshadeShadowColorTransition() const { using namespace conversion; +namespace { + +enum class Property : uint8_t { + HillshadeAccentColor, + HillshadeExaggeration, + HillshadeHighlightColor, + HillshadeIlluminationAnchor, + HillshadeIlluminationDirection, + HillshadeShadowColor, + HillshadeAccentColorTransition, + HillshadeExaggerationTransition, + HillshadeHighlightColorTransition, + HillshadeIlluminationAnchorTransition, + HillshadeIlluminationDirectionTransition, + HillshadeShadowColorTransition, +}; + +template <typename T> +constexpr uint8_t toUint8(T t) noexcept { + return uint8_t(mbgl::underlying_type(t)); +} + +MAPBOX_ETERNAL_CONSTEXPR const auto layerProperties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>( + {{"hillshade-accent-color", toUint8(Property::HillshadeAccentColor)}, + {"hillshade-exaggeration", toUint8(Property::HillshadeExaggeration)}, + {"hillshade-highlight-color", toUint8(Property::HillshadeHighlightColor)}, + {"hillshade-illumination-anchor", toUint8(Property::HillshadeIlluminationAnchor)}, + {"hillshade-illumination-direction", toUint8(Property::HillshadeIlluminationDirection)}, + {"hillshade-shadow-color", toUint8(Property::HillshadeShadowColor)}, + {"hillshade-accent-color-transition", toUint8(Property::HillshadeAccentColorTransition)}, + {"hillshade-exaggeration-transition", toUint8(Property::HillshadeExaggerationTransition)}, + {"hillshade-highlight-color-transition", toUint8(Property::HillshadeHighlightColorTransition)}, + {"hillshade-illumination-anchor-transition", toUint8(Property::HillshadeIlluminationAnchorTransition)}, + {"hillshade-illumination-direction-transition", toUint8(Property::HillshadeIlluminationDirectionTransition)}, + {"hillshade-shadow-color-transition", toUint8(Property::HillshadeShadowColorTransition)}}); + +constexpr uint8_t lastPaintPropertyIndex = toUint8(Property::HillshadeShadowColorTransition); +} // namespace + optional<Error> HillshadeLayer::setPaintProperty(const std::string& name, const Convertible& value) { - enum class Property { - HillshadeAccentColor, - HillshadeExaggeration, - HillshadeHighlightColor, - HillshadeIlluminationAnchor, - HillshadeIlluminationDirection, - HillshadeShadowColor, - HillshadeAccentColorTransition, - HillshadeExaggerationTransition, - HillshadeHighlightColorTransition, - HillshadeIlluminationAnchorTransition, - HillshadeIlluminationDirectionTransition, - HillshadeShadowColorTransition, - }; - - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({ - { "hillshade-accent-color", mbgl::underlying_type(Property::HillshadeAccentColor) }, - { "hillshade-exaggeration", mbgl::underlying_type(Property::HillshadeExaggeration) }, - { "hillshade-highlight-color", mbgl::underlying_type(Property::HillshadeHighlightColor) }, - { "hillshade-illumination-anchor", mbgl::underlying_type(Property::HillshadeIlluminationAnchor) }, - { "hillshade-illumination-direction", mbgl::underlying_type(Property::HillshadeIlluminationDirection) }, - { "hillshade-shadow-color", mbgl::underlying_type(Property::HillshadeShadowColor) }, - { "hillshade-accent-color-transition", mbgl::underlying_type(Property::HillshadeAccentColorTransition) }, - { "hillshade-exaggeration-transition", mbgl::underlying_type(Property::HillshadeExaggerationTransition) }, - { "hillshade-highlight-color-transition", mbgl::underlying_type(Property::HillshadeHighlightColorTransition) }, - { "hillshade-illumination-anchor-transition", mbgl::underlying_type(Property::HillshadeIlluminationAnchorTransition) }, - { "hillshade-illumination-direction-transition", mbgl::underlying_type(Property::HillshadeIlluminationDirectionTransition) }, - { "hillshade-shadow-color-transition", mbgl::underlying_type(Property::HillshadeShadowColorTransition) } - }); - - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { - return Error { "layer doesn't support this property" }; + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second > lastPaintPropertyIndex) { + return Error{"layer doesn't support this property"}; } auto property = static_cast<Property>(it->second); @@ -329,39 +336,73 @@ optional<Error> HillshadeLayer::setPaintProperty(const std::string& name, const if (!transition) { return error; } - + if (property == Property::HillshadeAccentColorTransition) { setHillshadeAccentColorTransition(*transition); return nullopt; } - + if (property == Property::HillshadeExaggerationTransition) { setHillshadeExaggerationTransition(*transition); return nullopt; } - + if (property == Property::HillshadeHighlightColorTransition) { setHillshadeHighlightColorTransition(*transition); return nullopt; } - + if (property == Property::HillshadeIlluminationAnchorTransition) { setHillshadeIlluminationAnchorTransition(*transition); return nullopt; } - + if (property == Property::HillshadeIlluminationDirectionTransition) { setHillshadeIlluminationDirectionTransition(*transition); return nullopt; } - + if (property == Property::HillshadeShadowColorTransition) { setHillshadeShadowColorTransition(*transition); return nullopt; } - - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; +} + +StyleProperty HillshadeLayer::getProperty(const std::string& name) const { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end()) { + return {}; + } + + switch (static_cast<Property>(it->second)) { + case Property::HillshadeAccentColor: + return makeStyleProperty(getHillshadeAccentColor()); + case Property::HillshadeExaggeration: + return makeStyleProperty(getHillshadeExaggeration()); + case Property::HillshadeHighlightColor: + return makeStyleProperty(getHillshadeHighlightColor()); + case Property::HillshadeIlluminationAnchor: + return makeStyleProperty(getHillshadeIlluminationAnchor()); + case Property::HillshadeIlluminationDirection: + return makeStyleProperty(getHillshadeIlluminationDirection()); + case Property::HillshadeShadowColor: + return makeStyleProperty(getHillshadeShadowColor()); + case Property::HillshadeAccentColorTransition: + return makeStyleProperty(getHillshadeAccentColorTransition()); + case Property::HillshadeExaggerationTransition: + return makeStyleProperty(getHillshadeExaggerationTransition()); + case Property::HillshadeHighlightColorTransition: + return makeStyleProperty(getHillshadeHighlightColorTransition()); + case Property::HillshadeIlluminationAnchorTransition: + return makeStyleProperty(getHillshadeIlluminationAnchorTransition()); + case Property::HillshadeIlluminationDirectionTransition: + return makeStyleProperty(getHillshadeIlluminationDirectionTransition()); + case Property::HillshadeShadowColorTransition: + return makeStyleProperty(getHillshadeShadowColorTransition()); + } + return {}; } optional<Error> HillshadeLayer::setLayoutProperty(const std::string& name, const Convertible& value) { @@ -378,5 +419,3 @@ Mutable<Layer::Impl> HillshadeLayer::mutableBaseImpl() const { } // namespace style } // namespace mbgl - -// clang-format on diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs index 0cd9a82d75..775288264f 100644 --- a/src/mbgl/style/layers/layer.cpp.ejs +++ b/src/mbgl/style/layers/layer.cpp.ejs @@ -3,8 +3,6 @@ const layoutProperties = locals.layoutProperties; const paintProperties = locals.paintProperties; -%> -// clang-format off - // This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer.hpp> @@ -190,24 +188,42 @@ TransitionOptions <%- camelize(type) %>Layer::get<%- camelize(property.name) %>T using namespace conversion; -optional<Error> <%- camelize(type) %>Layer::setPaintProperty(const std::string& name, const Convertible& value) { - enum class Property { +namespace { + +enum class Property : uint8_t { <% for (const property of paintProperties) { -%> - <%- camelize(property.name) %>, + <%- camelize(property.name) %>, <% } -%> <% for (const property of paintProperties) { -%> - <%- camelize(property.name) %>Transition, + <%- camelize(property.name) %>Transition, +<% } -%> +<% for (const property of layoutProperties) { -%> + <%- camelize(property.name) %>, <% } -%> - }; +}; - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({ - <%- paintProperties.map(p => `{ "${p.name}", mbgl::underlying_type(Property::${camelize(p.name)}) }`).join(',\n ') %>, - <%- paintProperties.map(p => `{ "${p.name}-transition", mbgl::underlying_type(Property::${camelize(p.name)}Transition) }`).join(',\n ') %> - }); +template <typename T> +constexpr uint8_t toUint8(T t) noexcept { + return uint8_t(mbgl::underlying_type(t)); +} - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { - return Error { "layer doesn't support this property" }; +MAPBOX_ETERNAL_CONSTEXPR const auto layerProperties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>( + {<%- paintProperties.map(p => `{"${p.name}", toUint8(Property::${camelize(p.name)})}`).join(',\n ') %>, +<% if (!layoutProperties.length) { -%> + <%- paintProperties.map(p => `{"${p.name}-transition", toUint8(Property::${camelize(p.name)}Transition)}`).join(',\n ') %>}); +<% } else { -%> + <%- paintProperties.map(p => `{"${p.name}-transition", toUint8(Property::${camelize(p.name)}Transition)}`).join(',\n ') %>, + <%- layoutProperties.map(p => `{"${p.name}", toUint8(Property::${camelize(p.name)})}`).join(',\n ') %>}); +<% } -%> + +<% const lastPaintProperty = paintProperties[paintProperties.length - 1]; -%> +<%-`constexpr uint8_t lastPaintPropertyIndex = toUint8(Property::${camelize(lastPaintProperty.name)}Transition);` %> +} // namespace + +optional<Error> <%- camelize(type) %>Layer::setPaintProperty(const std::string& name, const Convertible& value) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second > lastPaintPropertyIndex) { + return Error{"layer doesn't support this property"}; } auto property = static_cast<Property>(it->second); @@ -248,14 +264,36 @@ optional<Error> <%- camelize(type) %>Layer::setPaintProperty(const std::string& if (!transition) { return error; } - <% for (const property of paintProperties) { %> +<% for (const property of paintProperties) { %> if (property == Property::<%- camelize(property.name) %>Transition) { set<%- camelize(property.name) %>Transition(*transition); return nullopt; } - <% } %> +<% } %> + return Error{"layer doesn't support this property"}; +} - return Error { "layer doesn't support this property" }; +StyleProperty <%- camelize(type) %>Layer::getProperty(const std::string& name) const { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end()) { + return {}; + } + + switch (static_cast<Property>(it->second)) { +<% for (const property of paintProperties) { -%> + case Property::<%- camelize(property.name) %>: + return makeStyleProperty(get<%- camelize(property.name) %>()); +<% } -%> +<% for (const property of paintProperties) { -%> + case Property::<%- camelize(property.name) %>Transition: + return makeStyleProperty(get<%- camelize(property.name) %>Transition()); +<% } -%> +<% for (const property of layoutProperties) { -%> + case Property::<%- camelize(property.name) %>: + return makeStyleProperty(get<%- camelize(property.name) %>()); +<% } -%> + } + return {}; } optional<Error> <%- camelize(type) %>Layer::setLayoutProperty(const std::string& name, const Convertible& value) { @@ -263,17 +301,8 @@ optional<Error> <%- camelize(type) %>Layer::setLayoutProperty(const std::string& return Layer::setVisibility(value); } <% if (layoutProperties.length) { -%> - enum class Property { -<% for (const property of layoutProperties) { -%> - <%- camelize(property.name) %>, -<% } -%> - }; - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({ - <%- layoutProperties.map(p => `{ "${p.name}", mbgl::underlying_type(Property::${camelize(p.name)}) }`).join(',\n ') %> - }); - - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second <= lastPaintPropertyIndex) { return Error { "layer doesn't support this property" }; } @@ -319,5 +348,3 @@ Mutable<Layer::Impl> <%- camelize(type) %>Layer::mutableBaseImpl() const { } // namespace style } // namespace mbgl - -// clang-format on diff --git a/src/mbgl/style/layers/line_layer.cpp b/src/mbgl/style/layers/line_layer.cpp index bd29f7f6fd..309a81ae2b 100644 --- a/src/mbgl/style/layers/line_layer.cpp +++ b/src/mbgl/style/layers/line_layer.cpp @@ -1,5 +1,3 @@ -// clang-format off - // This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include <mbgl/style/layers/line_layer.hpp> @@ -430,60 +428,77 @@ TransitionOptions LineLayer::getLineWidthTransition() const { using namespace conversion; +namespace { + +enum class Property : uint8_t { + LineBlur, + LineColor, + LineDasharray, + LineGapWidth, + LineGradient, + LineOffset, + LineOpacity, + LinePattern, + LineTranslate, + LineTranslateAnchor, + LineWidth, + LineBlurTransition, + LineColorTransition, + LineDasharrayTransition, + LineGapWidthTransition, + LineGradientTransition, + LineOffsetTransition, + LineOpacityTransition, + LinePatternTransition, + LineTranslateTransition, + LineTranslateAnchorTransition, + LineWidthTransition, + LineCap, + LineJoin, + LineMiterLimit, + LineRoundLimit, +}; + +template <typename T> +constexpr uint8_t toUint8(T t) noexcept { + return uint8_t(mbgl::underlying_type(t)); +} + +MAPBOX_ETERNAL_CONSTEXPR const auto layerProperties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>( + {{"line-blur", toUint8(Property::LineBlur)}, + {"line-color", toUint8(Property::LineColor)}, + {"line-dasharray", toUint8(Property::LineDasharray)}, + {"line-gap-width", toUint8(Property::LineGapWidth)}, + {"line-gradient", toUint8(Property::LineGradient)}, + {"line-offset", toUint8(Property::LineOffset)}, + {"line-opacity", toUint8(Property::LineOpacity)}, + {"line-pattern", toUint8(Property::LinePattern)}, + {"line-translate", toUint8(Property::LineTranslate)}, + {"line-translate-anchor", toUint8(Property::LineTranslateAnchor)}, + {"line-width", toUint8(Property::LineWidth)}, + {"line-blur-transition", toUint8(Property::LineBlurTransition)}, + {"line-color-transition", toUint8(Property::LineColorTransition)}, + {"line-dasharray-transition", toUint8(Property::LineDasharrayTransition)}, + {"line-gap-width-transition", toUint8(Property::LineGapWidthTransition)}, + {"line-gradient-transition", toUint8(Property::LineGradientTransition)}, + {"line-offset-transition", toUint8(Property::LineOffsetTransition)}, + {"line-opacity-transition", toUint8(Property::LineOpacityTransition)}, + {"line-pattern-transition", toUint8(Property::LinePatternTransition)}, + {"line-translate-transition", toUint8(Property::LineTranslateTransition)}, + {"line-translate-anchor-transition", toUint8(Property::LineTranslateAnchorTransition)}, + {"line-width-transition", toUint8(Property::LineWidthTransition)}, + {"line-cap", toUint8(Property::LineCap)}, + {"line-join", toUint8(Property::LineJoin)}, + {"line-miter-limit", toUint8(Property::LineMiterLimit)}, + {"line-round-limit", toUint8(Property::LineRoundLimit)}}); + +constexpr uint8_t lastPaintPropertyIndex = toUint8(Property::LineWidthTransition); +} // namespace + optional<Error> LineLayer::setPaintProperty(const std::string& name, const Convertible& value) { - enum class Property { - LineBlur, - LineColor, - LineDasharray, - LineGapWidth, - LineGradient, - LineOffset, - LineOpacity, - LinePattern, - LineTranslate, - LineTranslateAnchor, - LineWidth, - LineBlurTransition, - LineColorTransition, - LineDasharrayTransition, - LineGapWidthTransition, - LineGradientTransition, - LineOffsetTransition, - LineOpacityTransition, - LinePatternTransition, - LineTranslateTransition, - LineTranslateAnchorTransition, - LineWidthTransition, - }; - - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({ - { "line-blur", mbgl::underlying_type(Property::LineBlur) }, - { "line-color", mbgl::underlying_type(Property::LineColor) }, - { "line-dasharray", mbgl::underlying_type(Property::LineDasharray) }, - { "line-gap-width", mbgl::underlying_type(Property::LineGapWidth) }, - { "line-gradient", mbgl::underlying_type(Property::LineGradient) }, - { "line-offset", mbgl::underlying_type(Property::LineOffset) }, - { "line-opacity", mbgl::underlying_type(Property::LineOpacity) }, - { "line-pattern", mbgl::underlying_type(Property::LinePattern) }, - { "line-translate", mbgl::underlying_type(Property::LineTranslate) }, - { "line-translate-anchor", mbgl::underlying_type(Property::LineTranslateAnchor) }, - { "line-width", mbgl::underlying_type(Property::LineWidth) }, - { "line-blur-transition", mbgl::underlying_type(Property::LineBlurTransition) }, - { "line-color-transition", mbgl::underlying_type(Property::LineColorTransition) }, - { "line-dasharray-transition", mbgl::underlying_type(Property::LineDasharrayTransition) }, - { "line-gap-width-transition", mbgl::underlying_type(Property::LineGapWidthTransition) }, - { "line-gradient-transition", mbgl::underlying_type(Property::LineGradientTransition) }, - { "line-offset-transition", mbgl::underlying_type(Property::LineOffsetTransition) }, - { "line-opacity-transition", mbgl::underlying_type(Property::LineOpacityTransition) }, - { "line-pattern-transition", mbgl::underlying_type(Property::LinePatternTransition) }, - { "line-translate-transition", mbgl::underlying_type(Property::LineTranslateTransition) }, - { "line-translate-anchor-transition", mbgl::underlying_type(Property::LineTranslateAnchorTransition) }, - { "line-width-transition", mbgl::underlying_type(Property::LineWidthTransition) } - }); - - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { - return Error { "layer doesn't support this property" }; + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second > lastPaintPropertyIndex) { + return Error{"layer doesn't support this property"}; } auto property = static_cast<Property>(it->second); @@ -601,85 +616,134 @@ optional<Error> LineLayer::setPaintProperty(const std::string& name, const Conve if (!transition) { return error; } - + if (property == Property::LineBlurTransition) { setLineBlurTransition(*transition); return nullopt; } - + if (property == Property::LineColorTransition) { setLineColorTransition(*transition); return nullopt; } - + if (property == Property::LineDasharrayTransition) { setLineDasharrayTransition(*transition); return nullopt; } - + if (property == Property::LineGapWidthTransition) { setLineGapWidthTransition(*transition); return nullopt; } - + if (property == Property::LineGradientTransition) { setLineGradientTransition(*transition); return nullopt; } - + if (property == Property::LineOffsetTransition) { setLineOffsetTransition(*transition); return nullopt; } - + if (property == Property::LineOpacityTransition) { setLineOpacityTransition(*transition); return nullopt; } - + if (property == Property::LinePatternTransition) { setLinePatternTransition(*transition); return nullopt; } - + if (property == Property::LineTranslateTransition) { setLineTranslateTransition(*transition); return nullopt; } - + if (property == Property::LineTranslateAnchorTransition) { setLineTranslateAnchorTransition(*transition); return nullopt; } - + if (property == Property::LineWidthTransition) { setLineWidthTransition(*transition); return nullopt; } - - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; +} + +StyleProperty LineLayer::getProperty(const std::string& name) const { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end()) { + return {}; + } + + switch (static_cast<Property>(it->second)) { + case Property::LineBlur: + return makeStyleProperty(getLineBlur()); + case Property::LineColor: + return makeStyleProperty(getLineColor()); + case Property::LineDasharray: + return makeStyleProperty(getLineDasharray()); + case Property::LineGapWidth: + return makeStyleProperty(getLineGapWidth()); + case Property::LineGradient: + return makeStyleProperty(getLineGradient()); + case Property::LineOffset: + return makeStyleProperty(getLineOffset()); + case Property::LineOpacity: + return makeStyleProperty(getLineOpacity()); + case Property::LinePattern: + return makeStyleProperty(getLinePattern()); + case Property::LineTranslate: + return makeStyleProperty(getLineTranslate()); + case Property::LineTranslateAnchor: + return makeStyleProperty(getLineTranslateAnchor()); + case Property::LineWidth: + return makeStyleProperty(getLineWidth()); + case Property::LineBlurTransition: + return makeStyleProperty(getLineBlurTransition()); + case Property::LineColorTransition: + return makeStyleProperty(getLineColorTransition()); + case Property::LineDasharrayTransition: + return makeStyleProperty(getLineDasharrayTransition()); + case Property::LineGapWidthTransition: + return makeStyleProperty(getLineGapWidthTransition()); + case Property::LineGradientTransition: + return makeStyleProperty(getLineGradientTransition()); + case Property::LineOffsetTransition: + return makeStyleProperty(getLineOffsetTransition()); + case Property::LineOpacityTransition: + return makeStyleProperty(getLineOpacityTransition()); + case Property::LinePatternTransition: + return makeStyleProperty(getLinePatternTransition()); + case Property::LineTranslateTransition: + return makeStyleProperty(getLineTranslateTransition()); + case Property::LineTranslateAnchorTransition: + return makeStyleProperty(getLineTranslateAnchorTransition()); + case Property::LineWidthTransition: + return makeStyleProperty(getLineWidthTransition()); + case Property::LineCap: + return makeStyleProperty(getLineCap()); + case Property::LineJoin: + return makeStyleProperty(getLineJoin()); + case Property::LineMiterLimit: + return makeStyleProperty(getLineMiterLimit()); + case Property::LineRoundLimit: + return makeStyleProperty(getLineRoundLimit()); + } + return {}; } optional<Error> LineLayer::setLayoutProperty(const std::string& name, const Convertible& value) { if (name == "visibility") { return Layer::setVisibility(value); } - enum class Property { - LineCap, - LineJoin, - LineMiterLimit, - LineRoundLimit, - }; - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({ - { "line-cap", mbgl::underlying_type(Property::LineCap) }, - { "line-join", mbgl::underlying_type(Property::LineJoin) }, - { "line-miter-limit", mbgl::underlying_type(Property::LineMiterLimit) }, - { "line-round-limit", mbgl::underlying_type(Property::LineRoundLimit) } - }); - - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second <= lastPaintPropertyIndex) { return Error { "layer doesn't support this property" }; } @@ -739,5 +803,3 @@ Mutable<Layer::Impl> LineLayer::mutableBaseImpl() const { } // namespace style } // namespace mbgl - -// clang-format on diff --git a/src/mbgl/style/layers/raster_layer.cpp b/src/mbgl/style/layers/raster_layer.cpp index fde1df838d..359e502f3e 100644 --- a/src/mbgl/style/layers/raster_layer.cpp +++ b/src/mbgl/style/layers/raster_layer.cpp @@ -1,5 +1,3 @@ -// clang-format off - // This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include <mbgl/style/layers/raster_layer.hpp> @@ -283,48 +281,57 @@ TransitionOptions RasterLayer::getRasterSaturationTransition() const { using namespace conversion; +namespace { + +enum class Property : uint8_t { + RasterBrightnessMax, + RasterBrightnessMin, + RasterContrast, + RasterFadeDuration, + RasterHueRotate, + RasterOpacity, + RasterResampling, + RasterSaturation, + RasterBrightnessMaxTransition, + RasterBrightnessMinTransition, + RasterContrastTransition, + RasterFadeDurationTransition, + RasterHueRotateTransition, + RasterOpacityTransition, + RasterResamplingTransition, + RasterSaturationTransition, +}; + +template <typename T> +constexpr uint8_t toUint8(T t) noexcept { + return uint8_t(mbgl::underlying_type(t)); +} + +MAPBOX_ETERNAL_CONSTEXPR const auto layerProperties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>( + {{"raster-brightness-max", toUint8(Property::RasterBrightnessMax)}, + {"raster-brightness-min", toUint8(Property::RasterBrightnessMin)}, + {"raster-contrast", toUint8(Property::RasterContrast)}, + {"raster-fade-duration", toUint8(Property::RasterFadeDuration)}, + {"raster-hue-rotate", toUint8(Property::RasterHueRotate)}, + {"raster-opacity", toUint8(Property::RasterOpacity)}, + {"raster-resampling", toUint8(Property::RasterResampling)}, + {"raster-saturation", toUint8(Property::RasterSaturation)}, + {"raster-brightness-max-transition", toUint8(Property::RasterBrightnessMaxTransition)}, + {"raster-brightness-min-transition", toUint8(Property::RasterBrightnessMinTransition)}, + {"raster-contrast-transition", toUint8(Property::RasterContrastTransition)}, + {"raster-fade-duration-transition", toUint8(Property::RasterFadeDurationTransition)}, + {"raster-hue-rotate-transition", toUint8(Property::RasterHueRotateTransition)}, + {"raster-opacity-transition", toUint8(Property::RasterOpacityTransition)}, + {"raster-resampling-transition", toUint8(Property::RasterResamplingTransition)}, + {"raster-saturation-transition", toUint8(Property::RasterSaturationTransition)}}); + +constexpr uint8_t lastPaintPropertyIndex = toUint8(Property::RasterSaturationTransition); +} // namespace + optional<Error> RasterLayer::setPaintProperty(const std::string& name, const Convertible& value) { - enum class Property { - RasterBrightnessMax, - RasterBrightnessMin, - RasterContrast, - RasterFadeDuration, - RasterHueRotate, - RasterOpacity, - RasterResampling, - RasterSaturation, - RasterBrightnessMaxTransition, - RasterBrightnessMinTransition, - RasterContrastTransition, - RasterFadeDurationTransition, - RasterHueRotateTransition, - RasterOpacityTransition, - RasterResamplingTransition, - RasterSaturationTransition, - }; - - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({ - { "raster-brightness-max", mbgl::underlying_type(Property::RasterBrightnessMax) }, - { "raster-brightness-min", mbgl::underlying_type(Property::RasterBrightnessMin) }, - { "raster-contrast", mbgl::underlying_type(Property::RasterContrast) }, - { "raster-fade-duration", mbgl::underlying_type(Property::RasterFadeDuration) }, - { "raster-hue-rotate", mbgl::underlying_type(Property::RasterHueRotate) }, - { "raster-opacity", mbgl::underlying_type(Property::RasterOpacity) }, - { "raster-resampling", mbgl::underlying_type(Property::RasterResampling) }, - { "raster-saturation", mbgl::underlying_type(Property::RasterSaturation) }, - { "raster-brightness-max-transition", mbgl::underlying_type(Property::RasterBrightnessMaxTransition) }, - { "raster-brightness-min-transition", mbgl::underlying_type(Property::RasterBrightnessMinTransition) }, - { "raster-contrast-transition", mbgl::underlying_type(Property::RasterContrastTransition) }, - { "raster-fade-duration-transition", mbgl::underlying_type(Property::RasterFadeDurationTransition) }, - { "raster-hue-rotate-transition", mbgl::underlying_type(Property::RasterHueRotateTransition) }, - { "raster-opacity-transition", mbgl::underlying_type(Property::RasterOpacityTransition) }, - { "raster-resampling-transition", mbgl::underlying_type(Property::RasterResamplingTransition) }, - { "raster-saturation-transition", mbgl::underlying_type(Property::RasterSaturationTransition) } - }); - - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { - return Error { "layer doesn't support this property" }; + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second > lastPaintPropertyIndex) { + return Error{"layer doesn't support this property"}; } auto property = static_cast<Property>(it->second); @@ -392,49 +399,91 @@ optional<Error> RasterLayer::setPaintProperty(const std::string& name, const Con if (!transition) { return error; } - + if (property == Property::RasterBrightnessMaxTransition) { setRasterBrightnessMaxTransition(*transition); return nullopt; } - + if (property == Property::RasterBrightnessMinTransition) { setRasterBrightnessMinTransition(*transition); return nullopt; } - + if (property == Property::RasterContrastTransition) { setRasterContrastTransition(*transition); return nullopt; } - + if (property == Property::RasterFadeDurationTransition) { setRasterFadeDurationTransition(*transition); return nullopt; } - + if (property == Property::RasterHueRotateTransition) { setRasterHueRotateTransition(*transition); return nullopt; } - + if (property == Property::RasterOpacityTransition) { setRasterOpacityTransition(*transition); return nullopt; } - + if (property == Property::RasterResamplingTransition) { setRasterResamplingTransition(*transition); return nullopt; } - + if (property == Property::RasterSaturationTransition) { setRasterSaturationTransition(*transition); return nullopt; } - - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; +} + +StyleProperty RasterLayer::getProperty(const std::string& name) const { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end()) { + return {}; + } + + switch (static_cast<Property>(it->second)) { + case Property::RasterBrightnessMax: + return makeStyleProperty(getRasterBrightnessMax()); + case Property::RasterBrightnessMin: + return makeStyleProperty(getRasterBrightnessMin()); + case Property::RasterContrast: + return makeStyleProperty(getRasterContrast()); + case Property::RasterFadeDuration: + return makeStyleProperty(getRasterFadeDuration()); + case Property::RasterHueRotate: + return makeStyleProperty(getRasterHueRotate()); + case Property::RasterOpacity: + return makeStyleProperty(getRasterOpacity()); + case Property::RasterResampling: + return makeStyleProperty(getRasterResampling()); + case Property::RasterSaturation: + return makeStyleProperty(getRasterSaturation()); + case Property::RasterBrightnessMaxTransition: + return makeStyleProperty(getRasterBrightnessMaxTransition()); + case Property::RasterBrightnessMinTransition: + return makeStyleProperty(getRasterBrightnessMinTransition()); + case Property::RasterContrastTransition: + return makeStyleProperty(getRasterContrastTransition()); + case Property::RasterFadeDurationTransition: + return makeStyleProperty(getRasterFadeDurationTransition()); + case Property::RasterHueRotateTransition: + return makeStyleProperty(getRasterHueRotateTransition()); + case Property::RasterOpacityTransition: + return makeStyleProperty(getRasterOpacityTransition()); + case Property::RasterResamplingTransition: + return makeStyleProperty(getRasterResamplingTransition()); + case Property::RasterSaturationTransition: + return makeStyleProperty(getRasterSaturationTransition()); + } + return {}; } optional<Error> RasterLayer::setLayoutProperty(const std::string& name, const Convertible& value) { @@ -451,5 +500,3 @@ Mutable<Layer::Impl> RasterLayer::mutableBaseImpl() const { } // namespace style } // namespace mbgl - -// clang-format on diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp index af5daa4dc0..b3ee0f698c 100644 --- a/src/mbgl/style/layers/symbol_layer.cpp +++ b/src/mbgl/style/layers/symbol_layer.cpp @@ -1,5 +1,3 @@ -// clang-format off - // This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include <mbgl/style/layers/symbol_layer.hpp> @@ -1102,72 +1100,163 @@ TransitionOptions SymbolLayer::getTextTranslateAnchorTransition() const { using namespace conversion; +namespace { + +enum class Property : uint8_t { + IconColor, + IconHaloBlur, + IconHaloColor, + IconHaloWidth, + IconOpacity, + IconTranslate, + IconTranslateAnchor, + TextColor, + TextHaloBlur, + TextHaloColor, + TextHaloWidth, + TextOpacity, + TextTranslate, + TextTranslateAnchor, + IconColorTransition, + IconHaloBlurTransition, + IconHaloColorTransition, + IconHaloWidthTransition, + IconOpacityTransition, + IconTranslateTransition, + IconTranslateAnchorTransition, + TextColorTransition, + TextHaloBlurTransition, + TextHaloColorTransition, + TextHaloWidthTransition, + TextOpacityTransition, + TextTranslateTransition, + TextTranslateAnchorTransition, + IconAllowOverlap, + IconAnchor, + IconIgnorePlacement, + IconImage, + IconKeepUpright, + IconOffset, + IconOptional, + IconPadding, + IconPitchAlignment, + IconRotate, + IconRotationAlignment, + IconSize, + IconTextFit, + IconTextFitPadding, + SymbolAvoidEdges, + SymbolPlacement, + SymbolSortKey, + SymbolSpacing, + SymbolZOrder, + TextAllowOverlap, + TextAnchor, + TextField, + TextFont, + TextIgnorePlacement, + TextJustify, + TextKeepUpright, + TextLetterSpacing, + TextLineHeight, + TextMaxAngle, + TextMaxWidth, + TextOffset, + TextOptional, + TextPadding, + TextPitchAlignment, + TextRadialOffset, + TextRotate, + TextRotationAlignment, + TextSize, + TextTransform, + TextVariableAnchor, + TextWritingMode, +}; + +template <typename T> +constexpr uint8_t toUint8(T t) noexcept { + return uint8_t(mbgl::underlying_type(t)); +} + +MAPBOX_ETERNAL_CONSTEXPR const auto layerProperties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>( + {{"icon-color", toUint8(Property::IconColor)}, + {"icon-halo-blur", toUint8(Property::IconHaloBlur)}, + {"icon-halo-color", toUint8(Property::IconHaloColor)}, + {"icon-halo-width", toUint8(Property::IconHaloWidth)}, + {"icon-opacity", toUint8(Property::IconOpacity)}, + {"icon-translate", toUint8(Property::IconTranslate)}, + {"icon-translate-anchor", toUint8(Property::IconTranslateAnchor)}, + {"text-color", toUint8(Property::TextColor)}, + {"text-halo-blur", toUint8(Property::TextHaloBlur)}, + {"text-halo-color", toUint8(Property::TextHaloColor)}, + {"text-halo-width", toUint8(Property::TextHaloWidth)}, + {"text-opacity", toUint8(Property::TextOpacity)}, + {"text-translate", toUint8(Property::TextTranslate)}, + {"text-translate-anchor", toUint8(Property::TextTranslateAnchor)}, + {"icon-color-transition", toUint8(Property::IconColorTransition)}, + {"icon-halo-blur-transition", toUint8(Property::IconHaloBlurTransition)}, + {"icon-halo-color-transition", toUint8(Property::IconHaloColorTransition)}, + {"icon-halo-width-transition", toUint8(Property::IconHaloWidthTransition)}, + {"icon-opacity-transition", toUint8(Property::IconOpacityTransition)}, + {"icon-translate-transition", toUint8(Property::IconTranslateTransition)}, + {"icon-translate-anchor-transition", toUint8(Property::IconTranslateAnchorTransition)}, + {"text-color-transition", toUint8(Property::TextColorTransition)}, + {"text-halo-blur-transition", toUint8(Property::TextHaloBlurTransition)}, + {"text-halo-color-transition", toUint8(Property::TextHaloColorTransition)}, + {"text-halo-width-transition", toUint8(Property::TextHaloWidthTransition)}, + {"text-opacity-transition", toUint8(Property::TextOpacityTransition)}, + {"text-translate-transition", toUint8(Property::TextTranslateTransition)}, + {"text-translate-anchor-transition", toUint8(Property::TextTranslateAnchorTransition)}, + {"icon-allow-overlap", toUint8(Property::IconAllowOverlap)}, + {"icon-anchor", toUint8(Property::IconAnchor)}, + {"icon-ignore-placement", toUint8(Property::IconIgnorePlacement)}, + {"icon-image", toUint8(Property::IconImage)}, + {"icon-keep-upright", toUint8(Property::IconKeepUpright)}, + {"icon-offset", toUint8(Property::IconOffset)}, + {"icon-optional", toUint8(Property::IconOptional)}, + {"icon-padding", toUint8(Property::IconPadding)}, + {"icon-pitch-alignment", toUint8(Property::IconPitchAlignment)}, + {"icon-rotate", toUint8(Property::IconRotate)}, + {"icon-rotation-alignment", toUint8(Property::IconRotationAlignment)}, + {"icon-size", toUint8(Property::IconSize)}, + {"icon-text-fit", toUint8(Property::IconTextFit)}, + {"icon-text-fit-padding", toUint8(Property::IconTextFitPadding)}, + {"symbol-avoid-edges", toUint8(Property::SymbolAvoidEdges)}, + {"symbol-placement", toUint8(Property::SymbolPlacement)}, + {"symbol-sort-key", toUint8(Property::SymbolSortKey)}, + {"symbol-spacing", toUint8(Property::SymbolSpacing)}, + {"symbol-z-order", toUint8(Property::SymbolZOrder)}, + {"text-allow-overlap", toUint8(Property::TextAllowOverlap)}, + {"text-anchor", toUint8(Property::TextAnchor)}, + {"text-field", toUint8(Property::TextField)}, + {"text-font", toUint8(Property::TextFont)}, + {"text-ignore-placement", toUint8(Property::TextIgnorePlacement)}, + {"text-justify", toUint8(Property::TextJustify)}, + {"text-keep-upright", toUint8(Property::TextKeepUpright)}, + {"text-letter-spacing", toUint8(Property::TextLetterSpacing)}, + {"text-line-height", toUint8(Property::TextLineHeight)}, + {"text-max-angle", toUint8(Property::TextMaxAngle)}, + {"text-max-width", toUint8(Property::TextMaxWidth)}, + {"text-offset", toUint8(Property::TextOffset)}, + {"text-optional", toUint8(Property::TextOptional)}, + {"text-padding", toUint8(Property::TextPadding)}, + {"text-pitch-alignment", toUint8(Property::TextPitchAlignment)}, + {"text-radial-offset", toUint8(Property::TextRadialOffset)}, + {"text-rotate", toUint8(Property::TextRotate)}, + {"text-rotation-alignment", toUint8(Property::TextRotationAlignment)}, + {"text-size", toUint8(Property::TextSize)}, + {"text-transform", toUint8(Property::TextTransform)}, + {"text-variable-anchor", toUint8(Property::TextVariableAnchor)}, + {"text-writing-mode", toUint8(Property::TextWritingMode)}}); + +constexpr uint8_t lastPaintPropertyIndex = toUint8(Property::TextTranslateAnchorTransition); +} // namespace + optional<Error> SymbolLayer::setPaintProperty(const std::string& name, const Convertible& value) { - enum class Property { - IconColor, - IconHaloBlur, - IconHaloColor, - IconHaloWidth, - IconOpacity, - IconTranslate, - IconTranslateAnchor, - TextColor, - TextHaloBlur, - TextHaloColor, - TextHaloWidth, - TextOpacity, - TextTranslate, - TextTranslateAnchor, - IconColorTransition, - IconHaloBlurTransition, - IconHaloColorTransition, - IconHaloWidthTransition, - IconOpacityTransition, - IconTranslateTransition, - IconTranslateAnchorTransition, - TextColorTransition, - TextHaloBlurTransition, - TextHaloColorTransition, - TextHaloWidthTransition, - TextOpacityTransition, - TextTranslateTransition, - TextTranslateAnchorTransition, - }; - - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({ - { "icon-color", mbgl::underlying_type(Property::IconColor) }, - { "icon-halo-blur", mbgl::underlying_type(Property::IconHaloBlur) }, - { "icon-halo-color", mbgl::underlying_type(Property::IconHaloColor) }, - { "icon-halo-width", mbgl::underlying_type(Property::IconHaloWidth) }, - { "icon-opacity", mbgl::underlying_type(Property::IconOpacity) }, - { "icon-translate", mbgl::underlying_type(Property::IconTranslate) }, - { "icon-translate-anchor", mbgl::underlying_type(Property::IconTranslateAnchor) }, - { "text-color", mbgl::underlying_type(Property::TextColor) }, - { "text-halo-blur", mbgl::underlying_type(Property::TextHaloBlur) }, - { "text-halo-color", mbgl::underlying_type(Property::TextHaloColor) }, - { "text-halo-width", mbgl::underlying_type(Property::TextHaloWidth) }, - { "text-opacity", mbgl::underlying_type(Property::TextOpacity) }, - { "text-translate", mbgl::underlying_type(Property::TextTranslate) }, - { "text-translate-anchor", mbgl::underlying_type(Property::TextTranslateAnchor) }, - { "icon-color-transition", mbgl::underlying_type(Property::IconColorTransition) }, - { "icon-halo-blur-transition", mbgl::underlying_type(Property::IconHaloBlurTransition) }, - { "icon-halo-color-transition", mbgl::underlying_type(Property::IconHaloColorTransition) }, - { "icon-halo-width-transition", mbgl::underlying_type(Property::IconHaloWidthTransition) }, - { "icon-opacity-transition", mbgl::underlying_type(Property::IconOpacityTransition) }, - { "icon-translate-transition", mbgl::underlying_type(Property::IconTranslateTransition) }, - { "icon-translate-anchor-transition", mbgl::underlying_type(Property::IconTranslateAnchorTransition) }, - { "text-color-transition", mbgl::underlying_type(Property::TextColorTransition) }, - { "text-halo-blur-transition", mbgl::underlying_type(Property::TextHaloBlurTransition) }, - { "text-halo-color-transition", mbgl::underlying_type(Property::TextHaloColorTransition) }, - { "text-halo-width-transition", mbgl::underlying_type(Property::TextHaloWidthTransition) }, - { "text-opacity-transition", mbgl::underlying_type(Property::TextOpacityTransition) }, - { "text-translate-transition", mbgl::underlying_type(Property::TextTranslateTransition) }, - { "text-translate-anchor-transition", mbgl::underlying_type(Property::TextTranslateAnchorTransition) } - }); - - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { - return Error { "layer doesn't support this property" }; + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second > lastPaintPropertyIndex) { + return Error{"layer doesn't support this property"}; } auto property = static_cast<Property>(it->second); @@ -1285,174 +1374,235 @@ optional<Error> SymbolLayer::setPaintProperty(const std::string& name, const Con if (!transition) { return error; } - + if (property == Property::IconColorTransition) { setIconColorTransition(*transition); return nullopt; } - + if (property == Property::IconHaloBlurTransition) { setIconHaloBlurTransition(*transition); return nullopt; } - + if (property == Property::IconHaloColorTransition) { setIconHaloColorTransition(*transition); return nullopt; } - + if (property == Property::IconHaloWidthTransition) { setIconHaloWidthTransition(*transition); return nullopt; } - + if (property == Property::IconOpacityTransition) { setIconOpacityTransition(*transition); return nullopt; } - + if (property == Property::IconTranslateTransition) { setIconTranslateTransition(*transition); return nullopt; } - + if (property == Property::IconTranslateAnchorTransition) { setIconTranslateAnchorTransition(*transition); return nullopt; } - + if (property == Property::TextColorTransition) { setTextColorTransition(*transition); return nullopt; } - + if (property == Property::TextHaloBlurTransition) { setTextHaloBlurTransition(*transition); return nullopt; } - + if (property == Property::TextHaloColorTransition) { setTextHaloColorTransition(*transition); return nullopt; } - + if (property == Property::TextHaloWidthTransition) { setTextHaloWidthTransition(*transition); return nullopt; } - + if (property == Property::TextOpacityTransition) { setTextOpacityTransition(*transition); return nullopt; } - + if (property == Property::TextTranslateTransition) { setTextTranslateTransition(*transition); return nullopt; } - + if (property == Property::TextTranslateAnchorTransition) { setTextTranslateAnchorTransition(*transition); return nullopt; } - - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; +} + +StyleProperty SymbolLayer::getProperty(const std::string& name) const { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end()) { + return {}; + } + + switch (static_cast<Property>(it->second)) { + case Property::IconColor: + return makeStyleProperty(getIconColor()); + case Property::IconHaloBlur: + return makeStyleProperty(getIconHaloBlur()); + case Property::IconHaloColor: + return makeStyleProperty(getIconHaloColor()); + case Property::IconHaloWidth: + return makeStyleProperty(getIconHaloWidth()); + case Property::IconOpacity: + return makeStyleProperty(getIconOpacity()); + case Property::IconTranslate: + return makeStyleProperty(getIconTranslate()); + case Property::IconTranslateAnchor: + return makeStyleProperty(getIconTranslateAnchor()); + case Property::TextColor: + return makeStyleProperty(getTextColor()); + case Property::TextHaloBlur: + return makeStyleProperty(getTextHaloBlur()); + case Property::TextHaloColor: + return makeStyleProperty(getTextHaloColor()); + case Property::TextHaloWidth: + return makeStyleProperty(getTextHaloWidth()); + case Property::TextOpacity: + return makeStyleProperty(getTextOpacity()); + case Property::TextTranslate: + return makeStyleProperty(getTextTranslate()); + case Property::TextTranslateAnchor: + return makeStyleProperty(getTextTranslateAnchor()); + case Property::IconColorTransition: + return makeStyleProperty(getIconColorTransition()); + case Property::IconHaloBlurTransition: + return makeStyleProperty(getIconHaloBlurTransition()); + case Property::IconHaloColorTransition: + return makeStyleProperty(getIconHaloColorTransition()); + case Property::IconHaloWidthTransition: + return makeStyleProperty(getIconHaloWidthTransition()); + case Property::IconOpacityTransition: + return makeStyleProperty(getIconOpacityTransition()); + case Property::IconTranslateTransition: + return makeStyleProperty(getIconTranslateTransition()); + case Property::IconTranslateAnchorTransition: + return makeStyleProperty(getIconTranslateAnchorTransition()); + case Property::TextColorTransition: + return makeStyleProperty(getTextColorTransition()); + case Property::TextHaloBlurTransition: + return makeStyleProperty(getTextHaloBlurTransition()); + case Property::TextHaloColorTransition: + return makeStyleProperty(getTextHaloColorTransition()); + case Property::TextHaloWidthTransition: + return makeStyleProperty(getTextHaloWidthTransition()); + case Property::TextOpacityTransition: + return makeStyleProperty(getTextOpacityTransition()); + case Property::TextTranslateTransition: + return makeStyleProperty(getTextTranslateTransition()); + case Property::TextTranslateAnchorTransition: + return makeStyleProperty(getTextTranslateAnchorTransition()); + case Property::IconAllowOverlap: + return makeStyleProperty(getIconAllowOverlap()); + case Property::IconAnchor: + return makeStyleProperty(getIconAnchor()); + case Property::IconIgnorePlacement: + return makeStyleProperty(getIconIgnorePlacement()); + case Property::IconImage: + return makeStyleProperty(getIconImage()); + case Property::IconKeepUpright: + return makeStyleProperty(getIconKeepUpright()); + case Property::IconOffset: + return makeStyleProperty(getIconOffset()); + case Property::IconOptional: + return makeStyleProperty(getIconOptional()); + case Property::IconPadding: + return makeStyleProperty(getIconPadding()); + case Property::IconPitchAlignment: + return makeStyleProperty(getIconPitchAlignment()); + case Property::IconRotate: + return makeStyleProperty(getIconRotate()); + case Property::IconRotationAlignment: + return makeStyleProperty(getIconRotationAlignment()); + case Property::IconSize: + return makeStyleProperty(getIconSize()); + case Property::IconTextFit: + return makeStyleProperty(getIconTextFit()); + case Property::IconTextFitPadding: + return makeStyleProperty(getIconTextFitPadding()); + case Property::SymbolAvoidEdges: + return makeStyleProperty(getSymbolAvoidEdges()); + case Property::SymbolPlacement: + return makeStyleProperty(getSymbolPlacement()); + case Property::SymbolSortKey: + return makeStyleProperty(getSymbolSortKey()); + case Property::SymbolSpacing: + return makeStyleProperty(getSymbolSpacing()); + case Property::SymbolZOrder: + return makeStyleProperty(getSymbolZOrder()); + case Property::TextAllowOverlap: + return makeStyleProperty(getTextAllowOverlap()); + case Property::TextAnchor: + return makeStyleProperty(getTextAnchor()); + case Property::TextField: + return makeStyleProperty(getTextField()); + case Property::TextFont: + return makeStyleProperty(getTextFont()); + case Property::TextIgnorePlacement: + return makeStyleProperty(getTextIgnorePlacement()); + case Property::TextJustify: + return makeStyleProperty(getTextJustify()); + case Property::TextKeepUpright: + return makeStyleProperty(getTextKeepUpright()); + case Property::TextLetterSpacing: + return makeStyleProperty(getTextLetterSpacing()); + case Property::TextLineHeight: + return makeStyleProperty(getTextLineHeight()); + case Property::TextMaxAngle: + return makeStyleProperty(getTextMaxAngle()); + case Property::TextMaxWidth: + return makeStyleProperty(getTextMaxWidth()); + case Property::TextOffset: + return makeStyleProperty(getTextOffset()); + case Property::TextOptional: + return makeStyleProperty(getTextOptional()); + case Property::TextPadding: + return makeStyleProperty(getTextPadding()); + case Property::TextPitchAlignment: + return makeStyleProperty(getTextPitchAlignment()); + case Property::TextRadialOffset: + return makeStyleProperty(getTextRadialOffset()); + case Property::TextRotate: + return makeStyleProperty(getTextRotate()); + case Property::TextRotationAlignment: + return makeStyleProperty(getTextRotationAlignment()); + case Property::TextSize: + return makeStyleProperty(getTextSize()); + case Property::TextTransform: + return makeStyleProperty(getTextTransform()); + case Property::TextVariableAnchor: + return makeStyleProperty(getTextVariableAnchor()); + case Property::TextWritingMode: + return makeStyleProperty(getTextWritingMode()); + } + return {}; } optional<Error> SymbolLayer::setLayoutProperty(const std::string& name, const Convertible& value) { if (name == "visibility") { return Layer::setVisibility(value); } - enum class Property { - IconAllowOverlap, - IconAnchor, - IconIgnorePlacement, - IconImage, - IconKeepUpright, - IconOffset, - IconOptional, - IconPadding, - IconPitchAlignment, - IconRotate, - IconRotationAlignment, - IconSize, - IconTextFit, - IconTextFitPadding, - SymbolAvoidEdges, - SymbolPlacement, - SymbolSortKey, - SymbolSpacing, - SymbolZOrder, - TextAllowOverlap, - TextAnchor, - TextField, - TextFont, - TextIgnorePlacement, - TextJustify, - TextKeepUpright, - TextLetterSpacing, - TextLineHeight, - TextMaxAngle, - TextMaxWidth, - TextOffset, - TextOptional, - TextPadding, - TextPitchAlignment, - TextRadialOffset, - TextRotate, - TextRotationAlignment, - TextSize, - TextTransform, - TextVariableAnchor, - TextWritingMode, - }; - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({ - { "icon-allow-overlap", mbgl::underlying_type(Property::IconAllowOverlap) }, - { "icon-anchor", mbgl::underlying_type(Property::IconAnchor) }, - { "icon-ignore-placement", mbgl::underlying_type(Property::IconIgnorePlacement) }, - { "icon-image", mbgl::underlying_type(Property::IconImage) }, - { "icon-keep-upright", mbgl::underlying_type(Property::IconKeepUpright) }, - { "icon-offset", mbgl::underlying_type(Property::IconOffset) }, - { "icon-optional", mbgl::underlying_type(Property::IconOptional) }, - { "icon-padding", mbgl::underlying_type(Property::IconPadding) }, - { "icon-pitch-alignment", mbgl::underlying_type(Property::IconPitchAlignment) }, - { "icon-rotate", mbgl::underlying_type(Property::IconRotate) }, - { "icon-rotation-alignment", mbgl::underlying_type(Property::IconRotationAlignment) }, - { "icon-size", mbgl::underlying_type(Property::IconSize) }, - { "icon-text-fit", mbgl::underlying_type(Property::IconTextFit) }, - { "icon-text-fit-padding", mbgl::underlying_type(Property::IconTextFitPadding) }, - { "symbol-avoid-edges", mbgl::underlying_type(Property::SymbolAvoidEdges) }, - { "symbol-placement", mbgl::underlying_type(Property::SymbolPlacement) }, - { "symbol-sort-key", mbgl::underlying_type(Property::SymbolSortKey) }, - { "symbol-spacing", mbgl::underlying_type(Property::SymbolSpacing) }, - { "symbol-z-order", mbgl::underlying_type(Property::SymbolZOrder) }, - { "text-allow-overlap", mbgl::underlying_type(Property::TextAllowOverlap) }, - { "text-anchor", mbgl::underlying_type(Property::TextAnchor) }, - { "text-field", mbgl::underlying_type(Property::TextField) }, - { "text-font", mbgl::underlying_type(Property::TextFont) }, - { "text-ignore-placement", mbgl::underlying_type(Property::TextIgnorePlacement) }, - { "text-justify", mbgl::underlying_type(Property::TextJustify) }, - { "text-keep-upright", mbgl::underlying_type(Property::TextKeepUpright) }, - { "text-letter-spacing", mbgl::underlying_type(Property::TextLetterSpacing) }, - { "text-line-height", mbgl::underlying_type(Property::TextLineHeight) }, - { "text-max-angle", mbgl::underlying_type(Property::TextMaxAngle) }, - { "text-max-width", mbgl::underlying_type(Property::TextMaxWidth) }, - { "text-offset", mbgl::underlying_type(Property::TextOffset) }, - { "text-optional", mbgl::underlying_type(Property::TextOptional) }, - { "text-padding", mbgl::underlying_type(Property::TextPadding) }, - { "text-pitch-alignment", mbgl::underlying_type(Property::TextPitchAlignment) }, - { "text-radial-offset", mbgl::underlying_type(Property::TextRadialOffset) }, - { "text-rotate", mbgl::underlying_type(Property::TextRotate) }, - { "text-rotation-alignment", mbgl::underlying_type(Property::TextRotationAlignment) }, - { "text-size", mbgl::underlying_type(Property::TextSize) }, - { "text-transform", mbgl::underlying_type(Property::TextTransform) }, - { "text-variable-anchor", mbgl::underlying_type(Property::TextVariableAnchor) }, - { "text-writing-mode", mbgl::underlying_type(Property::TextWritingMode) } - }); - - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second <= lastPaintPropertyIndex) { return Error { "layer doesn't support this property" }; } @@ -1805,5 +1955,3 @@ Mutable<Layer::Impl> SymbolLayer::mutableBaseImpl() const { } // namespace style } // namespace mbgl - -// clang-format on diff --git a/src/mbgl/style/light.cpp b/src/mbgl/style/light.cpp index be56a0d93b..a10e693073 100644 --- a/src/mbgl/style/light.cpp +++ b/src/mbgl/style/light.cpp @@ -1,5 +1,3 @@ -// clang-format off - // This file is generated. Do not edit. #include <mbgl/style/light.hpp> @@ -36,29 +34,37 @@ Mutable<Light::Impl> Light::mutableImpl() const { using namespace conversion; -optional<Error> Light::setProperty(const std::string& name, const Convertible& value) { - enum class Property { - Anchor, - Color, - Intensity, - Position, - AnchorTransition, - ColorTransition, - IntensityTransition, - PositionTransition, - }; - - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({ - { "anchor", mbgl::underlying_type(Property::Anchor) }, - { "color", mbgl::underlying_type(Property::Color) }, - { "intensity", mbgl::underlying_type(Property::Intensity) }, - { "position", mbgl::underlying_type(Property::Position) }, - { "anchor-transition", mbgl::underlying_type(Property::AnchorTransition) }, - { "color-transition", mbgl::underlying_type(Property::ColorTransition) }, - { "intensity-transition", mbgl::underlying_type(Property::IntensityTransition) }, - { "position-transition", mbgl::underlying_type(Property::PositionTransition) } - }); +namespace { + +enum class Property : uint8_t { + Anchor, + Color, + Intensity, + Position, + AnchorTransition, + ColorTransition, + IntensityTransition, + PositionTransition, +}; + +template <typename T> +constexpr uint8_t toUint8(T t) noexcept { + return uint8_t(mbgl::underlying_type(t)); +} + +MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>( + {{"anchor", toUint8(Property::Anchor)}, + {"color", toUint8(Property::Color)}, + {"intensity", toUint8(Property::Intensity)}, + {"position", toUint8(Property::Position)}, + {"anchor-transition", toUint8(Property::AnchorTransition)}, + {"color-transition", toUint8(Property::ColorTransition)}, + {"intensity-transition", toUint8(Property::IntensityTransition)}, + {"position-transition", toUint8(Property::PositionTransition)}}); +} // namespace + +optional<Error> Light::setProperty(const std::string& name, const Convertible& value) { const auto it = properties.find(name.c_str()); if (it == properties.end()) { return Error { "light doesn't support this property" }; @@ -146,6 +152,33 @@ optional<Error> Light::setProperty(const std::string& name, const Convertible& v return Error { "light doesn't support this property" }; } +StyleProperty Light::getProperty(const std::string& name) const { + const auto it = properties.find(name.c_str()); + if (it == properties.end()) { + return {}; + } + + switch (static_cast<Property>(it->second)) { + case Property::Anchor: + return makeStyleProperty(getAnchor()); + case Property::Color: + return makeStyleProperty(getColor()); + case Property::Intensity: + return makeStyleProperty(getIntensity()); + case Property::Position: + return makeStyleProperty(getPosition()); + case Property::AnchorTransition: + return makeStyleProperty(getAnchorTransition()); + case Property::ColorTransition: + return makeStyleProperty(getColorTransition()); + case Property::IntensityTransition: + return makeStyleProperty(getIntensityTransition()); + case Property::PositionTransition: + return makeStyleProperty(getPositionTransition()); + } + return {}; +} + LightAnchorType Light::getDefaultAnchor() { return LightAnchor::defaultValue(); } @@ -253,5 +286,3 @@ TransitionOptions Light::getPositionTransition() const { } // namespace style } // namespace mbgl - -// clang-format on diff --git a/src/mbgl/style/light.cpp.ejs b/src/mbgl/style/light.cpp.ejs index 55cc013827..68c1bf59e2 100644 --- a/src/mbgl/style/light.cpp.ejs +++ b/src/mbgl/style/light.cpp.ejs @@ -1,8 +1,6 @@ <% const properties = locals.properties; -%> -// clang-format off - // This file is generated. Do not edit. #include <mbgl/style/light.hpp> @@ -39,21 +37,29 @@ Mutable<Light::Impl> Light::mutableImpl() const { using namespace conversion; -optional<Error> Light::setProperty(const std::string& name, const Convertible& value) { - enum class Property { +namespace { + +enum class Property : uint8_t { <% for (const property of properties) { -%> - <%- camelize(property.name) %>, + <%- camelize(property.name) %>, <% } -%> <% for (const property of properties) { -%> - <%- camelize(property.name) %>Transition, + <%- camelize(property.name) %>Transition, <% } -%> - }; +}; + +template <typename T> +constexpr uint8_t toUint8(T t) noexcept { + return uint8_t(mbgl::underlying_type(t)); +} - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({ - <%- properties.map(p => `{ "${p.name}", mbgl::underlying_type(Property::${camelize(p.name)}) }`).join(',\n ') %>, - <%- properties.map(p => `{ "${p.name}-transition", mbgl::underlying_type(Property::${camelize(p.name)}Transition) }`).join(',\n ') %> - }); +MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>( + {<%- properties.map(p => `{"${p.name}", toUint8(Property::${camelize(p.name)})}`).join(',\n ') %>, + <%- properties.map(p => `{"${p.name}-transition", toUint8(Property::${camelize(p.name)}Transition)}`).join(',\n ') %>}); +} // namespace + +optional<Error> Light::setProperty(const std::string& name, const Convertible& value) { const auto it = properties.find(name.c_str()); if (it == properties.end()) { return Error { "light doesn't support this property" }; @@ -107,6 +113,25 @@ optional<Error> Light::setProperty(const std::string& name, const Convertible& v return Error { "light doesn't support this property" }; } +StyleProperty Light::getProperty(const std::string& name) const { + const auto it = properties.find(name.c_str()); + if (it == properties.end()) { + return {}; + } + + switch (static_cast<Property>(it->second)) { +<% for (const property of properties) { -%> + case Property::<%- camelize(property.name) %>: + return makeStyleProperty(get<%- camelize(property.name) %>()); +<% } -%> +<% for (const property of properties) { -%> + case Property::<%- camelize(property.name) %>Transition: + return makeStyleProperty(get<%- camelize(property.name) %>Transition()); +<% } -%> + } + return {}; +} + <% for (const property of properties) { -%> <%- evaluatedType(property) %> Light::getDefault<%- camelize(property.name) %>() { return Light<%- camelize(property.name) %>::defaultValue(); @@ -138,5 +163,3 @@ TransitionOptions Light::get<%- camelize(property.name) %>Transition() const { } // namespace style } // namespace mbgl - -// clang-format on diff --git a/src/mbgl/style/sources/geojson_source.cpp b/src/mbgl/style/sources/geojson_source.cpp index 5171c7c8d9..3832977cd4 100644 --- a/src/mbgl/style/sources/geojson_source.cpp +++ b/src/mbgl/style/sources/geojson_source.cpp @@ -32,8 +32,12 @@ void GeoJSONSource::setURL(const std::string& url_) { } void GeoJSONSource::setGeoJSON(const mapbox::geojson::geojson& geoJSON) { + setGeoJSONData(GeoJSONData::create(geoJSON, impl().getOptions())); +} + +void GeoJSONSource::setGeoJSONData(std::shared_ptr<GeoJSONData> geoJSONData) { req.reset(); - baseImpl = makeMutable<Impl>(impl(), geoJSON); + baseImpl = makeMutable<Impl>(impl(), std::move(geoJSONData)); observer->onSourceChanged(*this); } @@ -41,6 +45,10 @@ optional<std::string> GeoJSONSource::getURL() const { return url; } +const GeoJSONOptions& GeoJSONSource::getOptions() const { + return impl().getOptions(); +} + void GeoJSONSource::loadDescription(FileSource& fileSource) { if (!url) { loaded = true; @@ -62,17 +70,15 @@ void GeoJSONSource::loadDescription(FileSource& fileSource) { *this, std::make_exception_ptr(std::runtime_error("unexpectedly empty GeoJSON"))); } else { conversion::Error error; - optional<GeoJSON> geoJSON = conversion::convertJSON<GeoJSON>(*res.data, error); - if (!geoJSON) { + std::shared_ptr<GeoJSONData> geoJSONData; + if (optional<GeoJSON> geoJSON = conversion::convertJSON<GeoJSON>(*res.data, error)) { + geoJSONData = GeoJSONData::create(*geoJSON, impl().getOptions()); + } else { + // Create an empty GeoJSON VT object to make sure we're not infinitely waiting for tiles to load. Log::Error(Event::ParseStyle, "Failed to parse GeoJSON data: %s", error.message.c_str()); - // Create an empty GeoJSON VT object to make sure we're not infinitely waiting for - // tiles to load. - baseImpl = makeMutable<Impl>(impl(), GeoJSON{ FeatureCollection{} }); - } else { - baseImpl = makeMutable<Impl>(impl(), *geoJSON); } - + baseImpl = makeMutable<Impl>(impl(), std::move(geoJSONData)); loaded = true; observer->onSourceLoaded(*this); } diff --git a/src/mbgl/style/sources/geojson_source_impl.cpp b/src/mbgl/style/sources/geojson_source_impl.cpp index c3cb942709..468deb6134 100644 --- a/src/mbgl/style/sources/geojson_source_impl.cpp +++ b/src/mbgl/style/sources/geojson_source_impl.cpp @@ -82,13 +82,8 @@ T evaluateFeature(const mapbox::feature::feature<double>& f, return T(); } -GeoJSONSource::Impl::Impl(std::string id_, optional<GeoJSONOptions> options_) - : Source::Impl(SourceType::GeoJSON, std::move(id_)) { - options = options_ ? std::move(*options_) : GeoJSONOptions{}; -} - -GeoJSONSource::Impl::Impl(const Impl& other, const GeoJSON& geoJSON) - : Source::Impl(other), options(other.options) { +// static +std::shared_ptr<GeoJSONData> GeoJSONData::create(const GeoJSON& geoJSON, const GeoJSONOptions& options) { constexpr double scale = util::EXTENT / util::tileSize; if (options.cluster && geoJSON.is<mapbox::feature::feature_collection<double>>() && !geoJSON.get<mapbox::feature::feature_collection<double>>().empty()) { @@ -99,6 +94,7 @@ GeoJSONSource::Impl::Impl(const Impl& other, const GeoJSON& geoJSON) Feature feature; clusterOptions.map = [&](const PropertyMap& properties) -> PropertyMap { PropertyMap ret{}; + if (properties.empty()) return ret; for (const auto& p : options.clusterProperties) { feature.properties = properties; ret[p.first] = evaluateFeature<Value>(feature, p.second.first); @@ -115,19 +111,27 @@ GeoJSONSource::Impl::Impl(const Impl& other, const GeoJSON& geoJSON) toReturn[p.first] = evaluateFeature<Value>(feature, p.second.second, accumulated); } }; - data = std::make_shared<SuperclusterData>( - geoJSON.get<mapbox::feature::feature_collection<double>>(), clusterOptions); - } else { - mapbox::geojsonvt::Options vtOptions; - vtOptions.maxZoom = options.maxzoom; - vtOptions.extent = util::EXTENT; - vtOptions.buffer = ::round(scale * options.buffer); - vtOptions.tolerance = scale * options.tolerance; - vtOptions.lineMetrics = options.lineMetrics; - data = std::make_shared<GeoJSONVTData>(geoJSON, vtOptions); + return std::make_shared<SuperclusterData>(geoJSON.get<mapbox::feature::feature_collection<double>>(), + clusterOptions); } + + mapbox::geojsonvt::Options vtOptions; + vtOptions.maxZoom = options.maxzoom; + vtOptions.extent = util::EXTENT; + vtOptions.buffer = ::round(scale * options.buffer); + vtOptions.tolerance = scale * options.tolerance; + vtOptions.lineMetrics = options.lineMetrics; + return std::make_shared<GeoJSONVTData>(geoJSON, vtOptions); } +GeoJSONSource::Impl::Impl(std::string id_, optional<GeoJSONOptions> options_) + : Source::Impl(SourceType::GeoJSON, std::move(id_)) { + options = options_ ? std::move(*options_) : GeoJSONOptions{}; +} + +GeoJSONSource::Impl::Impl(const GeoJSONSource::Impl& other, std::shared_ptr<GeoJSONData> data_) + : Source::Impl(other), options(other.options), data(std::move(data_)) {} + GeoJSONSource::Impl::~Impl() = default; Range<uint8_t> GeoJSONSource::Impl::getZoomRange() const { diff --git a/src/mbgl/style/sources/geojson_source_impl.hpp b/src/mbgl/style/sources/geojson_source_impl.hpp index 26b9d95a39..da2673a38c 100644 --- a/src/mbgl/style/sources/geojson_source_impl.hpp +++ b/src/mbgl/style/sources/geojson_source_impl.hpp @@ -11,27 +11,15 @@ class CanonicalTileID; namespace style { -class GeoJSONData { -public: - virtual ~GeoJSONData() = default; - virtual mapbox::feature::feature_collection<int16_t> getTile(const CanonicalTileID&) = 0; - - // SuperclusterData - virtual mapbox::feature::feature_collection<double> getChildren(const std::uint32_t) = 0; - virtual mapbox::feature::feature_collection<double> getLeaves(const std::uint32_t, - const std::uint32_t limit = 10u, - const std::uint32_t offset = 0u) = 0; - virtual std::uint8_t getClusterExpansionZoom(std::uint32_t) = 0; -}; - class GeoJSONSource::Impl : public Source::Impl { public: Impl(std::string id, optional<GeoJSONOptions>); - Impl(const GeoJSONSource::Impl&, const GeoJSON&); + Impl(const GeoJSONSource::Impl&, std::shared_ptr<GeoJSONData>); ~Impl() final; Range<uint8_t> getZoomRange() const; std::weak_ptr<GeoJSONData> getData() const; + const GeoJSONOptions& getOptions() const { return options; } optional<std::string> getAttribution() const final; diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index 8b0a3975fc..ecc8f93032 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -164,12 +164,12 @@ void Placement::placeBucket( auto partiallyEvaluatedIconSize = bucket.iconSizeBinder->evaluateForZoom(state.getZoom()); optional<CollisionTileBoundaries> avoidEdges; - if (mapMode == MapMode::Tile && - (layout.get<style::SymbolAvoidEdges>() || - layout.get<style::SymbolPlacement>() == style::SymbolPlacementType::Line)) { + if (mapMode == MapMode::Tile && (layout.get<style::SymbolAvoidEdges>() || + layout.get<style::SymbolPlacement>() == style::SymbolPlacementType::Line || + !layout.get<style::TextVariableAnchor>().empty())) { avoidEdges = collisionIndex.projectTileBoundaries(posMatrix); } - + const bool textAllowOverlap = layout.get<style::TextAllowOverlap>(); const bool iconAllowOverlap = layout.get<style::IconAllowOverlap>(); // This logic is similar to the "defaultOpacityState" logic below in updateBucketOpacities @@ -220,7 +220,6 @@ void Placement::placeBucket( if (horizontalTextIndex) { const PlacedSymbol& placedSymbol = bucket.text.placedSymbols.at(*horizontalTextIndex); const float fontSize = evaluateSizeForFeature(partiallyEvaluatedTextSize, placedSymbol); - const CollisionFeature& textCollisionFeature = symbolInstance.textCollisionFeature; const auto updatePreviousOrientationIfNotPlaced = [&](bool isPlaced) { if (bucket.allowVerticalPlacement && !isPlaced && getPrevPlacement()) { @@ -282,7 +281,8 @@ void Placement::placeBucket( placeText = placed.first; offscreen &= placed.second; - } else if (!textCollisionFeature.alongLine && !textCollisionFeature.boxes.empty()) { + } else if (!symbolInstance.textCollisionFeature.alongLine && + !symbolInstance.textCollisionFeature.boxes.empty()) { // If this symbol was in the last placement, shift the previously used // anchor to the front of the anchor list, only if the previous anchor // is still in the anchor list. @@ -305,8 +305,13 @@ void Placement::placeBucket( } } - const auto placeFeatureForVariableAnchors = [&] (const CollisionFeature& collisionFeature, style::TextWritingModeType orientation) { - const CollisionBox& textBox = collisionFeature.boxes[0]; + const bool doVariableIconPlacement = + hasIconTextFit && !iconAllowOverlap && symbolInstance.placedIconIndex; + + const auto placeFeatureForVariableAnchors = [&](const CollisionFeature& textCollisionFeature, + style::TextWritingModeType orientation, + const CollisionFeature& iconCollisionFeature) { + const CollisionBox& textBox = textCollisionFeature.boxes[0]; const float width = textBox.x2 - textBox.x1; const float height = textBox.y2 - textBox.y1; const float textBoxScale = symbolInstance.textBoxScale; @@ -323,12 +328,40 @@ void Placement::placeBucket( } textBoxes.clear(); - placedFeature = collisionIndex.placeFeature(collisionFeature, shift, - posMatrix, mat4(), pixelRatio, - placedSymbol, scale, fontSize, + placedFeature = collisionIndex.placeFeature(textCollisionFeature, + shift, + posMatrix, + mat4(), + pixelRatio, + placedSymbol, + scale, + fontSize, allowOverlap, pitchWithMap, - params.showCollisionBoxes, avoidEdges, collisionGroup.second, textBoxes); + params.showCollisionBoxes, + avoidEdges, + collisionGroup.second, + textBoxes); + + if (doVariableIconPlacement) { + auto placedIconFeature = collisionIndex.placeFeature(iconCollisionFeature, + shift, + posMatrix, + iconLabelPlaneMatrix, + pixelRatio, + placedSymbol, + scale, + fontSize, + iconAllowOverlap, + pitchWithMap, + params.showCollisionBoxes, + avoidEdges, + collisionGroup.second, + iconBoxes); + iconBoxes.clear(); + if (!placedIconFeature.first) continue; + } + if (placedFeature.first) { assert(symbolInstance.crossTileID != 0u); optional<style::TextVariableAnchorType> prevAnchor; @@ -366,12 +399,18 @@ void Placement::placeBucket( }; const auto placeHorizontal = [&] { - return placeFeatureForVariableAnchors(symbolInstance.textCollisionFeature, style::TextWritingModeType::Horizontal); + return placeFeatureForVariableAnchors(symbolInstance.textCollisionFeature, + style::TextWritingModeType::Horizontal, + symbolInstance.iconCollisionFeature); }; const auto placeVertical = [&] { if (bucket.allowVerticalPlacement && !placed.first && symbolInstance.verticalTextCollisionFeature) { - return placeFeatureForVariableAnchors(*symbolInstance.verticalTextCollisionFeature, style::TextWritingModeType::Vertical); + return placeFeatureForVariableAnchors(*symbolInstance.verticalTextCollisionFeature, + style::TextWritingModeType::Vertical, + symbolInstance.verticalIconCollisionFeature + ? *symbolInstance.verticalIconCollisionFeature + : symbolInstance.iconCollisionFeature); } return std::pair<bool, bool>{false, false}; }; diff --git a/src/mbgl/text/quads.cpp b/src/mbgl/text/quads.cpp index 281c5d99de..a94bfee336 100644 --- a/src/mbgl/text/quads.cpp +++ b/src/mbgl/text/quads.cpp @@ -20,12 +20,28 @@ SymbolQuad getIconQuad(const PositionedIcon& shapedIcon, // If you have a 10px icon that isn't perfectly aligned to the pixel grid it will cover 11 actual // pixels. The quad needs to be padded to account for this, otherwise they'll look slightly clipped // on one edge in some cases. - const float border = 1.0; - - float top = shapedIcon.top() - border / image.pixelRatio; - float left = shapedIcon.left() - border / image.pixelRatio; - float bottom = shapedIcon.bottom() + border / image.pixelRatio; - float right = shapedIcon.right() + border / image.pixelRatio; + constexpr const float border = 1.0f; + + // Expand the box to respect the 1 pixel border in the atlas image. We're using `image.paddedRect - border` + // instead of image.displaySize because we only pad with one pixel for retina images as well, and the + // displaySize uses the logical dimensions, not the physical pixel dimensions. + // Unlike the JavaScript version, we're _not_ including the padding in the texture rect, so the + // logic "dimension * padded / non-padded - dimension" is swapped. + const float iconWidth = shapedIcon.right() - shapedIcon.left(); + const float expandX = (iconWidth * (static_cast<float>(image.textureRect.w) + 2.0f * border) / + static_cast<float>(image.textureRect.w) - + iconWidth) / + 2.0f; + const float left = shapedIcon.left() - expandX; + const float right = shapedIcon.right() + expandX; + + const float iconHeight = shapedIcon.bottom() - shapedIcon.top(); + const float expandY = (iconHeight * (static_cast<float>(image.textureRect.h) + 2.0f * border) / + static_cast<float>(image.textureRect.h) - + iconHeight) / + 2.0f; + const float top = shapedIcon.top() - expandY; + const float bottom = shapedIcon.bottom() + expandY; Point<float> tl{left, top}; Point<float> tr{right, top}; diff --git a/src/mbgl/text/shaping.cpp b/src/mbgl/text/shaping.cpp index d6d9a3d34e..8eb885af5d 100644 --- a/src/mbgl/text/shaping.cpp +++ b/src/mbgl/text/shaping.cpp @@ -32,7 +32,7 @@ AnchorAlignment AnchorAlignment::getAnchorAlignment(style::SymbolAnchorType anch result.horizontalAlign = 0.0f; break; default: - break; + break; } switch (anchor) { @@ -83,33 +83,41 @@ PositionedIcon PositionedIcon::shapeIcon(const ImagePosition& image, return PositionedIcon { image, top, bottom, left, right, iconRotation }; } -void PositionedIcon::fitIconToText(const style::SymbolLayoutProperties::Evaluated& layout, - const Shaping& shapedText, - float layoutTextSize) { - using namespace style; - assert(layout.get<IconTextFit>() != IconTextFitType::None); - if (shapedText) { - auto iconWidth = _right - _left; - auto iconHeight = _bottom - _top; - auto size = layoutTextSize / 24.0f; - auto textLeft = shapedText.left * size; - auto textRight = shapedText.right * size; - auto textTop = shapedText.top * size; - auto textBottom = shapedText.bottom * size; - auto textWidth = textRight - textLeft; - auto textHeight = textBottom - textTop; - auto padT = layout.get<IconTextFitPadding>()[0]; - auto padR = layout.get<IconTextFitPadding>()[1]; - auto padB = layout.get<IconTextFitPadding>()[2]; - auto padL = layout.get<IconTextFitPadding>()[3]; - auto offsetY = layout.get<IconTextFit>() == IconTextFitType::Width ? (textHeight - iconHeight) * 0.5 : 0; - auto offsetX = layout.get<IconTextFit>() == IconTextFitType::Height ? (textWidth - iconWidth) * 0.5 : 0; - auto width = layout.get<IconTextFit>() == IconTextFitType::Width || layout.get<IconTextFit>() == IconTextFitType::Both ? textWidth : iconWidth; - auto height = layout.get<IconTextFit>() == IconTextFitType::Height || layout.get<IconTextFit>() == IconTextFitType::Both ? textHeight : iconHeight; - _left = textLeft + offsetX - padL; - _top = textTop + offsetY - padT; - _right = textLeft + offsetX + padR + width; - _bottom = textTop + offsetY + padB + height; +void PositionedIcon::fitIconToText(const Shaping& shapedText, + const style::IconTextFitType textFit, + const std::array<float, 4>& padding, + const std::array<float, 2>& iconOffset, + const float fontScale) { + assert(textFit != style::IconTextFitType::None); + assert(shapedText); + + // We don't respect the icon-anchor, because icon-text-fit is set. Instead, + // the icon will be centered on the text, then stretched in the given + // dimensions. + + const float textLeft = shapedText.left * fontScale; + const float textRight = shapedText.right * fontScale; + + if (textFit == style::IconTextFitType::Width || textFit == style::IconTextFitType::Both) { + // Stretched horizontally to the text width + _left = iconOffset[0] + textLeft - padding[3]; + _right = iconOffset[0] + textRight + padding[1]; + } else { + // Centered on the text + _left = iconOffset[0] + (textLeft + textRight - image().displaySize()[0]) / 2.0f; + _right = _left + image().displaySize()[0]; + } + + const float textTop = shapedText.top * fontScale; + const float textBottom = shapedText.bottom * fontScale; + if (textFit == style::IconTextFitType::Height || textFit == style::IconTextFitType::Both) { + // Stretched vertically to the text height + _top = iconOffset[1] + textTop - padding[0]; + _bottom = iconOffset[1] + textBottom + padding[2]; + } else { + // Centered on the text + _top = iconOffset[1] + (textTop + textBottom - image().displaySize()[1]) / 2.0f; + _bottom = _top + image().displaySize()[1]; } } diff --git a/src/mbgl/text/shaping.hpp b/src/mbgl/text/shaping.hpp index 28730e9db9..6ed1b5cb0e 100644 --- a/src/mbgl/text/shaping.hpp +++ b/src/mbgl/text/shaping.hpp @@ -45,9 +45,11 @@ public: // Updates shaped icon's bounds based on shaped text's bounds and provided // layout properties. - void fitIconToText(const style::SymbolLayoutProperties::Evaluated& layout, - const Shaping& shapedText, - float layoutTextSize); + void fitIconToText(const Shaping& shapedText, + const style::IconTextFitType textFit, + const std::array<float, 4>& padding, + const std::array<float, 2>& iconOffset, + const float fontScale); const ImagePosition& image() const { return _image; } float top() const { return _top; } diff --git a/src/mbgl/util/color.cpp b/src/mbgl/util/color.cpp index 4c2814cf14..44f815e8b8 100644 --- a/src/mbgl/util/color.cpp +++ b/src/mbgl/util/color.cpp @@ -45,10 +45,7 @@ std::array<double, 4> Color::toArray() const { } mbgl::Value Color::toObject() const { - return std::unordered_map<std::string, mbgl::Value>{{"r", double(r)}, - {"g", double(g)}, - {"b", double(b)}, - {"a", double(a)}}; + return mapbox::base::ValueObject{{"r", double(r)}, {"g", double(g)}, {"b", double(b)}, {"a", double(a)}}; } } // namespace mbgl diff --git a/src/mbgl/util/thread_pool.cpp b/src/mbgl/util/thread_pool.cpp index e839d1b4be..040e996dd4 100644 --- a/src/mbgl/util/thread_pool.cpp +++ b/src/mbgl/util/thread_pool.cpp @@ -6,53 +6,44 @@ namespace mbgl { -ThreadPool::ThreadPool(std::size_t count) { - threads.reserve(count); +ThreadedSchedulerBase::~ThreadedSchedulerBase() = default; - for (std::size_t i = 0; i < count; ++i) { - threads.emplace_back([this, i]() { - platform::setCurrentThreadName(std::string{ "Worker " } + util::toString(i + 1)); - platform::attachThread(); - - while (true) { - std::unique_lock<std::mutex> lock(mutex); +void ThreadedSchedulerBase::terminate() { + { + std::lock_guard<std::mutex> lock(mutex); + terminated = true; + } + cv.notify_all(); +} - cv.wait(lock, [this] { - return !queue.empty() || terminate; - }); +std::thread ThreadedSchedulerBase::makeSchedulerThread(size_t index) { + return std::thread([this, index]() { + platform::setCurrentThreadName(std::string{"Worker "} + util::toString(index + 1)); + platform::attachThread(); - if (terminate) { - platform::detachThread(); - return; - } + while (true) { + std::unique_lock<std::mutex> lock(mutex); - auto mailbox = queue.front(); - queue.pop(); - lock.unlock(); + cv.wait(lock, [this] { return !queue.empty() || terminated; }); - Mailbox::maybeReceive(mailbox); + if (terminated) { + platform::detachThread(); + return; } - }); - } -} -ThreadPool::~ThreadPool() { - { - std::lock_guard<std::mutex> lock(mutex); - terminate = true; - } - - cv.notify_all(); - - for (auto& thread : threads) { - thread.join(); - } + auto function = std::move(queue.front()); + queue.pop(); + lock.unlock(); + if (function) function(); + } + }); } -void ThreadPool::schedule(std::weak_ptr<Mailbox> mailbox) { +void ThreadedSchedulerBase::schedule(std::function<void()> fn) { + assert(fn); { std::lock_guard<std::mutex> lock(mutex); - queue.push(mailbox); + queue.push(std::move(fn)); } cv.notify_one(); diff --git a/src/mbgl/util/thread_pool.hpp b/src/mbgl/util/thread_pool.hpp index 509fd06061..7642f9b4ca 100644 --- a/src/mbgl/util/thread_pool.hpp +++ b/src/mbgl/util/thread_pool.hpp @@ -3,6 +3,7 @@ #include <mbgl/actor/mailbox.hpp> #include <mbgl/actor/scheduler.hpp> +#include <array> #include <condition_variable> #include <mutex> #include <queue> @@ -10,19 +11,60 @@ namespace mbgl { -class ThreadPool final : public Scheduler { +class ThreadedSchedulerBase : public Scheduler { public: - explicit ThreadPool(std::size_t count); - ~ThreadPool() override; + void schedule(std::function<void()>) override; - void schedule(std::weak_ptr<Mailbox>) override; +protected: + ThreadedSchedulerBase() = default; + ~ThreadedSchedulerBase() override; -private: - std::vector<std::thread> threads; - std::queue<std::weak_ptr<Mailbox>> queue; + void terminate(); + std::thread makeSchedulerThread(size_t index); + + std::queue<std::function<void()>> queue; std::mutex mutex; std::condition_variable cv; - bool terminate{ false }; + bool terminated{false}; +}; + +/** + * @brief ThreadScheduler implements Scheduler interface using a lightweight event loop + * + * @tparam N number of threads + * + * Note: If N == 1 all scheduled tasks are guaranteed to execute consequently; + * otherwise, some of the scheduled tasks might be executed in parallel. + */ +template <std::size_t N> +class ThreadedScheduler : public ThreadedSchedulerBase { +public: + ThreadedScheduler() { + for (std::size_t i = 0u; i < N; ++i) { + threads[i] = makeSchedulerThread(i); + } + } + + ~ThreadedScheduler() override { + terminate(); + for (auto& thread : threads) { + thread.join(); + } + } + + mapbox::base::WeakPtr<Scheduler> makeWeakPtr() override { return weakFactory.makeWeakPtr(); } + +private: + std::array<std::thread, N> threads; + mapbox::base::WeakPtrFactory<Scheduler> weakFactory{this}; + static_assert(N > 0, "Thread count must be more than zero."); }; +using SequencedScheduler = ThreadedScheduler<1>; + +template <std::size_t extra> +using ParallelScheduler = ThreadedScheduler<1 + extra>; + +using ThreadPool = ParallelScheduler<3>; + } // namespace mbgl |