diff options
Diffstat (limited to 'src/mbgl')
86 files changed, 1531 insertions, 200 deletions
diff --git a/src/mbgl/annotation/render_annotation_source.cpp b/src/mbgl/annotation/render_annotation_source.cpp index 38ca5ccd0b..a237100d13 100644 --- a/src/mbgl/annotation/render_annotation_source.cpp +++ b/src/mbgl/annotation/render_annotation_source.cpp @@ -73,8 +73,8 @@ std::vector<Feature> RenderAnnotationSource::querySourceFeatures(const SourceQue return {}; } -void RenderAnnotationSource::onLowMemory() { - tilePyramid.onLowMemory(); +void RenderAnnotationSource::reduceMemoryUse() { + tilePyramid.reduceMemoryUse(); } void RenderAnnotationSource::dumpDebugLogs() const { diff --git a/src/mbgl/annotation/render_annotation_source.hpp b/src/mbgl/annotation/render_annotation_source.hpp index aa2578d4e3..e812ec2883 100644 --- a/src/mbgl/annotation/render_annotation_source.hpp +++ b/src/mbgl/annotation/render_annotation_source.hpp @@ -33,7 +33,7 @@ public: std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const final; - void onLowMemory() final; + void reduceMemoryUse() final; void dumpDebugLogs() const final; private: diff --git a/src/mbgl/geometry/dem_data.cpp b/src/mbgl/geometry/dem_data.cpp index 78134dadc1..7fa98950ea 100644 --- a/src/mbgl/geometry/dem_data.cpp +++ b/src/mbgl/geometry/dem_data.cpp @@ -3,7 +3,7 @@ namespace mbgl { -DEMData::DEMData(const PremultipliedImage& _image): +DEMData::DEMData(const PremultipliedImage& _image, Tileset::DEMEncoding encoding): dim(_image.size.height), border(std::max<int32_t>(std::ceil(_image.size.height / 2), 1)), stride(dim + 2 * border), @@ -13,13 +13,25 @@ DEMData::DEMData(const PremultipliedImage& _image): throw std::runtime_error("raster-dem tiles must be square."); } + auto decodeMapbox = [] (const uint8_t r, const uint8_t g, const uint8_t b){ + // https://www.mapbox.com/help/access-elevation-data/#mapbox-terrain-rgb + return (r * 256 * 256 + g * 256 + b)/10 - 10000; + }; + + auto decodeTerrarium = [] (const uint8_t r, const uint8_t g, const uint8_t b){ + // https://aws.amazon.com/public-datasets/terrain/ + return ((r * 256 + g + b / 256) - 32768); + }; + + auto decodeRGB = encoding == Tileset::DEMEncoding::Terrarium ? decodeTerrarium : decodeMapbox; + std::memset(image.data.get(), 0, image.bytes()); for (int32_t y = 0; y < dim; y++) { for (int32_t x = 0; x < dim; x++) { const int32_t i = y * dim + x; const int32_t j = i * 4; - set(x, y, (_image.data[j] * 256 * 256 + _image.data[j+1] * 256 + _image.data[j+2])/10 - 10000); + set(x, y, decodeRGB(_image.data[j], _image.data[j+1], _image.data[j+2])); } } diff --git a/src/mbgl/geometry/dem_data.hpp b/src/mbgl/geometry/dem_data.hpp index 507a51661d..817d3cc9c9 100644 --- a/src/mbgl/geometry/dem_data.hpp +++ b/src/mbgl/geometry/dem_data.hpp @@ -2,6 +2,7 @@ #include <mbgl/math/clamp.hpp> #include <mbgl/util/image.hpp> +#include <mbgl/util/tileset.hpp> #include <memory> #include <array> @@ -12,7 +13,7 @@ namespace mbgl { class DEMData { public: - DEMData(const PremultipliedImage& image); + DEMData(const PremultipliedImage& image, Tileset::DEMEncoding encoding); void backfillBorder(const DEMData& borderTileData, int8_t dx, int8_t dy); void set(const int32_t x, const int32_t y, const int32_t value) { diff --git a/src/mbgl/gl/color_mode.hpp b/src/mbgl/gl/color_mode.hpp index c6594a3a77..e394f43501 100644 --- a/src/mbgl/gl/color_mode.hpp +++ b/src/mbgl/gl/color_mode.hpp @@ -85,6 +85,10 @@ public: static ColorMode alphaBlended() { return ColorMode { Add { One, OneMinusSrcAlpha }, {}, { true, true, true, true } }; } + + static ColorMode additive() { + return ColorMode { Add { One, One }, {}, { true, true, true, true } }; + } }; constexpr bool operator!=(const ColorMode::Mask& a, const ColorMode::Mask& b) { diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index 7444ac112c..ba44adb42b 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -60,6 +60,16 @@ static_assert(std::is_same<std::underlying_type_t<TextureFormat>, GLenum>::value static_assert(underlying_type(TextureFormat::RGBA) == GL_RGBA, "OpenGL type mismatch"); static_assert(underlying_type(TextureFormat::Alpha) == GL_ALPHA, "OpenGL type mismatch"); +static_assert(std::is_same<std::underlying_type_t<TextureType>, GLenum>::value, "OpenGL type mismatch"); +static_assert(underlying_type(TextureType::UnsignedByte) == GL_UNSIGNED_BYTE, "OpenGL type mismatch"); + +#if MBGL_USE_GLES2 && GL_HALF_FLOAT_OES +static_assert(underlying_type(TextureType::HalfFloat) == GL_HALF_FLOAT_OES, "OpenGL type mismatch"); +#endif +#if !MBGL_USE_GLES2 && GL_HALF_FLOAT_ARB +static_assert(underlying_type(TextureType::HalfFloat) == GL_HALF_FLOAT_ARB, "OpenGL type mismatch"); +#endif + static_assert(underlying_type(UniformDataType::Float) == GL_FLOAT, "OpenGL type mismatch"); static_assert(underlying_type(UniformDataType::FloatVec2) == GL_FLOAT_VEC2, "OpenGL type mismatch"); static_assert(underlying_type(UniformDataType::FloatVec3) == GL_FLOAT_VEC3, "OpenGL type mismatch"); @@ -116,6 +126,19 @@ void Context::initializeExtensions(const std::function<gl::ProcAddress(const cha programBinary = std::make_unique<extension::ProgramBinary>(fn); #endif +#if MBGL_USE_GLES2 + constexpr const char* halfFloatExtensionName = "OES_texture_half_float"; + constexpr const char* halfFloatColorBufferExtensionName = "EXT_color_buffer_half_float"; +#else + constexpr const char* halfFloatExtensionName = "ARB_half_float_pixel"; + constexpr const char* halfFloatColorBufferExtensionName = "ARB_color_buffer_float"; +#endif + if (strstr(extensions, halfFloatExtensionName) != nullptr && + strstr(extensions, halfFloatColorBufferExtensionName) != nullptr) { + + supportsHalfFloatTextures = true; + } + if (!supportsVertexArrays()) { Log::Warning(Event::OpenGL, "Not using Vertex Array Objects"); } @@ -258,9 +281,17 @@ UniqueTexture Context::createTexture() { bool Context::supportsVertexArrays() const { static bool blacklisted = []() { - // Blacklist Adreno 3xx as it crashes on glBuffer(Sub)Data const std::string renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER)); - return renderer.find("Adreno (TM) 3") != std::string::npos; + + Log::Info(Event::General, "GPU Identifier: %s", renderer.c_str()); + + // Blacklist Adreno 2xx, 3xx as it crashes on glBuffer(Sub)Data + // Blacklist ARM Mali-T720 (in some MT8163 chipsets) as it crashes on glBindVertexArray + return renderer.find("Adreno (TM) 2") != std::string::npos + || renderer.find("Adreno (TM) 3") != std::string::npos + || renderer.find("Mali-T720") != std::string::npos + || renderer.find("Sapphire 650") != std::string::npos; + }(); return !blacklisted && @@ -490,10 +521,10 @@ Context::createFramebuffer(const Texture& color, } UniqueTexture -Context::createTexture(const Size size, const void* data, TextureFormat format, TextureUnit unit) { +Context::createTexture(const Size size, const void* data, TextureFormat format, TextureUnit unit, TextureType type) { auto obj = createTexture(); pixelStoreUnpack = { 1 }; - updateTexture(obj, size, data, format, unit); + updateTexture(obj, size, data, format, unit, type); // We are using clamp to edge here since OpenGL ES doesn't allow GL_REPEAT on NPOT textures. // We use those when the pixelRatio isn't a power of two, e.g. on iPhone 6 Plus. MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); @@ -504,11 +535,11 @@ Context::createTexture(const Size size, const void* data, TextureFormat format, } void Context::updateTexture( - TextureID id, const Size size, const void* data, TextureFormat format, TextureUnit unit) { + TextureID id, const Size size, const void* data, TextureFormat format, TextureUnit unit, TextureType type) { activeTextureUnit = unit; texture[unit] = id; MBGL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, static_cast<GLenum>(format), size.width, - size.height, 0, static_cast<GLenum>(format), GL_UNSIGNED_BYTE, + size.height, 0, static_cast<GLenum>(format), static_cast<GLenum>(type), data)); } diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index 14f078367f..67624288e2 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -125,23 +125,29 @@ public: // Create a texture from an image with data. template <typename Image> - Texture createTexture(const Image& image, TextureUnit unit = 0) { + Texture createTexture(const Image& image, + TextureUnit unit = 0, + TextureType type = TextureType::UnsignedByte) { auto format = image.channels == 4 ? TextureFormat::RGBA : TextureFormat::Alpha; - return { image.size, createTexture(image.size, image.data.get(), format, unit) }; + return { image.size, createTexture(image.size, image.data.get(), format, unit, type) }; } template <typename Image> - void updateTexture(Texture& obj, const Image& image, TextureUnit unit = 0) { + void updateTexture(Texture& obj, + const Image& image, + TextureUnit unit = 0, + TextureType type = TextureType::UnsignedByte) { auto format = image.channels == 4 ? TextureFormat::RGBA : TextureFormat::Alpha; - updateTexture(obj.texture.get(), image.size, image.data.get(), format, unit); + updateTexture(obj.texture.get(), image.size, image.data.get(), format, unit, type); obj.size = image.size; } // Creates an empty texture with the specified dimensions. Texture createTexture(const Size size, TextureFormat format = TextureFormat::RGBA, - TextureUnit unit = 0) { - return { size, createTexture(size, nullptr, format, unit) }; + TextureUnit unit = 0, + TextureType type = TextureType::UnsignedByte) { + return { size, createTexture(size, nullptr, format, unit, type) }; } void bindTexture(Texture&, @@ -232,6 +238,8 @@ public: State<value::PixelTransferStencil> pixelTransferStencil; #endif // MBGL_USE_GLES2 + bool supportsHalfFloatTextures = false; + private: State<value::StencilFunc> stencilFunc; State<value::StencilMask> stencilMask; @@ -259,8 +267,8 @@ private: void updateVertexBuffer(UniqueBuffer& buffer, const void* data, std::size_t size); UniqueBuffer createIndexBuffer(const void* data, std::size_t size, const BufferUsage usage); void updateIndexBuffer(UniqueBuffer& buffer, const void* data, std::size_t size); - UniqueTexture createTexture(Size size, const void* data, TextureFormat, TextureUnit); - void updateTexture(TextureID, Size size, const void* data, TextureFormat, TextureUnit); + UniqueTexture createTexture(Size size, const void* data, TextureFormat, TextureUnit, TextureType); + void updateTexture(TextureID, Size size, const void* data, TextureFormat, TextureUnit, TextureType); UniqueFramebuffer createFramebuffer(); UniqueRenderbuffer createRenderbuffer(RenderbufferType, Size size); std::unique_ptr<uint8_t[]> readFramebuffer(Size, TextureFormat, bool flip); diff --git a/src/mbgl/gl/types.hpp b/src/mbgl/gl/types.hpp index da08195e58..376a784a0c 100644 --- a/src/mbgl/gl/types.hpp +++ b/src/mbgl/gl/types.hpp @@ -64,6 +64,15 @@ enum class TextureFormat : uint32_t { #endif // MBGL_USE_GLES2 }; +enum class TextureType : uint32_t { + UnsignedByte = 0x1401, +#if MBGL_USE_GLES2 + HalfFloat = 0x8D61, +#else + HalfFloat = 0x140B, +#endif // MBGL_USE_GLES2 +}; + enum class PrimitiveType { Points = 0x0000, Lines = 0x0001, diff --git a/src/mbgl/layout/symbol_projection.cpp b/src/mbgl/layout/symbol_projection.cpp index ee6385c93c..9e077e2532 100644 --- a/src/mbgl/layout/symbol_projection.cpp +++ b/src/mbgl/layout/symbol_projection.cpp @@ -318,7 +318,7 @@ namespace mbgl { placedGlyphs.push_back(*placedGlyph); } placedGlyphs.push_back(firstAndLastGlyph->second); - } else { + } else if (symbol.glyphOffsets.size() == 1) { // Only a single glyph to place // So, determine whether to flip based on projected angle of the line segment it's on if (keepUpright && !flip) { @@ -337,7 +337,6 @@ namespace mbgl { return *orientationChange; } } - assert(symbol.glyphOffsets.size() == 1); // We are relying on SymbolInstance.hasText filtering out symbols without any glyphs at all const float glyphOffsetX = symbol.glyphOffsets.front(); optional<PlacedGlyph> singleGlyph = placeGlyphAlongLine(fontScale * glyphOffsetX, lineOffsetX, lineOffsetY, flip, projectedAnchorPoint, symbol.anchorPoint, symbol.segment, symbol.line, symbol.tileDistances, labelPlaneMatrix, false); @@ -347,6 +346,8 @@ namespace mbgl { placedGlyphs.push_back(*singleGlyph); } + // The number of placedGlyphs must equal the number of glyphOffsets, which must correspond to the number of glyph vertices + // There may be 0 glyphs here, if a label consists entirely of glyphs that have 0x0 dimensions for (auto& placedGlyph : placedGlyphs) { addDynamicAttributes(placedGlyph.point, placedGlyph.angle, dynamicVertexArray); } diff --git a/src/mbgl/programs/attributes.hpp b/src/mbgl/programs/attributes.hpp index 5d7a6474cf..c677c84d5d 100644 --- a/src/mbgl/programs/attributes.hpp +++ b/src/mbgl/programs/attributes.hpp @@ -30,7 +30,7 @@ MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_anchor_pos); MBGL_DEFINE_ATTRIBUTE(uint16_t, 2, a_texture_pos); MBGL_DEFINE_ATTRIBUTE(int16_t, 4, a_normal_ed); MBGL_DEFINE_ATTRIBUTE(uint8_t, 1, a_fade_opacity); -MBGL_DEFINE_ATTRIBUTE(uint8_t, 2, a_placed); +MBGL_DEFINE_ATTRIBUTE(uint8_t, 2, a_placed); template <typename T, std::size_t N> struct a_data { @@ -142,6 +142,11 @@ struct a_halo_blur { using Type = gl::Attribute<float, 1>; }; +struct a_weight { + static auto name() { return "a_weight"; } + using Type = gl::Attribute<float, 1>; +}; + } // namespace attributes struct PositionOnlyLayoutAttributes : gl::Attributes< diff --git a/src/mbgl/programs/collision_box_program.hpp b/src/mbgl/programs/collision_box_program.hpp index 8d712a3df3..6e75adf36e 100644 --- a/src/mbgl/programs/collision_box_program.hpp +++ b/src/mbgl/programs/collision_box_program.hpp @@ -110,6 +110,7 @@ class CollisionCircleProgram : public Program< gl::Uniforms< uniforms::u_matrix, uniforms::u_extrude_scale, + uniforms::u_overscale_factor, uniforms::u_camera_to_center_distance>, style::Properties<>> { diff --git a/src/mbgl/programs/heatmap_program.cpp b/src/mbgl/programs/heatmap_program.cpp new file mode 100644 index 0000000000..67f84fbd52 --- /dev/null +++ b/src/mbgl/programs/heatmap_program.cpp @@ -0,0 +1,7 @@ +#include <mbgl/programs/heatmap_program.hpp> + +namespace mbgl { + +static_assert(sizeof(HeatmapLayoutVertex) == 4, "expected HeatmapLayoutVertex size"); + +} // namespace mbgl diff --git a/src/mbgl/programs/heatmap_program.hpp b/src/mbgl/programs/heatmap_program.hpp new file mode 100644 index 0000000000..2d9b80404f --- /dev/null +++ b/src/mbgl/programs/heatmap_program.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include <mbgl/programs/program.hpp> +#include <mbgl/programs/attributes.hpp> +#include <mbgl/programs/uniforms.hpp> +#include <mbgl/shaders/heatmap.hpp> +#include <mbgl/util/geometry.hpp> +#include <mbgl/style/layers/heatmap_layer_properties.hpp> + +namespace mbgl { + +namespace uniforms { +MBGL_DEFINE_UNIFORM_SCALAR(float, u_intensity); +} // namespace uniforms + +class HeatmapProgram : public Program< + shaders::heatmap, + gl::Triangle, + gl::Attributes< + attributes::a_pos>, + gl::Uniforms< + uniforms::u_intensity, + uniforms::u_matrix, + uniforms::heatmap::u_extrude_scale>, + style::HeatmapPaintProperties> +{ +public: + using Program::Program; + + /* + * @param {number} x vertex position + * @param {number} y vertex position + * @param {number} ex extrude normal + * @param {number} ey extrude normal + */ + static LayoutVertex vertex(Point<int16_t> p, float ex, float ey) { + return LayoutVertex { + {{ + static_cast<int16_t>((p.x * 2) + ((ex + 1) / 2)), + static_cast<int16_t>((p.y * 2) + ((ey + 1) / 2)) + }} + }; + } +}; + +using HeatmapLayoutVertex = HeatmapProgram::LayoutVertex; +using HeatmapAttributes = HeatmapProgram::Attributes; + +} // namespace mbgl diff --git a/src/mbgl/programs/heatmap_texture_program.cpp b/src/mbgl/programs/heatmap_texture_program.cpp new file mode 100644 index 0000000000..3b0e24eab8 --- /dev/null +++ b/src/mbgl/programs/heatmap_texture_program.cpp @@ -0,0 +1,7 @@ +#include <mbgl/programs/heatmap_texture_program.hpp> + +namespace mbgl { + +static_assert(sizeof(HeatmapTextureLayoutVertex) == 4, "expected HeatmapTextureLayoutVertex size"); + +} // namespace mbgl diff --git a/src/mbgl/programs/heatmap_texture_program.hpp b/src/mbgl/programs/heatmap_texture_program.hpp new file mode 100644 index 0000000000..7afe8060d0 --- /dev/null +++ b/src/mbgl/programs/heatmap_texture_program.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include <mbgl/programs/program.hpp> +#include <mbgl/programs/attributes.hpp> +#include <mbgl/programs/uniforms.hpp> +#include <mbgl/shaders/heatmap_texture.hpp> +#include <mbgl/style/properties.hpp> +#include <mbgl/util/geometry.hpp> + +namespace mbgl { + +namespace uniforms { +MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_color_ramp); +} // namespace uniforms + +class HeatmapTextureProgram : public Program< + shaders::heatmap_texture, + gl::Triangle, + gl::Attributes<attributes::a_pos>, + gl::Uniforms< + uniforms::u_matrix, + uniforms::u_world, + uniforms::u_image, + uniforms::u_color_ramp, + uniforms::u_opacity>, + style::Properties<>> { +public: + using Program::Program; + + static LayoutVertex layoutVertex(Point<int16_t> p) { + return LayoutVertex{ + {{ + p.x, + p.y + }} + }; + } +}; + +using HeatmapTextureLayoutVertex = HeatmapTextureProgram::LayoutVertex; +using HeatmapTextureAttributes = HeatmapTextureProgram::Attributes; + +} // namespace mbgl diff --git a/src/mbgl/programs/hillshade_prepare_program.hpp b/src/mbgl/programs/hillshade_prepare_program.hpp index 0f31a22df5..76638afddd 100644 --- a/src/mbgl/programs/hillshade_prepare_program.hpp +++ b/src/mbgl/programs/hillshade_prepare_program.hpp @@ -10,6 +10,7 @@ namespace mbgl { namespace uniforms { MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 2, u_dimension); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_maxzoom); } // namespace uniforms class HillshadePrepareProgram : public Program< @@ -22,6 +23,7 @@ class HillshadePrepareProgram : public Program< uniforms::u_matrix, uniforms::u_dimension, uniforms::u_zoom, + uniforms::u_maxzoom, uniforms::u_image>, style::Properties<>> { public: diff --git a/src/mbgl/programs/programs.hpp b/src/mbgl/programs/programs.hpp index f533a6f633..b703323d9c 100644 --- a/src/mbgl/programs/programs.hpp +++ b/src/mbgl/programs/programs.hpp @@ -6,6 +6,8 @@ #include <mbgl/programs/extrusion_texture_program.hpp> #include <mbgl/programs/fill_program.hpp> #include <mbgl/programs/fill_extrusion_program.hpp> +#include <mbgl/programs/heatmap_program.hpp> +#include <mbgl/programs/heatmap_texture_program.hpp> #include <mbgl/programs/hillshade_program.hpp> #include <mbgl/programs/hillshade_prepare_program.hpp> #include <mbgl/programs/line_program.hpp> @@ -30,6 +32,8 @@ public: fillPattern(context, programParameters), fillOutline(context, programParameters), fillOutlinePattern(context, programParameters), + heatmap(context, programParameters), + heatmapTexture(context, programParameters), hillshade(context, programParameters), hillshadePrepare(context, programParameters), line(context, programParameters), @@ -55,6 +59,8 @@ public: ProgramMap<FillPatternProgram> fillPattern; ProgramMap<FillOutlineProgram> fillOutline; ProgramMap<FillOutlinePatternProgram> fillOutlinePattern; + ProgramMap<HeatmapProgram> heatmap; + HeatmapTextureProgram heatmapTexture; HillshadeProgram hillshade; HillshadePrepareProgram hillshadePrepare; ProgramMap<LineProgram> line; diff --git a/src/mbgl/programs/uniforms.hpp b/src/mbgl/programs/uniforms.hpp index 184f42e504..071a27c808 100644 --- a/src/mbgl/programs/uniforms.hpp +++ b/src/mbgl/programs/uniforms.hpp @@ -37,9 +37,14 @@ MBGL_DEFINE_UNIFORM_SCALAR(Size, u_texsize); MBGL_DEFINE_UNIFORM_SCALAR(bool, u_pitch_with_map); MBGL_DEFINE_UNIFORM_SCALAR(float, u_camera_to_center_distance); MBGL_DEFINE_UNIFORM_SCALAR(float, u_fade_change); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_weight); MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_extrude_scale); +namespace heatmap { +MBGL_DEFINE_UNIFORM_SCALAR(float, u_extrude_scale); +} // namespace heatmap + MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 2, u_pattern_tl_a); MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 2, u_pattern_br_a); MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 2, u_pattern_tl_b); @@ -55,6 +60,7 @@ MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_fadetexture); MBGL_DEFINE_UNIFORM_SCALAR(float, u_scale_a); MBGL_DEFINE_UNIFORM_SCALAR(float, u_scale_b); MBGL_DEFINE_UNIFORM_SCALAR(float, u_tile_units_to_pixels); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_overscale_factor); } // namespace uniforms } // namespace mbgl diff --git a/src/mbgl/renderer/buckets/heatmap_bucket.cpp b/src/mbgl/renderer/buckets/heatmap_bucket.cpp new file mode 100644 index 0000000000..a185e04ad2 --- /dev/null +++ b/src/mbgl/renderer/buckets/heatmap_bucket.cpp @@ -0,0 +1,98 @@ +#include <mbgl/renderer/buckets/heatmap_bucket.hpp> +#include <mbgl/renderer/bucket_parameters.hpp> +#include <mbgl/programs/heatmap_program.hpp> +#include <mbgl/style/layers/heatmap_layer_impl.hpp> +#include <mbgl/renderer/layers/render_heatmap_layer.hpp> +#include <mbgl/util/constants.hpp> +#include <mbgl/util/math.hpp> + +namespace mbgl { + +using namespace style; + +HeatmapBucket::HeatmapBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) + : mode(parameters.mode) { + for (const auto& layer : layers) { + paintPropertyBinders.emplace( + std::piecewise_construct, + std::forward_as_tuple(layer->getID()), + std::forward_as_tuple( + layer->as<RenderHeatmapLayer>()->evaluated, + parameters.tileID.overscaledZ)); + } +} + +void HeatmapBucket::upload(gl::Context& context) { + vertexBuffer = context.createVertexBuffer(std::move(vertices)); + indexBuffer = context.createIndexBuffer(std::move(triangles)); + + for (auto& pair : paintPropertyBinders) { + pair.second.upload(context); + } + + uploaded = true; +} + +bool HeatmapBucket::hasData() const { + return !segments.empty(); +} + +void HeatmapBucket::addFeature(const GeometryTileFeature& feature, + const GeometryCollection& geometry) { + constexpr const uint16_t vertexLength = 4; + + for (auto& points : geometry) { + for(auto& point : points) { + auto x = point.x; + auto y = point.y; + + // Do not include points that are outside the tile boundaries. + // Include all points in Still mode. You need to include points from + // neighbouring tiles so that they are not clipped at tile boundaries. + if ((mode == MapMode::Continuous) && + (x < 0 || x >= util::EXTENT || y < 0 || y >= util::EXTENT)) continue; + + if (segments.empty() || segments.back().vertexLength + vertexLength > std::numeric_limits<uint16_t>::max()) { + // Move to a new segments because the old one can't hold the geometry. + segments.emplace_back(vertices.vertexSize(), triangles.indexSize()); + } + + // this geometry will be of the Point type, and we'll derive + // two triangles from it. + // + // ┌─────────┐ + // │ 4 3 │ + // │ │ + // │ 1 2 │ + // └─────────┘ + // + vertices.emplace_back(HeatmapProgram::vertex(point, -1, -1)); // 1 + vertices.emplace_back(HeatmapProgram::vertex(point, 1, -1)); // 2 + vertices.emplace_back(HeatmapProgram::vertex(point, 1, 1)); // 3 + vertices.emplace_back(HeatmapProgram::vertex(point, -1, 1)); // 4 + + auto& segment = segments.back(); + assert(segment.vertexLength <= std::numeric_limits<uint16_t>::max()); + uint16_t index = segment.vertexLength; + + // 1, 2, 3 + // 1, 4, 3 + triangles.emplace_back(index, index + 1, index + 2); + triangles.emplace_back(index, index + 3, index + 2); + + segment.vertexLength += vertexLength; + segment.indexLength += 6; + } + } + + for (auto& pair : paintPropertyBinders) { + pair.second.populateVertexVectors(feature, vertices.vertexSize()); + } +} + +float HeatmapBucket::getQueryRadius(const RenderLayer& layer) const { + (void)layer; + return 0; +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/buckets/heatmap_bucket.hpp b/src/mbgl/renderer/buckets/heatmap_bucket.hpp new file mode 100644 index 0000000000..3b9f1edb81 --- /dev/null +++ b/src/mbgl/renderer/buckets/heatmap_bucket.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include <mbgl/renderer/bucket.hpp> +#include <mbgl/map/mode.hpp> +#include <mbgl/tile/geometry_tile_data.hpp> +#include <mbgl/gl/vertex_buffer.hpp> +#include <mbgl/gl/index_buffer.hpp> +#include <mbgl/programs/segment.hpp> +#include <mbgl/programs/heatmap_program.hpp> +#include <mbgl/style/layers/heatmap_layer_properties.hpp> + +namespace mbgl { + +class BucketParameters; + +class HeatmapBucket : public Bucket { +public: + HeatmapBucket(const BucketParameters&, const std::vector<const RenderLayer*>&); + + void addFeature(const GeometryTileFeature&, + const GeometryCollection&) override; + bool hasData() const override; + + void upload(gl::Context&) override; + + float getQueryRadius(const RenderLayer&) const override; + + gl::VertexVector<HeatmapLayoutVertex> vertices; + gl::IndexVector<gl::Triangles> triangles; + SegmentVector<HeatmapAttributes> segments; + + optional<gl::VertexBuffer<HeatmapLayoutVertex>> vertexBuffer; + optional<gl::IndexBuffer<gl::Triangles>> indexBuffer; + + std::map<std::string, HeatmapProgram::PaintPropertyBinders> paintPropertyBinders; + + const MapMode mode; +}; + +} // namespace mbgl diff --git a/src/mbgl/renderer/buckets/hillshade_bucket.cpp b/src/mbgl/renderer/buckets/hillshade_bucket.cpp index 8011681ee0..00b9536894 100644 --- a/src/mbgl/renderer/buckets/hillshade_bucket.cpp +++ b/src/mbgl/renderer/buckets/hillshade_bucket.cpp @@ -8,7 +8,7 @@ namespace mbgl { using namespace style; -HillshadeBucket::HillshadeBucket(PremultipliedImage&& image_): demdata(image_) { +HillshadeBucket::HillshadeBucket(PremultipliedImage&& image_, Tileset::DEMEncoding encoding): demdata(image_, encoding) { } HillshadeBucket::HillshadeBucket(DEMData&& demdata_) : demdata(std::move(demdata_)) { diff --git a/src/mbgl/renderer/buckets/hillshade_bucket.hpp b/src/mbgl/renderer/buckets/hillshade_bucket.hpp index 3d9f6c61af..5335f7ceda 100644 --- a/src/mbgl/renderer/buckets/hillshade_bucket.hpp +++ b/src/mbgl/renderer/buckets/hillshade_bucket.hpp @@ -8,6 +8,7 @@ #include <mbgl/renderer/bucket.hpp> #include <mbgl/renderer/tile_mask.hpp> #include <mbgl/geometry/dem_data.hpp> +#include <mbgl/util/tileset.hpp> #include <mbgl/util/image.hpp> #include <mbgl/util/mat4.hpp> #include <mbgl/util/optional.hpp> @@ -16,8 +17,8 @@ namespace mbgl { class HillshadeBucket : public Bucket { public: - HillshadeBucket(PremultipliedImage&&); - HillshadeBucket(std::shared_ptr<PremultipliedImage>); + HillshadeBucket(PremultipliedImage&&, Tileset::DEMEncoding encoding); + HillshadeBucket(std::shared_ptr<PremultipliedImage>, Tileset::DEMEncoding encoding); HillshadeBucket(DEMData&&); diff --git a/src/mbgl/renderer/layers/render_custom_layer.cpp b/src/mbgl/renderer/layers/render_custom_layer.cpp index adafd8583f..a429b8d82e 100644 --- a/src/mbgl/renderer/layers/render_custom_layer.cpp +++ b/src/mbgl/renderer/layers/render_custom_layer.cpp @@ -5,6 +5,7 @@ #include <mbgl/renderer/bucket.hpp> #include <mbgl/style/layers/custom_layer_impl.hpp> #include <mbgl/map/transform_state.hpp> +#include <mbgl/gl/gl.hpp> namespace mbgl { @@ -46,11 +47,11 @@ void RenderCustomLayer::render(PaintParameters& paintParameters, RenderSource*) if (context != impl().context || !initialized) { //If the context changed, deinitialize the previous one before initializing the new one. if (context && !contextDestroyed && impl().deinitializeFn) { - impl().deinitializeFn(context); + MBGL_CHECK_ERROR(impl().deinitializeFn(context)); } context = impl().context; assert(impl().initializeFn); - impl().initializeFn(impl().context); + MBGL_CHECK_ERROR(impl().initializeFn(impl().context)); initialized = true; } @@ -75,7 +76,7 @@ void RenderCustomLayer::render(PaintParameters& paintParameters, RenderSource*) parameters.fieldOfView = state.getFieldOfView(); assert(impl().renderFn); - impl().renderFn(context, parameters); + MBGL_CHECK_ERROR(impl().renderFn(context, parameters)); // Reset the view back to our original one, just in case the CustomLayer changed // the viewport or Framebuffer. diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.cpp b/src/mbgl/renderer/layers/render_heatmap_layer.cpp new file mode 100644 index 0000000000..4f2e899220 --- /dev/null +++ b/src/mbgl/renderer/layers/render_heatmap_layer.cpp @@ -0,0 +1,178 @@ +#include <mbgl/renderer/layers/render_heatmap_layer.hpp> +#include <mbgl/renderer/buckets/heatmap_bucket.hpp> +#include <mbgl/renderer/render_tile.hpp> +#include <mbgl/renderer/paint_parameters.hpp> +#include <mbgl/renderer/render_static_data.hpp> +#include <mbgl/programs/programs.hpp> +#include <mbgl/programs/heatmap_program.hpp> +#include <mbgl/tile/tile.hpp> +#include <mbgl/style/layers/heatmap_layer.hpp> +#include <mbgl/style/layers/heatmap_layer_impl.hpp> +#include <mbgl/geometry/feature_index.hpp> +#include <mbgl/util/math.hpp> +#include <mbgl/util/intersection_tests.hpp> + +namespace mbgl { + +using namespace style; + +RenderHeatmapLayer::RenderHeatmapLayer(Immutable<style::HeatmapLayer::Impl> _impl) + : RenderLayer(style::LayerType::Heatmap, _impl), + unevaluated(impl().paint.untransitioned()), colorRamp({256, 1}) { +} + +const style::HeatmapLayer::Impl& RenderHeatmapLayer::impl() const { + return static_cast<const style::HeatmapLayer::Impl&>(*baseImpl); +} + +std::unique_ptr<Bucket> RenderHeatmapLayer::createBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) const { + return std::make_unique<HeatmapBucket>(parameters, layers); +} + +void RenderHeatmapLayer::transition(const TransitionParameters& parameters) { + unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated)); +} + +void RenderHeatmapLayer::evaluate(const PropertyEvaluationParameters& parameters) { + evaluated = unevaluated.evaluate(parameters); + + passes = (evaluated.get<style::HeatmapOpacity>() > 0) + ? (RenderPass::Translucent | RenderPass::Pass3D) + : RenderPass::None; +} + +bool RenderHeatmapLayer::hasTransition() const { + return unevaluated.hasTransition(); +} + +void RenderHeatmapLayer::render(PaintParameters& parameters, RenderSource*) { + if (parameters.pass == RenderPass::Opaque) { + return; + } + + if (parameters.pass == RenderPass::Pass3D) { + const auto& viewportSize = parameters.staticData.backendSize; + const auto size = Size{viewportSize.width / 4, viewportSize.height / 4}; + + if (!renderTexture || renderTexture->getSize() != size) { + if (parameters.context.supportsHalfFloatTextures) { + renderTexture = OffscreenTexture(parameters.context, size, gl::TextureType::HalfFloat); + + try { + renderTexture->bind(); + } catch (const std::runtime_error& ex) { + // can't render to a half-float texture; falling back to unsigned byte one + renderTexture = nullopt; + parameters.context.supportsHalfFloatTextures = false; + } + } + + if (!parameters.context.supportsHalfFloatTextures || !renderTexture) { + renderTexture = OffscreenTexture(parameters.context, size, gl::TextureType::UnsignedByte); + renderTexture->bind(); + } + + } else { + renderTexture->bind(); + } + + if (!colorRampTexture) { + colorRampTexture = parameters.context.createTexture(colorRamp, 1, gl::TextureType::UnsignedByte); + } + + parameters.context.clear(Color{ 0.0f, 0.0f, 0.0f, 1.0f }, {}, {}); + + for (const RenderTile& tile : renderTiles) { + assert(dynamic_cast<HeatmapBucket*>(tile.tile.getBucket(*baseImpl))); + HeatmapBucket& bucket = *reinterpret_cast<HeatmapBucket*>(tile.tile.getBucket(*baseImpl)); + + const auto extrudeScale = tile.id.pixelsToTileUnits(1, parameters.state.getZoom()); + + const auto stencilMode = parameters.mapMode != MapMode::Continuous + ? parameters.stencilModeForClipping(tile.clip) + : gl::StencilMode::disabled(); + + parameters.programs.heatmap.get(evaluated).draw( + parameters.context, + gl::Triangles(), + parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly), + stencilMode, + gl::ColorMode::additive(), + HeatmapProgram::UniformValues { + uniforms::u_intensity::Value{evaluated.get<style::HeatmapIntensity>()}, + uniforms::u_matrix::Value{tile.matrix}, + uniforms::heatmap::u_extrude_scale::Value{extrudeScale} + }, + *bucket.vertexBuffer, + *bucket.indexBuffer, + bucket.segments, + bucket.paintPropertyBinders.at(getID()), + evaluated, + parameters.state.getZoom(), + getID() + ); + } + + } else if (parameters.pass == RenderPass::Translucent) { + parameters.context.bindTexture(renderTexture->getTexture(), 0, gl::TextureFilter::Linear); + parameters.context.bindTexture(*colorRampTexture, 1, gl::TextureFilter::Linear); + + const auto& size = parameters.staticData.backendSize; + + mat4 viewportMat; + matrix::ortho(viewportMat, 0, size.width, size.height, 0, 0, 1); + + const Properties<>::PossiblyEvaluated properties; + + parameters.programs.heatmapTexture.draw( + parameters.context, gl::Triangles(), gl::DepthMode::disabled(), + gl::StencilMode::disabled(), parameters.colorModeForRenderPass(), + HeatmapTextureProgram::UniformValues{ + uniforms::u_matrix::Value{ viewportMat }, uniforms::u_world::Value{ size }, + uniforms::u_image::Value{ 0 }, + uniforms::u_color_ramp::Value{ 1 }, + uniforms::u_opacity::Value{ evaluated.get<HeatmapOpacity>() } }, + parameters.staticData.extrusionTextureVertexBuffer, + parameters.staticData.quadTriangleIndexBuffer, + parameters.staticData.extrusionTextureSegments, + HeatmapTextureProgram::PaintPropertyBinders{ properties, 0 }, properties, + parameters.state.getZoom(), getID()); + } +} + +void RenderHeatmapLayer::updateColorRamp() { + auto colorValue = unevaluated.get<HeatmapColor>().getValue(); + if (colorValue.isUndefined()) { + colorValue = HeatmapLayer::getDefaultHeatmapColor(); + } + + const auto length = colorRamp.bytes(); + + for (uint32_t i = 0; i < length; i += 4) { + const auto color = colorValue.evaluate(static_cast<double>(i) / length); + colorRamp.data[i + 0] = std::floor(color.r * 255); + colorRamp.data[i + 1] = std::floor(color.g * 255); + colorRamp.data[i + 2] = std::floor(color.b * 255); + colorRamp.data[i + 3] = std::floor(color.a * 255); + } + + if (colorRampTexture) { + colorRampTexture = nullopt; + } +} + +bool RenderHeatmapLayer::queryIntersectsFeature( + const GeometryCoordinates& queryGeometry, + const GeometryTileFeature& feature, + const float zoom, + const float bearing, + const float pixelsToTileUnits) const { + (void) queryGeometry; + (void) feature; + (void) zoom; + (void) bearing; + (void) pixelsToTileUnits; + return false; +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.hpp b/src/mbgl/renderer/layers/render_heatmap_layer.hpp new file mode 100644 index 0000000000..3f0b1f91b4 --- /dev/null +++ b/src/mbgl/renderer/layers/render_heatmap_layer.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include <mbgl/renderer/render_layer.hpp> +#include <mbgl/style/layers/heatmap_layer_impl.hpp> +#include <mbgl/style/layers/heatmap_layer_properties.hpp> +#include <mbgl/util/optional.hpp> +#include <mbgl/util/offscreen_texture.hpp> + +namespace mbgl { + +class RenderHeatmapLayer: public RenderLayer { +public: + RenderHeatmapLayer(Immutable<style::HeatmapLayer::Impl>); + ~RenderHeatmapLayer() final = default; + + void transition(const TransitionParameters&) override; + void evaluate(const PropertyEvaluationParameters&) override; + bool hasTransition() const override; + void render(PaintParameters&, RenderSource*) override; + + bool queryIntersectsFeature( + const GeometryCoordinates&, + const GeometryTileFeature&, + const float, + const float, + const float) const override; + + void updateColorRamp(); + + std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const override; + + // Paint properties + style::HeatmapPaintProperties::Unevaluated unevaluated; + style::HeatmapPaintProperties::PossiblyEvaluated evaluated; + + const style::HeatmapLayer::Impl& impl() const; + + PremultipliedImage colorRamp; + optional<OffscreenTexture> renderTexture; + optional<gl::Texture> colorRampTexture; +}; + +template <> +inline bool RenderLayer::is<RenderHeatmapLayer>() const { + return type == style::LayerType::Heatmap; +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_hillshade_layer.cpp b/src/mbgl/renderer/layers/render_hillshade_layer.cpp index 7a767522c0..bcfd4ffe99 100644 --- a/src/mbgl/renderer/layers/render_hillshade_layer.cpp +++ b/src/mbgl/renderer/layers/render_hillshade_layer.cpp @@ -1,6 +1,7 @@ #include <mbgl/renderer/layers/render_hillshade_layer.hpp> #include <mbgl/renderer/buckets/hillshade_bucket.hpp> #include <mbgl/renderer/render_tile.hpp> +#include <mbgl/renderer/sources/render_raster_dem_source.hpp> #include <mbgl/renderer/paint_parameters.hpp> #include <mbgl/renderer/render_static_data.hpp> #include <mbgl/programs/programs.hpp> @@ -55,10 +56,14 @@ bool RenderHillshadeLayer::hasTransition() const { return unevaluated.hasTransition(); } -void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource*) { +void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource* src) { if (parameters.pass != RenderPass::Translucent && parameters.pass != RenderPass::Pass3D) return; + RenderRasterDEMSource* demsrc = dynamic_cast<RenderRasterDEMSource*>(src); + const uint8_t TERRAIN_RGB_MAXZOOM = 15; + const uint8_t maxzoom = demsrc != nullptr ? demsrc->getMaxZoom() : TERRAIN_RGB_MAXZOOM; + auto draw = [&] (const mat4& matrix, const auto& vertexBuffer, const auto& indexBuffer, @@ -118,6 +123,7 @@ void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource*) { uniforms::u_matrix::Value { mat }, uniforms::u_dimension::Value { {{uint16_t(tilesize * 2), uint16_t(tilesize * 2) }} }, uniforms::u_zoom::Value{ float(tile.id.canonical.z) }, + uniforms::u_maxzoom::Value{ float(maxzoom) }, uniforms::u_image::Value{ 0 } }, parameters.staticData.rasterVertexBuffer, @@ -136,14 +142,14 @@ void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource*) { if (bucket.vertexBuffer && bucket.indexBuffer && !bucket.segments.empty()) { // Draw only the parts of the tile that aren't drawn by another tile in the layer. - draw(tile.matrix, + draw(parameters.matrixForTile(tile.id, true), *bucket.vertexBuffer, *bucket.indexBuffer, bucket.segments, tile.id); } else { // Draw the full tile. - draw(tile.matrix, + draw(parameters.matrixForTile(tile.id, true), parameters.staticData.rasterVertexBuffer, parameters.staticData.quadTriangleIndexBuffer, parameters.staticData.rasterSegments, diff --git a/src/mbgl/renderer/layers/render_hillshade_layer.hpp b/src/mbgl/renderer/layers/render_hillshade_layer.hpp index e9b9db1ec3..13093ee7ef 100644 --- a/src/mbgl/renderer/layers/render_hillshade_layer.hpp +++ b/src/mbgl/renderer/layers/render_hillshade_layer.hpp @@ -16,7 +16,7 @@ public: void evaluate(const PropertyEvaluationParameters&) override; bool hasTransition() const override; - void render(PaintParameters&, RenderSource*) override; + void render(PaintParameters&, RenderSource* src) override; std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const override; diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 04fcb2c3ab..9e493003c0 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -268,9 +268,10 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { gl::DepthMode::disabled(), gl::StencilMode::disabled(), parameters.colorModeForRenderPass(), - CollisionBoxProgram::UniformValues { + CollisionCircleProgram::UniformValues { uniforms::u_matrix::Value{ tile.matrix }, uniforms::u_extrude_scale::Value{ extrudeScale }, + uniforms::u_overscale_factor::Value{ float(tile.tile.id.overscaleFactor()) }, uniforms::u_camera_to_center_distance::Value{ parameters.state.getCameraToCenterDistance() } }, *bucket.collisionCircle.vertexBuffer, diff --git a/src/mbgl/renderer/render_layer.cpp b/src/mbgl/renderer/render_layer.cpp index 248905f834..bcdc175f14 100644 --- a/src/mbgl/renderer/render_layer.cpp +++ b/src/mbgl/renderer/render_layer.cpp @@ -8,6 +8,7 @@ #include <mbgl/renderer/layers/render_line_layer.hpp> #include <mbgl/renderer/layers/render_raster_layer.hpp> #include <mbgl/renderer/layers/render_symbol_layer.hpp> +#include <mbgl/renderer/layers/render_heatmap_layer.hpp> #include <mbgl/style/types.hpp> #include <mbgl/renderer/render_tile.hpp> @@ -35,6 +36,8 @@ std::unique_ptr<RenderLayer> RenderLayer::create(Immutable<Layer::Impl> impl) { return std::make_unique<RenderCustomLayer>(staticImmutableCast<CustomLayer::Impl>(impl)); case LayerType::FillExtrusion: return std::make_unique<RenderFillExtrusionLayer>(staticImmutableCast<FillExtrusionLayer::Impl>(impl)); + case LayerType::Heatmap: + return std::make_unique<RenderHeatmapLayer>(staticImmutableCast<HeatmapLayer::Impl>(impl)); } // Not reachable, but placate GCC. diff --git a/src/mbgl/renderer/render_source.hpp b/src/mbgl/renderer/render_source.hpp index db88230e53..53519c763e 100644 --- a/src/mbgl/renderer/render_source.hpp +++ b/src/mbgl/renderer/render_source.hpp @@ -70,7 +70,7 @@ public: virtual std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const = 0; - virtual void onLowMemory() = 0; + virtual void reduceMemoryUse() = 0; virtual void dumpDebugLogs() const = 0; diff --git a/src/mbgl/renderer/renderer.cpp b/src/mbgl/renderer/renderer.cpp index 6d086c70b1..1d2f2bb522 100644 --- a/src/mbgl/renderer/renderer.cpp +++ b/src/mbgl/renderer/renderer.cpp @@ -94,9 +94,9 @@ void Renderer::dumpDebugLogs() { impl->dumDebugLogs(); } -void Renderer::onLowMemory() { +void Renderer::reduceMemoryUse() { BackendScope guard { impl->backend }; - impl->onLowMemory(); + impl->reduceMemoryUse(); } } // namespace mbgl diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp index 61e7d17242..2ac714e122 100644 --- a/src/mbgl/renderer/renderer_impl.cpp +++ b/src/mbgl/renderer/renderer_impl.cpp @@ -14,6 +14,7 @@ #include <mbgl/renderer/layers/render_background_layer.hpp> #include <mbgl/renderer/layers/render_custom_layer.hpp> #include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp> +#include <mbgl/renderer/layers/render_heatmap_layer.hpp> #include <mbgl/renderer/layers/render_hillshade_layer.hpp> #include <mbgl/renderer/style_diff.hpp> #include <mbgl/renderer/query.hpp> @@ -185,6 +186,10 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { if (layerAdded || layerChanged) { layer.transition(transitionParameters); + + if (layer.is<RenderHeatmapLayer>()) { + layer.as<RenderHeatmapLayer>()->updateColorRamp(); + } } if (layerAdded || layerChanged || zoomChanged || layer.hasTransition()) { @@ -290,7 +295,11 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { RenderLayer* layer = getRenderLayer(layerImpl->id); assert(layer); - if (!parameters.staticData.has3D && (layer->is<RenderFillExtrusionLayer>() || layer->is<RenderHillshadeLayer>())) { + if (!parameters.staticData.has3D && ( + layer->is<RenderFillExtrusionLayer>() || + layer->is<RenderHillshadeLayer>() || + layer->is<RenderHeatmapLayer>())) { + parameters.staticData.has3D = true; } @@ -722,12 +731,12 @@ std::vector<Feature> Renderer::Impl::querySourceFeatures(const std::string& sour return source->querySourceFeatures(options); } -void Renderer::Impl::onLowMemory() { +void Renderer::Impl::reduceMemoryUse() { assert(BackendScope::exists()); - backend.getContext().performCleanup(); for (const auto& entry : renderSources) { - entry.second->onLowMemory(); + entry.second->reduceMemoryUse(); } + backend.getContext().performCleanup(); observer->onInvalidate(); } diff --git a/src/mbgl/renderer/renderer_impl.hpp b/src/mbgl/renderer/renderer_impl.hpp index 4f45d514a5..4675ac79ea 100644 --- a/src/mbgl/renderer/renderer_impl.hpp +++ b/src/mbgl/renderer/renderer_impl.hpp @@ -53,7 +53,7 @@ public: std::vector<Feature> querySourceFeatures(const std::string& sourceID, const SourceQueryOptions&) const; std::vector<Feature> queryShapeAnnotations(const ScreenLineString&) const; - void onLowMemory(); + void reduceMemoryUse(); void dumDebugLogs(); private: diff --git a/src/mbgl/renderer/renderer_observer.hpp b/src/mbgl/renderer/renderer_observer.hpp deleted file mode 100644 index 551b5c803e..0000000000 --- a/src/mbgl/renderer/renderer_observer.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include <exception> - -namespace mbgl { - -class RendererObserver { -public: - virtual ~RendererObserver() = default; - - enum class RenderMode : uint32_t { - Partial, - Full - }; - - // Signals that a repaint is required - virtual void onInvalidate() {} - - // Resource failed to download / parse - virtual void onResourceError(std::exception_ptr) {} - - // First frame - virtual void onWillStartRenderingMap() {} - - // Start of frame, initial is the first frame for this map - virtual void onWillStartRenderingFrame() {} - - // End of frame, boolean flags that a repaint is required - virtual void onDidFinishRenderingFrame(RenderMode, bool) {} - - // Final frame - virtual void onDidFinishRenderingMap() {} -}; - -} // namespace mbgl diff --git a/src/mbgl/renderer/sources/render_custom_geometry_source.cpp b/src/mbgl/renderer/sources/render_custom_geometry_source.cpp index df615a7e20..057ad5a4a7 100644 --- a/src/mbgl/renderer/sources/render_custom_geometry_source.cpp +++ b/src/mbgl/renderer/sources/render_custom_geometry_source.cpp @@ -76,8 +76,8 @@ std::vector<Feature> RenderCustomGeometrySource::querySourceFeatures(const Sourc return tilePyramid.querySourceFeatures(options); } -void RenderCustomGeometrySource::onLowMemory() { - tilePyramid.onLowMemory(); +void RenderCustomGeometrySource::reduceMemoryUse() { + tilePyramid.reduceMemoryUse(); } void RenderCustomGeometrySource::dumpDebugLogs() const { diff --git a/src/mbgl/renderer/sources/render_custom_geometry_source.hpp b/src/mbgl/renderer/sources/render_custom_geometry_source.hpp index 82e691d5c9..033d731029 100644 --- a/src/mbgl/renderer/sources/render_custom_geometry_source.hpp +++ b/src/mbgl/renderer/sources/render_custom_geometry_source.hpp @@ -33,7 +33,7 @@ public: std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const final; - void onLowMemory() final; + void reduceMemoryUse() final; void dumpDebugLogs() const final; private: diff --git a/src/mbgl/renderer/sources/render_geojson_source.cpp b/src/mbgl/renderer/sources/render_geojson_source.cpp index 8ea80cd813..cbf4db70b5 100644 --- a/src/mbgl/renderer/sources/render_geojson_source.cpp +++ b/src/mbgl/renderer/sources/render_geojson_source.cpp @@ -94,8 +94,8 @@ std::vector<Feature> RenderGeoJSONSource::querySourceFeatures(const SourceQueryO return tilePyramid.querySourceFeatures(options); } -void RenderGeoJSONSource::onLowMemory() { - tilePyramid.onLowMemory(); +void RenderGeoJSONSource::reduceMemoryUse() { + tilePyramid.reduceMemoryUse(); } void RenderGeoJSONSource::dumpDebugLogs() const { diff --git a/src/mbgl/renderer/sources/render_geojson_source.hpp b/src/mbgl/renderer/sources/render_geojson_source.hpp index 55166ea901..72fccbd043 100644 --- a/src/mbgl/renderer/sources/render_geojson_source.hpp +++ b/src/mbgl/renderer/sources/render_geojson_source.hpp @@ -37,7 +37,7 @@ public: std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const final; - void onLowMemory() final; + void reduceMemoryUse() final; void dumpDebugLogs() const final; private: diff --git a/src/mbgl/renderer/sources/render_image_source.hpp b/src/mbgl/renderer/sources/render_image_source.hpp index 72cf4cea61..85ee0ace11 100644 --- a/src/mbgl/renderer/sources/render_image_source.hpp +++ b/src/mbgl/renderer/sources/render_image_source.hpp @@ -37,7 +37,7 @@ public: std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const final; - void onLowMemory() final { + void reduceMemoryUse() final { } void dumpDebugLogs() const final; diff --git a/src/mbgl/renderer/sources/render_raster_dem_source.cpp b/src/mbgl/renderer/sources/render_raster_dem_source.cpp index 76716518d7..b3153622c3 100644 --- a/src/mbgl/renderer/sources/render_raster_dem_source.cpp +++ b/src/mbgl/renderer/sources/render_raster_dem_source.cpp @@ -32,21 +32,22 @@ void RenderRasterDEMSource::update(Immutable<style::Source::Impl> baseImpl_, enabled = needsRendering; - optional<Tileset> tileset = impl().getTileset(); - - if (!tileset) { - return; - } - - if (tileURLTemplates != tileset->tiles) { - tileURLTemplates = tileset->tiles; + optional<Tileset> _tileset = impl().getTileset(); + if (tileset != _tileset) { + tileset = _tileset; + maxzoom = tileset->zoomRange.max; // TODO: this removes existing buckets, and will cause flickering. // Should instead refresh tile data in place. tilePyramid.tiles.clear(); tilePyramid.renderTiles.clear(); tilePyramid.cache.clear(); } + // Allow clearing the tile pyramid first, before the early return in case + // the new tileset is not yet available or has an error in loading + if (!_tileset) { + return; + } tilePyramid.update(layers, needsRendering, @@ -154,8 +155,8 @@ std::vector<Feature> RenderRasterDEMSource::querySourceFeatures(const SourceQuer return {}; } -void RenderRasterDEMSource::onLowMemory() { - tilePyramid.onLowMemory(); +void RenderRasterDEMSource::reduceMemoryUse() { + tilePyramid.reduceMemoryUse(); } void RenderRasterDEMSource::dumpDebugLogs() const { diff --git a/src/mbgl/renderer/sources/render_raster_dem_source.hpp b/src/mbgl/renderer/sources/render_raster_dem_source.hpp index b6b8bf977c..741214a14d 100644 --- a/src/mbgl/renderer/sources/render_raster_dem_source.hpp +++ b/src/mbgl/renderer/sources/render_raster_dem_source.hpp @@ -33,14 +33,19 @@ public: std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const final; - void onLowMemory() final; + void reduceMemoryUse() final; void dumpDebugLogs() const final; + uint8_t getMaxZoom() const { + return maxzoom; + }; + private: const style::RasterSource::Impl& impl() const; TilePyramid tilePyramid; - optional<std::vector<std::string>> tileURLTemplates; + optional<Tileset> tileset; + uint8_t maxzoom = 15; protected: void onTileChanged(Tile&) final; diff --git a/src/mbgl/renderer/sources/render_raster_source.cpp b/src/mbgl/renderer/sources/render_raster_source.cpp index e99cd040e9..60b3fa9a3b 100644 --- a/src/mbgl/renderer/sources/render_raster_source.cpp +++ b/src/mbgl/renderer/sources/render_raster_source.cpp @@ -29,14 +29,10 @@ void RenderRasterSource::update(Immutable<style::Source::Impl> baseImpl_, enabled = needsRendering; - optional<Tileset> tileset = impl().getTileset(); + optional<Tileset> _tileset = impl().getTileset(); - if (!tileset) { - return; - } - - if (tileURLTemplates != tileset->tiles) { - tileURLTemplates = tileset->tiles; + if (tileset != _tileset) { + tileset = _tileset; // TODO: this removes existing buckets, and will cause flickering. // Should instead refresh tile data in place. @@ -44,6 +40,11 @@ void RenderRasterSource::update(Immutable<style::Source::Impl> baseImpl_, tilePyramid.renderTiles.clear(); tilePyramid.cache.clear(); } + // Allow clearing the tile pyramid first, before the early return in case + // the new tileset is not yet available or has an error in loading + if (!_tileset) { + return; + } tilePyramid.update(layers, needsRendering, @@ -84,8 +85,8 @@ std::vector<Feature> RenderRasterSource::querySourceFeatures(const SourceQueryOp return {}; } -void RenderRasterSource::onLowMemory() { - tilePyramid.onLowMemory(); +void RenderRasterSource::reduceMemoryUse() { + tilePyramid.reduceMemoryUse(); } void RenderRasterSource::dumpDebugLogs() const { diff --git a/src/mbgl/renderer/sources/render_raster_source.hpp b/src/mbgl/renderer/sources/render_raster_source.hpp index 25041fde43..78eda199ac 100644 --- a/src/mbgl/renderer/sources/render_raster_source.hpp +++ b/src/mbgl/renderer/sources/render_raster_source.hpp @@ -33,14 +33,14 @@ public: std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const final; - void onLowMemory() final; + void reduceMemoryUse() final; void dumpDebugLogs() const final; private: const style::RasterSource::Impl& impl() const; TilePyramid tilePyramid; - optional<std::vector<std::string>> tileURLTemplates; + optional<Tileset> tileset; }; template <> diff --git a/src/mbgl/renderer/sources/render_vector_source.cpp b/src/mbgl/renderer/sources/render_vector_source.cpp index d53023e4d0..e87bea5dcd 100644 --- a/src/mbgl/renderer/sources/render_vector_source.cpp +++ b/src/mbgl/renderer/sources/render_vector_source.cpp @@ -32,14 +32,10 @@ void RenderVectorSource::update(Immutable<style::Source::Impl> baseImpl_, enabled = needsRendering; - optional<Tileset> tileset = impl().getTileset(); + optional<Tileset> _tileset = impl().getTileset(); - if (!tileset) { - return; - } - - if (tileURLTemplates != tileset->tiles) { - tileURLTemplates = tileset->tiles; + if (tileset != _tileset) { + tileset = _tileset; // TODO: this removes existing buckets, and will cause flickering. // Should instead refresh tile data in place. @@ -47,6 +43,11 @@ void RenderVectorSource::update(Immutable<style::Source::Impl> baseImpl_, tilePyramid.renderTiles.clear(); tilePyramid.cache.clear(); } + // Allow clearing the tile pyramid first, before the early return in case + // the new tileset is not yet available or has an error in loading + if (!_tileset) { + return; + } tilePyramid.update(layers, needsRendering, @@ -87,8 +88,8 @@ std::vector<Feature> RenderVectorSource::querySourceFeatures(const SourceQueryOp return tilePyramid.querySourceFeatures(options); } -void RenderVectorSource::onLowMemory() { - tilePyramid.onLowMemory(); +void RenderVectorSource::reduceMemoryUse() { + tilePyramid.reduceMemoryUse(); } void RenderVectorSource::dumpDebugLogs() const { diff --git a/src/mbgl/renderer/sources/render_vector_source.hpp b/src/mbgl/renderer/sources/render_vector_source.hpp index 4a992e854f..592160dc16 100644 --- a/src/mbgl/renderer/sources/render_vector_source.hpp +++ b/src/mbgl/renderer/sources/render_vector_source.hpp @@ -33,14 +33,14 @@ public: std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const final; - void onLowMemory() final; + void reduceMemoryUse() final; void dumpDebugLogs() const final; private: const style::VectorSource::Impl& impl() const; TilePyramid tilePyramid; - optional<std::vector<std::string>> tileURLTemplates; + optional<Tileset> tileset; }; template <> diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp index 07239b7a1c..8f83a0f982 100644 --- a/src/mbgl/renderer/tile_pyramid.cpp +++ b/src/mbgl/renderer/tile_pyramid.cpp @@ -143,10 +143,13 @@ void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layer auto it = tiles.find(tileID); return it == tiles.end() ? nullptr : it->second.get(); }; - + + // The min and max zoom for TileRange are based on the updateRenderables algorithm. + // Tiles are created at the ideal tile zoom or at lower zoom levels. Child + // tiles are used from the cache, but not created. optional<util::TileRange> tileRange = {}; if (bounds) { - tileRange = util::TileRange::fromLatLngBounds(*bounds, std::min(tileZoom, (int32_t)zoomRange.max)); + tileRange = util::TileRange::fromLatLngBounds(*bounds, zoomRange.min, std::min(tileZoom, (int32_t)zoomRange.max)); } auto createTileFn = [&](const OverscaledTileID& tileID) -> Tile* { if (tileRange && !tileRange->contains(tileID.canonical)) { @@ -303,7 +306,7 @@ void TilePyramid::setCacheSize(size_t size) { cache.setSize(size); } -void TilePyramid::onLowMemory() { +void TilePyramid::reduceMemoryUse() { cache.clear(); } diff --git a/src/mbgl/renderer/tile_pyramid.hpp b/src/mbgl/renderer/tile_pyramid.hpp index ad3f91bf88..2638599c38 100644 --- a/src/mbgl/renderer/tile_pyramid.hpp +++ b/src/mbgl/renderer/tile_pyramid.hpp @@ -59,7 +59,7 @@ public: std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const; void setCacheSize(size_t); - void onLowMemory(); + void reduceMemoryUse(); void setObserver(TileObserver*); void dumpDebugLogs() const; diff --git a/src/mbgl/shaders/collision_circle.cpp b/src/mbgl/shaders/collision_circle.cpp index f220586245..82ebbf05a0 100644 --- a/src/mbgl/shaders/collision_circle.cpp +++ b/src/mbgl/shaders/collision_circle.cpp @@ -26,7 +26,10 @@ varying vec2 v_extrude_scale; void main() { vec4 projectedPoint = u_matrix * vec4(a_anchor_pos, 0, 1); highp float camera_to_anchor_distance = projectedPoint.w; - highp float collision_perspective_ratio = 0.5 + 0.5 * (u_camera_to_center_distance / camera_to_anchor_distance); + highp float collision_perspective_ratio = clamp( + 0.5 + 0.5 * (u_camera_to_center_distance / camera_to_anchor_distance), + 0.0, // Prevents oversized near-field circles in pitched/overzoomed tiles + 4.0); gl_Position = u_matrix * vec4(a_pos, 0.0, 1.0); @@ -43,6 +46,7 @@ void main() { )MBGL_SHADER"; const char* collision_circle::fragmentSource = R"MBGL_SHADER( +uniform float u_overscale_factor; varying float v_placed; varying float v_notUsed; @@ -68,7 +72,7 @@ void main() { float extrude_scale_length = length(v_extrude_scale); float extrude_length = length(v_extrude) * extrude_scale_length; - float stroke_width = 15.0 * extrude_scale_length; + float stroke_width = 15.0 * extrude_scale_length / u_overscale_factor; float radius = v_radius * extrude_scale_length; float distance_to_edge = abs(extrude_length - radius); diff --git a/src/mbgl/shaders/heatmap.cpp b/src/mbgl/shaders/heatmap.cpp new file mode 100644 index 0000000000..19927cfcc6 --- /dev/null +++ b/src/mbgl/shaders/heatmap.cpp @@ -0,0 +1,128 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/shaders/heatmap.hpp> + +namespace mbgl { +namespace shaders { + +const char* heatmap::name = "heatmap"; +const char* heatmap::vertexSource = R"MBGL_SHADER( + +#ifndef HAS_UNIFORM_u_weight +uniform lowp float a_weight_t; +attribute highp vec2 a_weight; +varying highp float weight; +#else +uniform highp float u_weight; +#endif + + +#ifndef HAS_UNIFORM_u_radius +uniform lowp float a_radius_t; +attribute mediump vec2 a_radius; +#else +uniform mediump float u_radius; +#endif + + +uniform mat4 u_matrix; +uniform float u_extrude_scale; +uniform float u_opacity; +uniform float u_intensity; + +attribute vec2 a_pos; + +varying vec2 v_extrude; + +// Effective "0" in the kernel density texture to adjust the kernel size to; +// this empirically chosen number minimizes artifacts on overlapping kernels +// for typical heatmap cases (assuming clustered source) +const highp float ZERO = 1.0 / 255.0 / 16.0; + +// Gaussian kernel coefficient: 1 / sqrt(2 * PI) +#define GAUSS_COEF 0.3989422804014327 + +void main(void) { + +#ifndef HAS_UNIFORM_u_weight + weight = unpack_mix_vec2(a_weight, a_weight_t); +#else + highp float weight = u_weight; +#endif + + +#ifndef HAS_UNIFORM_u_radius + mediump float radius = unpack_mix_vec2(a_radius, a_radius_t); +#else + mediump float radius = u_radius; +#endif + + + // unencode the extrusion vector that we snuck into the a_pos vector + vec2 unscaled_extrude = vec2(mod(a_pos, 2.0) * 2.0 - 1.0); + + // This 'extrude' comes in ranging from [-1, -1], to [1, 1]. We'll use + // it to produce the vertices of a square mesh framing the point feature + // we're adding to the kernel density texture. We'll also pass it as + // a varying, so that the fragment shader can determine the distance of + // each fragment from the point feature. + // Before we do so, we need to scale it up sufficiently so that the + // kernel falls effectively to zero at the edge of the mesh. + // That is, we want to know S such that + // weight * u_intensity * GAUSS_COEF * exp(-0.5 * 3.0^2 * S^2) == ZERO + // Which solves to: + // S = sqrt(-2.0 * log(ZERO / (weight * u_intensity * GAUSS_COEF))) / 3.0 + float S = sqrt(-2.0 * log(ZERO / weight / u_intensity / GAUSS_COEF)) / 3.0; + + // Pass the varying in units of radius + v_extrude = S * unscaled_extrude; + + // Scale by radius and the zoom-based scale factor to produce actual + // mesh position + vec2 extrude = v_extrude * radius * u_extrude_scale; + + // multiply a_pos by 0.5, since we had it * 2 in order to sneak + // in extrusion data + vec4 pos = vec4(floor(a_pos * 0.5) + extrude, 0, 1); + + gl_Position = u_matrix * pos; +} + +)MBGL_SHADER"; +const char* heatmap::fragmentSource = R"MBGL_SHADER( + +#ifndef HAS_UNIFORM_u_weight +varying highp float weight; +#else +uniform highp float u_weight; +#endif + + +uniform highp float u_intensity; +varying vec2 v_extrude; + +// Gaussian kernel coefficient: 1 / sqrt(2 * PI) +#define GAUSS_COEF 0.3989422804014327 + +void main() { + +#ifdef HAS_UNIFORM_u_weight + highp float weight = u_weight; +#endif + + + // Kernel density estimation with a Gaussian kernel of size 5x5 + float d = -0.5 * 3.0 * 3.0 * dot(v_extrude, v_extrude); + float val = weight * u_intensity * GAUSS_COEF * exp(d); + + gl_FragColor = vec4(val, 1.0, 1.0, 1.0); + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(1.0); +#endif +} + +)MBGL_SHADER"; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/heatmap.hpp b/src/mbgl/shaders/heatmap.hpp new file mode 100644 index 0000000000..a3c64db942 --- /dev/null +++ b/src/mbgl/shaders/heatmap.hpp @@ -0,0 +1,16 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#pragma once + +namespace mbgl { +namespace shaders { + +class heatmap { +public: + static const char* name; + static const char* vertexSource; + static const char* fragmentSource; +}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/heatmap_texture.cpp b/src/mbgl/shaders/heatmap_texture.cpp new file mode 100644 index 0000000000..c5d35c48ae --- /dev/null +++ b/src/mbgl/shaders/heatmap_texture.cpp @@ -0,0 +1,42 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/shaders/heatmap_texture.hpp> + +namespace mbgl { +namespace shaders { + +const char* heatmap_texture::name = "heatmap_texture"; +const char* heatmap_texture::vertexSource = R"MBGL_SHADER( +uniform mat4 u_matrix; +uniform vec2 u_world; +attribute vec2 a_pos; +varying vec2 v_pos; + +void main() { + gl_Position = u_matrix * vec4(a_pos * u_world, 0, 1); + + v_pos.x = a_pos.x; + v_pos.y = 1.0 - a_pos.y; +} + +)MBGL_SHADER"; +const char* heatmap_texture::fragmentSource = R"MBGL_SHADER( +uniform sampler2D u_image; +uniform sampler2D u_color_ramp; +uniform float u_opacity; +varying vec2 v_pos; + +void main() { + float t = texture2D(u_image, v_pos).r; + vec4 color = texture2D(u_color_ramp, vec2(t, 0.5)); + gl_FragColor = color * u_opacity; + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(0.0); +#endif +} + +)MBGL_SHADER"; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/heatmap_texture.hpp b/src/mbgl/shaders/heatmap_texture.hpp new file mode 100644 index 0000000000..c51dc6b178 --- /dev/null +++ b/src/mbgl/shaders/heatmap_texture.hpp @@ -0,0 +1,16 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#pragma once + +namespace mbgl { +namespace shaders { + +class heatmap_texture { +public: + static const char* name; + static const char* vertexSource; + static const char* fragmentSource; +}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/hillshade_prepare.cpp b/src/mbgl/shaders/hillshade_prepare.cpp index 733658435e..8d0571f6a4 100644 --- a/src/mbgl/shaders/hillshade_prepare.cpp +++ b/src/mbgl/shaders/hillshade_prepare.cpp @@ -29,6 +29,7 @@ uniform sampler2D u_image; varying vec2 v_pos; uniform vec2 u_dimension; uniform float u_zoom; +uniform float u_maxzoom; float getElevation(vec2 coord, float bias) { // Convert encoded elevation value to meters @@ -71,16 +72,16 @@ void main() { // which can be reduced to: pow(2, 19.25619978527 - u_zoom) // we want to vertically exaggerate the hillshading though, because otherwise // it is barely noticeable at low zooms. to do this, we multiply this by some - // scale factor pow(2, (u_zoom - 14) * a) where a is an arbitrary value and 14 is the - // maxzoom of the tile source. here we use a=0.3 which works out to the - // expression below. see nickidlugash's awesome breakdown for more info + // scale factor pow(2, (u_zoom - u_maxzoom) * a) where a is an arbitrary value + // Here we use a=0.3 which works out to the expression below. see + // nickidlugash's awesome breakdown for more info // https://github.com/mapbox/mapbox-gl-js/pull/5286#discussion_r148419556 float exaggeration = u_zoom < 2.0 ? 0.4 : u_zoom < 4.5 ? 0.35 : 0.3; vec2 deriv = vec2( (c + f + f + i) - (a + d + d + g), (g + h + h + i) - (a + b + b + c) - ) / pow(2.0, (u_zoom - 14.0) * exaggeration + 19.2562 - u_zoom); + ) / pow(2.0, (u_zoom - u_maxzoom) * exaggeration + 19.2562 - u_zoom); gl_FragColor = clamp(vec4( deriv.x / 2.0 + 0.5, diff --git a/src/mbgl/style/conversion/layer.cpp b/src/mbgl/style/conversion/layer.cpp index ad6998341d..19472bc8d6 100644 --- a/src/mbgl/style/conversion/layer.cpp +++ b/src/mbgl/style/conversion/layer.cpp @@ -6,6 +6,7 @@ #include <mbgl/style/layers/circle_layer.hpp> #include <mbgl/style/layers/fill_layer.hpp> #include <mbgl/style/layers/fill_extrusion_layer.hpp> +#include <mbgl/style/layers/heatmap_layer.hpp> #include <mbgl/style/layers/hillshade_layer.hpp> #include <mbgl/style/layers/line_layer.hpp> #include <mbgl/style/layers/raster_layer.hpp> @@ -165,6 +166,8 @@ optional<std::unique_ptr<Layer>> Converter<std::unique_ptr<Layer>>::operator()(c converted = convertVectorLayer<SymbolLayer>(*id, value, error); } else if (*type == "raster") { converted = convertRasterLayer(*id, value, error); + } else if (*type == "heatmap") { + converted = convertVectorLayer<HeatmapLayer>(*id, value, error); } else if (*type == "hillshade") { converted = convertHillshadeLayer(*id, value, error); } else if (*type == "background") { diff --git a/src/mbgl/style/conversion/make_property_setters.hpp b/src/mbgl/style/conversion/make_property_setters.hpp index adfcc4dd61..25c8fdb1ca 100644 --- a/src/mbgl/style/conversion/make_property_setters.hpp +++ b/src/mbgl/style/conversion/make_property_setters.hpp @@ -8,6 +8,7 @@ #include <mbgl/style/layers/line_layer.hpp> #include <mbgl/style/layers/symbol_layer.hpp> #include <mbgl/style/layers/circle_layer.hpp> +#include <mbgl/style/layers/heatmap_layer.hpp> #include <mbgl/style/layers/fill_extrusion_layer.hpp> #include <mbgl/style/layers/raster_layer.hpp> #include <mbgl/style/layers/hillshade_layer.hpp> @@ -72,6 +73,7 @@ inline auto makeLayoutPropertySetters() { + return result; } @@ -166,6 +168,17 @@ inline auto makePaintPropertySetters() { result["circle-stroke-opacity"] = &setProperty<CircleLayer, DataDrivenPropertyValue<float>, &CircleLayer::setCircleStrokeOpacity>; result["circle-stroke-opacity-transition"] = &setTransition<CircleLayer, &CircleLayer::setCircleStrokeOpacityTransition>; + result["heatmap-radius"] = &setProperty<HeatmapLayer, DataDrivenPropertyValue<float>, &HeatmapLayer::setHeatmapRadius>; + result["heatmap-radius-transition"] = &setTransition<HeatmapLayer, &HeatmapLayer::setHeatmapRadiusTransition>; + result["heatmap-weight"] = &setProperty<HeatmapLayer, DataDrivenPropertyValue<float>, &HeatmapLayer::setHeatmapWeight>; + result["heatmap-weight-transition"] = &setTransition<HeatmapLayer, &HeatmapLayer::setHeatmapWeightTransition>; + result["heatmap-intensity"] = &setProperty<HeatmapLayer, PropertyValue<float>, &HeatmapLayer::setHeatmapIntensity>; + result["heatmap-intensity-transition"] = &setTransition<HeatmapLayer, &HeatmapLayer::setHeatmapIntensityTransition>; + result["heatmap-color"] = &setProperty<HeatmapLayer, HeatmapColorPropertyValue, &HeatmapLayer::setHeatmapColor>; + result["heatmap-color-transition"] = &setTransition<HeatmapLayer, &HeatmapLayer::setHeatmapColorTransition>; + result["heatmap-opacity"] = &setProperty<HeatmapLayer, PropertyValue<float>, &HeatmapLayer::setHeatmapOpacity>; + result["heatmap-opacity-transition"] = &setTransition<HeatmapLayer, &HeatmapLayer::setHeatmapOpacityTransition>; + result["fill-extrusion-opacity"] = &setProperty<FillExtrusionLayer, PropertyValue<float>, &FillExtrusionLayer::setFillExtrusionOpacity>; result["fill-extrusion-opacity-transition"] = &setTransition<FillExtrusionLayer, &FillExtrusionLayer::setFillExtrusionOpacityTransition>; result["fill-extrusion-color"] = &setProperty<FillExtrusionLayer, DataDrivenPropertyValue<Color>, &FillExtrusionLayer::setFillExtrusionColor>; diff --git a/src/mbgl/style/conversion/property_setter.hpp b/src/mbgl/style/conversion/property_setter.hpp index 9e382b9c38..e3716a18dc 100644 --- a/src/mbgl/style/conversion/property_setter.hpp +++ b/src/mbgl/style/conversion/property_setter.hpp @@ -5,6 +5,7 @@ #include <mbgl/style/conversion/constant.hpp> #include <mbgl/style/conversion/property_value.hpp> #include <mbgl/style/conversion/data_driven_property_value.hpp> +#include <mbgl/style/conversion/heatmap_color_property_value.hpp> #include <mbgl/style/conversion/transition_options.hpp> #include <string> diff --git a/src/mbgl/style/conversion/tileset.cpp b/src/mbgl/style/conversion/tileset.cpp index 6e559c0cac..6d89cef944 100644 --- a/src/mbgl/style/conversion/tileset.cpp +++ b/src/mbgl/style/conversion/tileset.cpp @@ -6,7 +6,7 @@ namespace style { namespace conversion { bool validateLatitude(const double lat) { - return lat < 90 && lat > -90; + return lat <= 90 && lat >= -90; } optional<Tileset> Converter<Tileset>::operator()(const Convertible& value, Error& error) const { @@ -40,6 +40,16 @@ optional<Tileset> Converter<Tileset>::operator()(const Convertible& value, Error } } + auto encodingValue = objectMember(value, "encoding"); + if (encodingValue) { + optional<std::string> encoding = toString(*encodingValue); + if (encoding && *encoding == "terrarium") { + result.encoding = Tileset::DEMEncoding::Terrarium; + } else if (encoding && *encoding != "mapbox") { + error = { "invalid raster-dem encoding type - valid types are 'mapbox' and 'terrarium' " }; + } + } + auto minzoomValue = objectMember(value, "minzoom"); if (minzoomValue) { optional<float> minzoom = toNumber(*minzoomValue); diff --git a/src/mbgl/style/expression/array_assertion.cpp b/src/mbgl/style/expression/array_assertion.cpp index 29f6a47b10..4049301b0b 100644 --- a/src/mbgl/style/expression/array_assertion.cpp +++ b/src/mbgl/style/expression/array_assertion.cpp @@ -81,6 +81,25 @@ ParseResult ArrayAssertion::parse(const Convertible& value, ParsingContext& ctx) )); } +mbgl::Value ArrayAssertion::serialize() const { + std::vector<mbgl::Value> serialized; + serialized.emplace_back(getOperator()); + + + const auto array = getType().get<type::Array>(); + if (array.itemType.is<type::StringType>() + || array.itemType.is<type::NumberType>() + || array.itemType.is<type::BooleanType>()) { + serialized.emplace_back(type::toString(array.itemType)); + if (array.N) { + serialized.emplace_back(uint64_t(*array.N)); + } + } + + serialized.emplace_back(input->serialize()); + return serialized; +} + } // namespace expression } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/expression/assertion.cpp b/src/mbgl/style/expression/assertion.cpp index 0187921af9..d6f3f1b584 100644 --- a/src/mbgl/style/expression/assertion.cpp +++ b/src/mbgl/style/expression/assertion.cpp @@ -35,6 +35,10 @@ ParseResult Assertion::parse(const Convertible& value, ParsingContext& ctx) { return ParseResult(std::make_unique<Assertion>(it->second, std::move(parsed))); } +std::string Assertion::getOperator() const { + return type::toString(getType()); +} + EvaluationResult Assertion::evaluate(const EvaluationContext& params) const { for (std::size_t i = 0; i < inputs.size(); i++) { EvaluationResult value = inputs[i]->evaluate(params); diff --git a/src/mbgl/style/expression/coercion.cpp b/src/mbgl/style/expression/coercion.cpp index 56ab33fcfd..d9cd3ffdc9 100644 --- a/src/mbgl/style/expression/coercion.cpp +++ b/src/mbgl/style/expression/coercion.cpp @@ -81,6 +81,13 @@ Coercion::Coercion(type::Type type_, std::vector<std::unique_ptr<Expression>> in } } +std::string Coercion::getOperator() const { + return getType().match( + [](const type::NumberType&) { return "to-number"; }, + [](const type::ColorType&) { return "to-color"; }, + [](const auto&) { assert(false); return ""; }); +} + using namespace mbgl::style::conversion; ParseResult Coercion::parse(const Convertible& value, ParsingContext& ctx) { static std::unordered_map<std::string, type::Type> types { diff --git a/src/mbgl/style/expression/compound_expression.cpp b/src/mbgl/style/expression/compound_expression.cpp index 42cb655024..86d968c521 100644 --- a/src/mbgl/style/expression/compound_expression.cpp +++ b/src/mbgl/style/expression/compound_expression.cpp @@ -42,20 +42,19 @@ template <class R, class... Params> struct Signature<R (Params...)> : SignatureBase { using Args = std::array<std::unique_ptr<Expression>, sizeof...(Params)>; - Signature(R (*evaluate_)(Params...)) : + Signature(R (*evaluate_)(Params...), std::string name_) : SignatureBase( valueTypeToExpressionType<std::decay_t<typename R::Value>>(), - std::vector<type::Type> {valueTypeToExpressionType<std::decay_t<Params>>()...} + std::vector<type::Type> {valueTypeToExpressionType<std::decay_t<Params>>()...}, + std::move(name_) ), - evaluate(evaluate_) - {} + evaluate(evaluate_) {} EvaluationResult apply(const EvaluationContext& evaluationParameters, const Args& args) const { return applyImpl(evaluationParameters, args, std::index_sequence_for<Params...>{}); } - std::unique_ptr<Expression> makeExpression(const std::string& name, - std::vector<std::unique_ptr<Expression>> args) const override { + std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override { typename Signature::Args argsArray; std::copy_n(std::make_move_iterator(args.begin()), sizeof...(Params), argsArray.begin()); return std::make_unique<CompoundExpression<Signature>>(name, *this, std::move(argsArray)); @@ -80,16 +79,16 @@ template <class R, typename T> struct Signature<R (const Varargs<T>&)> : SignatureBase { using Args = std::vector<std::unique_ptr<Expression>>; - Signature(R (*evaluate_)(const Varargs<T>&)) : + Signature(R (*evaluate_)(const Varargs<T>&), std::string name_) : SignatureBase( valueTypeToExpressionType<std::decay_t<typename R::Value>>(), - VarargsType { valueTypeToExpressionType<T>() } + VarargsType { valueTypeToExpressionType<T>() }, + std::move(name_) ), evaluate(evaluate_) {} - std::unique_ptr<Expression> makeExpression(const std::string& name, - std::vector<std::unique_ptr<Expression>> args) const override { + std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override { return std::make_unique<CompoundExpression<Signature>>(name, *this, std::move(args)); }; @@ -115,16 +114,16 @@ template <class R, class... Params> struct Signature<R (const EvaluationContext&, Params...)> : SignatureBase { using Args = std::array<std::unique_ptr<Expression>, sizeof...(Params)>; - Signature(R (*evaluate_)(const EvaluationContext&, Params...)) : + Signature(R (*evaluate_)(const EvaluationContext&, Params...), std::string name_) : SignatureBase( valueTypeToExpressionType<std::decay_t<typename R::Value>>(), - std::vector<type::Type> {valueTypeToExpressionType<std::decay_t<Params>>()...} + std::vector<type::Type> {valueTypeToExpressionType<std::decay_t<Params>>()...}, + std::move(name_) ), evaluate(evaluate_) {} - std::unique_ptr<Expression> makeExpression(const std::string& name, - std::vector<std::unique_ptr<Expression>> args) const override { + std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override { typename Signature::Args argsArray; std::copy_n(std::make_move_iterator(args.begin()), sizeof...(Params), argsArray.begin()); return std::make_unique<CompoundExpression<Signature>>(name, *this, std::move(argsArray)); @@ -176,14 +175,14 @@ struct Signature<Lambda, std::enable_if_t<std::is_class<Lambda>::value>> using Definition = CompoundExpressionRegistry::Definition; template <typename Fn> -static std::unique_ptr<detail::SignatureBase> makeSignature(Fn evaluateFunction) { - return std::make_unique<detail::Signature<Fn>>(evaluateFunction); +static std::unique_ptr<detail::SignatureBase> makeSignature(Fn evaluateFunction, std::string name) { + return std::make_unique<detail::Signature<Fn>>(evaluateFunction, std::move(name)); } std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initializeDefinitions() { std::unordered_map<std::string, CompoundExpressionRegistry::Definition> definitions; auto define = [&](std::string name, auto fn) { - definitions[name].push_back(makeSignature(fn)); + definitions[name].push_back(makeSignature(fn, name)); }; define("e", []() -> Result<double> { return 2.718281828459045; }); @@ -461,7 +460,7 @@ ParseResult parseCompoundExpression(const std::string name, const Convertible& v } args.push_back(std::move(*parsed)); } - return createCompoundExpression(name, definition, std::move(args), ctx); + return createCompoundExpression(definition, std::move(args), ctx); } @@ -469,12 +468,11 @@ ParseResult createCompoundExpression(const std::string& name, std::vector<std::unique_ptr<Expression>> args, ParsingContext& ctx) { - return createCompoundExpression(name, CompoundExpressionRegistry::definitions.at(name), std::move(args), ctx); + return createCompoundExpression(CompoundExpressionRegistry::definitions.at(name), std::move(args), ctx); } -ParseResult createCompoundExpression(const std::string& name, - const Definition& definition, +ParseResult createCompoundExpression(const Definition& definition, std::vector<std::unique_ptr<Expression>> args, ParsingContext& ctx) { @@ -512,7 +510,7 @@ ParseResult createCompoundExpression(const std::string& name, } if (signatureContext.getErrors().size() == 0) { - return ParseResult(signature->makeExpression(name, std::move(args))); + return ParseResult(signature->makeExpression(std::move(args))); } } diff --git a/src/mbgl/style/expression/interpolate.cpp b/src/mbgl/style/expression/interpolate.cpp index 4cb22a3e4f..30b2cba81b 100644 --- a/src/mbgl/style/expression/interpolate.cpp +++ b/src/mbgl/style/expression/interpolate.cpp @@ -216,6 +216,30 @@ std::vector<optional<Value>> InterpolateBase::possibleOutputs() const { return result; } +template <typename T> +mbgl::Value Interpolate<T>::serialize() const { + std::vector<mbgl::Value> serialized; + serialized.emplace_back(getOperator()); + + interpolator.match( + [&](const ExponentialInterpolator& exponential) { + serialized.emplace_back(std::vector<mbgl::Value>{{ std::string("exponential"), exponential.base }}); + }, + [&](const CubicBezierInterpolator& cubicBezier) { + static const std::string cubicBezierTag("cubic-bezier"); + auto p1 = cubicBezier.ub.getP1(); + auto p2 = cubicBezier.ub.getP2(); + serialized.emplace_back(std::vector<mbgl::Value>{{ cubicBezierTag, p1.first, p1.second, p2.first, p2.second }}); + } + ); + serialized.emplace_back(input->serialize()); + for (auto& entry : stops) { + serialized.emplace_back(entry.first); + serialized.emplace_back(entry.second->serialize()); + }; + return serialized; +} + } // namespace expression } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/expression/let.cpp b/src/mbgl/style/expression/let.cpp index fe48138ac3..242a995b0b 100644 --- a/src/mbgl/style/expression/let.cpp +++ b/src/mbgl/style/expression/let.cpp @@ -65,6 +65,17 @@ ParseResult Let::parse(const Convertible& value, ParsingContext& ctx) { return ParseResult(std::make_unique<Let>(std::move(bindings_), std::move(*result_))); } +mbgl::Value Let::serialize() const { + std::vector<mbgl::Value> serialized; + serialized.emplace_back(getOperator()); + for (auto entry : bindings) { + serialized.emplace_back(entry.first); + serialized.emplace_back(entry.second->serialize()); + } + serialized.emplace_back(result->serialize()); + return serialized; +} + EvaluationResult Var::evaluate(const EvaluationContext& params) const { return value->evaluate(params); } @@ -95,6 +106,10 @@ ParseResult Var::parse(const Convertible& value_, ParsingContext& ctx) { return ParseResult(std::make_unique<Var>(name_, std::move(*bindingValue))); } +mbgl::Value Var::serialize() const { + return std::vector<mbgl::Value>{{ getOperator(), name }}; +} + } // namespace expression } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/expression/literal.cpp b/src/mbgl/style/expression/literal.cpp index 7e79fcbfe6..8a63980dba 100644 --- a/src/mbgl/style/expression/literal.cpp +++ b/src/mbgl/style/expression/literal.cpp @@ -102,6 +102,14 @@ ParseResult Literal::parse(const Convertible& value, ParsingContext& ctx) { } } +mbgl::Value Literal::serialize() const { + if (getType().is<type::Array>() || getType().is<type::ObjectType>()) { + return std::vector<mbgl::Value>{{ getOperator(), *fromExpressionValue<mbgl::Value>(value) }}; + } else { + return *fromExpressionValue<mbgl::Value>(value); + } +} + } // namespace expression } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/expression/match.cpp b/src/mbgl/style/expression/match.cpp index 0b2790b688..3d41f0bdd3 100644 --- a/src/mbgl/style/expression/match.cpp +++ b/src/mbgl/style/expression/match.cpp @@ -40,6 +40,42 @@ std::vector<optional<Value>> Match<T>::possibleOutputs() const { return result; } +template <typename T> +mbgl::Value Match<T>::serialize() const { + std::vector<mbgl::Value> serialized; + serialized.emplace_back(getOperator()); + serialized.emplace_back(input->serialize()); + + // Sort so serialization has an arbitrary defined order, even though branch order doesn't affect evaluation + std::map<T, std::shared_ptr<Expression>> sortedBranches(branches.begin(), branches.end()); + + // Group branches by unique match expression to support condensed serializations + // of the form [case1, case2, ...] -> matchExpression + std::map<Expression*, size_t> outputLookup; + std::vector<std::pair<Expression*, std::vector<mbgl::Value>>> groupedByOutput; + for (auto& entry : sortedBranches) { + auto outputIndex = outputLookup.find(entry.second.get()); + if (outputIndex == outputLookup.end()) { + // First time seeing this output, add it to the end of the grouped list + outputLookup[entry.second.get()] = groupedByOutput.size(); + groupedByOutput.emplace_back(entry.second.get(), std::vector<mbgl::Value>{{entry.first}}); + } else { + // We've seen this expression before, add the label to that output's group + groupedByOutput[outputIndex->second].second.emplace_back(entry.first); + } + }; + + for (auto& entry : groupedByOutput) { + entry.second.size() == 1 + ? serialized.emplace_back(entry.second[0]) // Only a single label matches this output expression + : serialized.emplace_back(entry.second); // Array of literal labels pointing to this output expression + serialized.emplace_back(entry.first->serialize()); // The output expression itself + } + + serialized.emplace_back(otherwise->serialize()); + return serialized; +} + template<> EvaluationResult Match<std::string>::evaluate(const EvaluationContext& params) const { const EvaluationResult inputValue = input->evaluate(params); diff --git a/src/mbgl/style/expression/step.cpp b/src/mbgl/style/expression/step.cpp index 34537d48ae..ddaf9417cb 100644 --- a/src/mbgl/style/expression/step.cpp +++ b/src/mbgl/style/expression/step.cpp @@ -168,6 +168,18 @@ ParseResult Step::parse(const mbgl::style::conversion::Convertible& value, Parsi return ParseResult(std::make_unique<Step>(*outputType, std::move(*input), std::move(stops))); } +mbgl::Value Step::serialize() const { + std::vector<mbgl::Value> serialized; + serialized.emplace_back(getOperator()); + serialized.emplace_back(input->serialize()); + for (auto& entry : stops) { + if (entry.first > -std::numeric_limits<double>::infinity()) { + serialized.emplace_back(entry.first); + } + serialized.emplace_back(entry.second->serialize()); + } + return serialized; +} } // namespace expression } // namespace style diff --git a/src/mbgl/style/expression/value.cpp b/src/mbgl/style/expression/value.cpp index faa44e78aa..72779d4956 100644 --- a/src/mbgl/style/expression/value.cpp +++ b/src/mbgl/style/expression/value.cpp @@ -103,6 +103,37 @@ Value ValueConverter<mbgl::Value>::toExpressionValue(const mbgl::Value& value) { return mbgl::Value::visit(value, FromMBGLValue()); } +mbgl::Value ValueConverter<mbgl::Value>::fromExpressionValue(const Value& value) { + return value.match( + [&](const Color& color)->mbgl::Value { + return std::vector<mbgl::Value>{ + std::string("rgba"), + double(255 * color.r / color.a), + double(255 * color.g / color.a), + double(255 * color.b / color.a), + double(color.a) + }; + }, + [&](const std::vector<Value>& values)->mbgl::Value { + std::vector<mbgl::Value> converted; + converted.reserve(values.size()); + for (const Value& v : values) { + converted.emplace_back(fromExpressionValue(v)); + } + return converted; + }, + [&](const std::unordered_map<std::string, Value>& values)->mbgl::Value { + std::unordered_map<std::string, mbgl::Value> converted; + converted.reserve(values.size()); + for(const auto& entry : values) { + converted.emplace(entry.first, fromExpressionValue(entry.second)); + } + return converted; + }, + [&](const auto& a)->mbgl::Value { return a; } + ); +} + Value ValueConverter<float>::toExpressionValue(const float value) { return static_cast<double>(value); } @@ -237,7 +268,7 @@ template <> type::Type valueTypeToExpressionType<type::ErrorType>() { return typ template Value toExpressionValue(const mbgl::Value&); - +template optional<mbgl::Value> fromExpressionValue<mbgl::Value>(const Value&); // for to_rgba expression template type::Type valueTypeToExpressionType<std::array<double, 4>>(); diff --git a/src/mbgl/style/layers/heatmap_layer.cpp b/src/mbgl/style/layers/heatmap_layer.cpp new file mode 100644 index 0000000000..4989ff15f1 --- /dev/null +++ b/src/mbgl/style/layers/heatmap_layer.cpp @@ -0,0 +1,239 @@ +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. + +#include <mbgl/style/layers/heatmap_layer.hpp> +#include <mbgl/style/layers/heatmap_layer_impl.hpp> +#include <mbgl/style/layer_observer.hpp> +// for constructing default heatmap-color ramp expression from style JSON +#include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/json.hpp> +#include <mbgl/style/conversion/heatmap_color_property_value.hpp> + +namespace mbgl { +namespace style { + +HeatmapLayer::HeatmapLayer(const std::string& layerID, const std::string& sourceID) + : Layer(makeMutable<Impl>(LayerType::Heatmap, layerID, sourceID)) { +} + +HeatmapLayer::HeatmapLayer(Immutable<Impl> impl_) + : Layer(std::move(impl_)) { +} + +HeatmapLayer::~HeatmapLayer() = default; + +const HeatmapLayer::Impl& HeatmapLayer::impl() const { + return static_cast<const Impl&>(*baseImpl); +} + +Mutable<HeatmapLayer::Impl> HeatmapLayer::mutableImpl() const { + return makeMutable<Impl>(impl()); +} + +std::unique_ptr<Layer> HeatmapLayer::cloneRef(const std::string& id_) const { + auto impl_ = mutableImpl(); + impl_->id = id_; + impl_->paint = HeatmapPaintProperties::Transitionable(); + return std::make_unique<HeatmapLayer>(std::move(impl_)); +} + +void HeatmapLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const { +} + +// Source + +const std::string& HeatmapLayer::getSourceID() const { + return impl().source; +} + +void HeatmapLayer::setSourceLayer(const std::string& sourceLayer) { + auto impl_ = mutableImpl(); + impl_->sourceLayer = sourceLayer; + baseImpl = std::move(impl_); +} + +const std::string& HeatmapLayer::getSourceLayer() const { + return impl().sourceLayer; +} + +// Filter + +void HeatmapLayer::setFilter(const Filter& filter) { + auto impl_ = mutableImpl(); + impl_->filter = filter; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +const Filter& HeatmapLayer::getFilter() const { + return impl().filter; +} + +// Visibility + +void HeatmapLayer::setVisibility(VisibilityType value) { + if (value == getVisibility()) + return; + auto impl_ = mutableImpl(); + impl_->visibility = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +// Zoom range + +void HeatmapLayer::setMinZoom(float minZoom) { + auto impl_ = mutableImpl(); + impl_->minZoom = minZoom; + baseImpl = std::move(impl_); +} + +void HeatmapLayer::setMaxZoom(float maxZoom) { + auto impl_ = mutableImpl(); + impl_->maxZoom = maxZoom; + baseImpl = std::move(impl_); +} + +// Layout properties + + +// Paint properties + +DataDrivenPropertyValue<float> HeatmapLayer::getDefaultHeatmapRadius() { + return { 30 }; +} + +DataDrivenPropertyValue<float> HeatmapLayer::getHeatmapRadius() const { + return impl().paint.template get<HeatmapRadius>().value; +} + +void HeatmapLayer::setHeatmapRadius(DataDrivenPropertyValue<float> value) { + if (value == getHeatmapRadius()) + return; + auto impl_ = mutableImpl(); + impl_->paint.template get<HeatmapRadius>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +void HeatmapLayer::setHeatmapRadiusTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<HeatmapRadius>().options = options; + baseImpl = std::move(impl_); +} + +TransitionOptions HeatmapLayer::getHeatmapRadiusTransition() const { + return impl().paint.template get<HeatmapRadius>().options; +} + +DataDrivenPropertyValue<float> HeatmapLayer::getDefaultHeatmapWeight() { + return { 1 }; +} + +DataDrivenPropertyValue<float> HeatmapLayer::getHeatmapWeight() const { + return impl().paint.template get<HeatmapWeight>().value; +} + +void HeatmapLayer::setHeatmapWeight(DataDrivenPropertyValue<float> value) { + if (value == getHeatmapWeight()) + return; + auto impl_ = mutableImpl(); + impl_->paint.template get<HeatmapWeight>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +void HeatmapLayer::setHeatmapWeightTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<HeatmapWeight>().options = options; + baseImpl = std::move(impl_); +} + +TransitionOptions HeatmapLayer::getHeatmapWeightTransition() const { + return impl().paint.template get<HeatmapWeight>().options; +} + +PropertyValue<float> HeatmapLayer::getDefaultHeatmapIntensity() { + return { 1 }; +} + +PropertyValue<float> HeatmapLayer::getHeatmapIntensity() const { + return impl().paint.template get<HeatmapIntensity>().value; +} + +void HeatmapLayer::setHeatmapIntensity(PropertyValue<float> value) { + if (value == getHeatmapIntensity()) + return; + auto impl_ = mutableImpl(); + impl_->paint.template get<HeatmapIntensity>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +void HeatmapLayer::setHeatmapIntensityTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<HeatmapIntensity>().options = options; + baseImpl = std::move(impl_); +} + +TransitionOptions HeatmapLayer::getHeatmapIntensityTransition() const { + return impl().paint.template get<HeatmapIntensity>().options; +} + +HeatmapColorPropertyValue HeatmapLayer::getDefaultHeatmapColor() { + conversion::Error error; + std::string rawValue = R"JSON(["interpolate",["linear"],["heatmap-density"],0,"rgba(0, 0, 255, 0)",0.1,"royalblue",0.3,"cyan",0.5,"lime",0.7,"yellow",1,"red"])JSON"; + return *conversion::convertJSON<HeatmapColorPropertyValue>(rawValue, error); +} + +HeatmapColorPropertyValue HeatmapLayer::getHeatmapColor() const { + return impl().paint.template get<HeatmapColor>().value; +} + +void HeatmapLayer::setHeatmapColor(HeatmapColorPropertyValue value) { + if (value == getHeatmapColor()) + return; + auto impl_ = mutableImpl(); + impl_->paint.template get<HeatmapColor>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +void HeatmapLayer::setHeatmapColorTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<HeatmapColor>().options = options; + baseImpl = std::move(impl_); +} + +TransitionOptions HeatmapLayer::getHeatmapColorTransition() const { + return impl().paint.template get<HeatmapColor>().options; +} + +PropertyValue<float> HeatmapLayer::getDefaultHeatmapOpacity() { + return { 1 }; +} + +PropertyValue<float> HeatmapLayer::getHeatmapOpacity() const { + return impl().paint.template get<HeatmapOpacity>().value; +} + +void HeatmapLayer::setHeatmapOpacity(PropertyValue<float> value) { + if (value == getHeatmapOpacity()) + return; + auto impl_ = mutableImpl(); + impl_->paint.template get<HeatmapOpacity>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +void HeatmapLayer::setHeatmapOpacityTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<HeatmapOpacity>().options = options; + baseImpl = std::move(impl_); +} + +TransitionOptions HeatmapLayer::getHeatmapOpacityTransition() const { + return impl().paint.template get<HeatmapOpacity>().options; +} + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/layers/heatmap_layer_impl.cpp b/src/mbgl/style/layers/heatmap_layer_impl.cpp new file mode 100644 index 0000000000..af20888d9d --- /dev/null +++ b/src/mbgl/style/layers/heatmap_layer_impl.cpp @@ -0,0 +1,15 @@ +#include <mbgl/style/layers/heatmap_layer_impl.hpp> + +namespace mbgl { +namespace style { + +bool HeatmapLayer::Impl::hasLayoutDifference(const Layer::Impl& other) const { + assert(dynamic_cast<const HeatmapLayer::Impl*>(&other)); + const auto& impl = static_cast<const style::HeatmapLayer::Impl&>(other); + return filter != impl.filter || + visibility != impl.visibility || + paint.hasDataDrivenPropertyDifference(impl.paint); +} + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/layers/heatmap_layer_impl.hpp b/src/mbgl/style/layers/heatmap_layer_impl.hpp new file mode 100644 index 0000000000..cc27c3076a --- /dev/null +++ b/src/mbgl/style/layers/heatmap_layer_impl.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include <mbgl/style/layer_impl.hpp> +#include <mbgl/style/layers/heatmap_layer.hpp> +#include <mbgl/style/layers/heatmap_layer_properties.hpp> + +namespace mbgl { +namespace style { + +class HeatmapLayer::Impl : public Layer::Impl { +public: + using Layer::Impl::Impl; + + bool hasLayoutDifference(const Layer::Impl&) const override; + void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override; + + HeatmapPaintProperties::Transitionable paint; +}; + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/layers/heatmap_layer_properties.cpp b/src/mbgl/style/layers/heatmap_layer_properties.cpp new file mode 100644 index 0000000000..2edb839589 --- /dev/null +++ b/src/mbgl/style/layers/heatmap_layer_properties.cpp @@ -0,0 +1,9 @@ +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. + +#include <mbgl/style/layers/heatmap_layer_properties.hpp> + +namespace mbgl { +namespace style { + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/layers/heatmap_layer_properties.hpp b/src/mbgl/style/layers/heatmap_layer_properties.hpp new file mode 100644 index 0000000000..f7afa5fbeb --- /dev/null +++ b/src/mbgl/style/layers/heatmap_layer_properties.hpp @@ -0,0 +1,40 @@ +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. + +#pragma once + +#include <mbgl/style/types.hpp> +#include <mbgl/style/layout_property.hpp> +#include <mbgl/style/paint_property.hpp> +#include <mbgl/style/properties.hpp> +#include <mbgl/programs/attributes.hpp> +#include <mbgl/programs/uniforms.hpp> + +namespace mbgl { +namespace style { + +struct HeatmapRadius : DataDrivenPaintProperty<float, attributes::a_radius, uniforms::u_radius> { + static float defaultValue() { return 30; } +}; + +struct HeatmapWeight : DataDrivenPaintProperty<float, attributes::a_weight, uniforms::u_weight> { + static float defaultValue() { return 1; } +}; + +struct HeatmapIntensity : PaintProperty<float> { + static float defaultValue() { return 1; } +}; + +struct HeatmapOpacity : PaintProperty<float> { + static float defaultValue() { return 1; } +}; + +class HeatmapPaintProperties : public Properties< + HeatmapRadius, + HeatmapWeight, + HeatmapIntensity, + HeatmapColor, + HeatmapOpacity +> {}; + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs index be44bb353d..657a7f5a8a 100644 --- a/src/mbgl/style/layers/layer.cpp.ejs +++ b/src/mbgl/style/layers/layer.cpp.ejs @@ -8,6 +8,12 @@ #include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer.hpp> #include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer_impl.hpp> #include <mbgl/style/layer_observer.hpp> +<% if (type === 'heatmap') { -%> +// for constructing default heatmap-color ramp expression from style JSON +#include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/json.hpp> +#include <mbgl/style/conversion/heatmap_color_property_value.hpp> +<% } -%> namespace mbgl { namespace style { @@ -134,7 +140,13 @@ void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(<%- propertyV // Paint properties <% for (const property of paintProperties) { %> <%- propertyValueType(property) %> <%- camelize(type) %>Layer::getDefault<%- camelize(property.name) %>() { +<% if (property.name === 'heatmap-color') { -%> + conversion::Error error; + std::string rawValue = R"JSON(<%- JSON.stringify(property.default) %>)JSON"; + return *conversion::convertJSON<<%- propertyValueType(property)%>>(rawValue, error); +<% } else { -%> return { <%- defaultValue(property) %> }; +<% } -%> } <%- propertyValueType(property) %> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>() const { diff --git a/src/mbgl/style/layers/layer_properties.hpp.ejs b/src/mbgl/style/layers/layer_properties.hpp.ejs index cde1b80b7b..1bceb84960 100644 --- a/src/mbgl/style/layers/layer_properties.hpp.ejs +++ b/src/mbgl/style/layers/layer_properties.hpp.ejs @@ -25,6 +25,7 @@ struct <%- camelize(property.name) %> : <%- layoutPropertyType(property, type) % <% } -%> <% for (const property of paintProperties) { -%> +<% if (property.name === 'heatmap-color') continue; -%> struct <%- camelize(property.name) %> : <%- paintPropertyType(property, type) %> { static <%- evaluatedType(property) %> defaultValue() { return <%- defaultValue(property) %>; } }; diff --git a/src/mbgl/style/paint_property.hpp b/src/mbgl/style/paint_property.hpp index c4c996b3bd..195eb645a9 100644 --- a/src/mbgl/style/paint_property.hpp +++ b/src/mbgl/style/paint_property.hpp @@ -2,6 +2,7 @@ #include <mbgl/style/properties.hpp> #include <mbgl/style/property_value.hpp> +#include <mbgl/style/heatmap_color_property_value.hpp> #include <mbgl/style/data_driven_property_value.hpp> #include <mbgl/renderer/property_evaluator.hpp> #include <mbgl/renderer/cross_faded_property_evaluator.hpp> @@ -48,5 +49,27 @@ public: static constexpr bool IsDataDriven = false; }; +/* + * Special-case paint property traits for heatmap-color, needed because + * heatmap-color values do not fit into the + * Undefined | Value | {Camera,Source,Composite}Function taxonomy that applies + * to all other paint properties. + * + * These traits are provided here--despite the fact that heatmap-color + * is not used like other paint properties--to allow the parameter-pack-based + * batch evaluation of paint properties to compile properly. + */ +class HeatmapColor { +public: + using TransitionableType = Transitionable<HeatmapColorPropertyValue>; + using UnevaluatedType = Transitioning<HeatmapColorPropertyValue>; + using EvaluatorType = PropertyEvaluator<Color>; + using PossiblyEvaluatedType = Color; + using Type = Color; + static constexpr bool IsDataDriven = false; + + static Color defaultValue() { return {}; } +}; + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/style_impl.cpp b/src/mbgl/style/style_impl.cpp index f2a9c0f222..0c7f924917 100644 --- a/src/mbgl/style/style_impl.cpp +++ b/src/mbgl/style/style_impl.cpp @@ -6,6 +6,7 @@ #include <mbgl/style/layers/background_layer.hpp> #include <mbgl/style/layers/fill_layer.hpp> #include <mbgl/style/layers/fill_extrusion_layer.hpp> +#include <mbgl/style/layers/heatmap_layer.hpp> #include <mbgl/style/layers/line_layer.hpp> #include <mbgl/style/layers/circle_layer.hpp> #include <mbgl/style/layers/raster_layer.hpp> @@ -54,11 +55,6 @@ void Style::Impl::loadURL(const std::string& url_) { url = url_; styleRequest = fileSource.request(Resource::style(url), [this](Response res) { - // Once we get a fresh style, or the style is mutated, stop revalidating. - if (res.isFresh() || mutated) { - styleRequest.reset(); - } - // Don't allow a loaded, mutated style to be overwritten with a new version. if (mutated && loaded) { return; diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index 400fe79ac5..54b2b7539b 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -95,9 +95,6 @@ void Placement::placeLayerBucket( auto partiallyEvaluatedTextSize = bucket.textSizeBinder->evaluateForZoom(state.getZoom()); auto partiallyEvaluatedIconSize = bucket.iconSizeBinder->evaluateForZoom(state.getZoom()); - const bool iconWithoutText = !bucket.hasTextData() || bucket.layout.get<style::TextOptional>(); - const bool textWithoutIcon = !bucket.hasIconData() || bucket.layout.get<style::IconOptional>(); - for (auto& symbolInstance : bucket.symbolInstances) { if (seenCrossTileIDs.count(symbolInstance.crossTileID) == 0) { @@ -140,6 +137,9 @@ void Placement::placeLayerBucket( offscreen &= placed.second; } + const bool iconWithoutText = !symbolInstance.hasText || bucket.layout.get<style::TextOptional>(); + const bool textWithoutIcon = !symbolInstance.hasIcon || bucket.layout.get<style::IconOptional>(); + // combine placements for icon and text if (!iconWithoutText && !textWithoutIcon) { placeText = placeIcon = placeText && placeIcon; @@ -230,6 +230,8 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, std::set<uint32_t>& if (bucket.hasCollisionBoxData()) bucket.collisionBox.dynamicVertices.clear(); if (bucket.hasCollisionCircleData()) bucket.collisionCircle.dynamicVertices.clear(); + JointOpacityState duplicateOpacityState(false, false, true); + JointOpacityState defaultOpacityState( bucket.layout.get<style::TextAllowOverlap>(), bucket.layout.get<style::IconAllowOverlap>(), @@ -239,9 +241,12 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, std::set<uint32_t>& bool isDuplicate = seenCrossTileIDs.count(symbolInstance.crossTileID) > 0; auto it = opacities.find(symbolInstance.crossTileID); - auto opacityState = it != opacities.end() && !isDuplicate ? - it->second : - defaultOpacityState; + auto opacityState = defaultOpacityState; + if (isDuplicate) { + opacityState = duplicateOpacityState; + } else if (it != opacities.end()) { + opacityState = it->second; + } if (it == opacities.end()) { opacities.emplace(symbolInstance.crossTileID, defaultOpacityState); diff --git a/src/mbgl/tile/custom_geometry_tile.cpp b/src/mbgl/tile/custom_geometry_tile.cpp index 7c8a85c4a4..33962ad87d 100644 --- a/src/mbgl/tile/custom_geometry_tile.cpp +++ b/src/mbgl/tile/custom_geometry_tile.cpp @@ -39,7 +39,7 @@ void CustomGeometryTile::setTileData(const GeoJSON& geoJSON) { vtOptions.extent = util::EXTENT; vtOptions.buffer = ::round(scale * options.buffer); vtOptions.tolerance = scale * options.tolerance; - featureData = mapbox::geojsonvt::geoJSONToTile(geoJSON, id.canonical.z, id.canonical.x, id.canonical.y, vtOptions).features; + featureData = mapbox::geojsonvt::geoJSONToTile(geoJSON, id.canonical.z, id.canonical.x, id.canonical.y, vtOptions, options.wrap, options.clip).features; } else { setNecessity(TileNecessity::Optional); } diff --git a/src/mbgl/tile/raster_dem_tile.cpp b/src/mbgl/tile/raster_dem_tile.cpp index b270378ece..5db298cf4c 100644 --- a/src/mbgl/tile/raster_dem_tile.cpp +++ b/src/mbgl/tile/raster_dem_tile.cpp @@ -21,6 +21,7 @@ RasterDEMTile::RasterDEMTile(const OverscaledTileID& id_, worker(parameters.workerScheduler, ActorRef<RasterDEMTile>(*this, mailbox)) { + encoding = tileset.encoding; if ( id.canonical.y == 0 ){ // this tile doesn't have upper neighboring tiles so marked those as backfilled neighboringTiles = neighboringTiles | DEMTileNeighbors::NoUpper; @@ -47,7 +48,7 @@ void RasterDEMTile::setMetadata(optional<Timestamp> modified_, optional<Timestam void RasterDEMTile::setData(std::shared_ptr<const std::string> data) { pending = true; ++correlationID; - worker.invoke(&RasterDEMTileWorker::parse, data, correlationID); + worker.invoke(&RasterDEMTileWorker::parse, data, correlationID, encoding); } void RasterDEMTile::onParsed(std::unique_ptr<HillshadeBucket> result, const uint64_t resultCorrelationID) { diff --git a/src/mbgl/tile/raster_dem_tile.hpp b/src/mbgl/tile/raster_dem_tile.hpp index 68f8a91e00..0c8dd75961 100644 --- a/src/mbgl/tile/raster_dem_tile.hpp +++ b/src/mbgl/tile/raster_dem_tile.hpp @@ -94,6 +94,7 @@ private: Actor<RasterDEMTileWorker> worker; uint64_t correlationID = 0; + Tileset::DEMEncoding encoding; // Contains the Bucket object for the tile. Buckets are render // objects and they get added by tile parsing operations. diff --git a/src/mbgl/tile/raster_dem_tile_worker.cpp b/src/mbgl/tile/raster_dem_tile_worker.cpp index ed8573788f..7338e578c7 100644 --- a/src/mbgl/tile/raster_dem_tile_worker.cpp +++ b/src/mbgl/tile/raster_dem_tile_worker.cpp @@ -10,14 +10,14 @@ RasterDEMTileWorker::RasterDEMTileWorker(ActorRef<RasterDEMTileWorker>, ActorRef : parent(std::move(parent_)) { } -void RasterDEMTileWorker::parse(std::shared_ptr<const std::string> data, uint64_t correlationID) { +void RasterDEMTileWorker::parse(std::shared_ptr<const std::string> data, uint64_t correlationID, Tileset::DEMEncoding encoding) { if (!data) { parent.invoke(&RasterDEMTile::onParsed, nullptr, correlationID); // No data; empty tile. return; } try { - auto bucket = std::make_unique<HillshadeBucket>(decodeImage(*data)); + auto bucket = std::make_unique<HillshadeBucket>(decodeImage(*data), encoding); parent.invoke(&RasterDEMTile::onParsed, std::move(bucket), correlationID); } catch (...) { parent.invoke(&RasterDEMTile::onError, std::current_exception(), correlationID); diff --git a/src/mbgl/tile/raster_dem_tile_worker.hpp b/src/mbgl/tile/raster_dem_tile_worker.hpp index 14fd1f43b5..5a8222bc2d 100644 --- a/src/mbgl/tile/raster_dem_tile_worker.hpp +++ b/src/mbgl/tile/raster_dem_tile_worker.hpp @@ -1,6 +1,7 @@ #pragma once #include <mbgl/actor/actor_ref.hpp> +#include <mbgl/util/tileset.hpp> #include <memory> #include <string> @@ -13,7 +14,7 @@ class RasterDEMTileWorker { public: RasterDEMTileWorker(ActorRef<RasterDEMTileWorker>, ActorRef<RasterDEMTile>); - void parse(std::shared_ptr<const std::string> data, uint64_t correlationID); + void parse(std::shared_ptr<const std::string> data, uint64_t correlationID, Tileset::DEMEncoding encoding); private: ActorRef<RasterDEMTile> parent; diff --git a/src/mbgl/util/offscreen_texture.cpp b/src/mbgl/util/offscreen_texture.cpp index 339e74b250..03f555eae0 100644 --- a/src/mbgl/util/offscreen_texture.cpp +++ b/src/mbgl/util/offscreen_texture.cpp @@ -11,20 +11,21 @@ OffscreenTexture& OffscreenTexture::operator=(OffscreenTexture&&) = default; class OffscreenTexture::Impl { public: - Impl(gl::Context& context_, const Size size_) - : context(context_), size(std::move(size_)) { + Impl(gl::Context& context_, const Size size_, const gl::TextureType type_) + : context(context_), size(std::move(size_)), type(type_) { assert(!size.isEmpty()); } Impl(gl::Context& context_, const Size size_, - gl::Renderbuffer<gl::RenderbufferType::DepthComponent>& depth_) - : context(context_), size(std::move(size_)), depth(&depth_) { + gl::Renderbuffer<gl::RenderbufferType::DepthComponent>& depth_, + const gl::TextureType type_) + : context(context_), size(std::move(size_)), depth(&depth_), type(type_) { assert(!size.isEmpty()); } void bind() { if (!framebuffer) { - texture = context.createTexture(size, gl::TextureFormat::RGBA); + texture = context.createTexture(size, gl::TextureFormat::RGBA, 0, type); if (depth) { framebuffer = context.createFramebuffer(*texture, *depth); } else { @@ -58,18 +59,21 @@ private: optional<gl::Framebuffer> framebuffer; optional<gl::Texture> texture; gl::Renderbuffer<gl::RenderbufferType::DepthComponent>* depth = nullptr; + const gl::TextureType type; }; OffscreenTexture::OffscreenTexture(gl::Context& context, - const Size size) - : impl(std::make_unique<Impl>(context, std::move(size))) { + const Size size, + const gl::TextureType type) + : impl(std::make_unique<Impl>(context, std::move(size), type)) { assert(!size.isEmpty()); } OffscreenTexture::OffscreenTexture(gl::Context& context, const Size size, - gl::Renderbuffer<gl::RenderbufferType::DepthComponent>& renderbuffer) - : impl(std::make_unique<Impl>(context, std::move(size), renderbuffer)) { + gl::Renderbuffer<gl::RenderbufferType::DepthComponent>& renderbuffer, + const gl::TextureType type) + : impl(std::make_unique<Impl>(context, std::move(size), renderbuffer, type)) { assert(!size.isEmpty()); } diff --git a/src/mbgl/util/offscreen_texture.hpp b/src/mbgl/util/offscreen_texture.hpp index 7f7e0f0338..36f24f16d3 100644 --- a/src/mbgl/util/offscreen_texture.hpp +++ b/src/mbgl/util/offscreen_texture.hpp @@ -12,10 +12,12 @@ class Texture; class OffscreenTexture { public: OffscreenTexture(gl::Context&, - Size size = { 256, 256 }); + Size size = { 256, 256 }, + gl::TextureType type = gl::TextureType::UnsignedByte); OffscreenTexture(gl::Context&, Size size, - gl::Renderbuffer<gl::RenderbufferType::DepthComponent>&); + gl::Renderbuffer<gl::RenderbufferType::DepthComponent>&, + gl::TextureType type = gl::TextureType::UnsignedByte); ~OffscreenTexture(); OffscreenTexture(OffscreenTexture&&); OffscreenTexture& operator=(OffscreenTexture&&); diff --git a/src/mbgl/util/tile_range.hpp b/src/mbgl/util/tile_range.hpp index f630a49078..8554cfb65e 100644 --- a/src/mbgl/util/tile_range.hpp +++ b/src/mbgl/util/tile_range.hpp @@ -6,41 +6,61 @@ #include <mbgl/util/projection.hpp> namespace mbgl { - namespace util { class TileRange { public: - Range<Point<double>> range; - uint8_t z; + Range<Point<uint32_t>> range; + Range<uint8_t> zoomRange; + + // Compute the range of tiles covered by the bounds at maxZoom. + static TileRange fromLatLngBounds(const LatLngBounds& bounds, uint8_t minZoom, uint8_t maxZoom) { + if (minZoom > maxZoom) { + std::swap(minZoom, maxZoom); + } + + auto swProj = Projection::project(bounds.southwest().wrapped(), maxZoom); + auto ne = bounds.northeast(); + auto neProj = Projection::project(ne.longitude() > util::LONGITUDE_MAX ? ne.wrapped() : ne , maxZoom); + + const auto maxTile = std::pow(2.0, maxZoom); + const auto minX = static_cast<uint32_t>(std::floor(swProj.x)); + const auto maxX = static_cast<uint32_t>(std::floor(neProj.x)); + const auto minY = static_cast<uint32_t>(util::clamp(std::floor(neProj.y), 0.0 , maxTile)); + const auto maxY = static_cast<uint32_t>(util::clamp(std::floor(swProj.y), 0.0, maxTile)); + + return TileRange({ {minX, minY}, {maxX, maxY} }, {minZoom, maxZoom}); + } // Compute the range of tiles covered by the bounds. static TileRange fromLatLngBounds(const LatLngBounds& bounds, uint8_t z) { - auto swProj = Projection::project(bounds.southwest().wrapped(), z); - auto ne = bounds.northeast(); - auto neProj = Projection::project(ne.longitude() > util::LONGITUDE_MAX ? ne.wrapped() : ne , z); - const auto minX = std::floor(swProj.x); - const auto maxX = std::ceil(neProj.x); - const auto minY = std::floor(neProj.y); - const auto maxY = std::ceil(swProj.y); - return TileRange({ {minX, minY}, {maxX, maxY} }, z); + return fromLatLngBounds(bounds, z, z); } bool contains(const CanonicalTileID& tileID) { - return z == tileID.z && - (range.min.x >= range.max.x ? //For wrapped bounds - tileID.x >= range.min.x || tileID.x < range.max.x : - tileID.x < range.max.x && tileID.x >= range.min.x) && - tileID.y < range.max.y && - tileID.y >= range.min.y; + if (tileID.z <= zoomRange.max && tileID.z >= zoomRange.min) { + if (tileID.z == 0) { + return true; + } + uint8_t dz = (zoomRange.max - tileID.z); + auto x0 = range.min.x >> dz; + auto x1 = range.max.x >> dz; + auto y0 = range.min.y >> dz; + auto y1 = range.max.y >> dz; + return (range.min.x > range.max.x ? //For wrapped bounds + tileID.x >= x0 || tileID.x <= x1 : + tileID.x <= x1 && tileID.x >= x0) && + tileID.y <= y1 && + tileID.y >= y0; + } + return false; } private: - TileRange(Range<Point<double>> range_, uint8_t z_) + TileRange(Range<Point<uint32_t>> range_, Range<uint8_t> z_) : range(range_), - z(z_) { + zoomRange(z_) { } - }; } // namespace util diff --git a/src/mbgl/util/tiny_sdf.cpp b/src/mbgl/util/tiny_sdf.cpp index 60839357d5..6edcd83bc2 100644 --- a/src/mbgl/util/tiny_sdf.cpp +++ b/src/mbgl/util/tiny_sdf.cpp @@ -95,7 +95,7 @@ AlphaImage transformRasterToSDF(const AlphaImage& rasterInput, double radius, do for (uint32_t i = 0; i < size; i++) { double distance = gridOuter[i] - gridInner[i]; - sdf.data[i] = std::max(0l, std::min(255l, std::lround(255.0 - 255.0 * (distance / radius + cutoff)))); + sdf.data[i] = std::max(0l, std::min(255l, ::lround(255.0 - 255.0 * (distance / radius + cutoff)))); } return sdf; |