diff options
Diffstat (limited to 'src')
228 files changed, 6296 insertions, 4955 deletions
diff --git a/src/mbgl/algorithm/generate_clip_ids_impl.hpp b/src/mbgl/algorithm/generate_clip_ids_impl.hpp index ff8f8d3fdf..59ca66bf66 100644 --- a/src/mbgl/algorithm/generate_clip_ids_impl.hpp +++ b/src/mbgl/algorithm/generate_clip_ids_impl.hpp @@ -1,8 +1,8 @@ #pragma once #include <mbgl/algorithm/generate_clip_ids.hpp> -#include <mbgl/util/math.hpp> -#include <mbgl/platform/log.hpp> +#include <mbgl/math/log2.hpp> +#include <mbgl/util/logging.hpp> namespace mbgl { namespace algorithm { @@ -15,6 +15,10 @@ void ClipIDGenerator::update(Renderables& renderables) { for (auto it = renderables.begin(); it != end; it++) { auto& tileID = it->first; auto& renderable = it->second; + if (!renderable.used) { + continue; + } + renderable.clip = {}; Leaf leaf{ renderable.clip }; @@ -58,6 +62,9 @@ void ClipIDGenerator::update(Renderables& renderables) { uint8_t count = 1; for (auto& pair : renderables) { auto& renderable = pair.second; + if (!renderable.used) { + continue; + } renderable.clip.mask |= mask; // Assign only to clip IDs that have no value yet. diff --git a/src/mbgl/annotation/annotation_manager.cpp b/src/mbgl/annotation/annotation_manager.cpp index dbd5f1f433..f8c1c3adf7 100644 --- a/src/mbgl/annotation/annotation_manager.cpp +++ b/src/mbgl/annotation/annotation_manager.cpp @@ -20,7 +20,7 @@ const std::string AnnotationManager::SourceID = "com.mapbox.annotations"; const std::string AnnotationManager::PointLayerID = "com.mapbox.annotations.points"; AnnotationManager::AnnotationManager(float pixelRatio) - : spriteAtlas(1024, 1024, pixelRatio) { + : spriteAtlas({ 1024, 1024 }, pixelRatio) { struct NullFileSource : public FileSource { std::unique_ptr<AsyncRequest> request(const Resource&, Callback) override { @@ -232,7 +232,7 @@ void AnnotationManager::removeIcon(const std::string& name) { double AnnotationManager::getTopOffsetPixelsForIcon(const std::string& name) { auto sprite = spriteAtlas.getSprite(name); - return sprite ? -(sprite->image.height / sprite->pixelRatio) / 2 : 0; + return sprite ? -(sprite->image.size.height / sprite->pixelRatio) / 2 : 0; } } // namespace mbgl diff --git a/src/mbgl/annotation/annotation_tile.hpp b/src/mbgl/annotation/annotation_tile.hpp index d43ec82d38..bf73075992 100644 --- a/src/mbgl/annotation/annotation_tile.hpp +++ b/src/mbgl/annotation/annotation_tile.hpp @@ -31,7 +31,7 @@ public: FeatureType getType() const override { return type; } optional<Value> getValue(const std::string&) const override; - optional<FeatureIdentifier> getID() const override { return { id }; } + optional<FeatureIdentifier> getID() const override { return { static_cast<uint64_t>(id) }; } GeometryCollection getGeometries() const override { return geometries; } const AnnotationID id; diff --git a/src/mbgl/geometry/line_atlas.cpp b/src/mbgl/geometry/line_atlas.cpp index 50e82cc015..71a855b943 100644 --- a/src/mbgl/geometry/line_atlas.cpp +++ b/src/mbgl/geometry/line_atlas.cpp @@ -1,8 +1,7 @@ #include <mbgl/geometry/line_atlas.hpp> -#include <mbgl/gl/gl.hpp> #include <mbgl/gl/context.hpp> -#include <mbgl/platform/log.hpp> -#include <mbgl/platform/platform.hpp> +#include <mbgl/util/logging.hpp> +#include <mbgl/util/platform.hpp> #include <boost/functional/hash.hpp> @@ -11,10 +10,8 @@ namespace mbgl { -LineAtlas::LineAtlas(uint16_t w, uint16_t h) - : width(w), - height(h), - data(std::make_unique<char[]>(w * h)), +LineAtlas::LineAtlas(const Size size) + : image(size), dirty(true) { } @@ -40,11 +37,11 @@ LinePatternPos LineAtlas::getDashPosition(const std::vector<float>& dasharray, } LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatternCap patternCap) { - int n = patternCap == LinePatternCap::Round ? 7 : 0; - int dashheight = 2 * n + 1; + const uint8_t n = patternCap == LinePatternCap::Round ? 7 : 0; + const uint8_t dashheight = 2 * n + 1; const uint8_t offset = 128; - if (nextRow + dashheight > height) { + if (nextRow + dashheight > image.size.height) { Log::Warning(Event::OpenGL, "line atlas bitmap overflow"); return LinePatternPos(); } @@ -54,7 +51,7 @@ LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatte length += part; } - float stretch = width / length; + float stretch = image.size.width / length; float halfWidth = stretch * 0.5; // If dasharray has an odd length, both the first and last parts // are dashes and should be joined seamlessly. @@ -62,7 +59,7 @@ LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatte for (int y = -n; y <= n; y++) { int row = nextRow + n + y; - int index = width * row; + int index = image.size.width * row; float left = 0; float right = dasharray[0]; @@ -72,7 +69,7 @@ LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatte left -= dasharray.back(); } - for (int x = 0; x < width; x++) { + for (uint32_t x = 0; x < image.size.width; x++) { while (right < x / stretch) { left = right; @@ -104,13 +101,13 @@ LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatte signedDistance = int((inside ? 1 : -1) * dist); } - data[index + x] = fmax(0, fmin(255, signedDistance + offset)); + image.data[index + x] = fmax(0, fmin(255, signedDistance + offset)); } } LinePatternPos position; - position.y = (0.5 + nextRow + n) / height; - position.height = (2.0 * n) / height; + position.y = (0.5 + nextRow + n) / image.size.height; + position.height = (2.0 * n) / image.size.height; position.width = length; nextRow += dashheight; @@ -120,59 +117,24 @@ LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatte return position; } -void LineAtlas::upload(gl::Context& context, gl::TextureUnit unit) { - if (dirty) { - bind(context, unit); - } +Size LineAtlas::getSize() const { + return image.size; } -void LineAtlas::bind(gl::Context& context, gl::TextureUnit unit) { - bool first = false; +void LineAtlas::upload(gl::Context& context, gl::TextureUnit unit) { if (!texture) { - texture = context.createTexture(); - context.activeTexture = unit; - context.texture[unit] = *texture; - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)); - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); - first = true; - } else if (context.texture[unit] != *texture) { - context.activeTexture = unit; - context.texture[unit] = *texture; + texture = context.createTexture(image, unit); + } else if (dirty) { + context.updateTexture(*texture, image, unit); } - if (dirty) { - context.activeTexture = unit; - if (first) { - MBGL_CHECK_ERROR(glTexImage2D( - GL_TEXTURE_2D, // GLenum target - 0, // GLint level - GL_ALPHA, // GLint internalformat - width, // GLsizei width - height, // GLsizei height - 0, // GLint border - GL_ALPHA, // GLenum format - GL_UNSIGNED_BYTE, // GLenum type - data.get() // const GLvoid * data - )); - } else { - MBGL_CHECK_ERROR(glTexSubImage2D( - GL_TEXTURE_2D, // GLenum target - 0, // GLint level - 0, // GLint xoffset - 0, // GLint yoffset - width, // GLsizei width - height, // GLsizei height - GL_ALPHA, // GLenum format - GL_UNSIGNED_BYTE, // GLenum type - data.get() // const GLvoid *pixels - )); - } - + dirty = false; +} - dirty = false; - } +void LineAtlas::bind(gl::Context& context, gl::TextureUnit unit) { + upload(context, unit); + context.bindTexture(*texture, unit, gl::TextureFilter::Linear, gl::TextureMipMap::No, + gl::TextureWrap::Repeat, gl::TextureWrap::Clamp); } } // namespace mbgl diff --git a/src/mbgl/geometry/line_atlas.hpp b/src/mbgl/geometry/line_atlas.hpp index e974b4ff02..b1e7a670c1 100644 --- a/src/mbgl/geometry/line_atlas.hpp +++ b/src/mbgl/geometry/line_atlas.hpp @@ -1,6 +1,8 @@ #pragma once +#include <mbgl/gl/texture.hpp> #include <mbgl/gl/object.hpp> +#include <mbgl/util/image.hpp> #include <mbgl/util/optional.hpp> #include <vector> @@ -13,11 +15,12 @@ namespace gl { class Context; } // namespace gl -typedef struct { +class LinePatternPos { +public: float width; float height; float y; -} LinePatternPos; +}; enum class LinePatternCap : bool { Square = false, @@ -26,7 +29,7 @@ enum class LinePatternCap : bool { class LineAtlas { public: - LineAtlas(uint16_t width, uint16_t height); + LineAtlas(Size); ~LineAtlas(); // Binds the atlas texture to the GPU, and uploads data if it is out of date. @@ -39,14 +42,13 @@ public: LinePatternPos getDashPosition(const std::vector<float>&, LinePatternCap); LinePatternPos addDash(const std::vector<float>& dasharray, LinePatternCap); - const uint16_t width; - const uint16_t height; + Size getSize() const; private: - const std::unique_ptr<char[]> data; + const AlphaImage image; bool dirty; - mbgl::optional<gl::UniqueTexture> texture; - int nextRow = 0; + mbgl::optional<gl::Texture> texture; + uint32_t nextRow = 0; std::unordered_map<size_t, LinePatternPos> positions; }; diff --git a/src/mbgl/gl/attribute.cpp b/src/mbgl/gl/attribute.cpp new file mode 100644 index 0000000000..7432fff590 --- /dev/null +++ b/src/mbgl/gl/attribute.cpp @@ -0,0 +1,29 @@ +#include <mbgl/gl/attribute.hpp> +#include <mbgl/gl/gl.hpp> + +namespace mbgl { +namespace gl { + +AttributeLocation bindAttributeLocation(ProgramID id, AttributeLocation location, const char* name) { + MBGL_CHECK_ERROR(glBindAttribLocation(id, location, name)); + return location; +} + +void bindAttribute(AttributeLocation location, + std::size_t count, + DataType type, + std::size_t vertexSize, + std::size_t vertexOffset, + std::size_t attributeOffset) { + MBGL_CHECK_ERROR(glEnableVertexAttribArray(location)); + MBGL_CHECK_ERROR(glVertexAttribPointer( + location, + static_cast<GLint>(count), + static_cast<GLenum>(type), + GL_FALSE, + static_cast<GLsizei>(vertexSize), + reinterpret_cast<GLvoid*>(attributeOffset + (vertexSize * vertexOffset)))); +} + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/attribute.hpp b/src/mbgl/gl/attribute.hpp index 8bc474e967..e45014127b 100644 --- a/src/mbgl/gl/attribute.hpp +++ b/src/mbgl/gl/attribute.hpp @@ -1,50 +1,171 @@ #pragma once #include <mbgl/gl/types.hpp> -#include <mbgl/gl/shader.hpp> +#include <mbgl/util/ignore.hpp> +#include <mbgl/util/indexed_tuple.hpp> #include <cstddef> -#include <limits> -#include <vector> +#include <functional> namespace mbgl { namespace gl { -template <typename T, std::size_t N> +template <class Tag, class T, std::size_t N> class Attribute { public: - Attribute(const char* name, const Shader& shader) - : location(shader.getAttributeLocation(name)) {} + using Type = T[N]; - AttributeLocation location; + class State { + public: + explicit State(AttributeLocation location_) + : location(location_) {} + + AttributeLocation location; + static constexpr std::size_t count = N; + static constexpr DataType type = DataTypeOf<T>::value; + }; }; -class AttributeBinding { +#define MBGL_DEFINE_ATTRIBUTE(type_, n_, name_) \ + struct name_ : ::mbgl::gl::Attribute<name_, type_, n_> { static constexpr auto name = #name_; } + +namespace detail { + +// Attribute binding requires member offsets. The only standard way to +// obtain an offset is the offsetof macro. The offsetof macro has defined +// behavior only for standard layout types. That rules out std::tuple and +// any other solution that relies on chained inheritance. Manually implemented +// variadic specialization looks like the only solution. Fortunately, we +// only use a maximum of five attributes. + +template <class... As> +class Vertex; + +template <class A1> +class Vertex<A1> { public: - template <class Vertex, class T, std::size_t N, std::size_t O> - AttributeBinding(const T (Vertex::*)[N], const Attribute<T, N>& attribute, std::integral_constant<std::size_t, O>) - : location(attribute.location), - type(DataTypeOf<T>::value), - count(N), - offset(O) { - static_assert(std::is_standard_layout<Vertex>::value, "vertex type must use standard layout"); - static_assert(O % 4 == 0, "vertex attribute must be optimally aligned"); - static_assert(1 <= N && N <= 4, "count must be 1, 2, 3, or 4"); - static_assert(sizeof(Vertex) <= std::numeric_limits<int32_t>::max(), "vertex type is too big"); - } + typename A1::Type a1; - AttributeLocation location; - DataType type; - uint8_t count; - std::size_t offset; + using VertexType = Vertex<A1>; + static const std::size_t attributeOffsets[1]; }; -#define MBGL_MAKE_ATTRIBUTE_BINDING(Vertex, shader, name) \ - ::mbgl::gl::AttributeBinding(&Vertex::name, \ - shader.name, \ - std::integral_constant<std::size_t, offsetof(Vertex, name)>()) +template <class A1, class A2> +class Vertex<A1, A2> { +public: + typename A1::Type a1; + typename A2::Type a2; + + using VertexType = Vertex<A1, A2>; + static const std::size_t attributeOffsets[2]; +}; + +template <class A1, class A2, class A3> +class Vertex<A1, A2, A3> { +public: + typename A1::Type a1; + typename A2::Type a2; + typename A3::Type a3; + + using VertexType = Vertex<A1, A2, A3>; + static const std::size_t attributeOffsets[3]; +}; + +template <class A1, class A2, class A3, class A4> +class Vertex<A1, A2, A3, A4> { +public: + typename A1::Type a1; + typename A2::Type a2; + typename A3::Type a3; + typename A4::Type a4; + + using VertexType = Vertex<A1, A2, A3, A4>; + static const std::size_t attributeOffsets[4]; +}; + +template <class A1, class A2, class A3, class A4, class A5> +class Vertex<A1, A2, A3, A4, A5> { +public: + typename A1::Type a1; + typename A2::Type a2; + typename A3::Type a3; + typename A4::Type a4; + typename A5::Type a5; + + using VertexType = Vertex<A1, A2, A3, A4, A5>; + static const std::size_t attributeOffsets[5]; +}; -template <class Shader, class Vertex> struct AttributeBindings; +template <class A1> +const std::size_t Vertex<A1>::attributeOffsets[1] = { + offsetof(VertexType, a1) +}; + +template <class A1, class A2> +const std::size_t Vertex<A1, A2>::attributeOffsets[2] = { + offsetof(VertexType, a1), + offsetof(VertexType, a2) +}; + +template <class A1, class A2, class A3> +const std::size_t Vertex<A1, A2, A3>::attributeOffsets[3] = { + offsetof(VertexType, a1), + offsetof(VertexType, a2), + offsetof(VertexType, a3) +}; + +template <class A1, class A2, class A3, class A4> +const std::size_t Vertex<A1, A2, A3, A4>::attributeOffsets[4] = { + offsetof(VertexType, a1), + offsetof(VertexType, a2), + offsetof(VertexType, a3), + offsetof(VertexType, a4) +}; + +template <class A1, class A2, class A3, class A4, class A5> +const std::size_t Vertex<A1, A2, A3, A4, A5>::attributeOffsets[5] = { + offsetof(VertexType, a1), + offsetof(VertexType, a2), + offsetof(VertexType, a3), + offsetof(VertexType, a4), + offsetof(VertexType, a5) +}; + +} // namespace detail + +AttributeLocation bindAttributeLocation(ProgramID, AttributeLocation, const char * name); + +void bindAttribute(AttributeLocation location, + std::size_t count, + DataType type, + std::size_t vertexSize, + std::size_t vertexOffset, + std::size_t attributeOffset); + +template <class... As> +class Attributes { +public: + using State = IndexedTuple<TypeList<As...>, TypeList<typename As::State...>>; + using Vertex = detail::Vertex<As...>; + + template <class A> + static constexpr std::size_t Index = TypeIndex<A, As...>::value; + + static State state(const ProgramID& id) { + return State { typename As::State(bindAttributeLocation(id, Index<As>, As::name))... }; + } + + static std::function<void (std::size_t)> binder(const State& state) { + return [&state] (std::size_t vertexOffset) { + util::ignore({ (bindAttribute(state.template get<As>().location, + state.template get<As>().count, + state.template get<As>().type, + sizeof(Vertex), + vertexOffset, + Vertex::attributeOffsets[Index<As>]), 0)... }); + }; + } +}; } // namespace gl } // namespace mbgl diff --git a/src/mbgl/gl/color_mode.cpp b/src/mbgl/gl/color_mode.cpp new file mode 100644 index 0000000000..e838c8e2ff --- /dev/null +++ b/src/mbgl/gl/color_mode.cpp @@ -0,0 +1,44 @@ +#include <mbgl/gl/color_mode.hpp> +#include <mbgl/gl/gl.hpp> +#include <mbgl/util/traits.hpp> + +namespace mbgl { +namespace gl { + +static_assert(underlying_type(ColorMode::BlendEquation::Add) == GL_FUNC_ADD, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::BlendEquation::Subtract) == GL_FUNC_SUBTRACT, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::BlendEquation::ReverseSubtract) == GL_FUNC_REVERSE_SUBTRACT, "OpenGL enum mismatch"); + +static_assert(underlying_type(ColorMode::Zero) == GL_ZERO, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::One) == GL_ONE, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::SrcColor) == GL_SRC_COLOR, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::OneMinusSrcColor) == GL_ONE_MINUS_SRC_COLOR, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::DstColor) == GL_DST_COLOR, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::OneMinusDstColor) == GL_ONE_MINUS_DST_COLOR, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::SrcAlpha) == GL_SRC_ALPHA, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::OneMinusSrcAlpha) == GL_ONE_MINUS_SRC_ALPHA, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::DstAlpha) == GL_DST_ALPHA, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::OneMinusDstAlpha) == GL_ONE_MINUS_DST_ALPHA, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::ConstantColor) == GL_CONSTANT_COLOR, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::OneMinusConstantColor) == GL_ONE_MINUS_CONSTANT_COLOR, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::ConstantAlpha) == GL_CONSTANT_ALPHA, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::OneMinusConstantAlpha) == GL_ONE_MINUS_CONSTANT_ALPHA, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::SrcAlphaSaturate) == GL_SRC_ALPHA_SATURATE, "OpenGL enum mismatch"); + +static_assert(underlying_type(ColorMode::Zero) == GL_ZERO, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::One) == GL_ONE, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::SrcColor) == GL_SRC_COLOR, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::OneMinusSrcColor) == GL_ONE_MINUS_SRC_COLOR, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::DstColor) == GL_DST_COLOR, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::OneMinusDstColor) == GL_ONE_MINUS_DST_COLOR, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::SrcAlpha) == GL_SRC_ALPHA, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::OneMinusSrcAlpha) == GL_ONE_MINUS_SRC_ALPHA, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::DstAlpha) == GL_DST_ALPHA, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::OneMinusDstAlpha) == GL_ONE_MINUS_DST_ALPHA, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::ConstantColor) == GL_CONSTANT_COLOR, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::OneMinusConstantColor) == GL_ONE_MINUS_CONSTANT_COLOR, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::ConstantAlpha) == GL_CONSTANT_ALPHA, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::OneMinusConstantAlpha) == GL_ONE_MINUS_CONSTANT_ALPHA, "OpenGL enum mismatch"); + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/color_mode.hpp b/src/mbgl/gl/color_mode.hpp new file mode 100644 index 0000000000..e73c8737eb --- /dev/null +++ b/src/mbgl/gl/color_mode.hpp @@ -0,0 +1,95 @@ +#pragma once + +#include <mbgl/util/variant.hpp> +#include <mbgl/util/color.hpp> + +namespace mbgl { +namespace gl { + +class ColorMode { +public: + enum class BlendEquation { + Add = 0x8006, + Subtract = 0x800A, + ReverseSubtract = 0x800B + }; + + enum BlendFactor { + Zero = 0x0000, + One = 0x0001, + SrcColor = 0x0300, + OneMinusSrcColor = 0x0301, + SrcAlpha = 0x0302, + OneMinusSrcAlpha = 0x0303, + DstAlpha = 0x0304, + OneMinusDstAlpha = 0x0305, + DstColor = 0x0306, + OneMinusDstColor = 0x0307, + SrcAlphaSaturate = 0x0308, + ConstantColor = 0x8001, + OneMinusConstantColor = 0x8002, + ConstantAlpha = 0x8003, + OneMinusConstantAlpha = 0x8004 + }; + + template <BlendEquation E> + struct ConstantBlend { + static constexpr BlendEquation equation = E; + static constexpr BlendFactor srcFactor = One; + static constexpr BlendFactor dstFactor = One; + }; + + template <BlendEquation E> + struct LinearBlend { + static constexpr BlendEquation equation = E; + BlendFactor srcFactor; + BlendFactor dstFactor; + }; + + struct Replace { + static constexpr BlendEquation equation = BlendEquation::Add; + static constexpr BlendFactor srcFactor = One; + static constexpr BlendFactor dstFactor = One; + }; + + using Add = LinearBlend<BlendEquation::Add>; + using Subtract = LinearBlend<BlendEquation::Subtract>; + using ReverseSubtract = LinearBlend<BlendEquation::ReverseSubtract>; + + using BlendFunction = variant< + Replace, + Add, + Subtract, + ReverseSubtract>; + + BlendFunction blendFunction; + Color blendColor; + + struct Mask { + bool r; + bool g; + bool b; + bool a; + }; + + Mask mask; + + static ColorMode disabled() { + return ColorMode { Replace(), {}, { false, false, false, false } }; + } + + static ColorMode unblended() { + return ColorMode { Replace(), {}, { true, true, true, true } }; + } + + static ColorMode alphaBlended() { + return ColorMode { Add { One, OneMinusSrcAlpha }, {}, { true, true, true, true } }; + } +}; + +constexpr bool operator!=(const ColorMode::Mask& a, const ColorMode::Mask& b) { + return a.r != b.r || a.g != b.g || a.b != b.b || a.a != b.a; +} + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index 23b28a15df..5048ffcd66 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -3,10 +3,25 @@ #include <mbgl/gl/gl.hpp> #include <mbgl/gl/vertex_array.hpp> #include <mbgl/util/traits.hpp> +#include <mbgl/util/std.hpp> +#include <mbgl/util/logging.hpp> + +#include <cstring> namespace mbgl { namespace gl { +static_assert(underlying_type(ShaderType::Vertex) == GL_VERTEX_SHADER, "OpenGL type mismatch"); +static_assert(underlying_type(ShaderType::Fragment) == GL_FRAGMENT_SHADER, "OpenGL type mismatch"); + +static_assert(underlying_type(PrimitiveType::Points) == GL_POINTS, "OpenGL type mismatch"); +static_assert(underlying_type(PrimitiveType::Lines) == GL_LINES, "OpenGL type mismatch"); +static_assert(underlying_type(PrimitiveType::LineLoop) == GL_LINE_LOOP, "OpenGL type mismatch"); +static_assert(underlying_type(PrimitiveType::LineStrip) == GL_LINE_STRIP, "OpenGL type mismatch"); +static_assert(underlying_type(PrimitiveType::Triangles) == GL_TRIANGLES, "OpenGL type mismatch"); +static_assert(underlying_type(PrimitiveType::TriangleStrip) == GL_TRIANGLE_STRIP, "OpenGL type mismatch"); +static_assert(underlying_type(PrimitiveType::TriangleFan) == GL_TRIANGLE_FAN, "OpenGL type mismatch"); + static_assert(std::is_same<ProgramID, GLuint>::value, "OpenGL type mismatch"); static_assert(std::is_same<ShaderID, GLuint>::value, "OpenGL type mismatch"); static_assert(std::is_same<BufferID, GLuint>::value, "OpenGL type mismatch"); @@ -15,81 +30,66 @@ static_assert(std::is_same<VertexArrayID, GLuint>::value, "OpenGL type mismatch" static_assert(std::is_same<FramebufferID, GLuint>::value, "OpenGL type mismatch"); static_assert(std::is_same<RenderbufferID, GLuint>::value, "OpenGL type mismatch"); -static_assert(std::is_same<StencilValue, GLint>::value, "OpenGL type mismatch"); -static_assert(std::is_same<StencilMaskValue, GLuint>::value, "OpenGL type mismatch"); - -static_assert(underlying_type(StencilTestFunction::Never) == GL_NEVER, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestFunction::Less) == GL_LESS, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestFunction::Equal) == GL_EQUAL, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestFunction::LessEqual) == GL_LEQUAL, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestFunction::Greater) == GL_GREATER, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestFunction::NotEqual) == GL_NOTEQUAL, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestFunction::GreaterEqual) == GL_GEQUAL, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestFunction::Always) == GL_ALWAYS, "OpenGL enum mismatch"); - -static_assert(underlying_type(StencilTestOperation::Keep) == GL_KEEP, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestOperation::Zero) == GL_ZERO, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestOperation::Replace) == GL_REPLACE, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestOperation::Increment) == GL_INCR, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestOperation::IncrementWrap) == GL_INCR_WRAP, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestOperation::Decrement) == GL_DECR, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestOperation::DecrementWrap) == GL_DECR_WRAP, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestOperation::Invert) == GL_INVERT, "OpenGL enum mismatch"); - -static_assert(underlying_type(DepthTestFunction::Never) == GL_NEVER, "OpenGL enum mismatch"); -static_assert(underlying_type(DepthTestFunction::Less) == GL_LESS, "OpenGL enum mismatch"); -static_assert(underlying_type(DepthTestFunction::Equal) == GL_EQUAL, "OpenGL enum mismatch"); -static_assert(underlying_type(DepthTestFunction::LessEqual) == GL_LEQUAL, "OpenGL enum mismatch"); -static_assert(underlying_type(DepthTestFunction::Greater) == GL_GREATER, "OpenGL enum mismatch"); -static_assert(underlying_type(DepthTestFunction::NotEqual) == GL_NOTEQUAL, "OpenGL enum mismatch"); -static_assert(underlying_type(DepthTestFunction::GreaterEqual) == GL_GEQUAL, "OpenGL enum mismatch"); -static_assert(underlying_type(DepthTestFunction::Always) == GL_ALWAYS, "OpenGL enum mismatch"); - -static_assert(underlying_type(BlendSourceFactor::Zero) == GL_ZERO, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::One) == GL_ONE, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::SrcColor) == GL_SRC_COLOR, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::OneMinusSrcColor) == GL_ONE_MINUS_SRC_COLOR, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::DstColor) == GL_DST_COLOR, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::OneMinusDstColor) == GL_ONE_MINUS_DST_COLOR, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::SrcAlpha) == GL_SRC_ALPHA, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::OneMinusSrcAlpha) == GL_ONE_MINUS_SRC_ALPHA, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::DstAlpha) == GL_DST_ALPHA, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::OneMinusDstAlpha) == GL_ONE_MINUS_DST_ALPHA, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::ConstantColor) == GL_CONSTANT_COLOR, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::OneMinusConstantColor) == GL_ONE_MINUS_CONSTANT_COLOR, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::ConstantAlpha) == GL_CONSTANT_ALPHA, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::OneMinusConstantAlpha) == GL_ONE_MINUS_CONSTANT_ALPHA, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::SrcAlphaSaturate) == GL_SRC_ALPHA_SATURATE, "OpenGL enum mismatch"); - -static_assert(underlying_type(BlendDestinationFactor::Zero) == GL_ZERO, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::One) == GL_ONE, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::SrcColor) == GL_SRC_COLOR, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::OneMinusSrcColor) == GL_ONE_MINUS_SRC_COLOR, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::DstColor) == GL_DST_COLOR, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::OneMinusDstColor) == GL_ONE_MINUS_DST_COLOR, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::SrcAlpha) == GL_SRC_ALPHA, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::OneMinusSrcAlpha) == GL_ONE_MINUS_SRC_ALPHA, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::DstAlpha) == GL_DST_ALPHA, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::OneMinusDstAlpha) == GL_ONE_MINUS_DST_ALPHA, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::ConstantColor) == GL_CONSTANT_COLOR, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::OneMinusConstantColor) == GL_ONE_MINUS_CONSTANT_COLOR, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::ConstantAlpha) == GL_CONSTANT_ALPHA, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::OneMinusConstantAlpha) == GL_ONE_MINUS_CONSTANT_ALPHA, "OpenGL enum mismatch"); +static_assert(std::is_same<std::underlying_type_t<TextureFormat>, GLenum>::value, "OpenGL type mismatch"); +static_assert(underlying_type(TextureFormat::RGBA) == GL_RGBA, "OpenGL type mismatch"); +static_assert(underlying_type(TextureFormat::Alpha) == GL_ALPHA, "OpenGL type mismatch"); Context::~Context() { reset(); } -UniqueProgram Context::createProgram() { - return UniqueProgram{ MBGL_CHECK_ERROR(glCreateProgram()), { this } }; +UniqueShader Context::createShader(ShaderType type, const std::string& source) { + UniqueShader result { MBGL_CHECK_ERROR(glCreateShader(static_cast<GLenum>(type))), { this } }; + + const GLchar* sources = source.data(); + const GLsizei lengths = static_cast<GLsizei>(source.length()); + MBGL_CHECK_ERROR(glShaderSource(result, 1, &sources, &lengths)); + MBGL_CHECK_ERROR(glCompileShader(result)); + + GLint status = 0; + MBGL_CHECK_ERROR(glGetShaderiv(result, GL_COMPILE_STATUS, &status)); + if (status != 0) { + return result; + } + + GLint logLength; + MBGL_CHECK_ERROR(glGetShaderiv(result, GL_INFO_LOG_LENGTH, &logLength)); + if (logLength > 0) { + const auto log = std::make_unique<GLchar[]>(logLength); + MBGL_CHECK_ERROR(glGetShaderInfoLog(result, logLength, &logLength, log.get())); + Log::Error(Event::Shader, "Shader failed to compile: %s", log.get()); + } + + throw std::runtime_error("shader failed to compile"); } -UniqueShader Context::createVertexShader() { - return UniqueShader{ MBGL_CHECK_ERROR(glCreateShader(GL_VERTEX_SHADER)), { this } }; +UniqueProgram Context::createProgram(ShaderID vertexShader, ShaderID fragmentShader) { + UniqueProgram result { MBGL_CHECK_ERROR(glCreateProgram()), { this } }; + + MBGL_CHECK_ERROR(glAttachShader(result, vertexShader)); + MBGL_CHECK_ERROR(glAttachShader(result, fragmentShader)); + + return result; } -UniqueShader Context::createFragmentShader() { - return UniqueShader{ MBGL_CHECK_ERROR(glCreateShader(GL_FRAGMENT_SHADER)), { this } }; +void Context::linkProgram(ProgramID program_) { + MBGL_CHECK_ERROR(glLinkProgram(program_)); + + GLint status; + MBGL_CHECK_ERROR(glGetProgramiv(program_, GL_LINK_STATUS, &status)); + if (status == GL_TRUE) { + return; + } + + GLint logLength; + MBGL_CHECK_ERROR(glGetProgramiv(program_, GL_INFO_LOG_LENGTH, &logLength)); + const auto log = std::make_unique<GLchar[]>(logLength); + if (logLength > 0) { + MBGL_CHECK_ERROR(glGetProgramInfoLog(program_, logLength, &logLength, log.get())); + Log::Error(Event::Shader, "Program failed to link: %s", log.get()); + } + + throw std::runtime_error("program failed to link"); } UniqueBuffer Context::createVertexBuffer(const void* data, std::size_t size) { @@ -105,21 +105,12 @@ UniqueBuffer Context::createIndexBuffer(const void* data, std::size_t size) { BufferID id = 0; MBGL_CHECK_ERROR(glGenBuffers(1, &id)); UniqueBuffer result { std::move(id), { this } }; + vertexArrayObject = 0; elementBuffer = result; MBGL_CHECK_ERROR(glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW)); return result; } -void Context::bindAttribute(const AttributeBinding& binding, std::size_t stride, const int8_t* offset) { - MBGL_CHECK_ERROR(glEnableVertexAttribArray(binding.location)); - MBGL_CHECK_ERROR(glVertexAttribPointer(binding.location, - binding.count, - static_cast<GLenum>(binding.type), - false, - static_cast<GLsizei>(stride), - offset + binding.offset)); -} - UniqueTexture Context::createTexture() { if (pooledTextures.empty()) { pooledTextures.resize(TextureMax); @@ -131,31 +122,60 @@ UniqueTexture Context::createTexture() { return UniqueTexture{ std::move(id), { this } }; } -UniqueVertexArray Context::createVertexArray() { - VertexArrayID id = 0; - MBGL_CHECK_ERROR(gl::GenVertexArrays(1, &id)); - return UniqueVertexArray{ std::move(id), { this } }; -} - UniqueFramebuffer Context::createFramebuffer() { FramebufferID id = 0; MBGL_CHECK_ERROR(glGenFramebuffers(1, &id)); return UniqueFramebuffer{ std::move(id), { this } }; } -UniqueRenderbuffer Context::createRenderbuffer(const RenderbufferType type, - const uint16_t width, - const uint16_t height) { +UniqueRenderbuffer Context::createRenderbuffer(const RenderbufferType type, const Size size) { RenderbufferID id = 0; MBGL_CHECK_ERROR(glGenRenderbuffers(1, &id)); UniqueRenderbuffer renderbuffer{ std::move(id), { this } }; bindRenderbuffer = renderbuffer; MBGL_CHECK_ERROR( - glRenderbufferStorage(GL_RENDERBUFFER, static_cast<GLenum>(type), width, height)); + glRenderbufferStorage(GL_RENDERBUFFER, static_cast<GLenum>(type), size.width, size.height)); return renderbuffer; } +std::unique_ptr<uint8_t[]> Context::readFramebuffer(const Size size, const TextureFormat format, const bool flip) { + const size_t stride = size.width * (format == TextureFormat::RGBA ? 4 : 1); + auto data = std::make_unique<uint8_t[]>(stride * size.height); + +#if not MBGL_USE_GLES2 + // When reading data from the framebuffer, make sure that we are storing the values + // tightly packed into the buffer to avoid buffer overruns. + pixelStorePack = { 1 }; +#endif // MBGL_USE_GLES2 + + MBGL_CHECK_ERROR(glReadPixels(0, 0, size.width, size.height, static_cast<GLenum>(format), + GL_UNSIGNED_BYTE, data.get())); + + if (flip) { + auto tmp = std::make_unique<uint8_t[]>(stride); + uint8_t* rgba = data.get(); + for (int i = 0, j = size.height - 1; i < j; i++, j--) { + std::memcpy(tmp.get(), rgba + i * stride, stride); + std::memcpy(rgba + i * stride, rgba + j * stride, stride); + std::memcpy(rgba + j * stride, tmp.get(), stride); + } + } + + return data; +} + +#if not MBGL_USE_GLES2 +void Context::drawPixels(const Size size, const void* data, TextureFormat format) { + pixelStoreUnpack = { 1 }; + if (format != TextureFormat::RGBA) { + format = static_cast<TextureFormat>(GL_LUMINANCE); + } + MBGL_CHECK_ERROR(glDrawPixels(size.width, size.height, static_cast<GLenum>(GL_LUMINANCE), + GL_UNSIGNED_BYTE, data)); +} +#endif // MBGL_USE_GLES2 + namespace { void checkFramebuffer() { @@ -251,35 +271,62 @@ Framebuffer Context::createFramebuffer(const Texture& color) { } UniqueTexture -Context::createTexture(uint16_t width, uint16_t height, const void* data, TextureUnit unit) { +Context::createTexture(const Size size, const void* data, TextureFormat format, TextureUnit unit) { auto obj = createTexture(); - activeTexture = unit; - texture[unit] = obj; + updateTexture(obj, size, data, format, unit); + // 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)); MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); - MBGL_CHECK_ERROR( - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data)); return obj; } +void Context::updateTexture( + TextureID id, const Size size, const void* data, TextureFormat format, TextureUnit unit) { + activeTexture = 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, + data)); +} + void Context::bindTexture(Texture& obj, TextureUnit unit, TextureFilter filter, - TextureMipMap mipmap) { - if (filter != obj.filter || mipmap != obj.mipmap) { + TextureMipMap mipmap, + TextureWrap wrapX, + TextureWrap wrapY) { + if (filter != obj.filter || mipmap != obj.mipmap || wrapX != obj.wrapX || wrapY != obj.wrapY) { activeTexture = unit; texture[unit] = obj.texture; - MBGL_CHECK_ERROR(glTexParameteri( - GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, - filter == TextureFilter::Linear - ? (mipmap == TextureMipMap::Yes ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR) - : (mipmap == TextureMipMap::Yes ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST))); - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, - filter == TextureFilter::Linear ? GL_LINEAR : GL_NEAREST)); - obj.filter = filter; - obj.mipmap = mipmap; + + if (filter != obj.filter || mipmap != obj.mipmap) { + MBGL_CHECK_ERROR(glTexParameteri( + GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + filter == TextureFilter::Linear + ? (mipmap == TextureMipMap::Yes ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR) + : (mipmap == TextureMipMap::Yes ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST))); + MBGL_CHECK_ERROR( + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + filter == TextureFilter::Linear ? GL_LINEAR : GL_NEAREST)); + obj.filter = filter; + obj.mipmap = mipmap; + } + if (wrapX != obj.wrapX) { + + MBGL_CHECK_ERROR( + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, + wrapX == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT)); + obj.wrapX = wrapX; + } + if (wrapY != obj.wrapY) { + MBGL_CHECK_ERROR( + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, + wrapY == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT)); + obj.wrapY = wrapY; + } } else if (texture[unit] != obj.texture) { // We are checking first to avoid setting the active texture without a subsequent // texture bind. @@ -306,6 +353,7 @@ void Context::setDirtyState() { depthTest.setDirty(); depthFunc.setDirty(); blend.setDirty(); + blendEquation.setDirty(); blendFunc.setDirty(); blendColor.setDirty(); colorMask.setDirty(); @@ -316,8 +364,13 @@ void Context::setDirtyState() { lineWidth.setDirty(); activeTexture.setDirty(); #if not MBGL_USE_GLES2 + pointSize.setDirty(); pixelZoom.setDirty(); rasterPos.setDirty(); + pixelStorePack.setDirty(); + pixelStoreUnpack.setDirty(); + pixelTransferDepth.setDirty(); + pixelTransferStencil.setDirty(); #endif // MBGL_USE_GLES2 for (auto& tex : texture) { tex.setDirty(); @@ -327,6 +380,153 @@ void Context::setDirtyState() { vertexArrayObject.setDirty(); } +void Context::clear(optional<mbgl::Color> color, + optional<float> depth, + optional<int32_t> stencil) { + GLbitfield mask = 0; + + if (color) { + mask |= GL_COLOR_BUFFER_BIT; + clearColor = *color; + colorMask = { true, true, true, true }; + } + + if (depth) { + mask |= GL_DEPTH_BUFFER_BIT; + clearDepth = *depth; + depthMask = true; + } + + if (stencil) { + mask |= GL_STENCIL_BUFFER_BIT; + clearStencil = *stencil; + stencilMask = 0xFF; + } + + MBGL_CHECK_ERROR(glClear(mask)); +} + +#if not MBGL_USE_GLES2 +PrimitiveType Context::operator()(const Points& points) { + pointSize = points.pointSize; + return PrimitiveType::Points; +} +#else +PrimitiveType Context::operator()(const Points&) { + return PrimitiveType::Points; +} +#endif // MBGL_USE_GLES2 + +PrimitiveType Context::operator()(const Lines& lines) { + lineWidth = lines.lineWidth; + return PrimitiveType::Lines; +} + +PrimitiveType Context::operator()(const LineStrip& lineStrip) { + lineWidth = lineStrip.lineWidth; + return PrimitiveType::LineStrip; +} + +PrimitiveType Context::operator()(const Triangles&) { + return PrimitiveType::Triangles; +} + +PrimitiveType Context::operator()(const TriangleStrip&) { + return PrimitiveType::TriangleStrip; +} + +void Context::setDepthMode(const DepthMode& depth) { + if (depth.func == DepthMode::Always && !depth.mask) { + depthTest = false; + } else { + depthTest = true; + depthFunc = depth.func; + depthMask = depth.mask; + depthRange = depth.range; + } +} + +void Context::setStencilMode(const StencilMode& stencil) { + if (stencil.test.is<StencilMode::Always>() && !stencil.mask) { + stencilTest = false; + } else { + stencilTest = true; + stencilMask = stencil.mask; + stencilOp = { stencil.fail, stencil.depthFail, stencil.pass }; + apply_visitor([&] (const auto& test) { + stencilFunc = { test.func, stencil.ref, test.mask }; + }, stencil.test); + } +} + +void Context::setColorMode(const ColorMode& color) { + if (color.blendFunction.is<ColorMode::Replace>()) { + blend = false; + } else { + blend = true; + blendColor = color.blendColor; + apply_visitor([&] (const auto& blendFunction) { + blendEquation = ColorMode::BlendEquation(blendFunction.equation); + blendFunc = { blendFunction.srcFactor, blendFunction.dstFactor }; + }, color.blendFunction); + } + + colorMask = color.mask; +} + +void Context::draw(const Drawable& drawable) { + if (drawable.segments.empty()) { + return; + } + + PrimitiveType primitiveType = apply_visitor([&] (auto m) { return (*this)(m); }, drawable.drawMode); + + setDepthMode(drawable.depthMode); + setStencilMode(drawable.stencilMode); + setColorMode(drawable.colorMode); + + program = drawable.program; + + drawable.bindUniforms(); + + for (const auto& segment : drawable.segments) { + auto needAttributeBindings = [&] () { + if (!gl::GenVertexArrays || !gl::BindVertexArray) { + return true; + } + + if (segment.vao) { + vertexArrayObject = *segment.vao; + return false; + } + + VertexArrayID id = 0; + MBGL_CHECK_ERROR(gl::GenVertexArrays(1, &id)); + vertexArrayObject = id; + segment.vao = UniqueVertexArray(std::move(id), { this }); + + // If we are initializing a new VAO, we need to force the buffers + // to be rebound. VAOs don't inherit the existing buffer bindings. + vertexBuffer.setDirty(); + elementBuffer.setDirty(); + + return true; + }; + + if (needAttributeBindings()) { + vertexBuffer = drawable.vertexBuffer; + elementBuffer = drawable.indexBuffer; + drawable.bindAttributes(segment.vertexOffset); + } + + MBGL_CHECK_ERROR(glDrawElements( + static_cast<GLenum>(primitiveType), + static_cast<GLsizei>(segment.indexLength), + GL_UNSIGNED_SHORT, + reinterpret_cast<GLvoid*>(sizeof(uint16_t) * segment.indexOffset))); + } +} + void Context::performCleanup() { for (auto id : abandonedPrograms) { if (program == id) { diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index cf8bb2658b..093afa20ed 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -8,12 +8,21 @@ #include <mbgl/gl/framebuffer.hpp> #include <mbgl/gl/vertex_buffer.hpp> #include <mbgl/gl/index_buffer.hpp> -#include <mbgl/gl/attribute.hpp> +#include <mbgl/gl/types.hpp> +#include <mbgl/gl/draw_mode.hpp> +#include <mbgl/gl/depth_mode.hpp> +#include <mbgl/gl/stencil_mode.hpp> +#include <mbgl/gl/color_mode.hpp> +#include <mbgl/gl/segment.hpp> #include <mbgl/util/noncopyable.hpp> + +#include <functional> #include <memory> #include <vector> #include <array> +#include <string> +#include <unordered_map> namespace mbgl { @@ -27,32 +36,31 @@ class Context : private util::noncopyable { public: ~Context(); - UniqueProgram createProgram(); - UniqueShader createVertexShader(); - UniqueShader createFragmentShader(); + UniqueShader createShader(ShaderType type, const std::string& source); + UniqueProgram createProgram(ShaderID vertexShader, ShaderID fragmentShader); + void linkProgram(ProgramID); UniqueTexture createTexture(); - UniqueVertexArray createVertexArray(); - template <class V> - VertexBuffer<V> createVertexBuffer(std::vector<V>&& v) { - return VertexBuffer<V> { - v.size(), - createVertexBuffer(v.data(), v.size() * sizeof(V)) + template <class Vertex, class DrawMode> + VertexBuffer<Vertex, DrawMode> createVertexBuffer(VertexVector<Vertex, DrawMode>&& v) { + return VertexBuffer<Vertex, DrawMode> { + v.vertexSize(), + createVertexBuffer(v.data(), v.byteSize()) }; } - template <class P> - IndexBuffer<P> createIndexBuffer(std::vector<P>&& v) { - return IndexBuffer<P> { - createIndexBuffer(v.data(), v.size() * sizeof(P)) + template <class DrawMode> + IndexBuffer<DrawMode> createIndexBuffer(IndexVector<DrawMode>&& v) { + return IndexBuffer<DrawMode> { + createIndexBuffer(v.data(), v.byteSize()) }; } template <RenderbufferType type> - Renderbuffer<type> createRenderbuffer(const std::array<uint16_t, 2>& size) { + Renderbuffer<type> createRenderbuffer(const Size size) { static_assert(type == RenderbufferType::RGBA || type == RenderbufferType::DepthStencil, "invalid renderbuffer type"); - return { size, createRenderbuffer(type, size[0], size[1]) }; + return { size, createRenderbuffer(type, size) }; } Framebuffer createFramebuffer(const Renderbuffer<RenderbufferType::RGBA>&, @@ -62,30 +70,73 @@ public: const Renderbuffer<RenderbufferType::DepthStencil>&); Framebuffer createFramebuffer(const Texture&); + template <typename Image, + TextureFormat format = Image::channels == 4 ? TextureFormat::RGBA + : TextureFormat::Alpha> + Image readFramebuffer(const Size size, bool flip = true) { + static_assert(Image::channels == (format == TextureFormat::RGBA ? 4 : 1), + "image format mismatch"); + return { size, readFramebuffer(size, format, flip) }; + } + +#if not MBGL_USE_GLES2 + template <typename Image> + void drawPixels(const Image& image) { + auto format = image.channels == 4 ? TextureFormat::RGBA : TextureFormat::Alpha; + drawPixels(image.size, image.data.get(), format); + } +#endif // MBGL_USE_GLES2 + // Create a texture from an image with data. template <typename Image> Texture createTexture(const Image& image, TextureUnit unit = 0) { - return { {{ image.width, image.height }}, - createTexture(image.width, image.height, image.data.get(), unit) }; + auto format = image.channels == 4 ? TextureFormat::RGBA : TextureFormat::Alpha; + return { image.size, createTexture(image.size, image.data.get(), format, unit) }; + } + + template <typename Image> + void updateTexture(Texture& obj, const Image& image, TextureUnit unit = 0) { + auto format = image.channels == 4 ? TextureFormat::RGBA : TextureFormat::Alpha; + updateTexture(obj.texture.get(), image.size, image.data.get(), format, unit); + obj.size = image.size; } // Creates an empty texture with the specified dimensions. - Texture createTexture(const std::array<uint16_t, 2>& size, TextureUnit unit = 0) { - return { size, createTexture(size[0], size[1], nullptr, unit) }; + Texture createTexture(const Size size, + TextureFormat format = TextureFormat::RGBA, + TextureUnit unit = 0) { + return { size, createTexture(size, nullptr, format, unit) }; } void bindTexture(Texture&, TextureUnit = 0, TextureFilter = TextureFilter::Nearest, - TextureMipMap = TextureMipMap::No); - - template <class Shader, class Vertex> - void bindAttributes(const Shader& shader, const VertexBuffer<Vertex>&, const int8_t* offset) { - static_assert(std::is_same<typename Shader::VertexType, Vertex>::value, "vertex type mismatch"); - for (const auto& binding : AttributeBindings<Shader, Vertex>()(shader)) { - bindAttribute(binding, sizeof(Vertex), offset); - } - } + TextureMipMap = TextureMipMap::No, + TextureWrap wrapX = TextureWrap::Clamp, + TextureWrap wrapY = TextureWrap::Clamp); + + void clear(optional<mbgl::Color> color, + optional<float> depth, + optional<int32_t> stencil); + + struct Drawable { + DrawMode drawMode; + DepthMode depthMode; + StencilMode stencilMode; + ColorMode colorMode; + gl::ProgramID program; + gl::BufferID vertexBuffer; + gl::BufferID indexBuffer; + const std::vector<Segment>& segments; + std::function<void ()> bindUniforms; + std::function<void (std::size_t)> bindAttributes; + }; + + void draw(const Drawable&); + + void setDepthMode(const DepthMode&); + void setStencilMode(const StencilMode&); + void setColorMode(const ColorMode&); // Actually remove the objects we marked as abandoned with the above methods. // Only call this while the OpenGL context is exclusive to this thread. @@ -107,6 +158,23 @@ public: void setDirtyState(); + State<value::ActiveTexture> activeTexture; + State<value::BindFramebuffer> bindFramebuffer; + State<value::Viewport> viewport; + std::array<State<value::BindTexture>, 2> texture; + State<value::BindVertexArray> vertexArrayObject; + State<value::Program> program; + +#if not MBGL_USE_GLES2 + State<value::PixelZoom> pixelZoom; + State<value::RasterPos> rasterPos; + State<value::PixelStorePack> pixelStorePack; + State<value::PixelStoreUnpack> pixelStoreUnpack; + State<value::PixelTransferDepth> pixelTransferDepth; + State<value::PixelTransferStencil> pixelTransferStencil; +#endif // MBGL_USE_GLES2 + +private: State<value::StencilFunc> stencilFunc; State<value::StencilMask> stencilMask; State<value::StencilTest> stencilTest; @@ -116,34 +184,37 @@ public: State<value::DepthTest> depthTest; State<value::DepthFunc> depthFunc; State<value::Blend> blend; + State<value::BlendEquation> blendEquation; State<value::BlendFunc> blendFunc; State<value::BlendColor> blendColor; State<value::ColorMask> colorMask; State<value::ClearDepth> clearDepth; State<value::ClearColor> clearColor; State<value::ClearStencil> clearStencil; - State<value::Program> program; State<value::LineWidth> lineWidth; - State<value::ActiveTexture> activeTexture; - State<value::BindFramebuffer> bindFramebuffer; - State<value::Viewport> viewport; State<value::BindRenderbuffer> bindRenderbuffer; #if not MBGL_USE_GLES2 - State<value::PixelZoom> pixelZoom; - State<value::RasterPos> rasterPos; + State<value::PointSize> pointSize; #endif // MBGL_USE_GLES2 - std::array<State<value::BindTexture>, 2> texture; State<value::BindVertexBuffer> vertexBuffer; State<value::BindElementBuffer> elementBuffer; - State<value::BindVertexArray> vertexArrayObject; -private: UniqueBuffer createVertexBuffer(const void* data, std::size_t size); UniqueBuffer createIndexBuffer(const void* data, std::size_t size); - UniqueTexture createTexture(uint16_t width, uint16_t height, const void* data, TextureUnit); + UniqueTexture createTexture(Size size, const void* data, TextureFormat, TextureUnit); + void updateTexture(TextureID, Size size, const void* data, TextureFormat, TextureUnit); UniqueFramebuffer createFramebuffer(); - UniqueRenderbuffer createRenderbuffer(RenderbufferType, uint16_t width, uint16_t height); - void bindAttribute(const AttributeBinding&, std::size_t stride, const int8_t* offset); + UniqueRenderbuffer createRenderbuffer(RenderbufferType, Size size); + std::unique_ptr<uint8_t[]> readFramebuffer(Size, TextureFormat, bool flip); +#if not MBGL_USE_GLES2 + void drawPixels(Size size, const void* data, TextureFormat); +#endif // MBGL_USE_GLES2 + + PrimitiveType operator()(const Points&); + PrimitiveType operator()(const Lines&); + PrimitiveType operator()(const LineStrip&); + PrimitiveType operator()(const Triangles&); + PrimitiveType operator()(const TriangleStrip&); friend detail::ProgramDeleter; friend detail::ShaderDeleter; diff --git a/src/mbgl/gl/debugging.cpp b/src/mbgl/gl/debugging.cpp index 1d82b6afb0..8037fc5ef5 100644 --- a/src/mbgl/gl/debugging.cpp +++ b/src/mbgl/gl/debugging.cpp @@ -2,8 +2,8 @@ #include <mbgl/gl/debugging.hpp> #include <mbgl/gl/gl.hpp> #include <mbgl/gl/extension.hpp> -#include <mbgl/platform/event.hpp> -#include <mbgl/platform/log.hpp> +#include <mbgl/util/event.hpp> +#include <mbgl/util/logging.hpp> #define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 #define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 diff --git a/src/mbgl/gl/depth_mode.cpp b/src/mbgl/gl/depth_mode.cpp new file mode 100644 index 0000000000..21af75a391 --- /dev/null +++ b/src/mbgl/gl/depth_mode.cpp @@ -0,0 +1,18 @@ +#include <mbgl/gl/depth_mode.hpp> +#include <mbgl/gl/gl.hpp> +#include <mbgl/util/traits.hpp> + +namespace mbgl { +namespace gl { + +static_assert(underlying_type(DepthMode::Never) == GL_NEVER, "OpenGL enum mismatch"); +static_assert(underlying_type(DepthMode::Less) == GL_LESS, "OpenGL enum mismatch"); +static_assert(underlying_type(DepthMode::Equal) == GL_EQUAL, "OpenGL enum mismatch"); +static_assert(underlying_type(DepthMode::LessEqual) == GL_LEQUAL, "OpenGL enum mismatch"); +static_assert(underlying_type(DepthMode::Greater) == GL_GREATER, "OpenGL enum mismatch"); +static_assert(underlying_type(DepthMode::NotEqual) == GL_NOTEQUAL, "OpenGL enum mismatch"); +static_assert(underlying_type(DepthMode::GreaterEqual) == GL_GEQUAL, "OpenGL enum mismatch"); +static_assert(underlying_type(DepthMode::Always) == GL_ALWAYS, "OpenGL enum mismatch"); + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/depth_mode.hpp b/src/mbgl/gl/depth_mode.hpp new file mode 100644 index 0000000000..37617e3c34 --- /dev/null +++ b/src/mbgl/gl/depth_mode.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include <mbgl/util/range.hpp> + +namespace mbgl { +namespace gl { + +class DepthMode { +public: + enum Function { + Never = 0x0200, + Less = 0x0201, + Equal = 0x0202, + LessEqual = 0x0203, + Greater = 0x0204, + NotEqual = 0x0205, + GreaterEqual = 0x0206, + Always = 0x0207 + }; + + enum Mask : bool { + ReadOnly = false, + ReadWrite = true + }; + + Function func; + Mask mask; + Range<float> range; + + static DepthMode disabled() { + return DepthMode { Always, ReadOnly, { 0.0, 1.0 } }; + } +}; + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/draw_mode.hpp b/src/mbgl/gl/draw_mode.hpp new file mode 100644 index 0000000000..ab86d5e469 --- /dev/null +++ b/src/mbgl/gl/draw_mode.hpp @@ -0,0 +1,76 @@ +#pragma once + +#include <mbgl/gl/primitives.hpp> +#include <mbgl/util/variant.hpp> + +#include <cassert> + +namespace mbgl { +namespace gl { + +class Points { +public: + using Primitive = Point; + static constexpr std::size_t bufferGroupSize = 1; + + explicit Points(float pointSize_) : pointSize(pointSize_) {} + + float pointSize; +}; + +class Lines { +public: + using Primitive = Line; + static constexpr std::size_t bufferGroupSize = 2; + + explicit Lines(float lineWidth_) : lineWidth(lineWidth_) { + assert(lineWidth > 0); + } + + float lineWidth; +}; + +class LineStrip { +public: + // LineStrip is a form of "Line" rendering, but the element buffer + // cannot be grouped into logical elements beyond a single Point. + using Primitive = Line; + static constexpr std::size_t bufferGroupSize = 1; + + explicit LineStrip(float lineWidth_) : lineWidth(lineWidth_) { + assert(lineWidth > 0); + } + + float lineWidth; +}; + +class Triangles { +public: + using Primitive = Triangle; + static constexpr std::size_t bufferGroupSize = 3; +}; + +class TriangleStrip { +public: + // TriangleStrip is a form of "Triangle" rendering, but the element buffer + // cannot be grouped into logical elements beyond a single Point. + using Primitive = Triangle; + static constexpr std::size_t bufferGroupSize = 1; +}; + +// Special draw mode for use with VertexVector<Indexed, Vertex>, in which +// case the true draw mode is denoted by the IndexVector type. +class Indexed { +public: + static constexpr std::size_t bufferGroupSize = 1; +}; + +using DrawMode = variant< + Points, + Lines, + LineStrip, + Triangles, + TriangleStrip>; + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/extension.cpp b/src/mbgl/gl/extension.cpp index ee94e8ecfd..e6b4d9156e 100644 --- a/src/mbgl/gl/extension.cpp +++ b/src/mbgl/gl/extension.cpp @@ -4,6 +4,7 @@ #include <mutex> #include <string> #include <vector> +#include <cstring> namespace mbgl { namespace gl { @@ -26,18 +27,14 @@ static std::once_flag initializeExtensionsOnce; void InitializeExtensions(glProc (*getProcAddress)(const char*)) { std::call_once(initializeExtensionsOnce, [getProcAddress] { - const char* extensionsPtr = - reinterpret_cast<const char*>(MBGL_CHECK_ERROR(glGetString(GL_EXTENSIONS))); - - if (!extensionsPtr) - return; - - const std::string extensions = extensionsPtr; - for (auto fn : detail::extensionFunctions()) { - for (auto probe : fn.second) { - if (extensions.find(probe.first) != std::string::npos) { - *fn.first = getProcAddress(probe.second); - break; + if (const char* extensions = + reinterpret_cast<const char*>(MBGL_CHECK_ERROR(glGetString(GL_EXTENSIONS)))) { + for (auto fn : detail::extensionFunctions()) { + for (auto probe : fn.second) { + if (strstr(extensions, probe.first) != nullptr) { + *fn.first = getProcAddress(probe.second); + break; + } } } } diff --git a/src/mbgl/gl/framebuffer.hpp b/src/mbgl/gl/framebuffer.hpp index 880fed159e..91ed467b40 100644 --- a/src/mbgl/gl/framebuffer.hpp +++ b/src/mbgl/gl/framebuffer.hpp @@ -1,15 +1,14 @@ #pragma once #include <mbgl/gl/object.hpp> - -#include <array> +#include <mbgl/util/size.hpp> namespace mbgl { namespace gl { class Framebuffer { public: - std::array<uint16_t, 2> size; + Size size; gl::UniqueFramebuffer framebuffer; }; diff --git a/src/mbgl/gl/index_buffer.hpp b/src/mbgl/gl/index_buffer.hpp index f38d7fd4f5..b3610f4154 100644 --- a/src/mbgl/gl/index_buffer.hpp +++ b/src/mbgl/gl/index_buffer.hpp @@ -1,39 +1,38 @@ #pragma once #include <mbgl/gl/object.hpp> +#include <mbgl/gl/draw_mode.hpp> +#include <mbgl/util/ignore.hpp> + +#include <vector> namespace mbgl { namespace gl { -class Line { +template <class DrawMode> +class IndexVector { public: - Line(uint16_t a_, uint16_t b_) - : a(a_), b(b_) {} - - uint16_t a; - uint16_t b; + static constexpr std::size_t groupSize = DrawMode::bufferGroupSize; - static constexpr std::size_t IndexCount = 2; -}; + template <class... Args> + void emplace_back(Args&&... args) { + static_assert(sizeof...(args) == groupSize, "wrong buffer element count"); + util::ignore({(v.emplace_back(std::forward<Args>(args)), 0)...}); + } -class Triangle { -public: - Triangle(uint16_t a_, uint16_t b_, uint16_t c_) - : a(a_), b(b_), c(c_) {} + std::size_t indexSize() const { return v.size(); } + std::size_t byteSize() const { return v.size() * sizeof(uint16_t); } - uint16_t a; - uint16_t b; - uint16_t c; + bool empty() const { return v.empty(); } + const uint16_t* data() const { return v.data(); } - static constexpr std::size_t IndexCount = 3; +private: + std::vector<uint16_t> v; }; -template <class Primitive> +template <class DrawMode> class IndexBuffer { public: - static_assert(std::is_same<Primitive, Line>::value || std::is_same<Primitive, Triangle>::value, - "primitive must be Line or Triangle"); - static constexpr std::size_t primitiveSize = sizeof(Primitive); UniqueBuffer buffer; }; diff --git a/src/mbgl/gl/primitives.hpp b/src/mbgl/gl/primitives.hpp new file mode 100644 index 0000000000..fe6b1b2e5b --- /dev/null +++ b/src/mbgl/gl/primitives.hpp @@ -0,0 +1,22 @@ +#pragma once + +namespace mbgl { +namespace gl { + +class Point { +public: + static constexpr std::size_t vertexCount = 1; +}; + +class Line { +public: + static constexpr std::size_t vertexCount = 2; +}; + +class Triangle { +public: + static constexpr std::size_t vertexCount = 3; +}; + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/program.hpp b/src/mbgl/gl/program.hpp new file mode 100644 index 0000000000..33387e9d4e --- /dev/null +++ b/src/mbgl/gl/program.hpp @@ -0,0 +1,70 @@ +#pragma once + +#include <mbgl/gl/types.hpp> +#include <mbgl/gl/object.hpp> +#include <mbgl/gl/context.hpp> +#include <mbgl/gl/vertex_buffer.hpp> +#include <mbgl/gl/index_buffer.hpp> +#include <mbgl/gl/attribute.hpp> +#include <mbgl/gl/uniform.hpp> + +#include <string> + +namespace mbgl { +namespace gl { + +template <class P, class As, class Us> +class Program { +public: + using Primitive = P; + using Attributes = As; + using Uniforms = Us; + + using Vertex = typename Attributes::Vertex; + using UniformValues = typename Uniforms::Values; + + static_assert(std::is_standard_layout<Vertex>::value, "vertex type must use standard layout"); + + Program(Context& context, const std::string& vertexSource, const std::string& fragmentSource) + : vertexShader(context.createShader(ShaderType::Vertex, vertexSource)), + fragmentShader(context.createShader(ShaderType::Fragment, fragmentSource)), + program(context.createProgram(vertexShader, fragmentShader)), + attributesState(Attributes::state(program)), + uniformsState((context.linkProgram(program), Uniforms::state(program))) {} + + template <class DrawMode> + void draw(Context& context, + DrawMode drawMode, + DepthMode depthMode, + StencilMode stencilMode, + ColorMode colorMode, + UniformValues&& uniformValues, + const VertexBuffer<Vertex>& vertexBuffer, + const IndexBuffer<DrawMode>& indexBuffer, + const SegmentVector<Attributes>& segments) { + static_assert(std::is_same<Primitive, typename DrawMode::Primitive>::value, "incompatible draw mode"); + context.draw({ + std::move(drawMode), + std::move(depthMode), + std::move(stencilMode), + std::move(colorMode), + program, + vertexBuffer.buffer, + indexBuffer.buffer, + segments, + Uniforms::binder(uniformsState, std::move(uniformValues)), + Attributes::binder(attributesState) + }); + } + +private: + UniqueShader vertexShader; + UniqueShader fragmentShader; + UniqueProgram program; + + typename Attributes::State attributesState; + typename Uniforms::State uniformsState; +}; + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/renderbuffer.hpp b/src/mbgl/gl/renderbuffer.hpp index 9e8993bb77..cc8ff13268 100644 --- a/src/mbgl/gl/renderbuffer.hpp +++ b/src/mbgl/gl/renderbuffer.hpp @@ -1,8 +1,7 @@ #pragma once #include <mbgl/gl/object.hpp> - -#include <array> +#include <mbgl/util/size.hpp> namespace mbgl { namespace gl { @@ -11,7 +10,7 @@ template <RenderbufferType renderbufferType> class Renderbuffer { public: using type = std::integral_constant<RenderbufferType, renderbufferType>; - std::array<uint16_t, 2> size; + Size size; gl::UniqueRenderbuffer renderbuffer; }; diff --git a/src/mbgl/gl/segment.hpp b/src/mbgl/gl/segment.hpp new file mode 100644 index 0000000000..8f74afd237 --- /dev/null +++ b/src/mbgl/gl/segment.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include <mbgl/util/optional.hpp> + +#include <cstddef> + +namespace mbgl { +namespace gl { + +class Segment { +public: + Segment(std::size_t vertexOffset_, + std::size_t indexOffset_, + std::size_t vertexLength_ = 0, + std::size_t indexLength_ = 0) + : vertexOffset(vertexOffset_), + indexOffset(indexOffset_), + vertexLength(vertexLength_), + indexLength(indexLength_) {} + + const std::size_t vertexOffset; + const std::size_t indexOffset; + + std::size_t vertexLength; + std::size_t indexLength; + +private: + friend class Context; + mutable optional<UniqueVertexArray> vao; +}; + +template <class Attributes> +class SegmentVector : public std::vector<Segment> { +public: + SegmentVector() = default; +}; + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/shader.cpp b/src/mbgl/gl/shader.cpp deleted file mode 100644 index d8ee734567..0000000000 --- a/src/mbgl/gl/shader.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#include <mbgl/gl/shader.hpp> -#include <mbgl/gl/gl.hpp> -#include <mbgl/gl/context.hpp> -#include <mbgl/util/stopwatch.hpp> -#include <mbgl/util/exception.hpp> -#include <mbgl/platform/log.hpp> -#include <mbgl/platform/platform.hpp> - -#include <cstring> -#include <cassert> -#include <iostream> -#include <string> -#include <fstream> -#include <cstdio> -#include <cassert> - -namespace mbgl { -namespace gl { - -Shader::Shader(const char* name_, - const char* vertexSource, - const char* fragmentSource, - Context& context, - Defines defines) - : name(name_), - program(context.createProgram()), - vertexShader(context.createVertexShader()), - fragmentShader(context.createFragmentShader()) { - util::stopwatch stopwatch("shader compilation", Event::Shader); - - if (!compileShader(vertexShader, vertexSource)) { - Log::Error(Event::Shader, "Vertex shader %s failed to compile: %s", name, vertexSource); - throw util::ShaderException(std::string { "Vertex shader " } + name + " failed to compile"); - } - - std::string fragment(fragmentSource); - if (defines & Defines::Overdraw) { - assert(fragment.find("#ifdef OVERDRAW_INSPECTOR") != std::string::npos); - fragment.replace(fragment.find_first_of('\n'), 1, "\n#define OVERDRAW_INSPECTOR\n"); - } - - if (!compileShader(fragmentShader, fragment.c_str())) { - Log::Error(Event::Shader, "Fragment shader %s failed to compile: %s", name, fragmentSource); - throw util::ShaderException(std::string { "Fragment shader " } + name + " failed to compile"); - } - - // Attach shaders - MBGL_CHECK_ERROR(glAttachShader(program.get(), vertexShader.get())); - MBGL_CHECK_ERROR(glAttachShader(program.get(), fragmentShader.get())); - - // Link program - GLint status; - MBGL_CHECK_ERROR(glLinkProgram(program.get())); - - MBGL_CHECK_ERROR(glGetProgramiv(program.get(), GL_LINK_STATUS, &status)); - if (status == 0) { - GLint logLength; - MBGL_CHECK_ERROR(glGetProgramiv(program.get(), GL_INFO_LOG_LENGTH, &logLength)); - const auto log = std::make_unique<GLchar[]>(logLength); - if (logLength > 0) { - MBGL_CHECK_ERROR(glGetProgramInfoLog(program.get(), logLength, &logLength, log.get())); - Log::Error(Event::Shader, "Program failed to link: %s", log.get()); - } - throw util::ShaderException(std::string { "Program " } + name + " failed to link: " + log.get()); - } -} - -bool Shader::compileShader(UniqueShader& shader, const GLchar *source) { - GLint status = 0; - - const GLsizei lengths = static_cast<GLsizei>(std::strlen(source)); - MBGL_CHECK_ERROR(glShaderSource(shader.get(), 1, &source, &lengths)); - - MBGL_CHECK_ERROR(glCompileShader(shader.get())); - - MBGL_CHECK_ERROR(glGetShaderiv(shader.get(), GL_COMPILE_STATUS, &status)); - if (status == 0) { - GLint logLength; - MBGL_CHECK_ERROR(glGetShaderiv(shader.get(), GL_INFO_LOG_LENGTH, &logLength)); - if (logLength > 0) { - const auto log = std::make_unique<GLchar[]>(logLength); - MBGL_CHECK_ERROR(glGetShaderInfoLog(shader.get(), logLength, &logLength, log.get())); - Log::Error(Event::Shader, "Shader failed to compile: %s", log.get()); - } - return false; - } - - MBGL_CHECK_ERROR(glGetShaderiv(shader.get(), GL_COMPILE_STATUS, &status)); - if (status == GL_FALSE) { - Log::Error(Event::Shader, "Shader %s failed to compile.", name); - return false; - } - - return true; -} - -Shader::~Shader() { - if (program.get()) { - MBGL_CHECK_ERROR(glDetachShader(program.get(), vertexShader.get())); - MBGL_CHECK_ERROR(glDetachShader(program.get(), fragmentShader.get())); - } -} - -UniformLocation Shader::getUniformLocation(const char* uniform) const { - return MBGL_CHECK_ERROR(glGetUniformLocation(program.get(), uniform)); -} - -AttributeLocation Shader::getAttributeLocation(const char* attribute) const { - return MBGL_CHECK_ERROR(glGetAttribLocation(program.get(), attribute)); -} - -} // namespace gl -} // namespace mbgl diff --git a/src/mbgl/gl/shader.hpp b/src/mbgl/gl/shader.hpp deleted file mode 100644 index f88bd4f867..0000000000 --- a/src/mbgl/gl/shader.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include <mbgl/gl/types.hpp> -#include <mbgl/gl/object.hpp> -#include <mbgl/util/noncopyable.hpp> - -namespace mbgl { -namespace gl { - -class Context; - -class Shader : private util::noncopyable { -public: - ~Shader(); - const char* name; - - ProgramID getID() const { - return program.get(); - } - - AttributeLocation getAttributeLocation(const char* uniform) const; - UniformLocation getUniformLocation(const char* uniform) const; - - enum Defines : bool { - None = false, - Overdraw = true, - }; - -protected: - Shader(const char* name_, - const char* vertex, - const char* fragment, - Context&, - Defines defines = Defines::None); - -private: - bool compileShader(UniqueShader&, const char *source); - - UniqueProgram program; - UniqueShader vertexShader; - UniqueShader fragmentShader; -}; - -} // namespace gl -} // namespace mbgl diff --git a/src/mbgl/gl/stencil_mode.cpp b/src/mbgl/gl/stencil_mode.cpp new file mode 100644 index 0000000000..6858d6d106 --- /dev/null +++ b/src/mbgl/gl/stencil_mode.cpp @@ -0,0 +1,27 @@ +#include <mbgl/gl/stencil_mode.hpp> +#include <mbgl/gl/gl.hpp> +#include <mbgl/util/traits.hpp> + +namespace mbgl { +namespace gl { + +static_assert(StencilMode::Never::func == GL_NEVER, "OpenGL enum mismatch"); +static_assert(StencilMode::Less::func == GL_LESS, "OpenGL enum mismatch"); +static_assert(StencilMode::Equal::func == GL_EQUAL, "OpenGL enum mismatch"); +static_assert(StencilMode::LessEqual::func == GL_LEQUAL, "OpenGL enum mismatch"); +static_assert(StencilMode::Greater::func == GL_GREATER, "OpenGL enum mismatch"); +static_assert(StencilMode::NotEqual::func == GL_NOTEQUAL, "OpenGL enum mismatch"); +static_assert(StencilMode::GreaterEqual::func == GL_GEQUAL, "OpenGL enum mismatch"); +static_assert(StencilMode::Always::func == GL_ALWAYS, "OpenGL enum mismatch"); + +static_assert(underlying_type(StencilMode::Keep) == GL_KEEP, "OpenGL enum mismatch"); +static_assert(underlying_type(StencilMode::Zero) == GL_ZERO, "OpenGL enum mismatch"); +static_assert(underlying_type(StencilMode::Replace) == GL_REPLACE, "OpenGL enum mismatch"); +static_assert(underlying_type(StencilMode::Increment) == GL_INCR, "OpenGL enum mismatch"); +static_assert(underlying_type(StencilMode::IncrementWrap) == GL_INCR_WRAP, "OpenGL enum mismatch"); +static_assert(underlying_type(StencilMode::Decrement) == GL_DECR, "OpenGL enum mismatch"); +static_assert(underlying_type(StencilMode::DecrementWrap) == GL_DECR_WRAP, "OpenGL enum mismatch"); +static_assert(underlying_type(StencilMode::Invert) == GL_INVERT, "OpenGL enum mismatch"); + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/stencil_mode.hpp b/src/mbgl/gl/stencil_mode.hpp new file mode 100644 index 0000000000..bc959c9a73 --- /dev/null +++ b/src/mbgl/gl/stencil_mode.hpp @@ -0,0 +1,66 @@ +#pragma once + +#include <mbgl/util/variant.hpp> + +namespace mbgl { +namespace gl { + +class StencilMode { +public: + template <uint32_t F> + struct SimpleTest { + static constexpr uint32_t func = F; + static constexpr uint32_t mask = 0; + }; + + template <uint32_t F> + struct MaskedTest { + static constexpr uint32_t func = F; + uint32_t mask; + }; + + using Never = SimpleTest<0x0200>; + using Less = MaskedTest<0x0201>; + using Equal = MaskedTest<0x0202>; + using LessEqual = MaskedTest<0x0203>; + using Greater = MaskedTest<0x0204>; + using NotEqual = MaskedTest<0x0205>; + using GreaterEqual = MaskedTest<0x0206>; + using Always = SimpleTest<0x0207>; + + using Test = variant< + Never, + Less, + Equal, + LessEqual, + Greater, + NotEqual, + GreaterEqual, + Always>; + + enum Op { + Zero = 0x0000, + Keep = 0x1E00, + Replace = 0x1E01, + Increment = 0x1E02, + Decrement = 0x1E03, + Invert = 0x150A, + IncrementWrap = 0x8507, + DecrementWrap = 0x8508 + }; + + Test test; + int32_t ref; + uint32_t mask; + + Op fail; + Op depthFail; + Op pass; + + static StencilMode disabled() { + return StencilMode { Always(), 0, 0, Keep, Keep, Keep }; + } +}; + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/texture.hpp b/src/mbgl/gl/texture.hpp index 49e1323095..5330689ac2 100644 --- a/src/mbgl/gl/texture.hpp +++ b/src/mbgl/gl/texture.hpp @@ -1,18 +1,19 @@ #pragma once #include <mbgl/gl/object.hpp> - -#include <array> +#include <mbgl/util/size.hpp> namespace mbgl { namespace gl { class Texture { public: - std::array<uint16_t, 2> size; + Size size; UniqueTexture texture; TextureFilter filter = TextureFilter::Nearest; TextureMipMap mipmap = TextureMipMap::No; + TextureWrap wrapX = TextureWrap::Clamp; + TextureWrap wrapY = TextureWrap::Clamp; }; } // namespace gl diff --git a/src/mbgl/gl/types.hpp b/src/mbgl/gl/types.hpp index dccc61b03a..577629d5d3 100644 --- a/src/mbgl/gl/types.hpp +++ b/src/mbgl/gl/types.hpp @@ -19,9 +19,10 @@ using AttributeLocation = int32_t; using UniformLocation = int32_t; using TextureUnit = uint8_t; -using DepthValue = double; -using StencilValue = int32_t; -using StencilMaskValue = uint32_t; +enum class ShaderType : uint32_t { + Vertex = 0x8B31, + Fragment = 0x8B30 +}; enum class DataType : uint32_t { Byte = 0x1400, @@ -43,11 +44,6 @@ template <> struct DataTypeOf<int32_t> : std::integral_constant<DataType, DataT template <> struct DataTypeOf<uint32_t> : std::integral_constant<DataType, DataType::UnsignedInteger> {}; template <> struct DataTypeOf<float> : std::integral_constant<DataType, DataType::Float> {}; -enum class BufferType : uint32_t { - Vertex = 0x8892, - Element = 0x8893 -}; - enum class RenderbufferType : uint32_t { RGBA = 0x8058, DepthStencil = 0x88F0, @@ -55,74 +51,37 @@ enum class RenderbufferType : uint32_t { enum class TextureMipMap : bool { No = false, Yes = true }; enum class TextureFilter : bool { Nearest = false, Linear = true }; - -enum class StencilTestFunction : uint32_t { - Never = 0x0200, - Less = 0x0201, - Equal = 0x0202, - LessEqual = 0x0203, - Greater = 0x0204, - NotEqual = 0x0205, - GreaterEqual = 0x0206, - Always = 0x0207, +enum class TextureWrap : bool { Clamp, Repeat }; +enum class TextureFormat : uint32_t { + RGBA = 0x1908, + Alpha = 0x1906, +#if not MBGL_USE_GLES2 + Stencil = 0x1901, + Depth = 0x1902, +#endif // MBGL_USE_GLES2 }; -enum class StencilTestOperation : uint32_t { - Keep = 0x1E00, - Zero = 0x0000, - Replace = 0x1E01, - Increment = 0x1E02, - IncrementWrap = 0x8507, - Decrement = 0x1E03, - DecrementWrap = 0x8508, - Invert = 0x150A, +enum class PrimitiveType { + Points = 0x0000, + Lines = 0x0001, + LineLoop = 0x0002, + LineStrip = 0x0003, + Triangles = 0x0004, + TriangleStrip = 0x0005, + TriangleFan = 0x0006 }; -enum class DepthTestFunction : uint32_t { - Never = 0x0200, - Less = 0x0201, - Equal = 0x0202, - LessEqual = 0x0203, - Greater = 0x0204, - NotEqual = 0x0205, - GreaterEqual = 0x0206, - Always = 0x0207, -}; +#if not MBGL_USE_GLES2 -enum class BlendSourceFactor : uint32_t { - Zero = 0x0000, - One = 0x0001, - SrcColor = 0x0300, - OneMinusSrcColor = 0x0301, - DstColor = 0x0306, - OneMinusDstColor = 0x0307, - SrcAlpha = 0x0302, - OneMinusSrcAlpha = 0x0303, - DstAlpha = 0x0304, - OneMinusDstAlpha = 0x0305, - ConstantColor = 0x8001, - OneMinusConstantColor = 0x8002, - ConstantAlpha = 0x8003, - OneMinusConstantAlpha = 0x8004, - SrcAlphaSaturate = 0x0308, +struct PixelStorageType { + int32_t alignment; }; -enum class BlendDestinationFactor : uint32_t { - Zero = 0x0000, - One = 0x0001, - SrcColor = 0x0300, - OneMinusSrcColor = 0x0301, - DstColor = 0x0306, - OneMinusDstColor = 0x0307, - SrcAlpha = 0x0302, - OneMinusSrcAlpha = 0x0303, - DstAlpha = 0x0304, - OneMinusDstAlpha = 0x0305, - ConstantColor = 0x8001, - OneMinusConstantColor = 0x8002, - ConstantAlpha = 0x8003, - OneMinusConstantAlpha = 0x8004, -}; +constexpr bool operator!=(const PixelStorageType& a, const PixelStorageType& b) { + return a.alignment != b.alignment; +} + +#endif // MBGL_USE_GLES2 } // namespace gl } // namespace mbgl diff --git a/src/mbgl/gl/uniform.cpp b/src/mbgl/gl/uniform.cpp index 07a27963d9..7b674f2cde 100644 --- a/src/mbgl/gl/uniform.cpp +++ b/src/mbgl/gl/uniform.cpp @@ -1,54 +1,80 @@ #include <mbgl/gl/uniform.hpp> #include <mbgl/gl/gl.hpp> #include <mbgl/util/color.hpp> +#include <mbgl/util/size.hpp> +#include <mbgl/util/convert.hpp> namespace mbgl { namespace gl { +UniformLocation uniformLocation(ProgramID id, const char* name) { + return MBGL_CHECK_ERROR(glGetUniformLocation(id, name)); +} + template <> -void Uniform<float>::bind(const float& t) { +void bindUniform<float>(UniformLocation location, const float& t) { MBGL_CHECK_ERROR(glUniform1f(location, t)); } template <> -void Uniform<int32_t>::bind(const int32_t& t) { +void bindUniform<int32_t>(UniformLocation location, const int32_t& t) { MBGL_CHECK_ERROR(glUniform1i(location, t)); } template <> -void Uniform<std::array<float, 2>>::bind(const std::array<float, 2>& t) { +void bindUniform<std::array<float, 2>>(UniformLocation location, const std::array<float, 2>& t) { MBGL_CHECK_ERROR(glUniform2fv(location, 1, t.data())); } template <> -void Uniform<std::array<float, 3>>::bind(const std::array<float, 3>& t) { +void bindUniform<std::array<float, 3>>(UniformLocation location, const std::array<float, 3>& t) { MBGL_CHECK_ERROR(glUniform3fv(location, 1, t.data())); } template <> -void Uniform<std::array<float, 4>>::bind(const std::array<float, 4>& t) { +void bindUniform<std::array<float, 4>>(UniformLocation location, const std::array<float, 4>& t) { MBGL_CHECK_ERROR(glUniform4fv(location, 1, t.data())); } template <> -void Uniform<Color>::bind(const Color& t) { - std::array<float, 4> a = {{ t.r, t.g, t.b, t.a }}; - MBGL_CHECK_ERROR(glUniform4fv(location, 1, a.data())); +void bindUniform<std::array<double, 4>>(UniformLocation location, const std::array<double, 4>& t) { + MBGL_CHECK_ERROR(glUniformMatrix2fv(location, 1, GL_FALSE, util::convert<float>(t).data())); +} + +template <> +void bindUniform<std::array<double, 9>>(UniformLocation location, const std::array<double, 9>& t) { + MBGL_CHECK_ERROR(glUniformMatrix3fv(location, 1, GL_FALSE, util::convert<float>(t).data())); +} + +template <> +void bindUniform<std::array<double, 16>>(UniformLocation location, const std::array<double, 16>& t) { + MBGL_CHECK_ERROR(glUniformMatrix4fv(location, 1, GL_FALSE, util::convert<float>(t).data())); +} + + +template <> +void bindUniform<bool>(UniformLocation location, const bool& t) { + return bindUniform(location, int32_t(t)); +} + +template <> +void bindUniform<uint8_t>(UniformLocation location, const uint8_t& t) { + bindUniform(location, int32_t(t)); } template <> -void UniformMatrix<2>::bind(const std::array<float, 4>& t) { - MBGL_CHECK_ERROR(glUniformMatrix2fv(location, 1, GL_FALSE, t.data())); +void bindUniform<Color>(UniformLocation location, const Color& t) { + bindUniform(location, std::array<float, 4> {{ t.r, t.g, t.b, t.a }}); } template <> -void UniformMatrix<3>::bind(const std::array<float, 9>& t) { - MBGL_CHECK_ERROR(glUniformMatrix3fv(location, 1, GL_FALSE, t.data())); +void bindUniform<Size>(UniformLocation location, const Size& t) { + bindUniform(location, util::convert<float>(std::array<uint32_t, 2> {{ t.width, t.height }})); } template <> -void UniformMatrix<4>::bind(const std::array<float, 16>& t) { - MBGL_CHECK_ERROR(glUniformMatrix4fv(location, 1, GL_FALSE, t.data())); +void bindUniform<std::array<uint16_t, 2>>(UniformLocation location, const std::array<uint16_t, 2>& t) { + bindUniform(location, util::convert<float>(t)); } // Add more as needed. diff --git a/src/mbgl/gl/uniform.hpp b/src/mbgl/gl/uniform.hpp index 5af781043d..726cd4fe10 100644 --- a/src/mbgl/gl/uniform.hpp +++ b/src/mbgl/gl/uniform.hpp @@ -1,60 +1,80 @@ #pragma once -#include <mbgl/gl/shader.hpp> +#include <mbgl/gl/types.hpp> +#include <mbgl/util/optional.hpp> +#include <mbgl/util/ignore.hpp> +#include <mbgl/util/indexed_tuple.hpp> #include <array> +#include <functional> namespace mbgl { namespace gl { -template <typename T> +template <class T> +void bindUniform(UniformLocation, const T&); + +template <class Tag, class T> +class UniformValue { +public: + explicit UniformValue(T t_) : t(std::move(t_)) {} + T t; +}; + +template <class Tag, class T> class Uniform { public: - Uniform(const char* name, const Shader& shader) - : current(), location(shader.getUniformLocation(name)) { - } + using Value = UniformValue<Tag, T>; - void operator=(const T& t) { - if (current != t) { - current = t; - bind(t); + class State { + public: + void operator=(const Value& value) { + if (!current || *current != value.t) { + current = value.t; + bindUniform(location, value.t); + } } - } - -private: - void bind(const T&); - T current; - UniformLocation location; + UniformLocation location; + optional<T> current = {}; + }; }; -template <size_t C, size_t R = C> -class UniformMatrix { +template <class Tag, class T> +using UniformScalar = Uniform<Tag, T>; + +template <class Tag, class T, size_t N> +using UniformVector = Uniform<Tag, std::array<T, N>>; + +template <class Tag, class T, size_t N> +using UniformMatrix = Uniform<Tag, std::array<T, N*N>>; + +#define MBGL_DEFINE_UNIFORM_SCALAR(type_, name_) \ + struct name_ : ::mbgl::gl::UniformScalar<name_, type_> { static constexpr auto name = #name_; } + +#define MBGL_DEFINE_UNIFORM_VECTOR(type_, n_, name_) \ + struct name_ : ::mbgl::gl::UniformVector<name_, type_, n_> { static constexpr auto name = #name_; } + +#define MBGL_DEFINE_UNIFORM_MATRIX(type_, n_, name_) \ + struct name_ : ::mbgl::gl::UniformMatrix<name_, type_, n_> { static constexpr auto name = #name_; } + +UniformLocation uniformLocation(ProgramID, const char * name); + +template <class... Us> +class Uniforms { public: - typedef std::array<float, C*R> T; + using State = IndexedTuple<TypeList<Us...>, TypeList<typename Us::State...>>; + using Values = IndexedTuple<TypeList<Us...>, TypeList<typename Us::Value...>>; - UniformMatrix(const char* name, const Shader& shader) - : current(), location(shader.getUniformLocation(name)) { + static State state(const ProgramID& id) { + return State { { uniformLocation(id, Us::name) }... }; } - void operator=(const std::array<double, C*R>& t) { - bool dirty = false; - for (unsigned int i = 0; i < C*R; i++) { - if (current[i] != t[i]) { - current[i] = t[i]; - dirty = true; - } - } - if (dirty) { - bind(current); - } + static std::function<void ()> binder(State& state, Values&& values_) { + return [&state, values = std::move(values_)] () mutable { + util::ignore({ (state.template get<Us>() = values.template get<Us>(), 0)... }); + }; } - -private: - void bind(const T&); - - T current; - UniformLocation location; }; } // namespace gl diff --git a/src/mbgl/gl/value.cpp b/src/mbgl/gl/value.cpp index 14cd03efc4..86218f3d9a 100644 --- a/src/mbgl/gl/value.cpp +++ b/src/mbgl/gl/value.cpp @@ -94,7 +94,7 @@ StencilFunc::Type StencilFunc::Get() { MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_FUNC, &func)); MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_REF, &ref)); MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_VALUE_MASK, &mask)); - return { static_cast<StencilTestFunction>(func), ref, static_cast<StencilMaskValue>(mask) }; + return { static_cast<uint32_t>(func), ref, static_cast<uint32_t>(mask) }; } const constexpr StencilTest::Type StencilTest::Default; @@ -122,17 +122,17 @@ StencilOp::Type StencilOp::Get() { MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_FAIL, &sfail)); MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &dpfail)); MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &dppass)); - return { static_cast<StencilTestOperation>(sfail), static_cast<StencilTestOperation>(dpfail), - static_cast<StencilTestOperation>(dppass) }; + return { static_cast<StencilMode::Op>(sfail), static_cast<StencilMode::Op>(dpfail), + static_cast<StencilMode::Op>(dppass) }; } const constexpr DepthRange::Type DepthRange::Default; void DepthRange::Set(const Type& value) { #if MBGL_USE_GLES2 - MBGL_CHECK_ERROR(glDepthRangef(value.near, value.far)); + MBGL_CHECK_ERROR(glDepthRangef(value.min, value.max)); #else - MBGL_CHECK_ERROR(glDepthRange(value.near, value.far)); + MBGL_CHECK_ERROR(glDepthRange(value.min, value.max)); #endif } @@ -178,6 +178,18 @@ Blend::Type Blend::Get() { return blend; } +const constexpr BlendEquation::Type BlendEquation::Default; + +void BlendEquation::Set(const Type& value) { + MBGL_CHECK_ERROR(glBlendEquation(static_cast<GLenum>(value))); +} + +BlendEquation::Type BlendEquation::Get() { + GLint blend; + MBGL_CHECK_ERROR(glGetIntegerv(GL_BLEND_EQUATION_RGB, &blend)); + return static_cast<Type>(blend); +} + const constexpr BlendFunc::Type BlendFunc::Default; void BlendFunc::Set(const Type& value) { @@ -189,8 +201,8 @@ BlendFunc::Type BlendFunc::Get() { GLint sfactor, dfactor; MBGL_CHECK_ERROR(glGetIntegerv(GL_BLEND_SRC_ALPHA, &sfactor)); MBGL_CHECK_ERROR(glGetIntegerv(GL_BLEND_DST_ALPHA, &dfactor)); - return { static_cast<BlendSourceFactor>(sfactor), - static_cast<BlendDestinationFactor>(dfactor) }; + return { static_cast<ColorMode::BlendFactor>(sfactor), + static_cast<ColorMode::BlendFactor>(dfactor) }; } const constexpr BlendColor::Type BlendColor::Default; @@ -244,14 +256,14 @@ ActiveTexture::Type ActiveTexture::Get() { const constexpr Viewport::Type Viewport::Default; void Viewport::Set(const Type& value) { - MBGL_CHECK_ERROR(glViewport(value.x, value.y, value.width, value.height)); + MBGL_CHECK_ERROR(glViewport(value.x, value.y, value.size.width, value.size.height)); } Viewport::Type Viewport::Get() { GLint viewport[4]; MBGL_CHECK_ERROR(glGetIntegerv(GL_VIEWPORT, viewport)); return { static_cast<int32_t>(viewport[0]), static_cast<int32_t>(viewport[1]), - static_cast<uint16_t>(viewport[2]), static_cast<uint16_t>(viewport[3]) }; + { static_cast<uint32_t>(viewport[2]), static_cast<uint32_t>(viewport[3]) } }; } const constexpr BindFramebuffer::Type BindFramebuffer::Default; @@ -340,6 +352,18 @@ BindVertexArray::Type BindVertexArray::Get() { #if not MBGL_USE_GLES2 +const constexpr PointSize::Type PointSize::Default; + +void PointSize::Set(const Type& value) { + MBGL_CHECK_ERROR(glPointSize(value)); +} + +PointSize::Type PointSize::Get() { + GLfloat pointSize; + MBGL_CHECK_ERROR(glGetFloatv(GL_POINT_SIZE, &pointSize)); + return pointSize; +} + const constexpr PixelZoom::Type PixelZoom::Default; void PixelZoom::Set(const Type& value) { @@ -365,8 +389,63 @@ RasterPos::Type RasterPos::Get() { return { pos[0], pos[1], pos[2], pos[3] }; } -#endif // MBGL_USE_GLES2 +const constexpr PixelStorePack::Type PixelStorePack::Default; + +void PixelStorePack::Set(const Type& value) { + assert(value.alignment == 1 || value.alignment == 2 || value.alignment == 4 || + value.alignment == 8); + MBGL_CHECK_ERROR(glPixelStorei(GL_PACK_ALIGNMENT, value.alignment)); +} + +PixelStorePack::Type PixelStorePack::Get() { + Type value; + MBGL_CHECK_ERROR(glGetIntegerv(GL_PACK_ALIGNMENT, &value.alignment)); + return value; +} + +const constexpr PixelStoreUnpack::Type PixelStoreUnpack::Default; +void PixelStoreUnpack::Set(const Type& value) { + assert(value.alignment == 1 || value.alignment == 2 || value.alignment == 4 || + value.alignment == 8); + MBGL_CHECK_ERROR(glPixelStorei(GL_UNPACK_ALIGNMENT, value.alignment)); +} + +PixelStoreUnpack::Type PixelStoreUnpack::Get() { + Type value; + MBGL_CHECK_ERROR(glGetIntegerv(GL_UNPACK_ALIGNMENT, &value.alignment)); + return value; +} + +const constexpr PixelTransferDepth::Type PixelTransferDepth::Default; + +void PixelTransferDepth::Set(const Type& value) { + MBGL_CHECK_ERROR(glPixelTransferf(GL_DEPTH_SCALE, value.scale)); + MBGL_CHECK_ERROR(glPixelTransferf(GL_DEPTH_BIAS, value.bias)); +} + +PixelTransferDepth::Type PixelTransferDepth::Get() { + Type value; + MBGL_CHECK_ERROR(glGetFloatv(GL_DEPTH_SCALE, &value.scale)); + MBGL_CHECK_ERROR(glGetFloatv(GL_DEPTH_BIAS, &value.bias)); + return value; +} + +const constexpr PixelTransferStencil::Type PixelTransferStencil::Default; + +void PixelTransferStencil::Set(const Type& value) { + MBGL_CHECK_ERROR(glPixelTransferf(GL_INDEX_SHIFT, value.shift)); + MBGL_CHECK_ERROR(glPixelTransferf(GL_INDEX_OFFSET, value.offset)); +} + +PixelTransferStencil::Type PixelTransferStencil::Get() { + Type value; + MBGL_CHECK_ERROR(glGetIntegerv(GL_INDEX_SHIFT, &value.shift)); + MBGL_CHECK_ERROR(glGetIntegerv(GL_INDEX_OFFSET, &value.offset)); + return value; +} + +#endif // MBGL_USE_GLES2 } // namespace value } // namespace gl diff --git a/src/mbgl/gl/value.hpp b/src/mbgl/gl/value.hpp index 866ce389a4..3586c26bda 100644 --- a/src/mbgl/gl/value.hpp +++ b/src/mbgl/gl/value.hpp @@ -1,7 +1,12 @@ #pragma once #include <mbgl/gl/types.hpp> +#include <mbgl/gl/depth_mode.hpp> +#include <mbgl/gl/stencil_mode.hpp> +#include <mbgl/gl/color_mode.hpp> #include <mbgl/util/color.hpp> +#include <mbgl/util/size.hpp> +#include <mbgl/util/range.hpp> namespace mbgl { namespace gl { @@ -22,14 +27,14 @@ struct ClearColor { }; struct ClearStencil { - using Type = StencilValue; + using Type = int32_t; static const constexpr Type Default = 0; static void Set(const Type&); static Type Get(); }; struct StencilMask { - using Type = StencilMaskValue; + using Type = uint32_t; static const constexpr Type Default = ~0u; static void Set(const Type&); static Type Get(); @@ -43,28 +48,19 @@ struct DepthMask { }; struct ColorMask { - struct Type { - bool r; - bool g; - bool b; - bool a; - }; + using Type = ColorMode::Mask; static const constexpr Type Default = { true, true, true, true }; static void Set(const Type&); static Type Get(); }; -constexpr bool operator!=(const ColorMask::Type& a, const ColorMask::Type& b) { - return a.r != b.r || a.g != b.g || a.b != b.b || a.a != b.a; -} - struct StencilFunc { struct Type { - StencilTestFunction func; - StencilValue ref; - StencilMaskValue mask; + uint32_t func; + int32_t ref; + uint32_t mask; }; - static const constexpr Type Default = { StencilTestFunction::Always, 0, ~0u }; + static const constexpr Type Default = { StencilMode::Always::func, 0, ~0u }; static void Set(const Type&); static Type Get(); }; @@ -82,12 +78,11 @@ struct StencilTest { struct StencilOp { struct Type { - StencilTestOperation sfail; - StencilTestOperation dpfail; - StencilTestOperation dppass; + StencilMode::Op sfail; + StencilMode::Op dpfail; + StencilMode::Op dppass; }; - static const constexpr Type Default = { StencilTestOperation::Keep, StencilTestOperation::Keep, - StencilTestOperation::Keep }; + static const constexpr Type Default = { StencilMode::Keep, StencilMode::Keep, StencilMode::Keep }; static void Set(const Type&); static Type Get(); }; @@ -97,19 +92,12 @@ constexpr bool operator!=(const StencilOp::Type& a, const StencilOp::Type& b) { } struct DepthRange { - struct Type { - float near; - float far; - }; + using Type = Range<float>; static const constexpr Type Default = { 0, 1 }; static void Set(const Type&); static Type Get(); }; -constexpr bool operator!=(const DepthRange::Type& a, const DepthRange::Type& b) { - return a.near != b.near || a.far != b.far; -} - struct DepthTest { using Type = bool; static const constexpr Type Default = false; @@ -118,8 +106,8 @@ struct DepthTest { }; struct DepthFunc { - using Type = DepthTestFunction; - static const constexpr Type Default = DepthTestFunction::Less; + using Type = DepthMode::Function; + static const constexpr Type Default = DepthMode::Less; static void Set(const Type&); static Type Get(); }; @@ -131,12 +119,19 @@ struct Blend { static Type Get(); }; +struct BlendEquation { + using Type = ColorMode::BlendEquation; + static const constexpr Type Default = ColorMode::BlendEquation::Add; + static void Set(const Type&); + static Type Get(); +}; + struct BlendFunc { struct Type { - BlendSourceFactor sfactor; - BlendDestinationFactor dfactor; + ColorMode::BlendFactor sfactor; + ColorMode::BlendFactor dfactor; }; - static const constexpr Type Default = { BlendSourceFactor::One, BlendDestinationFactor::Zero }; + static const constexpr Type Default = { ColorMode::One, ColorMode::Zero }; static void Set(const Type&); static Type Get(); }; @@ -177,16 +172,19 @@ struct Viewport { struct Type { int32_t x; int32_t y; - uint16_t width; - uint16_t height; + Size size; }; - static const constexpr Type Default = { 0, 0, 0, 0 }; + static const constexpr Type Default = { 0, 0, { 0, 0 } }; static void Set(const Type&); static Type Get(); }; constexpr bool operator!=(const Viewport::Type& a, const Viewport::Type& b) { - return a.x != b.x || a.y != b.y || a.width != b.width || a.height != b.height; + return a.x != b.x || a.y != b.y || a.size != b.size; +} + +constexpr bool operator==(const Viewport::Type& a, const Viewport::Type& b) { + return !(a != b); } struct BindFramebuffer { @@ -233,6 +231,13 @@ struct BindVertexArray { #if not MBGL_USE_GLES2 +struct PointSize { + using Type = float; + static const constexpr Type Default = 1; + static void Set(const Type&); + static Type Get(); +}; + struct PixelZoom { struct Type { float xfactor; @@ -254,7 +259,7 @@ struct RasterPos { double z; double w; }; - static const constexpr Type Default = { 0, 0, 0, 0 }; + static const constexpr Type Default = { 0, 0, 0, 1 }; static void Set(const Type&); static Type Get(); }; @@ -263,6 +268,48 @@ constexpr bool operator!=(const RasterPos::Type& a, const RasterPos::Type& b) { return a.x != b.x || a.y != b.y || a.z != b.z || a.w != b.w; } +struct PixelStorePack { + using Type = PixelStorageType; + static const constexpr Type Default = { 4 }; + static void Set(const Type&); + static Type Get(); +}; + +struct PixelStoreUnpack { + using Type = PixelStorageType; + static const constexpr Type Default = { 4 }; + static void Set(const Type&); + static Type Get(); +}; + +struct PixelTransferDepth { + struct Type { + float scale; + float bias; + }; + static const constexpr Type Default = { 1, 0 }; + static void Set(const Type&); + static Type Get(); +}; + +constexpr bool operator!=(const PixelTransferDepth::Type& a, const PixelTransferDepth::Type& b) { + return a.scale != b.scale || a.bias != b.bias; +} + +struct PixelTransferStencil { + struct Type { + int32_t shift; + int32_t offset; + }; + static const constexpr Type Default = { 0, 0 }; + static void Set(const Type&); + static Type Get(); +}; + +constexpr bool operator!=(const PixelTransferStencil::Type& a, const PixelTransferStencil::Type& b) { + return a.shift != b.shift || a.offset != b.offset; +} + #endif // MBGL_USE_GLES2 } // namespace value diff --git a/src/mbgl/gl/vao.cpp b/src/mbgl/gl/vao.cpp deleted file mode 100644 index b235b0e63b..0000000000 --- a/src/mbgl/gl/vao.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include <mbgl/gl/vao.hpp> -#include <mbgl/gl/vertex_array.hpp> -#include <mbgl/platform/log.hpp> -#include <mbgl/util/string.hpp> -#include <mbgl/gl/gl.hpp> - -namespace mbgl { -namespace gl { - -void VertexArrayObject::bindVertexArrayObject(Context& context) { - if (!GenVertexArrays || !BindVertexArray) { - static bool reported = false; - if (!reported) { - Log::Warning(Event::OpenGL, "Not using Vertex Array Objects"); - reported = true; - } - return; - } - - if (!vertexArray) { - vertexArray = context.createVertexArray(); - context.vertexBuffer.setDirty(); - context.elementBuffer.setDirty(); - } - - context.vertexArrayObject = *vertexArray; -} - -void VertexArrayObject::verifyBinding(Shader& shader, - BufferID vertexBuffer, - BufferID elementsBuffer, - int8_t* offset) { - if (bound_shader != shader.getID()) { - throw std::runtime_error(std::string("trying to rebind VAO to another shader from " + - util::toString(bound_shader) + "(" + bound_shader_name + ") to " + - util::toString(shader.getID()) + "(" + shader.name + ")" )); - } else if (bound_offset != offset) { - throw std::runtime_error("trying to bind VAO to another offset"); - } else if (bound_vertex_buffer != vertexBuffer) { - throw std::runtime_error("trying to bind VAO to another vertex buffer"); - } else if (bound_elements_buffer != elementsBuffer) { - throw std::runtime_error("trying to bind VAO to another elements buffer"); - } -} - -void VertexArrayObject::storeBinding(Shader& shader, - BufferID vertexBuffer, - BufferID elementsBuffer, - int8_t* offset) { - bound_shader = shader.getID(); - bound_shader_name = shader.name; - bound_offset = offset; - bound_vertex_buffer = vertexBuffer; - bound_elements_buffer = elementsBuffer; -} - -} // namespace gl -} // namespace mbgl diff --git a/src/mbgl/gl/vao.hpp b/src/mbgl/gl/vao.hpp deleted file mode 100644 index 826c028d32..0000000000 --- a/src/mbgl/gl/vao.hpp +++ /dev/null @@ -1,78 +0,0 @@ -#pragma once - -#include <mbgl/gl/shader.hpp> -#include <mbgl/gl/context.hpp> -#include <mbgl/gl/vertex_buffer.hpp> -#include <mbgl/util/optional.hpp> - -#include <stdexcept> - -namespace mbgl { -namespace gl { - -class VertexArrayObject { -public: - template <typename Shader, typename T> - void bind(Shader& shader, - const VertexBuffer<T>& vertexBuffer, - int8_t* offset, - Context& context) { - bindVertexArrayObject(context); - if (bound_shader == 0) { - context.vertexBuffer = vertexBuffer.buffer; - context.bindAttributes(shader, vertexBuffer, offset); - if (vertexArray) { - storeBinding(shader, vertexBuffer.buffer, 0, offset); - } - } else { - verifyBinding(shader, vertexBuffer.buffer, 0, offset); - } - } - - template <typename Shader, typename T, typename P> - void bind(Shader& shader, - const VertexBuffer<T>& vertexBuffer, - const IndexBuffer<P>& indexBuffer, - int8_t* offset, - Context& context) { - bindVertexArrayObject(context); - if (bound_shader == 0) { - context.vertexBuffer = vertexBuffer.buffer; - context.elementBuffer = indexBuffer.buffer; - context.bindAttributes(shader, vertexBuffer, offset); - if (vertexArray) { - storeBinding(shader, vertexBuffer.buffer, indexBuffer.buffer, offset); - } - } else { - verifyBinding(shader, vertexBuffer.buffer, indexBuffer.buffer, offset); - } - } - - VertexArrayID getID() const { - return *vertexArray; - } - -private: - void bindVertexArrayObject(Context&); - void storeBinding(Shader& shader, - BufferID vertexBuffer, - BufferID elementsBuffer, - int8_t* offset); - void verifyBinding(Shader& shader, - BufferID vertexBuffer, - BufferID elementsBuffer, - int8_t* offset); - - optional<UniqueVertexArray> vertexArray; - - // For debug reasons, we're storing the bind information so that we can - // detect errors and report - ProgramID bound_shader = 0; - const char* bound_shader_name = ""; - BufferID bound_vertex_buffer = 0; - BufferID bound_elements_buffer = 0; - int8_t *bound_offset = nullptr; -}; - -} // namespace gl -} // namespace mbgl diff --git a/src/mbgl/gl/vertex_buffer.hpp b/src/mbgl/gl/vertex_buffer.hpp index c77a9a4213..c9bc01f3e8 100644 --- a/src/mbgl/gl/vertex_buffer.hpp +++ b/src/mbgl/gl/vertex_buffer.hpp @@ -1,14 +1,43 @@ #pragma once #include <mbgl/gl/object.hpp> +#include <mbgl/gl/primitives.hpp> +#include <mbgl/gl/draw_mode.hpp> +#include <mbgl/util/ignore.hpp> + +#include <vector> namespace mbgl { namespace gl { -template <class Vertex> +template <class V, class DrawMode = Indexed> +class VertexVector { +public: + using Vertex = V; + static constexpr std::size_t groupSize = DrawMode::bufferGroupSize; + + template <class... Args> + void emplace_back(Args&&... args) { + static_assert(sizeof...(args) == groupSize, "wrong buffer element count"); + util::ignore({(v.emplace_back(std::forward<Args>(args)), 0)...}); + } + + std::size_t vertexSize() const { return v.size(); } + std::size_t byteSize() const { return v.size() * sizeof(Vertex); } + + bool empty() const { return v.empty(); } + const Vertex* data() const { return v.data(); } + +private: + std::vector<Vertex> v; +}; + +template <class V, class DrawMode = Indexed> class VertexBuffer { public: + using Vertex = V; static constexpr std::size_t vertexSize = sizeof(Vertex); + std::size_t vertexCount; UniqueBuffer buffer; }; diff --git a/src/mbgl/layout/merge_lines.cpp b/src/mbgl/layout/merge_lines.cpp index f4fdb82617..676cbc092d 100644 --- a/src/mbgl/layout/merge_lines.cpp +++ b/src/mbgl/layout/merge_lines.cpp @@ -47,10 +47,10 @@ enum class Side { }; size_t -getKey(const std::u32string& text, const GeometryCollection& geom, Side side) { +getKey(const std::u16string& text, const GeometryCollection& geom, Side side) { const GeometryCoordinate& coord = side == Side::Right ? geom[0].back() : geom[0].front(); - auto hash = std::hash<std::u32string>()(text); + auto hash = std::hash<std::u16string>()(text); boost::hash_combine(hash, coord.x); boost::hash_combine(hash, coord.y); return hash; diff --git a/src/mbgl/layout/symbol_feature.hpp b/src/mbgl/layout/symbol_feature.hpp index 99db4f9ac5..5dd61d9156 100644 --- a/src/mbgl/layout/symbol_feature.hpp +++ b/src/mbgl/layout/symbol_feature.hpp @@ -9,8 +9,9 @@ namespace mbgl { class SymbolFeature { public: + FeatureType type; GeometryCollection geometry; - optional<std::u32string> text; + optional<std::u16string> text; optional<std::string> icon; std::size_t index; }; diff --git a/src/mbgl/layout/symbol_instance.cpp b/src/mbgl/layout/symbol_instance.cpp index 64b913200e..fafcc7c15d 100644 --- a/src/mbgl/layout/symbol_instance.cpp +++ b/src/mbgl/layout/symbol_instance.cpp @@ -7,7 +7,7 @@ using namespace style; SymbolInstance::SymbolInstance(Anchor& anchor, const GeometryCoordinates& line, const Shaping& shapedText, const PositionedIcon& shapedIcon, - const SymbolLayoutProperties& layout, const bool addToBuffers, const uint32_t index_, + const SymbolLayoutProperties::Evaluated& layout, const bool addToBuffers, const uint32_t index_, const float textBoxScale, const float textPadding, const SymbolPlacementType textPlacement, const float iconBoxScale, const float iconPadding, const SymbolPlacementType iconPlacement, const GlyphPositions& face, const IndexedSubfeature& indexedFeature) : diff --git a/src/mbgl/layout/symbol_instance.hpp b/src/mbgl/layout/symbol_instance.hpp index 3087bf09f9..508c11a394 100644 --- a/src/mbgl/layout/symbol_instance.hpp +++ b/src/mbgl/layout/symbol_instance.hpp @@ -2,21 +2,18 @@ #include <mbgl/text/quads.hpp> #include <mbgl/text/collision_feature.hpp> +#include <mbgl/style/layers/symbol_layer_properties.hpp> namespace mbgl { struct Anchor; class IndexedSubfeature; -namespace style { -class SymbolLayoutProperties; -} // namespace style - class SymbolInstance { public: explicit SymbolInstance(Anchor& anchor, const GeometryCoordinates& line, const Shaping& shapedText, const PositionedIcon& shapedIcon, - const style::SymbolLayoutProperties&, const bool inside, const uint32_t index, + const style::SymbolLayoutProperties::Evaluated&, const bool inside, const uint32_t index, const float textBoxScale, const float textPadding, style::SymbolPlacementType textPlacement, const float iconBoxScale, const float iconPadding, style::SymbolPlacementType iconPlacement, const GlyphPositions& face, const IndexedSubfeature& indexedfeature); diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index 07ba2bf4a3..7be2c13ada 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -11,14 +11,14 @@ #include <mbgl/util/constants.hpp> #include <mbgl/util/utf.hpp> #include <mbgl/util/token.hpp> -#include <mbgl/util/math.hpp> #include <mbgl/util/std.hpp> #include <mbgl/util/constants.hpp> #include <mbgl/util/string.hpp> #include <mbgl/math/clamp.hpp> #include <mbgl/math/minmax.hpp> -#include <mbgl/platform/platform.hpp> -#include <mbgl/platform/log.hpp> +#include <mbgl/math/log2.hpp> +#include <mbgl/util/platform.hpp> +#include <mbgl/util/logging.hpp> namespace mbgl { @@ -31,7 +31,7 @@ SymbolLayout::SymbolLayout(std::string bucketName_, const MapMode mode_, const GeometryTileLayer& layer, const style::Filter& filter, - style::SymbolLayoutProperties layout_, + style::SymbolLayoutProperties::Evaluated layout_, float textMaxSize_, SpriteAtlas& spriteAtlas_) : bucketName(std::move(bucketName_)), @@ -45,8 +45,8 @@ SymbolLayout::SymbolLayout(std::string bucketName_, tileSize(util::tileSize * overscaling_), tilePixelRatio(float(util::EXTENT) / tileSize) { - const bool hasText = !layout.textField.value.empty() && !layout.textFont.value.empty(); - const bool hasIcon = !layout.iconImage.value.empty(); + const bool hasText = !layout.get<TextField>().empty() && !layout.get<TextFont>().empty(); + const bool hasIcon = !layout.get<IconImage>().empty(); if (!hasText && !hasIcon) { return; @@ -82,42 +82,34 @@ SymbolLayout::SymbolLayout(std::string bucketName_, }; if (hasText) { - std::string u8string = util::replaceTokens(layout.textField, getValue); + std::string u8string = util::replaceTokens(layout.get<TextField>(), getValue); - if (layout.textTransform == TextTransformType::Uppercase) { + if (layout.get<TextTransform>() == TextTransformType::Uppercase) { u8string = platform::uppercase(u8string); - } else if (layout.textTransform == TextTransformType::Lowercase) { + } else if (layout.get<TextTransform>() == TextTransformType::Lowercase) { u8string = platform::lowercase(u8string); } - ft.text = util::utf8_to_utf32::convert(u8string); + ft.text = applyArabicShaping(util::utf8_to_utf16::convert(u8string)); // Loop through all characters of this text and collect unique codepoints. - for (char32_t chr : *ft.text) { + for (char16_t chr : *ft.text) { ranges.insert(getGlyphRange(chr)); } } if (hasIcon) { - ft.icon = util::replaceTokens(layout.iconImage, getValue); + ft.icon = util::replaceTokens(layout.get<IconImage>(), getValue); } if (ft.text || ft.icon) { - auto &multiline = ft.geometry; - - GeometryCollection geometryCollection = feature->getGeometries(); - for (auto& line : geometryCollection) { - multiline.emplace_back(); - for (auto& point : line) { - multiline.back().emplace_back(point.x, point.y); - } - } - + ft.type = feature->getType(); + ft.geometry = feature->getGeometries(); features.push_back(std::move(ft)); } } - if (layout.symbolPlacement == SymbolPlacementType::Line) { + if (layout.get<SymbolPlacement>() == SymbolPlacementType::Line) { util::mergeLines(features); } } @@ -127,11 +119,11 @@ bool SymbolLayout::hasSymbolInstances() const { } bool SymbolLayout::canPrepare(GlyphAtlas& glyphAtlas) { - if (!layout.textField.value.empty() && !layout.textFont.value.empty() && !glyphAtlas.hasGlyphRanges(layout.textFont, ranges)) { + if (!layout.get<TextField>().empty() && !layout.get<TextFont>().empty() && !glyphAtlas.hasGlyphRanges(layout.get<TextFont>(), ranges)) { return false; } - if (!layout.iconImage.value.empty() && !spriteAtlas.isLoaded()) { + if (!layout.get<IconImage>().empty() && !spriteAtlas.isLoaded()) { return false; } @@ -143,7 +135,7 @@ void SymbolLayout::prepare(uintptr_t tileUID, float horizontalAlign = 0.5; float verticalAlign = 0.5; - switch (layout.textAnchor) { + switch (layout.get<TextAnchor>()) { case TextAnchorType::Top: case TextAnchorType::Bottom: case TextAnchorType::Center: @@ -160,7 +152,7 @@ void SymbolLayout::prepare(uintptr_t tileUID, break; } - switch (layout.textAnchor) { + switch (layout.get<TextAnchor>()) { case TextAnchorType::Left: case TextAnchorType::Right: case TextAnchorType::Center: @@ -177,11 +169,11 @@ void SymbolLayout::prepare(uintptr_t tileUID, break; } - const float justify = layout.textJustify == TextJustifyType::Right ? 1 : - layout.textJustify == TextJustifyType::Left ? 0 : + const float justify = layout.get<TextJustify>() == TextJustifyType::Right ? 1 : + layout.get<TextJustify>() == TextJustifyType::Left ? 0 : 0.5; - auto glyphSet = glyphAtlas.getGlyphSet(layout.textFont); + auto glyphSet = glyphAtlas.getGlyphSet(layout.get<TextFont>()); for (const auto& feature : features) { if (feature.geometry.empty()) continue; @@ -194,18 +186,19 @@ void SymbolLayout::prepare(uintptr_t tileUID, if (feature.text) { shapedText = glyphSet->getShaping( /* string */ *feature.text, - /* maxWidth: ems */ layout.symbolPlacement != SymbolPlacementType::Line ? - layout.textMaxWidth * 24 : 0, - /* lineHeight: ems */ layout.textLineHeight * 24, + /* maxWidth: ems */ layout.get<SymbolPlacement>() != SymbolPlacementType::Line ? + layout.get<TextMaxWidth>() * 24 : 0, + /* lineHeight: ems */ layout.get<TextLineHeight>() * 24, /* horizontalAlign */ horizontalAlign, /* verticalAlign */ verticalAlign, /* justify */ justify, - /* spacing: ems */ layout.textLetterSpacing * 24, - /* translate */ Point<float>(layout.textOffset.value[0], layout.textOffset.value[1])); + /* spacing: ems */ layout.get<TextLetterSpacing>() * 24, + /* translate */ Point<float>(layout.get<TextOffset>()[0], layout.get<TextOffset>()[1]), + /* bidirectional algorithm object */ bidi); // Add the glyphs we need for this label to the glyph atlas. if (shapedText) { - glyphAtlas.addGlyphs(tileUID, *feature.text, layout.textFont, **glyphSet, face); + glyphAtlas.addGlyphs(tileUID, *feature.text, layout.get<TextFont>(), **glyphSet, face); } } @@ -220,7 +213,7 @@ void SymbolLayout::prepare(uintptr_t tileUID, } if ((*image).relativePixelRatio != 1.0f) { iconsNeedLinear = true; - } else if (layout.iconRotate != 0) { + } else if (layout.get<IconRotate>() != 0) { iconsNeedLinear = true; } } @@ -228,93 +221,114 @@ void SymbolLayout::prepare(uintptr_t tileUID, // if either shapedText or icon position is present, add the feature if (shapedText || shapedIcon) { - addFeature(feature.geometry, shapedText, shapedIcon, face, feature.index); + addFeature(feature, shapedText, shapedIcon, face); } } features.clear(); } - -void SymbolLayout::addFeature(const GeometryCollection &lines, - const Shaping &shapedText, const PositionedIcon &shapedIcon, const GlyphPositions &face, const size_t index) { - +void SymbolLayout::addFeature(const SymbolFeature& feature, + const Shaping& shapedText, + const PositionedIcon& shapedIcon, + const GlyphPositions& face) { const float minScale = 0.5f; const float glyphSize = 24.0f; - const float fontScale = layout.textSize / glyphSize; + const float fontScale = layout.get<TextSize>() / glyphSize; const float textBoxScale = tilePixelRatio * fontScale; const float textMaxBoxScale = tilePixelRatio * textMaxSize / glyphSize; - const float iconBoxScale = tilePixelRatio * layout.iconSize; - const float symbolSpacing = tilePixelRatio * layout.symbolSpacing; - const bool avoidEdges = layout.symbolAvoidEdges && layout.symbolPlacement != SymbolPlacementType::Line; - const float textPadding = layout.textPadding * tilePixelRatio; - const float iconPadding = layout.iconPadding * tilePixelRatio; - const float textMaxAngle = layout.textMaxAngle * util::DEG2RAD; - const SymbolPlacementType textPlacement = layout.textRotationAlignment != AlignmentType::Map + const float iconBoxScale = tilePixelRatio * layout.get<IconSize>(); + const float symbolSpacing = tilePixelRatio * layout.get<SymbolSpacing>(); + const bool avoidEdges = layout.get<SymbolAvoidEdges>() && layout.get<SymbolPlacement>() != SymbolPlacementType::Line; + const float textPadding = layout.get<TextPadding>() * tilePixelRatio; + const float iconPadding = layout.get<IconPadding>() * tilePixelRatio; + const float textMaxAngle = layout.get<TextMaxAngle>() * util::DEG2RAD; + const SymbolPlacementType textPlacement = layout.get<TextRotationAlignment>() != AlignmentType::Map ? SymbolPlacementType::Point - : layout.symbolPlacement; - const SymbolPlacementType iconPlacement = layout.iconRotationAlignment != AlignmentType::Map + : layout.get<SymbolPlacement>(); + const SymbolPlacementType iconPlacement = layout.get<IconRotationAlignment>() != AlignmentType::Map ? SymbolPlacementType::Point - : layout.symbolPlacement; - const bool mayOverlap = layout.textAllowOverlap || layout.iconAllowOverlap || - layout.textIgnorePlacement || layout.iconIgnorePlacement; - const bool isLine = layout.symbolPlacement == SymbolPlacementType::Line; + : layout.get<SymbolPlacement>(); const float textRepeatDistance = symbolSpacing / 2; - - auto& clippedLines = isLine ? - util::clipLines(lines, 0, 0, util::EXTENT, util::EXTENT) : - lines; - - IndexedSubfeature indexedFeature = {index, sourceLayerName, bucketName, symbolInstances.size()}; - - for (const auto& line : clippedLines) { - if (line.empty()) continue; - - // Calculate the anchor points around which you want to place labels - Anchors anchors = isLine ? - getAnchors(line, symbolSpacing, textMaxAngle, shapedText.left, shapedText.right, shapedIcon.left, shapedIcon.right, glyphSize, textMaxBoxScale, overscaling) : - Anchors({ Anchor(float(line[0].x), float(line[0].y), 0, minScale) }); - - // For each potential label, create the placement features used to check for collisions, and the quads use for rendering. - for (Anchor &anchor : anchors) { - if (shapedText && isLine) { - if (anchorIsTooClose(shapedText.text, textRepeatDistance, anchor)) { - continue; + IndexedSubfeature indexedFeature = {feature.index, sourceLayerName, bucketName, symbolInstances.size()}; + + auto addSymbolInstance = [&] (const GeometryCoordinates& line, Anchor& anchor) { + // https://github.com/mapbox/vector-tile-spec/tree/master/2.1#41-layers + // +-------------------+ Symbols with anchors located on tile edges + // |(0,0) || are duplicated on neighbor tiles. + // | || + // | || In continuous mode, to avoid overdraw we + // | || skip symbols located on the extent edges. + // | Tile || In still mode, we include the features in + // | || the buffers for both tiles and clip them + // | || at draw time. + // | || + // +-------------------| In this scenario, the inner bounding box + // +-------------------+ is called 'withinPlus0', and the outer + // (extent,extent) is called 'inside'. + const bool withinPlus0 = anchor.point.x >= 0 && anchor.point.x < util::EXTENT && anchor.point.y >= 0 && anchor.point.y < util::EXTENT; + const bool inside = withinPlus0 || anchor.point.x == util::EXTENT || anchor.point.y == util::EXTENT; + + if (avoidEdges && !inside) return; + + const bool addToBuffers = mode == MapMode::Still || withinPlus0; + + symbolInstances.emplace_back(anchor, line, shapedText, shapedIcon, layout, addToBuffers, symbolInstances.size(), + textBoxScale, textPadding, textPlacement, + iconBoxScale, iconPadding, iconPlacement, + face, indexedFeature); + }; + + if (layout.get<SymbolPlacement>() == SymbolPlacementType::Line) { + auto clippedLines = util::clipLines(feature.geometry, 0, 0, util::EXTENT, util::EXTENT); + for (const auto& line : clippedLines) { + Anchors anchors = getAnchors(line, + symbolSpacing, + textMaxAngle, + shapedText.left, + shapedText.right, + shapedIcon.left, + shapedIcon.right, + glyphSize, + textMaxBoxScale, + overscaling); + + for (auto& anchor : anchors) { + if (!shapedText || !anchorIsTooClose(shapedText.text, textRepeatDistance, anchor)) { + addSymbolInstance(line, anchor); } } - - const bool inside = !(anchor.point.x < 0 || anchor.point.x > util::EXTENT || anchor.point.y < 0 || anchor.point.y > util::EXTENT); - - if (avoidEdges && !inside) continue; - - // Normally symbol layers are drawn across tile boundaries. Only symbols - // with their anchors within the tile boundaries are added to the buffers - // to prevent symbols from being drawn twice. - // - // Symbols in layers with overlap are sorted in the y direction so that - // symbols lower on the canvas are drawn on top of symbols near the top. - // To preserve this order across tile boundaries these symbols can't - // be drawn across tile boundaries. Instead they need to be included in - // the buffers for both tiles and clipped to tile boundaries at draw time. - // - // TODO remove the `&& false` when is #1673 implemented - const bool addToBuffers = (mode == MapMode::Still) || inside || (mayOverlap && false); - - symbolInstances.emplace_back(anchor, line, shapedText, shapedIcon, layout, addToBuffers, symbolInstances.size(), - textBoxScale, textPadding, textPlacement, - iconBoxScale, iconPadding, iconPlacement, - face, indexedFeature); + } + } else if (feature.type == FeatureType::Polygon) { + // TODO: pole of inaccessibility + for (const auto& ring : feature.geometry) { + for (const auto& point : ring) { + Anchor anchor(point.x, point.y, 0, minScale); + addSymbolInstance(ring, anchor); + } + } + } else if (feature.type == FeatureType::LineString) { + for (const auto& line : feature.geometry) { + Anchor anchor(line[0].x, line[0].y, 0, minScale); + addSymbolInstance(line, anchor); + } + } else if (feature.type == FeatureType::Point) { + for (const auto& points : feature.geometry) { + for (const auto& point : points) { + Anchor anchor(point.x, point.y, 0, minScale); + addSymbolInstance({point}, anchor); + } } } } -bool SymbolLayout::anchorIsTooClose(const std::u32string &text, const float repeatDistance, Anchor &anchor) { +bool SymbolLayout::anchorIsTooClose(const std::u16string& text, const float repeatDistance, const Anchor& anchor) { if (compareText.find(text) == compareText.end()) { compareText.emplace(text, Anchors()); } else { auto otherAnchors = compareText.find(text)->second; - for (Anchor &otherAnchor : otherAnchors) { + for (const Anchor& otherAnchor : otherAnchors) { if (util::dist<float>(anchor.point, otherAnchor.point) < repeatDistance) { return true; } @@ -330,15 +344,15 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile) // Calculate which labels can be shown and when they can be shown and // create the bufers used for rendering. - const SymbolPlacementType textPlacement = layout.textRotationAlignment != AlignmentType::Map + const SymbolPlacementType textPlacement = layout.get<TextRotationAlignment>() != AlignmentType::Map ? SymbolPlacementType::Point - : layout.symbolPlacement; - const SymbolPlacementType iconPlacement = layout.iconRotationAlignment != AlignmentType::Map + : layout.get<SymbolPlacement>(); + const SymbolPlacementType iconPlacement = layout.get<IconRotationAlignment>() != AlignmentType::Map ? SymbolPlacementType::Point - : layout.symbolPlacement; + : layout.get<SymbolPlacement>(); - const bool mayOverlap = layout.textAllowOverlap || layout.iconAllowOverlap || - layout.textIgnorePlacement || layout.iconIgnorePlacement; + const bool mayOverlap = layout.get<TextAllowOverlap>() || layout.get<IconAllowOverlap>() || + layout.get<TextIgnorePlacement>() || layout.get<IconIgnorePlacement>(); // Sort symbols by their y position on the canvas so that they lower symbols // are drawn on top of higher symbols. @@ -362,18 +376,18 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile) const bool hasText = symbolInstance.hasText; const bool hasIcon = symbolInstance.hasIcon; - const bool iconWithoutText = layout.textOptional || !hasText; - const bool textWithoutIcon = layout.iconOptional || !hasIcon; + const bool iconWithoutText = layout.get<TextOptional>() || !hasText; + const bool textWithoutIcon = layout.get<IconOptional>() || !hasIcon; // Calculate the scales at which the text and icon can be placed without collision. float glyphScale = hasText ? collisionTile.placeFeature(symbolInstance.textCollisionFeature, - layout.textAllowOverlap, layout.symbolAvoidEdges) : + layout.get<TextAllowOverlap>(), layout.get<SymbolAvoidEdges>()) : collisionTile.minScale; float iconScale = hasIcon ? collisionTile.placeFeature(symbolInstance.iconCollisionFeature, - layout.iconAllowOverlap, layout.symbolAvoidEdges) : + layout.get<IconAllowOverlap>(), layout.get<SymbolAvoidEdges>()) : collisionTile.minScale; @@ -391,20 +405,20 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile) // Insert final placement into collision tree and add glyphs/icons to buffers if (hasText) { - collisionTile.insertFeature(symbolInstance.textCollisionFeature, glyphScale, layout.textIgnorePlacement); + collisionTile.insertFeature(symbolInstance.textCollisionFeature, glyphScale, layout.get<TextIgnorePlacement>()); if (glyphScale < collisionTile.maxScale) { addSymbols( bucket->text, symbolInstance.glyphQuads, glyphScale, - layout.textKeepUpright, textPlacement, collisionTile.config.angle); + layout.get<TextKeepUpright>(), textPlacement, collisionTile.config.angle); } } if (hasIcon) { - collisionTile.insertFeature(symbolInstance.iconCollisionFeature, iconScale, layout.iconIgnorePlacement); + collisionTile.insertFeature(symbolInstance.iconCollisionFeature, iconScale, layout.get<IconIgnorePlacement>()); if (iconScale < collisionTile.maxScale) { addSymbols( bucket->icon, symbolInstance.iconQuads, iconScale, - layout.iconKeepUpright, iconPlacement, collisionTile.config.angle); + layout.get<IconKeepUpright>(), iconPlacement, collisionTile.config.angle); } } } @@ -418,8 +432,8 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile) template <typename Buffer> void SymbolLayout::addSymbols(Buffer &buffer, const SymbolQuads &symbols, float scale, const bool keepUpright, const style::SymbolPlacementType placement, const float placementAngle) { - - const float placementZoom = ::fmax(std::log(scale) / std::log(2) + zoom, 0); + constexpr const uint16_t vertexLength = 4; + const float placementZoom = util::max(util::log2(scale) + zoom, 0.0f); for (const auto& symbol : symbols) { const auto &tl = symbol.tl; @@ -428,9 +442,8 @@ void SymbolLayout::addSymbols(Buffer &buffer, const SymbolQuads &symbols, float const auto &br = symbol.br; const auto &tex = symbol.tex; - float minZoom = - util::max(static_cast<float>(zoom + log(symbol.minScale) / log(2)), placementZoom); - float maxZoom = util::min(static_cast<float>(zoom + log(symbol.maxScale) / log(2)), 25.0f); + float minZoom = util::max(zoom + util::log2(symbol.minScale), placementZoom); + float maxZoom = util::min(zoom + util::log2(symbol.maxScale), util::MAX_ZOOM_F); const auto &anchorPoint = symbol.anchorPoint; // drop upside down versions of glyphs @@ -449,41 +462,35 @@ void SymbolLayout::addSymbols(Buffer &buffer, const SymbolQuads &symbols, float minZoom = 0; } - const int glyph_vertex_length = 4; - - if (buffer.groups.empty() || buffer.groups.back().vertexLength + glyph_vertex_length > 65535) { - // Move to a new group because the old one can't hold the geometry. - buffer.groups.emplace_back(); + if (buffer.segments.empty() || buffer.segments.back().vertexLength + vertexLength > std::numeric_limits<uint16_t>::max()) { + buffer.segments.emplace_back(buffer.vertices.vertexSize(), buffer.triangles.indexSize()); } // We're generating triangle fans, so we always start with the first // coordinate in this polygon. - auto& group = buffer.groups.back(); - size_t index = group.vertexLength; + auto& segment = buffer.segments.back(); + assert(segment.vertexLength <= std::numeric_limits<uint16_t>::max()); + uint16_t index = segment.vertexLength; // Encode angle of glyph uint8_t glyphAngle = std::round((symbol.glyphAngle / (M_PI * 2)) * 256); // coordinates (2 triangles) - buffer.vertices.emplace_back(anchorPoint.x, anchorPoint.y, tl.x, tl.y, tex.x, tex.y, minZoom, - maxZoom, placementZoom, glyphAngle); - buffer.vertices.emplace_back(anchorPoint.x, anchorPoint.y, tr.x, tr.y, tex.x + tex.w, tex.y, - minZoom, maxZoom, placementZoom, glyphAngle); - buffer.vertices.emplace_back(anchorPoint.x, anchorPoint.y, bl.x, bl.y, tex.x, tex.y + tex.h, - minZoom, maxZoom, placementZoom, glyphAngle); - buffer.vertices.emplace_back(anchorPoint.x, anchorPoint.y, br.x, br.y, tex.x + tex.w, tex.y + tex.h, - minZoom, maxZoom, placementZoom, glyphAngle); + buffer.vertices.emplace_back(SymbolAttributes::vertex(anchorPoint, tl, tex.x, tex.y, + minZoom, maxZoom, placementZoom, glyphAngle)); + buffer.vertices.emplace_back(SymbolAttributes::vertex(anchorPoint, tr, tex.x + tex.w, tex.y, + minZoom, maxZoom, placementZoom, glyphAngle)); + buffer.vertices.emplace_back(SymbolAttributes::vertex(anchorPoint, bl, tex.x, tex.y + tex.h, + minZoom, maxZoom, placementZoom, glyphAngle)); + buffer.vertices.emplace_back(SymbolAttributes::vertex(anchorPoint, br, tex.x + tex.w, tex.y + tex.h, + minZoom, maxZoom, placementZoom, glyphAngle)); // add the two triangles, referencing the four coordinates we just inserted. - buffer.triangles.emplace_back(static_cast<uint16_t>(index + 0), - static_cast<uint16_t>(index + 1), - static_cast<uint16_t>(index + 2)); - buffer.triangles.emplace_back(static_cast<uint16_t>(index + 1), - static_cast<uint16_t>(index + 2), - static_cast<uint16_t>(index + 3)); - - group.vertexLength += glyph_vertex_length; - group.indexLength += 2; + buffer.triangles.emplace_back(index + 0, index + 1, index + 2); + buffer.triangles.emplace_back(index + 1, index + 2, index + 3); + + segment.vertexLength += vertexLength; + segment.indexLength += 6; } } @@ -496,10 +503,6 @@ void SymbolLayout::addToDebugBuffers(CollisionTile& collisionTile, SymbolBucket& const float yStretch = collisionTile.yStretch; auto& collisionBox = bucket.collisionBox; - if (collisionBox.groups.empty()) { - // Move to a new group because the old one can't hold the geometry. - collisionBox.groups.emplace_back(); - } for (const SymbolInstance &symbolInstance : symbolInstances) { auto populateCollisionBox = [&](const auto& feature) { @@ -515,20 +518,31 @@ void SymbolLayout::addToDebugBuffers(CollisionTile& collisionTile, SymbolBucket& bl = util::matrixMultiply(collisionTile.reverseRotationMatrix, bl); br = util::matrixMultiply(collisionTile.reverseRotationMatrix, br); - const float maxZoom = util::clamp(zoom + log(box.maxScale) / log(2), util::MIN_ZOOM, util::MAX_ZOOM); - const float placementZoom = util::clamp(zoom + log(box.placementScale) / log(2), util::MIN_ZOOM, util::MAX_ZOOM); + const float maxZoom = util::clamp(zoom + util::log2(box.maxScale), util::MIN_ZOOM_F, util::MAX_ZOOM_F); + const float placementZoom = util::clamp(zoom + util::log2(box.placementScale), util::MIN_ZOOM_F, util::MAX_ZOOM_F); + + static constexpr std::size_t vertexLength = 4; + static constexpr std::size_t indexLength = 8; + + if (collisionBox.segments.empty() || collisionBox.segments.back().vertexLength + vertexLength > std::numeric_limits<uint16_t>::max()) { + collisionBox.segments.emplace_back(collisionBox.vertices.vertexSize(), collisionBox.lines.indexSize()); + } + + auto& segment = collisionBox.segments.back(); + uint16_t index = segment.vertexLength; + + collisionBox.vertices.emplace_back(CollisionBoxProgram::vertex(anchor, tl, maxZoom, placementZoom)); + collisionBox.vertices.emplace_back(CollisionBoxProgram::vertex(anchor, tr, maxZoom, placementZoom)); + collisionBox.vertices.emplace_back(CollisionBoxProgram::vertex(anchor, br, maxZoom, placementZoom)); + collisionBox.vertices.emplace_back(CollisionBoxProgram::vertex(anchor, bl, maxZoom, placementZoom)); - collisionBox.vertices.emplace_back(anchor.x, anchor.y, tl.x, tl.y, maxZoom, placementZoom); - collisionBox.vertices.emplace_back(anchor.x, anchor.y, tr.x, tr.y, maxZoom, placementZoom); - collisionBox.vertices.emplace_back(anchor.x, anchor.y, tr.x, tr.y, maxZoom, placementZoom); - collisionBox.vertices.emplace_back(anchor.x, anchor.y, br.x, br.y, maxZoom, placementZoom); - collisionBox.vertices.emplace_back(anchor.x, anchor.y, br.x, br.y, maxZoom, placementZoom); - collisionBox.vertices.emplace_back(anchor.x, anchor.y, bl.x, bl.y, maxZoom, placementZoom); - collisionBox.vertices.emplace_back(anchor.x, anchor.y, bl.x, bl.y, maxZoom, placementZoom); - collisionBox.vertices.emplace_back(anchor.x, anchor.y, tl.x, tl.y, maxZoom, placementZoom); + collisionBox.lines.emplace_back(index + 0, index + 1); + collisionBox.lines.emplace_back(index + 1, index + 2); + collisionBox.lines.emplace_back(index + 2, index + 3); + collisionBox.lines.emplace_back(index + 3, index + 0); - auto& group = collisionBox.groups.back(); - group.vertexLength += 8; + segment.vertexLength += vertexLength; + segment.indexLength += indexLength; } }; populateCollisionBox(symbolInstance.textCollisionFeature); diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index 54acf84aaf..18fb9ff4bc 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -4,6 +4,7 @@ #include <mbgl/style/layers/symbol_layer_properties.hpp> #include <mbgl/layout/symbol_feature.hpp> #include <mbgl/layout/symbol_instance.hpp> +#include <mbgl/text/bidi.hpp> #include <memory> #include <map> @@ -33,7 +34,7 @@ public: const MapMode, const GeometryTileLayer&, const style::Filter&, - style::SymbolLayoutProperties, + style::SymbolLayoutProperties::Evaluated, float textMaxSize, SpriteAtlas&); @@ -58,14 +59,13 @@ public: const std::string sourceLayerName; private: - void addFeature(const GeometryCollection&, + void addFeature(const SymbolFeature&, const Shaping& shapedText, const PositionedIcon& shapedIcon, - const GlyphPositions& face, - const size_t index); + const GlyphPositions& face); - bool anchorIsTooClose(const std::u32string& text, const float repeatDistance, Anchor&); - std::map<std::u32string, std::vector<Anchor>> compareText; + bool anchorIsTooClose(const std::u16string& text, const float repeatDistance, const Anchor&); + std::map<std::u16string, std::vector<Anchor>> compareText; void addToDebugBuffers(CollisionTile&, SymbolBucket&); @@ -77,7 +77,7 @@ private: const float overscaling; const float zoom; const MapMode mode; - const style::SymbolLayoutProperties layout; + const style::SymbolLayoutProperties::Evaluated layout; const float textMaxSize; SpriteAtlas& spriteAtlas; @@ -91,6 +91,8 @@ private: GlyphRangeSet ranges; std::vector<SymbolInstance> symbolInstances; std::vector<SymbolFeature> features; + + BiDi bidi; // Consider moving this up to geometry tile worker to reduce reinstantiation costs; use of BiDi/ubiditransform object must be constrained to one thread }; } // namespace mbgl diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 1efc1c063a..d76044cd47 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -23,7 +23,8 @@ #include <mbgl/util/mapbox.hpp> #include <mbgl/util/tile_coordinate.hpp> #include <mbgl/actor/scheduler.hpp> -#include <mbgl/platform/log.hpp> +#include <mbgl/util/logging.hpp> +#include <mbgl/math/log2.hpp> namespace mbgl { @@ -46,7 +47,8 @@ struct StillImageRequest { class Map::Impl : public style::Observer { public: - Impl(Backend&, + Impl(Map&, + Backend&, float pixelRatio, FileSource&, Scheduler&, @@ -66,6 +68,7 @@ public: void loadStyleJSON(const std::string&); + Map& map; Backend& backend; FileSource& fileSource; Scheduler& scheduler; @@ -89,6 +92,7 @@ public: std::string styleURL; std::string styleJSON; bool styleMutated = false; + bool cameraMutated = false; std::unique_ptr<AsyncRequest> styleRequest; @@ -99,7 +103,7 @@ public: }; Map::Map(Backend& backend, - const std::array<uint16_t, 2> size, + const Size size, const float pixelRatio, FileSource& fileSource, Scheduler& scheduler, @@ -107,7 +111,8 @@ Map::Map(Backend& backend, GLContextMode contextMode, ConstrainMode constrainMode, ViewportMode viewportMode) - : impl(std::make_unique<Impl>(backend, + : impl(std::make_unique<Impl>(*this, + backend, pixelRatio, fileSource, scheduler, @@ -118,7 +123,8 @@ Map::Map(Backend& backend, impl->transform.resize(size); } -Map::Impl::Impl(Backend& backend_, +Map::Impl::Impl(Map& map_, + Backend& backend_, float pixelRatio_, FileSource& fileSource_, Scheduler& scheduler_, @@ -126,7 +132,8 @@ Map::Impl::Impl(Backend& backend_, GLContextMode contextMode_, ConstrainMode constrainMode_, ViewportMode viewportMode_) - : backend(backend_), + : map(map_), + backend(backend_), fileSource(fileSource_), scheduler(scheduler_), transform([this](MapChange change) { backend.notifyMapChange(change); }, @@ -282,7 +289,7 @@ void Map::Impl::update() { void Map::Impl::render(View& view) { if (!painter) { - painter = std::make_unique<Painter>(backend.getContext(), transform.getState()); + painter = std::make_unique<Painter>(backend.getContext(), transform.getState(), pixelRatio); } FrameData frameData { timePoint, @@ -384,6 +391,14 @@ void Map::Impl::loadStyleJSON(const std::string& json) { // force style cascade, causing all pending transitions to complete. style->cascade(Clock::now(), mode); + if (!cameraMutated) { + // Zoom first because it may constrain subsequent operations. + map.setZoom(map.getDefaultZoom()); + map.setLatLng(map.getDefaultLatLng()); + map.setBearing(map.getDefaultBearing()); + map.setPitch(map.getDefaultPitch()); + } + updateFlags |= Update::Classes | Update::RecalculateStyle | Update::AnnotationStyle; asyncUpdate.send(); } @@ -431,16 +446,19 @@ CameraOptions Map::getCameraOptions(optional<EdgeInsets> padding) const { } void Map::jumpTo(const CameraOptions& camera) { + impl->cameraMutated = true; impl->transform.jumpTo(camera); impl->onUpdate(camera.zoom ? Update::RecalculateStyle : Update::Repaint); } void Map::easeTo(const CameraOptions& camera, const AnimationOptions& animation) { + impl->cameraMutated = true; impl->transform.easeTo(camera, animation); impl->onUpdate(camera.zoom ? Update::RecalculateStyle : Update::Repaint); } void Map::flyTo(const CameraOptions& camera, const AnimationOptions& animation) { + impl->cameraMutated = true; impl->transform.flyTo(camera, animation); impl->onUpdate(Update::RecalculateStyle); } @@ -448,20 +466,24 @@ void Map::flyTo(const CameraOptions& camera, const AnimationOptions& animation) #pragma mark - Position void Map::moveBy(const ScreenCoordinate& point, const Duration& duration) { + impl->cameraMutated = true; impl->transform.moveBy(point, duration); impl->onUpdate(Update::Repaint); } void Map::setLatLng(const LatLng& latLng, const Duration& duration) { + impl->cameraMutated = true; setLatLng(latLng, optional<ScreenCoordinate> {}, duration); } void Map::setLatLng(const LatLng& latLng, optional<EdgeInsets> padding, const Duration& duration) { + impl->cameraMutated = true; impl->transform.setLatLng(latLng, padding, duration); impl->onUpdate(Update::Repaint); } void Map::setLatLng(const LatLng& latLng, optional<ScreenCoordinate> anchor, const Duration& duration) { + impl->cameraMutated = true; impl->transform.setLatLng(latLng, anchor, duration); impl->onUpdate(Update::Repaint); } @@ -471,6 +493,7 @@ LatLng Map::getLatLng(optional<EdgeInsets> padding) const { } void Map::resetPosition(optional<EdgeInsets> padding) { + impl->cameraMutated = true; CameraOptions camera; camera.angle = 0; camera.pitch = 0; @@ -485,11 +508,13 @@ void Map::resetPosition(optional<EdgeInsets> padding) { #pragma mark - Scale void Map::scaleBy(double ds, optional<ScreenCoordinate> anchor, const Duration& duration) { + impl->cameraMutated = true; impl->transform.scaleBy(ds, anchor, duration); impl->onUpdate(Update::RecalculateStyle); } void Map::setScale(double scale, optional<ScreenCoordinate> anchor, const Duration& duration) { + impl->cameraMutated = true; impl->transform.setScale(scale, anchor, duration); impl->onUpdate(Update::RecalculateStyle); } @@ -499,10 +524,12 @@ double Map::getScale() const { } void Map::setZoom(double zoom, const Duration& duration) { + impl->cameraMutated = true; setZoom(zoom, {}, duration); } void Map::setZoom(double zoom, optional<EdgeInsets> padding, const Duration& duration) { + impl->cameraMutated = true; impl->transform.setZoom(zoom, padding, duration); impl->onUpdate(Update::RecalculateStyle); } @@ -512,10 +539,12 @@ double Map::getZoom() const { } void Map::setLatLngZoom(const LatLng& latLng, double zoom, const Duration& duration) { + impl->cameraMutated = true; setLatLngZoom(latLng, zoom, {}, duration); } void Map::setLatLngZoom(const LatLng& latLng, double zoom, optional<EdgeInsets> padding, const Duration& duration) { + impl->cameraMutated = true; impl->transform.setLatLngZoom(latLng, zoom, padding, duration); impl->onUpdate(Update::RecalculateStyle); } @@ -538,7 +567,7 @@ CameraOptions Map::cameraForLatLngs(const std::vector<LatLng>& latLngs, optional // Calculate the bounds of the possibly rotated shape with respect to the viewport. ScreenCoordinate nePixel = {-INFINITY, -INFINITY}; ScreenCoordinate swPixel = {INFINITY, INFINITY}; - double viewportHeight = getHeight(); + double viewportHeight = getSize().height; for (LatLng latLng : latLngs) { ScreenCoordinate pixel = pixelForLatLng(latLng); swPixel.x = std::min(swPixel.x, pixel.x); @@ -552,8 +581,8 @@ CameraOptions Map::cameraForLatLngs(const std::vector<LatLng>& latLngs, optional // Calculate the zoom level. double minScale = INFINITY; if (width > 0 || height > 0) { - double scaleX = getWidth() / width; - double scaleY = getHeight() / height; + double scaleX = double(getSize().width) / width; + double scaleY = double(getSize().height) / height; if (padding && *padding) { scaleX -= (padding->left + padding->right) / width; scaleY -= (padding->top + padding->bottom) / height; @@ -587,6 +616,7 @@ CameraOptions Map::cameraForLatLngs(const std::vector<LatLng>& latLngs, optional } void Map::resetZoom() { + impl->cameraMutated = true; setZoom(0); } @@ -614,36 +644,36 @@ double Map::getMaxZoom() const { #pragma mark - Size -void Map::setSize(const std::array<uint16_t, 2>& size) { +void Map::setSize(const Size size) { impl->transform.resize(size); impl->onUpdate(Update::Repaint); } -uint16_t Map::getWidth() const { - return impl->transform.getState().getWidth(); -} - -uint16_t Map::getHeight() const { - return impl->transform.getState().getHeight(); +Size Map::getSize() const { + return impl->transform.getState().getSize(); } #pragma mark - Rotation void Map::rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const Duration& duration) { + impl->cameraMutated = true; impl->transform.rotateBy(first, second, duration); impl->onUpdate(Update::Repaint); } void Map::setBearing(double degrees, const Duration& duration) { + impl->cameraMutated = true; setBearing(degrees, EdgeInsets(), duration); } void Map::setBearing(double degrees, optional<ScreenCoordinate> anchor, const Duration& duration) { + impl->cameraMutated = true; impl->transform.setAngle(-degrees * util::DEG2RAD, anchor, duration); impl->onUpdate(Update::Repaint); } void Map::setBearing(double degrees, optional<EdgeInsets> padding, const Duration& duration) { + impl->cameraMutated = true; impl->transform.setAngle(-degrees * util::DEG2RAD, padding, duration); impl->onUpdate(Update::Repaint); } @@ -653,6 +683,7 @@ double Map::getBearing() const { } void Map::resetNorth(const Duration& duration) { + impl->cameraMutated = true; impl->transform.setAngle(0, duration); impl->onUpdate(Update::Repaint); } @@ -660,10 +691,12 @@ void Map::resetNorth(const Duration& duration) { #pragma mark - Pitch void Map::setPitch(double pitch, const Duration& duration) { + impl->cameraMutated = true; setPitch(pitch, {}, duration); } void Map::setPitch(double pitch, optional<ScreenCoordinate> anchor, const Duration& duration) { + impl->cameraMutated = true; impl->transform.setPitch(pitch * util::DEG2RAD, anchor, duration); impl->onUpdate(Update::Repaint); } @@ -789,7 +822,8 @@ AnnotationIDs Map::queryPointAnnotations(const ScreenBox& box) { std::set<AnnotationID> set; for (auto &feature : features) { assert(feature.id); - assert(*feature.id <= std::numeric_limits<AnnotationID>::max()); + assert(feature.id->is<uint64_t>()); + assert(feature.id->get<uint64_t>() <= std::numeric_limits<AnnotationID>::max()); set.insert(static_cast<AnnotationID>(feature.id->get<uint64_t>())); } AnnotationIDs ids; @@ -826,7 +860,7 @@ std::unique_ptr<Source> Map::removeSource(const std::string& sourceID) { } return nullptr; } - + std::vector<style::Layer*> Map::getLayers() { return impl->style ? impl->style->getLayers() : std::vector<style::Layer*>(); } diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp index 85805a109d..ba5e205301 100644 --- a/src/mbgl/map/transform.cpp +++ b/src/mbgl/map/transform.cpp @@ -9,8 +9,8 @@ #include <mbgl/util/chrono.hpp> #include <mbgl/util/projection.hpp> #include <mbgl/math/clamp.hpp> -#include <mbgl/platform/log.hpp> -#include <mbgl/platform/platform.hpp> +#include <mbgl/util/logging.hpp> +#include <mbgl/util/platform.hpp> #include <cstdio> #include <cmath> @@ -45,8 +45,8 @@ Transform::Transform(std::function<void(MapChange)> callback_, #pragma mark - Map View -bool Transform::resize(const std::array<uint16_t, 2> size) { - if (state.width == size[0] && state.height == size[1]) { +bool Transform::resize(const Size size) { + if (state.size == size) { return false; } @@ -54,8 +54,7 @@ bool Transform::resize(const std::array<uint16_t, 2> size) { callback(MapChangeRegionWillChange); } - state.width = size[0]; - state.height = size[1]; + state.size = size; state.constrain(state.scale, state.x, state.y); if (callback) { @@ -117,7 +116,7 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim const Point<double> endPoint = Projection::project(latLng, state.scale); ScreenCoordinate center = getScreenCoordinate(padding); - center.y = state.height - center.y; + center.y = state.size.height - center.y; // Constrain camera options. zoom = util::clamp(zoom, state.getMinZoom(), state.getMaxZoom()); @@ -187,7 +186,7 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima const Point<double> endPoint = Projection::project(latLng, state.scale); ScreenCoordinate center = getScreenCoordinate(padding); - center.y = state.height - center.y; + center.y = state.size.height - center.y; // Constrain camera options. zoom = util::clamp(zoom, state.getMinZoom(), state.getMaxZoom()); @@ -203,9 +202,9 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima /// w₀: Initial visible span, measured in pixels at the initial scale. /// Known henceforth as a <i>screenful</i>. - double w0 = padding ? std::max(state.width, state.height) - : std::max(state.width - padding.left - padding.right, - state.height - padding.top - padding.bottom); + double w0 = padding ? std::max(state.size.width, state.size.height) + : std::max(state.size.width - padding.left - padding.right, + state.size.height - padding.top - padding.bottom); /// w₁: Final visible span, measured in pixels with respect to the initial /// scale. double w1 = w0 / state.zoomScale(zoom - startZoom); @@ -355,8 +354,8 @@ void Transform::setLatLng(const LatLng& latLng, optional<ScreenCoordinate> ancho EdgeInsets padding; padding.top = anchor->y; padding.left = anchor->x; - padding.bottom = state.height - anchor->y; - padding.right = state.width - anchor->x; + padding.bottom = state.size.height - anchor->y; + padding.right = state.size.width - anchor->x; if (padding) camera.padding = padding; } easeTo(camera, duration); @@ -378,7 +377,7 @@ void Transform::setLatLngZoom(const LatLng& latLng, double zoom, optional<EdgeIn LatLng Transform::getLatLng(optional<EdgeInsets> padding) const { if (padding && *padding) { - return screenCoordinateToLatLng(padding->getCenter(state.width, state.height)); + return screenCoordinateToLatLng(padding->getCenter(state.size.width, state.size.height)); } else { return state.getLatLng(); } @@ -386,9 +385,9 @@ LatLng Transform::getLatLng(optional<EdgeInsets> padding) const { ScreenCoordinate Transform::getScreenCoordinate(optional<EdgeInsets> padding) const { if (padding && *padding) { - return padding->getCenter(state.width, state.height); + return padding->getCenter(state.size.width, state.size.height); } else { - return { state.width / 2., state.height / 2. }; + return { state.size.width / 2., state.size.height / 2. }; } } @@ -565,7 +564,7 @@ void Transform::startTransition(const CameraOptions& camera, optional<ScreenCoordinate> anchor = camera.anchor; LatLng anchorLatLng; if (anchor) { - anchor->y = state.getHeight() - anchor->y; + anchor->y = state.size.height - anchor->y; anchorLatLng = state.screenCoordinateToLatLng(*anchor); } @@ -650,13 +649,13 @@ ScreenCoordinate Transform::latLngToScreenCoordinate(const LatLng& latLng) const LatLng unwrappedLatLng = latLng.wrapped(); unwrappedLatLng.unwrapForShortestPath(getLatLng()); ScreenCoordinate point = state.latLngToScreenCoordinate(unwrappedLatLng); - point.y = state.height - point.y; + point.y = state.size.height - point.y; return point; } LatLng Transform::screenCoordinateToLatLng(const ScreenCoordinate& point) const { ScreenCoordinate flippedPoint = point; - flippedPoint.y = state.height - flippedPoint.y; + flippedPoint.y = state.size.height - flippedPoint.y; return state.screenCoordinateToLatLng(flippedPoint).wrapped(); } diff --git a/src/mbgl/map/transform.hpp b/src/mbgl/map/transform.hpp index abc301b1cb..febe71035d 100644 --- a/src/mbgl/map/transform.hpp +++ b/src/mbgl/map/transform.hpp @@ -23,7 +23,7 @@ public: ViewportMode = ViewportMode::Default); // Map view - bool resize(std::array<uint16_t, 2> size); + bool resize(Size size); // Camera /** Returns the current camera options. */ diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index 4f6bcecdb6..59ae129518 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -2,7 +2,7 @@ #include <mbgl/tile/tile_id.hpp> #include <mbgl/util/constants.hpp> #include <mbgl/util/interpolate.hpp> -#include <mbgl/util/math.hpp> +#include <mbgl/math/log2.hpp> #include <mbgl/math/clamp.hpp> namespace mbgl { @@ -33,15 +33,16 @@ void TransformState::getProjMatrix(mat4& projMatrix) const { // Calculate z value of the farthest fragment that should be rendered. double farZ = std::cos(M_PI / 2.0f - getPitch()) * topHalfSurfaceDistance + getAltitude(); - matrix::perspective(projMatrix, 2.0f * std::atan((getHeight() / 2.0f) / getAltitude()), - double(getWidth()) / getHeight(), 0.1, farZ); + matrix::perspective(projMatrix, 2.0f * std::atan((size.height / 2.0f) / getAltitude()), + double(size.width) / size.height, 0.1, farZ); matrix::translate(projMatrix, projMatrix, 0, 0, -getAltitude()); // After the rotateX, z values are in pixel units. Convert them to // altitude unites. 1 altitude unit = the screen height. const bool flippedY = viewportMode == ViewportMode::FlippedY; - matrix::scale(projMatrix, projMatrix, 1, flippedY ? 1 : -1, 1.0f / (rotatedNorth() ? getWidth() : getHeight())); + matrix::scale(projMatrix, projMatrix, 1, flippedY ? 1 : -1, + 1.0f / (rotatedNorth() ? size.width : size.height)); using NO = NorthOrientation; switch (getNorthOrientation()) { @@ -53,18 +54,14 @@ void TransformState::getProjMatrix(mat4& projMatrix) const { matrix::rotate_z(projMatrix, projMatrix, getAngle() + getNorthOrientationAngle()); - matrix::translate(projMatrix, projMatrix, pixel_x() - getWidth() / 2.0f, - pixel_y() - getHeight() / 2.0f, 0); + matrix::translate(projMatrix, projMatrix, pixel_x() - size.width / 2.0f, + pixel_y() - size.height / 2.0f, 0); } #pragma mark - Dimensions -uint16_t TransformState::getWidth() const { - return width; -} - -uint16_t TransformState::getHeight() const { - return height; +Size TransformState::getSize() const { + return size; } #pragma mark - North Orientation @@ -108,23 +105,23 @@ LatLng TransformState::getLatLng(LatLng::WrapMode wrapMode) const { } double TransformState::pixel_x() const { - const double center = (width - Projection::worldSize(scale)) / 2; + const double center = (size.width - Projection::worldSize(scale)) / 2; return center + x; } double TransformState::pixel_y() const { - const double center = (height - Projection::worldSize(scale)) / 2; + const double center = (size.height - Projection::worldSize(scale)) / 2; return center + y; } #pragma mark - Zoom double TransformState::getZoom() const { - return std::log(scale) / M_LN2; + return scaleZoom(scale); } int32_t TransformState::getIntegerZoom() const { - return std::floor(getZoom()); + return getZoom(); } double TransformState::getZoomFraction() const { @@ -202,7 +199,7 @@ bool TransformState::isGestureInProgress() const { #pragma mark - Projection double TransformState::zoomScale(double zoom) const { - return std::pow(2.0f, zoom); + return std::pow(2.0, zoom); } double TransformState::scaleZoom(double s) const { @@ -210,7 +207,7 @@ double TransformState::scaleZoom(double s) const { } ScreenCoordinate TransformState::latLngToScreenCoordinate(const LatLng& latLng) const { - if (width == 0 || height == 0) { + if (!size) { return {}; } @@ -219,11 +216,11 @@ ScreenCoordinate TransformState::latLngToScreenCoordinate(const LatLng& latLng) Point<double> pt = Projection::project(latLng, scale) / double(util::tileSize); vec4 c = {{ pt.x, pt.y, 0, 1 }}; matrix::transformMat4(p, c, mat); - return { p[0] / p[3], height - p[1] / p[3] }; + return { p[0] / p[3], size.height - p[1] / p[3] }; } LatLng TransformState::screenCoordinateToLatLng(const ScreenCoordinate& point, LatLng::WrapMode wrapMode) const { - if (width == 0 || height == 0) { + if (!size) { return {}; } @@ -235,7 +232,7 @@ LatLng TransformState::screenCoordinateToLatLng(const ScreenCoordinate& point, L if (err) throw std::runtime_error("failed to invert coordinatePointMatrix"); - double flippedY = height - point.y; + double flippedY = size.height - point.y; // since we don't know the correct projected z value for the point, // unproject two points to get a line and then find the point on that @@ -273,7 +270,8 @@ mat4 TransformState::coordinatePointMatrix(double z) const { mat4 TransformState::getPixelMatrix() const { mat4 m; matrix::identity(m); - matrix::scale(m, m, width / 2.0f, -height / 2.0f, 1); + matrix::scale(m, m, + static_cast<double>(size.width) / 2, -static_cast<double>(size.height) / 2, 1); matrix::translate(m, m, 1, -1, 0); return m; } @@ -289,17 +287,17 @@ bool TransformState::rotatedNorth() const { void TransformState::constrain(double& scale_, double& x_, double& y_) const { // Constrain minimum scale to avoid zooming out far enough to show off-world areas. scale_ = util::max(scale_, - static_cast<double>((rotatedNorth() ? height : width) / util::tileSize), - static_cast<double>((rotatedNorth() ? width : height) / util::tileSize)); + static_cast<double>(rotatedNorth() ? size.height : size.width) / util::tileSize, + static_cast<double>(rotatedNorth() ? size.width : size.height) / util::tileSize); // Constrain min/max pan to avoid showing off-world areas. if (constrainMode == ConstrainMode::WidthAndHeight) { - double max_x = (scale_ * util::tileSize - (rotatedNorth() ? height : width)) / 2; + double max_x = (scale_ * util::tileSize - (rotatedNorth() ? size.height : size.width)) / 2; x_ = std::max(-max_x, std::min(x_, max_x)); } if (constrainMode != ConstrainMode::None) { - double max_y = (scale_ * util::tileSize - (rotatedNorth() ? width : height)) / 2; + double max_y = (scale_ * util::tileSize - (rotatedNorth() ? size.width : size.height)) / 2; y_ = std::max(-max_y, std::min(y_, max_y)); } } diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp index 8a12b62a9e..6faaf4ac41 100644 --- a/src/mbgl/map/transform_state.hpp +++ b/src/mbgl/map/transform_state.hpp @@ -6,6 +6,7 @@ #include <mbgl/util/constants.hpp> #include <mbgl/util/projection.hpp> #include <mbgl/util/mat4.hpp> +#include <mbgl/util/size.hpp> #include <cstdint> #include <array> @@ -26,8 +27,7 @@ public: void getProjMatrix(mat4& matrix) const; // Dimensions - uint16_t getWidth() const; - uint16_t getHeight() const; + Size getSize() const; // North Orientation NorthOrientation getNorthOrientation() const; @@ -84,7 +84,7 @@ private: NorthOrientation orientation = NorthOrientation::Upwards; // logical dimensions - uint16_t width = 0, height = 0; + Size size; mat4 coordinatePointMatrix(double z) const; mat4 getPixelMatrix() const; diff --git a/src/mbgl/util/math.cpp b/src/mbgl/math/log2.cpp index 7b1516c041..222e67dbd7 100644 --- a/src/mbgl/util/math.cpp +++ b/src/mbgl/math/log2.cpp @@ -1,4 +1,4 @@ -#include <mbgl/util/math.hpp> +#include <mbgl/math/log2.hpp> namespace mbgl { namespace util { @@ -21,15 +21,5 @@ uint32_t ceil_log2(uint64_t x) { return y; } -double log2(double x) { -// log2() is producing wrong results on ARMv5 binaries -// running on ARMv7+ CPUs. -#if defined(__ANDROID__) - return std::log(x) / 0.6931471805599453; // log(x) / log(2) -#else - return ::log2(x); -#endif -} - } // namespace util } // namespace mbgl diff --git a/src/mbgl/programs/attributes.hpp b/src/mbgl/programs/attributes.hpp new file mode 100644 index 0000000000..38bbe89377 --- /dev/null +++ b/src/mbgl/programs/attributes.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include <mbgl/gl/attribute.hpp> + +#include <cstdint> + +namespace mbgl { +namespace attributes { + +// Attributes common to several shaders. + +MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_pos); +MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_offset); +MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_extrude); +MBGL_DEFINE_ATTRIBUTE(uint16_t, 2, a_texture_pos); + +template <std::size_t N> +struct a_data : gl::Attribute<a_data<N>, uint8_t, N> { + static constexpr auto name = "a_data"; +}; + +} // namespace attributes +} // namespace mbgl diff --git a/src/mbgl/programs/circle_program.cpp b/src/mbgl/programs/circle_program.cpp new file mode 100644 index 0000000000..d6bc439feb --- /dev/null +++ b/src/mbgl/programs/circle_program.cpp @@ -0,0 +1,7 @@ +#include <mbgl/programs/circle_program.hpp> + +namespace mbgl { + +static_assert(sizeof(CircleProgram::Vertex) == 4, "expected CircleVertex size"); + +} // namespace mbgl diff --git a/src/mbgl/programs/circle_program.hpp b/src/mbgl/programs/circle_program.hpp new file mode 100644 index 0000000000..c9aea1d137 --- /dev/null +++ b/src/mbgl/programs/circle_program.hpp @@ -0,0 +1,59 @@ +#pragma once + +#include <mbgl/programs/program.hpp> +#include <mbgl/programs/attributes.hpp> +#include <mbgl/programs/uniforms.hpp> +#include <mbgl/shader/circle.hpp> +#include <mbgl/util/geometry.hpp> + +namespace mbgl { + +namespace uniforms { +MBGL_DEFINE_UNIFORM_SCALAR(float, u_radius); +MBGL_DEFINE_UNIFORM_SCALAR(Color, u_stroke_color); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_stroke_width); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_stroke_opacity); +MBGL_DEFINE_UNIFORM_SCALAR(bool, u_scale_with_map); +} // namespace uniforms + +using CircleAttributes = gl::Attributes< + attributes::a_pos>; + +class CircleProgram : public Program< + shaders::circle, + gl::Triangle, + CircleAttributes, + gl::Uniforms< + uniforms::u_matrix, + uniforms::u_opacity, + uniforms::u_color, + uniforms::u_radius, + uniforms::u_blur, + uniforms::u_stroke_color, + uniforms::u_stroke_width, + uniforms::u_stroke_opacity, + uniforms::u_scale_with_map, + uniforms::u_extrude_scale>> +{ +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 Vertex vertex(Point<int16_t> p, float ex, float ey) { + return Vertex { + { + static_cast<int16_t>((p.x * 2) + ((ex + 1) / 2)), + static_cast<int16_t>((p.y * 2) + ((ey + 1) / 2)) + } + }; + } +}; + +using CircleVertex = CircleProgram::Vertex; + +} // namespace mbgl diff --git a/src/mbgl/programs/collision_box_program.cpp b/src/mbgl/programs/collision_box_program.cpp new file mode 100644 index 0000000000..d6a36e54a1 --- /dev/null +++ b/src/mbgl/programs/collision_box_program.cpp @@ -0,0 +1,7 @@ +#include <mbgl/programs/collision_box_program.hpp> + +namespace mbgl { + +static_assert(sizeof(CollisionBoxProgram::Vertex) == 10, "expected CollisionBoxVertex size"); + +} // namespace mbgl diff --git a/src/mbgl/programs/collision_box_program.hpp b/src/mbgl/programs/collision_box_program.hpp new file mode 100644 index 0000000000..26e38419a4 --- /dev/null +++ b/src/mbgl/programs/collision_box_program.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include <mbgl/programs/program.hpp> +#include <mbgl/programs/attributes.hpp> +#include <mbgl/programs/uniforms.hpp> +#include <mbgl/shader/collision_box.hpp> +#include <mbgl/util/geometry.hpp> + +#include <cmath> + +namespace mbgl { + +namespace uniforms { +MBGL_DEFINE_UNIFORM_SCALAR(float, u_scale); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_maxzoom); +} // namespace uniforms + +using CollisionBoxAttributes = gl::Attributes< + attributes::a_pos, + attributes::a_extrude, + attributes::a_data<2>>; + +class CollisionBoxProgram : public Program< + shaders::collision_box, + gl::Line, + CollisionBoxAttributes, + gl::Uniforms< + uniforms::u_matrix, + uniforms::u_scale, + uniforms::u_zoom, + uniforms::u_maxzoom>> +{ +public: + using Program::Program; + + static Vertex vertex(Point<float> a, Point<float> o, float maxzoom, float placementZoom) { + return Vertex { + { + static_cast<int16_t>(a.x), + static_cast<int16_t>(a.y) + }, + { + static_cast<int16_t>(::round(o.x)), + static_cast<int16_t>(::round(o.y)) + }, + { + static_cast<uint8_t>(maxzoom * 10), + static_cast<uint8_t>(placementZoom * 10) + } + }; + } +}; + +using CollisionBoxVertex = CollisionBoxProgram::Vertex; + +} // namespace mbgl diff --git a/src/mbgl/programs/debug_program.hpp b/src/mbgl/programs/debug_program.hpp new file mode 100644 index 0000000000..cd4e08b1bc --- /dev/null +++ b/src/mbgl/programs/debug_program.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include <mbgl/programs/program.hpp> +#include <mbgl/programs/attributes.hpp> +#include <mbgl/programs/uniforms.hpp> +#include <mbgl/shader/debug.hpp> + +namespace mbgl { + +using DebugAttributes = gl::Attributes< + attributes::a_pos>; + +class DebugProgram : public Program< + shaders::debug, + gl::Line, + DebugAttributes, + gl::Uniforms< + uniforms::u_matrix, + uniforms::u_color>> +{ +public: + using Program::Program; +}; + +using DebugVertex = DebugProgram::Vertex; + +} // namespace mbgl diff --git a/src/mbgl/programs/fill_program.cpp b/src/mbgl/programs/fill_program.cpp new file mode 100644 index 0000000000..a8154d08f9 --- /dev/null +++ b/src/mbgl/programs/fill_program.cpp @@ -0,0 +1,47 @@ +#include <mbgl/programs/fill_program.hpp> +#include <mbgl/sprite/sprite_atlas.hpp> +#include <mbgl/style/cross_faded_property_evaluator.hpp> +#include <mbgl/tile/tile_id.hpp> +#include <mbgl/map/transform_state.hpp> + +namespace mbgl { + +using namespace style; + +static_assert(sizeof(FillAttributes::Vertex) == 4, "expected FillVertex size"); + +FillPatternUniforms::Values +FillPatternUniforms::values(mat4 matrix, + float opacity, + Size framebufferSize, + const SpriteAtlasPosition& a, + const SpriteAtlasPosition& b, + const Faded<std::string>& fading, + const UnwrappedTileID& tileID, + const TransformState& state) +{ + int32_t tileSizeAtNearestZoom = util::tileSize * state.zoomScale(state.getIntegerZoom() - tileID.canonical.z); + int32_t pixelX = tileSizeAtNearestZoom * (tileID.canonical.x + tileID.wrap * state.zoomScale(tileID.canonical.z)); + int32_t pixelY = tileSizeAtNearestZoom * tileID.canonical.y; + + return FillPatternUniforms::Values { + uniforms::u_matrix::Value{ matrix }, + uniforms::u_opacity::Value{ opacity }, + uniforms::u_world::Value{ framebufferSize }, + uniforms::u_pattern_tl_a::Value{ a.tl }, + uniforms::u_pattern_br_a::Value{ a.br }, + uniforms::u_pattern_tl_b::Value{ b.tl }, + uniforms::u_pattern_br_b::Value{ b.br }, + uniforms::u_pattern_size_a::Value{ a.size }, + uniforms::u_pattern_size_b::Value{ b.size }, + uniforms::u_scale_a::Value{ fading.fromScale }, + uniforms::u_scale_b::Value{ fading.toScale }, + uniforms::u_mix::Value{ fading.t }, + uniforms::u_image::Value{ 0 }, + uniforms::u_pixel_coord_upper::Value{ std::array<float, 2> {{ float(pixelX >> 16), float(pixelY >> 16) }} }, + uniforms::u_pixel_coord_lower::Value{ std::array<float, 2> {{ float(pixelX & 0xFFFF), float(pixelY & 0xFFFF) }} }, + uniforms::u_tile_units_to_pixels::Value{ 1.0f / tileID.pixelsToTileUnits(1.0f, state.getIntegerZoom()) }, + }; +} + +} // namespace mbgl diff --git a/src/mbgl/programs/fill_program.hpp b/src/mbgl/programs/fill_program.hpp new file mode 100644 index 0000000000..d885215c59 --- /dev/null +++ b/src/mbgl/programs/fill_program.hpp @@ -0,0 +1,123 @@ +#pragma once + +#include <mbgl/programs/program.hpp> +#include <mbgl/programs/attributes.hpp> +#include <mbgl/programs/uniforms.hpp> +#include <mbgl/shader/fill.hpp> +#include <mbgl/shader/fill_pattern.hpp> +#include <mbgl/shader/fill_outline.hpp> +#include <mbgl/shader/fill_outline_pattern.hpp> +#include <mbgl/util/geometry.hpp> +#include <mbgl/util/mat4.hpp> +#include <mbgl/util/size.hpp> + +#include <string> + +namespace mbgl { + +class SpriteAtlasPosition; +class UnwrappedTileID; +class TransformState; + +namespace style { +template <class> class Faded; +} // namespace style + +namespace uniforms { +MBGL_DEFINE_UNIFORM_SCALAR(Size, u_world); +MBGL_DEFINE_UNIFORM_SCALAR(Color, u_outline_color); +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_VECTOR(float, 2, u_pixel_coord_upper); +MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pixel_coord_lower); +} // namespace uniforms + +struct FillAttributes : gl::Attributes< + attributes::a_pos> +{ + static Vertex vertex(Point<int16_t> p) { + return Vertex { + { + p.x, + p.y + } + }; + } +}; + +using FillVertex = FillAttributes::Vertex; + +struct FillUniforms : gl::Uniforms< + uniforms::u_matrix, + uniforms::u_opacity, + uniforms::u_color, + uniforms::u_outline_color, + uniforms::u_world> +{}; + +struct FillPatternUniforms : gl::Uniforms< + uniforms::u_matrix, + uniforms::u_opacity, + uniforms::u_world, + uniforms::u_pattern_tl_a, + uniforms::u_pattern_br_a, + uniforms::u_pattern_tl_b, + uniforms::u_pattern_br_b, + uniforms::u_pattern_size_a, + uniforms::u_pattern_size_b, + uniforms::u_scale_a, + uniforms::u_scale_b, + uniforms::u_mix, + uniforms::u_image, + uniforms::u_pixel_coord_upper, + uniforms::u_pixel_coord_lower, + uniforms::u_tile_units_to_pixels> +{ + static Values values(mat4 matrix, + float opacity, + Size framebufferSize, + const SpriteAtlasPosition&, + const SpriteAtlasPosition&, + const style::Faded<std::string>&, + const UnwrappedTileID&, + const TransformState&); +}; + +class FillProgram : public Program< + shaders::fill, + gl::Triangle, + FillAttributes, + FillUniforms> +{ + using Program::Program; +}; + +class FillPatternProgram : public Program< + shaders::fill_pattern, + gl::Triangle, + FillAttributes, + FillPatternUniforms> +{ + using Program::Program; +}; + +class FillOutlineProgram : public Program< + shaders::fill_outline, + gl::Line, + FillAttributes, + FillUniforms> +{ + using Program::Program; +}; + +class FillOutlinePatternProgram : public Program< + shaders::fill_outline_pattern, + gl::Line, + FillAttributes, + FillPatternUniforms> +{ + using Program::Program; +}; + +} // namespace mbgl diff --git a/src/mbgl/programs/line_program.cpp b/src/mbgl/programs/line_program.cpp new file mode 100644 index 0000000000..2cadaa6c11 --- /dev/null +++ b/src/mbgl/programs/line_program.cpp @@ -0,0 +1,129 @@ +#include <mbgl/programs/line_program.hpp> +#include <mbgl/style/layers/line_layer_properties.hpp> +#include <mbgl/renderer/render_tile.hpp> +#include <mbgl/map/transform_state.hpp> +#include <mbgl/util/mat2.hpp> +#include <mbgl/sprite/sprite_atlas.hpp> +#include <mbgl/geometry/line_atlas.hpp> + +namespace mbgl { + +using namespace style; + +static_assert(sizeof(LineAttributes::Vertex) == 8, "expected LineVertex size"); + +template <class Values, class...Args> +Values makeValues(const LinePaintProperties::Evaluated& properties, + const RenderTile& tile, + const TransformState& state, + Args&&... args) { + + mat2 antialiasingMatrix; + matrix::identity(antialiasingMatrix); + matrix::scale(antialiasingMatrix, antialiasingMatrix, 1.0, std::cos(state.getPitch())); + matrix::rotate(antialiasingMatrix, antialiasingMatrix, state.getAngle()); + + // calculate how much longer the real world distance is at the top of the screen + // than at the middle of the screen. + float topedgelength = std::sqrt(std::pow(state.getSize().height, 2.0f) / 4.0f * (1.0f + std::pow(state.getAltitude(), 2.0f))); + float x = state.getSize().height / 2.0f * std::tan(state.getPitch()); + + return Values { + uniforms::u_matrix::Value{ + tile.translatedMatrix(properties.get<LineTranslate>(), + properties.get<LineTranslateAnchor>(), + state) + }, + uniforms::u_opacity::Value{ properties.get<LineOpacity>() }, + uniforms::u_width::Value{ properties.get<LineWidth>() }, + uniforms::u_gapwidth::Value{ properties.get<LineGapWidth>() }, + uniforms::u_blur::Value{ properties.get<LineBlur>() }, + uniforms::u_offset::Value{ properties.get<LineOffset>() }, + uniforms::u_antialiasingmatrix::Value{ antialiasingMatrix }, + uniforms::u_ratio::Value{ 1.0f / tile.id.pixelsToTileUnits(1.0, state.getZoom()) }, + uniforms::u_extra::Value{ (topedgelength + x) / topedgelength - 1.0f }, + std::forward<Args>(args)... + }; +} + +LineProgram::UniformValues +LineProgram::uniformValues(const LinePaintProperties::Evaluated& properties, + const RenderTile& tile, + const TransformState& state) { + return makeValues<LineProgram::UniformValues>( + properties, + tile, + state, + uniforms::u_color::Value{ properties.get<LineColor>() } + ); +} + +LineSDFProgram::UniformValues +LineSDFProgram::uniformValues(const LinePaintProperties::Evaluated& properties, + float pixelRatio, + const RenderTile& tile, + const TransformState& state, + const LinePatternPos& posA, + const LinePatternPos& posB, + float dashLineWidth, + float atlasWidth) { + const float widthA = posA.width * properties.get<LineDasharray>().fromScale * dashLineWidth; + const float widthB = posB.width * properties.get<LineDasharray>().toScale * dashLineWidth; + + std::array<float, 2> scaleA {{ + 1.0f / tile.id.pixelsToTileUnits(widthA, state.getIntegerZoom()), + -posA.height / 2.0f + }}; + + std::array<float, 2> scaleB {{ + 1.0f / tile.id.pixelsToTileUnits(widthB, state.getIntegerZoom()), + -posB.height / 2.0f + }}; + + return makeValues<LineSDFProgram::UniformValues>( + properties, + tile, + state, + uniforms::u_color::Value{ properties.get<LineColor>() }, + uniforms::u_patternscale_a::Value{ scaleA }, + uniforms::u_patternscale_b::Value{ scaleB }, + uniforms::u_tex_y_a::Value{ posA.y }, + uniforms::u_tex_y_b::Value{ posB.y }, + uniforms::u_mix::Value{ properties.get<LineDasharray>().t }, + uniforms::u_sdfgamma::Value{ atlasWidth / (std::min(widthA, widthB) * 256.0f * pixelRatio) / 2.0f }, + uniforms::u_image::Value{ 0 } + ); +} + +LinePatternProgram::UniformValues +LinePatternProgram::uniformValues(const LinePaintProperties::Evaluated& properties, + const RenderTile& tile, + const TransformState& state, + const SpriteAtlasPosition& posA, + const SpriteAtlasPosition& posB) { + std::array<float, 2> sizeA {{ + tile.id.pixelsToTileUnits(posA.size[0] * properties.get<LinePattern>().fromScale, state.getIntegerZoom()), + posA.size[1] + }}; + + std::array<float, 2> sizeB {{ + tile.id.pixelsToTileUnits(posB.size[0] * properties.get<LinePattern>().toScale, state.getIntegerZoom()), + posB.size[1] + }}; + + return makeValues<LinePatternProgram::UniformValues>( + properties, + tile, + state, + uniforms::u_pattern_tl_a::Value{ posA.tl }, + uniforms::u_pattern_br_a::Value{ posA.br }, + uniforms::u_pattern_tl_b::Value{ posB.tl }, + uniforms::u_pattern_br_b::Value{ posB.br }, + uniforms::u_pattern_size_a::Value{ sizeA }, + uniforms::u_pattern_size_b::Value{ sizeB }, + uniforms::u_fade::Value{ properties.get<LinePattern>().t }, + uniforms::u_image::Value{ 0 } + ); +} + +} // namespace mbgl diff --git a/src/mbgl/programs/line_program.hpp b/src/mbgl/programs/line_program.hpp new file mode 100644 index 0000000000..059806ffb2 --- /dev/null +++ b/src/mbgl/programs/line_program.hpp @@ -0,0 +1,178 @@ +#pragma once + +#include <mbgl/programs/program.hpp> +#include <mbgl/programs/attributes.hpp> +#include <mbgl/programs/uniforms.hpp> +#include <mbgl/shader/line.hpp> +#include <mbgl/shader/line_pattern.hpp> +#include <mbgl/shader/line_sdf.hpp> +#include <mbgl/style/layers/line_layer_properties.hpp> +#include <mbgl/util/geometry.hpp> + +#include <cmath> + +namespace mbgl { + +class RenderTile; +class TransformState; +class LinePatternPos; +class SpriteAtlasPosition; + +namespace uniforms { +MBGL_DEFINE_UNIFORM_SCALAR(float, u_ratio); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_width); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_gapwidth); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_extra); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_offset); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_tex_y_a); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_tex_y_b); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_sdfgamma); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_fade); +MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_patternscale_a); +MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_patternscale_b); +MBGL_DEFINE_UNIFORM_MATRIX(double, 2, u_antialiasingmatrix); +} // namespace uniforms + +struct LineAttributes : gl::Attributes< + attributes::a_pos, + attributes::a_data<4>> +{ + /* + * @param p vertex position + * @param e extrude normal + * @param t texture normal + * @param dir direction of the line cap (-1/0/1) + */ + static Vertex vertex(Point<int16_t> p, Point<double> e, Point<bool> t, int8_t dir, int32_t linesofar = 0) { + return Vertex { + { + static_cast<int16_t>((p.x * 2) | t.x), + static_cast<int16_t>((p.y * 2) | t.y) + }, + { + // add 128 to store an byte in an unsigned byte + static_cast<uint8_t>(::round(extrudeScale * e.x) + 128), + static_cast<uint8_t>(::round(extrudeScale * e.y) + 128), + + // Encode the -1/0/1 direction value into the first two bits of .z of a_data. + // Combine it with the lower 6 bits of `linesofar` (shifted by 2 bites to make + // room for the direction value). The upper 8 bits of `linesofar` are placed in + // the `w` component. `linesofar` is scaled down by `LINE_DISTANCE_SCALE` so that + // we can store longer distances while sacrificing precision. + + // Encode the -1/0/1 direction value into .zw coordinates of a_data, which is normally covered + // by linesofar, so we need to merge them. + // The z component's first bit, as well as the sign bit is reserved for the direction, + // so we need to shift the linesofar. + static_cast<uint8_t>(((dir == 0 ? 0 : (dir < 0 ? -1 : 1 )) + 1) | ((linesofar & 0x3F) << 2)), + static_cast<uint8_t>(linesofar >> 6) + } + }; + } + + /* + * Scale the extrusion vector so that the normal length is this value. + * Contains the "texture" normals (-1..1). This is distinct from the extrude + * normals for line joins, because the x-value remains 0 for the texture + * normal array, while the extrude normal actually moves the vertex to create + * the acute/bevelled line join. + */ + static const int8_t extrudeScale = 63; +}; + +using LineVertex = LineAttributes::Vertex; + +class LineProgram : public Program< + shaders::line, + gl::Triangle, + LineAttributes, + gl::Uniforms< + uniforms::u_matrix, + uniforms::u_opacity, + uniforms::u_width, + uniforms::u_gapwidth, + uniforms::u_blur, + uniforms::u_offset, + uniforms::u_antialiasingmatrix, + uniforms::u_ratio, + uniforms::u_extra, + uniforms::u_color>> +{ +public: + using Program::Program; + + static UniformValues uniformValues(const style::LinePaintProperties::Evaluated&, + const RenderTile&, + const TransformState&); +}; + +class LinePatternProgram : public Program< + shaders::line_pattern, + gl::Triangle, + LineAttributes, + gl::Uniforms< + uniforms::u_matrix, + uniforms::u_opacity, + uniforms::u_width, + uniforms::u_gapwidth, + uniforms::u_blur, + uniforms::u_offset, + uniforms::u_antialiasingmatrix, + uniforms::u_ratio, + uniforms::u_extra, + uniforms::u_pattern_tl_a, + uniforms::u_pattern_br_a, + uniforms::u_pattern_tl_b, + uniforms::u_pattern_br_b, + uniforms::u_pattern_size_a, + uniforms::u_pattern_size_b, + uniforms::u_fade, + uniforms::u_image>> +{ +public: + using Program::Program; + + static UniformValues uniformValues(const style::LinePaintProperties::Evaluated&, + const RenderTile&, + const TransformState&, + const SpriteAtlasPosition& posA, + const SpriteAtlasPosition& posB); +}; + +class LineSDFProgram : public Program< + shaders::line_sdf, + gl::Triangle, + LineAttributes, + gl::Uniforms< + uniforms::u_matrix, + uniforms::u_opacity, + uniforms::u_width, + uniforms::u_gapwidth, + uniforms::u_blur, + uniforms::u_offset, + uniforms::u_antialiasingmatrix, + uniforms::u_ratio, + uniforms::u_extra, + uniforms::u_color, + uniforms::u_patternscale_a, + uniforms::u_patternscale_b, + uniforms::u_tex_y_a, + uniforms::u_tex_y_b, + uniforms::u_mix, + uniforms::u_sdfgamma, + uniforms::u_image>> +{ +public: + using Program::Program; + + static UniformValues uniformValues(const style::LinePaintProperties::Evaluated&, + float pixelRatio, + const RenderTile&, + const TransformState&, + const LinePatternPos& posA, + const LinePatternPos& posB, + float dashLineWidth, + float atlasWidth); +}; + +} // namespace mbgl diff --git a/src/mbgl/programs/program.hpp b/src/mbgl/programs/program.hpp new file mode 100644 index 0000000000..e5aae24997 --- /dev/null +++ b/src/mbgl/programs/program.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include <mbgl/gl/program.hpp> +#include <mbgl/programs/program_parameters.hpp> + +#include <sstream> +#include <cassert> + +namespace mbgl { + +template <class Shaders, class Primitive, class Attributes, class Uniforms> +class Program : public gl::Program<Primitive, Attributes, Uniforms> { +public: + using ParentType = gl::Program<Primitive, Attributes, Uniforms>; + + Program(gl::Context& context, const ProgramParameters& programParameters) + : ParentType(context, vertexSource(programParameters), fragmentSource(programParameters)) + {} + + static std::string pixelRatioDefine(const ProgramParameters& parameters) { + std::ostringstream pixelRatioSS; + pixelRatioSS.imbue(std::locale("C")); + pixelRatioSS.setf(std::ios_base::showpoint); + pixelRatioSS << parameters.pixelRatio; + return std::string("#define DEVICE_PIXEL_RATIO ") + pixelRatioSS.str() + "\n"; + } + + static std::string fragmentSource(const ProgramParameters& parameters) { + std::string source = pixelRatioDefine(parameters) + Shaders::fragmentSource; + if (parameters.overdraw) { + assert(source.find("#ifdef OVERDRAW_INSPECTOR") != std::string::npos); + source.replace(source.find_first_of('\n'), 1, "\n#define OVERDRAW_INSPECTOR\n"); + } + return source; + } + + static std::string vertexSource(const ProgramParameters& parameters) { + return pixelRatioDefine(parameters) + Shaders::vertexSource; + } + +}; + +} // namespace mbgl diff --git a/src/mbgl/programs/program_parameters.hpp b/src/mbgl/programs/program_parameters.hpp new file mode 100644 index 0000000000..ad8cbf1bf8 --- /dev/null +++ b/src/mbgl/programs/program_parameters.hpp @@ -0,0 +1,16 @@ +#pragma once + +namespace mbgl { + +class ProgramParameters { +public: + ProgramParameters(float pixelRatio_ = 1.0, bool overdraw_ = false) + : pixelRatio(pixelRatio_), + overdraw(overdraw_) {} + + float pixelRatio; + bool overdraw; +}; + +} // namespace mbgl + diff --git a/src/mbgl/programs/programs.hpp b/src/mbgl/programs/programs.hpp new file mode 100644 index 0000000000..dd71c2ce97 --- /dev/null +++ b/src/mbgl/programs/programs.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include <mbgl/programs/circle_program.hpp> +#include <mbgl/programs/fill_program.hpp> +#include <mbgl/programs/line_program.hpp> +#include <mbgl/programs/raster_program.hpp> +#include <mbgl/programs/symbol_program.hpp> +#include <mbgl/programs/debug_program.hpp> +#include <mbgl/programs/collision_box_program.hpp> +#include <mbgl/programs/program_parameters.hpp> + +namespace mbgl { + +class Programs { +public: + Programs(gl::Context& context, const ProgramParameters& programParameters) + : circle(context, programParameters), + fill(context, programParameters), + fillPattern(context, programParameters), + fillOutline(context, programParameters), + fillOutlinePattern(context, programParameters), + line(context, programParameters), + lineSDF(context, programParameters), + linePattern(context, programParameters), + raster(context, programParameters), + symbolIcon(context, programParameters), + symbolIconSDF(context, programParameters), + symbolGlyph(context, programParameters), + debug(context, ProgramParameters(programParameters.pixelRatio, false)), + collisionBox(context, ProgramParameters(programParameters.pixelRatio, false)) { + } + + CircleProgram circle; + FillProgram fill; + FillPatternProgram fillPattern; + FillOutlineProgram fillOutline; + FillOutlinePatternProgram fillOutlinePattern; + LineProgram line; + LineSDFProgram lineSDF; + LinePatternProgram linePattern; + RasterProgram raster; + SymbolIconProgram symbolIcon; + SymbolSDFProgram symbolIconSDF; + SymbolSDFProgram symbolGlyph; + + DebugProgram debug; + CollisionBoxProgram collisionBox; +}; + +} // namespace mbgl diff --git a/src/mbgl/programs/raster_program.cpp b/src/mbgl/programs/raster_program.cpp new file mode 100644 index 0000000000..ebec4c68cc --- /dev/null +++ b/src/mbgl/programs/raster_program.cpp @@ -0,0 +1,7 @@ +#include <mbgl/programs/raster_program.hpp> + +namespace mbgl { + +static_assert(sizeof(RasterProgram::Vertex) == 8, "expected RasterVertex size"); + +} // namespace mbgl diff --git a/src/mbgl/programs/raster_program.hpp b/src/mbgl/programs/raster_program.hpp new file mode 100644 index 0000000000..d6179904d2 --- /dev/null +++ b/src/mbgl/programs/raster_program.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include <mbgl/programs/program.hpp> +#include <mbgl/programs/attributes.hpp> +#include <mbgl/programs/uniforms.hpp> +#include <mbgl/shader/raster.hpp> +#include <mbgl/util/geometry.hpp> + +namespace mbgl { + +namespace uniforms { +MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_image0); +MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_image1); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_opacity0); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_opacity1); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_buffer_scale); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_brightness_low); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_brightness_high); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_saturation_factor); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_contrast_factor); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_scale_parent); +MBGL_DEFINE_UNIFORM_VECTOR(float, 3, u_spin_weights); +MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_tl_parent); +} // namespace uniforms + +using RasterAttributes = gl::Attributes< + attributes::a_pos, + attributes::a_texture_pos>; + +class RasterProgram : public Program< + shaders::raster, + gl::Triangle, + RasterAttributes, + gl::Uniforms< + uniforms::u_matrix, + uniforms::u_image0, + uniforms::u_image1, + uniforms::u_opacity0, + uniforms::u_opacity1, + uniforms::u_brightness_low, + uniforms::u_brightness_high, + uniforms::u_saturation_factor, + uniforms::u_contrast_factor, + uniforms::u_spin_weights, + uniforms::u_buffer_scale, + uniforms::u_scale_parent, + uniforms::u_tl_parent>> +{ +public: + using Program::Program; + + static Vertex vertex(Point<int16_t> p, Point<uint16_t> t) { + return Vertex { + { + p.x, + p.y + }, + { + t.x, + t.y + } + }; + } +}; + +using RasterVertex = RasterProgram::Vertex; + +} // namespace mbgl diff --git a/src/mbgl/programs/symbol_program.cpp b/src/mbgl/programs/symbol_program.cpp new file mode 100644 index 0000000000..8c9c34210c --- /dev/null +++ b/src/mbgl/programs/symbol_program.cpp @@ -0,0 +1,145 @@ +#include <mbgl/programs/symbol_program.hpp> +#include <mbgl/renderer/render_tile.hpp> +#include <mbgl/map/transform_state.hpp> +#include <mbgl/style/layers/symbol_layer_impl.hpp> + +namespace mbgl { + +using namespace style; + +static_assert(sizeof(SymbolAttributes::Vertex) == 16, "expected SymbolVertex size"); + +template <class Values, class...Args> +Values makeValues(const style::SymbolPropertyValues& values, + const Size& texsize, + const std::array<float, 2>& pixelsToGLUnits, + const RenderTile& tile, + const TransformState& state, + Args&&... args) { + std::array<float, 2> extrudeScale; + + const float scale = values.paintSize / values.sdfScale; + if (values.pitchAlignment == AlignmentType::Map) { + extrudeScale.fill(tile.id.pixelsToTileUnits(1, state.getZoom()) * scale); + } else { + extrudeScale = {{ + pixelsToGLUnits[0] * scale * state.getAltitude(), + pixelsToGLUnits[1] * scale * state.getAltitude() + }}; + } + + // adjust min/max zooms for variable font sies + float zoomAdjust = std::log(values.paintSize / values.layoutSize) / std::log(2); + + return Values { + uniforms::u_matrix::Value{ tile.translatedMatrix(values.translate, + values.translateAnchor, + state) }, + uniforms::u_opacity::Value{ values.opacity }, + uniforms::u_extrude_scale::Value{ extrudeScale }, + uniforms::u_texsize::Value{ std::array<float, 2> {{ float(texsize.width) / 4, float(texsize.height) / 4 }} }, + uniforms::u_zoom::Value{ float((state.getZoom() - zoomAdjust) * 10) }, + uniforms::u_rotate_with_map::Value{ values.rotationAlignment == AlignmentType::Map }, + uniforms::u_texture::Value{ 0 }, + uniforms::u_fadetexture::Value{ 1 }, + std::forward<Args>(args)... + }; +} + +SymbolIconProgram::UniformValues +SymbolIconProgram::uniformValues(const style::SymbolPropertyValues& values, + const Size& texsize, + const std::array<float, 2>& pixelsToGLUnits, + const RenderTile& tile, + const TransformState& state) +{ + return makeValues<SymbolIconProgram::UniformValues>( + values, + texsize, + pixelsToGLUnits, + tile, + state + ); +} + +static SymbolSDFProgram::UniformValues makeSDFValues(const style::SymbolPropertyValues& values, + const Size& texsize, + const std::array<float, 2>& pixelsToGLUnits, + const RenderTile& tile, + const TransformState& state, + float pixelRatio, + Color color, + float buffer, + float gammaAdjust) +{ + // The default gamma value has to be adjust for the current pixelratio so that we're not + // drawing blurry font on retina screens. + const float gammaBase = 0.105 * values.sdfScale / values.paintSize / pixelRatio; + const float gammaScale = values.pitchAlignment == AlignmentType::Map + ? 1.0 / std::cos(state.getPitch()) + : 1.0; + + return makeValues<SymbolSDFProgram::UniformValues>( + values, + texsize, + pixelsToGLUnits, + tile, + state, + uniforms::u_color::Value{ color }, + uniforms::u_buffer::Value{ buffer }, + uniforms::u_gamma::Value{ (gammaBase + gammaAdjust) * gammaScale }, + uniforms::u_pitch::Value{ state.getPitch() }, + uniforms::u_bearing::Value{ -1.0f * state.getAngle() }, + uniforms::u_aspect_ratio::Value{ (state.getSize().width * 1.0f) / (state.getSize().height * 1.0f) }, + uniforms::u_pitch_with_map::Value{ values.pitchAlignment == AlignmentType::Map } + ); +} + +SymbolSDFProgram::UniformValues +SymbolSDFProgram::haloUniformValues(const style::SymbolPropertyValues& values, + const Size& texsize, + const std::array<float, 2>& pixelsToGLUnits, + const RenderTile& tile, + const TransformState& state, + float pixelRatio) +{ + const float scale = values.paintSize / values.sdfScale; + const float sdfPx = 8.0f; + const float blurOffset = 1.19f; + const float haloOffset = 6.0f; + + return makeSDFValues( + values, + texsize, + pixelsToGLUnits, + tile, + state, + pixelRatio, + values.haloColor, + (haloOffset - values.haloWidth / scale) / sdfPx, + values.haloBlur * blurOffset / scale / sdfPx + ); +} + +SymbolSDFProgram::UniformValues +SymbolSDFProgram::foregroundUniformValues(const style::SymbolPropertyValues& values, + const Size& texsize, + const std::array<float, 2>& pixelsToGLUnits, + const RenderTile& tile, + const TransformState& state, + float pixelRatio) +{ + return makeSDFValues( + values, + texsize, + pixelsToGLUnits, + tile, + state, + pixelRatio, + values.color, + (256.0f - 64.0f) / 256.0f, + 0 + ); +} + +} // namespace mbgl diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp new file mode 100644 index 0000000000..be987551c0 --- /dev/null +++ b/src/mbgl/programs/symbol_program.hpp @@ -0,0 +1,136 @@ +#pragma once + +#include <mbgl/programs/program.hpp> +#include <mbgl/programs/attributes.hpp> +#include <mbgl/programs/uniforms.hpp> +#include <mbgl/shader/symbol_icon.hpp> +#include <mbgl/shader/symbol_sdf.hpp> +#include <mbgl/util/geometry.hpp> +#include <mbgl/util/size.hpp> + +#include <cmath> +#include <array> + +namespace mbgl { + +namespace style { +class SymbolPropertyValues; +} // namespace style + +class RenderTile; +class TransformState; + +namespace uniforms { +MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_texsize); +MBGL_DEFINE_UNIFORM_SCALAR(bool, u_rotate_with_map); +MBGL_DEFINE_UNIFORM_SCALAR(bool, u_pitch_with_map); +MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_texture); +MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_fadetexture); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_buffer); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_gamma); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_aspect_ratio); +} // namespace uniforms + +struct SymbolAttributes : gl::Attributes< + attributes::a_pos, + attributes::a_offset, + attributes::a_texture_pos, + attributes::a_data<4>> +{ + static Vertex vertex(Point<float> a, + Point<float> o, + uint16_t tx, + uint16_t ty, + float minzoom, + float maxzoom, + float labelminzoom, + uint8_t labelangle) { + return Vertex { + { + static_cast<int16_t>(a.x), + static_cast<int16_t>(a.y) + }, + { + static_cast<int16_t>(::round(o.x * 64)), // use 1/64 pixels for placement + static_cast<int16_t>(::round(o.y * 64)) + }, + { + static_cast<uint16_t>(tx / 4), + static_cast<uint16_t>(ty / 4) + }, + { + static_cast<uint8_t>(labelminzoom * 10), // 1/10 zoom levels: z16 == 160 + static_cast<uint8_t>(labelangle), + static_cast<uint8_t>(minzoom * 10), + static_cast<uint8_t>(::fmin(maxzoom, 25) * 10) + } + }; + } +}; + +using SymbolVertex = SymbolAttributes::Vertex; + +class SymbolIconProgram : public Program< + shaders::symbol_icon, + gl::Triangle, + SymbolAttributes, + gl::Uniforms< + uniforms::u_matrix, + uniforms::u_opacity, + uniforms::u_extrude_scale, + uniforms::u_texsize, + uniforms::u_zoom, + uniforms::u_rotate_with_map, + uniforms::u_texture, + uniforms::u_fadetexture>> +{ +public: + using Program::Program; + + static UniformValues uniformValues(const style::SymbolPropertyValues&, + const Size& texsize, + const std::array<float, 2>& pixelsToGLUnits, + const RenderTile&, + const TransformState&); +}; + +class SymbolSDFProgram : public Program< + shaders::symbol_sdf, + gl::Triangle, + SymbolAttributes, + gl::Uniforms< + uniforms::u_matrix, + uniforms::u_opacity, + uniforms::u_extrude_scale, + uniforms::u_texsize, + uniforms::u_zoom, + uniforms::u_rotate_with_map, + uniforms::u_texture, + uniforms::u_fadetexture, + uniforms::u_color, + uniforms::u_buffer, + uniforms::u_gamma, + uniforms::u_pitch, + uniforms::u_bearing, + uniforms::u_aspect_ratio, + uniforms::u_pitch_with_map>> +{ +public: + using Program::Program; + + static UniformValues haloUniformValues(const style::SymbolPropertyValues&, + const Size& texsize, + const std::array<float, 2>& pixelsToGLUnits, + const RenderTile&, + const TransformState&, + float pixelRatio); + + static UniformValues foregroundUniformValues(const style::SymbolPropertyValues&, + const Size& texsize, + const std::array<float, 2>& pixelsToGLUnits, + const RenderTile&, + const TransformState&, + float pixelRatio); +}; + +} // namespace mbgl diff --git a/src/mbgl/programs/uniforms.hpp b/src/mbgl/programs/uniforms.hpp new file mode 100644 index 0000000000..e0c5a0d361 --- /dev/null +++ b/src/mbgl/programs/uniforms.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include <mbgl/gl/uniform.hpp> +#include <mbgl/util/color.hpp> + +namespace mbgl { +namespace uniforms { + +// Uniforms common to several shaders. + +MBGL_DEFINE_UNIFORM_MATRIX(double, 4, u_matrix); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_opacity); +MBGL_DEFINE_UNIFORM_SCALAR(Color, u_color); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_blur); + +MBGL_DEFINE_UNIFORM_SCALAR(float, u_zoom); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_pitch); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_bearing); + +MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_extrude_scale); + +MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_tl_a); +MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_br_a); +MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_tl_b); +MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_br_b); +MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_size_a); +MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_size_b); + +MBGL_DEFINE_UNIFORM_SCALAR(float, u_mix); +MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_image); + +} // namespace uniforms +} // namespace mbgl diff --git a/src/mbgl/renderer/bucket.hpp b/src/mbgl/renderer/bucket.hpp index 2c3c7a6e47..49619c14f7 100644 --- a/src/mbgl/renderer/bucket.hpp +++ b/src/mbgl/renderer/bucket.hpp @@ -5,9 +5,6 @@ #include <atomic> -#define BUFFER_OFFSET_0 ((int8_t*)nullptr) -#define BUFFER_OFFSET(i) ((BUFFER_OFFSET_0) + (i)) - namespace mbgl { class Painter; @@ -38,8 +35,6 @@ public: virtual bool hasData() const = 0; - virtual bool needsClipping() const = 0; - bool needsUpload() const { return !uploaded; } diff --git a/src/mbgl/renderer/circle_bucket.cpp b/src/mbgl/renderer/circle_bucket.cpp index f12139d004..ba2285c4eb 100644 --- a/src/mbgl/renderer/circle_bucket.cpp +++ b/src/mbgl/renderer/circle_bucket.cpp @@ -1,8 +1,8 @@ #include <mbgl/renderer/circle_bucket.hpp> #include <mbgl/renderer/painter.hpp> -#include <mbgl/gl/gl.hpp> +#include <mbgl/gl/context.hpp> -#include <mbgl/shader/circle_shader.hpp> +#include <mbgl/programs/circle_program.hpp> #include <mbgl/style/layers/circle_layer.hpp> #include <mbgl/util/constants.hpp> @@ -13,10 +13,6 @@ using namespace style; CircleBucket::CircleBucket(MapMode mode_) : mode(mode_) { } -CircleBucket::~CircleBucket() { - // Do not remove. header file only contains forward definitions to unique pointers. -} - void CircleBucket::upload(gl::Context& context) { vertexBuffer = context.createVertexBuffer(std::move(vertices)); indexBuffer = context.createIndexBuffer(std::move(triangles)); @@ -31,18 +27,16 @@ void CircleBucket::render(Painter& painter, } bool CircleBucket::hasData() const { - return !groups.empty(); -} - -bool CircleBucket::needsClipping() const { - return true; + return !segments.empty(); } void CircleBucket::addGeometry(const GeometryCollection& geometryCollection) { + constexpr const uint16_t vertexLength = 4; + for (auto& circle : geometryCollection) { - for(auto & geometry : circle) { - auto x = geometry.x; - auto y = geometry.y; + for(auto& point : circle) { + 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 @@ -50,6 +44,11 @@ void CircleBucket::addGeometry(const GeometryCollection& geometryCollection) { if ((mode != MapMode::Still) && (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. // @@ -59,47 +58,23 @@ void CircleBucket::addGeometry(const GeometryCollection& geometryCollection) { // │ 1 2 │ // └─────────┘ // - vertices.emplace_back(x, y, -1, -1); // 1 - vertices.emplace_back(x, y, 1, -1); // 2 - vertices.emplace_back(x, y, 1, 1); // 3 - vertices.emplace_back(x, y, -1, 1); // 4 - - if (!groups.size() || groups.back().vertexLength + 4 > 65535) { - // Move to a new group because the old one can't hold the geometry. - groups.emplace_back(); - } + vertices.emplace_back(CircleProgram::vertex(point, -1, -1)); // 1 + vertices.emplace_back(CircleProgram::vertex(point, 1, -1)); // 2 + vertices.emplace_back(CircleProgram::vertex(point, 1, 1)); // 3 + vertices.emplace_back(CircleProgram::vertex(point, -1, 1)); // 4 - auto& group = groups.back(); - uint16_t index = group.vertexLength; + 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, - static_cast<uint16_t>(index + 1), - static_cast<uint16_t>(index + 2)); - triangles.emplace_back(index, - static_cast<uint16_t>(index + 3), - static_cast<uint16_t>(index + 2)); - - group.vertexLength += 4; - group.indexLength += 2; - } - } -} - -void CircleBucket::drawCircles(CircleShader& shader, gl::Context& context, PaintMode paintMode) { - GLbyte* vertexIndex = BUFFER_OFFSET(0); - GLbyte* elementsIndex = BUFFER_OFFSET(0); + triangles.emplace_back(index, index + 1, index + 2); + triangles.emplace_back(index, index + 3, index + 2); - for (auto& group : groups) { - if (!group.indexLength) continue; - - group.getVAO(shader, paintMode).bind(shader, *vertexBuffer, *indexBuffer, vertexIndex, context); - - MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(group.indexLength * 3), GL_UNSIGNED_SHORT, elementsIndex)); - - vertexIndex += group.vertexLength * vertexBuffer->vertexSize; - elementsIndex += group.indexLength * indexBuffer->primitiveSize; + segment.vertexLength += vertexLength; + segment.indexLength += 6; + } } } diff --git a/src/mbgl/renderer/circle_bucket.hpp b/src/mbgl/renderer/circle_bucket.hpp index 2f3faccdec..af7041a238 100644 --- a/src/mbgl/renderer/circle_bucket.hpp +++ b/src/mbgl/renderer/circle_bucket.hpp @@ -1,39 +1,31 @@ #pragma once #include <mbgl/renderer/bucket.hpp> -#include <mbgl/renderer/element_group.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/shader/circle_vertex.hpp> +#include <mbgl/gl/segment.hpp> +#include <mbgl/programs/circle_program.hpp> namespace mbgl { -class CircleShader; - class CircleBucket : public Bucket { public: CircleBucket(const MapMode); - ~CircleBucket() override; void upload(gl::Context&) override; void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override; bool hasData() const override; - bool needsClipping() const override; void addGeometry(const GeometryCollection&); - void drawCircles(CircleShader&, gl::Context&, PaintMode); - -private: - std::vector<CircleVertex> vertices; - std::vector<gl::Triangle> triangles; - - std::vector<ElementGroup<CircleShader>> groups; + gl::VertexVector<CircleVertex> vertices; + gl::IndexVector<gl::Triangles> triangles; + gl::SegmentVector<CircleAttributes> segments; optional<gl::VertexBuffer<CircleVertex>> vertexBuffer; - optional<gl::IndexBuffer<gl::Triangle>> indexBuffer; + optional<gl::IndexBuffer<gl::Triangles>> indexBuffer; const MapMode mode; }; diff --git a/src/mbgl/renderer/debug_bucket.cpp b/src/mbgl/renderer/debug_bucket.cpp index c47ae434be..167df4376f 100644 --- a/src/mbgl/renderer/debug_bucket.cpp +++ b/src/mbgl/renderer/debug_bucket.cpp @@ -1,25 +1,30 @@ #include <mbgl/renderer/debug_bucket.hpp> #include <mbgl/renderer/painter.hpp> -#include <mbgl/shader/fill_shader.hpp> -#include <mbgl/shader/fill_vertex.hpp> +#include <mbgl/programs/fill_program.hpp> #include <mbgl/geometry/debug_font_data.hpp> #include <mbgl/util/string.hpp> -#include <mbgl/gl/gl.hpp> - #include <cmath> #include <string> #include <vector> namespace mbgl { -std::vector<FillVertex> buildTextVertices(const OverscaledTileID& id, - const bool renderable, - const bool complete, - optional<Timestamp> modified, - optional<Timestamp> expires, - MapDebugOptions debugMode) { - std::vector<FillVertex> textPoints; +DebugBucket::DebugBucket(const OverscaledTileID& id, + const bool renderable_, + const bool complete_, + optional<Timestamp> modified_, + optional<Timestamp> expires_, + MapDebugOptions debugMode_, + gl::Context& context) + : renderable(renderable_), + complete(complete_), + modified(std::move(modified_)), + expires(std::move(expires_)), + debugMode(debugMode_) { + + gl::VertexVector<FillVertex> vertices; + gl::IndexVector<gl::Lines> indices; auto addText = [&] (const std::string& text, double left, double baseline, double scale) { for (uint8_t c : text) { @@ -38,9 +43,11 @@ std::vector<FillVertex> buildTextVertices(const OverscaledTileID& id, int16_t(::round(baseline - glyph.data[j + 1] * scale)) }; + vertices.emplace_back(FillAttributes::vertex(p)); + if (prev) { - textPoints.emplace_back(prev->x, prev->y); - textPoints.emplace_back(p.x, p.y); + indices.emplace_back(vertices.vertexSize() - 2, + vertices.vertexSize() - 1); } prev = p; @@ -67,36 +74,10 @@ std::vector<FillVertex> buildTextVertices(const OverscaledTileID& id, addText(expiresText, 50, baseline + 200, 5); } - return textPoints; -} - -DebugBucket::DebugBucket(const OverscaledTileID& id, - const bool renderable_, - const bool complete_, - optional<Timestamp> modified_, - optional<Timestamp> expires_, - MapDebugOptions debugMode_, - gl::Context& context) - : renderable(renderable_), - complete(complete_), - modified(std::move(modified_)), - expires(std::move(expires_)), - debugMode(debugMode_), - vertexBuffer(context.createVertexBuffer(buildTextVertices(id, renderable_, complete_, modified_, expires_, debugMode_))) { -} + segments.emplace_back(0, 0, vertices.vertexSize(), indices.indexSize()); -void DebugBucket::drawLines(FillShader& shader, gl::Context& context) { - if (vertexBuffer.vertexCount != 0) { - array.bind(shader, vertexBuffer, BUFFER_OFFSET_0, context); - MBGL_CHECK_ERROR(glDrawArrays(GL_LINES, 0, static_cast<GLsizei>(vertexBuffer.vertexCount))); - } -} - -void DebugBucket::drawPoints(FillShader& shader, gl::Context& context) { - if (vertexBuffer.vertexCount != 0) { - array.bind(shader, vertexBuffer, BUFFER_OFFSET_0, context); - MBGL_CHECK_ERROR(glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(vertexBuffer.vertexCount))); - } + vertexBuffer = context.createVertexBuffer(std::move(vertices)); + indexBuffer = context.createIndexBuffer(std::move(indices)); } } // namespace mbgl diff --git a/src/mbgl/renderer/debug_bucket.hpp b/src/mbgl/renderer/debug_bucket.hpp index 89087f0010..4676381789 100644 --- a/src/mbgl/renderer/debug_bucket.hpp +++ b/src/mbgl/renderer/debug_bucket.hpp @@ -6,13 +6,12 @@ #include <mbgl/util/optional.hpp> #include <mbgl/util/noncopyable.hpp> #include <mbgl/gl/vertex_buffer.hpp> -#include <mbgl/gl/vao.hpp> -#include <mbgl/shader/fill_vertex.hpp> +#include <mbgl/gl/index_buffer.hpp> +#include <mbgl/programs/debug_program.hpp> namespace mbgl { class OverscaledTileID; -class FillShader; namespace gl { class Context; @@ -28,18 +27,15 @@ public: MapDebugOptions, gl::Context&); - void drawLines(FillShader&, gl::Context&); - void drawPoints(FillShader&, gl::Context&); - const bool renderable; const bool complete; const optional<Timestamp> modified; const optional<Timestamp> expires; const MapDebugOptions debugMode; -private: - gl::VertexBuffer<FillVertex> vertexBuffer; - gl::VertexArrayObject array; + gl::SegmentVector<DebugAttributes> segments; + optional<gl::VertexBuffer<DebugVertex>> vertexBuffer; + optional<gl::IndexBuffer<gl::Lines>> indexBuffer; }; } // namespace mbgl diff --git a/src/mbgl/renderer/element_group.hpp b/src/mbgl/renderer/element_group.hpp deleted file mode 100644 index 59b5c3068d..0000000000 --- a/src/mbgl/renderer/element_group.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include <mbgl/gl/vao.hpp> -#include <mbgl/renderer/render_pass.hpp> - -namespace mbgl { - -template <class... Shaders> -struct ElementGroup { - template <class Shader> - struct VAOs { - gl::VertexArrayObject normalVAO; - gl::VertexArrayObject overdrawVAO; - }; - - std::tuple<VAOs<Shaders>...> vaos; - - template <class Shader> - gl::VertexArrayObject& getVAO(const Shader&, PaintMode paintMode) { - auto& vao = std::get<VAOs<Shader>>(vaos); - return paintMode == PaintMode::Overdraw ? vao.overdrawVAO : vao.normalVAO; - } - - std::size_t vertexLength = 0; - std::size_t indexLength = 0; -}; - -} // namespace mbgl diff --git a/src/mbgl/renderer/fill_bucket.cpp b/src/mbgl/renderer/fill_bucket.cpp index cd4277cabc..b89e982057 100644 --- a/src/mbgl/renderer/fill_bucket.cpp +++ b/src/mbgl/renderer/fill_bucket.cpp @@ -1,12 +1,8 @@ #include <mbgl/renderer/fill_bucket.hpp> #include <mbgl/style/layers/fill_layer.hpp> #include <mbgl/renderer/painter.hpp> -#include <mbgl/shader/fill_shader.hpp> -#include <mbgl/shader/fill_pattern_shader.hpp> -#include <mbgl/shader/fill_outline_shader.hpp> -#include <mbgl/shader/fill_outline_pattern_shader.hpp> -#include <mbgl/gl/gl.hpp> -#include <mbgl/platform/log.hpp> +#include <mbgl/programs/fill_program.hpp> +#include <mbgl/util/logging.hpp> #include <mapbox/earcut.hpp> @@ -30,11 +26,6 @@ using namespace style; struct GeometryTooLongException : std::exception {}; -FillBucket::FillBucket() { -} - -FillBucket::~FillBucket() = default; - void FillBucket::addGeometry(const GeometryCollection& geometry) { for (auto& polygon : classifyRings(geometry)) { // Optimize polygons with many interior rings for earcut tesselation. @@ -44,34 +35,36 @@ void FillBucket::addGeometry(const GeometryCollection& geometry) { for (const auto& ring : polygon) { totalVertices += ring.size(); - if (totalVertices > 65535) + if (totalVertices > std::numeric_limits<uint16_t>::max()) throw GeometryTooLongException(); } + std::size_t startVertices = vertices.vertexSize(); + for (const auto& ring : polygon) { std::size_t nVertices = ring.size(); if (nVertices == 0) continue; - if (lineGroups.empty() || lineGroups.back().vertexLength + nVertices > 65535) - lineGroups.emplace_back(); + if (lineSegments.empty() || lineSegments.back().vertexLength + nVertices > std::numeric_limits<uint16_t>::max()) { + lineSegments.emplace_back(vertices.vertexSize(), lines.indexSize()); + } - auto& lineGroup = lineGroups.back(); - uint16_t lineIndex = lineGroup.vertexLength; + auto& lineSegment = lineSegments.back(); + assert(lineSegment.vertexLength <= std::numeric_limits<uint16_t>::max()); + uint16_t lineIndex = lineSegment.vertexLength; - vertices.emplace_back(ring[0].x, ring[0].y); - lines.emplace_back(static_cast<uint16_t>(lineIndex + nVertices - 1), - static_cast<uint16_t>(lineIndex)); + vertices.emplace_back(FillAttributes::vertex(ring[0])); + lines.emplace_back(lineIndex + nVertices - 1, lineIndex); for (uint32_t i = 1; i < nVertices; i++) { - vertices.emplace_back(ring[i].x, ring[i].y); - lines.emplace_back(static_cast<uint16_t>(lineIndex + i - 1), - static_cast<uint16_t>(lineIndex + i)); + vertices.emplace_back(FillAttributes::vertex(ring[i])); + lines.emplace_back(lineIndex + i - 1, lineIndex + i); } - lineGroup.vertexLength += nVertices; - lineGroup.indexLength += nVertices; + lineSegment.vertexLength += nVertices; + lineSegment.indexLength += nVertices * 2; } std::vector<uint32_t> indices = mapbox::earcut(polygon); @@ -79,21 +72,22 @@ void FillBucket::addGeometry(const GeometryCollection& geometry) { std::size_t nIndicies = indices.size(); assert(nIndicies % 3 == 0); - if (triangleGroups.empty() || triangleGroups.back().vertexLength + totalVertices > 65535) { - triangleGroups.emplace_back(); + if (triangleSegments.empty() || triangleSegments.back().vertexLength + totalVertices > std::numeric_limits<uint16_t>::max()) { + triangleSegments.emplace_back(startVertices, triangles.indexSize()); } - auto& triangleGroup = triangleGroups.back(); - uint16_t triangleIndex = triangleGroup.vertexLength; + auto& triangleSegment = triangleSegments.back(); + assert(triangleSegment.vertexLength <= std::numeric_limits<uint16_t>::max()); + uint16_t triangleIndex = triangleSegment.vertexLength; for (uint32_t i = 0; i < nIndicies; i += 3) { - triangles.emplace_back(static_cast<uint16_t>(triangleIndex + indices[i]), - static_cast<uint16_t>(triangleIndex + indices[i + 1]), - static_cast<uint16_t>(triangleIndex + indices[i + 2])); + triangles.emplace_back(triangleIndex + indices[i], + triangleIndex + indices[i + 1], + triangleIndex + indices[i + 2]); } - triangleGroup.vertexLength += totalVertices; - triangleGroup.indexLength += nIndicies / 3; + triangleSegment.vertexLength += totalVertices; + triangleSegment.indexLength += nIndicies; } } @@ -114,71 +108,7 @@ void FillBucket::render(Painter& painter, } bool FillBucket::hasData() const { - return !triangleGroups.empty() || !lineGroups.empty(); -} - -bool FillBucket::needsClipping() const { - return true; -} - -void FillBucket::drawElements(FillShader& shader, - gl::Context& context, - PaintMode paintMode) { - GLbyte* vertex_index = BUFFER_OFFSET(0); - GLbyte* elements_index = BUFFER_OFFSET(0); - for (auto& group : triangleGroups) { - group.getVAO(shader, paintMode).bind( - shader, *vertexBuffer, *triangleIndexBuffer, vertex_index, context); - MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(group.indexLength * 3), GL_UNSIGNED_SHORT, - elements_index)); - vertex_index += group.vertexLength * vertexBuffer->vertexSize; - elements_index += group.indexLength * triangleIndexBuffer->primitiveSize; - } -} - -void FillBucket::drawElements(FillPatternShader& shader, - gl::Context& context, - PaintMode paintMode) { - GLbyte* vertex_index = BUFFER_OFFSET(0); - GLbyte* elements_index = BUFFER_OFFSET(0); - for (auto& group : triangleGroups) { - group.getVAO(shader, paintMode).bind( - shader, *vertexBuffer, *triangleIndexBuffer, vertex_index, context); - MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(group.indexLength * 3), GL_UNSIGNED_SHORT, - elements_index)); - vertex_index += group.vertexLength * vertexBuffer->vertexSize; - elements_index += group.indexLength * triangleIndexBuffer->primitiveSize; - } -} - -void FillBucket::drawVertices(FillOutlineShader& shader, - gl::Context& context, - PaintMode paintMode) { - GLbyte* vertex_index = BUFFER_OFFSET(0); - GLbyte* elements_index = BUFFER_OFFSET(0); - for (auto& group : lineGroups) { - group.getVAO(shader, paintMode).bind( - shader, *vertexBuffer, *lineIndexBuffer, vertex_index, context); - MBGL_CHECK_ERROR(glDrawElements(GL_LINES, static_cast<GLsizei>(group.indexLength * 2), GL_UNSIGNED_SHORT, - elements_index)); - vertex_index += group.vertexLength * vertexBuffer->vertexSize; - elements_index += group.indexLength * lineIndexBuffer->primitiveSize; - } -} - -void FillBucket::drawVertices(FillOutlinePatternShader& shader, - gl::Context& context, - PaintMode paintMode) { - GLbyte* vertex_index = BUFFER_OFFSET(0); - GLbyte* elements_index = BUFFER_OFFSET(0); - for (auto& group : lineGroups) { - group.getVAO(shader, paintMode).bind( - shader, *vertexBuffer, *lineIndexBuffer, vertex_index, context); - MBGL_CHECK_ERROR(glDrawElements(GL_LINES, static_cast<GLsizei>(group.indexLength * 2), GL_UNSIGNED_SHORT, - elements_index)); - vertex_index += group.vertexLength * vertexBuffer->vertexSize; - elements_index += group.indexLength * lineIndexBuffer->primitiveSize; - } + return !triangleSegments.empty() || !lineSegments.empty(); } } // namespace mbgl diff --git a/src/mbgl/renderer/fill_bucket.hpp b/src/mbgl/renderer/fill_bucket.hpp index 34cd886687..edb1521c1d 100644 --- a/src/mbgl/renderer/fill_bucket.hpp +++ b/src/mbgl/renderer/fill_bucket.hpp @@ -1,50 +1,33 @@ #pragma once #include <mbgl/renderer/bucket.hpp> -#include <mbgl/renderer/element_group.hpp> #include <mbgl/tile/geometry_tile_data.hpp> #include <mbgl/gl/vertex_buffer.hpp> #include <mbgl/gl/index_buffer.hpp> -#include <mbgl/shader/fill_vertex.hpp> +#include <mbgl/gl/segment.hpp> +#include <mbgl/programs/fill_program.hpp> #include <vector> -#include <memory> namespace mbgl { -class FillShader; -class FillPatternShader; -class FillOutlineShader; -class FillOutlinePatternShader; - class FillBucket : public Bucket { public: - FillBucket(); - ~FillBucket() override; - void upload(gl::Context&) override; void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override; bool hasData() const override; - bool needsClipping() const override; void addGeometry(const GeometryCollection&); - void drawElements(FillShader&, gl::Context&, PaintMode); - void drawElements(FillPatternShader&, gl::Context&, PaintMode); - void drawVertices(FillOutlineShader&, gl::Context&, PaintMode); - void drawVertices(FillOutlinePatternShader&, gl::Context&, PaintMode); - -private: - std::vector<FillVertex> vertices; - std::vector<gl::Line> lines; - std::vector<gl::Triangle> triangles; - - std::vector<ElementGroup<FillOutlineShader, FillOutlinePatternShader>> lineGroups; - std::vector<ElementGroup<FillShader, FillPatternShader>> triangleGroups; + gl::VertexVector<FillVertex> vertices; + gl::IndexVector<gl::Lines> lines; + gl::IndexVector<gl::Triangles> triangles; + gl::SegmentVector<FillAttributes> lineSegments; + gl::SegmentVector<FillAttributes> triangleSegments; optional<gl::VertexBuffer<FillVertex>> vertexBuffer; - optional<gl::IndexBuffer<gl::Line>> lineIndexBuffer; - optional<gl::IndexBuffer<gl::Triangle>> triangleIndexBuffer; + optional<gl::IndexBuffer<gl::Lines>> lineIndexBuffer; + optional<gl::IndexBuffer<gl::Triangles>> triangleIndexBuffer; }; } // namespace mbgl diff --git a/src/mbgl/renderer/frame_history.cpp b/src/mbgl/renderer/frame_history.cpp index daf24c8c37..1ee53d87b2 100644 --- a/src/mbgl/renderer/frame_history.cpp +++ b/src/mbgl/renderer/frame_history.cpp @@ -1,13 +1,14 @@ #include <mbgl/renderer/frame_history.hpp> #include <mbgl/math/minmax.hpp> #include <mbgl/gl/context.hpp> -#include <mbgl/gl/gl.hpp> + +#include <cassert> namespace mbgl { FrameHistory::FrameHistory() { changeOpacities.fill(0); - opacities.fill(0); + std::fill(opacities.data.get(), opacities.data.get() + opacities.bytes(), 0); } void FrameHistory::record(const TimePoint& now, float zoom, const Duration& duration) { @@ -18,7 +19,7 @@ void FrameHistory::record(const TimePoint& now, float zoom, const Duration& dura changeTimes.fill(now); for (int16_t z = 0; z <= zoomIndex; z++) { - opacities[z] = 255u; + opacities.data[z] = 255u; } firstFrame = false; } @@ -26,12 +27,12 @@ void FrameHistory::record(const TimePoint& now, float zoom, const Duration& dura if (zoomIndex < previousZoomIndex) { for (int16_t z = zoomIndex + 1; z <= previousZoomIndex; z++) { changeTimes[z] = now; - changeOpacities[z] = opacities[z]; + changeOpacities[z] = opacities.data[z]; } } else { for (int16_t z = zoomIndex; z > previousZoomIndex; z--) { changeTimes[z] = now; - changeOpacities[z] = opacities[z]; + changeOpacities[z] = opacities.data[z]; } } @@ -39,13 +40,13 @@ void FrameHistory::record(const TimePoint& now, float zoom, const Duration& dura std::chrono::duration<float> timeDiff = now - changeTimes[z]; int32_t opacityChange = (duration == Milliseconds(0) ? 1 : (timeDiff / duration)) * 255; if (z <= zoomIndex) { - opacities[z] = util::min(255, changeOpacities[z] + opacityChange); + opacities.data[z] = util::min(255, changeOpacities[z] + opacityChange); } else { - opacities[z] = util::max(0, changeOpacities[z] - opacityChange); + opacities.data[z] = util::max(0, changeOpacities[z] - opacityChange); } } - changed = true; + dirty = true; if (zoomIndex != previousZoomIndex) { previousZoomIndex = zoomIndex; @@ -60,58 +61,17 @@ bool FrameHistory::needsAnimation(const Duration& duration) const { } void FrameHistory::upload(gl::Context& context, uint32_t unit) { - - if (changed) { - const bool first = !texture; - bind(context, unit); - - if (first) { - MBGL_CHECK_ERROR(glTexImage2D( - GL_TEXTURE_2D, // GLenum target - 0, // GLint level - GL_ALPHA, // GLint internalformat - width, // GLsizei width - height, // GLsizei height - 0, // GLint border - GL_ALPHA, // GLenum format - GL_UNSIGNED_BYTE, // GLenum type - opacities.data() - )); - } else { - MBGL_CHECK_ERROR(glTexSubImage2D( - GL_TEXTURE_2D, // GLenum target - 0, // GLint level - 0, // GLint xoffset - 0, // GLint yoffset - width, // GLsizei width - height, // GLsizei height - GL_ALPHA, // GLenum format - GL_UNSIGNED_BYTE, // GLenum type - opacities.data() - )); - } - - changed = false; - + if (!texture) { + texture = context.createTexture(opacities, unit); + } else if (dirty) { + context.updateTexture(*texture, opacities, unit); } + dirty = false; } void FrameHistory::bind(gl::Context& context, uint32_t unit) { - if (!texture) { - texture = context.createTexture(); - context.activeTexture = unit; - context.texture[unit] = *texture; -#if not MBGL_USE_GLES2 - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); -#endif - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); - } else if (context.texture[unit] != *texture) { - context.activeTexture = unit; - context.texture[unit] = *texture; - } + upload(context, unit); + context.bindTexture(*texture, unit); } } // namespace mbgl diff --git a/src/mbgl/renderer/frame_history.hpp b/src/mbgl/renderer/frame_history.hpp index 063930af26..fffbd113ed 100644 --- a/src/mbgl/renderer/frame_history.hpp +++ b/src/mbgl/renderer/frame_history.hpp @@ -2,9 +2,10 @@ #include <array> -#include <mbgl/platform/platform.hpp> -#include <mbgl/gl/object.hpp> +#include <mbgl/util/platform.hpp> +#include <mbgl/gl/texture.hpp> #include <mbgl/util/chrono.hpp> +#include <mbgl/util/image.hpp> #include <mbgl/util/optional.hpp> namespace mbgl { @@ -23,20 +24,17 @@ public: void upload(gl::Context&, uint32_t); private: - const int width = 256; - const int height = 1; - std::array<TimePoint, 256> changeTimes; std::array<uint8_t, 256> changeOpacities; - std::array<uint8_t, 256> opacities; + const AlphaImage opacities{ { 256, 1 } }; int16_t previousZoomIndex = 0; - TimePoint previousTime = TimePoint::min(); - TimePoint time = TimePoint::min(); + TimePoint previousTime; + TimePoint time; bool firstFrame = true; - bool changed = true; + bool dirty = true; - mbgl::optional<gl::UniqueTexture> texture; + mbgl::optional<gl::Texture> texture; }; } // namespace mbgl diff --git a/src/mbgl/renderer/line_bucket.cpp b/src/mbgl/renderer/line_bucket.cpp index 7a5309bafc..007060bd1b 100644 --- a/src/mbgl/renderer/line_bucket.cpp +++ b/src/mbgl/renderer/line_bucket.cpp @@ -1,12 +1,8 @@ #include <mbgl/renderer/line_bucket.hpp> #include <mbgl/style/layers/line_layer.hpp> #include <mbgl/renderer/painter.hpp> -#include <mbgl/shader/line_shader.hpp> -#include <mbgl/shader/line_sdf_shader.hpp> -#include <mbgl/shader/line_pattern_shader.hpp> #include <mbgl/util/math.hpp> #include <mbgl/util/constants.hpp> -#include <mbgl/gl/gl.hpp> #include <cassert> @@ -54,8 +50,8 @@ const float LINE_DISTANCE_SCALE = 1.0 / 2.0; const float MAX_LINE_DISTANCE = std::pow(2, LINE_DISTANCE_BUFFER_BITS) / LINE_DISTANCE_SCALE; void LineBucket::addGeometry(const GeometryCoordinates& coordinates) { - const GLsizei len = [&coordinates] { - GLsizei l = static_cast<GLsizei>(coordinates.size()); + const std::size_t len = [&coordinates] { + std::size_t l = coordinates.size(); // If the line has duplicate vertices at the end, adjust length to remove them. while (l > 2 && coordinates[l - 1] == coordinates[l - 2]) { l--; @@ -68,7 +64,7 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates) { return; } - const float miterLimit = layout.lineJoin == LineJoinType::Bevel ? 1.05f : float(layout.lineMiterLimit); + const float miterLimit = layout.get<LineJoin>() == LineJoinType::Bevel ? 1.05f : float(layout.get<LineMiterLimit>()); const double sharpCornerOffset = SHARP_CORNER_OFFSET * (float(util::EXTENT) / (util::tileSize * overscaling)); @@ -81,8 +77,8 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates) { return; } - const LineCapType beginCap = layout.lineCap; - const LineCapType endCap = closed ? LineCapType::Butt : LineCapType(layout.lineCap); + const LineCapType beginCap = layout.get<LineCap>(); + const LineCapType endCap = closed ? LineCapType::Butt : LineCapType(layout.get<LineCap>()); double distance = 0; bool startOfLine = true; @@ -100,10 +96,10 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates) { nextNormal = util::perp(util::unit(convertPoint<double>(firstCoordinate - *currentCoordinate))); } - const std::size_t startVertex = vertices.size(); + const std::size_t startVertex = vertices.vertexSize(); std::vector<TriangleElement> triangleStore; - for (GLsizei i = 0; i < len; ++i) { + for (std::size_t i = 0; i < len; ++i) { if (closed && i == len - 1) { // if the line is closed, we treat the last vertex like the first nextCoordinate = coordinates[1]; @@ -175,12 +171,12 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates) { // The join if a middle vertex, otherwise the cap const bool middleVertex = prevCoordinate && nextCoordinate; - LineJoinType currentJoin = layout.lineJoin; + LineJoinType currentJoin = layout.get<LineJoin>(); const LineCapType currentCap = nextCoordinate ? beginCap : endCap; if (middleVertex) { if (currentJoin == LineJoinType::Round) { - if (miterLength < layout.lineRoundLimit) { + if (miterLength < layout.get<LineRoundLimit>()) { currentJoin = LineJoinType::Miter; } else if (miterLength <= 2) { currentJoin = LineJoinType::FakeRound; @@ -349,25 +345,23 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates) { startOfLine = false; } - const std::size_t endVertex = vertices.size(); + const std::size_t endVertex = vertices.vertexSize(); const std::size_t vertexCount = endVertex - startVertex; - if (groups.empty() || groups.back().vertexLength + vertexCount > 65535) { - // Move to a new group because the old one can't hold the geometry. - groups.emplace_back(); + if (segments.empty() || segments.back().vertexLength + vertexCount > std::numeric_limits<uint16_t>::max()) { + segments.emplace_back(startVertex, triangles.indexSize()); } - auto& group = groups.back(); - uint16_t index = group.vertexLength; + auto& segment = segments.back(); + assert(segment.vertexLength <= std::numeric_limits<uint16_t>::max()); + uint16_t index = segment.vertexLength; for (const auto& triangle : triangleStore) { - triangles.emplace_back(static_cast<uint16_t>(index + triangle.a), - static_cast<uint16_t>(index + triangle.b), - static_cast<uint16_t>(index + triangle.c)); + triangles.emplace_back(index + triangle.a, index + triangle.b, index + triangle.c); } - group.vertexLength += vertexCount; - group.indexLength += triangleStore.size(); + segment.vertexLength += vertexCount; + segment.indexLength += triangleStore.size() * 3; } void LineBucket::addCurrentVertex(const GeometryCoordinate& currentCoordinate, @@ -378,13 +372,11 @@ void LineBucket::addCurrentVertex(const GeometryCoordinate& currentCoordinate, bool round, std::size_t startVertex, std::vector<TriangleElement>& triangleStore) { - int8_t tx = round ? 1 : 0; - Point<double> extrude = normal; if (endLeft) extrude = extrude - (util::perp(normal) * endLeft); - vertices.emplace_back(currentCoordinate.x, currentCoordinate.y, extrude.x, extrude.y, tx, 0, endLeft, distance * LINE_DISTANCE_SCALE); - e3 = vertices.size() - 1 - startVertex; + vertices.emplace_back(LineAttributes::vertex(currentCoordinate, extrude, { round, false }, endLeft, distance * LINE_DISTANCE_SCALE)); + e3 = vertices.vertexSize() - 1 - startVertex; if (e1 >= 0 && e2 >= 0) { triangleStore.emplace_back(e1, e2, e3); } @@ -394,8 +386,8 @@ void LineBucket::addCurrentVertex(const GeometryCoordinate& currentCoordinate, extrude = normal * -1.0; if (endRight) extrude = extrude - (util::perp(normal) * endRight); - vertices.emplace_back(currentCoordinate.x, currentCoordinate.y, extrude.x, extrude.y, tx, 1, -endRight, distance * LINE_DISTANCE_SCALE); - e3 = vertices.size() - 1 - startVertex; + vertices.emplace_back(LineAttributes::vertex(currentCoordinate, extrude, { round, true }, -endRight, distance * LINE_DISTANCE_SCALE)); + e3 = vertices.vertexSize() - 1 - startVertex; if (e1 >= 0 && e2 >= 0) { triangleStore.emplace_back(e1, e2, e3); } @@ -418,11 +410,9 @@ void LineBucket::addPieSliceVertex(const GeometryCoordinate& currentVertex, bool lineTurnsLeft, std::size_t startVertex, std::vector<TriangleElement>& triangleStore) { - int8_t ty = lineTurnsLeft; - Point<double> flippedExtrude = extrude * (lineTurnsLeft ? -1.0 : 1.0); - vertices.emplace_back(currentVertex.x, currentVertex.y, flippedExtrude.x, flippedExtrude.y, 0, ty, 0, distance * LINE_DISTANCE_SCALE); - e3 = vertices.size() - 1 - startVertex; + vertices.emplace_back(LineAttributes::vertex(currentVertex, flippedExtrude, { false, lineTurnsLeft }, 0, distance * LINE_DISTANCE_SCALE)); + e3 = vertices.vertexSize() - 1 - startVertex; if (e1 >= 0 && e2 >= 0) { triangleStore.emplace_back(e1, e2, e3); } @@ -450,65 +440,7 @@ void LineBucket::render(Painter& painter, } bool LineBucket::hasData() const { - return !groups.empty(); -} - -bool LineBucket::needsClipping() const { - return true; -} - -void LineBucket::drawLines(LineShader& shader, - gl::Context& context, - PaintMode paintMode) { - GLbyte* vertex_index = BUFFER_OFFSET(0); - GLbyte* elements_index = BUFFER_OFFSET(0); - for (auto& group : groups) { - if (!group.indexLength) { - continue; - } - group.getVAO(shader, paintMode).bind( - shader, *vertexBuffer, *indexBuffer, vertex_index, context); - MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(group.indexLength * 3), GL_UNSIGNED_SHORT, - elements_index)); - vertex_index += group.vertexLength * vertexBuffer->vertexSize; - elements_index += group.indexLength * indexBuffer->primitiveSize; - } -} - -void LineBucket::drawLineSDF(LineSDFShader& shader, - gl::Context& context, - PaintMode paintMode) { - GLbyte* vertex_index = BUFFER_OFFSET(0); - GLbyte* elements_index = BUFFER_OFFSET(0); - for (auto& group : groups) { - if (!group.indexLength) { - continue; - } - group.getVAO(shader, paintMode).bind( - shader, *vertexBuffer, *indexBuffer, vertex_index, context); - MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(group.indexLength * 3), GL_UNSIGNED_SHORT, - elements_index)); - vertex_index += group.vertexLength * vertexBuffer->vertexSize; - elements_index += group.indexLength * indexBuffer->primitiveSize; - } -} - -void LineBucket::drawLinePatterns(LinePatternShader& shader, - gl::Context& context, - PaintMode paintMode) { - GLbyte* vertex_index = BUFFER_OFFSET(0); - GLbyte* elements_index = BUFFER_OFFSET(0); - for (auto& group : groups) { - if (!group.indexLength) { - continue; - } - group.getVAO(shader, paintMode).bind( - shader, *vertexBuffer, *indexBuffer, vertex_index, context); - MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(group.indexLength * 3), GL_UNSIGNED_SHORT, - elements_index)); - vertex_index += group.vertexLength * vertexBuffer->vertexSize; - elements_index += group.indexLength * indexBuffer->primitiveSize; - } + return !segments.empty(); } } // namespace mbgl diff --git a/src/mbgl/renderer/line_bucket.hpp b/src/mbgl/renderer/line_bucket.hpp index 14af710877..d11d78ff69 100644 --- a/src/mbgl/renderer/line_bucket.hpp +++ b/src/mbgl/renderer/line_bucket.hpp @@ -1,23 +1,18 @@ #pragma once #include <mbgl/renderer/bucket.hpp> -#include <mbgl/renderer/element_group.hpp> #include <mbgl/tile/geometry_tile_data.hpp> #include <mbgl/gl/vertex_buffer.hpp> #include <mbgl/gl/index_buffer.hpp> -#include <mbgl/shader/line_vertex.hpp> +#include <mbgl/gl/segment.hpp> +#include <mbgl/programs/line_program.hpp> #include <mbgl/style/layers/line_layer_properties.hpp> #include <vector> namespace mbgl { -class LineShader; -class LineSDFShader; -class LinePatternShader; - class LineBucket : public Bucket { - public: LineBucket(uint32_t overscaling); ~LineBucket() override; @@ -25,14 +20,18 @@ public: void upload(gl::Context&) override; void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override; bool hasData() const override; - bool needsClipping() const override; void addGeometry(const GeometryCollection&); void addGeometry(const GeometryCoordinates& line); - void drawLines(LineShader&, gl::Context&, PaintMode); - void drawLineSDF(LineSDFShader&, gl::Context&, PaintMode); - void drawLinePatterns(LinePatternShader&, gl::Context&, PaintMode); + style::LineLayoutProperties::Evaluated layout; + + gl::VertexVector<LineVertex> vertices; + gl::IndexVector<gl::Triangles> triangles; + gl::SegmentVector<LineAttributes> segments; + + optional<gl::VertexBuffer<LineVertex>> vertexBuffer; + optional<gl::IndexBuffer<gl::Triangles>> indexBuffer; private: struct TriangleElement { @@ -46,18 +45,6 @@ private: const Point<double>& extrude, bool lineTurnsLeft, std::size_t startVertex, std::vector<TriangleElement>& triangleStore); -public: - style::LineLayoutProperties layout; - -private: - std::vector<LineVertex> vertices; - std::vector<gl::Triangle> triangles; - - std::vector<ElementGroup<LineShader, LineSDFShader, LinePatternShader>> groups; - - optional<gl::VertexBuffer<LineVertex>> vertexBuffer; - optional<gl::IndexBuffer<gl::Triangle>> indexBuffer; - std::ptrdiff_t e1; std::ptrdiff_t e2; std::ptrdiff_t e3; diff --git a/src/mbgl/renderer/paint_parameters.hpp b/src/mbgl/renderer/paint_parameters.hpp index bd67dc9cfd..213c01cfbd 100644 --- a/src/mbgl/renderer/paint_parameters.hpp +++ b/src/mbgl/renderer/paint_parameters.hpp @@ -2,12 +2,12 @@ namespace mbgl { -class Shaders; +class Programs; class View; class PaintParameters { public: - Shaders& shaders; + Programs& programs; View& view; }; diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index fc61d6e0a0..5894912ef3 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -7,8 +7,7 @@ #include <mbgl/map/view.hpp> -#include <mbgl/platform/log.hpp> -#include <mbgl/gl/gl.hpp> +#include <mbgl/util/logging.hpp> #include <mbgl/gl/debugging.hpp> #include <mbgl/style/style.hpp> @@ -22,7 +21,8 @@ #include <mbgl/geometry/line_atlas.hpp> #include <mbgl/text/glyph_atlas.hpp> -#include <mbgl/shader/shaders.hpp> +#include <mbgl/programs/program_parameters.hpp> +#include <mbgl/programs/programs.hpp> #include <mbgl/algorithm/generate_clip_ids.hpp> #include <mbgl/algorithm/generate_clip_ids_impl.hpp> @@ -42,37 +42,63 @@ namespace mbgl { using namespace style; -Painter::Painter(gl::Context& context_, const TransformState& state_) +static gl::VertexVector<FillVertex> tileVertices() { + gl::VertexVector<FillVertex> result; + result.emplace_back(FillAttributes::vertex({ 0, 0 })); + result.emplace_back(FillAttributes::vertex({ util::EXTENT, 0 })); + result.emplace_back(FillAttributes::vertex({ 0, util::EXTENT })); + result.emplace_back(FillAttributes::vertex({ util::EXTENT, util::EXTENT })); + return result; +} + +static gl::IndexVector<gl::Triangles> tileTriangleIndices() { + gl::IndexVector<gl::Triangles> result; + result.emplace_back(0, 1, 2); + result.emplace_back(1, 2, 3); + return result; +} + +static gl::IndexVector<gl::LineStrip> tileLineStripIndices() { + gl::IndexVector<gl::LineStrip> result; + result.emplace_back(0); + result.emplace_back(1); + result.emplace_back(3); + result.emplace_back(2); + result.emplace_back(0); + return result; +} + +static gl::VertexVector<RasterVertex> rasterVertices() { + gl::VertexVector<RasterVertex> result; + result.emplace_back(RasterProgram::vertex({ 0, 0 }, { 0, 0 })); + result.emplace_back(RasterProgram::vertex({ util::EXTENT, 0 }, { 32767, 0 })); + result.emplace_back(RasterProgram::vertex({ 0, util::EXTENT }, { 0, 32767 })); + result.emplace_back(RasterProgram::vertex({ util::EXTENT, util::EXTENT }, { 32767, 32767 })); + return result; +} + +Painter::Painter(gl::Context& context_, const TransformState& state_, float pixelRatio) : context(context_), state(state_), - tileTriangleVertexBuffer(context.createVertexBuffer(std::vector<FillVertex> {{ - { 0, 0 }, - { util::EXTENT, 0 }, - { 0, util::EXTENT }, - { util::EXTENT, 0 }, - { 0, util::EXTENT }, - { util::EXTENT, util::EXTENT } - }})), - tileLineStripVertexBuffer(context.createVertexBuffer(std::vector<FillVertex> {{ - { 0, 0 }, - { util::EXTENT, 0 }, - { util::EXTENT, util::EXTENT }, - { 0, util::EXTENT }, - { 0, 0 } - }})), - rasterVertexBuffer(context.createVertexBuffer(std::vector<RasterVertex> {{ - { 0, 0, 0, 0 }, - { util::EXTENT, 0, 32767, 0 }, - { 0, util::EXTENT, 0, 32767 }, - { util::EXTENT, util::EXTENT, 32767, 32767 } - }})) { + tileVertexBuffer(context.createVertexBuffer(tileVertices())), + rasterVertexBuffer(context.createVertexBuffer(rasterVertices())), + tileTriangleIndexBuffer(context.createIndexBuffer(tileTriangleIndices())), + tileBorderIndexBuffer(context.createIndexBuffer(tileLineStripIndices())) { + + tileTriangleSegments.emplace_back(0, 0, 4, 6); + tileBorderSegments.emplace_back(0, 0, 4, 5); + rasterSegments.emplace_back(0, 0, 4, 6); + #ifndef NDEBUG gl::debugging::enable(); #endif - shaders = std::make_unique<Shaders>(context); + ProgramParameters programParameters{ pixelRatio, false }; + programs = std::make_unique<Programs>(context, programParameters); #ifndef NDEBUG - overdrawShaders = std::make_unique<Shaders>(context, gl::Shader::Overdraw); + + ProgramParameters programParametersOverdraw{ pixelRatio, true }; + overdrawPrograms = std::make_unique<Programs>(context, programParametersOverdraw); #endif } @@ -82,12 +108,6 @@ bool Painter::needsAnimation() const { return frameHistory.needsAnimation(util::DEFAULT_FADE_DURATION); } -void Painter::setClipping(const ClipID& clip) { - const GLint ref = (GLint)clip.reference.to_ulong(); - const GLuint mask = (GLuint)clip.mask.to_ulong(); - context.stencilFunc = { gl::StencilTestFunction::Equal, ref, mask }; -} - void Painter::cleanup() { context.performCleanup(); } @@ -100,9 +120,9 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp PaintParameters parameters { #ifndef NDEBUG - paintMode() == PaintMode::Overdraw ? *overdrawShaders : *shaders, + paintMode() == PaintMode::Overdraw ? *overdrawPrograms : *programs, #else - *shaders, + *programs, #endif view }; @@ -111,15 +131,14 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp spriteAtlas = style.spriteAtlas.get(); lineAtlas = style.lineAtlas.get(); - RenderData renderData = style.getRenderData(frame.debugOptions); + RenderData renderData = style.getRenderData(frame.debugOptions, state.getAngle()); const std::vector<RenderItem>& order = renderData.order; const std::unordered_set<Source*>& sources = renderData.sources; - const Color& background = renderData.backgroundColor; // Update the default matrices to the current viewport dimensions. state.getProjMatrix(projMatrix); - pixelsToGLUnits = {{ 2.0f / state.getWidth(), -2.0f / state.getHeight() }}; + pixelsToGLUnits = {{ 2.0f / state.getSize().width, -2.0f / state.getSize().height }}; if (state.getViewportMode() == ViewportMode::FlippedY) { pixelsToGLUnits[1] *= -1; } @@ -153,26 +172,11 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp { MBGL_DEBUG_GROUP("clear"); view.bind(); - context.stencilFunc = { gl::StencilTestFunction::Always, 0, ~0u }; - context.stencilTest = true; - context.stencilMask = 0xFF; - context.depthTest = false; - context.depthMask = true; - context.colorMask = { true, true, true, true }; - - if (paintMode() == PaintMode::Overdraw) { - context.blend = true; - context.blendFunc = { gl::BlendSourceFactor::ConstantColor, - gl::BlendDestinationFactor::One }; - const float overdraw = 1.0f / 8.0f; - context.blendColor = { overdraw, overdraw, overdraw, 0.0f }; - context.clearColor = Color::black(); - } else { - context.clearColor = background; - } - context.clearStencil = 0; - context.clearDepth = 1; - MBGL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); + context.clear(paintMode() == PaintMode::Overdraw + ? Color::black() + : renderData.backgroundColor, + 1.0f, + 0); } // - CLIPPING MASKS ---------------------------------------------------------------------------- @@ -186,7 +190,12 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp source->baseImpl->startRender(generator, projMatrix, state); } - drawClippingMasks(parameters, generator.getStencils()); + MBGL_DEBUG_GROUP("clipping masks"); + + for (const auto& stencil : generator.getStencils()) { + MBGL_DEBUG_GROUP(std::string{ "mask: " } + util::toString(stencil.first)); + renderClippingMask(stencil.first, stencil.second); + } } #if not MBGL_USE_GLES2 and not defined(NDEBUG) @@ -214,7 +223,7 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp renderPass(parameters, RenderPass::Translucent, order.begin(), order.end(), - static_cast<GLsizei>(order.size()) - 1, -1); + static_cast<uint32_t>(order.size()) - 1, -1); if (debug::renderTree) { Log::Info(Event::Render, "}"); indent--; } @@ -275,19 +284,6 @@ void Painter::renderPass(PaintParameters& parameters, if (!layer.baseImpl->hasRenderPass(pass)) continue; - if (paintMode() == PaintMode::Overdraw) { - context.blend = true; - } else if (pass == RenderPass::Translucent) { - context.blend = true; - context.blendFunc = { gl::BlendSourceFactor::One, - gl::BlendDestinationFactor::OneMinusSrcAlpha }; - } else { - context.blend = false; - } - - context.colorMask = { true, true, true, true }; - context.stencilMask = 0x0; - if (layer.is<BackgroundLayer>()) { MBGL_DEBUG_GROUP("background"); renderBackground(parameters, *layer.as<BackgroundLayer>()); @@ -296,11 +292,9 @@ void Painter::renderPass(PaintParameters& parameters, // Reset GL state to a known state so the CustomLayer always has a clean slate. context.vertexArrayObject = 0; - context.depthFunc = gl::DepthTestFunction::LessEqual; - context.depthTest = true; - context.depthMask = false; - context.stencilTest = false; - setDepthSublayer(0); + context.setDepthMode(depthModeForSublayer(0, gl::DepthMode::ReadOnly)); + context.setStencilMode(gl::StencilMode::disabled()); + context.setColorMode(colorModeForRenderPass()); layer.as<CustomLayer>()->impl->render(state); @@ -310,9 +304,6 @@ void Painter::renderPass(PaintParameters& parameters, context.setDirtyState(); } else { MBGL_DEBUG_GROUP(layer.baseImpl->id + " - " + util::toString(item.tile->id)); - if (item.bucket->needsClipping()) { - setClipping(item.tile->clip); - } item.bucket->render(*this, parameters, layer, *item.tile); } } @@ -322,10 +313,46 @@ void Painter::renderPass(PaintParameters& parameters, } } -void Painter::setDepthSublayer(int n) { +mat4 Painter::matrixForTile(const UnwrappedTileID& tileID) { + mat4 matrix; + state.matrixFor(matrix, tileID); + matrix::multiply(matrix, projMatrix, matrix); + return matrix; +} + +gl::DepthMode Painter::depthModeForSublayer(uint8_t n, gl::DepthMode::Mask mask) const { float nearDepth = ((1 + currentLayer) * numSublayers + n) * depthEpsilon; float farDepth = nearDepth + depthRangeSize; - context.depthRange = { nearDepth, farDepth }; + return gl::DepthMode { gl::DepthMode::LessEqual, mask, { nearDepth, farDepth } }; +} + +gl::StencilMode Painter::stencilModeForClipping(const ClipID& id) const { + return gl::StencilMode { + gl::StencilMode::Equal { static_cast<uint32_t>(id.mask.to_ulong()) }, + static_cast<int32_t>(id.reference.to_ulong()), + 0, + gl::StencilMode::Keep, + gl::StencilMode::Keep, + gl::StencilMode::Replace + }; +} + +gl::ColorMode Painter::colorModeForRenderPass() const { + if (paintMode() == PaintMode::Overdraw) { + const float overdraw = 1.0f / 8.0f; + return gl::ColorMode { + gl::ColorMode::Add { + gl::ColorMode::ConstantColor, + gl::ColorMode::One + }, + Color { overdraw, overdraw, overdraw, 0.0f }, + gl::ColorMode::Mask { true, true, true, true } + }; + } else if (pass == RenderPass::Translucent) { + return gl::ColorMode::alphaBlended(); + } else { + return gl::ColorMode::unblended(); + } } } // namespace mbgl diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp index f339ed1aed..dec7fa57fd 100644 --- a/src/mbgl/renderer/painter.hpp +++ b/src/mbgl/renderer/painter.hpp @@ -8,10 +8,11 @@ #include <mbgl/renderer/render_item.hpp> #include <mbgl/renderer/bucket.hpp> -#include <mbgl/gl/vao.hpp> #include <mbgl/gl/context.hpp> -#include <mbgl/shader/fill_vertex.hpp> -#include <mbgl/shader/raster_vertex.hpp> +#include <mbgl/programs/debug_program.hpp> +#include <mbgl/programs/program_parameters.hpp> +#include <mbgl/programs/fill_program.hpp> +#include <mbgl/programs/raster_program.hpp> #include <mbgl/style/style.hpp> @@ -41,8 +42,7 @@ class CircleBucket; class SymbolBucket; class RasterBucket; -class Shaders; -class SymbolSDFShader; +class Programs; class PaintParameters; struct ClipID; @@ -68,7 +68,7 @@ struct FrameData { class Painter : private util::noncopyable { public: - Painter(gl::Context&, const TransformState&); + Painter(gl::Context&, const TransformState&, float pixelRatio); ~Painter(); void render(const style::Style&, @@ -78,20 +78,8 @@ public: void cleanup(); - // Renders debug information for a tile. + void renderClippingMask(const UnwrappedTileID&, const ClipID&); void renderTileDebug(const RenderTile&); - - // Renders the red debug frame around a tile, visualizing its perimeter. - void renderDebugFrame(const mat4 &matrix); - -#ifndef NDEBUG - // Renders tile clip boundaries, using stencil buffer to calculate fill color. - void renderClipMasks(PaintParameters&); - // Renders the depth buffer. - void renderDepthBuffer(PaintParameters&); -#endif - - void renderDebugText(Tile&, const mat4&); void renderFill(PaintParameters&, FillBucket&, const style::FillLayer&, const RenderTile&); void renderLine(PaintParameters&, LineBucket&, const style::LineLayer&, const RenderTile&); void renderCircle(PaintParameters&, CircleBucket&, const style::CircleLayer&, const RenderTile&); @@ -99,11 +87,12 @@ public: void renderRaster(PaintParameters&, RasterBucket&, const style::RasterLayer&, const RenderTile&); void renderBackground(PaintParameters&, const style::BackgroundLayer&); - float saturationFactor(float saturation); - float contrastFactor(float contrast); - std::array<float, 3> spinWeights(float spin_value); - - void drawClippingMasks(PaintParameters&, const std::map<UnwrappedTileID, ClipID>&); +#ifndef NDEBUG + // Renders tile clip boundaries, using stencil buffer to calculate fill color. + void renderClipMasks(PaintParameters&); + // Renders the depth buffer. + void renderDepthBuffer(PaintParameters&); +#endif bool needsAnimation() const; @@ -116,31 +105,10 @@ private: Iterator it, Iterator end, uint32_t i, int8_t increment); - void setClipping(const ClipID&); - - void renderSDF(SymbolBucket&, - const RenderTile&, - float scaleDivisor, - std::array<float, 2> texsize, - SymbolSDFShader& sdfShader, - void (SymbolBucket::*drawSDF)(SymbolSDFShader&, gl::Context&, PaintMode), - - // Layout - style::AlignmentType rotationAlignment, - style::AlignmentType pitchAlignment, - float layoutSize, - - // Paint - float opacity, - Color color, - Color haloColor, - float haloWidth, - float haloBlur, - std::array<float, 2> translate, - style::TranslateAnchorType translateAnchor, - float paintSize); - - void setDepthSublayer(int n); + mat4 matrixForTile(const UnwrappedTileID&); + gl::DepthMode depthModeForSublayer(uint8_t n, gl::DepthMode::Mask) const; + gl::StencilMode stencilModeForClipping(const ClipID&) const; + gl::ColorMode colorModeForRenderPass() const; #ifndef NDEBUG PaintMode paintMode() const { @@ -185,16 +153,20 @@ private: FrameHistory frameHistory; - std::unique_ptr<Shaders> shaders; + std::unique_ptr<Programs> programs; #ifndef NDEBUG - std::unique_ptr<Shaders> overdrawShaders; + std::unique_ptr<Programs> overdrawPrograms; #endif - gl::VertexBuffer<FillVertex> tileTriangleVertexBuffer; - gl::VertexBuffer<FillVertex> tileLineStripVertexBuffer; + gl::VertexBuffer<FillVertex> tileVertexBuffer; gl::VertexBuffer<RasterVertex> rasterVertexBuffer; - gl::VertexArrayObject tileBorderArray; + gl::IndexBuffer<gl::Triangles> tileTriangleIndexBuffer; + gl::IndexBuffer<gl::LineStrip> tileBorderIndexBuffer; + + gl::SegmentVector<FillAttributes> tileTriangleSegments; + gl::SegmentVector<DebugAttributes> tileBorderSegments; + gl::SegmentVector<RasterAttributes> rasterSegments; }; } // namespace mbgl diff --git a/src/mbgl/renderer/painter_background.cpp b/src/mbgl/renderer/painter_background.cpp index 61ec76d1d8..4a3e41701d 100644 --- a/src/mbgl/renderer/painter_background.cpp +++ b/src/mbgl/renderer/painter_background.cpp @@ -1,12 +1,10 @@ #include <mbgl/renderer/painter.hpp> #include <mbgl/renderer/paint_parameters.hpp> -#include <mbgl/gl/gl.hpp> - #include <mbgl/style/layers/background_layer.hpp> #include <mbgl/style/layers/background_layer_impl.hpp> -#include <mbgl/shader/shaders.hpp> +#include <mbgl/programs/programs.hpp> +#include <mbgl/programs/fill_program.hpp> #include <mbgl/sprite/sprite_atlas.hpp> -#include <mbgl/util/mat4.hpp> #include <mbgl/util/tile_cover.hpp> namespace mbgl { @@ -16,75 +14,61 @@ using namespace style; void Painter::renderBackground(PaintParameters& parameters, const BackgroundLayer& layer) { // Note that for bottommost layers without a pattern, the background color is drawn with // glClear rather than this method. - const BackgroundPaintProperties& properties = layer.impl->paint; - - bool isPatterned = !properties.backgroundPattern.value.to.empty();// && false; - optional<SpriteAtlasPosition> imagePosA; - optional<SpriteAtlasPosition> imagePosB; - - auto& patternShader = parameters.shaders.fillPattern; - auto& plainShader = parameters.shaders.fill; - auto& arrayBackgroundPattern = parameters.shaders.backgroundPatternArray; - auto& arrayBackground = parameters.shaders.backgroundArray; + const BackgroundPaintProperties::Evaluated& properties = layer.impl->paint.evaluated; - if (isPatterned) { - imagePosA = spriteAtlas->getPosition(properties.backgroundPattern.value.from, - SpritePatternMode::Repeating); - imagePosB = spriteAtlas->getPosition(properties.backgroundPattern.value.to, - SpritePatternMode::Repeating); + if (!properties.get<BackgroundPattern>().to.empty()) { + optional<SpriteAtlasPosition> imagePosA = spriteAtlas->getPosition( + properties.get<BackgroundPattern>().from, SpritePatternMode::Repeating); + optional<SpriteAtlasPosition> imagePosB = spriteAtlas->getPosition( + properties.get<BackgroundPattern>().to, SpritePatternMode::Repeating); if (!imagePosA || !imagePosB) return; - context.program = patternShader.getID(); - patternShader.u_matrix = identityMatrix; - patternShader.u_pattern_tl_a = imagePosA->tl; - patternShader.u_pattern_br_a = imagePosA->br; - patternShader.u_pattern_tl_b = imagePosB->tl; - patternShader.u_pattern_br_b = imagePosB->br; - patternShader.u_mix = properties.backgroundPattern.value.t; - patternShader.u_opacity = properties.backgroundOpacity; - spriteAtlas->bind(true, context, 0); - arrayBackgroundPattern.bind(patternShader, tileTriangleVertexBuffer, BUFFER_OFFSET(0), context); + for (const auto& tileID : util::tileCover(state, state.getIntegerZoom())) { + parameters.programs.fillPattern.draw( + context, + gl::Triangles(), + depthModeForSublayer(0, gl::DepthMode::ReadOnly), + gl::StencilMode::disabled(), + colorModeForRenderPass(), + FillPatternUniforms::values( + matrixForTile(tileID), + properties.get<BackgroundOpacity>(), + context.viewport.getCurrentValue().size, + *imagePosA, + *imagePosB, + properties.get<BackgroundPattern>(), + tileID, + state + ), + tileVertexBuffer, + tileTriangleIndexBuffer, + tileTriangleSegments + ); + } } else { - context.program = plainShader.getID(); - plainShader.u_color = properties.backgroundColor; - plainShader.u_opacity = properties.backgroundOpacity; - - arrayBackground.bind(plainShader, tileTriangleVertexBuffer, BUFFER_OFFSET(0), context); - } - - context.stencilTest = false; - context.depthFunc = gl::DepthTestFunction::LessEqual; - context.depthTest = true; - context.depthMask = false; - setDepthSublayer(0); - - for (const auto& tileID : util::tileCover(state, state.getIntegerZoom())) { - mat4 vertexMatrix; - state.matrixFor(vertexMatrix, tileID); - matrix::multiply(vertexMatrix, projMatrix, vertexMatrix); - - if (isPatterned) { - patternShader.u_matrix = vertexMatrix; - patternShader.u_pattern_size_a = imagePosA->size; - patternShader.u_pattern_size_b = imagePosB->size; - patternShader.u_scale_a = properties.backgroundPattern.value.fromScale; - patternShader.u_scale_b = properties.backgroundPattern.value.toScale; - patternShader.u_tile_units_to_pixels = 1.0f / tileID.pixelsToTileUnits(1.0f, state.getIntegerZoom()); - - GLint tileSizeAtNearestZoom = util::tileSize * state.zoomScale(state.getIntegerZoom() - tileID.canonical.z); - GLint pixelX = tileSizeAtNearestZoom * (tileID.canonical.x + tileID.wrap * state.zoomScale(tileID.canonical.z)); - GLint pixelY = tileSizeAtNearestZoom * tileID.canonical.y; - patternShader.u_pixel_coord_upper = {{ float(pixelX >> 16), float(pixelY >> 16) }}; - patternShader.u_pixel_coord_lower = {{ float(pixelX & 0xFFFF), float(pixelY & 0xFFFF) }}; - } else { - plainShader.u_matrix = vertexMatrix; + for (const auto& tileID : util::tileCover(state, state.getIntegerZoom())) { + parameters.programs.fill.draw( + context, + gl::Triangles(), + depthModeForSublayer(0, gl::DepthMode::ReadOnly), + gl::StencilMode::disabled(), + colorModeForRenderPass(), + FillProgram::UniformValues { + uniforms::u_matrix::Value{ matrixForTile(tileID) }, + uniforms::u_opacity::Value{ properties.get<BackgroundOpacity>() }, + uniforms::u_color::Value{ properties.get<BackgroundColor>() }, + uniforms::u_outline_color::Value{ properties.get<BackgroundColor>() }, + uniforms::u_world::Value{ context.viewport.getCurrentValue().size }, + }, + tileVertexBuffer, + tileTriangleIndexBuffer, + tileTriangleSegments + ); } - - MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, static_cast<GLsizei>(tileTriangleVertexBuffer.vertexCount))); } } diff --git a/src/mbgl/renderer/painter_circle.cpp b/src/mbgl/renderer/painter_circle.cpp index 462ed59ebf..9385b7b1a3 100644 --- a/src/mbgl/renderer/painter_circle.cpp +++ b/src/mbgl/renderer/painter_circle.cpp @@ -2,11 +2,11 @@ #include <mbgl/renderer/paint_parameters.hpp> #include <mbgl/renderer/circle_bucket.hpp> #include <mbgl/renderer/render_tile.hpp> - #include <mbgl/style/layers/circle_layer.hpp> #include <mbgl/style/layers/circle_layer_impl.hpp> - -#include <mbgl/shader/shaders.hpp> +#include <mbgl/programs/programs.hpp> +#include <mbgl/programs/circle_program.hpp> +#include <mbgl/gl/context.hpp> namespace mbgl { @@ -16,42 +16,46 @@ void Painter::renderCircle(PaintParameters& parameters, CircleBucket& bucket, const CircleLayer& layer, const RenderTile& tile) { - // Abort early. - if (pass == RenderPass::Opaque) return; - - context.stencilTest = frame.mapMode == MapMode::Still; - context.depthFunc = gl::DepthTestFunction::LessEqual; - context.depthTest = true; - context.depthMask = false; - setDepthSublayer(0); - - const CirclePaintProperties& properties = layer.impl->paint; - auto& circleShader = parameters.shaders.circle; - - context.program = circleShader.getID(); - - circleShader.u_matrix = tile.translatedMatrix(properties.circleTranslate, - properties.circleTranslateAnchor, - state); - - if (properties.circlePitchScale == CirclePitchScaleType::Map) { - circleShader.u_extrude_scale = {{ - pixelsToGLUnits[0] * state.getAltitude(), - pixelsToGLUnits[1] * state.getAltitude() - }}; - circleShader.u_scale_with_map = true; - } else { - circleShader.u_extrude_scale = pixelsToGLUnits; - circleShader.u_scale_with_map = false; + if (pass == RenderPass::Opaque) { + return; } - circleShader.u_devicepixelratio = frame.pixelRatio; - circleShader.u_color = properties.circleColor; - circleShader.u_radius = properties.circleRadius; - circleShader.u_blur = properties.circleBlur; - circleShader.u_opacity = properties.circleOpacity; - - bucket.drawCircles(circleShader, context, paintMode()); + const CirclePaintProperties::Evaluated& properties = layer.impl->paint.evaluated; + const bool scaleWithMap = properties.get<CirclePitchScale>() == CirclePitchScaleType::Map; + + parameters.programs.circle.draw( + context, + gl::Triangles(), + depthModeForSublayer(0, gl::DepthMode::ReadOnly), + frame.mapMode == MapMode::Still + ? stencilModeForClipping(tile.clip) + : gl::StencilMode::disabled(), + colorModeForRenderPass(), + CircleProgram::UniformValues { + uniforms::u_matrix::Value{ + tile.translatedMatrix(properties.get<CircleTranslate>(), + properties.get<CircleTranslateAnchor>(), + state) + }, + uniforms::u_opacity::Value{ properties.get<CircleOpacity>() }, + uniforms::u_color::Value{ properties.get<CircleColor>() }, + uniforms::u_radius::Value{ properties.get<CircleRadius>() }, + uniforms::u_blur::Value{ properties.get<CircleBlur>() }, + uniforms::u_stroke_color::Value{ properties.get<CircleStrokeColor>() }, + uniforms::u_stroke_width::Value{ properties.get<CircleStrokeWidth>() }, + uniforms::u_stroke_opacity::Value{ properties.get<CircleStrokeOpacity>() }, + uniforms::u_scale_with_map::Value{ scaleWithMap }, + uniforms::u_extrude_scale::Value{ scaleWithMap + ? std::array<float, 2> {{ + pixelsToGLUnits[0] * state.getAltitude(), + pixelsToGLUnits[1] * state.getAltitude() + }} + : pixelsToGLUnits } + }, + *bucket.vertexBuffer, + *bucket.indexBuffer, + bucket.segments + ); } } // namespace mbgl diff --git a/src/mbgl/renderer/painter_clipping.cpp b/src/mbgl/renderer/painter_clipping.cpp index 68f580c280..a2529561fe 100644 --- a/src/mbgl/renderer/painter_clipping.cpp +++ b/src/mbgl/renderer/painter_clipping.cpp @@ -1,49 +1,35 @@ #include <mbgl/renderer/painter.hpp> -#include <mbgl/renderer/paint_parameters.hpp> -#include <mbgl/gl/gl.hpp> - -#include <mbgl/style/source.hpp> -#include <mbgl/shader/shaders.hpp> +#include <mbgl/programs/programs.hpp> +#include <mbgl/programs/fill_program.hpp> #include <mbgl/util/clip_id.hpp> -#include <mbgl/util/string.hpp> -#include <mbgl/gl/debugging.hpp> namespace mbgl { - -void Painter::drawClippingMasks(PaintParameters& parameters, const std::map<UnwrappedTileID, ClipID>& stencils) { - MBGL_DEBUG_GROUP("clipping masks"); - - auto& plainShader = parameters.shaders.fill; - auto& arrayCoveringPlain = parameters.shaders.coveringPlainArray; - - mat4 matrix; - const GLuint mask = 0b11111111; - - context.program = plainShader.getID(); - context.stencilOp = { gl::StencilTestOperation::Keep, gl::StencilTestOperation::Keep, - gl::StencilTestOperation::Replace }; - context.stencilTest = true; - context.depthTest = false; - context.depthMask = false; - context.colorMask = { false, false, false, false }; - context.stencilMask = mask; - - arrayCoveringPlain.bind(plainShader, tileTriangleVertexBuffer, BUFFER_OFFSET_0, context); - - for (const auto& stencil : stencils) { - const auto& id = stencil.first; - const auto& clip = stencil.second; - - MBGL_DEBUG_GROUP(std::string{ "mask: " } + util::toString(id)); - state.matrixFor(matrix, id); - matrix::multiply(matrix, projMatrix, matrix); - plainShader.u_matrix = matrix; - - const GLint ref = (GLint)(clip.reference.to_ulong()); - context.stencilFunc = { gl::StencilTestFunction::Always, ref, mask }; - MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(tileTriangleVertexBuffer.vertexCount))); - } +void Painter::renderClippingMask(const UnwrappedTileID& tileID, const ClipID& clip) { + programs->fill.draw( + context, + gl::Triangles(), + gl::DepthMode::disabled(), + gl::StencilMode { + gl::StencilMode::Always(), + static_cast<int32_t>(clip.reference.to_ulong()), + 0b11111111, + gl::StencilMode::Keep, + gl::StencilMode::Keep, + gl::StencilMode::Replace + }, + gl::ColorMode::disabled(), + FillProgram::UniformValues { + uniforms::u_matrix::Value{ matrixForTile(tileID) }, + uniforms::u_opacity::Value{ 0.0f }, + uniforms::u_color::Value{ Color {} }, + uniforms::u_outline_color::Value{ Color {} }, + uniforms::u_world::Value{ context.viewport.getCurrentValue().size }, + }, + tileVertexBuffer, + tileTriangleIndexBuffer, + tileTriangleSegments + ); } } // namespace mbgl diff --git a/src/mbgl/renderer/painter_debug.cpp b/src/mbgl/renderer/painter_debug.cpp index e57bb2205e..2b838dec0e 100644 --- a/src/mbgl/renderer/painter_debug.cpp +++ b/src/mbgl/renderer/painter_debug.cpp @@ -4,161 +4,121 @@ #include <mbgl/renderer/paint_parameters.hpp> #include <mbgl/map/view.hpp> #include <mbgl/tile/tile.hpp> -#include <mbgl/shader/shaders.hpp> +#include <mbgl/programs/programs.hpp> +#include <mbgl/programs/fill_program.hpp> #include <mbgl/util/string.hpp> #include <mbgl/gl/debugging.hpp> -#include <mbgl/gl/gl.hpp> #include <mbgl/util/color.hpp> namespace mbgl { -void Painter::renderTileDebug(const RenderTile& tile) { - MBGL_DEBUG_GROUP(std::string { "debug " } + util::toString(tile.id)); - if (frame.debugOptions != MapDebugOptions::NoDebug) { - setClipping(tile.clip); - if (frame.debugOptions & (MapDebugOptions::Timestamps | MapDebugOptions::ParseStatus)) { - renderDebugText(tile.tile, tile.matrix); +void Painter::renderTileDebug(const RenderTile& renderTile) { + if (frame.debugOptions == MapDebugOptions::NoDebug) + return; + + MBGL_DEBUG_GROUP(std::string { "debug " } + util::toString(renderTile.id)); + + auto draw = [&] (Color color, const auto& vertexBuffer, const auto& indexBuffer, const auto& segments, auto drawMode) { + programs->debug.draw( + context, + drawMode, + gl::DepthMode::disabled(), + stencilModeForClipping(renderTile.clip), + gl::ColorMode::unblended(), + DebugProgram::UniformValues { + uniforms::u_matrix::Value{ renderTile.matrix }, + uniforms::u_color::Value{ color } + }, + vertexBuffer, + indexBuffer, + segments + ); + }; + + if (frame.debugOptions & (MapDebugOptions::Timestamps | MapDebugOptions::ParseStatus)) { + Tile& tile = renderTile.tile; + if (!tile.debugBucket || tile.debugBucket->renderable != tile.isRenderable() || + tile.debugBucket->complete != tile.isComplete() || + !(tile.debugBucket->modified == tile.modified) || + !(tile.debugBucket->expires == tile.expires) || + tile.debugBucket->debugMode != frame.debugOptions) { + tile.debugBucket = std::make_unique<DebugBucket>( + tile.id, tile.isRenderable(), tile.isComplete(), tile.modified, + tile.expires, frame.debugOptions, context); } - if (frame.debugOptions & MapDebugOptions::TileBorders) { - renderDebugFrame(tile.matrix); - } - } -} -void Painter::renderDebugText(Tile& tile, const mat4 &matrix) { - MBGL_DEBUG_GROUP("debug text"); - - context.depthTest = false; - - if (!tile.debugBucket || tile.debugBucket->renderable != tile.isRenderable() || - tile.debugBucket->complete != tile.isComplete() || - !(tile.debugBucket->modified == tile.modified) || - !(tile.debugBucket->expires == tile.expires) || - tile.debugBucket->debugMode != frame.debugOptions) { - tile.debugBucket = std::make_unique<DebugBucket>( - tile.id, tile.isRenderable(), tile.isComplete(), tile.modified, - tile.expires, frame.debugOptions, context); + draw(Color::white(), + *tile.debugBucket->vertexBuffer, + *tile.debugBucket->indexBuffer, + tile.debugBucket->segments, + gl::Lines { 4.0f * frame.pixelRatio }); + + draw(Color::black(), + *tile.debugBucket->vertexBuffer, + *tile.debugBucket->indexBuffer, + tile.debugBucket->segments, + gl::Lines { 2.0f * frame.pixelRatio }); } - auto& plainShader = shaders->fill; - context.program = plainShader.getID(); - plainShader.u_matrix = matrix; - plainShader.u_opacity = 1.0f; - - // Draw white outline - plainShader.u_color = Color::white(); - context.lineWidth = 4.0f * frame.pixelRatio; - tile.debugBucket->drawLines(plainShader, context); - -#if not MBGL_USE_GLES2 - // Draw line "end caps" - MBGL_CHECK_ERROR(glPointSize(2)); - tile.debugBucket->drawPoints(plainShader, context); -#endif // MBGL_USE_GLES2 - - // Draw black text. - plainShader.u_color = Color::black(); - context.lineWidth = 2.0f * frame.pixelRatio; - tile.debugBucket->drawLines(plainShader, context); - - context.depthFunc = gl::DepthTestFunction::LessEqual; - context.depthTest = true; -} - -void Painter::renderDebugFrame(const mat4 &matrix) { - MBGL_DEBUG_GROUP("debug frame"); - - // Disable depth test and don't count this towards the depth buffer, - // but *don't* disable stencil test, as we want to clip the red tile border - // to the tile viewport. - context.depthTest = false; - context.stencilOp = { gl::StencilTestOperation::Keep, gl::StencilTestOperation::Keep, - gl::StencilTestOperation::Replace }; - context.stencilTest = true; - - auto& plainShader = shaders->fill; - context.program = plainShader.getID(); - plainShader.u_matrix = matrix; - plainShader.u_opacity = 1.0f; - - // draw tile outline - tileBorderArray.bind(plainShader, tileLineStripVertexBuffer, BUFFER_OFFSET_0, context); - plainShader.u_color = { 1.0f, 0.0f, 0.0f, 1.0f }; - context.lineWidth = 4.0f * frame.pixelRatio; - MBGL_CHECK_ERROR(glDrawArrays(GL_LINE_STRIP, 0, static_cast<GLsizei>(tileLineStripVertexBuffer.vertexCount))); + if (frame.debugOptions & MapDebugOptions::TileBorders) { + draw(Color::red(), + tileVertexBuffer, + tileBorderIndexBuffer, + tileBorderSegments, + gl::LineStrip { 4.0f * frame.pixelRatio }); + } } #ifndef NDEBUG void Painter::renderClipMasks(PaintParameters&) { - context.stencilTest = false; - context.depthTest = false; + context.setStencilMode(gl::StencilMode::disabled()); + context.setDepthMode(gl::DepthMode::disabled()); + context.setColorMode(gl::ColorMode::unblended()); context.program = 0; - context.colorMask = { true, true, true, true }; #if not MBGL_USE_GLES2 - context.pixelZoom = { 1, 1 }; - context.rasterPos = { -1, -1, 0, 0 }; + // Reset the value in case someone else changed it, or it's dirty. + context.pixelTransferStencil = gl::value::PixelTransferStencil::Default; // Read the stencil buffer const auto viewport = context.viewport.getCurrentValue(); - auto pixels = std::make_unique<uint8_t[]>(viewport.width * viewport.height); - MBGL_CHECK_ERROR(glReadPixels( - viewport.x, // GLint x - viewport.y, // GLint y - viewport.width, // GLsizei width - viewport.height, // GLsizei height - GL_STENCIL_INDEX, // GLenum format - GL_UNSIGNED_BYTE, // GLenum type - pixels.get() // GLvoid * data - )); + auto image = + context.readFramebuffer<AlphaImage, gl::TextureFormat::Stencil>(viewport.size, false); // Scale the Stencil buffer to cover the entire color space. - auto it = pixels.get(); - auto end = it + viewport.width * viewport.height; + auto it = image.data.get(); + auto end = it + viewport.size.width * viewport.size.height; const auto factor = 255.0f / *std::max_element(it, end); for (; it != end; ++it) { *it *= factor; } - MBGL_CHECK_ERROR(glWindowPos2i(viewport.x, viewport.y)); - MBGL_CHECK_ERROR(glDrawPixels(viewport.width, viewport.height, GL_LUMINANCE, GL_UNSIGNED_BYTE, - pixels.get())); + context.pixelZoom = { 1, 1 }; + context.rasterPos = { -1, -1, 0, 1 }; + context.drawPixels(image); #endif // MBGL_USE_GLES2 } -#endif // NDEBUG -#ifndef NDEBUG void Painter::renderDepthBuffer(PaintParameters&) { - context.stencilTest = false; - context.depthTest = false; + context.setStencilMode(gl::StencilMode::disabled()); + context.setDepthMode(gl::DepthMode::disabled()); + context.setColorMode(gl::ColorMode::unblended()); context.program = 0; - context.colorMask = { true, true, true, true }; #if not MBGL_USE_GLES2 - context.pixelZoom = { 1, 1 }; - context.rasterPos = { -1, -1, 0, 0 }; + // Scales the values in the depth buffer so that they cover the entire grayscale range. This + // makes it easier to spot tiny differences. + const float base = 1.0f / (1.0f - depthRangeSize); + context.pixelTransferDepth = { base, 1.0f - base }; // Read the stencil buffer - const auto viewport = context.viewport.getCurrentValue(); - auto pixels = std::make_unique<uint8_t[]>(viewport.width * viewport.height); - - const double base = 1.0 / (1.0 - depthRangeSize); - glPixelTransferf(GL_DEPTH_SCALE, base); - glPixelTransferf(GL_DEPTH_BIAS, 1.0 - base); - - MBGL_CHECK_ERROR(glReadPixels( - viewport.x, // GLint x - viewport.y, // GLint y - viewport.width, // GLsizei width - viewport.height, // GLsizei height - GL_DEPTH_COMPONENT, // GLenum format - GL_UNSIGNED_BYTE, // GLenum type - pixels.get() // GLvoid * data - )); - - MBGL_CHECK_ERROR(glWindowPos2i(viewport.x, viewport.y)); - MBGL_CHECK_ERROR(glDrawPixels(viewport.width, viewport.height, GL_LUMINANCE, GL_UNSIGNED_BYTE, - pixels.get())); + auto viewport = context.viewport.getCurrentValue(); + auto image = + context.readFramebuffer<AlphaImage, gl::TextureFormat::Depth>(viewport.size, false); + + context.pixelZoom = { 1, 1 }; + context.rasterPos = { -1, -1, 0, 1 }; + context.drawPixels(image); #endif // MBGL_USE_GLES2 } #endif // NDEBUG diff --git a/src/mbgl/renderer/painter_fill.cpp b/src/mbgl/renderer/painter_fill.cpp index b6606ca40b..356ccfc0b2 100644 --- a/src/mbgl/renderer/painter_fill.cpp +++ b/src/mbgl/renderer/painter_fill.cpp @@ -1,14 +1,12 @@ #include <mbgl/renderer/painter.hpp> #include <mbgl/renderer/paint_parameters.hpp> -#include <mbgl/gl/gl.hpp> -#include <mbgl/map/view.hpp> - #include <mbgl/renderer/fill_bucket.hpp> #include <mbgl/renderer/render_tile.hpp> #include <mbgl/style/layers/fill_layer.hpp> #include <mbgl/style/layers/fill_layer_impl.hpp> #include <mbgl/sprite/sprite_atlas.hpp> -#include <mbgl/shader/shaders.hpp> +#include <mbgl/programs/programs.hpp> +#include <mbgl/programs/fill_program.hpp> #include <mbgl/util/convert.hpp> namespace mbgl { @@ -19,160 +17,131 @@ void Painter::renderFill(PaintParameters& parameters, FillBucket& bucket, const FillLayer& layer, const RenderTile& tile) { - const FillPaintProperties& properties = layer.impl->paint; - mat4 vertexMatrix = tile.translatedMatrix(properties.fillTranslate, - properties.fillTranslateAnchor, - state); - - Color fillColor = properties.fillColor; - float opacity = properties.fillOpacity; - - const bool isOutlineColorDefined = !properties.fillOutlineColor.isUndefined(); - Color strokeColor = isOutlineColorDefined? properties.fillOutlineColor : fillColor; - - const auto viewport = context.viewport.getCurrentValue(); - const std::array<GLfloat, 2> worldSize{ { static_cast<GLfloat>(viewport.width), - static_cast<GLfloat>(viewport.height) } }; - - bool pattern = !properties.fillPattern.value.from.empty(); - bool outline = properties.fillAntialias && !pattern && isOutlineColorDefined; - bool fringeline = properties.fillAntialias && !pattern && !isOutlineColorDefined; - - context.stencilOp = { gl::StencilTestOperation::Keep, gl::StencilTestOperation::Keep, - gl::StencilTestOperation::Replace }; - context.stencilTest = true; - context.depthFunc = gl::DepthTestFunction::LessEqual; - context.depthTest = true; - context.depthMask = true; - context.lineWidth = 2.0f; // This is always fixed and does not depend on the pixelRatio! - - auto& outlineShader = parameters.shaders.fillOutline; - auto& patternShader = parameters.shaders.fillPattern; - auto& outlinePatternShader = parameters.shaders.fillOutlinePattern; - auto& plainShader = parameters.shaders.fill; + const FillPaintProperties::Evaluated& properties = layer.impl->paint.evaluated; - // Because we're drawing top-to-bottom, and we update the stencil mask - // befrom, we have to draw the outline first (!) - if (outline && pass == RenderPass::Translucent) { - context.program = outlineShader.getID(); - outlineShader.u_matrix = vertexMatrix; - - outlineShader.u_outline_color = strokeColor; - outlineShader.u_opacity = opacity; - - // Draw the entire line - outlineShader.u_world = worldSize; - if (isOutlineColorDefined) { - // If we defined a different color for the fill outline, we are - // going to ignore the bits in 0x07 and just care about the global - // clipping mask. - setDepthSublayer(2); // OK - } else { - // Otherwise, we only want to drawFill the antialiased parts that are - // *outside* the current shape. This is important in case the fill - // or stroke color is translucent. If we wouldn't clip to outside - // the current shape, some pixels from the outline stroke overlapped - // the (non-antialiased) fill. - setDepthSublayer(0); // OK + if (!properties.get<FillPattern>().from.empty()) { + if (pass != RenderPass::Translucent) { + return; } - bucket.drawVertices(outlineShader, context, paintMode()); - } - if (pattern) { optional<SpriteAtlasPosition> imagePosA = spriteAtlas->getPosition( - properties.fillPattern.value.from, SpritePatternMode::Repeating); - optional<SpriteAtlasPosition> imagePosB = - spriteAtlas->getPosition(properties.fillPattern.value.to, SpritePatternMode::Repeating); - - // Image fill. - if (pass == RenderPass::Translucent && imagePosA && imagePosB) { - context.program = patternShader.getID(); - patternShader.u_matrix = vertexMatrix; - patternShader.u_pattern_tl_a = imagePosA->tl; - patternShader.u_pattern_br_a = imagePosA->br; - patternShader.u_pattern_tl_b = imagePosB->tl; - patternShader.u_pattern_br_b = imagePosB->br; - patternShader.u_opacity = properties.fillOpacity; - patternShader.u_image = 0; - patternShader.u_mix = properties.fillPattern.value.t; - patternShader.u_pattern_size_a = imagePosA->size; - patternShader.u_pattern_size_b = imagePosB->size; - patternShader.u_scale_a = properties.fillPattern.value.fromScale; - patternShader.u_scale_b = properties.fillPattern.value.toScale; - patternShader.u_tile_units_to_pixels = 1.0f / tile.id.pixelsToTileUnits(1.0f, state.getIntegerZoom()); - - GLint tileSizeAtNearestZoom = util::tileSize * state.zoomScale(state.getIntegerZoom() - tile.id.canonical.z); - GLint pixelX = tileSizeAtNearestZoom * (tile.id.canonical.x + tile.id.wrap * state.zoomScale(tile.id.canonical.z)); - GLint pixelY = tileSizeAtNearestZoom * tile.id.canonical.y; - patternShader.u_pixel_coord_upper = {{ float(pixelX >> 16), float(pixelY >> 16) }}; - patternShader.u_pixel_coord_lower = {{ float(pixelX & 0xFFFF), float(pixelY & 0xFFFF) }}; - - spriteAtlas->bind(true, context, 0); + properties.get<FillPattern>().from, SpritePatternMode::Repeating); + optional<SpriteAtlasPosition> imagePosB = spriteAtlas->getPosition( + properties.get<FillPattern>().to, SpritePatternMode::Repeating); - // Draw the actual triangles into the color & stencil buffer. - setDepthSublayer(0); - bucket.drawElements(patternShader, context, paintMode()); - - if (properties.fillAntialias && !isOutlineColorDefined) { - context.program = outlinePatternShader.getID(); - outlinePatternShader.u_matrix = vertexMatrix; - - outlinePatternShader.u_pattern_tl_a = imagePosA->tl; - outlinePatternShader.u_pattern_br_a = imagePosA->br; - outlinePatternShader.u_pattern_tl_b = imagePosB->tl; - outlinePatternShader.u_pattern_br_b = imagePosB->br; - outlinePatternShader.u_opacity = properties.fillOpacity; - outlinePatternShader.u_image = 0; - outlinePatternShader.u_mix = properties.fillPattern.value.t; - outlinePatternShader.u_pattern_size_a = imagePosA->size; - outlinePatternShader.u_pattern_size_b = imagePosB->size; - outlinePatternShader.u_scale_a = properties.fillPattern.value.fromScale; - outlinePatternShader.u_scale_b = properties.fillPattern.value.toScale; - outlinePatternShader.u_tile_units_to_pixels = 1.0f / tile.id.pixelsToTileUnits(1.0f, state.getIntegerZoom()); - outlinePatternShader.u_pixel_coord_upper = {{ float(pixelX >> 16), float(pixelY >> 16) }}; - outlinePatternShader.u_pixel_coord_lower = {{ float(pixelX & 0xFFFF), float(pixelY & 0xFFFF) }}; - - // Draw the entire line - outlinePatternShader.u_world = worldSize; - - spriteAtlas->bind(true, context, 0); - - setDepthSublayer(2); - bucket.drawVertices(outlinePatternShader, context, paintMode()); - } + if (!imagePosA || !imagePosB) { + return; } - } else { - // No image fill. - if ((fillColor.a >= 1.0f && opacity >= 1.0f) == (pass == RenderPass::Opaque)) { - // Only draw the fill when it's either opaque and we're drawing opaque - // fragments or when it's translucent and we're drawing translucent - // fragments - // Draw filling rectangle. - context.program = plainShader.getID(); - plainShader.u_matrix = vertexMatrix; - plainShader.u_color = fillColor; - plainShader.u_opacity = opacity; - // Draw the actual triangles into the color & stencil buffer. - setDepthSublayer(1); - bucket.drawElements(plainShader, context, paintMode()); + spriteAtlas->bind(true, context, 0); + + auto draw = [&] (uint8_t sublayer, + auto& program, + const auto& drawMode, + const auto& vertexBuffer, + const auto& indexBuffer, + const auto& segments) { + program.draw( + context, + drawMode, + depthModeForSublayer(sublayer, gl::DepthMode::ReadWrite), + stencilModeForClipping(tile.clip), + colorModeForRenderPass(), + FillPatternUniforms::values( + tile.translatedMatrix(properties.get<FillTranslate>(), + properties.get<FillTranslateAnchor>(), + state), + properties.get<FillOpacity>(), + context.viewport.getCurrentValue().size, + *imagePosA, + *imagePosB, + properties.get<FillPattern>(), + tile.id, + state + ), + vertexBuffer, + indexBuffer, + segments + ); + }; + + draw(0, + parameters.programs.fillPattern, + gl::Triangles(), + *bucket.vertexBuffer, + *bucket.triangleIndexBuffer, + bucket.triangleSegments); + + if (!properties.get<FillAntialias>() || !layer.impl->paint.unevaluated.get<FillOutlineColor>().isUndefined()) { + return; } - } - - // Because we're drawing top-to-bottom, and we update the stencil mask - // below, we have to draw the outline first (!) - if (fringeline && pass == RenderPass::Translucent) { - context.program = outlineShader.getID(); - outlineShader.u_matrix = vertexMatrix; - outlineShader.u_outline_color = fillColor; - outlineShader.u_opacity = opacity; + draw(2, + parameters.programs.fillOutlinePattern, + gl::Lines { 2.0f }, + *bucket.vertexBuffer, + *bucket.lineIndexBuffer, + bucket.lineSegments); + } else { + auto draw = [&] (uint8_t sublayer, + auto& program, + Color outlineColor, + const auto& drawMode, + const auto& vertexBuffer, + const auto& indexBuffer, + const auto& segments) { + program.draw( + context, + drawMode, + depthModeForSublayer(sublayer, gl::DepthMode::ReadWrite), + stencilModeForClipping(tile.clip), + colorModeForRenderPass(), + FillProgram::UniformValues { + uniforms::u_matrix::Value{ tile.translatedMatrix(properties.get<FillTranslate>(), + properties.get<FillTranslateAnchor>(), + state) }, + uniforms::u_opacity::Value{ properties.get<FillOpacity>() }, + uniforms::u_color::Value{ properties.get<FillColor>() }, + uniforms::u_outline_color::Value{ outlineColor }, + uniforms::u_world::Value{ context.viewport.getCurrentValue().size }, + }, + vertexBuffer, + indexBuffer, + segments + ); + }; + + if (properties.get<FillAntialias>() && !layer.impl->paint.unevaluated.get<FillOutlineColor>().isUndefined() && pass == RenderPass::Translucent) { + draw(2, + parameters.programs.fillOutline, + properties.get<FillOutlineColor>(), + gl::Lines { 2.0f }, + *bucket.vertexBuffer, + *bucket.lineIndexBuffer, + bucket.lineSegments); + } - // Draw the entire line - outlineShader.u_world = worldSize; + // Only draw the fill when it's opaque and we're drawing opaque fragments, + // or when it's translucent and we're drawing translucent fragments. + if ((properties.get<FillColor>().a >= 1.0f && properties.get<FillOpacity>() >= 1.0f) == (pass == RenderPass::Opaque)) { + draw(1, + parameters.programs.fill, + properties.get<FillOutlineColor>(), + gl::Triangles(), + *bucket.vertexBuffer, + *bucket.triangleIndexBuffer, + bucket.triangleSegments); + } - setDepthSublayer(2); - bucket.drawVertices(outlineShader, context, paintMode()); + if (properties.get<FillAntialias>() && layer.impl->paint.unevaluated.get<FillOutlineColor>().isUndefined() && pass == RenderPass::Translucent) { + draw(2, + parameters.programs.fillOutline, + properties.get<FillColor>(), + gl::Lines { 2.0f }, + *bucket.vertexBuffer, + *bucket.lineIndexBuffer, + bucket.lineSegments); + } } } diff --git a/src/mbgl/renderer/painter_line.cpp b/src/mbgl/renderer/painter_line.cpp index 85a5786353..a66f53a856 100644 --- a/src/mbgl/renderer/painter_line.cpp +++ b/src/mbgl/renderer/painter_line.cpp @@ -4,10 +4,10 @@ #include <mbgl/renderer/render_tile.hpp> #include <mbgl/style/layers/line_layer.hpp> #include <mbgl/style/layers/line_layer_impl.hpp> -#include <mbgl/shader/shaders.hpp> +#include <mbgl/programs/programs.hpp> +#include <mbgl/programs/line_program.hpp> #include <mbgl/sprite/sprite_atlas.hpp> #include <mbgl/geometry/line_atlas.hpp> -#include <mbgl/util/mat2.hpp> namespace mbgl { @@ -17,150 +17,70 @@ void Painter::renderLine(PaintParameters& parameters, LineBucket& bucket, const LineLayer& layer, const RenderTile& tile) { - // Abort early. - if (pass == RenderPass::Opaque) return; - - context.stencilOp = { gl::StencilTestOperation::Keep, gl::StencilTestOperation::Keep, - gl::StencilTestOperation::Replace }; - context.stencilTest = true; - context.depthFunc = gl::DepthTestFunction::LessEqual; - context.depthTest = true; - context.depthMask = false; - - const auto& properties = layer.impl->paint; - const auto& layout = bucket.layout; - - // the distance over which the line edge fades out. - // Retina devices need a smaller distance to avoid aliasing. - float antialiasing = 1.0 / frame.pixelRatio; - - float blur = properties.lineBlur + antialiasing; - - const Color color = properties.lineColor; - const float opacity = properties.lineOpacity; - const float ratio = 1.0 / tile.id.pixelsToTileUnits(1.0, state.getZoom()); - - mat2 antialiasingMatrix; - matrix::identity(antialiasingMatrix); - matrix::scale(antialiasingMatrix, antialiasingMatrix, 1.0, std::cos(state.getPitch())); - matrix::rotate(antialiasingMatrix, antialiasingMatrix, state.getAngle()); - - // calculate how much longer the real world distance is at the top of the screen - // than at the middle of the screen. - float topedgelength = std::sqrt(std::pow(state.getHeight(), 2.0f) / 4.0f * (1.0f + std::pow(state.getAltitude(), 2.0f))); - float x = state.getHeight() / 2.0f * std::tan(state.getPitch()); - float extra = (topedgelength + x) / topedgelength - 1.0f; - - mat4 vtxMatrix = tile.translatedMatrix(properties.lineTranslate, - properties.lineTranslateAnchor, - state); - - setDepthSublayer(0); - - auto& linesdfShader = parameters.shaders.lineSDF; - auto& linepatternShader = parameters.shaders.linePattern; - auto& lineShader = parameters.shaders.line; - - if (!properties.lineDasharray.value.from.empty()) { - context.program = linesdfShader.getID(); - - linesdfShader.u_matrix = vtxMatrix; - linesdfShader.u_linewidth = properties.lineWidth / 2; - linesdfShader.u_gapwidth = properties.lineGapWidth / 2; - linesdfShader.u_antialiasing = antialiasing / 2; - linesdfShader.u_ratio = ratio; - linesdfShader.u_blur = blur; - linesdfShader.u_color = color; - linesdfShader.u_opacity = opacity; - - const LinePatternCap cap = - layout.lineCap == LineCapType::Round ? LinePatternCap::Round : LinePatternCap::Square; - LinePatternPos posA = lineAtlas->getDashPosition(properties.lineDasharray.value.from, cap); - LinePatternPos posB = lineAtlas->getDashPosition(properties.lineDasharray.value.to, cap); - - const float widthA = posA.width * properties.lineDasharray.value.fromScale * layer.impl->dashLineWidth; - const float widthB = posB.width * properties.lineDasharray.value.toScale * layer.impl->dashLineWidth; - - float scaleXA = 1.0 / tile.id.pixelsToTileUnits(widthA, state.getIntegerZoom()); - float scaleYA = -posA.height / 2.0; - float scaleXB = 1.0 / tile.id.pixelsToTileUnits(widthB, state.getIntegerZoom()); - float scaleYB = -posB.height / 2.0; + if (pass == RenderPass::Opaque) { + return; + } - linesdfShader.u_patternscale_a = {{ scaleXA, scaleYA }}; - linesdfShader.u_tex_y_a = posA.y; - linesdfShader.u_patternscale_b = {{ scaleXB, scaleYB }}; - linesdfShader.u_tex_y_b = posB.y; - linesdfShader.u_sdfgamma = lineAtlas->width / (std::min(widthA, widthB) * 256.0 * frame.pixelRatio) / 2; - linesdfShader.u_mix = properties.lineDasharray.value.t; - linesdfShader.u_extra = extra; - linesdfShader.u_offset = -properties.lineOffset; - linesdfShader.u_antialiasingmatrix = antialiasingMatrix; + const LinePaintProperties::Evaluated& properties = layer.impl->paint.evaluated; + + auto draw = [&] (auto& program, auto&& uniformValues) { + program.draw( + context, + gl::Triangles(), + depthModeForSublayer(0, gl::DepthMode::ReadOnly), + stencilModeForClipping(tile.clip), + colorModeForRenderPass(), + std::move(uniformValues), + *bucket.vertexBuffer, + *bucket.indexBuffer, + bucket.segments + ); + }; + + if (!properties.get<LineDasharray>().from.empty()) { + const LinePatternCap cap = bucket.layout.get<LineCap>() == LineCapType::Round + ? LinePatternCap::Round : LinePatternCap::Square; + LinePatternPos posA = lineAtlas->getDashPosition(properties.get<LineDasharray>().from, cap); + LinePatternPos posB = lineAtlas->getDashPosition(properties.get<LineDasharray>().to, cap); - linesdfShader.u_image = 0; lineAtlas->bind(context, 0); - bucket.drawLineSDF(linesdfShader, context, paintMode()); - - } else if (!properties.linePattern.value.from.empty()) { - optional<SpriteAtlasPosition> imagePosA = spriteAtlas->getPosition( - properties.linePattern.value.from, SpritePatternMode::Repeating); - optional<SpriteAtlasPosition> imagePosB = - spriteAtlas->getPosition(properties.linePattern.value.to, SpritePatternMode::Repeating); - - if (!imagePosA || !imagePosB) + draw(parameters.programs.lineSDF, + LineSDFProgram::uniformValues( + properties, + frame.pixelRatio, + tile, + state, + posA, + posB, + layer.impl->dashLineWidth, + lineAtlas->getSize().width)); + + } else if (!properties.get<LinePattern>().from.empty()) { + optional<SpriteAtlasPosition> posA = spriteAtlas->getPosition( + properties.get<LinePattern>().from, SpritePatternMode::Repeating); + optional<SpriteAtlasPosition> posB = spriteAtlas->getPosition( + properties.get<LinePattern>().to, SpritePatternMode::Repeating); + + if (!posA || !posB) return; - context.program = linepatternShader.getID(); - - linepatternShader.u_matrix = vtxMatrix; - linepatternShader.u_linewidth = properties.lineWidth / 2; - linepatternShader.u_gapwidth = properties.lineGapWidth / 2; - linepatternShader.u_antialiasing = antialiasing / 2; - linepatternShader.u_ratio = ratio; - linepatternShader.u_blur = blur; - - linepatternShader.u_pattern_size_a = {{ - tile.id.pixelsToTileUnits((*imagePosA).size[0] * properties.linePattern.value.fromScale, state.getIntegerZoom()), - (*imagePosA).size[1] - }}; - linepatternShader.u_pattern_tl_a = (*imagePosA).tl; - linepatternShader.u_pattern_br_a = (*imagePosA).br; - - linepatternShader.u_pattern_size_b = {{ - tile.id.pixelsToTileUnits((*imagePosB).size[0] * properties.linePattern.value.toScale, state.getIntegerZoom()), - (*imagePosB).size[1] - }}; - linepatternShader.u_pattern_tl_b = (*imagePosB).tl; - linepatternShader.u_pattern_br_b = (*imagePosB).br; - - linepatternShader.u_fade = properties.linePattern.value.t; - linepatternShader.u_opacity = properties.lineOpacity; - linepatternShader.u_extra = extra; - linepatternShader.u_offset = -properties.lineOffset; - linepatternShader.u_antialiasingmatrix = antialiasingMatrix; - - linepatternShader.u_image = 0; spriteAtlas->bind(true, context, 0); - bucket.drawLinePatterns(linepatternShader, context, paintMode()); + draw(parameters.programs.linePattern, + LinePatternProgram::uniformValues( + properties, + tile, + state, + *posA, + *posB)); } else { - context.program = lineShader.getID(); - - lineShader.u_matrix = vtxMatrix; - lineShader.u_linewidth = properties.lineWidth / 2; - lineShader.u_gapwidth = properties.lineGapWidth / 2; - lineShader.u_antialiasing = antialiasing / 2; - lineShader.u_ratio = ratio; - lineShader.u_blur = blur; - lineShader.u_extra = extra; - lineShader.u_offset = -properties.lineOffset; - lineShader.u_antialiasingmatrix = antialiasingMatrix; - - lineShader.u_color = color; - lineShader.u_opacity = opacity; - - bucket.drawLines(lineShader, context, paintMode()); + draw(parameters.programs.line, + LineProgram::uniformValues( + properties, + tile, + state)); } } diff --git a/src/mbgl/renderer/painter_raster.cpp b/src/mbgl/renderer/painter_raster.cpp index 8b39c8adf8..96bb6dc565 100644 --- a/src/mbgl/renderer/painter_raster.cpp +++ b/src/mbgl/renderer/painter_raster.cpp @@ -1,57 +1,17 @@ #include <mbgl/renderer/painter.hpp> #include <mbgl/renderer/paint_parameters.hpp> #include <mbgl/renderer/render_tile.hpp> -#include <mbgl/gl/gl.hpp> #include <mbgl/renderer/raster_bucket.hpp> #include <mbgl/style/layers/raster_layer.hpp> #include <mbgl/style/layers/raster_layer_impl.hpp> -#include <mbgl/shader/shaders.hpp> +#include <mbgl/programs/programs.hpp> +#include <mbgl/programs/raster_program.hpp> namespace mbgl { using namespace style; -void Painter::renderRaster(PaintParameters& parameters, - RasterBucket& bucket, - const RasterLayer& layer, - const RenderTile& tile) { - if (pass != RenderPass::Translucent) return; - - const RasterPaintProperties& properties = layer.impl->paint; - - if (bucket.hasData()) { - auto& rasterShader = parameters.shaders.raster; - auto& rasterVAO = parameters.shaders.coveringRasterArray; - - context.program = rasterShader.getID(); - rasterShader.u_matrix = tile.matrix; - rasterShader.u_buffer_scale = 1.0f; - rasterShader.u_opacity0 = properties.rasterOpacity; - rasterShader.u_opacity1 = 0; - - rasterShader.u_brightness_low = properties.rasterBrightnessMin; - rasterShader.u_brightness_high = properties.rasterBrightnessMax; - rasterShader.u_saturation_factor = saturationFactor(properties.rasterSaturation); - rasterShader.u_contrast_factor = contrastFactor(properties.rasterContrast); - rasterShader.u_spin_weights = spinWeights(properties.rasterHueRotate); - - context.stencilTest = false; - - rasterShader.u_image0 = 0; // GL_TEXTURE0 - rasterShader.u_image1 = 1; // GL_TEXTURE1 - rasterShader.u_tl_parent = {{ 0.0f, 0.0f }}; - rasterShader.u_scale_parent = 1.0f; - - context.depthFunc = gl::DepthTestFunction::LessEqual; - context.depthTest = true; - context.depthMask = false; - setDepthSublayer(0); - - bucket.drawRaster(rasterShader, rasterVertexBuffer, rasterVAO, context); - } -} - -float Painter::saturationFactor(float saturation) { +static float saturationFactor(float saturation) { if (saturation > 0) { return 1 - 1 / (1.001 - saturation); } else { @@ -59,7 +19,7 @@ float Painter::saturationFactor(float saturation) { } } -float Painter::contrastFactor(float contrast) { +static float contrastFactor(float contrast) { if (contrast > 0) { return 1 / (1 - contrast); } else { @@ -67,7 +27,7 @@ float Painter::contrastFactor(float contrast) { } } -std::array<float, 3> Painter::spinWeights(float spin) { +static std::array<float, 3> spinWeights(float spin) { spin *= util::DEG2RAD; float s = std::sin(spin); float c = std::cos(spin); @@ -79,4 +39,46 @@ std::array<float, 3> Painter::spinWeights(float spin) { return spin_weights; } +void Painter::renderRaster(PaintParameters& parameters, + RasterBucket& bucket, + const RasterLayer& layer, + const RenderTile& tile) { + if (pass != RenderPass::Translucent) + return; + if (!bucket.hasData()) + return; + + const RasterPaintProperties::Evaluated& properties = layer.impl->paint.evaluated; + + assert(bucket.texture); + context.bindTexture(*bucket.texture, 0, gl::TextureFilter::Linear); + context.bindTexture(*bucket.texture, 1, gl::TextureFilter::Linear); + + parameters.programs.raster.draw( + context, + gl::Triangles(), + depthModeForSublayer(0, gl::DepthMode::ReadOnly), + gl::StencilMode::disabled(), + colorModeForRenderPass(), + RasterProgram::UniformValues { + uniforms::u_matrix::Value{ tile.matrix }, + uniforms::u_image0::Value{ 0 }, + uniforms::u_image1::Value{ 1 }, + uniforms::u_opacity0::Value{ properties.get<RasterOpacity>() }, + uniforms::u_opacity1::Value{ 0 }, + uniforms::u_brightness_low::Value{ properties.get<RasterBrightnessMin>() }, + uniforms::u_brightness_high::Value{ properties.get<RasterBrightnessMax>() }, + uniforms::u_saturation_factor::Value{ saturationFactor(properties.get<RasterSaturation>()) }, + uniforms::u_contrast_factor::Value{ contrastFactor(properties.get<RasterContrast>()) }, + uniforms::u_spin_weights::Value{ spinWeights(properties.get<RasterHueRotate>()) }, + uniforms::u_buffer_scale::Value{ 1.0f }, + uniforms::u_scale_parent::Value{ 1.0f }, + uniforms::u_tl_parent::Value{ std::array<float, 2> {{ 0.0f, 0.0f }} }, + }, + rasterVertexBuffer, + tileTriangleIndexBuffer, + rasterSegments + ); +} + } // namespace mbgl diff --git a/src/mbgl/renderer/painter_symbol.cpp b/src/mbgl/renderer/painter_symbol.cpp index 2ed6facad8..39075976a0 100644 --- a/src/mbgl/renderer/painter_symbol.cpp +++ b/src/mbgl/renderer/painter_symbol.cpp @@ -6,8 +6,11 @@ #include <mbgl/style/layers/symbol_layer_impl.hpp> #include <mbgl/text/glyph_atlas.hpp> #include <mbgl/sprite/sprite_atlas.hpp> -#include <mbgl/shader/shaders.hpp> +#include <mbgl/programs/programs.hpp> +#include <mbgl/programs/symbol_program.hpp> +#include <mbgl/programs/collision_box_program.hpp> #include <mbgl/util/math.hpp> +#include <mbgl/tile/tile.hpp> #include <cmath> @@ -15,254 +18,114 @@ namespace mbgl { using namespace style; -void Painter::renderSDF(SymbolBucket& bucket, - const RenderTile& tile, - float sdfFontSize, - std::array<float, 2> texsize, - SymbolSDFShader& sdfShader, - void (SymbolBucket::*drawSDF)(SymbolSDFShader&, gl::Context&, PaintMode), - - // Layout - AlignmentType rotationAlignment, - AlignmentType pitchAlignment, - float layoutSize, - - // Paint - float opacity, - Color color, - Color haloColor, - float haloWidth, - float haloBlur, - std::array<float, 2> translate, - TranslateAnchorType translateAnchor, - float paintSize) -{ - mat4 vtxMatrix = tile.translatedMatrix(translate, translateAnchor, state); - - // If layerStyle.size > bucket.info.fontSize then labels may collide - float fontSize = paintSize; - float fontScale = fontSize / sdfFontSize; - - bool rotateWithMap = rotationAlignment == AlignmentType::Map; - bool pitchWithMap = pitchAlignment == AlignmentType::Map; - - std::array<float, 2> extrudeScale; - float gammaScale; - - if (pitchWithMap) { - gammaScale = 1.0 / std::cos(state.getPitch()); - extrudeScale.fill(tile.id.pixelsToTileUnits(1, state.getZoom()) * fontScale); - } else { - gammaScale = 1.0; - extrudeScale = {{ - pixelsToGLUnits[0] * fontScale * state.getAltitude(), - pixelsToGLUnits[1] * fontScale * state.getAltitude() - }}; - } - - context.program = sdfShader.getID(); - sdfShader.u_matrix = vtxMatrix; - sdfShader.u_extrude_scale = extrudeScale; - sdfShader.u_texsize = texsize; - sdfShader.u_rotate_with_map = rotateWithMap; - sdfShader.u_pitch_with_map = pitchWithMap; - sdfShader.u_texture = 0; - sdfShader.u_pitch = state.getPitch(); - sdfShader.u_bearing = -1.0f * state.getAngle(); - sdfShader.u_aspect_ratio = (state.getWidth() * 1.0f) / (state.getHeight() * 1.0f); - - // adjust min/max zooms for variable font sies - float zoomAdjust = std::log(fontSize / layoutSize) / std::log(2); - - sdfShader.u_zoom = (state.getZoom() - zoomAdjust) * 10; // current zoom level - - frameHistory.bind(context, 1); - sdfShader.u_fadetexture = 1; - - // The default gamma value has to be adjust for the current pixelratio so that we're not - // drawing blurry font on retina screens. - const float gamma = 0.105 * sdfFontSize / fontSize / frame.pixelRatio; - - const float sdfPx = 8.0f; - const float blurOffset = 1.19f; - const float haloOffset = 6.0f; - - // We're drawing in the translucent pass which is bottom-to-top, so we need - // to draw the halo first. - if (haloColor.a > 0.0f && haloWidth > 0.0f) { - sdfShader.u_gamma = (haloBlur * blurOffset / fontScale / sdfPx + gamma) * gammaScale; - sdfShader.u_color = haloColor; - sdfShader.u_opacity = opacity; - sdfShader.u_buffer = (haloOffset - haloWidth / fontScale) / sdfPx; - (bucket.*drawSDF)(sdfShader, context, paintMode()); - } - - // Then, we draw the text/icon over the halo - if (color.a > 0.0f) { - sdfShader.u_gamma = gamma * gammaScale; - sdfShader.u_color = color; - sdfShader.u_opacity = opacity; - sdfShader.u_buffer = (256.0f - 64.0f) / 256.0f; - (bucket.*drawSDF)(sdfShader, context, paintMode()); - } -} - void Painter::renderSymbol(PaintParameters& parameters, SymbolBucket& bucket, const SymbolLayer& layer, const RenderTile& tile) { - // Abort early. if (pass == RenderPass::Opaque) { return; } - const auto& paint = layer.impl->paint; const auto& layout = bucket.layout; - context.depthMask = false; - - // TODO remove the `true ||` when #1673 is implemented - const bool drawAcrossEdges = (frame.mapMode == MapMode::Continuous) && (true || !(layout.textAllowOverlap || layout.iconAllowOverlap || - layout.textIgnorePlacement || layout.iconIgnorePlacement)); - - // Disable the stencil test so that labels aren't clipped to tile boundaries. - // - // Layers with features that may be drawn overlapping aren't clipped. These - // layers are sorted in the y direction, and to draw the correct ordering near - // tile edges the icons are included in both tiles and clipped when drawing. - if (drawAcrossEdges) { - context.stencilTest = false; - } else { - context.stencilOp = { gl::StencilTestOperation::Keep, gl::StencilTestOperation::Keep, - gl::StencilTestOperation::Replace }; - context.stencilTest = true; - } + frameHistory.bind(context, 1); - setDepthSublayer(0); + auto draw = [&] (auto& program, + auto&& uniformValues, + const auto& buffers, + const SymbolPropertyValues& values_) + { + // We clip symbols to their tile extent in still mode. + const bool needsClipping = frame.mapMode == MapMode::Still; + + program.draw( + context, + gl::Triangles(), + values_.pitchAlignment == AlignmentType::Map + ? depthModeForSublayer(0, gl::DepthMode::ReadOnly) + : gl::DepthMode::disabled(), + needsClipping + ? stencilModeForClipping(tile.clip) + : gl::StencilMode::disabled(), + colorModeForRenderPass(), + std::move(uniformValues), + *buffers.vertexBuffer, + *buffers.indexBuffer, + buffers.segments + ); + }; if (bucket.hasIconData()) { - if (layout.iconRotationAlignment == AlignmentType::Map) { - context.depthFunc = gl::DepthTestFunction::LessEqual; - context.depthTest = true; - } else { - context.depthTest = false; - } + auto values = layer.impl->iconPropertyValues(layout); - bool sdf = bucket.sdfIcons; + SpriteAtlas& atlas = *layer.impl->spriteAtlas; + const bool iconScaled = values.paintSize != 1.0f || frame.pixelRatio != atlas.getPixelRatio() || bucket.iconsNeedLinear; + const bool iconTransformed = values.rotationAlignment == AlignmentType::Map || state.getPitch() != 0; + atlas.bind(bucket.sdfIcons || state.isChanging() || iconScaled || iconTransformed, context, 0); - const float angleOffset = - layout.iconRotationAlignment == AlignmentType::Map - ? state.getAngle() - : 0; + const Size texsize = atlas.getSize(); - const float fontSize = layer.impl->iconSize; - const float fontScale = fontSize / 1.0f; - - SpriteAtlas* activeSpriteAtlas = layer.impl->spriteAtlas; - const bool iconScaled = fontScale != 1 || frame.pixelRatio != activeSpriteAtlas->getPixelRatio() || bucket.iconsNeedLinear; - const bool iconTransformed = layout.iconRotationAlignment == AlignmentType::Map || angleOffset != 0 || state.getPitch() != 0; - activeSpriteAtlas->bind(sdf || state.isChanging() || iconScaled || iconTransformed, context, 0); - - if (sdf) { - renderSDF(bucket, - tile, - 1.0f, - {{ float(activeSpriteAtlas->getWidth()) / 4.0f, float(activeSpriteAtlas->getHeight()) / 4.0f }}, - parameters.shaders.symbolIconSDF, - &SymbolBucket::drawIcons, - layout.iconRotationAlignment, - // icon-pitch-alignment is not yet implemented - // and we simply inherit the rotation alignment - layout.iconRotationAlignment, - layout.iconSize, - paint.iconOpacity, - paint.iconColor, - paint.iconHaloColor, - paint.iconHaloWidth, - paint.iconHaloBlur, - paint.iconTranslate, - paint.iconTranslateAnchor, - layer.impl->iconSize); - } else { - mat4 vtxMatrix = tile.translatedMatrix(paint.iconTranslate, - paint.iconTranslateAnchor, - state); - - std::array<float, 2> extrudeScale; - - const bool alignedWithMap = layout.iconRotationAlignment == AlignmentType::Map; - if (alignedWithMap) { - extrudeScale.fill(tile.id.pixelsToTileUnits(1, state.getZoom()) * fontScale); - } else { - extrudeScale = {{ - pixelsToGLUnits[0] * fontScale * state.getAltitude(), - pixelsToGLUnits[1] * fontScale * state.getAltitude() - }}; + if (bucket.sdfIcons) { + if (values.hasHalo()) { + draw(parameters.programs.symbolIconSDF, + SymbolSDFProgram::haloUniformValues(values, texsize, pixelsToGLUnits, tile, state, frame.pixelRatio), + bucket.icon, + values); } - auto& iconShader = parameters.shaders.symbolIcon; + if (values.hasForeground()) { + draw(parameters.programs.symbolIconSDF, + SymbolSDFProgram::foregroundUniformValues(values, texsize, pixelsToGLUnits, tile, state, frame.pixelRatio), + bucket.icon, + values); + } + } else { + draw(parameters.programs.symbolIcon, + SymbolIconProgram::uniformValues(values, texsize, pixelsToGLUnits, tile, state), + bucket.icon, + values); + } + } - context.program = iconShader.getID(); - iconShader.u_matrix = vtxMatrix; - iconShader.u_extrude_scale = extrudeScale; - iconShader.u_texsize = {{ float(activeSpriteAtlas->getWidth()) / 4.0f, float(activeSpriteAtlas->getHeight()) / 4.0f }}; - iconShader.u_rotate_with_map = alignedWithMap; - iconShader.u_texture = 0; + if (bucket.hasTextData()) { + glyphAtlas->bind(context, 0); - // adjust min/max zooms for variable font sies - float zoomAdjust = std::log(fontSize / layout.iconSize) / std::log(2); - iconShader.u_zoom = (state.getZoom() - zoomAdjust) * 10; // current zoom level - iconShader.u_opacity = paint.iconOpacity; + auto values = layer.impl->textPropertyValues(layout); - frameHistory.bind(context, 1); - iconShader.u_fadetexture = 1; + const Size texsize = glyphAtlas->getSize(); - bucket.drawIcons(iconShader, context, paintMode()); + if (values.hasHalo()) { + draw(parameters.programs.symbolGlyph, + SymbolSDFProgram::haloUniformValues(values, texsize, pixelsToGLUnits, tile, state, frame.pixelRatio), + bucket.text, + values); } - } - if (bucket.hasTextData()) { - if (layout.textPitchAlignment == AlignmentType::Map) { - context.depthFunc = gl::DepthTestFunction::LessEqual; - context.depthTest = true; - } else { - context.depthTest = false; + if (values.hasForeground()) { + draw(parameters.programs.symbolGlyph, + SymbolSDFProgram::foregroundUniformValues(values, texsize, pixelsToGLUnits, tile, state, frame.pixelRatio), + bucket.text, + values); } - - glyphAtlas->bind(context, 0); - - renderSDF(bucket, - tile, - 24.0f, - {{ float(glyphAtlas->width) / 4, float(glyphAtlas->height) / 4 }}, - parameters.shaders.symbolGlyph, - &SymbolBucket::drawGlyphs, - layout.textRotationAlignment, - layout.textPitchAlignment, - layout.textSize, - paint.textOpacity, - paint.textColor, - paint.textHaloColor, - paint.textHaloWidth, - paint.textHaloBlur, - paint.textTranslate, - paint.textTranslateAnchor, - layer.impl->textSize); } if (bucket.hasCollisionBoxData()) { - context.stencilTest = false; - - auto& collisionBoxShader = shaders->collisionBox; - context.program = collisionBoxShader.getID(); - collisionBoxShader.u_matrix = tile.matrix; - // TODO: This was the overscaled z instead of the canonical z. - collisionBoxShader.u_scale = std::pow(2, state.getZoom() - tile.id.canonical.z); - collisionBoxShader.u_zoom = state.getZoom() * 10; - collisionBoxShader.u_maxzoom = (tile.id.canonical.z + 1) * 10; - context.lineWidth = 1.0f; - - bucket.drawCollisionBoxes(collisionBoxShader, context); + programs->collisionBox.draw( + context, + gl::Lines { 1.0f }, + gl::DepthMode::disabled(), + gl::StencilMode::disabled(), + colorModeForRenderPass(), + CollisionBoxProgram::UniformValues { + uniforms::u_matrix::Value{ tile.matrix }, + uniforms::u_scale::Value{ std::pow(2.0f, float(state.getZoom() - tile.tile.id.overscaledZ)) }, + uniforms::u_zoom::Value{ float(state.getZoom() * 10) }, + uniforms::u_maxzoom::Value{ float((tile.id.canonical.z + 1) * 10) }, + }, + *bucket.collisionBox.vertexBuffer, + *bucket.collisionBox.indexBuffer, + bucket.collisionBox.segments + ); } } diff --git a/src/mbgl/renderer/raster_bucket.cpp b/src/mbgl/renderer/raster_bucket.cpp index 80d6dfe8dd..0355911296 100644 --- a/src/mbgl/renderer/raster_bucket.cpp +++ b/src/mbgl/renderer/raster_bucket.cpp @@ -1,8 +1,7 @@ #include <mbgl/renderer/raster_bucket.hpp> #include <mbgl/style/layers/raster_layer.hpp> -#include <mbgl/shader/raster_shader.hpp> +#include <mbgl/programs/raster_program.hpp> #include <mbgl/renderer/painter.hpp> -#include <mbgl/gl/gl.hpp> #include <mbgl/gl/context.hpp> namespace mbgl { @@ -25,23 +24,8 @@ void RasterBucket::render(Painter& painter, painter.renderRaster(parameters, *this, *layer.as<RasterLayer>(), tile); } -void RasterBucket::drawRaster(RasterShader& shader, - gl::VertexBuffer<RasterVertex>& vertices, - gl::VertexArrayObject& array, - gl::Context& context) { - assert(texture); - context.bindTexture(*texture, 0, gl::TextureFilter::Linear); - context.bindTexture(*texture, 1, gl::TextureFilter::Linear); - array.bind(shader, vertices, BUFFER_OFFSET_0, context); - MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, static_cast<GLsizei>(vertices.vertexCount))); -} - bool RasterBucket::hasData() const { return true; } -bool RasterBucket::needsClipping() const { - return false; -} - } // namespace mbgl diff --git a/src/mbgl/renderer/raster_bucket.hpp b/src/mbgl/renderer/raster_bucket.hpp index b0d3ca49c7..9648e954bd 100644 --- a/src/mbgl/renderer/raster_bucket.hpp +++ b/src/mbgl/renderer/raster_bucket.hpp @@ -7,15 +7,6 @@ namespace mbgl { -class RasterShader; -class RasterVertex; - -namespace gl { -class Context; -template <class> class VertexBuffer; -class VertexArrayObject; -} // namespace gl - class RasterBucket : public Bucket { public: RasterBucket(PremultipliedImage&&); @@ -23,11 +14,7 @@ public: void upload(gl::Context&) override; void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override; bool hasData() const override; - bool needsClipping() const override; - - void drawRaster(RasterShader&, gl::VertexBuffer<RasterVertex>&, gl::VertexArrayObject&, gl::Context&); -private: PremultipliedImage image; optional<gl::Texture> texture; }; diff --git a/src/mbgl/renderer/render_tile.hpp b/src/mbgl/renderer/render_tile.hpp index 74669faaf9..e2e0c3d656 100644 --- a/src/mbgl/renderer/render_tile.hpp +++ b/src/mbgl/renderer/render_tile.hpp @@ -24,6 +24,7 @@ public: Tile& tile; ClipID clip; mat4 matrix; + bool used = false; mat4 translatedMatrix(const std::array<float, 2>& translate, style::TranslateAnchorType anchor, diff --git a/src/mbgl/renderer/symbol_bucket.cpp b/src/mbgl/renderer/symbol_bucket.cpp index 565c58c7ed..0f2c89339f 100644 --- a/src/mbgl/renderer/symbol_bucket.cpp +++ b/src/mbgl/renderer/symbol_bucket.cpp @@ -1,17 +1,13 @@ #include <mbgl/renderer/symbol_bucket.hpp> #include <mbgl/renderer/painter.hpp> #include <mbgl/style/layers/symbol_layer.hpp> -#include <mbgl/shader/symbol_sdf_shader.hpp> -#include <mbgl/shader/symbol_icon_shader.hpp> -#include <mbgl/shader/collision_box_shader.hpp> -#include <mbgl/gl/gl.hpp> namespace mbgl { using namespace style; SymbolBucket::SymbolBucket(const MapMode mode_, - style::SymbolLayoutProperties layout_, + style::SymbolLayoutProperties::Evaluated layout_, bool sdfIcons_, bool iconsNeedLinear_) : mode(mode_), @@ -31,8 +27,9 @@ void SymbolBucket::upload(gl::Context& context) { icon.indexBuffer = context.createIndexBuffer(std::move(icon.triangles)); } - if (hasCollisionBoxData()) { + if (!collisionBox.vertices.empty()) { collisionBox.vertexBuffer = context.createVertexBuffer(std::move(collisionBox.vertices)); + collisionBox.indexBuffer = context.createIndexBuffer(std::move(collisionBox.lines)); } uploaded = true; @@ -46,79 +43,20 @@ void SymbolBucket::render(Painter& painter, } bool SymbolBucket::hasData() const { - assert(false); // Should be calling SymbolLayout::hasSymbolInstances() instead. + assert(false); // Should be calling SymbolLayout::has{Text,Icon,CollisonBox}Data() instead. return false; } bool SymbolBucket::hasTextData() const { - return !text.groups.empty(); + return !text.segments.empty(); } bool SymbolBucket::hasIconData() const { - return !icon.groups.empty(); + return !icon.segments.empty(); } bool SymbolBucket::hasCollisionBoxData() const { - return !collisionBox.groups.empty(); -} - -bool SymbolBucket::needsClipping() const { - return mode == MapMode::Still; -} - -void SymbolBucket::drawGlyphs(SymbolSDFShader& shader, - gl::Context& context, - PaintMode paintMode) { - GLbyte* vertex_index = BUFFER_OFFSET_0; - GLbyte* elements_index = BUFFER_OFFSET_0; - for (auto& group : text.groups) { - group.getVAO(shader, paintMode).bind( - shader, *text.vertexBuffer, *text.indexBuffer, vertex_index, context); - MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(group.indexLength * 3), GL_UNSIGNED_SHORT, - elements_index)); - vertex_index += group.vertexLength * text.vertexBuffer->vertexSize; - elements_index += group.indexLength * text.indexBuffer->primitiveSize; - } -} - -void SymbolBucket::drawIcons(SymbolSDFShader& shader, - gl::Context& context, - PaintMode paintMode) { - GLbyte* vertex_index = BUFFER_OFFSET_0; - GLbyte* elements_index = BUFFER_OFFSET_0; - for (auto& group : icon.groups) { - group.getVAO(shader, paintMode).bind( - shader, *icon.vertexBuffer, *icon.indexBuffer, vertex_index, context); - MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(group.indexLength * 3), GL_UNSIGNED_SHORT, - elements_index)); - vertex_index += group.vertexLength * icon.vertexBuffer->vertexSize; - elements_index += group.indexLength * icon.indexBuffer->primitiveSize; - } -} - -void SymbolBucket::drawIcons(SymbolIconShader& shader, - gl::Context& context, - PaintMode paintMode) { - GLbyte* vertex_index = BUFFER_OFFSET_0; - GLbyte* elements_index = BUFFER_OFFSET_0; - for (auto& group : icon.groups) { - group.getVAO(shader, paintMode).bind( - shader, *icon.vertexBuffer, *icon.indexBuffer, vertex_index, context); - MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(group.indexLength * 3), GL_UNSIGNED_SHORT, - elements_index)); - vertex_index += group.vertexLength * icon.vertexBuffer->vertexSize; - elements_index += group.indexLength * icon.indexBuffer->primitiveSize; - } -} - -void SymbolBucket::drawCollisionBoxes(CollisionBoxShader& shader, - gl::Context& context) { - GLbyte* vertex_index = BUFFER_OFFSET_0; - for (auto& group : collisionBox.groups) { - group.getVAO(shader, PaintMode::Regular).bind( - shader, *collisionBox.vertexBuffer, vertex_index, context); - MBGL_CHECK_ERROR(glDrawArrays(GL_LINES, 0, static_cast<GLsizei>(group.vertexLength))); - } + return !collisionBox.segments.empty(); } } // namespace mbgl diff --git a/src/mbgl/renderer/symbol_bucket.hpp b/src/mbgl/renderer/symbol_bucket.hpp index e5180c31e2..d62a61aab7 100644 --- a/src/mbgl/renderer/symbol_bucket.hpp +++ b/src/mbgl/renderer/symbol_bucket.hpp @@ -1,28 +1,23 @@ #pragma once #include <mbgl/renderer/bucket.hpp> -#include <mbgl/renderer/element_group.hpp> #include <mbgl/map/mode.hpp> #include <mbgl/gl/vertex_buffer.hpp> #include <mbgl/gl/index_buffer.hpp> -#include <mbgl/shader/symbol_vertex.hpp> -#include <mbgl/shader/collision_box_vertex.hpp> +#include <mbgl/gl/segment.hpp> +#include <mbgl/programs/symbol_program.hpp> +#include <mbgl/programs/collision_box_program.hpp> #include <mbgl/text/glyph_range.hpp> #include <mbgl/style/layers/symbol_layer_properties.hpp> -#include <memory> #include <vector> namespace mbgl { -class SymbolSDFShader; -class SymbolIconShader; -class CollisionBoxShader; - class SymbolBucket : public Bucket { public: SymbolBucket(const MapMode, - style::SymbolLayoutProperties, + style::SymbolLayoutProperties::Evaluated, bool sdfIcons, bool iconsNeedLinear); @@ -32,46 +27,37 @@ public: bool hasTextData() const; bool hasIconData() const; bool hasCollisionBoxData() const; - bool needsClipping() const override; - - void drawGlyphs(SymbolSDFShader&, gl::Context&, PaintMode); - void drawIcons(SymbolSDFShader&, gl::Context&, PaintMode); - void drawIcons(SymbolIconShader&, gl::Context&, PaintMode); - void drawCollisionBoxes(CollisionBoxShader&, gl::Context&); const MapMode mode; - const style::SymbolLayoutProperties layout; + const style::SymbolLayoutProperties::Evaluated layout; const bool sdfIcons; const bool iconsNeedLinear; -private: - friend class SymbolLayout; - struct TextBuffer { - std::vector<SymbolVertex> vertices; - std::vector<gl::Triangle> triangles; - std::vector<ElementGroup<SymbolSDFShader>> groups; + gl::VertexVector<SymbolVertex> vertices; + gl::IndexVector<gl::Triangles> triangles; + gl::SegmentVector<SymbolAttributes> segments; optional<gl::VertexBuffer<SymbolVertex>> vertexBuffer; - optional<gl::IndexBuffer<gl::Triangle>> indexBuffer; + optional<gl::IndexBuffer<gl::Triangles>> indexBuffer; } text; struct IconBuffer { - std::vector<SymbolVertex> vertices; - std::vector<gl::Triangle> triangles; - std::vector<ElementGroup<SymbolSDFShader, SymbolIconShader>> groups; + gl::VertexVector<SymbolVertex> vertices; + gl::IndexVector<gl::Triangles> triangles; + gl::SegmentVector<SymbolAttributes> segments; optional<gl::VertexBuffer<SymbolVertex>> vertexBuffer; - optional<gl::IndexBuffer<gl::Triangle>> indexBuffer; + optional<gl::IndexBuffer<gl::Triangles>> indexBuffer; } icon; struct CollisionBoxBuffer { - std::vector<CollisionBoxVertex> vertices; - std::vector<gl::Line> lines; - std::vector<ElementGroup<CollisionBoxShader>> groups; + gl::VertexVector<CollisionBoxVertex> vertices; + gl::IndexVector<gl::Lines> lines; + gl::SegmentVector<CollisionBoxAttributes> segments; optional<gl::VertexBuffer<CollisionBoxVertex>> vertexBuffer; - optional<gl::IndexBuffer<gl::Line>> indexBuffer; + optional<gl::IndexBuffer<gl::Lines>> indexBuffer; } collisionBox; }; diff --git a/src/mbgl/shader/circle_shader.cpp b/src/mbgl/shader/circle_shader.cpp deleted file mode 100644 index 9e294f8d76..0000000000 --- a/src/mbgl/shader/circle_shader.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include <mbgl/shader/circle_shader.hpp> -#include <mbgl/shader/circle.vertex.hpp> -#include <mbgl/shader/circle.fragment.hpp> -#include <mbgl/shader/circle_vertex.hpp> - -namespace mbgl { - -CircleShader::CircleShader(gl::Context& context, Defines defines) - : Shader(shaders::circle::name, - shaders::circle::vertex, - shaders::circle::fragment, - context, defines) { -} - -} // namespace mbgl diff --git a/src/mbgl/shader/circle_shader.hpp b/src/mbgl/shader/circle_shader.hpp deleted file mode 100644 index c2c4053ba4..0000000000 --- a/src/mbgl/shader/circle_shader.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include <mbgl/gl/shader.hpp> -#include <mbgl/gl/attribute.hpp> -#include <mbgl/gl/uniform.hpp> -#include <mbgl/util/color.hpp> - -namespace mbgl { - -class CircleVertex; - -class CircleShader : public gl::Shader { -public: - CircleShader(gl::Context&, Defines defines = None); - - using VertexType = CircleVertex; - - gl::Attribute<int16_t, 2> a_pos = {"a_pos", *this}; - - gl::UniformMatrix<4> u_matrix = {"u_matrix", *this}; - gl::Uniform<std::array<float, 2>> u_extrude_scale = {"u_extrude_scale", *this}; - gl::Uniform<float> u_devicepixelratio = {"u_devicepixelratio", *this}; - gl::Uniform<Color> u_color = {"u_color", *this}; - gl::Uniform<float> u_radius = {"u_radius", *this}; - gl::Uniform<float> u_blur = {"u_blur", *this}; - gl::Uniform<float> u_opacity = {"u_opacity", *this}; - gl::Uniform<int32_t> u_scale_with_map = {"u_scale_with_map", *this}; -}; - -} // namespace mbgl diff --git a/src/mbgl/shader/circle_vertex.cpp b/src/mbgl/shader/circle_vertex.cpp deleted file mode 100644 index 8beb88e650..0000000000 --- a/src/mbgl/shader/circle_vertex.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include <mbgl/shader/circle_vertex.hpp> - -namespace mbgl { - -static_assert(sizeof(CircleVertex) == 4, "expected CircleVertex size"); - -} // namespace mbgl diff --git a/src/mbgl/shader/circle_vertex.hpp b/src/mbgl/shader/circle_vertex.hpp deleted file mode 100644 index 4fce49f137..0000000000 --- a/src/mbgl/shader/circle_vertex.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include <mbgl/gl/attribute.hpp> - -#include <array> -#include <cstdint> - -namespace mbgl { - -class CircleVertex { -public: - /* - * @param {number} x vertex position - * @param {number} y vertex position - * @param {number} ex extrude normal - * @param {number} ey extrude normal - */ - CircleVertex(int16_t x, int16_t y, float ex, float ey) - : a_pos { - static_cast<int16_t>((x * 2) + ((ex + 1) / 2)), - static_cast<int16_t>((y * 2) + ((ey + 1) / 2)) - } {} - - const int16_t a_pos[2]; -}; - -namespace gl { - -template <class Shader> -struct AttributeBindings<Shader, CircleVertex> { - std::array<AttributeBinding, 1> operator()(const Shader& shader) { - return {{ - MBGL_MAKE_ATTRIBUTE_BINDING(CircleVertex, shader, a_pos) - }}; - }; -}; - -} // namespace gl -} // namespace mbgl diff --git a/src/mbgl/shader/collision_box_shader.cpp b/src/mbgl/shader/collision_box_shader.cpp deleted file mode 100644 index d61c849cd1..0000000000 --- a/src/mbgl/shader/collision_box_shader.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include <mbgl/shader/collision_box_shader.hpp> -#include <mbgl/shader/collision_box.vertex.hpp> -#include <mbgl/shader/collision_box.fragment.hpp> -#include <mbgl/shader/collision_box_vertex.hpp> - -namespace mbgl { - -CollisionBoxShader::CollisionBoxShader(gl::Context& context) - : Shader(shaders::collision_box::name, - shaders::collision_box::vertex, - shaders::collision_box::fragment, - context) { -} - -} // namespace mbgl diff --git a/src/mbgl/shader/collision_box_shader.hpp b/src/mbgl/shader/collision_box_shader.hpp deleted file mode 100644 index 2f5c506168..0000000000 --- a/src/mbgl/shader/collision_box_shader.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include <mbgl/gl/shader.hpp> -#include <mbgl/gl/attribute.hpp> -#include <mbgl/gl/uniform.hpp> - -namespace mbgl { - -class CollisionBoxVertex; - -class CollisionBoxShader : public gl::Shader { -public: - CollisionBoxShader(gl::Context&); - - using VertexType = CollisionBoxVertex; - - gl::Attribute<int16_t, 2> a_pos = {"a_pos", *this}; - gl::Attribute<int16_t, 2> a_extrude = {"a_extrude", *this}; - gl::Attribute<uint8_t, 2> a_data = {"a_data", *this}; - - gl::UniformMatrix<4> u_matrix = {"u_matrix", *this}; - gl::Uniform<float> u_scale = {"u_scale", *this}; - gl::Uniform<float> u_zoom = {"u_zoom", *this}; - gl::Uniform<float> u_maxzoom = {"u_maxzoom", *this}; -}; - -} // namespace mbgl diff --git a/src/mbgl/shader/collision_box_vertex.cpp b/src/mbgl/shader/collision_box_vertex.cpp deleted file mode 100644 index 397fbfe6a3..0000000000 --- a/src/mbgl/shader/collision_box_vertex.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include <mbgl/shader/collision_box_vertex.hpp> - -namespace mbgl { - -static_assert(sizeof(CollisionBoxVertex) == 10, "expected CollisionBoxVertex size"); - -} // namespace mbgl diff --git a/src/mbgl/shader/collision_box_vertex.hpp b/src/mbgl/shader/collision_box_vertex.hpp deleted file mode 100644 index ba72b1c0ee..0000000000 --- a/src/mbgl/shader/collision_box_vertex.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include <mbgl/gl/attribute.hpp> - -#include <array> -#include <cstdint> -#include <cmath> - -namespace mbgl { - -class CollisionBoxVertex { -public: - CollisionBoxVertex(int16_t x, int16_t y, float ox, float oy, float maxzoom, float placementZoom) - : a_pos { x, y }, - a_extrude { - static_cast<int16_t>(::round(ox)), - static_cast<int16_t>(::round(oy)) - }, - a_data { - static_cast<uint8_t>(maxzoom * 10), - static_cast<uint8_t>(placementZoom * 10) - } {} - - const int16_t a_pos[2]; - const int16_t a_extrude[2]; - const uint8_t a_data[2]; -}; - -namespace gl { - -template <class Shader> -struct AttributeBindings<Shader, CollisionBoxVertex> { - std::array<AttributeBinding, 3> operator()(const Shader& shader) { - return {{ - MBGL_MAKE_ATTRIBUTE_BINDING(CollisionBoxVertex, shader, a_pos), - MBGL_MAKE_ATTRIBUTE_BINDING(CollisionBoxVertex, shader, a_extrude), - MBGL_MAKE_ATTRIBUTE_BINDING(CollisionBoxVertex, shader, a_data) - }}; - }; -}; - -} // namespace gl -} // namespace mbgl diff --git a/src/mbgl/shader/fill_outline_pattern_shader.cpp b/src/mbgl/shader/fill_outline_pattern_shader.cpp deleted file mode 100644 index b03921d384..0000000000 --- a/src/mbgl/shader/fill_outline_pattern_shader.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include <mbgl/shader/fill_outline_pattern_shader.hpp> -#include <mbgl/shader/fill_outline_pattern.vertex.hpp> -#include <mbgl/shader/fill_outline_pattern.fragment.hpp> -#include <mbgl/shader/fill_vertex.hpp> - -namespace mbgl { - -FillOutlinePatternShader::FillOutlinePatternShader(gl::Context& context, Defines defines) - : Shader(shaders::fill_outline_pattern::name, - shaders::fill_outline_pattern::vertex, - shaders::fill_outline_pattern::fragment, - context, defines) { -} - -} // namespace mbgl diff --git a/src/mbgl/shader/fill_outline_pattern_shader.hpp b/src/mbgl/shader/fill_outline_pattern_shader.hpp deleted file mode 100644 index 630e6a7ce8..0000000000 --- a/src/mbgl/shader/fill_outline_pattern_shader.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include <mbgl/gl/shader.hpp> -#include <mbgl/gl/attribute.hpp> -#include <mbgl/gl/uniform.hpp> - -namespace mbgl { - -class FillVertex; - -class FillOutlinePatternShader : public gl::Shader { -public: - FillOutlinePatternShader(gl::Context&, Defines defines = None); - - using VertexType = FillVertex; - - gl::Attribute<int16_t, 2> a_pos = {"a_pos", *this}; - - gl::UniformMatrix<4> u_matrix = {"u_matrix", *this}; - gl::Uniform<std::array<float, 2>> u_pattern_tl_a = {"u_pattern_tl_a", *this}; - gl::Uniform<std::array<float, 2>> u_pattern_br_a = {"u_pattern_br_a", *this}; - gl::Uniform<std::array<float, 2>> u_pattern_tl_b = {"u_pattern_tl_b", *this}; - gl::Uniform<std::array<float, 2>> u_pattern_br_b = {"u_pattern_br_b", *this}; - gl::Uniform<float> u_opacity = {"u_opacity", *this}; - gl::Uniform<float> u_mix = {"u_mix", *this}; - gl::Uniform<float> u_scale_a = {"u_scale_a", *this}; - gl::Uniform<float> u_scale_b = {"u_scale_b", *this}; - gl::Uniform<float> u_tile_units_to_pixels = {"u_tile_units_to_pixels", *this}; - gl::Uniform<int32_t> u_image = {"u_image", *this}; - gl::Uniform<std::array<float, 2>> u_pattern_size_a = {"u_pattern_size_a", *this}; - gl::Uniform<std::array<float, 2>> u_pattern_size_b = {"u_pattern_size_b", *this}; - gl::Uniform<std::array<float, 2>> u_pixel_coord_upper = {"u_pixel_coord_upper", *this}; - gl::Uniform<std::array<float, 2>> u_pixel_coord_lower = {"u_pixel_coord_lower", *this}; - gl::Uniform<std::array<float, 2>> u_world = {"u_world", *this}; -}; - -} // namespace mbgl diff --git a/src/mbgl/shader/fill_outline_shader.cpp b/src/mbgl/shader/fill_outline_shader.cpp deleted file mode 100644 index 6e6d8c2239..0000000000 --- a/src/mbgl/shader/fill_outline_shader.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include <mbgl/shader/fill_outline_shader.hpp> -#include <mbgl/shader/fill_outline.vertex.hpp> -#include <mbgl/shader/fill_outline.fragment.hpp> -#include <mbgl/shader/fill_vertex.hpp> - -namespace mbgl { - -FillOutlineShader::FillOutlineShader(gl::Context& context, Defines defines) - : Shader(shaders::fill_outline::name, - shaders::fill_outline::vertex, - shaders::fill_outline::fragment, - context, defines) { -} - -} // namespace mbgl diff --git a/src/mbgl/shader/fill_outline_shader.hpp b/src/mbgl/shader/fill_outline_shader.hpp deleted file mode 100644 index c20bc187d3..0000000000 --- a/src/mbgl/shader/fill_outline_shader.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include <mbgl/gl/shader.hpp> -#include <mbgl/gl/attribute.hpp> -#include <mbgl/gl/uniform.hpp> -#include <mbgl/util/color.hpp> - -namespace mbgl { - -class FillVertex; - -class FillOutlineShader : public gl::Shader { -public: - FillOutlineShader(gl::Context&, Defines defines = None); - - using VertexType = FillVertex; - - gl::Attribute<int16_t, 2> a_pos = {"a_pos", *this}; - - gl::UniformMatrix<4> u_matrix = {"u_matrix", *this}; - gl::Uniform<Color> u_outline_color = {"u_outline_color", *this}; - gl::Uniform<float> u_opacity = {"u_opacity", *this}; - gl::Uniform<std::array<float, 2>> u_world = {"u_world", *this}; -}; - -} // namespace mbgl diff --git a/src/mbgl/shader/fill_pattern_shader.cpp b/src/mbgl/shader/fill_pattern_shader.cpp deleted file mode 100644 index 60be6d79ad..0000000000 --- a/src/mbgl/shader/fill_pattern_shader.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include <mbgl/shader/fill_pattern_shader.hpp> -#include <mbgl/shader/fill_pattern.vertex.hpp> -#include <mbgl/shader/fill_pattern.fragment.hpp> -#include <mbgl/shader/fill_vertex.hpp> - -namespace mbgl { - -FillPatternShader::FillPatternShader(gl::Context& context, Defines defines) - : Shader(shaders::fill_pattern::name, - shaders::fill_pattern::vertex, - shaders::fill_pattern::fragment, - context, defines) { -} - -} // namespace mbgl diff --git a/src/mbgl/shader/fill_pattern_shader.hpp b/src/mbgl/shader/fill_pattern_shader.hpp deleted file mode 100644 index 36be538000..0000000000 --- a/src/mbgl/shader/fill_pattern_shader.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include <mbgl/gl/shader.hpp> -#include <mbgl/gl/attribute.hpp> -#include <mbgl/gl/uniform.hpp> - -namespace mbgl { - -class FillVertex; - -class FillPatternShader : public gl::Shader { -public: - FillPatternShader(gl::Context&, Defines defines = None); - - using VertexType = FillVertex; - - gl::Attribute<int16_t, 2> a_pos = {"a_pos", *this}; - - gl::UniformMatrix<4> u_matrix = {"u_matrix", *this}; - gl::Uniform<std::array<float, 2>> u_pattern_tl_a = {"u_pattern_tl_a", *this}; - gl::Uniform<std::array<float, 2>> u_pattern_br_a = {"u_pattern_br_a", *this}; - gl::Uniform<std::array<float, 2>> u_pattern_tl_b = {"u_pattern_tl_b", *this}; - gl::Uniform<std::array<float, 2>> u_pattern_br_b = {"u_pattern_br_b", *this}; - gl::Uniform<float> u_opacity = {"u_opacity", *this}; - gl::Uniform<float> u_mix = {"u_mix", *this}; - gl::Uniform<float> u_scale_a = {"u_scale_a", *this}; - gl::Uniform<float> u_scale_b = {"u_scale_b", *this}; - gl::Uniform<float> u_tile_units_to_pixels = {"u_tile_units_to_pixels", *this}; - gl::Uniform<int32_t> u_image = {"u_image", *this}; - gl::Uniform<std::array<float, 2>> u_pattern_size_a = {"u_pattern_size_a", *this}; - gl::Uniform<std::array<float, 2>> u_pattern_size_b = {"u_pattern_size_b", *this}; - gl::Uniform<std::array<float, 2>> u_pixel_coord_upper = {"u_pixel_coord_upper", *this}; - gl::Uniform<std::array<float, 2>> u_pixel_coord_lower = {"u_pixel_coord_lower", *this}; -}; - -} // namespace mbgl diff --git a/src/mbgl/shader/fill_shader.cpp b/src/mbgl/shader/fill_shader.cpp deleted file mode 100644 index 7026bb2f1c..0000000000 --- a/src/mbgl/shader/fill_shader.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include <mbgl/shader/fill_shader.hpp> -#include <mbgl/shader/fill.vertex.hpp> -#include <mbgl/shader/fill.fragment.hpp> -#include <mbgl/shader/fill_vertex.hpp> - -namespace mbgl { - -FillShader::FillShader(gl::Context& context, Defines defines) - : Shader(shaders::fill::name, - shaders::fill::vertex, - shaders::fill::fragment, - context, defines) { -} - -} // namespace mbgl diff --git a/src/mbgl/shader/fill_shader.hpp b/src/mbgl/shader/fill_shader.hpp deleted file mode 100644 index 1240b73aa2..0000000000 --- a/src/mbgl/shader/fill_shader.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include <mbgl/gl/shader.hpp> -#include <mbgl/gl/attribute.hpp> -#include <mbgl/gl/uniform.hpp> -#include <mbgl/util/color.hpp> - -namespace mbgl { - -class FillVertex; - -class FillShader : public gl::Shader { -public: - FillShader(gl::Context&, Defines defines = None); - - using VertexType = FillVertex; - - gl::Attribute<int16_t, 2> a_pos = {"a_pos", *this}; - - gl::UniformMatrix<4> u_matrix = {"u_matrix", *this}; - gl::Uniform<Color> u_color = {"u_color", *this}; - gl::Uniform<float> u_opacity = {"u_opacity", *this}; -}; - -} // namespace mbgl diff --git a/src/mbgl/shader/fill_vertex.cpp b/src/mbgl/shader/fill_vertex.cpp deleted file mode 100644 index c39a0b96b1..0000000000 --- a/src/mbgl/shader/fill_vertex.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include <mbgl/shader/fill_vertex.hpp> - -namespace mbgl { - -static_assert(sizeof(FillVertex) == 4, "expected FillVertex size"); - -} // namespace mbgl diff --git a/src/mbgl/shader/fill_vertex.hpp b/src/mbgl/shader/fill_vertex.hpp deleted file mode 100644 index 1b8130382a..0000000000 --- a/src/mbgl/shader/fill_vertex.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include <mbgl/gl/attribute.hpp> - -#include <array> -#include <cstdint> - -namespace mbgl { - -class FillVertex { -public: - FillVertex(int16_t x, int16_t y) - : a_pos { x, y } {} - - const int16_t a_pos[2]; -}; - -namespace gl { - -template <class Shader> -struct AttributeBindings<Shader, FillVertex> { - std::array<AttributeBinding, 1> operator()(const Shader& shader) { - return {{ - MBGL_MAKE_ATTRIBUTE_BINDING(FillVertex, shader, a_pos) - }}; - }; -}; - -} // namespace gl -} // namespace mbgl diff --git a/src/mbgl/shader/line_pattern_shader.cpp b/src/mbgl/shader/line_pattern_shader.cpp deleted file mode 100644 index e6bc32a5c9..0000000000 --- a/src/mbgl/shader/line_pattern_shader.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include <mbgl/shader/line_pattern_shader.hpp> -#include <mbgl/shader/line_pattern.vertex.hpp> -#include <mbgl/shader/line_pattern.fragment.hpp> -#include <mbgl/shader/line_vertex.hpp> - -namespace mbgl { - -LinePatternShader::LinePatternShader(gl::Context& context, Defines defines) - : Shader(shaders::line_pattern::name, - shaders::line_pattern::vertex, - shaders::line_pattern::fragment, - context, defines) { -} - -} // namespace mbgl diff --git a/src/mbgl/shader/line_pattern_shader.hpp b/src/mbgl/shader/line_pattern_shader.hpp deleted file mode 100644 index 1bd6085c8b..0000000000 --- a/src/mbgl/shader/line_pattern_shader.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include <mbgl/gl/shader.hpp> -#include <mbgl/gl/uniform.hpp> -#include <mbgl/gl/attribute.hpp> - -namespace mbgl { - -class LineVertex; - -class LinePatternShader : public gl::Shader { -public: - LinePatternShader(gl::Context&, Defines defines = None); - - using VertexType = LineVertex; - - gl::Attribute<int16_t, 2> a_pos = { "a_pos", *this }; - gl::Attribute<uint8_t, 4> a_data = { "a_data", *this }; - - gl::UniformMatrix<4> u_matrix = {"u_matrix", *this}; - gl::Uniform<float> u_linewidth = {"u_linewidth", *this}; - gl::Uniform<float> u_gapwidth = {"u_gapwidth", *this}; - gl::Uniform<float> u_antialiasing = {"u_antialiasing", *this}; - gl::Uniform<std::array<float, 2>> u_pattern_size_a = {"u_pattern_size_a", *this}; - gl::Uniform<std::array<float, 2>> u_pattern_tl_a = {"u_pattern_tl_a", *this}; - gl::Uniform<std::array<float, 2>> u_pattern_br_a = {"u_pattern_br_a", *this}; - gl::Uniform<std::array<float, 2>> u_pattern_size_b = {"u_pattern_size_b", *this}; - gl::Uniform<std::array<float, 2>> u_pattern_tl_b = {"u_pattern_tl_b", *this}; - gl::Uniform<std::array<float, 2>> u_pattern_br_b = {"u_pattern_br_b", *this}; - gl::Uniform<float> u_ratio = {"u_ratio", *this}; - gl::Uniform<float> u_point = {"u_point", *this}; - gl::Uniform<float> u_blur = {"u_blur", *this}; - gl::Uniform<float> u_fade = {"u_fade", *this}; - gl::Uniform<float> u_opacity = {"u_opacity", *this}; - gl::Uniform<float> u_extra = {"u_extra", *this}; - gl::Uniform<float> u_offset = {"u_offset", *this}; - gl::Uniform<int32_t> u_image = {"u_image", *this}; - gl::UniformMatrix<2> u_antialiasingmatrix = {"u_antialiasingmatrix", *this}; -}; - -} // namespace mbgl diff --git a/src/mbgl/shader/line_sdf_shader.cpp b/src/mbgl/shader/line_sdf_shader.cpp deleted file mode 100644 index dd724365ea..0000000000 --- a/src/mbgl/shader/line_sdf_shader.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include <mbgl/shader/line_sdf_shader.hpp> -#include <mbgl/shader/line_sdf.vertex.hpp> -#include <mbgl/shader/line_sdf.fragment.hpp> -#include <mbgl/shader/line_vertex.hpp> - -namespace mbgl { - -LineSDFShader::LineSDFShader(gl::Context& context, Defines defines) - : Shader(shaders::line_sdf::name, - shaders::line_sdf::vertex, - shaders::line_sdf::fragment, - context, defines) { -} - -} // namespace mbgl diff --git a/src/mbgl/shader/line_sdf_shader.hpp b/src/mbgl/shader/line_sdf_shader.hpp deleted file mode 100644 index d74e42e50f..0000000000 --- a/src/mbgl/shader/line_sdf_shader.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include <mbgl/gl/shader.hpp> -#include <mbgl/gl/attribute.hpp> -#include <mbgl/gl/uniform.hpp> -#include <mbgl/util/color.hpp> - -namespace mbgl { - -class LineVertex; - -class LineSDFShader : public gl::Shader { -public: - LineSDFShader(gl::Context&, Defines defines = None); - - using VertexType = LineVertex; - - gl::Attribute<int16_t, 2> a_pos = { "a_pos", *this }; - gl::Attribute<uint8_t, 4> a_data = { "a_data", *this }; - - gl::UniformMatrix<4> u_matrix = {"u_matrix", *this}; - gl::Uniform<Color> u_color = {"u_color", *this}; - gl::Uniform<float> u_opacity = {"u_opacity", *this}; - gl::Uniform<float> u_linewidth = {"u_linewidth", *this}; - gl::Uniform<float> u_gapwidth = {"u_gapwidth", *this}; - gl::Uniform<float> u_antialiasing = {"u_antialiasing", *this}; - gl::Uniform<float> u_ratio = {"u_ratio", *this}; - gl::Uniform<float> u_blur = {"u_blur", *this}; - gl::Uniform<std::array<float, 2>> u_patternscale_a = { "u_patternscale_a", *this}; - gl::Uniform<float> u_tex_y_a = {"u_tex_y_a", *this}; - gl::Uniform<std::array<float, 2>> u_patternscale_b = { "u_patternscale_b", *this}; - gl::Uniform<float> u_tex_y_b = {"u_tex_y_b", *this}; - gl::Uniform<int32_t> u_image = {"u_image", *this}; - gl::Uniform<float> u_sdfgamma = {"u_sdfgamma", *this}; - gl::Uniform<float> u_mix = {"u_mix", *this}; - gl::Uniform<float> u_extra = {"u_extra", *this}; - gl::Uniform<float> u_offset = {"u_offset", *this}; - gl::UniformMatrix<2> u_antialiasingmatrix = {"u_antialiasingmatrix", *this}; -}; - - -} // namespace mbgl diff --git a/src/mbgl/shader/line_shader.cpp b/src/mbgl/shader/line_shader.cpp deleted file mode 100644 index 4e934cd60c..0000000000 --- a/src/mbgl/shader/line_shader.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include <mbgl/shader/line_shader.hpp> -#include <mbgl/shader/line.vertex.hpp> -#include <mbgl/shader/line.fragment.hpp> -#include <mbgl/shader/line_vertex.hpp> - -namespace mbgl { - -LineShader::LineShader(gl::Context& context, Defines defines) - : Shader(shaders::line::name, - shaders::line::vertex, - shaders::line::fragment, - context, defines) { -} - -} // namespace mbgl diff --git a/src/mbgl/shader/line_shader.hpp b/src/mbgl/shader/line_shader.hpp deleted file mode 100644 index 79991e1883..0000000000 --- a/src/mbgl/shader/line_shader.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include <mbgl/gl/shader.hpp> -#include <mbgl/gl/attribute.hpp> -#include <mbgl/gl/uniform.hpp> -#include <mbgl/util/color.hpp> - -namespace mbgl { - -class LineVertex; - -class LineShader : public gl::Shader { -public: - LineShader(gl::Context&, Defines defines = None); - - using VertexType = LineVertex; - - gl::Attribute<int16_t, 2> a_pos = { "a_pos", *this }; - gl::Attribute<uint8_t, 4> a_data = { "a_data", *this }; - - gl::UniformMatrix<4> u_matrix = {"u_matrix", *this}; - gl::Uniform<Color> u_color = {"u_color", *this}; - gl::Uniform<float> u_opacity = {"u_opacity", *this}; - gl::Uniform<float> u_ratio = {"u_ratio", *this}; - gl::Uniform<float> u_linewidth = {"u_linewidth", *this}; - gl::Uniform<float> u_gapwidth = {"u_gapwidth", *this}; - gl::Uniform<float> u_antialiasing = {"u_antialiasing", *this}; - gl::Uniform<float> u_blur = {"u_blur", *this}; - gl::Uniform<float> u_extra = {"u_extra", *this}; - gl::Uniform<float> u_offset = {"u_offset", *this}; - gl::UniformMatrix<2> u_antialiasingmatrix = {"u_antialiasingmatrix", *this}; -}; - - -} // namespace mbgl diff --git a/src/mbgl/shader/line_vertex.cpp b/src/mbgl/shader/line_vertex.cpp deleted file mode 100644 index ad466310d8..0000000000 --- a/src/mbgl/shader/line_vertex.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include <mbgl/shader/line_vertex.hpp> - -namespace mbgl { - -static_assert(sizeof(LineVertex) == 8, "expected LineVertex size"); - -} // namespace mbgl diff --git a/src/mbgl/shader/line_vertex.hpp b/src/mbgl/shader/line_vertex.hpp deleted file mode 100644 index 086100810e..0000000000 --- a/src/mbgl/shader/line_vertex.hpp +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once - -#include <mbgl/gl/attribute.hpp> - -#include <array> -#include <cstdint> -#include <cmath> - -namespace mbgl { - -class LineVertex { -public: - /* - * @param {number} x vertex position - * @param {number} y vertex position - * @param {number} ex extrude normal - * @param {number} ey extrude normal - * @param {number} tx texture normal - * @param {number} ty texture normal - * @param {number} dir direction of the line cap (-1/0/1) - */ - LineVertex(int16_t x, int16_t y, float ex, float ey, bool tx, bool ty, int8_t dir, int32_t linesofar = 0) - : a_pos { - static_cast<int16_t>((x * 2) | tx), - static_cast<int16_t>((y * 2) | ty) - }, - a_data { - // add 128 to store an byte in an unsigned byte - static_cast<uint8_t>(::round(extrudeScale * ex) + 128), - static_cast<uint8_t>(::round(extrudeScale * ey) + 128), - - // Encode the -1/0/1 direction value into the first two bits of .z of a_data. - // Combine it with the lower 6 bits of `linesofar` (shifted by 2 bites to make - // room for the direction value). The upper 8 bits of `linesofar` are placed in - // the `w` component. `linesofar` is scaled down by `LINE_DISTANCE_SCALE` so that - // we can store longer distances while sacrificing precision. - - // Encode the -1/0/1 direction value into .zw coordinates of a_data, which is normally covered - // by linesofar, so we need to merge them. - // The z component's first bit, as well as the sign bit is reserved for the direction, - // so we need to shift the linesofar. - static_cast<uint8_t>(((dir == 0 ? 0 : (dir < 0 ? -1 : 1 )) + 1) | ((linesofar & 0x3F) << 2)), - static_cast<uint8_t>(linesofar >> 6) - } {} - - const int16_t a_pos[2]; - const uint8_t a_data[4]; - - /* - * Scale the extrusion vector so that the normal length is this value. - * Contains the "texture" normals (-1..1). This is distinct from the extrude - * normals for line joins, because the x-value remains 0 for the texture - * normal array, while the extrude normal actually moves the vertex to create - * the acute/bevelled line join. - */ - static const int8_t extrudeScale = 63; -}; - -namespace gl { - -template <class Shader> -struct AttributeBindings<Shader, LineVertex> { - std::array<AttributeBinding, 2> operator()(const Shader& shader) { - return {{ - MBGL_MAKE_ATTRIBUTE_BINDING(LineVertex, shader, a_pos), - MBGL_MAKE_ATTRIBUTE_BINDING(LineVertex, shader, a_data) - }}; - }; -}; - -} // namespace gl -} // namespace mbgl diff --git a/src/mbgl/shader/raster_shader.cpp b/src/mbgl/shader/raster_shader.cpp deleted file mode 100644 index 34b2bdf47b..0000000000 --- a/src/mbgl/shader/raster_shader.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include <mbgl/shader/raster_shader.hpp> -#include <mbgl/shader/raster.vertex.hpp> -#include <mbgl/shader/raster.fragment.hpp> -#include <mbgl/shader/raster_vertex.hpp> - -namespace mbgl { - -RasterShader::RasterShader(gl::Context& context, Defines defines) - : Shader(shaders::raster::name, - shaders::raster::vertex, - shaders::raster::fragment, - context, defines) { -} - -} // namespace mbgl diff --git a/src/mbgl/shader/raster_shader.hpp b/src/mbgl/shader/raster_shader.hpp deleted file mode 100644 index 9633fd5fa0..0000000000 --- a/src/mbgl/shader/raster_shader.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include <mbgl/gl/shader.hpp> -#include <mbgl/gl/attribute.hpp> -#include <mbgl/gl/uniform.hpp> - -namespace mbgl { - -class RasterVertex; - -class RasterShader : public gl::Shader { -public: - RasterShader(gl::Context&, Defines defines = None); - - using VertexType = RasterVertex; - - gl::Attribute<int16_t, 2> a_pos = { "a_pos", *this }; - gl::Attribute<uint16_t, 2> a_texture_pos = { "a_texture_pos", *this }; - - gl::UniformMatrix<4> u_matrix = {"u_matrix", *this}; - gl::Uniform<int32_t> u_image0 = {"u_image0", *this}; - gl::Uniform<int32_t> u_image1 = {"u_image1", *this}; - gl::Uniform<float> u_opacity0 = {"u_opacity0", *this}; - gl::Uniform<float> u_opacity1 = {"u_opacity1", *this}; - gl::Uniform<float> u_buffer_scale = {"u_buffer_scale", *this}; - gl::Uniform<float> u_brightness_low = {"u_brightness_low", *this}; - gl::Uniform<float> u_brightness_high = {"u_brightness_high", *this}; - gl::Uniform<float> u_saturation_factor = {"u_saturation_factor", *this}; - gl::Uniform<float> u_contrast_factor = {"u_contrast_factor", *this}; - gl::Uniform<std::array<float, 3>> u_spin_weights = {"u_spin_weights", *this}; - gl::Uniform<std::array<float, 2>> u_tl_parent = {"u_tl_parent", *this}; - gl::Uniform<float> u_scale_parent = {"u_scale_parent", *this}; -}; - -} // namespace mbgl diff --git a/src/mbgl/shader/raster_vertex.cpp b/src/mbgl/shader/raster_vertex.cpp deleted file mode 100644 index fc9b1f11c2..0000000000 --- a/src/mbgl/shader/raster_vertex.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include <mbgl/shader/raster_vertex.hpp> - -namespace mbgl { - -static_assert(sizeof(RasterVertex) == 8, "expected RasterVertex size"); - -} // namespace mbgl diff --git a/src/mbgl/shader/raster_vertex.hpp b/src/mbgl/shader/raster_vertex.hpp deleted file mode 100644 index 70e08c609d..0000000000 --- a/src/mbgl/shader/raster_vertex.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include <mbgl/gl/attribute.hpp> - -#include <array> -#include <cstdint> - -namespace mbgl { - -class RasterVertex { -public: - RasterVertex(int16_t x, int16_t y, uint16_t tx, uint16_t ty) - : a_pos { - x, - y - }, - a_texture_pos { - tx, - ty - } {} - - const int16_t a_pos[2]; - const uint16_t a_texture_pos[2]; -}; - -namespace gl { - -template <class Shader> -struct AttributeBindings<Shader, RasterVertex> { - std::array<AttributeBinding, 2> operator()(const Shader& shader) { - return {{ - MBGL_MAKE_ATTRIBUTE_BINDING(RasterVertex, shader, a_pos), - MBGL_MAKE_ATTRIBUTE_BINDING(RasterVertex, shader, a_texture_pos) - }}; - }; -}; - -} // namespace gl -} // namespace mbgl diff --git a/src/mbgl/shader/shaders.hpp b/src/mbgl/shader/shaders.hpp deleted file mode 100644 index 937ee85f44..0000000000 --- a/src/mbgl/shader/shaders.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include <mbgl/shader/circle_shader.hpp> -#include <mbgl/shader/fill_shader.hpp> -#include <mbgl/shader/fill_pattern_shader.hpp> -#include <mbgl/shader/fill_outline_shader.hpp> -#include <mbgl/shader/fill_outline_pattern_shader.hpp> -#include <mbgl/shader/line_shader.hpp> -#include <mbgl/shader/line_sdf_shader.hpp> -#include <mbgl/shader/line_pattern_shader.hpp> -#include <mbgl/shader/raster_shader.hpp> -#include <mbgl/shader/symbol_icon_shader.hpp> -#include <mbgl/shader/symbol_sdf_shader.hpp> - -#include <mbgl/shader/collision_box_shader.hpp> - -namespace mbgl { - -class Shaders { -public: - Shaders(gl::Context& context, gl::Shader::Defines defines = gl::Shader::None) - : circle(context, defines), - fill(context, defines), - fillPattern(context, defines), - fillOutline(context, defines), - fillOutlinePattern(context, defines), - line(context, defines), - lineSDF(context, defines), - linePattern(context, defines), - raster(context, defines), - symbolIcon(context, defines), - symbolIconSDF(context, defines), - symbolGlyph(context, defines), - collisionBox(context) { - } - - CircleShader circle; - FillShader fill; - FillPatternShader fillPattern; - FillOutlineShader fillOutline; - FillOutlinePatternShader fillOutlinePattern; - LineShader line; - LineSDFShader lineSDF; - LinePatternShader linePattern; - RasterShader raster; - SymbolIconShader symbolIcon; - SymbolSDFShader symbolIconSDF; - SymbolSDFShader symbolGlyph; - - CollisionBoxShader collisionBox; - - gl::VertexArrayObject coveringPlainArray; - gl::VertexArrayObject coveringRasterArray; - gl::VertexArrayObject backgroundPatternArray; - gl::VertexArrayObject backgroundArray; -}; - -} // namespace mbgl diff --git a/src/mbgl/shader/symbol_icon_shader.cpp b/src/mbgl/shader/symbol_icon_shader.cpp deleted file mode 100644 index 2655a1c9b5..0000000000 --- a/src/mbgl/shader/symbol_icon_shader.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include <mbgl/shader/symbol_icon_shader.hpp> -#include <mbgl/shader/symbol_icon.vertex.hpp> -#include <mbgl/shader/symbol_icon.fragment.hpp> -#include <mbgl/shader/symbol_vertex.hpp> - -namespace mbgl { - -SymbolIconShader::SymbolIconShader(gl::Context& context, Defines defines) - : Shader(shaders::symbol_icon::name, - shaders::symbol_icon::vertex, - shaders::symbol_icon::fragment, - context, defines) { -} - -} // namespace mbgl diff --git a/src/mbgl/shader/symbol_icon_shader.hpp b/src/mbgl/shader/symbol_icon_shader.hpp deleted file mode 100644 index 5281beb60c..0000000000 --- a/src/mbgl/shader/symbol_icon_shader.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include <mbgl/gl/shader.hpp> -#include <mbgl/gl/attribute.hpp> -#include <mbgl/gl/uniform.hpp> - -namespace mbgl { - -class SymbolVertex; - -class SymbolIconShader : public gl::Shader { -public: - SymbolIconShader(gl::Context&, Defines defines = None); - - using VertexType = SymbolVertex; - - gl::Attribute<int16_t, 2> a_pos = { "a_pos", *this }; - gl::Attribute<int16_t, 2> a_offset = { "a_offset", *this }; - gl::Attribute<uint16_t, 2> a_texture_pos = { "a_texture_pos", *this }; - gl::Attribute<uint8_t, 4> a_data = { "a_data", *this }; - - gl::UniformMatrix<4> u_matrix = {"u_matrix", *this}; - gl::Uniform<std::array<float, 2>> u_extrude_scale = {"u_extrude_scale", *this}; - gl::Uniform<float> u_zoom = {"u_zoom", *this}; - gl::Uniform<float> u_opacity = {"u_opacity", *this}; - gl::Uniform<std::array<float, 2>> u_texsize = {"u_texsize", *this}; - gl::Uniform<int32_t> u_rotate_with_map = {"u_rotate_with_map", *this}; - gl::Uniform<int32_t> u_texture = {"u_texture", *this}; - gl::Uniform<int32_t> u_fadetexture = {"u_fadetexture", *this}; -}; - -} // namespace mbgl diff --git a/src/mbgl/shader/symbol_sdf_shader.cpp b/src/mbgl/shader/symbol_sdf_shader.cpp deleted file mode 100644 index 63c3bd5a4a..0000000000 --- a/src/mbgl/shader/symbol_sdf_shader.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include <mbgl/shader/symbol_sdf_shader.hpp> -#include <mbgl/shader/symbol_sdf.vertex.hpp> -#include <mbgl/shader/symbol_sdf.fragment.hpp> -#include <mbgl/shader/symbol_vertex.hpp> - -namespace mbgl { - -SymbolSDFShader::SymbolSDFShader(gl::Context& context, Defines defines) - : Shader(shaders::symbol_sdf::name, - shaders::symbol_sdf::vertex, - shaders::symbol_sdf::fragment, - context, defines) { -} - -} // namespace mbgl diff --git a/src/mbgl/shader/symbol_sdf_shader.hpp b/src/mbgl/shader/symbol_sdf_shader.hpp deleted file mode 100644 index 8d3b3df939..0000000000 --- a/src/mbgl/shader/symbol_sdf_shader.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include <mbgl/gl/shader.hpp> -#include <mbgl/gl/attribute.hpp> -#include <mbgl/gl/uniform.hpp> -#include <mbgl/util/color.hpp> - -namespace mbgl { - -class SymbolVertex; - -class SymbolSDFShader : public gl::Shader { -public: - SymbolSDFShader(gl::Context&, Defines defines = None); - - using VertexType = SymbolVertex; - - gl::Attribute<int16_t, 2> a_pos = { "a_pos", *this }; - gl::Attribute<int16_t, 2> a_offset = { "a_offset", *this }; - gl::Attribute<uint16_t, 2> a_texture_pos = { "a_texture_pos", *this }; - gl::Attribute<uint8_t, 4> a_data = { "a_data", *this }; - - gl::UniformMatrix<4> u_matrix = {"u_matrix", *this}; - gl::Uniform<std::array<float, 2>> u_extrude_scale = {"u_extrude_scale", *this}; - gl::Uniform<Color> u_color = {"u_color", *this}; - gl::Uniform<float> u_opacity = {"u_opacity", *this}; - gl::Uniform<std::array<float, 2>> u_texsize = {"u_texsize", *this}; - gl::Uniform<float> u_buffer = {"u_buffer", *this}; - gl::Uniform<float> u_gamma = {"u_gamma", *this}; - gl::Uniform<float> u_zoom = {"u_zoom", *this}; - gl::Uniform<float> u_pitch = {"u_pitch", *this}; - gl::Uniform<float> u_bearing = {"u_bearing", *this}; - gl::Uniform<float> u_aspect_ratio = {"u_aspect_ratio", *this}; - gl::Uniform<int32_t> u_rotate_with_map = {"u_rotate_with_map", *this}; - gl::Uniform<int32_t> u_pitch_with_map = {"u_pitch_with_map", *this}; - gl::Uniform<int32_t> u_texture = {"u_texture", *this}; - gl::Uniform<int32_t> u_fadetexture = {"u_fadetexture", *this}; -}; - -} // namespace mbgl diff --git a/src/mbgl/shader/symbol_vertex.cpp b/src/mbgl/shader/symbol_vertex.cpp deleted file mode 100644 index 4075d749ea..0000000000 --- a/src/mbgl/shader/symbol_vertex.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include <mbgl/shader/symbol_vertex.hpp> -#include <mbgl/gl/shader.hpp> -#include <mbgl/gl/gl.hpp> - -namespace mbgl { - -static_assert(sizeof(SymbolVertex) == 16, "expected SymbolVertex size"); - -} // namespace mbgl diff --git a/src/mbgl/shader/symbol_vertex.hpp b/src/mbgl/shader/symbol_vertex.hpp deleted file mode 100644 index 4eba86f946..0000000000 --- a/src/mbgl/shader/symbol_vertex.hpp +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include <mbgl/gl/attribute.hpp> - -#include <array> -#include <cstdint> -#include <cmath> - -namespace mbgl { - -class SymbolVertex { -public: - SymbolVertex(int16_t x, int16_t y, float ox, float oy, uint16_t tx, uint16_t ty, float minzoom, float maxzoom, float labelminzoom, uint8_t labelangle) - : a_pos { - x, - y - }, - a_offset { - static_cast<int16_t>(::round(ox * 64)), // use 1/64 pixels for placement - static_cast<int16_t>(::round(oy * 64)) - }, - a_texture_pos { - static_cast<uint16_t>(tx / 4), - static_cast<uint16_t>(ty / 4) - }, - a_data { - static_cast<uint8_t>(labelminzoom * 10), // 1/10 zoom levels: z16 == 160 - static_cast<uint8_t>(labelangle), - static_cast<uint8_t>(minzoom * 10), - static_cast<uint8_t>(::fmin(maxzoom, 25) * 10) - } {} - - const int16_t a_pos[2]; - const int16_t a_offset[2]; - const uint16_t a_texture_pos[2]; - const uint8_t a_data[4]; -}; - -namespace gl { - -template <class Shader> -struct AttributeBindings<Shader, SymbolVertex> { - std::array<AttributeBinding, 4> operator()(const Shader& shader) { - return {{ - MBGL_MAKE_ATTRIBUTE_BINDING(SymbolVertex, shader, a_pos), - MBGL_MAKE_ATTRIBUTE_BINDING(SymbolVertex, shader, a_offset), - MBGL_MAKE_ATTRIBUTE_BINDING(SymbolVertex, shader, a_texture_pos), - MBGL_MAKE_ATTRIBUTE_BINDING(SymbolVertex, shader, a_data) - }}; - }; -}; - -} // namespace gl -} // namespace mbgl diff --git a/src/mbgl/sprite/sprite_atlas.cpp b/src/mbgl/sprite/sprite_atlas.cpp index 198b0a6c57..ea055ce5ec 100644 --- a/src/mbgl/sprite/sprite_atlas.cpp +++ b/src/mbgl/sprite/sprite_atlas.cpp @@ -1,10 +1,9 @@ #include <mbgl/sprite/sprite_atlas.hpp> #include <mbgl/sprite/sprite_atlas_observer.hpp> #include <mbgl/sprite/sprite_parser.hpp> -#include <mbgl/gl/gl.hpp> #include <mbgl/gl/context.hpp> -#include <mbgl/platform/log.hpp> -#include <mbgl/platform/platform.hpp> +#include <mbgl/util/logging.hpp> +#include <mbgl/util/platform.hpp> #include <mbgl/util/math.hpp> #include <mbgl/util/std.hpp> #include <mbgl/util/constants.hpp> @@ -28,15 +27,12 @@ struct SpriteAtlas::Loader { std::unique_ptr<AsyncRequest> spriteRequest; }; -SpriteAtlas::SpriteAtlas(dimension width_, dimension height_, float pixelRatio_) - : width(width_), - height(height_), - pixelWidth(std::ceil(width * pixelRatio_)), - pixelHeight(std::ceil(height * pixelRatio_)), +SpriteAtlas::SpriteAtlas(Size size_, float pixelRatio_) + : size(std::move(size_)), pixelRatio(pixelRatio_), observer(&nullObserver), - bin(width_, height_), - dirtyFlag(true) { + bin(size.width, size.height), + dirty(true) { } SpriteAtlas::~SpriteAtlas() = default; @@ -128,7 +124,7 @@ void SpriteAtlas::_setSprite(const std::string& name, auto it = sprites.find(name); if (it != sprites.end()) { // There is already a sprite with that name in our store. - if ((it->second->image.width != sprite->image.width || it->second->image.height != sprite->image.height)) { + if (it->second->image.size != sprite->image.size) { Log::Warning(Event::Sprite, "Can't change sprite dimensions for '%s'", name.c_str()); return; } @@ -162,10 +158,10 @@ std::shared_ptr<const SpriteImage> SpriteAtlas::getSprite(const std::string& nam } } -Rect<SpriteAtlas::dimension> SpriteAtlas::allocateImage(const SpriteImage& spriteImage) { +Rect<uint16_t> SpriteAtlas::allocateImage(const SpriteImage& spriteImage) { - const uint16_t pixel_width = std::ceil(spriteImage.image.width / pixelRatio); - const uint16_t pixel_height = std::ceil(spriteImage.image.height / pixelRatio); + const uint16_t pixel_width = std::ceil(spriteImage.image.size.width / pixelRatio); + const uint16_t pixel_height = std::ceil(spriteImage.image.size.height / pixelRatio); // Increase to next number divisible by 4, but at least 1. // This is so we can scale down the texture coordinates and pack them @@ -175,7 +171,7 @@ Rect<SpriteAtlas::dimension> SpriteAtlas::allocateImage(const SpriteImage& sprit // We have to allocate a new area in the bin, and store an empty image in it. // Add a 1px border around every image. - Rect<dimension> rect = bin.allocate(pack_width, pack_height); + Rect<uint16_t> rect = bin.allocate(pack_width, pack_height); if (rect.w == 0) { return rect; } @@ -197,7 +193,7 @@ optional<SpriteAtlasElement> SpriteAtlas::getImage(const std::string& name, return {}; } - Rect<dimension> rect = allocateImage(*sprite); + Rect<uint16_t> rect = allocateImage(*sprite); if (rect.w == 0) { if (debug::spriteWarnings) { Log::Warning(Event::Sprite, "sprite atlas bitmap overflow"); @@ -230,8 +226,8 @@ optional<SpriteAtlasPosition> SpriteAtlas::getPosition(const std::string& name, return SpriteAtlasPosition { {{ float(spriteImage->getWidth()), spriteImage->getHeight() }}, - {{ float(rect.x + padding) / width, float(rect.y + padding) / height }}, - {{ float(rect.x + padding + w) / width, float(rect.y + padding + h) / height }} + {{ float(rect.x + padding) / size.width, float(rect.y + padding) / size.height }}, + {{ float(rect.x + padding + w) / size.width, float(rect.y + padding + h) / size.height }} }; } @@ -264,28 +260,25 @@ void copyBitmap(const uint32_t *src, const uint32_t srcStride, const uint32_t sr } void SpriteAtlas::copy(const Holder& holder, const SpritePatternMode mode) { - if (!data) { - data = std::make_unique<uint32_t[]>(pixelWidth * pixelHeight); - std::fill(data.get(), data.get() + pixelWidth * pixelHeight, 0); + if (!image.valid()) { + image = PremultipliedImage({ static_cast<uint32_t>(std::ceil(size.width * pixelRatio)), + static_cast<uint32_t>(std::ceil(size.height * pixelRatio)) }); + std::fill(image.data.get(), image.data.get() + image.bytes(), 0); } - const uint32_t *srcData = reinterpret_cast<const uint32_t *>(holder.spriteImage->image.data.get()); + const uint32_t* srcData = + reinterpret_cast<const uint32_t*>(holder.spriteImage->image.data.get()); if (!srcData) return; - uint32_t *const dstData = data.get(); + uint32_t* const dstData = reinterpret_cast<uint32_t*>(image.data.get()); const int padding = 1; - copyBitmap(srcData, uint32_t(holder.spriteImage->image.width), 0, 0, - dstData, pixelWidth, (holder.pos.x + padding) * pixelRatio, (holder.pos.y + padding) * pixelRatio, pixelWidth * pixelHeight, - uint32_t(holder.spriteImage->image.width), uint32_t(holder.spriteImage->image.height), mode); + copyBitmap(srcData, holder.spriteImage->image.size.width, 0, 0, dstData, image.size.width, + (holder.pos.x + padding) * pixelRatio, (holder.pos.y + padding) * pixelRatio, + image.size.width * image.size.height, holder.spriteImage->image.size.width, + holder.spriteImage->image.size.height, mode); - dirtyFlag = true; -} - -void SpriteAtlas::upload(gl::Context& context, gl::TextureUnit unit) { - if (dirtyFlag) { - bind(false, context, unit); - } + dirty = true; } void SpriteAtlas::updateDirty() { @@ -316,77 +309,31 @@ void SpriteAtlas::updateDirty() { dirtySprites.clear(); } -void SpriteAtlas::bind(bool linear, gl::Context& context, gl::TextureUnit unit) { - if (!data) { - return; // Empty atlas +void SpriteAtlas::upload(gl::Context& context, gl::TextureUnit unit) { + if (!texture) { + texture = context.createTexture(image, unit); + } else if (dirty) { + context.updateTexture(*texture, image, unit); } - if (!texture) { - texture = context.createTexture(); - context.activeTexture = unit; - context.texture[unit] = *texture; #if not MBGL_USE_GLES2 - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); +// if (dirty) { +// platform::showColorDebugImage("Sprite Atlas", +// reinterpret_cast<const char*>(image.data.get()), size.width, +// size.height, image.size.width, image.size.height); +// } #endif // MBGL_USE_GLES2 - // 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)); - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); - fullUploadRequired = true; - } else if (context.texture[unit] != *texture) { - context.activeTexture = unit; - context.texture[unit] = *texture; - } - GLuint filter_val = linear ? GL_LINEAR : GL_NEAREST; - if (filter_val != filter) { - context.activeTexture = unit; - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter_val)); - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter_val)); - filter = filter_val; - } - - if (dirtyFlag) { - std::lock_guard<std::recursive_mutex> lock(mtx); - - context.activeTexture = unit; - if (fullUploadRequired) { - MBGL_CHECK_ERROR(glTexImage2D( - GL_TEXTURE_2D, // GLenum target - 0, // GLint level - GL_RGBA, // GLint internalformat - pixelWidth, // GLsizei width - pixelHeight, // GLsizei height - 0, // GLint border - GL_RGBA, // GLenum format - GL_UNSIGNED_BYTE, // GLenum type - data.get() // const GLvoid * data - )); - fullUploadRequired = false; - } else { - MBGL_CHECK_ERROR(glTexSubImage2D( - GL_TEXTURE_2D, // GLenum target - 0, // GLint level - 0, // GLint xoffset - 0, // GLint yoffset - pixelWidth, // GLsizei width - pixelHeight, // GLsizei height - GL_RGBA, // GLenum format - GL_UNSIGNED_BYTE, // GLenum type - data.get() // const GLvoid *pixels - )); - } - - dirtyFlag = false; + dirty = false; +} -#if not MBGL_USE_GLES2 - // platform::showColorDebugImage("Sprite Atlas", reinterpret_cast<const char*>(data.get()), - // pixelWidth, pixelHeight, pixelWidth, pixelHeight); -#endif // MBGL_USE_GLES2 - } +void SpriteAtlas::bind(bool linear, gl::Context& context, gl::TextureUnit unit) { + upload(context, unit); + context.bindTexture(*texture, unit, + linear ? gl::TextureFilter::Linear : gl::TextureFilter::Nearest); } -SpriteAtlas::Holder::Holder(std::shared_ptr<const SpriteImage> spriteImage_, Rect<dimension> pos_) +SpriteAtlas::Holder::Holder(std::shared_ptr<const SpriteImage> spriteImage_, Rect<uint16_t> pos_) : spriteImage(std::move(spriteImage_)), pos(std::move(pos_)) { } diff --git a/src/mbgl/sprite/sprite_atlas.hpp b/src/mbgl/sprite/sprite_atlas.hpp index 3a0aea2dad..c79aec135e 100644 --- a/src/mbgl/sprite/sprite_atlas.hpp +++ b/src/mbgl/sprite/sprite_atlas.hpp @@ -1,7 +1,7 @@ #pragma once #include <mbgl/geometry/binpack.hpp> -#include <mbgl/gl/object.hpp> +#include <mbgl/gl/texture.hpp> #include <mbgl/util/noncopyable.hpp> #include <mbgl/util/optional.hpp> #include <mbgl/sprite/sprite_image.hpp> @@ -26,13 +26,15 @@ class Context; class SpriteImage; class SpritePosition; -struct SpriteAtlasPosition { +class SpriteAtlasPosition { +public: std::array<float, 2> size = {{ 0, 0 }}; std::array<float, 2> tl = {{ 0, 0 }}; std::array<float, 2> br = {{ 0, 0 }}; }; -struct SpriteAtlasElement { +class SpriteAtlasElement { +public: Rect<uint16_t> pos; std::shared_ptr<const SpriteImage> spriteImage; float relativePixelRatio; @@ -45,10 +47,9 @@ enum class SpritePatternMode : bool { class SpriteAtlas : public util::noncopyable { public: - typedef uint16_t dimension; using Sprites = std::map<std::string, std::shared_ptr<const SpriteImage>>; - SpriteAtlas(dimension width, dimension height, float pixelRatio); + SpriteAtlas(Size, float pixelRatio); ~SpriteAtlas(); void load(const std::string& url, FileSource&); @@ -91,21 +92,19 @@ public: // the texture is only bound when the data is out of date (=dirty). void upload(gl::Context&, gl::TextureUnit unit); - dimension getWidth() const { return width; } - dimension getHeight() const { return height; } - dimension getTextureWidth() const { return pixelWidth; } - dimension getTextureHeight() const { return pixelHeight; } + Size getSize() const { return size; } float getPixelRatio() const { return pixelRatio; } // Only for use in tests. - const uint32_t* getData() const { return data.get(); } + const PremultipliedImage& getAtlasImage() const { + return image; + } private: void _setSprite(const std::string&, const std::shared_ptr<const SpriteImage>& = nullptr); void emitSpriteLoadedIfComplete(); - const uint16_t width, height; - const dimension pixelWidth, pixelHeight; + const Size size; const float pixelRatio; struct Loader; @@ -125,26 +124,24 @@ private: Sprites dirtySprites; struct Holder : private util::noncopyable { - Holder(std::shared_ptr<const SpriteImage>, Rect<dimension>); + Holder(std::shared_ptr<const SpriteImage>, Rect<uint16_t>); Holder(Holder&&); std::shared_ptr<const SpriteImage> spriteImage; - const Rect<dimension> pos; + const Rect<uint16_t> pos; }; using Key = std::pair<std::string, SpritePatternMode>; - Rect<SpriteAtlas::dimension> allocateImage(const SpriteImage&); + Rect<uint16_t> allocateImage(const SpriteImage&); void copy(const Holder& holder, SpritePatternMode mode); std::recursive_mutex mtx; - BinPack<dimension> bin; + BinPack<uint16_t> bin; std::map<Key, Holder> images; std::unordered_set<std::string> uninitialized; - std::unique_ptr<uint32_t[]> data; - std::atomic<bool> dirtyFlag; - bool fullUploadRequired = true; - mbgl::optional<gl::UniqueTexture> texture; - uint32_t filter = 0; + PremultipliedImage image; + mbgl::optional<gl::Texture> texture; + std::atomic<bool> dirty; static const int buffer = 1; }; diff --git a/src/mbgl/sprite/sprite_image.cpp b/src/mbgl/sprite/sprite_image.cpp index d7e422ed1d..1579d9d89e 100644 --- a/src/mbgl/sprite/sprite_image.cpp +++ b/src/mbgl/sprite/sprite_image.cpp @@ -13,7 +13,7 @@ SpriteImage::SpriteImage(PremultipliedImage&& image_, pixelRatio(pixelRatio_), sdf(sdf_) { - if (image.size() == 0) { + if (!image.valid()) { throw util::SpriteImageException("Sprite image dimensions may not be zero"); } else if (pixelRatio <= 0) { throw util::SpriteImageException("Sprite pixelRatio may not be <= 0"); diff --git a/src/mbgl/sprite/sprite_parser.cpp b/src/mbgl/sprite/sprite_parser.cpp index 34b1d875b6..9de8515e14 100644 --- a/src/mbgl/sprite/sprite_parser.cpp +++ b/src/mbgl/sprite/sprite_parser.cpp @@ -1,10 +1,11 @@ #include <mbgl/sprite/sprite_parser.hpp> #include <mbgl/sprite/sprite_image.hpp> -#include <mbgl/platform/log.hpp> +#include <mbgl/util/logging.hpp> #include <mbgl/util/image.hpp> #include <mbgl/util/rapidjson.hpp> +#include <mbgl/util/string.hpp> #include <cmath> #include <limits> @@ -13,30 +14,34 @@ namespace mbgl { SpriteImagePtr createSpriteImage(const PremultipliedImage& image, - const uint16_t srcX, - const uint16_t srcY, - const uint16_t width, - const uint16_t height, + const uint32_t srcX, + const uint32_t srcY, + const uint32_t width, + const uint32_t height, const double ratio, const bool sdf) { // Disallow invalid parameter configurations. if (width <= 0 || height <= 0 || width > 1024 || height > 1024 || ratio <= 0 || ratio > 10 || - srcX + width > image.width || srcY + height > image.height) { - Log::Error(Event::Sprite, "Can't create sprite with invalid metrics"); + srcX >= image.size.width || srcY >= image.size.height || + srcX + width > image.size.width || srcY + height > image.size.height) { + Log::Error(Event::Sprite, "Can't create sprite with invalid metrics: %ux%u@%u,%u in %ux%u@%sx sprite", + width, height, srcX, srcY, + image.size.width, image.size.height, + util::toString(ratio).c_str()); return nullptr; } - PremultipliedImage dstImage(width, height); + PremultipliedImage dstImage({ width, height }); auto srcData = reinterpret_cast<const uint32_t*>(image.data.get()); auto dstData = reinterpret_cast<uint32_t*>(dstImage.data.get()); // Copy from the source image into our individual sprite image - for (uint16_t y = 0; y < height; ++y) { + for (uint32_t y = 0; y < height; ++y) { const auto dstRow = y * width; - const auto srcRow = (y + srcY) * image.width + srcX; - for (uint16_t x = 0; x < width; ++x) { + const auto srcRow = (y + srcY) * image.size.width + srcX; + for (uint32_t x = 0; x < width; ++x) { dstData[dstRow + x] = srcData[srcRow + x]; } } diff --git a/src/mbgl/sprite/sprite_parser.hpp b/src/mbgl/sprite/sprite_parser.hpp index 6a564ce330..4a63d4858a 100644 --- a/src/mbgl/sprite/sprite_parser.hpp +++ b/src/mbgl/sprite/sprite_parser.hpp @@ -17,10 +17,10 @@ using SpriteImagePtr = std::shared_ptr<const SpriteImage>; // Extracts an individual image from a spritesheet from the given location. SpriteImagePtr createSpriteImage(const PremultipliedImage&, - uint16_t srcX, - uint16_t srcY, - uint16_t srcWidth, - uint16_t srcHeight, + uint32_t srcX, + uint32_t srcY, + uint32_t srcWidth, + uint32_t srcHeight, double ratio, bool sdf); diff --git a/src/mbgl/style/class_dictionary.hpp b/src/mbgl/style/class_dictionary.hpp index e609fb5303..37eb488240 100644 --- a/src/mbgl/style/class_dictionary.hpp +++ b/src/mbgl/style/class_dictionary.hpp @@ -9,7 +9,6 @@ namespace mbgl { namespace style { enum class ClassID : uint32_t { - Fallback = 0, // These values are from the fallback properties Default = 1, // These values are from the default style for a layer Named = 2 // These values (and all subsequent IDs) are from a named style from the layer }; diff --git a/src/mbgl/style/cross_faded_property_evaluator.cpp b/src/mbgl/style/cross_faded_property_evaluator.cpp new file mode 100644 index 0000000000..4de939576e --- /dev/null +++ b/src/mbgl/style/cross_faded_property_evaluator.cpp @@ -0,0 +1,53 @@ +#include <mbgl/style/cross_faded_property_evaluator.hpp> +#include <mbgl/util/chrono.hpp> + +#include <cmath> + +namespace mbgl { +namespace style { + +template <typename T> +Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const Undefined&) const { + return calculate(defaultValue, defaultValue, defaultValue); +} + +template <typename T> +Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const T& constant) const { + return calculate(constant, constant, constant); +} + +template <typename T> +T getBiggestStopLessThan(const Function<T>& function, float z) { + const auto& stops = function.getStops(); + for (uint32_t i = 0; i < stops.size(); i++) { + if (stops[i].first > z) { + return stops[i == 0 ? i : i - 1].second; + } + } + return stops.at(stops.size() - 1).second; +} + +template <typename T> +Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const Function<T>& function) const { + return calculate(getBiggestStopLessThan(function, parameters.z - 1.0f), + getBiggestStopLessThan(function, parameters.z), + getBiggestStopLessThan(function, parameters.z + 1.0f)); +} + +template <typename T> +Faded<T> CrossFadedPropertyEvaluator<T>::calculate(const T& min, const T& mid, const T& max) const { + const float z = parameters.z; + const float fraction = z - std::floor(z); + const std::chrono::duration<float> d = parameters.defaultFadeDuration; + const float t = std::min((parameters.now - parameters.zoomHistory.lastIntegerZoomTime) / d, 1.0f); + + return z > parameters.zoomHistory.lastIntegerZoom + ? Faded<T> { min, mid, 2.0f, 1.0f, fraction + (1.0f - fraction) * t } + : Faded<T> { max, mid, 0.5f, 1.0f, 1 - (1 - t) * fraction }; +} + +template class CrossFadedPropertyEvaluator<std::string>; +template class CrossFadedPropertyEvaluator<std::vector<float>>; + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/cross_faded_property_evaluator.hpp b/src/mbgl/style/cross_faded_property_evaluator.hpp new file mode 100644 index 0000000000..70c8c0c978 --- /dev/null +++ b/src/mbgl/style/cross_faded_property_evaluator.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include <mbgl/style/property_value.hpp> +#include <mbgl/style/property_evaluation_parameters.hpp> +#include <mbgl/util/interpolate.hpp> + +namespace mbgl { +namespace style { + +template <typename T> +class Faded { +public: + T from; + T to; + float fromScale; + float toScale; + float t; +}; + +template <typename T> +class CrossFadedPropertyEvaluator { +public: + using ResultType = Faded<T>; + + CrossFadedPropertyEvaluator(const PropertyEvaluationParameters& parameters_, T defaultValue_) + : parameters(parameters_), + defaultValue(std::move(defaultValue_)) {} + + Faded<T> operator()(const Undefined&) const; + Faded<T> operator()(const T& constant) const; + Faded<T> operator()(const Function<T>&) const; + +private: + Faded<T> calculate(const T& min, const T& mid, const T& max) const; + + const PropertyEvaluationParameters& parameters; + T defaultValue; +}; + +} // namespace style + +namespace util { +template <typename T> +struct Interpolator<style::Faded<T>> + : Uninterpolated {}; +} // namespace util + +} // namespace mbgl diff --git a/src/mbgl/style/function.cpp b/src/mbgl/style/function.cpp new file mode 100644 index 0000000000..02750c7d2e --- /dev/null +++ b/src/mbgl/style/function.cpp @@ -0,0 +1,81 @@ +#include <mbgl/style/function.hpp> +#include <mbgl/style/types.hpp> +#include <mbgl/util/color.hpp> +#include <mbgl/util/interpolate.hpp> + +#include <cmath> + +namespace mbgl { +namespace style { + +template <typename T> +T Function<T>::evaluate(float z) const { + bool smaller = false; + float smaller_z = 0.0f; + T smaller_val = T(); + bool larger = false; + float larger_z = 0.0f; + T larger_val = T(); + + for (uint32_t i = 0; i < stops.size(); i++) { + float stop_z = stops[i].first; + T stop_val = stops[i].second; + if (stop_z <= z && (!smaller || smaller_z < stop_z)) { + smaller = true; + smaller_z = stop_z; + smaller_val = stop_val; + } + if (stop_z >= z && (!larger || larger_z > stop_z)) { + larger = true; + larger_z = stop_z; + larger_val = stop_val; + } + } + + if (smaller && larger) { + if (larger_z == smaller_z || larger_val == smaller_val) { + return smaller_val; + } + const float zoomDiff = larger_z - smaller_z; + const float zoomProgress = z - smaller_z; + if (base == 1.0f) { + const float t = zoomProgress / zoomDiff; + return util::interpolate(smaller_val, larger_val, t); + } else { + const float t = (std::pow(base, zoomProgress) - 1) / (std::pow(base, zoomDiff) - 1); + return util::interpolate(smaller_val, larger_val, t); + } + } else if (larger) { + return larger_val; + } else if (smaller) { + return smaller_val; + } else { + // No stop defined. + assert(false); + return T(); + } +} + +template class Function<bool>; +template class Function<float>; +template class Function<Color>; +template class Function<std::vector<float>>; +template class Function<std::vector<std::string>>; +template class Function<std::array<float, 2>>; +template class Function<std::array<float, 4>>; + +template class Function<std::string>; +template class Function<TranslateAnchorType>; +template class Function<RotateAnchorType>; +template class Function<CirclePitchScaleType>; +template class Function<LineCapType>; +template class Function<LineJoinType>; +template class Function<SymbolPlacementType>; +template class Function<TextAnchorType>; +template class Function<TextJustifyType>; +template class Function<TextTransformType>; +template class Function<AlignmentType>; +template class Function<IconTextFitType>; + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/layer_impl.hpp b/src/mbgl/style/layer_impl.hpp index 4bf2956a6d..38ac32e1de 100644 --- a/src/mbgl/style/layer_impl.hpp +++ b/src/mbgl/style/layer_impl.hpp @@ -19,7 +19,7 @@ class Bucket; namespace style { class CascadeParameters; -class CalculationParameters; +class PropertyEvaluationParameters; class BucketParameters; /** @@ -57,7 +57,7 @@ public: // Fully evaluate cascaded paint properties based on a zoom level. // Returns true if any paint properties have active transitions. - virtual bool recalculate(const CalculationParameters&) = 0; + virtual bool evaluate(const PropertyEvaluationParameters&) = 0; virtual std::unique_ptr<Bucket> createBucket(BucketParameters&) const = 0; diff --git a/src/mbgl/style/layers/background_layer.cpp b/src/mbgl/style/layers/background_layer.cpp index 5e5faf37e6..a54115d1a7 100644 --- a/src/mbgl/style/layers/background_layer.cpp +++ b/src/mbgl/style/layers/background_layer.cpp @@ -42,13 +42,13 @@ PropertyValue<Color> BackgroundLayer::getDefaultBackgroundColor() { } PropertyValue<Color> BackgroundLayer::getBackgroundColor(const optional<std::string>& klass) const { - return impl->paint.backgroundColor.get(klass); + return impl->paint.get<BackgroundColor>(klass); } void BackgroundLayer::setBackgroundColor(PropertyValue<Color> value, const optional<std::string>& klass) { if (value == getBackgroundColor(klass)) return; - impl->paint.backgroundColor.set(value, klass); + impl->paint.set<BackgroundColor>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -57,13 +57,13 @@ PropertyValue<std::string> BackgroundLayer::getDefaultBackgroundPattern() { } PropertyValue<std::string> BackgroundLayer::getBackgroundPattern(const optional<std::string>& klass) const { - return impl->paint.backgroundPattern.get(klass); + return impl->paint.get<BackgroundPattern>(klass); } void BackgroundLayer::setBackgroundPattern(PropertyValue<std::string> value, const optional<std::string>& klass) { if (value == getBackgroundPattern(klass)) return; - impl->paint.backgroundPattern.set(value, klass); + impl->paint.set<BackgroundPattern>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -72,13 +72,13 @@ PropertyValue<float> BackgroundLayer::getDefaultBackgroundOpacity() { } PropertyValue<float> BackgroundLayer::getBackgroundOpacity(const optional<std::string>& klass) const { - return impl->paint.backgroundOpacity.get(klass); + return impl->paint.get<BackgroundOpacity>(klass); } void BackgroundLayer::setBackgroundOpacity(PropertyValue<float> value, const optional<std::string>& klass) { if (value == getBackgroundOpacity(klass)) return; - impl->paint.backgroundOpacity.set(value, klass); + impl->paint.set<BackgroundOpacity>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } diff --git a/src/mbgl/style/layers/background_layer_impl.cpp b/src/mbgl/style/layers/background_layer_impl.cpp index ea389b828e..9a7db9416e 100644 --- a/src/mbgl/style/layers/background_layer_impl.cpp +++ b/src/mbgl/style/layers/background_layer_impl.cpp @@ -8,12 +8,12 @@ void BackgroundLayer::Impl::cascade(const CascadeParameters& parameters) { paint.cascade(parameters); } -bool BackgroundLayer::Impl::recalculate(const CalculationParameters& parameters) { - bool hasTransitions = paint.recalculate(parameters); +bool BackgroundLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) { + paint.evaluate(parameters); - passes = paint.backgroundOpacity > 0 ? RenderPass::Translucent : RenderPass::None; + passes = paint.evaluated.get<BackgroundOpacity>() > 0 ? RenderPass::Translucent : RenderPass::None; - return hasTransitions; + return paint.hasTransition(); } std::unique_ptr<Bucket> BackgroundLayer::Impl::createBucket(BucketParameters&) const { diff --git a/src/mbgl/style/layers/background_layer_impl.hpp b/src/mbgl/style/layers/background_layer_impl.hpp index abbb740f42..6ede1b7d97 100644 --- a/src/mbgl/style/layers/background_layer_impl.hpp +++ b/src/mbgl/style/layers/background_layer_impl.hpp @@ -13,7 +13,7 @@ public: std::unique_ptr<Layer> cloneRef(const std::string& id) const override; void cascade(const CascadeParameters&) override; - bool recalculate(const CalculationParameters&) override; + bool evaluate(const PropertyEvaluationParameters&) override; std::unique_ptr<Bucket> createBucket(BucketParameters&) const override; diff --git a/src/mbgl/style/layers/background_layer_properties.cpp b/src/mbgl/style/layers/background_layer_properties.cpp index 558093a255..ba3e638977 100644 --- a/src/mbgl/style/layers/background_layer_properties.cpp +++ b/src/mbgl/style/layers/background_layer_properties.cpp @@ -5,21 +5,5 @@ namespace mbgl { namespace style { -void BackgroundPaintProperties::cascade(const CascadeParameters& parameters) { - backgroundColor.cascade(parameters); - backgroundPattern.cascade(parameters); - backgroundOpacity.cascade(parameters); -} - -bool BackgroundPaintProperties::recalculate(const CalculationParameters& parameters) { - bool hasTransitions = false; - - hasTransitions |= backgroundColor.calculate(parameters); - hasTransitions |= backgroundPattern.calculate(parameters); - hasTransitions |= backgroundOpacity.calculate(parameters); - - return hasTransitions; -} - } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layers/background_layer_properties.hpp b/src/mbgl/style/layers/background_layer_properties.hpp index 78a35a4f0c..792bf3de94 100644 --- a/src/mbgl/style/layers/background_layer_properties.hpp +++ b/src/mbgl/style/layers/background_layer_properties.hpp @@ -9,18 +9,23 @@ namespace mbgl { namespace style { -class CascadeParameters; -class CalculationParameters; +struct BackgroundColor : PaintProperty<Color> { + static Color defaultValue() { return Color::black(); } +}; -class BackgroundPaintProperties { -public: - void cascade(const CascadeParameters&); - bool recalculate(const CalculationParameters&); +struct BackgroundPattern : CrossFadedPaintProperty<std::string> { + static std::string defaultValue() { return ""; } +}; - PaintProperty<Color> backgroundColor { Color::black() }; - PaintProperty<std::string, CrossFadedPropertyEvaluator> backgroundPattern { "" }; - PaintProperty<float> backgroundOpacity { 1 }; +struct BackgroundOpacity : PaintProperty<float> { + static float defaultValue() { return 1; } }; +class BackgroundPaintProperties : public PaintProperties< + BackgroundColor, + BackgroundPattern, + BackgroundOpacity +> {}; + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp index a2b8d316d6..e3a506e895 100644 --- a/src/mbgl/style/layers/circle_layer.cpp +++ b/src/mbgl/style/layers/circle_layer.cpp @@ -67,13 +67,13 @@ PropertyValue<float> CircleLayer::getDefaultCircleRadius() { } PropertyValue<float> CircleLayer::getCircleRadius(const optional<std::string>& klass) const { - return impl->paint.circleRadius.get(klass); + return impl->paint.get<CircleRadius>(klass); } void CircleLayer::setCircleRadius(PropertyValue<float> value, const optional<std::string>& klass) { if (value == getCircleRadius(klass)) return; - impl->paint.circleRadius.set(value, klass); + impl->paint.set<CircleRadius>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -82,13 +82,13 @@ PropertyValue<Color> CircleLayer::getDefaultCircleColor() { } PropertyValue<Color> CircleLayer::getCircleColor(const optional<std::string>& klass) const { - return impl->paint.circleColor.get(klass); + return impl->paint.get<CircleColor>(klass); } void CircleLayer::setCircleColor(PropertyValue<Color> value, const optional<std::string>& klass) { if (value == getCircleColor(klass)) return; - impl->paint.circleColor.set(value, klass); + impl->paint.set<CircleColor>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -97,13 +97,13 @@ PropertyValue<float> CircleLayer::getDefaultCircleBlur() { } PropertyValue<float> CircleLayer::getCircleBlur(const optional<std::string>& klass) const { - return impl->paint.circleBlur.get(klass); + return impl->paint.get<CircleBlur>(klass); } void CircleLayer::setCircleBlur(PropertyValue<float> value, const optional<std::string>& klass) { if (value == getCircleBlur(klass)) return; - impl->paint.circleBlur.set(value, klass); + impl->paint.set<CircleBlur>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -112,13 +112,13 @@ PropertyValue<float> CircleLayer::getDefaultCircleOpacity() { } PropertyValue<float> CircleLayer::getCircleOpacity(const optional<std::string>& klass) const { - return impl->paint.circleOpacity.get(klass); + return impl->paint.get<CircleOpacity>(klass); } void CircleLayer::setCircleOpacity(PropertyValue<float> value, const optional<std::string>& klass) { if (value == getCircleOpacity(klass)) return; - impl->paint.circleOpacity.set(value, klass); + impl->paint.set<CircleOpacity>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -127,13 +127,13 @@ PropertyValue<std::array<float, 2>> CircleLayer::getDefaultCircleTranslate() { } PropertyValue<std::array<float, 2>> CircleLayer::getCircleTranslate(const optional<std::string>& klass) const { - return impl->paint.circleTranslate.get(klass); + return impl->paint.get<CircleTranslate>(klass); } void CircleLayer::setCircleTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) { if (value == getCircleTranslate(klass)) return; - impl->paint.circleTranslate.set(value, klass); + impl->paint.set<CircleTranslate>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -142,13 +142,13 @@ PropertyValue<TranslateAnchorType> CircleLayer::getDefaultCircleTranslateAnchor( } PropertyValue<TranslateAnchorType> CircleLayer::getCircleTranslateAnchor(const optional<std::string>& klass) const { - return impl->paint.circleTranslateAnchor.get(klass); + return impl->paint.get<CircleTranslateAnchor>(klass); } void CircleLayer::setCircleTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) { if (value == getCircleTranslateAnchor(klass)) return; - impl->paint.circleTranslateAnchor.set(value, klass); + impl->paint.set<CircleTranslateAnchor>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -157,13 +157,58 @@ PropertyValue<CirclePitchScaleType> CircleLayer::getDefaultCirclePitchScale() { } PropertyValue<CirclePitchScaleType> CircleLayer::getCirclePitchScale(const optional<std::string>& klass) const { - return impl->paint.circlePitchScale.get(klass); + return impl->paint.get<CirclePitchScale>(klass); } void CircleLayer::setCirclePitchScale(PropertyValue<CirclePitchScaleType> value, const optional<std::string>& klass) { if (value == getCirclePitchScale(klass)) return; - impl->paint.circlePitchScale.set(value, klass); + impl->paint.set<CirclePitchScale>(value, klass); + impl->observer->onLayerPaintPropertyChanged(*this); +} + +PropertyValue<float> CircleLayer::getDefaultCircleStrokeWidth() { + return { 0 }; +} + +PropertyValue<float> CircleLayer::getCircleStrokeWidth(const optional<std::string>& klass) const { + return impl->paint.get<CircleStrokeWidth>(klass); +} + +void CircleLayer::setCircleStrokeWidth(PropertyValue<float> value, const optional<std::string>& klass) { + if (value == getCircleStrokeWidth(klass)) + return; + impl->paint.set<CircleStrokeWidth>(value, klass); + impl->observer->onLayerPaintPropertyChanged(*this); +} + +PropertyValue<Color> CircleLayer::getDefaultCircleStrokeColor() { + return { Color::black() }; +} + +PropertyValue<Color> CircleLayer::getCircleStrokeColor(const optional<std::string>& klass) const { + return impl->paint.get<CircleStrokeColor>(klass); +} + +void CircleLayer::setCircleStrokeColor(PropertyValue<Color> value, const optional<std::string>& klass) { + if (value == getCircleStrokeColor(klass)) + return; + impl->paint.set<CircleStrokeColor>(value, klass); + impl->observer->onLayerPaintPropertyChanged(*this); +} + +PropertyValue<float> CircleLayer::getDefaultCircleStrokeOpacity() { + return { 1 }; +} + +PropertyValue<float> CircleLayer::getCircleStrokeOpacity(const optional<std::string>& klass) const { + return impl->paint.get<CircleStrokeOpacity>(klass); +} + +void CircleLayer::setCircleStrokeOpacity(PropertyValue<float> value, const optional<std::string>& klass) { + if (value == getCircleStrokeOpacity(klass)) + return; + impl->paint.set<CircleStrokeOpacity>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } diff --git a/src/mbgl/style/layers/circle_layer_impl.cpp b/src/mbgl/style/layers/circle_layer_impl.cpp index 33699b6665..6599126702 100644 --- a/src/mbgl/style/layers/circle_layer_impl.cpp +++ b/src/mbgl/style/layers/circle_layer_impl.cpp @@ -12,13 +12,13 @@ void CircleLayer::Impl::cascade(const CascadeParameters& parameters) { paint.cascade(parameters); } -bool CircleLayer::Impl::recalculate(const CalculationParameters& parameters) { - bool hasTransitions = paint.recalculate(parameters); +bool CircleLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) { + paint.evaluate(parameters); - passes = (paint.circleRadius > 0 && paint.circleColor.value.a > 0 && paint.circleOpacity > 0) + passes = (paint.evaluated.get<CircleRadius>() > 0 && paint.evaluated.get<CircleColor>().a > 0 && paint.evaluated.get<CircleOpacity>() > 0) ? RenderPass::Translucent : RenderPass::None; - return hasTransitions; + return paint.hasTransition(); } std::unique_ptr<Bucket> CircleLayer::Impl::createBucket(BucketParameters& parameters) const { @@ -35,8 +35,8 @@ std::unique_ptr<Bucket> CircleLayer::Impl::createBucket(BucketParameters& parame } float CircleLayer::Impl::getQueryRadius() const { - const std::array<float, 2>& translate = paint.circleTranslate; - return paint.circleRadius + util::length(translate[0], translate[1]); + const std::array<float, 2>& translate = paint.evaluated.get<CircleTranslate>(); + return paint.evaluated.get<CircleRadius>() + util::length(translate[0], translate[1]); } bool CircleLayer::Impl::queryIntersectsGeometry( @@ -46,9 +46,9 @@ bool CircleLayer::Impl::queryIntersectsGeometry( const float pixelsToTileUnits) const { auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry( - queryGeometry, paint.circleTranslate, paint.circleTranslateAnchor, bearing, pixelsToTileUnits); + queryGeometry, paint.evaluated.get<CircleTranslate>(), paint.evaluated.get<CircleTranslateAnchor>(), bearing, pixelsToTileUnits); - auto circleRadius = paint.circleRadius * pixelsToTileUnits; + auto circleRadius = paint.evaluated.get<CircleRadius>() * pixelsToTileUnits; return util::polygonIntersectsBufferedMultiPoint( translatedQueryGeometry.value_or(queryGeometry), geometry, circleRadius); diff --git a/src/mbgl/style/layers/circle_layer_impl.hpp b/src/mbgl/style/layers/circle_layer_impl.hpp index 14baaf84e4..df3b34cc1a 100644 --- a/src/mbgl/style/layers/circle_layer_impl.hpp +++ b/src/mbgl/style/layers/circle_layer_impl.hpp @@ -13,7 +13,7 @@ public: std::unique_ptr<Layer> cloneRef(const std::string& id) const override; void cascade(const CascadeParameters&) override; - bool recalculate(const CalculationParameters&) override; + bool evaluate(const PropertyEvaluationParameters&) override; std::unique_ptr<Bucket> createBucket(BucketParameters&) const override; diff --git a/src/mbgl/style/layers/circle_layer_properties.cpp b/src/mbgl/style/layers/circle_layer_properties.cpp index 7243cf87f4..af727fa36f 100644 --- a/src/mbgl/style/layers/circle_layer_properties.cpp +++ b/src/mbgl/style/layers/circle_layer_properties.cpp @@ -5,29 +5,5 @@ namespace mbgl { namespace style { -void CirclePaintProperties::cascade(const CascadeParameters& parameters) { - circleRadius.cascade(parameters); - circleColor.cascade(parameters); - circleBlur.cascade(parameters); - circleOpacity.cascade(parameters); - circleTranslate.cascade(parameters); - circleTranslateAnchor.cascade(parameters); - circlePitchScale.cascade(parameters); -} - -bool CirclePaintProperties::recalculate(const CalculationParameters& parameters) { - bool hasTransitions = false; - - hasTransitions |= circleRadius.calculate(parameters); - hasTransitions |= circleColor.calculate(parameters); - hasTransitions |= circleBlur.calculate(parameters); - hasTransitions |= circleOpacity.calculate(parameters); - hasTransitions |= circleTranslate.calculate(parameters); - hasTransitions |= circleTranslateAnchor.calculate(parameters); - hasTransitions |= circlePitchScale.calculate(parameters); - - return hasTransitions; -} - } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layers/circle_layer_properties.hpp b/src/mbgl/style/layers/circle_layer_properties.hpp index 0166bc8be4..ea36b31949 100644 --- a/src/mbgl/style/layers/circle_layer_properties.hpp +++ b/src/mbgl/style/layers/circle_layer_properties.hpp @@ -9,22 +9,58 @@ namespace mbgl { namespace style { -class CascadeParameters; -class CalculationParameters; - -class CirclePaintProperties { -public: - void cascade(const CascadeParameters&); - bool recalculate(const CalculationParameters&); - - PaintProperty<float> circleRadius { 5 }; - PaintProperty<Color> circleColor { Color::black() }; - PaintProperty<float> circleBlur { 0 }; - PaintProperty<float> circleOpacity { 1 }; - PaintProperty<std::array<float, 2>> circleTranslate { {{ 0, 0 }} }; - PaintProperty<TranslateAnchorType> circleTranslateAnchor { TranslateAnchorType::Map }; - PaintProperty<CirclePitchScaleType> circlePitchScale { CirclePitchScaleType::Map }; +struct CircleRadius : PaintProperty<float> { + static float defaultValue() { return 5; } }; +struct CircleColor : PaintProperty<Color> { + static Color defaultValue() { return Color::black(); } +}; + +struct CircleBlur : PaintProperty<float> { + static float defaultValue() { return 0; } +}; + +struct CircleOpacity : PaintProperty<float> { + static float defaultValue() { return 1; } +}; + +struct CircleTranslate : PaintProperty<std::array<float, 2>> { + static std::array<float, 2> defaultValue() { return {{ 0, 0 }}; } +}; + +struct CircleTranslateAnchor : PaintProperty<TranslateAnchorType> { + static TranslateAnchorType defaultValue() { return TranslateAnchorType::Map; } +}; + +struct CirclePitchScale : PaintProperty<CirclePitchScaleType> { + static CirclePitchScaleType defaultValue() { return CirclePitchScaleType::Map; } +}; + +struct CircleStrokeWidth : PaintProperty<float> { + static float defaultValue() { return 0; } +}; + +struct CircleStrokeColor : PaintProperty<Color> { + static Color defaultValue() { return Color::black(); } +}; + +struct CircleStrokeOpacity : PaintProperty<float> { + static float defaultValue() { return 1; } +}; + +class CirclePaintProperties : public PaintProperties< + CircleRadius, + CircleColor, + CircleBlur, + CircleOpacity, + CircleTranslate, + CircleTranslateAnchor, + CirclePitchScale, + CircleStrokeWidth, + CircleStrokeColor, + CircleStrokeOpacity +> {}; + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layers/custom_layer_impl.cpp b/src/mbgl/style/layers/custom_layer_impl.cpp index 8896d04ca1..50dcc0dda9 100644 --- a/src/mbgl/style/layers/custom_layer_impl.cpp +++ b/src/mbgl/style/layers/custom_layer_impl.cpp @@ -50,8 +50,8 @@ void CustomLayer::Impl::render(const TransformState& state) const { CustomLayerRenderParameters parameters; - parameters.width = state.getWidth(); - parameters.height = state.getHeight(); + parameters.width = state.getSize().width; + parameters.height = state.getSize().height; parameters.latitude = state.getLatLng().latitude; parameters.longitude = state.getLatLng().longitude; parameters.zoom = state.getZoom(); @@ -62,7 +62,7 @@ void CustomLayer::Impl::render(const TransformState& state) const { renderFn(context, parameters); } -bool CustomLayer::Impl::recalculate(const CalculationParameters&) { +bool CustomLayer::Impl::evaluate(const PropertyEvaluationParameters&) { passes = RenderPass::Translucent; return false; } diff --git a/src/mbgl/style/layers/custom_layer_impl.hpp b/src/mbgl/style/layers/custom_layer_impl.hpp index b5b626ca5e..56e3f3146c 100644 --- a/src/mbgl/style/layers/custom_layer_impl.hpp +++ b/src/mbgl/style/layers/custom_layer_impl.hpp @@ -29,7 +29,7 @@ private: std::unique_ptr<Layer> cloneRef(const std::string& id) const override; void cascade(const CascadeParameters&) final {} - bool recalculate(const CalculationParameters&) final; + bool evaluate(const PropertyEvaluationParameters&) final; std::unique_ptr<Bucket> createBucket(BucketParameters&) const final; diff --git a/src/mbgl/style/layers/fill_extrusion_layer.cpp b/src/mbgl/style/layers/fill_extrusion_layer.cpp new file mode 100644 index 0000000000..64efb1dd6a --- /dev/null +++ b/src/mbgl/style/layers/fill_extrusion_layer.cpp @@ -0,0 +1,171 @@ +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. + +#include <mbgl/style/layers/fill_extrusion_layer.hpp> +#include <mbgl/style/layers/fill_extrusion_layer_impl.hpp> + +namespace mbgl { +namespace style { + +FillExtrusionLayer::FillExtrusionLayer(const std::string& layerID, const std::string& sourceID) + : Layer(Type::FillExtrusion, std::make_unique<Impl>()) + , impl(static_cast<Impl*>(baseImpl.get())) { + impl->id = layerID; + impl->source = sourceID; +} + +FillExtrusionLayer::FillExtrusionLayer(const Impl& other) + : Layer(Type::FillExtrusion, std::make_unique<Impl>(other)) + , impl(static_cast<Impl*>(baseImpl.get())) { +} + +FillExtrusionLayer::~FillExtrusionLayer() = default; + +std::unique_ptr<Layer> FillExtrusionLayer::Impl::clone() const { + return std::make_unique<FillExtrusionLayer>(*this); +} + +std::unique_ptr<Layer> FillExtrusionLayer::Impl::cloneRef(const std::string& id_) const { + auto result = std::make_unique<FillExtrusionLayer>(*this); + result->impl->id = id_; + result->impl->ref = this->id; + result->impl->paint = FillExtrusionPaintProperties(); + return std::move(result); +} + +// Source + +const std::string& FillExtrusionLayer::getSourceID() const { + return impl->source; +} + +void FillExtrusionLayer::setSourceLayer(const std::string& sourceLayer) { + impl->sourceLayer = sourceLayer; +} + +const std::string& FillExtrusionLayer::getSourceLayer() const { + return impl->sourceLayer; +} + +// Filter + +void FillExtrusionLayer::setFilter(const Filter& filter) { + impl->filter = filter; + impl->observer->onLayerFilterChanged(*this); +} + +const Filter& FillExtrusionLayer::getFilter() const { + return impl->filter; +} + +// Layout properties + + +// Paint properties + +PropertyValue<float> FillExtrusionLayer::getDefaultFillExtrusionOpacity() { + return { 1 }; +} + +PropertyValue<float> FillExtrusionLayer::getFillExtrusionOpacity(const optional<std::string>& klass) const { + return impl->paint.get<FillExtrusionOpacity>(klass); +} + +void FillExtrusionLayer::setFillExtrusionOpacity(PropertyValue<float> value, const optional<std::string>& klass) { + if (value == getFillExtrusionOpacity(klass)) + return; + impl->paint.set<FillExtrusionOpacity>(value, klass); + impl->observer->onLayerPaintPropertyChanged(*this); +} + +PropertyValue<Color> FillExtrusionLayer::getDefaultFillExtrusionColor() { + return { Color::black() }; +} + +PropertyValue<Color> FillExtrusionLayer::getFillExtrusionColor(const optional<std::string>& klass) const { + return impl->paint.get<FillExtrusionColor>(klass); +} + +void FillExtrusionLayer::setFillExtrusionColor(PropertyValue<Color> value, const optional<std::string>& klass) { + if (value == getFillExtrusionColor(klass)) + return; + impl->paint.set<FillExtrusionColor>(value, klass); + impl->observer->onLayerPaintPropertyChanged(*this); +} + +PropertyValue<std::array<float, 2>> FillExtrusionLayer::getDefaultFillExtrusionTranslate() { + return { {{ 0, 0 }} }; +} + +PropertyValue<std::array<float, 2>> FillExtrusionLayer::getFillExtrusionTranslate(const optional<std::string>& klass) const { + return impl->paint.get<FillExtrusionTranslate>(klass); +} + +void FillExtrusionLayer::setFillExtrusionTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) { + if (value == getFillExtrusionTranslate(klass)) + return; + impl->paint.set<FillExtrusionTranslate>(value, klass); + impl->observer->onLayerPaintPropertyChanged(*this); +} + +PropertyValue<TranslateAnchorType> FillExtrusionLayer::getDefaultFillExtrusionTranslateAnchor() { + return { TranslateAnchorType::Map }; +} + +PropertyValue<TranslateAnchorType> FillExtrusionLayer::getFillExtrusionTranslateAnchor(const optional<std::string>& klass) const { + return impl->paint.get<FillExtrusionTranslateAnchor>(klass); +} + +void FillExtrusionLayer::setFillExtrusionTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) { + if (value == getFillExtrusionTranslateAnchor(klass)) + return; + impl->paint.set<FillExtrusionTranslateAnchor>(value, klass); + impl->observer->onLayerPaintPropertyChanged(*this); +} + +PropertyValue<std::string> FillExtrusionLayer::getDefaultFillExtrusionPattern() { + return { "" }; +} + +PropertyValue<std::string> FillExtrusionLayer::getFillExtrusionPattern(const optional<std::string>& klass) const { + return impl->paint.get<FillExtrusionPattern>(klass); +} + +void FillExtrusionLayer::setFillExtrusionPattern(PropertyValue<std::string> value, const optional<std::string>& klass) { + if (value == getFillExtrusionPattern(klass)) + return; + impl->paint.set<FillExtrusionPattern>(value, klass); + impl->observer->onLayerPaintPropertyChanged(*this); +} + +PropertyValue<float> FillExtrusionLayer::getDefaultFillExtrusionHeight() { + return { 0 }; +} + +PropertyValue<float> FillExtrusionLayer::getFillExtrusionHeight(const optional<std::string>& klass) const { + return impl->paint.get<FillExtrusionHeight>(klass); +} + +void FillExtrusionLayer::setFillExtrusionHeight(PropertyValue<float> value, const optional<std::string>& klass) { + if (value == getFillExtrusionHeight(klass)) + return; + impl->paint.set<FillExtrusionHeight>(value, klass); + impl->observer->onLayerPaintPropertyChanged(*this); +} + +PropertyValue<float> FillExtrusionLayer::getDefaultFillExtrusionBase() { + return { 0 }; +} + +PropertyValue<float> FillExtrusionLayer::getFillExtrusionBase(const optional<std::string>& klass) const { + return impl->paint.get<FillExtrusionBase>(klass); +} + +void FillExtrusionLayer::setFillExtrusionBase(PropertyValue<float> value, const optional<std::string>& klass) { + if (value == getFillExtrusionBase(klass)) + return; + impl->paint.set<FillExtrusionBase>(value, klass); + impl->observer->onLayerPaintPropertyChanged(*this); +} + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp b/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp new file mode 100644 index 0000000000..239f7754d0 --- /dev/null +++ b/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp @@ -0,0 +1,19 @@ +#include <mbgl/style/layers/fill_extrusion_layer_impl.hpp> +#include <mbgl/renderer/bucket.hpp> + +namespace mbgl { +namespace style { + +void FillExtrusionLayer::Impl::cascade(const CascadeParameters&) { +} + +bool FillExtrusionLayer::Impl::evaluate(const PropertyEvaluationParameters&) { + return false; +} + +std::unique_ptr<Bucket> FillExtrusionLayer::Impl::createBucket(BucketParameters&) const { + return nullptr; +} + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp b/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp new file mode 100644 index 0000000000..79ae02dd5b --- /dev/null +++ b/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include <mbgl/style/layer_impl.hpp> +#include <mbgl/style/layers/fill_extrusion_layer.hpp> +#include <mbgl/style/layers/fill_extrusion_layer_properties.hpp> + +namespace mbgl { +namespace style { + +class FillExtrusionLayer::Impl : public Layer::Impl { +public: + std::unique_ptr<Layer> clone() const override; + std::unique_ptr<Layer> cloneRef(const std::string& id) const override; + + void cascade(const CascadeParameters&) override; + bool evaluate(const PropertyEvaluationParameters&) override; + + std::unique_ptr<Bucket> createBucket(BucketParameters&) const override; + + FillExtrusionPaintProperties paint; +}; + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/layers/fill_extrusion_layer_properties.cpp b/src/mbgl/style/layers/fill_extrusion_layer_properties.cpp new file mode 100644 index 0000000000..59572bd3ab --- /dev/null +++ b/src/mbgl/style/layers/fill_extrusion_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/fill_extrusion_layer_properties.hpp> + +namespace mbgl { +namespace style { + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp b/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp new file mode 100644 index 0000000000..a2d01199a5 --- /dev/null +++ b/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp @@ -0,0 +1,51 @@ +// 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> + +namespace mbgl { +namespace style { + +struct FillExtrusionOpacity : PaintProperty<float> { + static float defaultValue() { return 1; } +}; + +struct FillExtrusionColor : PaintProperty<Color> { + static Color defaultValue() { return Color::black(); } +}; + +struct FillExtrusionTranslate : PaintProperty<std::array<float, 2>> { + static std::array<float, 2> defaultValue() { return {{ 0, 0 }}; } +}; + +struct FillExtrusionTranslateAnchor : PaintProperty<TranslateAnchorType> { + static TranslateAnchorType defaultValue() { return TranslateAnchorType::Map; } +}; + +struct FillExtrusionPattern : CrossFadedPaintProperty<std::string> { + static std::string defaultValue() { return ""; } +}; + +struct FillExtrusionHeight : PaintProperty<float> { + static float defaultValue() { return 0; } +}; + +struct FillExtrusionBase : PaintProperty<float> { + static float defaultValue() { return 0; } +}; + +class FillExtrusionPaintProperties : public PaintProperties< + FillExtrusionOpacity, + FillExtrusionColor, + FillExtrusionTranslate, + FillExtrusionTranslateAnchor, + FillExtrusionPattern, + FillExtrusionHeight, + FillExtrusionBase +> {}; + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/layers/fill_layer.cpp b/src/mbgl/style/layers/fill_layer.cpp index c61de81d1a..3bea9b56b0 100644 --- a/src/mbgl/style/layers/fill_layer.cpp +++ b/src/mbgl/style/layers/fill_layer.cpp @@ -67,13 +67,13 @@ PropertyValue<bool> FillLayer::getDefaultFillAntialias() { } PropertyValue<bool> FillLayer::getFillAntialias(const optional<std::string>& klass) const { - return impl->paint.fillAntialias.get(klass); + return impl->paint.get<FillAntialias>(klass); } void FillLayer::setFillAntialias(PropertyValue<bool> value, const optional<std::string>& klass) { if (value == getFillAntialias(klass)) return; - impl->paint.fillAntialias.set(value, klass); + impl->paint.set<FillAntialias>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -82,13 +82,13 @@ PropertyValue<float> FillLayer::getDefaultFillOpacity() { } PropertyValue<float> FillLayer::getFillOpacity(const optional<std::string>& klass) const { - return impl->paint.fillOpacity.get(klass); + return impl->paint.get<FillOpacity>(klass); } void FillLayer::setFillOpacity(PropertyValue<float> value, const optional<std::string>& klass) { if (value == getFillOpacity(klass)) return; - impl->paint.fillOpacity.set(value, klass); + impl->paint.set<FillOpacity>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -97,13 +97,13 @@ PropertyValue<Color> FillLayer::getDefaultFillColor() { } PropertyValue<Color> FillLayer::getFillColor(const optional<std::string>& klass) const { - return impl->paint.fillColor.get(klass); + return impl->paint.get<FillColor>(klass); } void FillLayer::setFillColor(PropertyValue<Color> value, const optional<std::string>& klass) { if (value == getFillColor(klass)) return; - impl->paint.fillColor.set(value, klass); + impl->paint.set<FillColor>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -112,13 +112,13 @@ PropertyValue<Color> FillLayer::getDefaultFillOutlineColor() { } PropertyValue<Color> FillLayer::getFillOutlineColor(const optional<std::string>& klass) const { - return impl->paint.fillOutlineColor.get(klass); + return impl->paint.get<FillOutlineColor>(klass); } void FillLayer::setFillOutlineColor(PropertyValue<Color> value, const optional<std::string>& klass) { if (value == getFillOutlineColor(klass)) return; - impl->paint.fillOutlineColor.set(value, klass); + impl->paint.set<FillOutlineColor>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -127,13 +127,13 @@ PropertyValue<std::array<float, 2>> FillLayer::getDefaultFillTranslate() { } PropertyValue<std::array<float, 2>> FillLayer::getFillTranslate(const optional<std::string>& klass) const { - return impl->paint.fillTranslate.get(klass); + return impl->paint.get<FillTranslate>(klass); } void FillLayer::setFillTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) { if (value == getFillTranslate(klass)) return; - impl->paint.fillTranslate.set(value, klass); + impl->paint.set<FillTranslate>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -142,13 +142,13 @@ PropertyValue<TranslateAnchorType> FillLayer::getDefaultFillTranslateAnchor() { } PropertyValue<TranslateAnchorType> FillLayer::getFillTranslateAnchor(const optional<std::string>& klass) const { - return impl->paint.fillTranslateAnchor.get(klass); + return impl->paint.get<FillTranslateAnchor>(klass); } void FillLayer::setFillTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) { if (value == getFillTranslateAnchor(klass)) return; - impl->paint.fillTranslateAnchor.set(value, klass); + impl->paint.set<FillTranslateAnchor>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -157,13 +157,13 @@ PropertyValue<std::string> FillLayer::getDefaultFillPattern() { } PropertyValue<std::string> FillLayer::getFillPattern(const optional<std::string>& klass) const { - return impl->paint.fillPattern.get(klass); + return impl->paint.get<FillPattern>(klass); } void FillLayer::setFillPattern(PropertyValue<std::string> value, const optional<std::string>& klass) { if (value == getFillPattern(klass)) return; - impl->paint.fillPattern.set(value, klass); + impl->paint.set<FillPattern>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } diff --git a/src/mbgl/style/layers/fill_layer_impl.cpp b/src/mbgl/style/layers/fill_layer_impl.cpp index fc439f1cd1..6a690ba447 100644 --- a/src/mbgl/style/layers/fill_layer_impl.cpp +++ b/src/mbgl/style/layers/fill_layer_impl.cpp @@ -12,22 +12,22 @@ void FillLayer::Impl::cascade(const CascadeParameters& parameters) { paint.cascade(parameters); } -bool FillLayer::Impl::recalculate(const CalculationParameters& parameters) { - bool hasTransitions = paint.recalculate(parameters); +bool FillLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) { + paint.evaluate(parameters); passes = RenderPass::None; - if (paint.fillAntialias) { + if (paint.evaluated.get<FillAntialias>()) { passes |= RenderPass::Translucent; } - if (!paint.fillPattern.value.from.empty() || (paint.fillColor.value.a * paint.fillOpacity) < 1.0f) { + if (!paint.evaluated.get<FillPattern>().from.empty() || (paint.evaluated.get<FillColor>().a * paint.evaluated.get<FillOpacity>()) < 1.0f) { passes |= RenderPass::Translucent; } else { passes |= RenderPass::Opaque; } - return hasTransitions; + return paint.hasTransition(); } std::unique_ptr<Bucket> FillLayer::Impl::createBucket(BucketParameters& parameters) const { @@ -44,7 +44,7 @@ std::unique_ptr<Bucket> FillLayer::Impl::createBucket(BucketParameters& paramete } float FillLayer::Impl::getQueryRadius() const { - const std::array<float, 2>& translate = paint.fillTranslate; + const std::array<float, 2>& translate = paint.evaluated.get<FillTranslate>(); return util::length(translate[0], translate[1]); } @@ -55,7 +55,7 @@ bool FillLayer::Impl::queryIntersectsGeometry( const float pixelsToTileUnits) const { auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry( - queryGeometry, paint.fillTranslate, paint.fillTranslateAnchor, bearing, pixelsToTileUnits); + queryGeometry, paint.evaluated.get<FillTranslate>(), paint.evaluated.get<FillTranslateAnchor>(), bearing, pixelsToTileUnits); return util::polygonIntersectsMultiPolygon(translatedQueryGeometry.value_or(queryGeometry), geometry); } diff --git a/src/mbgl/style/layers/fill_layer_impl.hpp b/src/mbgl/style/layers/fill_layer_impl.hpp index 54cfb80c86..53276d744a 100644 --- a/src/mbgl/style/layers/fill_layer_impl.hpp +++ b/src/mbgl/style/layers/fill_layer_impl.hpp @@ -13,7 +13,7 @@ public: std::unique_ptr<Layer> cloneRef(const std::string& id) const override; void cascade(const CascadeParameters&) override; - bool recalculate(const CalculationParameters&) override; + bool evaluate(const PropertyEvaluationParameters&) override; std::unique_ptr<Bucket> createBucket(BucketParameters&) const override; diff --git a/src/mbgl/style/layers/fill_layer_properties.cpp b/src/mbgl/style/layers/fill_layer_properties.cpp index 9a55cbc145..b07a083950 100644 --- a/src/mbgl/style/layers/fill_layer_properties.cpp +++ b/src/mbgl/style/layers/fill_layer_properties.cpp @@ -5,29 +5,5 @@ namespace mbgl { namespace style { -void FillPaintProperties::cascade(const CascadeParameters& parameters) { - fillAntialias.cascade(parameters); - fillOpacity.cascade(parameters); - fillColor.cascade(parameters); - fillOutlineColor.cascade(parameters); - fillTranslate.cascade(parameters); - fillTranslateAnchor.cascade(parameters); - fillPattern.cascade(parameters); -} - -bool FillPaintProperties::recalculate(const CalculationParameters& parameters) { - bool hasTransitions = false; - - hasTransitions |= fillAntialias.calculate(parameters); - hasTransitions |= fillOpacity.calculate(parameters); - hasTransitions |= fillColor.calculate(parameters); - hasTransitions |= fillOutlineColor.calculate(parameters); - hasTransitions |= fillTranslate.calculate(parameters); - hasTransitions |= fillTranslateAnchor.calculate(parameters); - hasTransitions |= fillPattern.calculate(parameters); - - return hasTransitions; -} - } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layers/fill_layer_properties.hpp b/src/mbgl/style/layers/fill_layer_properties.hpp index d12eb8d6f4..b2d926c31e 100644 --- a/src/mbgl/style/layers/fill_layer_properties.hpp +++ b/src/mbgl/style/layers/fill_layer_properties.hpp @@ -9,22 +9,43 @@ namespace mbgl { namespace style { -class CascadeParameters; -class CalculationParameters; - -class FillPaintProperties { -public: - void cascade(const CascadeParameters&); - bool recalculate(const CalculationParameters&); - - PaintProperty<bool> fillAntialias { true }; - PaintProperty<float> fillOpacity { 1 }; - PaintProperty<Color> fillColor { Color::black() }; - PaintProperty<Color> fillOutlineColor { {} }; - PaintProperty<std::array<float, 2>> fillTranslate { {{ 0, 0 }} }; - PaintProperty<TranslateAnchorType> fillTranslateAnchor { TranslateAnchorType::Map }; - PaintProperty<std::string, CrossFadedPropertyEvaluator> fillPattern { "" }; +struct FillAntialias : PaintProperty<bool> { + static bool defaultValue() { return true; } }; +struct FillOpacity : PaintProperty<float> { + static float defaultValue() { return 1; } +}; + +struct FillColor : PaintProperty<Color> { + static Color defaultValue() { return Color::black(); } +}; + +struct FillOutlineColor : PaintProperty<Color> { + static Color defaultValue() { return {}; } +}; + +struct FillTranslate : PaintProperty<std::array<float, 2>> { + static std::array<float, 2> defaultValue() { return {{ 0, 0 }}; } +}; + +struct FillTranslateAnchor : PaintProperty<TranslateAnchorType> { + static TranslateAnchorType defaultValue() { return TranslateAnchorType::Map; } +}; + +struct FillPattern : CrossFadedPaintProperty<std::string> { + static std::string defaultValue() { return ""; } +}; + +class FillPaintProperties : public PaintProperties< + FillAntialias, + FillOpacity, + FillColor, + FillOutlineColor, + FillTranslate, + FillTranslateAnchor, + FillPattern +> {}; + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs index c2cbc56a09..5fe78519ec 100644 --- a/src/mbgl/style/layers/layer.cpp.ejs +++ b/src/mbgl/style/layers/layer.cpp.ejs @@ -5,8 +5,8 @@ -%> // This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. -#include <mbgl/style/layers/<%- type %>_layer.hpp> -#include <mbgl/style/layers/<%- type %>_layer_impl.hpp> +#include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer.hpp> +#include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer_impl.hpp> namespace mbgl { namespace style { @@ -78,17 +78,17 @@ const Filter& <%- camelize(type) %>Layer::getFilter() const { <% for (const property of layoutProperties) { -%> PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::getDefault<%- camelize(property.name) %>() { - return { <%- defaultValue(property) %> }; + return <%- camelize(property.name) %>::defaultValue(); } PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>() const { - return impl->layout.<%- camelizeWithLeadingLowercase(property.name) %>.get(); + return impl->layout.unevaluated.get<<%- camelize(property.name) %>>(); } void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(PropertyValue<<%- propertyType(property) %>> value) { if (value == get<%- camelize(property.name) %>()) return; - impl->layout.<%- camelizeWithLeadingLowercase(property.name) %>.set(value); + impl->layout.unevaluated.get<<%- camelize(property.name) %>>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "<%- property.name %>"); } <% } -%> @@ -100,13 +100,13 @@ PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::getDefa } PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>(const optional<std::string>& klass) const { - return impl->paint.<%- camelizeWithLeadingLowercase(property.name) %>.get(klass); + return impl->paint.get<<%- camelize(property.name) %>>(klass); } void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(PropertyValue<<%- propertyType(property) %>> value, const optional<std::string>& klass) { if (value == get<%- camelize(property.name) %>(klass)) return; - impl->paint.<%- camelizeWithLeadingLowercase(property.name) %>.set(value, klass); + impl->paint.set<<%- camelize(property.name) %>>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } <% } -%> diff --git a/src/mbgl/style/layers/layer_properties.cpp.ejs b/src/mbgl/style/layers/layer_properties.cpp.ejs index b781a4a9d9..e5523e5439 100644 --- a/src/mbgl/style/layers/layer_properties.cpp.ejs +++ b/src/mbgl/style/layers/layer_properties.cpp.ejs @@ -5,34 +5,10 @@ -%> // This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. -#include <mbgl/style/layers/<%- type %>_layer_properties.hpp> +#include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer_properties.hpp> namespace mbgl { namespace style { -<% if (layoutProperties.length) { -%> -void <%- camelize(type) %>LayoutProperties::recalculate(const CalculationParameters& parameters) { -<% for (const property of layoutProperties) { -%> - <%- camelizeWithLeadingLowercase(property.name) %>.calculate(parameters); -<% } -%> -} - -<% } -%> -void <%- camelize(type) %>PaintProperties::cascade(const CascadeParameters& parameters) { -<% for (const property of paintProperties) { -%> - <%- camelizeWithLeadingLowercase(property.name) %>.cascade(parameters); -<% } -%> -} - -bool <%- camelize(type) %>PaintProperties::recalculate(const CalculationParameters& parameters) { - bool hasTransitions = false; - -<% for (const property of paintProperties) { -%> - hasTransitions |= <%- camelizeWithLeadingLowercase(property.name) %>.calculate(parameters); -<% } -%> - - return hasTransitions; -} - } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layers/layer_properties.hpp.ejs b/src/mbgl/style/layers/layer_properties.hpp.ejs index 0c91ecba8c..f490a636f9 100644 --- a/src/mbgl/style/layers/layer_properties.hpp.ejs +++ b/src/mbgl/style/layers/layer_properties.hpp.ejs @@ -14,33 +14,35 @@ namespace mbgl { namespace style { -class CascadeParameters; -class CalculationParameters; - -<% if (layoutProperties.length) { -%> -class <%- camelize(type) %>LayoutProperties { -public: - void recalculate(const CalculationParameters&); - <% for (const property of layoutProperties) { -%> - LayoutProperty<<%- propertyType(property) %>> <%- camelizeWithLeadingLowercase(property.name) %> { <%- defaultValue(property) %> }; +struct <%- camelize(property.name) %> : LayoutProperty<<%- propertyType(property) %>> { + static <%- propertyType(property) %> defaultValue() { return <%- defaultValue(property) %>; } +}; + <% } -%> +<% for (const property of paintProperties) { -%> +struct <%- camelize(property.name) %> : <% +if (/-pattern$/.test(property.name) || property.name === 'line-dasharray') { +%>CrossFaded<% } -%>PaintProperty<<%- propertyType(property) %>> { + static <%- propertyType(property) %> defaultValue() { return <%- defaultValue(property) %>; } }; <% } -%> -class <%- camelize(type) %>PaintProperties { -public: - void cascade(const CascadeParameters&); - bool recalculate(const CalculationParameters&); +<% if (layoutProperties.length) { -%> +class <%- camelize(type) %>LayoutProperties : public LayoutProperties< +<% for (const property of layoutProperties.slice(0, -1)) { -%> + <%- camelize(property.name) %>, +<% } -%> + <%- camelize(layoutProperties.slice(-1)[0].name) %> +> {}; -<% for (const property of paintProperties) { -%> -<% if (/-pattern$/.test(property.name) || property.name === 'line-dasharray') { -%> - PaintProperty<<%- propertyType(property) %>, CrossFadedPropertyEvaluator> <%- camelizeWithLeadingLowercase(property.name) %> { <%- defaultValue(property) %> }; -<% } else { -%> - PaintProperty<<%- propertyType(property) %>> <%- camelizeWithLeadingLowercase(property.name) %> { <%- defaultValue(property) %> }; <% } -%> +class <%- camelize(type) %>PaintProperties : public PaintProperties< +<% for (const property of paintProperties.slice(0, -1)) { -%> + <%- camelize(property.name) %>, <% } -%> -}; + <%- camelize(paintProperties.slice(-1)[0].name) %> +> {}; } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layers/line_layer.cpp b/src/mbgl/style/layers/line_layer.cpp index 49ecf63c18..8c38ef5694 100644 --- a/src/mbgl/style/layers/line_layer.cpp +++ b/src/mbgl/style/layers/line_layer.cpp @@ -60,59 +60,59 @@ const Filter& LineLayer::getFilter() const { // Layout properties PropertyValue<LineCapType> LineLayer::getDefaultLineCap() { - return { LineCapType::Butt }; + return LineCap::defaultValue(); } PropertyValue<LineCapType> LineLayer::getLineCap() const { - return impl->layout.lineCap.get(); + return impl->layout.unevaluated.get<LineCap>(); } void LineLayer::setLineCap(PropertyValue<LineCapType> value) { if (value == getLineCap()) return; - impl->layout.lineCap.set(value); + impl->layout.unevaluated.get<LineCap>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "line-cap"); } PropertyValue<LineJoinType> LineLayer::getDefaultLineJoin() { - return { LineJoinType::Miter }; + return LineJoin::defaultValue(); } PropertyValue<LineJoinType> LineLayer::getLineJoin() const { - return impl->layout.lineJoin.get(); + return impl->layout.unevaluated.get<LineJoin>(); } void LineLayer::setLineJoin(PropertyValue<LineJoinType> value) { if (value == getLineJoin()) return; - impl->layout.lineJoin.set(value); + impl->layout.unevaluated.get<LineJoin>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "line-join"); } PropertyValue<float> LineLayer::getDefaultLineMiterLimit() { - return { 2 }; + return LineMiterLimit::defaultValue(); } PropertyValue<float> LineLayer::getLineMiterLimit() const { - return impl->layout.lineMiterLimit.get(); + return impl->layout.unevaluated.get<LineMiterLimit>(); } void LineLayer::setLineMiterLimit(PropertyValue<float> value) { if (value == getLineMiterLimit()) return; - impl->layout.lineMiterLimit.set(value); + impl->layout.unevaluated.get<LineMiterLimit>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "line-miter-limit"); } PropertyValue<float> LineLayer::getDefaultLineRoundLimit() { - return { 1 }; + return LineRoundLimit::defaultValue(); } PropertyValue<float> LineLayer::getLineRoundLimit() const { - return impl->layout.lineRoundLimit.get(); + return impl->layout.unevaluated.get<LineRoundLimit>(); } void LineLayer::setLineRoundLimit(PropertyValue<float> value) { if (value == getLineRoundLimit()) return; - impl->layout.lineRoundLimit.set(value); + impl->layout.unevaluated.get<LineRoundLimit>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "line-round-limit"); } @@ -123,13 +123,13 @@ PropertyValue<float> LineLayer::getDefaultLineOpacity() { } PropertyValue<float> LineLayer::getLineOpacity(const optional<std::string>& klass) const { - return impl->paint.lineOpacity.get(klass); + return impl->paint.get<LineOpacity>(klass); } void LineLayer::setLineOpacity(PropertyValue<float> value, const optional<std::string>& klass) { if (value == getLineOpacity(klass)) return; - impl->paint.lineOpacity.set(value, klass); + impl->paint.set<LineOpacity>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -138,13 +138,13 @@ PropertyValue<Color> LineLayer::getDefaultLineColor() { } PropertyValue<Color> LineLayer::getLineColor(const optional<std::string>& klass) const { - return impl->paint.lineColor.get(klass); + return impl->paint.get<LineColor>(klass); } void LineLayer::setLineColor(PropertyValue<Color> value, const optional<std::string>& klass) { if (value == getLineColor(klass)) return; - impl->paint.lineColor.set(value, klass); + impl->paint.set<LineColor>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -153,13 +153,13 @@ PropertyValue<std::array<float, 2>> LineLayer::getDefaultLineTranslate() { } PropertyValue<std::array<float, 2>> LineLayer::getLineTranslate(const optional<std::string>& klass) const { - return impl->paint.lineTranslate.get(klass); + return impl->paint.get<LineTranslate>(klass); } void LineLayer::setLineTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) { if (value == getLineTranslate(klass)) return; - impl->paint.lineTranslate.set(value, klass); + impl->paint.set<LineTranslate>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -168,13 +168,13 @@ PropertyValue<TranslateAnchorType> LineLayer::getDefaultLineTranslateAnchor() { } PropertyValue<TranslateAnchorType> LineLayer::getLineTranslateAnchor(const optional<std::string>& klass) const { - return impl->paint.lineTranslateAnchor.get(klass); + return impl->paint.get<LineTranslateAnchor>(klass); } void LineLayer::setLineTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) { if (value == getLineTranslateAnchor(klass)) return; - impl->paint.lineTranslateAnchor.set(value, klass); + impl->paint.set<LineTranslateAnchor>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -183,13 +183,13 @@ PropertyValue<float> LineLayer::getDefaultLineWidth() { } PropertyValue<float> LineLayer::getLineWidth(const optional<std::string>& klass) const { - return impl->paint.lineWidth.get(klass); + return impl->paint.get<LineWidth>(klass); } void LineLayer::setLineWidth(PropertyValue<float> value, const optional<std::string>& klass) { if (value == getLineWidth(klass)) return; - impl->paint.lineWidth.set(value, klass); + impl->paint.set<LineWidth>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -198,13 +198,13 @@ PropertyValue<float> LineLayer::getDefaultLineGapWidth() { } PropertyValue<float> LineLayer::getLineGapWidth(const optional<std::string>& klass) const { - return impl->paint.lineGapWidth.get(klass); + return impl->paint.get<LineGapWidth>(klass); } void LineLayer::setLineGapWidth(PropertyValue<float> value, const optional<std::string>& klass) { if (value == getLineGapWidth(klass)) return; - impl->paint.lineGapWidth.set(value, klass); + impl->paint.set<LineGapWidth>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -213,13 +213,13 @@ PropertyValue<float> LineLayer::getDefaultLineOffset() { } PropertyValue<float> LineLayer::getLineOffset(const optional<std::string>& klass) const { - return impl->paint.lineOffset.get(klass); + return impl->paint.get<LineOffset>(klass); } void LineLayer::setLineOffset(PropertyValue<float> value, const optional<std::string>& klass) { if (value == getLineOffset(klass)) return; - impl->paint.lineOffset.set(value, klass); + impl->paint.set<LineOffset>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -228,13 +228,13 @@ PropertyValue<float> LineLayer::getDefaultLineBlur() { } PropertyValue<float> LineLayer::getLineBlur(const optional<std::string>& klass) const { - return impl->paint.lineBlur.get(klass); + return impl->paint.get<LineBlur>(klass); } void LineLayer::setLineBlur(PropertyValue<float> value, const optional<std::string>& klass) { if (value == getLineBlur(klass)) return; - impl->paint.lineBlur.set(value, klass); + impl->paint.set<LineBlur>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -243,13 +243,13 @@ PropertyValue<std::vector<float>> LineLayer::getDefaultLineDasharray() { } PropertyValue<std::vector<float>> LineLayer::getLineDasharray(const optional<std::string>& klass) const { - return impl->paint.lineDasharray.get(klass); + return impl->paint.get<LineDasharray>(klass); } void LineLayer::setLineDasharray(PropertyValue<std::vector<float>> value, const optional<std::string>& klass) { if (value == getLineDasharray(klass)) return; - impl->paint.lineDasharray.set(value, klass); + impl->paint.set<LineDasharray>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -258,13 +258,13 @@ PropertyValue<std::string> LineLayer::getDefaultLinePattern() { } PropertyValue<std::string> LineLayer::getLinePattern(const optional<std::string>& klass) const { - return impl->paint.linePattern.get(klass); + return impl->paint.get<LinePattern>(klass); } void LineLayer::setLinePattern(PropertyValue<std::string> value, const optional<std::string>& klass) { if (value == getLinePattern(klass)) return; - impl->paint.linePattern.set(value, klass); + impl->paint.set<LinePattern>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } diff --git a/src/mbgl/style/layers/line_layer_impl.cpp b/src/mbgl/style/layers/line_layer_impl.cpp index c116af5fc2..e6ec21a659 100644 --- a/src/mbgl/style/layers/line_layer_impl.cpp +++ b/src/mbgl/style/layers/line_layer_impl.cpp @@ -12,26 +12,24 @@ void LineLayer::Impl::cascade(const CascadeParameters& parameters) { paint.cascade(parameters); } -bool LineLayer::Impl::recalculate(const CalculationParameters& parameters) { +bool LineLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) { // for scaling dasharrays - CalculationParameters dashArrayParams = parameters; + PropertyEvaluationParameters dashArrayParams = parameters; dashArrayParams.z = std::floor(dashArrayParams.z); - paint.lineWidth.calculate(dashArrayParams); - dashLineWidth = paint.lineWidth; + dashLineWidth = paint.evaluate<LineWidth>(dashArrayParams); - bool hasTransitions = paint.recalculate(parameters); + paint.evaluate(parameters); - passes = (paint.lineOpacity > 0 && paint.lineColor.value.a > 0 && paint.lineWidth > 0) + passes = (paint.evaluated.get<LineOpacity>() > 0 && paint.evaluated.get<LineColor>().a > 0 && paint.evaluated.get<LineWidth>() > 0) ? RenderPass::Translucent : RenderPass::None; - return hasTransitions; + return paint.hasTransition(); } std::unique_ptr<Bucket> LineLayer::Impl::createBucket(BucketParameters& parameters) const { auto bucket = std::make_unique<LineBucket>(parameters.tileID.overscaleFactor()); - bucket->layout = layout; - bucket->layout.recalculate(CalculationParameters(parameters.tileID.overscaledZ)); + bucket->layout = layout.evaluate(PropertyEvaluationParameters(parameters.tileID.overscaledZ)); auto& name = bucketName(); parameters.eachFilteredFeature(filter, [&] (const auto& feature, std::size_t index, const std::string& layerName) { @@ -44,10 +42,10 @@ std::unique_ptr<Bucket> LineLayer::Impl::createBucket(BucketParameters& paramete } float LineLayer::Impl::getLineWidth() const { - if (paint.lineGapWidth > 0) { - return paint.lineGapWidth + 2 * paint.lineWidth; + if (paint.evaluated.get<LineGapWidth>() > 0) { + return paint.evaluated.get<LineGapWidth>() + 2 * paint.evaluated.get<LineWidth>(); } else { - return paint.lineWidth; + return paint.evaluated.get<LineWidth>(); } } @@ -82,8 +80,8 @@ optional<GeometryCollection> offsetLine(const GeometryCollection& rings, const d } float LineLayer::Impl::getQueryRadius() const { - const std::array<float, 2>& translate = paint.lineTranslate; - return getLineWidth() / 2.0 + std::abs(paint.lineOffset) + util::length(translate[0], translate[1]); + const std::array<float, 2>& translate = paint.evaluated.get<LineTranslate>(); + return getLineWidth() / 2.0 + std::abs(paint.evaluated.get<LineOffset>()) + util::length(translate[0], translate[1]); } bool LineLayer::Impl::queryIntersectsGeometry( @@ -95,8 +93,8 @@ bool LineLayer::Impl::queryIntersectsGeometry( const float halfWidth = getLineWidth() / 2.0 * pixelsToTileUnits; auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry( - queryGeometry, paint.lineTranslate, paint.lineTranslateAnchor, bearing, pixelsToTileUnits); - auto offsetGeometry = offsetLine(geometry, paint.lineOffset * pixelsToTileUnits); + queryGeometry, paint.evaluated.get<LineTranslate>(), paint.evaluated.get<LineTranslateAnchor>(), bearing, pixelsToTileUnits); + auto offsetGeometry = offsetLine(geometry, paint.evaluated.get<LineOffset>() * pixelsToTileUnits); return util::polygonIntersectsBufferedMultiLine( translatedQueryGeometry.value_or(queryGeometry), diff --git a/src/mbgl/style/layers/line_layer_impl.hpp b/src/mbgl/style/layers/line_layer_impl.hpp index c6b4be3bec..3387db07f0 100644 --- a/src/mbgl/style/layers/line_layer_impl.hpp +++ b/src/mbgl/style/layers/line_layer_impl.hpp @@ -13,7 +13,7 @@ public: std::unique_ptr<Layer> cloneRef(const std::string& id) const override; void cascade(const CascadeParameters&) override; - bool recalculate(const CalculationParameters&) override; + bool evaluate(const PropertyEvaluationParameters&) override; std::unique_ptr<Bucket> createBucket(BucketParameters&) const override; diff --git a/src/mbgl/style/layers/line_layer_properties.cpp b/src/mbgl/style/layers/line_layer_properties.cpp index 2d6092745e..174239bcc8 100644 --- a/src/mbgl/style/layers/line_layer_properties.cpp +++ b/src/mbgl/style/layers/line_layer_properties.cpp @@ -5,42 +5,5 @@ namespace mbgl { namespace style { -void LineLayoutProperties::recalculate(const CalculationParameters& parameters) { - lineCap.calculate(parameters); - lineJoin.calculate(parameters); - lineMiterLimit.calculate(parameters); - lineRoundLimit.calculate(parameters); -} - -void LinePaintProperties::cascade(const CascadeParameters& parameters) { - lineOpacity.cascade(parameters); - lineColor.cascade(parameters); - lineTranslate.cascade(parameters); - lineTranslateAnchor.cascade(parameters); - lineWidth.cascade(parameters); - lineGapWidth.cascade(parameters); - lineOffset.cascade(parameters); - lineBlur.cascade(parameters); - lineDasharray.cascade(parameters); - linePattern.cascade(parameters); -} - -bool LinePaintProperties::recalculate(const CalculationParameters& parameters) { - bool hasTransitions = false; - - hasTransitions |= lineOpacity.calculate(parameters); - hasTransitions |= lineColor.calculate(parameters); - hasTransitions |= lineTranslate.calculate(parameters); - hasTransitions |= lineTranslateAnchor.calculate(parameters); - hasTransitions |= lineWidth.calculate(parameters); - hasTransitions |= lineGapWidth.calculate(parameters); - hasTransitions |= lineOffset.calculate(parameters); - hasTransitions |= lineBlur.calculate(parameters); - hasTransitions |= lineDasharray.calculate(parameters); - hasTransitions |= linePattern.calculate(parameters); - - return hasTransitions; -} - } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layers/line_layer_properties.hpp b/src/mbgl/style/layers/line_layer_properties.hpp index b73e3f2ef2..07458cd634 100644 --- a/src/mbgl/style/layers/line_layer_properties.hpp +++ b/src/mbgl/style/layers/line_layer_properties.hpp @@ -9,35 +9,81 @@ namespace mbgl { namespace style { -class CascadeParameters; -class CalculationParameters; - -class LineLayoutProperties { -public: - void recalculate(const CalculationParameters&); - - LayoutProperty<LineCapType> lineCap { LineCapType::Butt }; - LayoutProperty<LineJoinType> lineJoin { LineJoinType::Miter }; - LayoutProperty<float> lineMiterLimit { 2 }; - LayoutProperty<float> lineRoundLimit { 1 }; -}; - -class LinePaintProperties { -public: - void cascade(const CascadeParameters&); - bool recalculate(const CalculationParameters&); - - PaintProperty<float> lineOpacity { 1 }; - PaintProperty<Color> lineColor { Color::black() }; - PaintProperty<std::array<float, 2>> lineTranslate { {{ 0, 0 }} }; - PaintProperty<TranslateAnchorType> lineTranslateAnchor { TranslateAnchorType::Map }; - PaintProperty<float> lineWidth { 1 }; - PaintProperty<float> lineGapWidth { 0 }; - PaintProperty<float> lineOffset { 0 }; - PaintProperty<float> lineBlur { 0 }; - PaintProperty<std::vector<float>, CrossFadedPropertyEvaluator> lineDasharray { { } }; - PaintProperty<std::string, CrossFadedPropertyEvaluator> linePattern { "" }; +struct LineCap : LayoutProperty<LineCapType> { + static LineCapType defaultValue() { return LineCapType::Butt; } }; +struct LineJoin : LayoutProperty<LineJoinType> { + static LineJoinType defaultValue() { return LineJoinType::Miter; } +}; + +struct LineMiterLimit : LayoutProperty<float> { + static float defaultValue() { return 2; } +}; + +struct LineRoundLimit : LayoutProperty<float> { + static float defaultValue() { return 1; } +}; + +struct LineOpacity : PaintProperty<float> { + static float defaultValue() { return 1; } +}; + +struct LineColor : PaintProperty<Color> { + static Color defaultValue() { return Color::black(); } +}; + +struct LineTranslate : PaintProperty<std::array<float, 2>> { + static std::array<float, 2> defaultValue() { return {{ 0, 0 }}; } +}; + +struct LineTranslateAnchor : PaintProperty<TranslateAnchorType> { + static TranslateAnchorType defaultValue() { return TranslateAnchorType::Map; } +}; + +struct LineWidth : PaintProperty<float> { + static float defaultValue() { return 1; } +}; + +struct LineGapWidth : PaintProperty<float> { + static float defaultValue() { return 0; } +}; + +struct LineOffset : PaintProperty<float> { + static float defaultValue() { return 0; } +}; + +struct LineBlur : PaintProperty<float> { + static float defaultValue() { return 0; } +}; + +struct LineDasharray : CrossFadedPaintProperty<std::vector<float>> { + static std::vector<float> defaultValue() { return { }; } +}; + +struct LinePattern : CrossFadedPaintProperty<std::string> { + static std::string defaultValue() { return ""; } +}; + +class LineLayoutProperties : public LayoutProperties< + LineCap, + LineJoin, + LineMiterLimit, + LineRoundLimit +> {}; + +class LinePaintProperties : public PaintProperties< + LineOpacity, + LineColor, + LineTranslate, + LineTranslateAnchor, + LineWidth, + LineGapWidth, + LineOffset, + LineBlur, + LineDasharray, + LinePattern +> {}; + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layers/raster_layer.cpp b/src/mbgl/style/layers/raster_layer.cpp index 238bfef6e4..21d72a0fdc 100644 --- a/src/mbgl/style/layers/raster_layer.cpp +++ b/src/mbgl/style/layers/raster_layer.cpp @@ -49,13 +49,13 @@ PropertyValue<float> RasterLayer::getDefaultRasterOpacity() { } PropertyValue<float> RasterLayer::getRasterOpacity(const optional<std::string>& klass) const { - return impl->paint.rasterOpacity.get(klass); + return impl->paint.get<RasterOpacity>(klass); } void RasterLayer::setRasterOpacity(PropertyValue<float> value, const optional<std::string>& klass) { if (value == getRasterOpacity(klass)) return; - impl->paint.rasterOpacity.set(value, klass); + impl->paint.set<RasterOpacity>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -64,13 +64,13 @@ PropertyValue<float> RasterLayer::getDefaultRasterHueRotate() { } PropertyValue<float> RasterLayer::getRasterHueRotate(const optional<std::string>& klass) const { - return impl->paint.rasterHueRotate.get(klass); + return impl->paint.get<RasterHueRotate>(klass); } void RasterLayer::setRasterHueRotate(PropertyValue<float> value, const optional<std::string>& klass) { if (value == getRasterHueRotate(klass)) return; - impl->paint.rasterHueRotate.set(value, klass); + impl->paint.set<RasterHueRotate>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -79,13 +79,13 @@ PropertyValue<float> RasterLayer::getDefaultRasterBrightnessMin() { } PropertyValue<float> RasterLayer::getRasterBrightnessMin(const optional<std::string>& klass) const { - return impl->paint.rasterBrightnessMin.get(klass); + return impl->paint.get<RasterBrightnessMin>(klass); } void RasterLayer::setRasterBrightnessMin(PropertyValue<float> value, const optional<std::string>& klass) { if (value == getRasterBrightnessMin(klass)) return; - impl->paint.rasterBrightnessMin.set(value, klass); + impl->paint.set<RasterBrightnessMin>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -94,13 +94,13 @@ PropertyValue<float> RasterLayer::getDefaultRasterBrightnessMax() { } PropertyValue<float> RasterLayer::getRasterBrightnessMax(const optional<std::string>& klass) const { - return impl->paint.rasterBrightnessMax.get(klass); + return impl->paint.get<RasterBrightnessMax>(klass); } void RasterLayer::setRasterBrightnessMax(PropertyValue<float> value, const optional<std::string>& klass) { if (value == getRasterBrightnessMax(klass)) return; - impl->paint.rasterBrightnessMax.set(value, klass); + impl->paint.set<RasterBrightnessMax>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -109,13 +109,13 @@ PropertyValue<float> RasterLayer::getDefaultRasterSaturation() { } PropertyValue<float> RasterLayer::getRasterSaturation(const optional<std::string>& klass) const { - return impl->paint.rasterSaturation.get(klass); + return impl->paint.get<RasterSaturation>(klass); } void RasterLayer::setRasterSaturation(PropertyValue<float> value, const optional<std::string>& klass) { if (value == getRasterSaturation(klass)) return; - impl->paint.rasterSaturation.set(value, klass); + impl->paint.set<RasterSaturation>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -124,13 +124,13 @@ PropertyValue<float> RasterLayer::getDefaultRasterContrast() { } PropertyValue<float> RasterLayer::getRasterContrast(const optional<std::string>& klass) const { - return impl->paint.rasterContrast.get(klass); + return impl->paint.get<RasterContrast>(klass); } void RasterLayer::setRasterContrast(PropertyValue<float> value, const optional<std::string>& klass) { if (value == getRasterContrast(klass)) return; - impl->paint.rasterContrast.set(value, klass); + impl->paint.set<RasterContrast>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -139,13 +139,13 @@ PropertyValue<float> RasterLayer::getDefaultRasterFadeDuration() { } PropertyValue<float> RasterLayer::getRasterFadeDuration(const optional<std::string>& klass) const { - return impl->paint.rasterFadeDuration.get(klass); + return impl->paint.get<RasterFadeDuration>(klass); } void RasterLayer::setRasterFadeDuration(PropertyValue<float> value, const optional<std::string>& klass) { if (value == getRasterFadeDuration(klass)) return; - impl->paint.rasterFadeDuration.set(value, klass); + impl->paint.set<RasterFadeDuration>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } diff --git a/src/mbgl/style/layers/raster_layer_impl.cpp b/src/mbgl/style/layers/raster_layer_impl.cpp index 879bfa4559..3be4bb4fbd 100644 --- a/src/mbgl/style/layers/raster_layer_impl.cpp +++ b/src/mbgl/style/layers/raster_layer_impl.cpp @@ -8,12 +8,12 @@ void RasterLayer::Impl::cascade(const CascadeParameters& parameters) { paint.cascade(parameters); } -bool RasterLayer::Impl::recalculate(const CalculationParameters& parameters) { - bool hasTransitions = paint.recalculate(parameters); +bool RasterLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) { + paint.evaluate(parameters); - passes = paint.rasterOpacity > 0 ? RenderPass::Translucent : RenderPass::None; + passes = paint.evaluated.get<RasterOpacity>() > 0 ? RenderPass::Translucent : RenderPass::None; - return hasTransitions; + return paint.hasTransition(); } std::unique_ptr<Bucket> RasterLayer::Impl::createBucket(BucketParameters&) const { diff --git a/src/mbgl/style/layers/raster_layer_impl.hpp b/src/mbgl/style/layers/raster_layer_impl.hpp index a5b396e2ed..df5d388bdf 100644 --- a/src/mbgl/style/layers/raster_layer_impl.hpp +++ b/src/mbgl/style/layers/raster_layer_impl.hpp @@ -13,7 +13,7 @@ public: std::unique_ptr<Layer> cloneRef(const std::string& id) const override; void cascade(const CascadeParameters&) override; - bool recalculate(const CalculationParameters&) override; + bool evaluate(const PropertyEvaluationParameters&) override; std::unique_ptr<Bucket> createBucket(BucketParameters&) const override; diff --git a/src/mbgl/style/layers/raster_layer_properties.cpp b/src/mbgl/style/layers/raster_layer_properties.cpp index 68d9d1d35d..303719af40 100644 --- a/src/mbgl/style/layers/raster_layer_properties.cpp +++ b/src/mbgl/style/layers/raster_layer_properties.cpp @@ -5,29 +5,5 @@ namespace mbgl { namespace style { -void RasterPaintProperties::cascade(const CascadeParameters& parameters) { - rasterOpacity.cascade(parameters); - rasterHueRotate.cascade(parameters); - rasterBrightnessMin.cascade(parameters); - rasterBrightnessMax.cascade(parameters); - rasterSaturation.cascade(parameters); - rasterContrast.cascade(parameters); - rasterFadeDuration.cascade(parameters); -} - -bool RasterPaintProperties::recalculate(const CalculationParameters& parameters) { - bool hasTransitions = false; - - hasTransitions |= rasterOpacity.calculate(parameters); - hasTransitions |= rasterHueRotate.calculate(parameters); - hasTransitions |= rasterBrightnessMin.calculate(parameters); - hasTransitions |= rasterBrightnessMax.calculate(parameters); - hasTransitions |= rasterSaturation.calculate(parameters); - hasTransitions |= rasterContrast.calculate(parameters); - hasTransitions |= rasterFadeDuration.calculate(parameters); - - return hasTransitions; -} - } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layers/raster_layer_properties.hpp b/src/mbgl/style/layers/raster_layer_properties.hpp index ddfb833e12..caa6d0c58d 100644 --- a/src/mbgl/style/layers/raster_layer_properties.hpp +++ b/src/mbgl/style/layers/raster_layer_properties.hpp @@ -9,22 +9,43 @@ namespace mbgl { namespace style { -class CascadeParameters; -class CalculationParameters; - -class RasterPaintProperties { -public: - void cascade(const CascadeParameters&); - bool recalculate(const CalculationParameters&); - - PaintProperty<float> rasterOpacity { 1 }; - PaintProperty<float> rasterHueRotate { 0 }; - PaintProperty<float> rasterBrightnessMin { 0 }; - PaintProperty<float> rasterBrightnessMax { 1 }; - PaintProperty<float> rasterSaturation { 0 }; - PaintProperty<float> rasterContrast { 0 }; - PaintProperty<float> rasterFadeDuration { 300 }; +struct RasterOpacity : PaintProperty<float> { + static float defaultValue() { return 1; } }; +struct RasterHueRotate : PaintProperty<float> { + static float defaultValue() { return 0; } +}; + +struct RasterBrightnessMin : PaintProperty<float> { + static float defaultValue() { return 0; } +}; + +struct RasterBrightnessMax : PaintProperty<float> { + static float defaultValue() { return 1; } +}; + +struct RasterSaturation : PaintProperty<float> { + static float defaultValue() { return 0; } +}; + +struct RasterContrast : PaintProperty<float> { + static float defaultValue() { return 0; } +}; + +struct RasterFadeDuration : PaintProperty<float> { + static float defaultValue() { return 300; } +}; + +class RasterPaintProperties : public PaintProperties< + RasterOpacity, + RasterHueRotate, + RasterBrightnessMin, + RasterBrightnessMax, + RasterSaturation, + RasterContrast, + RasterFadeDuration +> {}; + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp index d49e8d7fe3..61f360ff64 100644 --- a/src/mbgl/style/layers/symbol_layer.cpp +++ b/src/mbgl/style/layers/symbol_layer.cpp @@ -60,479 +60,479 @@ const Filter& SymbolLayer::getFilter() const { // Layout properties PropertyValue<SymbolPlacementType> SymbolLayer::getDefaultSymbolPlacement() { - return { SymbolPlacementType::Point }; + return SymbolPlacement::defaultValue(); } PropertyValue<SymbolPlacementType> SymbolLayer::getSymbolPlacement() const { - return impl->layout.symbolPlacement.get(); + return impl->layout.unevaluated.get<SymbolPlacement>(); } void SymbolLayer::setSymbolPlacement(PropertyValue<SymbolPlacementType> value) { if (value == getSymbolPlacement()) return; - impl->layout.symbolPlacement.set(value); + impl->layout.unevaluated.get<SymbolPlacement>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "symbol-placement"); } PropertyValue<float> SymbolLayer::getDefaultSymbolSpacing() { - return { 250 }; + return SymbolSpacing::defaultValue(); } PropertyValue<float> SymbolLayer::getSymbolSpacing() const { - return impl->layout.symbolSpacing.get(); + return impl->layout.unevaluated.get<SymbolSpacing>(); } void SymbolLayer::setSymbolSpacing(PropertyValue<float> value) { if (value == getSymbolSpacing()) return; - impl->layout.symbolSpacing.set(value); + impl->layout.unevaluated.get<SymbolSpacing>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "symbol-spacing"); } PropertyValue<bool> SymbolLayer::getDefaultSymbolAvoidEdges() { - return { false }; + return SymbolAvoidEdges::defaultValue(); } PropertyValue<bool> SymbolLayer::getSymbolAvoidEdges() const { - return impl->layout.symbolAvoidEdges.get(); + return impl->layout.unevaluated.get<SymbolAvoidEdges>(); } void SymbolLayer::setSymbolAvoidEdges(PropertyValue<bool> value) { if (value == getSymbolAvoidEdges()) return; - impl->layout.symbolAvoidEdges.set(value); + impl->layout.unevaluated.get<SymbolAvoidEdges>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "symbol-avoid-edges"); } PropertyValue<bool> SymbolLayer::getDefaultIconAllowOverlap() { - return { false }; + return IconAllowOverlap::defaultValue(); } PropertyValue<bool> SymbolLayer::getIconAllowOverlap() const { - return impl->layout.iconAllowOverlap.get(); + return impl->layout.unevaluated.get<IconAllowOverlap>(); } void SymbolLayer::setIconAllowOverlap(PropertyValue<bool> value) { if (value == getIconAllowOverlap()) return; - impl->layout.iconAllowOverlap.set(value); + impl->layout.unevaluated.get<IconAllowOverlap>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "icon-allow-overlap"); } PropertyValue<bool> SymbolLayer::getDefaultIconIgnorePlacement() { - return { false }; + return IconIgnorePlacement::defaultValue(); } PropertyValue<bool> SymbolLayer::getIconIgnorePlacement() const { - return impl->layout.iconIgnorePlacement.get(); + return impl->layout.unevaluated.get<IconIgnorePlacement>(); } void SymbolLayer::setIconIgnorePlacement(PropertyValue<bool> value) { if (value == getIconIgnorePlacement()) return; - impl->layout.iconIgnorePlacement.set(value); + impl->layout.unevaluated.get<IconIgnorePlacement>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "icon-ignore-placement"); } PropertyValue<bool> SymbolLayer::getDefaultIconOptional() { - return { false }; + return IconOptional::defaultValue(); } PropertyValue<bool> SymbolLayer::getIconOptional() const { - return impl->layout.iconOptional.get(); + return impl->layout.unevaluated.get<IconOptional>(); } void SymbolLayer::setIconOptional(PropertyValue<bool> value) { if (value == getIconOptional()) return; - impl->layout.iconOptional.set(value); + impl->layout.unevaluated.get<IconOptional>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "icon-optional"); } PropertyValue<AlignmentType> SymbolLayer::getDefaultIconRotationAlignment() { - return { AlignmentType::Auto }; + return IconRotationAlignment::defaultValue(); } PropertyValue<AlignmentType> SymbolLayer::getIconRotationAlignment() const { - return impl->layout.iconRotationAlignment.get(); + return impl->layout.unevaluated.get<IconRotationAlignment>(); } void SymbolLayer::setIconRotationAlignment(PropertyValue<AlignmentType> value) { if (value == getIconRotationAlignment()) return; - impl->layout.iconRotationAlignment.set(value); + impl->layout.unevaluated.get<IconRotationAlignment>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "icon-rotation-alignment"); } PropertyValue<float> SymbolLayer::getDefaultIconSize() { - return { 1 }; + return IconSize::defaultValue(); } PropertyValue<float> SymbolLayer::getIconSize() const { - return impl->layout.iconSize.get(); + return impl->layout.unevaluated.get<IconSize>(); } void SymbolLayer::setIconSize(PropertyValue<float> value) { if (value == getIconSize()) return; - impl->layout.iconSize.set(value); + impl->layout.unevaluated.get<IconSize>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "icon-size"); } PropertyValue<IconTextFitType> SymbolLayer::getDefaultIconTextFit() { - return { IconTextFitType::None }; + return IconTextFit::defaultValue(); } PropertyValue<IconTextFitType> SymbolLayer::getIconTextFit() const { - return impl->layout.iconTextFit.get(); + return impl->layout.unevaluated.get<IconTextFit>(); } void SymbolLayer::setIconTextFit(PropertyValue<IconTextFitType> value) { if (value == getIconTextFit()) return; - impl->layout.iconTextFit.set(value); + impl->layout.unevaluated.get<IconTextFit>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "icon-text-fit"); } PropertyValue<std::array<float, 4>> SymbolLayer::getDefaultIconTextFitPadding() { - return { {{ 0, 0, 0, 0 }} }; + return IconTextFitPadding::defaultValue(); } PropertyValue<std::array<float, 4>> SymbolLayer::getIconTextFitPadding() const { - return impl->layout.iconTextFitPadding.get(); + return impl->layout.unevaluated.get<IconTextFitPadding>(); } void SymbolLayer::setIconTextFitPadding(PropertyValue<std::array<float, 4>> value) { if (value == getIconTextFitPadding()) return; - impl->layout.iconTextFitPadding.set(value); + impl->layout.unevaluated.get<IconTextFitPadding>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "icon-text-fit-padding"); } PropertyValue<std::string> SymbolLayer::getDefaultIconImage() { - return { "" }; + return IconImage::defaultValue(); } PropertyValue<std::string> SymbolLayer::getIconImage() const { - return impl->layout.iconImage.get(); + return impl->layout.unevaluated.get<IconImage>(); } void SymbolLayer::setIconImage(PropertyValue<std::string> value) { if (value == getIconImage()) return; - impl->layout.iconImage.set(value); + impl->layout.unevaluated.get<IconImage>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "icon-image"); } PropertyValue<float> SymbolLayer::getDefaultIconRotate() { - return { 0 }; + return IconRotate::defaultValue(); } PropertyValue<float> SymbolLayer::getIconRotate() const { - return impl->layout.iconRotate.get(); + return impl->layout.unevaluated.get<IconRotate>(); } void SymbolLayer::setIconRotate(PropertyValue<float> value) { if (value == getIconRotate()) return; - impl->layout.iconRotate.set(value); + impl->layout.unevaluated.get<IconRotate>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "icon-rotate"); } PropertyValue<float> SymbolLayer::getDefaultIconPadding() { - return { 2 }; + return IconPadding::defaultValue(); } PropertyValue<float> SymbolLayer::getIconPadding() const { - return impl->layout.iconPadding.get(); + return impl->layout.unevaluated.get<IconPadding>(); } void SymbolLayer::setIconPadding(PropertyValue<float> value) { if (value == getIconPadding()) return; - impl->layout.iconPadding.set(value); + impl->layout.unevaluated.get<IconPadding>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "icon-padding"); } PropertyValue<bool> SymbolLayer::getDefaultIconKeepUpright() { - return { false }; + return IconKeepUpright::defaultValue(); } PropertyValue<bool> SymbolLayer::getIconKeepUpright() const { - return impl->layout.iconKeepUpright.get(); + return impl->layout.unevaluated.get<IconKeepUpright>(); } void SymbolLayer::setIconKeepUpright(PropertyValue<bool> value) { if (value == getIconKeepUpright()) return; - impl->layout.iconKeepUpright.set(value); + impl->layout.unevaluated.get<IconKeepUpright>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "icon-keep-upright"); } PropertyValue<std::array<float, 2>> SymbolLayer::getDefaultIconOffset() { - return { {{ 0, 0 }} }; + return IconOffset::defaultValue(); } PropertyValue<std::array<float, 2>> SymbolLayer::getIconOffset() const { - return impl->layout.iconOffset.get(); + return impl->layout.unevaluated.get<IconOffset>(); } void SymbolLayer::setIconOffset(PropertyValue<std::array<float, 2>> value) { if (value == getIconOffset()) return; - impl->layout.iconOffset.set(value); + impl->layout.unevaluated.get<IconOffset>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "icon-offset"); } PropertyValue<AlignmentType> SymbolLayer::getDefaultTextPitchAlignment() { - return { AlignmentType::Auto }; + return TextPitchAlignment::defaultValue(); } PropertyValue<AlignmentType> SymbolLayer::getTextPitchAlignment() const { - return impl->layout.textPitchAlignment.get(); + return impl->layout.unevaluated.get<TextPitchAlignment>(); } void SymbolLayer::setTextPitchAlignment(PropertyValue<AlignmentType> value) { if (value == getTextPitchAlignment()) return; - impl->layout.textPitchAlignment.set(value); + impl->layout.unevaluated.get<TextPitchAlignment>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "text-pitch-alignment"); } PropertyValue<AlignmentType> SymbolLayer::getDefaultTextRotationAlignment() { - return { AlignmentType::Auto }; + return TextRotationAlignment::defaultValue(); } PropertyValue<AlignmentType> SymbolLayer::getTextRotationAlignment() const { - return impl->layout.textRotationAlignment.get(); + return impl->layout.unevaluated.get<TextRotationAlignment>(); } void SymbolLayer::setTextRotationAlignment(PropertyValue<AlignmentType> value) { if (value == getTextRotationAlignment()) return; - impl->layout.textRotationAlignment.set(value); + impl->layout.unevaluated.get<TextRotationAlignment>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "text-rotation-alignment"); } PropertyValue<std::string> SymbolLayer::getDefaultTextField() { - return { "" }; + return TextField::defaultValue(); } PropertyValue<std::string> SymbolLayer::getTextField() const { - return impl->layout.textField.get(); + return impl->layout.unevaluated.get<TextField>(); } void SymbolLayer::setTextField(PropertyValue<std::string> value) { if (value == getTextField()) return; - impl->layout.textField.set(value); + impl->layout.unevaluated.get<TextField>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "text-field"); } PropertyValue<std::vector<std::string>> SymbolLayer::getDefaultTextFont() { - return { { "Open Sans Regular", "Arial Unicode MS Regular" } }; + return TextFont::defaultValue(); } PropertyValue<std::vector<std::string>> SymbolLayer::getTextFont() const { - return impl->layout.textFont.get(); + return impl->layout.unevaluated.get<TextFont>(); } void SymbolLayer::setTextFont(PropertyValue<std::vector<std::string>> value) { if (value == getTextFont()) return; - impl->layout.textFont.set(value); + impl->layout.unevaluated.get<TextFont>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "text-font"); } PropertyValue<float> SymbolLayer::getDefaultTextSize() { - return { 16 }; + return TextSize::defaultValue(); } PropertyValue<float> SymbolLayer::getTextSize() const { - return impl->layout.textSize.get(); + return impl->layout.unevaluated.get<TextSize>(); } void SymbolLayer::setTextSize(PropertyValue<float> value) { if (value == getTextSize()) return; - impl->layout.textSize.set(value); + impl->layout.unevaluated.get<TextSize>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "text-size"); } PropertyValue<float> SymbolLayer::getDefaultTextMaxWidth() { - return { 10 }; + return TextMaxWidth::defaultValue(); } PropertyValue<float> SymbolLayer::getTextMaxWidth() const { - return impl->layout.textMaxWidth.get(); + return impl->layout.unevaluated.get<TextMaxWidth>(); } void SymbolLayer::setTextMaxWidth(PropertyValue<float> value) { if (value == getTextMaxWidth()) return; - impl->layout.textMaxWidth.set(value); + impl->layout.unevaluated.get<TextMaxWidth>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "text-max-width"); } PropertyValue<float> SymbolLayer::getDefaultTextLineHeight() { - return { 1.2 }; + return TextLineHeight::defaultValue(); } PropertyValue<float> SymbolLayer::getTextLineHeight() const { - return impl->layout.textLineHeight.get(); + return impl->layout.unevaluated.get<TextLineHeight>(); } void SymbolLayer::setTextLineHeight(PropertyValue<float> value) { if (value == getTextLineHeight()) return; - impl->layout.textLineHeight.set(value); + impl->layout.unevaluated.get<TextLineHeight>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "text-line-height"); } PropertyValue<float> SymbolLayer::getDefaultTextLetterSpacing() { - return { 0 }; + return TextLetterSpacing::defaultValue(); } PropertyValue<float> SymbolLayer::getTextLetterSpacing() const { - return impl->layout.textLetterSpacing.get(); + return impl->layout.unevaluated.get<TextLetterSpacing>(); } void SymbolLayer::setTextLetterSpacing(PropertyValue<float> value) { if (value == getTextLetterSpacing()) return; - impl->layout.textLetterSpacing.set(value); + impl->layout.unevaluated.get<TextLetterSpacing>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "text-letter-spacing"); } PropertyValue<TextJustifyType> SymbolLayer::getDefaultTextJustify() { - return { TextJustifyType::Center }; + return TextJustify::defaultValue(); } PropertyValue<TextJustifyType> SymbolLayer::getTextJustify() const { - return impl->layout.textJustify.get(); + return impl->layout.unevaluated.get<TextJustify>(); } void SymbolLayer::setTextJustify(PropertyValue<TextJustifyType> value) { if (value == getTextJustify()) return; - impl->layout.textJustify.set(value); + impl->layout.unevaluated.get<TextJustify>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "text-justify"); } PropertyValue<TextAnchorType> SymbolLayer::getDefaultTextAnchor() { - return { TextAnchorType::Center }; + return TextAnchor::defaultValue(); } PropertyValue<TextAnchorType> SymbolLayer::getTextAnchor() const { - return impl->layout.textAnchor.get(); + return impl->layout.unevaluated.get<TextAnchor>(); } void SymbolLayer::setTextAnchor(PropertyValue<TextAnchorType> value) { if (value == getTextAnchor()) return; - impl->layout.textAnchor.set(value); + impl->layout.unevaluated.get<TextAnchor>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "text-anchor"); } PropertyValue<float> SymbolLayer::getDefaultTextMaxAngle() { - return { 45 }; + return TextMaxAngle::defaultValue(); } PropertyValue<float> SymbolLayer::getTextMaxAngle() const { - return impl->layout.textMaxAngle.get(); + return impl->layout.unevaluated.get<TextMaxAngle>(); } void SymbolLayer::setTextMaxAngle(PropertyValue<float> value) { if (value == getTextMaxAngle()) return; - impl->layout.textMaxAngle.set(value); + impl->layout.unevaluated.get<TextMaxAngle>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "text-max-angle"); } PropertyValue<float> SymbolLayer::getDefaultTextRotate() { - return { 0 }; + return TextRotate::defaultValue(); } PropertyValue<float> SymbolLayer::getTextRotate() const { - return impl->layout.textRotate.get(); + return impl->layout.unevaluated.get<TextRotate>(); } void SymbolLayer::setTextRotate(PropertyValue<float> value) { if (value == getTextRotate()) return; - impl->layout.textRotate.set(value); + impl->layout.unevaluated.get<TextRotate>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "text-rotate"); } PropertyValue<float> SymbolLayer::getDefaultTextPadding() { - return { 2 }; + return TextPadding::defaultValue(); } PropertyValue<float> SymbolLayer::getTextPadding() const { - return impl->layout.textPadding.get(); + return impl->layout.unevaluated.get<TextPadding>(); } void SymbolLayer::setTextPadding(PropertyValue<float> value) { if (value == getTextPadding()) return; - impl->layout.textPadding.set(value); + impl->layout.unevaluated.get<TextPadding>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "text-padding"); } PropertyValue<bool> SymbolLayer::getDefaultTextKeepUpright() { - return { true }; + return TextKeepUpright::defaultValue(); } PropertyValue<bool> SymbolLayer::getTextKeepUpright() const { - return impl->layout.textKeepUpright.get(); + return impl->layout.unevaluated.get<TextKeepUpright>(); } void SymbolLayer::setTextKeepUpright(PropertyValue<bool> value) { if (value == getTextKeepUpright()) return; - impl->layout.textKeepUpright.set(value); + impl->layout.unevaluated.get<TextKeepUpright>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "text-keep-upright"); } PropertyValue<TextTransformType> SymbolLayer::getDefaultTextTransform() { - return { TextTransformType::None }; + return TextTransform::defaultValue(); } PropertyValue<TextTransformType> SymbolLayer::getTextTransform() const { - return impl->layout.textTransform.get(); + return impl->layout.unevaluated.get<TextTransform>(); } void SymbolLayer::setTextTransform(PropertyValue<TextTransformType> value) { if (value == getTextTransform()) return; - impl->layout.textTransform.set(value); + impl->layout.unevaluated.get<TextTransform>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "text-transform"); } PropertyValue<std::array<float, 2>> SymbolLayer::getDefaultTextOffset() { - return { {{ 0, 0 }} }; + return TextOffset::defaultValue(); } PropertyValue<std::array<float, 2>> SymbolLayer::getTextOffset() const { - return impl->layout.textOffset.get(); + return impl->layout.unevaluated.get<TextOffset>(); } void SymbolLayer::setTextOffset(PropertyValue<std::array<float, 2>> value) { if (value == getTextOffset()) return; - impl->layout.textOffset.set(value); + impl->layout.unevaluated.get<TextOffset>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "text-offset"); } PropertyValue<bool> SymbolLayer::getDefaultTextAllowOverlap() { - return { false }; + return TextAllowOverlap::defaultValue(); } PropertyValue<bool> SymbolLayer::getTextAllowOverlap() const { - return impl->layout.textAllowOverlap.get(); + return impl->layout.unevaluated.get<TextAllowOverlap>(); } void SymbolLayer::setTextAllowOverlap(PropertyValue<bool> value) { if (value == getTextAllowOverlap()) return; - impl->layout.textAllowOverlap.set(value); + impl->layout.unevaluated.get<TextAllowOverlap>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "text-allow-overlap"); } PropertyValue<bool> SymbolLayer::getDefaultTextIgnorePlacement() { - return { false }; + return TextIgnorePlacement::defaultValue(); } PropertyValue<bool> SymbolLayer::getTextIgnorePlacement() const { - return impl->layout.textIgnorePlacement.get(); + return impl->layout.unevaluated.get<TextIgnorePlacement>(); } void SymbolLayer::setTextIgnorePlacement(PropertyValue<bool> value) { if (value == getTextIgnorePlacement()) return; - impl->layout.textIgnorePlacement.set(value); + impl->layout.unevaluated.get<TextIgnorePlacement>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "text-ignore-placement"); } PropertyValue<bool> SymbolLayer::getDefaultTextOptional() { - return { false }; + return TextOptional::defaultValue(); } PropertyValue<bool> SymbolLayer::getTextOptional() const { - return impl->layout.textOptional.get(); + return impl->layout.unevaluated.get<TextOptional>(); } void SymbolLayer::setTextOptional(PropertyValue<bool> value) { if (value == getTextOptional()) return; - impl->layout.textOptional.set(value); + impl->layout.unevaluated.get<TextOptional>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "text-optional"); } @@ -543,13 +543,13 @@ PropertyValue<float> SymbolLayer::getDefaultIconOpacity() { } PropertyValue<float> SymbolLayer::getIconOpacity(const optional<std::string>& klass) const { - return impl->paint.iconOpacity.get(klass); + return impl->paint.get<IconOpacity>(klass); } void SymbolLayer::setIconOpacity(PropertyValue<float> value, const optional<std::string>& klass) { if (value == getIconOpacity(klass)) return; - impl->paint.iconOpacity.set(value, klass); + impl->paint.set<IconOpacity>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -558,13 +558,13 @@ PropertyValue<Color> SymbolLayer::getDefaultIconColor() { } PropertyValue<Color> SymbolLayer::getIconColor(const optional<std::string>& klass) const { - return impl->paint.iconColor.get(klass); + return impl->paint.get<IconColor>(klass); } void SymbolLayer::setIconColor(PropertyValue<Color> value, const optional<std::string>& klass) { if (value == getIconColor(klass)) return; - impl->paint.iconColor.set(value, klass); + impl->paint.set<IconColor>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -573,13 +573,13 @@ PropertyValue<Color> SymbolLayer::getDefaultIconHaloColor() { } PropertyValue<Color> SymbolLayer::getIconHaloColor(const optional<std::string>& klass) const { - return impl->paint.iconHaloColor.get(klass); + return impl->paint.get<IconHaloColor>(klass); } void SymbolLayer::setIconHaloColor(PropertyValue<Color> value, const optional<std::string>& klass) { if (value == getIconHaloColor(klass)) return; - impl->paint.iconHaloColor.set(value, klass); + impl->paint.set<IconHaloColor>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -588,13 +588,13 @@ PropertyValue<float> SymbolLayer::getDefaultIconHaloWidth() { } PropertyValue<float> SymbolLayer::getIconHaloWidth(const optional<std::string>& klass) const { - return impl->paint.iconHaloWidth.get(klass); + return impl->paint.get<IconHaloWidth>(klass); } void SymbolLayer::setIconHaloWidth(PropertyValue<float> value, const optional<std::string>& klass) { if (value == getIconHaloWidth(klass)) return; - impl->paint.iconHaloWidth.set(value, klass); + impl->paint.set<IconHaloWidth>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -603,13 +603,13 @@ PropertyValue<float> SymbolLayer::getDefaultIconHaloBlur() { } PropertyValue<float> SymbolLayer::getIconHaloBlur(const optional<std::string>& klass) const { - return impl->paint.iconHaloBlur.get(klass); + return impl->paint.get<IconHaloBlur>(klass); } void SymbolLayer::setIconHaloBlur(PropertyValue<float> value, const optional<std::string>& klass) { if (value == getIconHaloBlur(klass)) return; - impl->paint.iconHaloBlur.set(value, klass); + impl->paint.set<IconHaloBlur>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -618,13 +618,13 @@ PropertyValue<std::array<float, 2>> SymbolLayer::getDefaultIconTranslate() { } PropertyValue<std::array<float, 2>> SymbolLayer::getIconTranslate(const optional<std::string>& klass) const { - return impl->paint.iconTranslate.get(klass); + return impl->paint.get<IconTranslate>(klass); } void SymbolLayer::setIconTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) { if (value == getIconTranslate(klass)) return; - impl->paint.iconTranslate.set(value, klass); + impl->paint.set<IconTranslate>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -633,13 +633,13 @@ PropertyValue<TranslateAnchorType> SymbolLayer::getDefaultIconTranslateAnchor() } PropertyValue<TranslateAnchorType> SymbolLayer::getIconTranslateAnchor(const optional<std::string>& klass) const { - return impl->paint.iconTranslateAnchor.get(klass); + return impl->paint.get<IconTranslateAnchor>(klass); } void SymbolLayer::setIconTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) { if (value == getIconTranslateAnchor(klass)) return; - impl->paint.iconTranslateAnchor.set(value, klass); + impl->paint.set<IconTranslateAnchor>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -648,13 +648,13 @@ PropertyValue<float> SymbolLayer::getDefaultTextOpacity() { } PropertyValue<float> SymbolLayer::getTextOpacity(const optional<std::string>& klass) const { - return impl->paint.textOpacity.get(klass); + return impl->paint.get<TextOpacity>(klass); } void SymbolLayer::setTextOpacity(PropertyValue<float> value, const optional<std::string>& klass) { if (value == getTextOpacity(klass)) return; - impl->paint.textOpacity.set(value, klass); + impl->paint.set<TextOpacity>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -663,13 +663,13 @@ PropertyValue<Color> SymbolLayer::getDefaultTextColor() { } PropertyValue<Color> SymbolLayer::getTextColor(const optional<std::string>& klass) const { - return impl->paint.textColor.get(klass); + return impl->paint.get<TextColor>(klass); } void SymbolLayer::setTextColor(PropertyValue<Color> value, const optional<std::string>& klass) { if (value == getTextColor(klass)) return; - impl->paint.textColor.set(value, klass); + impl->paint.set<TextColor>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -678,13 +678,13 @@ PropertyValue<Color> SymbolLayer::getDefaultTextHaloColor() { } PropertyValue<Color> SymbolLayer::getTextHaloColor(const optional<std::string>& klass) const { - return impl->paint.textHaloColor.get(klass); + return impl->paint.get<TextHaloColor>(klass); } void SymbolLayer::setTextHaloColor(PropertyValue<Color> value, const optional<std::string>& klass) { if (value == getTextHaloColor(klass)) return; - impl->paint.textHaloColor.set(value, klass); + impl->paint.set<TextHaloColor>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -693,13 +693,13 @@ PropertyValue<float> SymbolLayer::getDefaultTextHaloWidth() { } PropertyValue<float> SymbolLayer::getTextHaloWidth(const optional<std::string>& klass) const { - return impl->paint.textHaloWidth.get(klass); + return impl->paint.get<TextHaloWidth>(klass); } void SymbolLayer::setTextHaloWidth(PropertyValue<float> value, const optional<std::string>& klass) { if (value == getTextHaloWidth(klass)) return; - impl->paint.textHaloWidth.set(value, klass); + impl->paint.set<TextHaloWidth>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -708,13 +708,13 @@ PropertyValue<float> SymbolLayer::getDefaultTextHaloBlur() { } PropertyValue<float> SymbolLayer::getTextHaloBlur(const optional<std::string>& klass) const { - return impl->paint.textHaloBlur.get(klass); + return impl->paint.get<TextHaloBlur>(klass); } void SymbolLayer::setTextHaloBlur(PropertyValue<float> value, const optional<std::string>& klass) { if (value == getTextHaloBlur(klass)) return; - impl->paint.textHaloBlur.set(value, klass); + impl->paint.set<TextHaloBlur>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -723,13 +723,13 @@ PropertyValue<std::array<float, 2>> SymbolLayer::getDefaultTextTranslate() { } PropertyValue<std::array<float, 2>> SymbolLayer::getTextTranslate(const optional<std::string>& klass) const { - return impl->paint.textTranslate.get(klass); + return impl->paint.get<TextTranslate>(klass); } void SymbolLayer::setTextTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) { if (value == getTextTranslate(klass)) return; - impl->paint.textTranslate.set(value, klass); + impl->paint.set<TextTranslate>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } @@ -738,13 +738,13 @@ PropertyValue<TranslateAnchorType> SymbolLayer::getDefaultTextTranslateAnchor() } PropertyValue<TranslateAnchorType> SymbolLayer::getTextTranslateAnchor(const optional<std::string>& klass) const { - return impl->paint.textTranslateAnchor.get(klass); + return impl->paint.get<TextTranslateAnchor>(klass); } void SymbolLayer::setTextTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) { if (value == getTextTranslateAnchor(klass)) return; - impl->paint.textTranslateAnchor.set(value, klass); + impl->paint.set<TextTranslateAnchor>(value, klass); impl->observer->onLayerPaintPropertyChanged(*this); } diff --git a/src/mbgl/style/layers/symbol_layer_impl.cpp b/src/mbgl/style/layers/symbol_layer_impl.cpp index e85f3a90f9..957bc1993e 100644 --- a/src/mbgl/style/layers/symbol_layer_impl.cpp +++ b/src/mbgl/style/layers/symbol_layer_impl.cpp @@ -10,20 +10,18 @@ void SymbolLayer::Impl::cascade(const CascadeParameters& parameters) { paint.cascade(parameters); } -bool SymbolLayer::Impl::recalculate(const CalculationParameters& parameters) { - bool hasTransitions = paint.recalculate(parameters); +bool SymbolLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) { + paint.evaluate(parameters); // text-size and icon-size are layout properties but they also need to be evaluated as paint properties: - layout.iconSize.calculate(parameters); - layout.textSize.calculate(parameters); - iconSize = layout.iconSize; - textSize = layout.textSize; + iconSize = layout.evaluate<IconSize>(parameters); + textSize = layout.evaluate<TextSize>(parameters); - passes = ((paint.iconOpacity > 0 && (paint.iconColor.value.a > 0 || paint.iconHaloColor.value.a > 0) && iconSize > 0) - || (paint.textOpacity > 0 && (paint.textColor.value.a > 0 || paint.textHaloColor.value.a > 0) && textSize > 0)) + passes = ((paint.evaluated.get<IconOpacity>() > 0 && (paint.evaluated.get<IconColor>().a > 0 || paint.evaluated.get<IconHaloColor>().a > 0) && iconSize > 0) + || (paint.evaluated.get<TextOpacity>() > 0 && (paint.evaluated.get<TextColor>().a > 0 || paint.evaluated.get<TextHaloColor>().a > 0) && textSize > 0)) ? RenderPass::Translucent : RenderPass::None; - return hasTransitions; + return paint.hasTransition(); } std::unique_ptr<Bucket> SymbolLayer::Impl::createBucket(BucketParameters&) const { @@ -32,37 +30,34 @@ std::unique_ptr<Bucket> SymbolLayer::Impl::createBucket(BucketParameters&) const } std::unique_ptr<SymbolLayout> SymbolLayer::Impl::createLayout(BucketParameters& parameters) const { - SymbolLayoutProperties layoutProperties = layout; + PropertyEvaluationParameters p(parameters.tileID.overscaledZ); + SymbolLayoutProperties::Evaluated evaluated = layout.evaluate(p); - CalculationParameters p(parameters.tileID.overscaledZ); - layoutProperties.recalculate(p); - - if (layoutProperties.iconRotationAlignment.value == AlignmentType::Auto) { - if (layoutProperties.symbolPlacement.value == SymbolPlacementType::Line) { - layoutProperties.iconRotationAlignment.value = AlignmentType::Map; + if (evaluated.get<IconRotationAlignment>() == AlignmentType::Auto) { + if (evaluated.get<SymbolPlacement>() == SymbolPlacementType::Line) { + evaluated.get<IconRotationAlignment>() = AlignmentType::Map; } else { - layoutProperties.iconRotationAlignment.value = AlignmentType::Viewport; + evaluated.get<IconRotationAlignment>() = AlignmentType::Viewport; } } - if (layoutProperties.textRotationAlignment.value == AlignmentType::Auto) { - if (layoutProperties.symbolPlacement.value == SymbolPlacementType::Line) { - layoutProperties.textRotationAlignment.value = AlignmentType::Map; + if (evaluated.get<TextRotationAlignment>() == AlignmentType::Auto) { + if (evaluated.get<SymbolPlacement>() == SymbolPlacementType::Line) { + evaluated.get<TextRotationAlignment>() = AlignmentType::Map; } else { - layoutProperties.textRotationAlignment.value = AlignmentType::Viewport; + evaluated.get<TextRotationAlignment>() = AlignmentType::Viewport; } } // If unspecified `text-pitch-alignment` inherits `text-rotation-alignment` - if (layoutProperties.textPitchAlignment.value == AlignmentType::Auto) { - layoutProperties.textPitchAlignment.value = layoutProperties.textRotationAlignment.value; + if (evaluated.get<TextPitchAlignment>() == AlignmentType::Auto) { + evaluated.get<TextPitchAlignment>() = evaluated.get<TextRotationAlignment>(); } - layoutProperties.textSize.calculate(CalculationParameters(18)); - float textMaxSize = layoutProperties.textSize; + float textMaxSize = layout.evaluate<TextSize>(PropertyEvaluationParameters(18)); - layoutProperties.iconSize.calculate(CalculationParameters(p.z + 1)); - layoutProperties.textSize.calculate(CalculationParameters(p.z + 1)); + evaluated.get<IconSize>() = layout.evaluate<IconSize>(PropertyEvaluationParameters(p.z + 1)); + evaluated.get<TextSize>() = layout.evaluate<TextSize>(PropertyEvaluationParameters(p.z + 1)); return std::make_unique<SymbolLayout>(id, parameters.layer.getName(), @@ -71,10 +66,44 @@ std::unique_ptr<SymbolLayout> SymbolLayer::Impl::createLayout(BucketParameters& parameters.mode, parameters.layer, filter, - layoutProperties, + evaluated, textMaxSize, *spriteAtlas); } +SymbolPropertyValues SymbolLayer::Impl::iconPropertyValues(const SymbolLayoutProperties::Evaluated& layout_) const { + return SymbolPropertyValues { + layout_.get<IconRotationAlignment>(), // icon-pitch-alignment is not yet implemented; inherit the rotation alignment + layout_.get<IconRotationAlignment>(), + layout_.get<IconSize>(), + paint.evaluated.get<IconOpacity>(), + paint.evaluated.get<IconColor>(), + paint.evaluated.get<IconHaloColor>(), + paint.evaluated.get<IconHaloWidth>(), + paint.evaluated.get<IconHaloBlur>(), + paint.evaluated.get<IconTranslate>(), + paint.evaluated.get<IconTranslateAnchor>(), + iconSize, + 1.0f + }; +} + +SymbolPropertyValues SymbolLayer::Impl::textPropertyValues(const SymbolLayoutProperties::Evaluated& layout_) const { + return SymbolPropertyValues { + layout_.get<TextPitchAlignment>(), + layout_.get<TextRotationAlignment>(), + layout_.get<TextSize>(), + paint.evaluated.get<TextOpacity>(), + paint.evaluated.get<TextColor>(), + paint.evaluated.get<TextHaloColor>(), + paint.evaluated.get<TextHaloWidth>(), + paint.evaluated.get<TextHaloBlur>(), + paint.evaluated.get<TextTranslate>(), + paint.evaluated.get<TextTranslateAnchor>(), + textSize, + 24.0f + }; +} + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layers/symbol_layer_impl.hpp b/src/mbgl/style/layers/symbol_layer_impl.hpp index fe37ba86ea..46ed75b231 100644 --- a/src/mbgl/style/layers/symbol_layer_impl.hpp +++ b/src/mbgl/style/layers/symbol_layer_impl.hpp @@ -11,17 +11,50 @@ class SymbolLayout; namespace style { +// Repackaging evaluated values from SymbolLayoutProperties + SymbolPaintProperties +// for genericity over icons vs. text. +class SymbolPropertyValues { +public: + // Layout + AlignmentType pitchAlignment; + AlignmentType rotationAlignment; + float layoutSize; + + // Paint + float opacity; + Color color; + Color haloColor; + float haloWidth; + float haloBlur; + std::array<float, 2> translate; + TranslateAnchorType translateAnchor; + float paintSize; + + float sdfScale; // Constant (1.0 or 24.0) + + bool hasHalo() const { + return haloColor.a > 0.0f && haloWidth > 0.0f; + } + + bool hasForeground() const { + return color.a > 0.0f; + } +}; + class SymbolLayer::Impl : public Layer::Impl { public: std::unique_ptr<Layer> clone() const override; std::unique_ptr<Layer> cloneRef(const std::string& id) const override; void cascade(const CascadeParameters&) override; - bool recalculate(const CalculationParameters&) override; + bool evaluate(const PropertyEvaluationParameters&) override; std::unique_ptr<Bucket> createBucket(BucketParameters&) const override; std::unique_ptr<SymbolLayout> createLayout(BucketParameters&) const; + SymbolPropertyValues iconPropertyValues(const SymbolLayoutProperties::Evaluated&) const; + SymbolPropertyValues textPropertyValues(const SymbolLayoutProperties::Evaluated&) const; + SymbolLayoutProperties layout; SymbolPaintProperties paint; diff --git a/src/mbgl/style/layers/symbol_layer_properties.cpp b/src/mbgl/style/layers/symbol_layer_properties.cpp index 59a73d3d59..5a1ce713ba 100644 --- a/src/mbgl/style/layers/symbol_layer_properties.cpp +++ b/src/mbgl/style/layers/symbol_layer_properties.cpp @@ -5,80 +5,5 @@ namespace mbgl { namespace style { -void SymbolLayoutProperties::recalculate(const CalculationParameters& parameters) { - symbolPlacement.calculate(parameters); - symbolSpacing.calculate(parameters); - symbolAvoidEdges.calculate(parameters); - iconAllowOverlap.calculate(parameters); - iconIgnorePlacement.calculate(parameters); - iconOptional.calculate(parameters); - iconRotationAlignment.calculate(parameters); - iconSize.calculate(parameters); - iconTextFit.calculate(parameters); - iconTextFitPadding.calculate(parameters); - iconImage.calculate(parameters); - iconRotate.calculate(parameters); - iconPadding.calculate(parameters); - iconKeepUpright.calculate(parameters); - iconOffset.calculate(parameters); - textPitchAlignment.calculate(parameters); - textRotationAlignment.calculate(parameters); - textField.calculate(parameters); - textFont.calculate(parameters); - textSize.calculate(parameters); - textMaxWidth.calculate(parameters); - textLineHeight.calculate(parameters); - textLetterSpacing.calculate(parameters); - textJustify.calculate(parameters); - textAnchor.calculate(parameters); - textMaxAngle.calculate(parameters); - textRotate.calculate(parameters); - textPadding.calculate(parameters); - textKeepUpright.calculate(parameters); - textTransform.calculate(parameters); - textOffset.calculate(parameters); - textAllowOverlap.calculate(parameters); - textIgnorePlacement.calculate(parameters); - textOptional.calculate(parameters); -} - -void SymbolPaintProperties::cascade(const CascadeParameters& parameters) { - iconOpacity.cascade(parameters); - iconColor.cascade(parameters); - iconHaloColor.cascade(parameters); - iconHaloWidth.cascade(parameters); - iconHaloBlur.cascade(parameters); - iconTranslate.cascade(parameters); - iconTranslateAnchor.cascade(parameters); - textOpacity.cascade(parameters); - textColor.cascade(parameters); - textHaloColor.cascade(parameters); - textHaloWidth.cascade(parameters); - textHaloBlur.cascade(parameters); - textTranslate.cascade(parameters); - textTranslateAnchor.cascade(parameters); -} - -bool SymbolPaintProperties::recalculate(const CalculationParameters& parameters) { - bool hasTransitions = false; - - hasTransitions |= iconOpacity.calculate(parameters); - hasTransitions |= iconColor.calculate(parameters); - hasTransitions |= iconHaloColor.calculate(parameters); - hasTransitions |= iconHaloWidth.calculate(parameters); - hasTransitions |= iconHaloBlur.calculate(parameters); - hasTransitions |= iconTranslate.calculate(parameters); - hasTransitions |= iconTranslateAnchor.calculate(parameters); - hasTransitions |= textOpacity.calculate(parameters); - hasTransitions |= textColor.calculate(parameters); - hasTransitions |= textHaloColor.calculate(parameters); - hasTransitions |= textHaloWidth.calculate(parameters); - hasTransitions |= textHaloBlur.calculate(parameters); - hasTransitions |= textTranslate.calculate(parameters); - hasTransitions |= textTranslateAnchor.calculate(parameters); - - return hasTransitions; -} - } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layers/symbol_layer_properties.hpp b/src/mbgl/style/layers/symbol_layer_properties.hpp index fefa0ae05e..8b72c4347a 100644 --- a/src/mbgl/style/layers/symbol_layer_properties.hpp +++ b/src/mbgl/style/layers/symbol_layer_properties.hpp @@ -9,69 +9,251 @@ namespace mbgl { namespace style { -class CascadeParameters; -class CalculationParameters; - -class SymbolLayoutProperties { -public: - void recalculate(const CalculationParameters&); - - LayoutProperty<SymbolPlacementType> symbolPlacement { SymbolPlacementType::Point }; - LayoutProperty<float> symbolSpacing { 250 }; - LayoutProperty<bool> symbolAvoidEdges { false }; - LayoutProperty<bool> iconAllowOverlap { false }; - LayoutProperty<bool> iconIgnorePlacement { false }; - LayoutProperty<bool> iconOptional { false }; - LayoutProperty<AlignmentType> iconRotationAlignment { AlignmentType::Auto }; - LayoutProperty<float> iconSize { 1 }; - LayoutProperty<IconTextFitType> iconTextFit { IconTextFitType::None }; - LayoutProperty<std::array<float, 4>> iconTextFitPadding { {{ 0, 0, 0, 0 }} }; - LayoutProperty<std::string> iconImage { "" }; - LayoutProperty<float> iconRotate { 0 }; - LayoutProperty<float> iconPadding { 2 }; - LayoutProperty<bool> iconKeepUpright { false }; - LayoutProperty<std::array<float, 2>> iconOffset { {{ 0, 0 }} }; - LayoutProperty<AlignmentType> textPitchAlignment { AlignmentType::Auto }; - LayoutProperty<AlignmentType> textRotationAlignment { AlignmentType::Auto }; - LayoutProperty<std::string> textField { "" }; - LayoutProperty<std::vector<std::string>> textFont { { "Open Sans Regular", "Arial Unicode MS Regular" } }; - LayoutProperty<float> textSize { 16 }; - LayoutProperty<float> textMaxWidth { 10 }; - LayoutProperty<float> textLineHeight { 1.2 }; - LayoutProperty<float> textLetterSpacing { 0 }; - LayoutProperty<TextJustifyType> textJustify { TextJustifyType::Center }; - LayoutProperty<TextAnchorType> textAnchor { TextAnchorType::Center }; - LayoutProperty<float> textMaxAngle { 45 }; - LayoutProperty<float> textRotate { 0 }; - LayoutProperty<float> textPadding { 2 }; - LayoutProperty<bool> textKeepUpright { true }; - LayoutProperty<TextTransformType> textTransform { TextTransformType::None }; - LayoutProperty<std::array<float, 2>> textOffset { {{ 0, 0 }} }; - LayoutProperty<bool> textAllowOverlap { false }; - LayoutProperty<bool> textIgnorePlacement { false }; - LayoutProperty<bool> textOptional { false }; -}; - -class SymbolPaintProperties { -public: - void cascade(const CascadeParameters&); - bool recalculate(const CalculationParameters&); - - PaintProperty<float> iconOpacity { 1 }; - PaintProperty<Color> iconColor { Color::black() }; - PaintProperty<Color> iconHaloColor { {} }; - PaintProperty<float> iconHaloWidth { 0 }; - PaintProperty<float> iconHaloBlur { 0 }; - PaintProperty<std::array<float, 2>> iconTranslate { {{ 0, 0 }} }; - PaintProperty<TranslateAnchorType> iconTranslateAnchor { TranslateAnchorType::Map }; - PaintProperty<float> textOpacity { 1 }; - PaintProperty<Color> textColor { Color::black() }; - PaintProperty<Color> textHaloColor { {} }; - PaintProperty<float> textHaloWidth { 0 }; - PaintProperty<float> textHaloBlur { 0 }; - PaintProperty<std::array<float, 2>> textTranslate { {{ 0, 0 }} }; - PaintProperty<TranslateAnchorType> textTranslateAnchor { TranslateAnchorType::Map }; +struct SymbolPlacement : LayoutProperty<SymbolPlacementType> { + static SymbolPlacementType defaultValue() { return SymbolPlacementType::Point; } }; +struct SymbolSpacing : LayoutProperty<float> { + static float defaultValue() { return 250; } +}; + +struct SymbolAvoidEdges : LayoutProperty<bool> { + static bool defaultValue() { return false; } +}; + +struct IconAllowOverlap : LayoutProperty<bool> { + static bool defaultValue() { return false; } +}; + +struct IconIgnorePlacement : LayoutProperty<bool> { + static bool defaultValue() { return false; } +}; + +struct IconOptional : LayoutProperty<bool> { + static bool defaultValue() { return false; } +}; + +struct IconRotationAlignment : LayoutProperty<AlignmentType> { + static AlignmentType defaultValue() { return AlignmentType::Auto; } +}; + +struct IconSize : LayoutProperty<float> { + static float defaultValue() { return 1; } +}; + +struct IconTextFit : LayoutProperty<IconTextFitType> { + static IconTextFitType defaultValue() { return IconTextFitType::None; } +}; + +struct IconTextFitPadding : LayoutProperty<std::array<float, 4>> { + static std::array<float, 4> defaultValue() { return {{ 0, 0, 0, 0 }}; } +}; + +struct IconImage : LayoutProperty<std::string> { + static std::string defaultValue() { return ""; } +}; + +struct IconRotate : LayoutProperty<float> { + static float defaultValue() { return 0; } +}; + +struct IconPadding : LayoutProperty<float> { + static float defaultValue() { return 2; } +}; + +struct IconKeepUpright : LayoutProperty<bool> { + static bool defaultValue() { return false; } +}; + +struct IconOffset : LayoutProperty<std::array<float, 2>> { + static std::array<float, 2> defaultValue() { return {{ 0, 0 }}; } +}; + +struct TextPitchAlignment : LayoutProperty<AlignmentType> { + static AlignmentType defaultValue() { return AlignmentType::Auto; } +}; + +struct TextRotationAlignment : LayoutProperty<AlignmentType> { + static AlignmentType defaultValue() { return AlignmentType::Auto; } +}; + +struct TextField : LayoutProperty<std::string> { + static std::string defaultValue() { return ""; } +}; + +struct TextFont : LayoutProperty<std::vector<std::string>> { + static std::vector<std::string> defaultValue() { return { "Open Sans Regular", "Arial Unicode MS Regular" }; } +}; + +struct TextSize : LayoutProperty<float> { + static float defaultValue() { return 16; } +}; + +struct TextMaxWidth : LayoutProperty<float> { + static float defaultValue() { return 10; } +}; + +struct TextLineHeight : LayoutProperty<float> { + static float defaultValue() { return 1.2; } +}; + +struct TextLetterSpacing : LayoutProperty<float> { + static float defaultValue() { return 0; } +}; + +struct TextJustify : LayoutProperty<TextJustifyType> { + static TextJustifyType defaultValue() { return TextJustifyType::Center; } +}; + +struct TextAnchor : LayoutProperty<TextAnchorType> { + static TextAnchorType defaultValue() { return TextAnchorType::Center; } +}; + +struct TextMaxAngle : LayoutProperty<float> { + static float defaultValue() { return 45; } +}; + +struct TextRotate : LayoutProperty<float> { + static float defaultValue() { return 0; } +}; + +struct TextPadding : LayoutProperty<float> { + static float defaultValue() { return 2; } +}; + +struct TextKeepUpright : LayoutProperty<bool> { + static bool defaultValue() { return true; } +}; + +struct TextTransform : LayoutProperty<TextTransformType> { + static TextTransformType defaultValue() { return TextTransformType::None; } +}; + +struct TextOffset : LayoutProperty<std::array<float, 2>> { + static std::array<float, 2> defaultValue() { return {{ 0, 0 }}; } +}; + +struct TextAllowOverlap : LayoutProperty<bool> { + static bool defaultValue() { return false; } +}; + +struct TextIgnorePlacement : LayoutProperty<bool> { + static bool defaultValue() { return false; } +}; + +struct TextOptional : LayoutProperty<bool> { + static bool defaultValue() { return false; } +}; + +struct IconOpacity : PaintProperty<float> { + static float defaultValue() { return 1; } +}; + +struct IconColor : PaintProperty<Color> { + static Color defaultValue() { return Color::black(); } +}; + +struct IconHaloColor : PaintProperty<Color> { + static Color defaultValue() { return {}; } +}; + +struct IconHaloWidth : PaintProperty<float> { + static float defaultValue() { return 0; } +}; + +struct IconHaloBlur : PaintProperty<float> { + static float defaultValue() { return 0; } +}; + +struct IconTranslate : PaintProperty<std::array<float, 2>> { + static std::array<float, 2> defaultValue() { return {{ 0, 0 }}; } +}; + +struct IconTranslateAnchor : PaintProperty<TranslateAnchorType> { + static TranslateAnchorType defaultValue() { return TranslateAnchorType::Map; } +}; + +struct TextOpacity : PaintProperty<float> { + static float defaultValue() { return 1; } +}; + +struct TextColor : PaintProperty<Color> { + static Color defaultValue() { return Color::black(); } +}; + +struct TextHaloColor : PaintProperty<Color> { + static Color defaultValue() { return {}; } +}; + +struct TextHaloWidth : PaintProperty<float> { + static float defaultValue() { return 0; } +}; + +struct TextHaloBlur : PaintProperty<float> { + static float defaultValue() { return 0; } +}; + +struct TextTranslate : PaintProperty<std::array<float, 2>> { + static std::array<float, 2> defaultValue() { return {{ 0, 0 }}; } +}; + +struct TextTranslateAnchor : PaintProperty<TranslateAnchorType> { + static TranslateAnchorType defaultValue() { return TranslateAnchorType::Map; } +}; + +class SymbolLayoutProperties : public LayoutProperties< + SymbolPlacement, + SymbolSpacing, + SymbolAvoidEdges, + IconAllowOverlap, + IconIgnorePlacement, + IconOptional, + IconRotationAlignment, + IconSize, + IconTextFit, + IconTextFitPadding, + IconImage, + IconRotate, + IconPadding, + IconKeepUpright, + IconOffset, + TextPitchAlignment, + TextRotationAlignment, + TextField, + TextFont, + TextSize, + TextMaxWidth, + TextLineHeight, + TextLetterSpacing, + TextJustify, + TextAnchor, + TextMaxAngle, + TextRotate, + TextPadding, + TextKeepUpright, + TextTransform, + TextOffset, + TextAllowOverlap, + TextIgnorePlacement, + TextOptional +> {}; + +class SymbolPaintProperties : public PaintProperties< + IconOpacity, + IconColor, + IconHaloColor, + IconHaloWidth, + IconHaloBlur, + IconTranslate, + IconTranslateAnchor, + TextOpacity, + TextColor, + TextHaloColor, + TextHaloWidth, + TextHaloBlur, + TextTranslate, + TextTranslateAnchor +> {}; + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layout_property.hpp b/src/mbgl/style/layout_property.hpp index db1a1ebf28..6ea06ce556 100644 --- a/src/mbgl/style/layout_property.hpp +++ b/src/mbgl/style/layout_property.hpp @@ -1,43 +1,55 @@ #pragma once -#include <mbgl/style/property_value.hpp> -#include <mbgl/style/property_parsing.hpp> #include <mbgl/style/property_evaluator.hpp> - -#include <utility> +#include <mbgl/util/indexed_tuple.hpp> namespace mbgl { namespace style { -template <typename T> +class PropertyEvaluationParameters; + +template <class T> class LayoutProperty { public: - explicit LayoutProperty(T v) - : value(std::move(v)), - defaultValue(value) {} - - const PropertyValue<T>& get() const { - return currentValue; - } + using EvaluatorType = PropertyEvaluator<T>; + using UnevaluatedType = PropertyValue<T>; + using EvaluatedType = T; +}; - void set(const PropertyValue<T>& value_) { - currentValue = value_; +template <class... Ps> +class LayoutProperties { +public: + using Properties = TypeList<Ps...>; + using EvaluatedTypes = TypeList<typename Ps::EvaluatedType...>; + using UnevaluatedTypes = TypeList<typename Ps::UnevaluatedType...>; + + template <class TypeList> + using Tuple = IndexedTuple<Properties, TypeList>; + + class Evaluated : public Tuple<EvaluatedTypes> { + public: + using Tuple<EvaluatedTypes>::Tuple; + }; + + class Unevaluated : public Tuple<UnevaluatedTypes> { + public: + using Tuple<UnevaluatedTypes>::Tuple; + }; + + template <class P> + auto evaluate(const PropertyEvaluationParameters& parameters) const { + using Evaluator = typename P::EvaluatorType; + return unevaluated.template get<P>() + .evaluate(Evaluator(parameters, P::defaultValue())); } - void calculate(const CalculationParameters& parameters) { - if (currentValue) { - PropertyEvaluator<T> evaluator(parameters, defaultValue); - value = PropertyValue<T>::visit(currentValue, evaluator); - } + Evaluated evaluate(const PropertyEvaluationParameters& parameters) const { + return Evaluated { + evaluate<Ps>(parameters)... + }; } - // TODO: remove / privatize - operator T() const { return value; } - T value; - -private: - T defaultValue; - PropertyValue<T> currentValue; + Unevaluated unevaluated; }; } // namespace style diff --git a/src/mbgl/style/paint_property.hpp b/src/mbgl/style/paint_property.hpp index 4a620706ec..15df2a77c7 100644 --- a/src/mbgl/style/paint_property.hpp +++ b/src/mbgl/style/paint_property.hpp @@ -1,14 +1,15 @@ #pragma once #include <mbgl/style/class_dictionary.hpp> -#include <mbgl/style/property_parsing.hpp> #include <mbgl/style/property_evaluator.hpp> +#include <mbgl/style/cross_faded_property_evaluator.hpp> #include <mbgl/style/transition_options.hpp> #include <mbgl/style/cascade_parameters.hpp> -#include <mbgl/style/calculation_parameters.hpp> +#include <mbgl/style/property_evaluation_parameters.hpp> #include <mbgl/util/constants.hpp> #include <mbgl/util/interpolate.hpp> -#include <mbgl/util/rapidjson.hpp> +#include <mbgl/util/indexed_tuple.hpp> +#include <mbgl/util/ignore.hpp> #include <unordered_map> #include <utility> @@ -16,29 +17,59 @@ namespace mbgl { namespace style { -template <class T, template <class S> class Evaluator = PropertyEvaluator> -class PaintProperty { +template <class T, class Evaluator> +class UnevaluatedPaintProperty { public: - using Result = typename Evaluator<T>::ResultType; + using Result = typename Evaluator::ResultType; + + UnevaluatedPaintProperty() = default; + + UnevaluatedPaintProperty(PropertyValue<T> value_, + UnevaluatedPaintProperty<T, Evaluator> prior_, + TransitionOptions transition, + TimePoint now) + : begin(now + transition.delay.value_or(Duration::zero())), + end(begin + transition.duration.value_or(Duration::zero())), + value(std::move(value_)) { + if (transition) { + prior = { std::move(prior_) }; + } + } - explicit PaintProperty(T defaultValue_) - : defaultValue(defaultValue_) { - values.emplace(ClassID::Fallback, defaultValue_); + Result evaluate(const PropertyEvaluationParameters& parameters, T defaultValue) { + Result finalValue = value.evaluate(Evaluator(parameters, defaultValue)); + if (!prior) { + // No prior value. + return finalValue; + } else if (parameters.now >= end) { + // Transition from prior value is now complete. + prior = {}; + return finalValue; + } else { + // Interpolate between recursively-calculated prior value and final. + float t = std::chrono::duration<float>(parameters.now - begin) / (end - begin); + return util::interpolate(prior->get().evaluate(parameters, defaultValue), finalValue, util::DEFAULT_TRANSITION_EASE.solve(t, 0.001)); + } } - PaintProperty(const PaintProperty& other) - : defaultValue(other.defaultValue), - values(other.values), - transitions(other.transitions) { + bool hasTransition() const { + return bool(prior); } - PaintProperty& operator=(const PaintProperty& other) { - defaultValue = other.defaultValue; - values = other.values; - transitions = other.transitions; - return *this; + bool isUndefined() const { + return value.isUndefined(); } +private: + optional<mapbox::util::recursive_wrapper<UnevaluatedPaintProperty<T, Evaluator>>> prior; + TimePoint begin; + TimePoint end; + PropertyValue<T> value; +}; + +template <class T> +class CascadingPaintProperty { +public: bool isUndefined() const { return values.find(ClassID::Default) == values.end(); } @@ -57,82 +88,119 @@ public: transitions[klass ? ClassDictionary::Get().lookup(*klass) : ClassID::Default] = transition; } - void cascade(const CascadeParameters& params) { - const bool overrideTransition = !params.transition.delay && !params.transition.duration; - Duration delay = params.transition.delay.value_or(Duration::zero()); - Duration duration = params.transition.duration.value_or(Duration::zero()); + template <class UnevaluatedPaintProperty> + UnevaluatedPaintProperty cascade(const CascadeParameters& params, UnevaluatedPaintProperty prior) const { + TransitionOptions transition; + PropertyValue<T> value; for (const auto classID : params.classes) { - if (values.find(classID) == values.end()) - continue; - - if (overrideTransition && transitions.find(classID) != transitions.end()) { - const TransitionOptions& transition = transitions[classID]; - if (transition.delay) delay = *transition.delay; - if (transition.duration) duration = *transition.duration; + if (values.find(classID) != values.end()) { + value = values.at(classID); + break; } - - cascaded = std::make_unique<CascadedValue>(std::move(cascaded), - params.now + delay, - params.now + delay + duration, - values.at(classID)); - - break; } - assert(cascaded); - } + for (const auto classID : params.classes) { + if (transitions.find(classID) != transitions.end()) { + transition = transitions.at(classID).reverseMerge(transition); + break; + } + } - bool calculate(const CalculationParameters& parameters) { - assert(cascaded); - Evaluator<T> evaluator(parameters, defaultValue); - value = cascaded->calculate(evaluator, parameters.now); - return cascaded->prior.operator bool(); + return UnevaluatedPaintProperty(std::move(value), + std::move(prior), + transition.reverseMerge(params.transition), + params.now); } - // TODO: remove / privatize - operator T() const { return value; } - Result value; - private: - T defaultValue; std::unordered_map<ClassID, PropertyValue<T>> values; std::unordered_map<ClassID, TransitionOptions> transitions; +}; - struct CascadedValue { - CascadedValue(std::unique_ptr<CascadedValue> prior_, - TimePoint begin_, - TimePoint end_, - PropertyValue<T> value_) - : prior(std::move(prior_)), - begin(std::move(begin_)), - end(std::move(end_)), - value(std::move(value_)) { - } +template <class T> +class PaintProperty { +public: + using ValueType = PropertyValue<T>; + using CascadingType = CascadingPaintProperty<T>; + using EvaluatorType = PropertyEvaluator<T>; + using UnevaluatedType = UnevaluatedPaintProperty<T, EvaluatorType>; + using EvaluatedType = T; +}; - Result calculate(const Evaluator<T>& evaluator, const TimePoint& now) { - Result finalValue = PropertyValue<T>::visit(value, evaluator); - if (!prior) { - // No prior value. - return finalValue; - } else if (now >= end) { - // Transition from prior value is now complete. - prior.reset(); - return finalValue; - } else { - // Interpolate between recursively-calculated prior value and final. - float t = std::chrono::duration<float>(now - begin) / (end - begin); - return util::interpolate(prior->calculate(evaluator, now), finalValue, util::DEFAULT_TRANSITION_EASE.solve(t, 0.001)); - } - } +template <class T> +class CrossFadedPaintProperty { +public: + using ValueType = PropertyValue<T>; + using CascadingType = CascadingPaintProperty<T>; + using EvaluatorType = CrossFadedPropertyEvaluator<T>; + using UnevaluatedType = UnevaluatedPaintProperty<T, EvaluatorType>; + using EvaluatedType = Faded<T>; +}; - std::unique_ptr<CascadedValue> prior; - TimePoint begin; - TimePoint end; - PropertyValue<T> value; +template <class... Ps> +class PaintProperties { +public: + using Properties = TypeList<Ps...>; + using EvaluatedTypes = TypeList<typename Ps::EvaluatedType...>; + using UnevaluatedTypes = TypeList<typename Ps::UnevaluatedType...>; + using CascadingTypes = TypeList<typename Ps::CascadingType...>; + + template <class TypeList> + using Tuple = IndexedTuple<Properties, TypeList>; + + class Evaluated : public Tuple<EvaluatedTypes> { + public: + using Tuple<EvaluatedTypes>::Tuple; + }; + + class Unevaluated : public Tuple<UnevaluatedTypes> { + public: + using Tuple<UnevaluatedTypes>::Tuple; }; - std::unique_ptr<CascadedValue> cascaded; + class Cascading : public Tuple<CascadingTypes> { + public: + using Tuple<CascadingTypes>::Tuple; + }; + + template <class P> + auto get(const optional<std::string>& klass) const { + return cascading.template get<P>().get(klass); + } + + template <class P> + void set(const typename P::ValueType& value, const optional<std::string>& klass) { + cascading.template get<P>().set(value, klass); + } + + void cascade(const CascadeParameters& parameters) { + unevaluated = Unevaluated { + cascading.template get<Ps>().cascade(parameters, + std::move(unevaluated.template get<Ps>()))... + }; + } + + template <class P> + auto evaluate(const PropertyEvaluationParameters& parameters) { + return unevaluated.template get<P>().evaluate(parameters, P::defaultValue()); + } + + void evaluate(const PropertyEvaluationParameters& parameters) { + evaluated = Evaluated { + evaluate<Ps>(parameters)... + }; + } + + bool hasTransition() const { + bool result = false; + util::ignore({ result |= unevaluated.template get<Ps>().hasTransition()... }); + return result; + } + + Cascading cascading; + Unevaluated unevaluated; + Evaluated evaluated; }; } // namespace style diff --git a/src/mbgl/style/parser.cpp b/src/mbgl/style/parser.cpp index 059082980d..c6c6e50dd7 100644 --- a/src/mbgl/style/parser.cpp +++ b/src/mbgl/style/parser.cpp @@ -5,7 +5,7 @@ #include <mbgl/style/conversion/source.hpp> #include <mbgl/style/conversion/layer.hpp> -#include <mbgl/platform/log.hpp> +#include <mbgl/util/logging.hpp> #include <mapbox/geojsonvt.hpp> diff --git a/src/mbgl/style/calculation_parameters.hpp b/src/mbgl/style/property_evaluation_parameters.hpp index e1f059c524..2591fc07a1 100644 --- a/src/mbgl/style/calculation_parameters.hpp +++ b/src/mbgl/style/property_evaluation_parameters.hpp @@ -6,12 +6,12 @@ namespace mbgl { namespace style { -class CalculationParameters { +class PropertyEvaluationParameters { public: - explicit CalculationParameters(float z_) + explicit PropertyEvaluationParameters(float z_) : z(z_) {} - CalculationParameters(float z_, + PropertyEvaluationParameters(float z_, TimePoint now_, ZoomHistory zoomHistory_, Duration defaultFadeDuration_) diff --git a/src/mbgl/style/property_evaluator.cpp b/src/mbgl/style/property_evaluator.cpp deleted file mode 100644 index abb3681efa..0000000000 --- a/src/mbgl/style/property_evaluator.cpp +++ /dev/null @@ -1,152 +0,0 @@ -#include <mbgl/style/property_evaluator.hpp> -#include <mbgl/style/calculation_parameters.hpp> -#include <mbgl/style/types.hpp> -#include <mbgl/util/interpolate.hpp> -#include <mbgl/util/chrono.hpp> -#include <mbgl/util/color.hpp> - -#include <cmath> - -namespace mbgl { -namespace style { - -template <typename T> -T defaultStopsValue(); - -template <> bool defaultStopsValue() { return true; } -template <> float defaultStopsValue() { return 1.0f; } -template <> Color defaultStopsValue() { return { 0, 0, 0, 1 }; } -template <> std::vector<float> defaultStopsValue() { return {{ 1, 0 }}; } -template <> std::vector<std::string> defaultStopsValue() { return {{}}; } -template <> std::array<float, 2> defaultStopsValue() { return {{ 0, 0 }}; } -template <> std::array<float, 4> defaultStopsValue() { return {{ 0, 0, 0, 0 }}; } - -template <> std::string defaultStopsValue() { return {}; } -template <> TranslateAnchorType defaultStopsValue() { return {}; } -template <> RotateAnchorType defaultStopsValue() { return {}; } -template <> CirclePitchScaleType defaultStopsValue() { return {}; } -template <> LineCapType defaultStopsValue() { return {}; } -template <> LineJoinType defaultStopsValue() { return {}; } -template <> SymbolPlacementType defaultStopsValue() { return {}; } -template <> TextAnchorType defaultStopsValue() { return {}; } -template <> TextJustifyType defaultStopsValue() { return {}; } -template <> TextTransformType defaultStopsValue() { return {}; } -template <> AlignmentType defaultStopsValue() { return {}; } -template <> IconTextFitType defaultStopsValue() { return {}; }; - -template <typename T> -T PropertyEvaluator<T>::operator()(const Function<T>& fn) const { - float base = fn.getBase(); - const std::vector<std::pair<float, T>>& stops = fn.getStops(); - float z = parameters.z; - bool smaller = false; - float smaller_z = 0.0f; - T smaller_val = T(); - bool larger = false; - float larger_z = 0.0f; - T larger_val = T(); - - for (uint32_t i = 0; i < stops.size(); i++) { - float stop_z = stops[i].first; - T stop_val = stops[i].second; - if (stop_z <= z && (!smaller || smaller_z < stop_z)) { - smaller = true; - smaller_z = stop_z; - smaller_val = stop_val; - } - if (stop_z >= z && (!larger || larger_z > stop_z)) { - larger = true; - larger_z = stop_z; - larger_val = stop_val; - } - } - - if (smaller && larger) { - if (larger_z == smaller_z || larger_val == smaller_val) { - return smaller_val; - } - const float zoomDiff = larger_z - smaller_z; - const float zoomProgress = z - smaller_z; - if (base == 1.0f) { - const float t = zoomProgress / zoomDiff; - return util::interpolate(smaller_val, larger_val, t); - } else { - const float t = (std::pow(base, zoomProgress) - 1) / (std::pow(base, zoomDiff) - 1); - return util::interpolate(smaller_val, larger_val, t); - } - } else if (larger) { - return larger_val; - } else if (smaller) { - return smaller_val; - } else { - // No stop defined. - return defaultStopsValue<T>(); - } -} - -template class PropertyEvaluator<bool>; -template class PropertyEvaluator<float>; -template class PropertyEvaluator<Color>; -template class PropertyEvaluator<std::vector<float>>; -template class PropertyEvaluator<std::vector<std::string>>; -template class PropertyEvaluator<std::array<float, 2>>; -template class PropertyEvaluator<std::array<float, 4>>; - -template class PropertyEvaluator<std::string>; -template class PropertyEvaluator<TranslateAnchorType>; -template class PropertyEvaluator<RotateAnchorType>; -template class PropertyEvaluator<CirclePitchScaleType>; -template class PropertyEvaluator<LineCapType>; -template class PropertyEvaluator<LineJoinType>; -template class PropertyEvaluator<SymbolPlacementType>; -template class PropertyEvaluator<TextAnchorType>; -template class PropertyEvaluator<TextJustifyType>; -template class PropertyEvaluator<TextTransformType>; -template class PropertyEvaluator<AlignmentType>; -template class PropertyEvaluator<IconTextFitType>; - -template <typename T> -Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const Undefined&) const { - return calculate(defaultValue, defaultValue, defaultValue); -} - -template <typename T> -Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const T& constant) const { - return calculate(constant, constant, constant); -} - -template <typename T> -T getBiggestStopLessThan(const Function<T>& function, float z) { - const auto& stops = function.getStops(); - for (uint32_t i = 0; i < stops.size(); i++) { - if (stops[i].first > z) { - return stops[i == 0 ? i : i - 1].second; - } - } - return stops.at(stops.size() - 1).second; -} - -template <typename T> -Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const Function<T>& function) const { - return calculate(getBiggestStopLessThan(function, parameters.z - 1.0f), - getBiggestStopLessThan(function, parameters.z), - getBiggestStopLessThan(function, parameters.z + 1.0f)); -} - -template <typename T> -Faded<T> CrossFadedPropertyEvaluator<T>::calculate(const T& min, const T& mid, const T& max) const { - const float z = parameters.z; - const float fraction = z - std::floor(z); - const std::chrono::duration<float> d = parameters.defaultFadeDuration; - const float t = std::min((parameters.now - parameters.zoomHistory.lastIntegerZoomTime) / d, 1.0f); - - return z > parameters.zoomHistory.lastIntegerZoom - ? Faded<T> { min, mid, 2.0f, 1.0f, fraction + (1.0f - fraction) * t } - : Faded<T> { max, mid, 0.5f, 1.0f, 1 - (1 - t) * fraction }; -} - -template class CrossFadedPropertyEvaluator<std::string>; -template class CrossFadedPropertyEvaluator<std::vector<float>>; - -} // namespace style -} // namespace mbgl diff --git a/src/mbgl/style/property_evaluator.hpp b/src/mbgl/style/property_evaluator.hpp index a0bce2f499..ca4962d948 100644 --- a/src/mbgl/style/property_evaluator.hpp +++ b/src/mbgl/style/property_evaluator.hpp @@ -1,66 +1,28 @@ #pragma once #include <mbgl/style/property_value.hpp> -#include <mbgl/util/interpolate.hpp> +#include <mbgl/style/property_evaluation_parameters.hpp> namespace mbgl { namespace style { -class CalculationParameters; - template <typename T> class PropertyEvaluator { public: using ResultType = T; - PropertyEvaluator(const CalculationParameters& parameters_, T defaultValue_) + PropertyEvaluator(const PropertyEvaluationParameters& parameters_, T defaultValue_) : parameters(parameters_), defaultValue(std::move(defaultValue_)) {} T operator()(const Undefined&) const { return defaultValue; } T operator()(const T& constant) const { return constant; } - T operator()(const Function<T>&) const; + T operator()(const Function<T>& fn) const { return fn.evaluate(parameters.z); } private: - const CalculationParameters& parameters; - T defaultValue; -}; - -template <typename T> -struct Faded { - T from; - T to; - float fromScale; - float toScale; - float t; -}; - -template <typename T> -class CrossFadedPropertyEvaluator { -public: - using ResultType = Faded<T>; - - CrossFadedPropertyEvaluator(const CalculationParameters& parameters_, T defaultValue_) - : parameters(parameters_), - defaultValue(std::move(defaultValue_)) {} - - Faded<T> operator()(const Undefined&) const; - Faded<T> operator()(const T& constant) const; - Faded<T> operator()(const Function<T>&) const; - -private: - Faded<T> calculate(const T& min, const T& mid, const T& max) const; - - const CalculationParameters& parameters; + const PropertyEvaluationParameters& parameters; T defaultValue; }; } // namespace style - -namespace util { -template <typename T> -struct Interpolator<style::Faded<T>> - : Uninterpolated {}; -} // namespace util - } // namespace mbgl diff --git a/src/mbgl/style/property_parsing.hpp b/src/mbgl/style/property_parsing.hpp index 8c2bd2c0f4..b542c8ae47 100644 --- a/src/mbgl/style/property_parsing.hpp +++ b/src/mbgl/style/property_parsing.hpp @@ -5,7 +5,7 @@ #include <mbgl/style/rapidjson_conversion.hpp> #include <mbgl/style/conversion/property_value.hpp> -#include <mbgl/platform/log.hpp> +#include <mbgl/util/logging.hpp> namespace mbgl { namespace style { diff --git a/src/mbgl/style/source_impl.cpp b/src/mbgl/style/source_impl.cpp index d0ae54092d..149bf99f9d 100644 --- a/src/mbgl/style/source_impl.cpp +++ b/src/mbgl/style/source_impl.cpp @@ -6,7 +6,7 @@ #include <mbgl/style/update_parameters.hpp> #include <mbgl/style/query_parameters.hpp> #include <mbgl/text/placement_config.hpp> -#include <mbgl/platform/log.hpp> +#include <mbgl/util/logging.hpp> #include <mbgl/math/clamp.hpp> #include <mbgl/util/tile_cover.hpp> #include <mbgl/util/enum.hpp> @@ -70,11 +70,13 @@ void Source::Impl::startRender(algorithm::ClipIDGenerator& generator, void Source::Impl::finishRender(Painter& painter) { for (auto& pair : renderTiles) { auto& tile = pair.second; - painter.renderTileDebug(tile); + if (tile.used) { + painter.renderTileDebug(tile); + } } } -const std::map<UnwrappedTileID, RenderTile>& Source::Impl::getRenderTiles() const { +std::map<UnwrappedTileID, RenderTile>& Source::Impl::getRenderTiles() { return renderTiles; } @@ -139,13 +141,26 @@ void Source::Impl::updateTiles(const UpdateParameters& parameters) { if (type != SourceType::Annotations && cache.getSize() == 0) { size_t conservativeCacheSize = - std::max((float)parameters.transformState.getWidth() / util::tileSize, 1.0f) * - std::max((float)parameters.transformState.getHeight() / util::tileSize, 1.0f) * + std::max((float)parameters.transformState.getSize().width / util::tileSize, 1.0f) * + std::max((float)parameters.transformState.getSize().height / util::tileSize, 1.0f) * (parameters.transformState.getMaxZoom() - parameters.transformState.getMinZoom() + 1) * 0.5; cache.setSize(conservativeCacheSize); } + removeStaleTiles(retain); + + const PlacementConfig config { parameters.transformState.getAngle(), + parameters.transformState.getPitch(), + parameters.debugOptions & MapDebugOptions::Collision }; + + for (auto& pair : tiles) { + pair.second->setPlacementConfig(config); + } +} + +// Moves all tiles to the cache except for those specified in the retain set. +void Source::Impl::removeStaleTiles(const std::set<OverscaledTileID>& retain) { // Remove stale tiles. This goes through the (sorted!) tiles map and retain set in lockstep // and removes items from tiles that don't have the corresponding key in the retain set. auto tilesIt = tiles.begin(); @@ -162,13 +177,12 @@ void Source::Impl::updateTiles(const UpdateParameters& parameters) { ++retainIt; } } +} - const PlacementConfig config { parameters.transformState.getAngle(), - parameters.transformState.getPitch(), - parameters.debugOptions & MapDebugOptions::Collision }; - - for (auto& pair : tiles) { - pair.second->setPlacementConfig(config); +void Source::Impl::removeTiles() { + renderTiles.clear(); + if (!tiles.empty()) { + removeStaleTiles({}); } } @@ -196,7 +210,7 @@ std::unordered_map<std::string, std::vector<Feature>> Source::Impl::queryRendere for (const auto& p : parameters.geometry) { queryGeometry.push_back(TileCoordinate::fromScreenCoordinate( - parameters.transformState, 0, { p.x, parameters.transformState.getHeight() - p.y }).p); + parameters.transformState, 0, { p.x, parameters.transformState.getSize().height - p.y }).p); } mapbox::geometry::box<double> box = mapbox::geometry::envelope(queryGeometry); diff --git a/src/mbgl/style/source_impl.hpp b/src/mbgl/style/source_impl.hpp index a4dd48444e..e6340ae1cb 100644 --- a/src/mbgl/style/source_impl.hpp +++ b/src/mbgl/style/source_impl.hpp @@ -63,7 +63,7 @@ public: const TransformState&); void finishRender(Painter&); - const std::map<UnwrappedTileID, RenderTile>& getRenderTiles() const; + std::map<UnwrappedTileID, RenderTile>& getRenderTiles(); std::unordered_map<std::string, std::vector<Feature>> queryRenderedFeatures(const QueryParameters&) const; @@ -88,6 +88,7 @@ public: protected: void invalidateTiles(); + void removeStaleTiles(const std::set<OverscaledTileID>&); Source& base; SourceObserver* observer = nullptr; diff --git a/src/mbgl/style/sources/geojson_source_impl.cpp b/src/mbgl/style/sources/geojson_source_impl.cpp index 4800b9c4be..7f41e0e321 100644 --- a/src/mbgl/style/sources/geojson_source_impl.cpp +++ b/src/mbgl/style/sources/geojson_source_impl.cpp @@ -1,4 +1,4 @@ -#include <mbgl/platform/log.hpp> +#include <mbgl/util/logging.hpp> #include <mbgl/storage/file_source.hpp> #include <mbgl/style/conversion/geojson.hpp> #include <mbgl/style/source_observer.hpp> diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index d28963aa64..2d11d16b1f 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -8,6 +8,7 @@ #include <mbgl/style/layers/background_layer.hpp> #include <mbgl/style/layers/background_layer_impl.hpp> #include <mbgl/style/layers/fill_layer.hpp> +#include <mbgl/style/layers/fill_extrusion_layer.hpp> #include <mbgl/style/layers/line_layer.hpp> #include <mbgl/style/layers/circle_layer.hpp> #include <mbgl/style/layers/raster_layer.hpp> @@ -18,7 +19,7 @@ #include <mbgl/style/class_dictionary.hpp> #include <mbgl/style/update_parameters.hpp> #include <mbgl/style/cascade_parameters.hpp> -#include <mbgl/style/calculation_parameters.hpp> +#include <mbgl/style/property_evaluation_parameters.hpp> #include <mbgl/sprite/sprite_atlas.hpp> #include <mbgl/text/glyph_atlas.hpp> #include <mbgl/geometry/line_atlas.hpp> @@ -26,7 +27,7 @@ #include <mbgl/renderer/render_tile.hpp> #include <mbgl/util/constants.hpp> #include <mbgl/util/string.hpp> -#include <mbgl/platform/log.hpp> +#include <mbgl/util/logging.hpp> #include <mbgl/math/minmax.hpp> #include <algorithm> @@ -38,9 +39,9 @@ static Observer nullObserver; Style::Style(FileSource& fileSource_, float pixelRatio) : fileSource(fileSource_), - glyphAtlas(std::make_unique<GlyphAtlas>(2048, 2048, fileSource)), - spriteAtlas(std::make_unique<SpriteAtlas>(1024, 1024, pixelRatio)), - lineAtlas(std::make_unique<LineAtlas>(256, 512)), + glyphAtlas(std::make_unique<GlyphAtlas>(Size{ 2048, 2048 }, fileSource)), + spriteAtlas(std::make_unique<SpriteAtlas>(Size{ 1024, 1024 }, pixelRatio)), + lineAtlas(std::make_unique<LineAtlas>(Size{ 256, 512 })), observer(&nullObserver) { glyphAtlas->setObserver(this); spriteAtlas->setObserver(this); @@ -262,7 +263,9 @@ double Style::getDefaultPitch() const { void Style::updateTiles(const UpdateParameters& parameters) { for (const auto& source : sources) { - source->baseImpl->updateTiles(parameters); + if (source->baseImpl->enabled) { + source->baseImpl->updateTiles(parameters); + } } } @@ -275,8 +278,9 @@ void Style::updateSymbolDependentTiles() { void Style::relayout() { for (const auto& sourceID : updateBatch.sourceIDs) { Source* source = getSource(sourceID); - if (!source) continue; - source->baseImpl->reloadTiles(); + if (source && source->baseImpl->enabled) { + source->baseImpl->reloadTiles(); + } } updateBatch.sourceIDs.clear(); } @@ -291,7 +295,6 @@ void Style::cascade(const TimePoint& timePoint, MapMode mode) { classIDs.push_back(ClassDictionary::Get().lookup(className)); } classIDs.push_back(ClassID::Default); - classIDs.push_back(ClassID::Fallback); const CascadeParameters parameters { classIDs, @@ -305,13 +308,15 @@ void Style::cascade(const TimePoint& timePoint, MapMode mode) { } void Style::recalculate(float z, const TimePoint& timePoint, MapMode mode) { + // Disable all sources first. If we find an enabled layer that uses this source, we will + // re-enable it later. for (const auto& source : sources) { source->baseImpl->enabled = false; } zoomHistory.update(z, timePoint); - const CalculationParameters parameters { + const PropertyEvaluationParameters parameters { z, mode == MapMode::Continuous ? timePoint : Clock::time_point::max(), zoomHistory, @@ -320,7 +325,7 @@ void Style::recalculate(float z, const TimePoint& timePoint, MapMode mode) { hasPendingTransitions = false; for (const auto& layer : layers) { - const bool hasTransitions = layer->baseImpl->recalculate(parameters); + const bool hasTransitions = layer->baseImpl->evaluate(parameters); // Disable this layer if it doesn't need to be rendered. const bool needsRendering = layer->baseImpl->needsRendering(zoomHistory.lastZoom); @@ -338,6 +343,13 @@ void Style::recalculate(float z, const TimePoint& timePoint, MapMode mode) { } } } + + // Remove the existing tiles if we didn't end up re-enabling the source. + for (const auto& source : sources) { + if (!source->baseImpl->enabled) { + source->baseImpl->removeTiles(); + } + } } std::vector<const Source*> Style::getSources() const { @@ -388,7 +400,7 @@ bool Style::isLoaded() const { return true; } -RenderData Style::getRenderData(MapDebugOptions debugOptions) const { +RenderData Style::getRenderData(MapDebugOptions debugOptions, float angle) const { RenderData result; for (const auto& source : sources) { @@ -397,6 +409,9 @@ RenderData Style::getRenderData(MapDebugOptions debugOptions) const { } } + const bool isLeft = std::abs(angle) > M_PI_2; + const bool isBottom = angle < 0; + for (const auto& layer : layers) { if (!layer->baseImpl->needsRendering(zoomHistory.lastZoom)) { continue; @@ -408,10 +423,10 @@ RenderData Style::getRenderData(MapDebugOptions debugOptions) const { result.order.emplace_back(*layer); continue; } - const BackgroundPaintProperties& paint = background->impl->paint; - if (layer.get() == layers[0].get() && paint.backgroundPattern.value.from.empty()) { + const BackgroundPaintProperties::Evaluated& paint = background->impl->paint.evaluated; + if (layer.get() == layers[0].get() && paint.get<BackgroundPattern>().from.empty()) { // This is a solid background. We can use glClear(). - result.backgroundColor = paint.backgroundColor * paint.backgroundOpacity; + result.backgroundColor = paint.get<BackgroundColor>() * paint.get<BackgroundOpacity>(); } else { // This is a textured background, or not the bottommost layer. We need to render it with a quad. result.order.emplace_back(*layer); @@ -430,8 +445,29 @@ RenderData Style::getRenderData(MapDebugOptions debugOptions) const { continue; } - for (auto& pair : source->baseImpl->getRenderTiles()) { - auto& tile = pair.second; + auto& renderTiles = source->baseImpl->getRenderTiles(); + const bool symbolLayer = layer->is<SymbolLayer>(); + + // Sort symbol tiles in opposite y position, so tiles with overlapping + // symbols are drawn on top of each other, with lower symbols being + // drawn on top of higher symbols. + std::vector<std::reference_wrapper<RenderTile>> sortedTiles; + std::transform(renderTiles.begin(), renderTiles.end(), std::back_inserter(sortedTiles), + [](auto& pair) { return std::ref(pair.second); }); + if (symbolLayer) { + std::sort(sortedTiles.begin(), sortedTiles.end(), + [isLeft, isBottom](const RenderTile& a, const RenderTile& b) { + bool sortX = a.id.canonical.x > b.id.canonical.x; + bool sortW = a.id.wrap > b.id.wrap; + bool sortY = a.id.canonical.y > b.id.canonical.y; + return + a.id.canonical.y != b.id.canonical.y ? (isLeft ? sortY : !sortY) : + a.id.wrap != b.id.wrap ? (isBottom ? sortW : !sortW) : (isBottom ? sortX : !sortX); + }); + } + + for (auto& tileRef : sortedTiles) { + auto& tile = tileRef.get(); if (!tile.tile.isRenderable()) { continue; } @@ -439,7 +475,7 @@ RenderData Style::getRenderData(MapDebugOptions debugOptions) const { // We're not clipping symbol layers, so when we have both parents and children of symbol // layers, we drop all children in favor of their parent to avoid duplicate labels. // See https://github.com/mapbox/mapbox-gl-native/issues/2482 - if (layer->is<SymbolLayer>()) { + if (symbolLayer) { bool skip = false; // Look back through the buckets we decided to render to find out whether there is // already a bucket from this layer that is a parent of this tile. Tiles are ordered @@ -458,6 +494,7 @@ RenderData Style::getRenderData(MapDebugOptions debugOptions) const { auto bucket = tile.tile.getBucket(*layer); if (bucket) { result.order.emplace_back(*layer, &tile, bucket); + tile.used = true; } } } diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp index 1da22b8cf3..d46e80e8bf 100644 --- a/src/mbgl/style/style.hpp +++ b/src/mbgl/style/style.hpp @@ -93,7 +93,7 @@ public: bool hasClass(const std::string&) const; std::vector<std::string> getClasses() const; - RenderData getRenderData(MapDebugOptions) const; + RenderData getRenderData(MapDebugOptions, float angle) const; std::vector<Feature> queryRenderedFeatures(const QueryParameters&) const; @@ -118,9 +118,9 @@ private: // Defaults std::string name; LatLng defaultLatLng; - double defaultZoom; - double defaultBearing; - double defaultPitch; + double defaultZoom = 0; + double defaultBearing = 0; + double defaultPitch = 0; std::vector<std::unique_ptr<Layer>>::const_iterator findLayer(const std::string& layerID) const; void reloadLayerSource(Layer&); diff --git a/src/mbgl/text/bidi.hpp b/src/mbgl/text/bidi.hpp new file mode 100644 index 0000000000..6c209c427c --- /dev/null +++ b/src/mbgl/text/bidi.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include <set> +#include <string> +#include <vector> +#include <memory> + +#include <mbgl/util/noncopyable.hpp> + +namespace mbgl { + +class BiDi; +class BiDiImpl; + +std::u16string applyArabicShaping(const std::u16string&); + +class ProcessedBiDiText { +public: + ProcessedBiDiText(BiDi&); + + std::vector<std::u16string> applyLineBreaking(std::set<int32_t>); + +private: + void mergeParagraphLineBreaks(std::set<int32_t>&); + + BiDi& bidi; +}; + +class BiDi : private util::noncopyable { +public: + BiDi(); + ~BiDi(); + + // Calling processText resets internal state, invalidating any existing ProcessedBiDiText + // objects + ProcessedBiDiText processText(const std::u16string&); + + friend class ProcessedBiDiText; + +private: + std::u16string getLine(int32_t start, int32_t end); + + std::unique_ptr<BiDiImpl> impl; +}; + +} // end namespace mbgl diff --git a/src/mbgl/text/collision_tile.cpp b/src/mbgl/text/collision_tile.cpp index e485fbf36c..419ab31a79 100644 --- a/src/mbgl/text/collision_tile.cpp +++ b/src/mbgl/text/collision_tile.cpp @@ -1,5 +1,6 @@ #include <mbgl/text/collision_tile.hpp> #include <mbgl/geometry/feature_index.hpp> +#include <mbgl/math/log2.hpp> #include <mbgl/util/constants.hpp> #include <mbgl/util/math.hpp> #include <mbgl/math/minmax.hpp> diff --git a/src/mbgl/text/get_anchors.cpp b/src/mbgl/text/get_anchors.cpp index ce45e05d9c..b912c7763e 100644 --- a/src/mbgl/text/get_anchors.cpp +++ b/src/mbgl/text/get_anchors.cpp @@ -72,6 +72,7 @@ Anchors getAnchors(const GeometryCoordinates &line, float spacing, const float maxAngle, const float textLeft, const float textRight, const float iconLeft, const float iconRight, const float glyphSize, const float boxScale, const float overscaling) { + if (line.empty()) return {}; // Resample a line to get anchor points for labels and check that each // potential label passes text-max-angle check and has enough froom to fit diff --git a/src/mbgl/text/glyph.cpp b/src/mbgl/text/glyph.cpp index a877d7a799..29929b73e6 100644 --- a/src/mbgl/text/glyph.cpp +++ b/src/mbgl/text/glyph.cpp @@ -3,7 +3,7 @@ namespace mbgl { // Note: this only works for the BMP -GlyphRange getGlyphRange(char32_t glyph) { +GlyphRange getGlyphRange(char16_t glyph) { unsigned start = (glyph/256) * 256; unsigned end = (start + 255); if (start > 65280) start = 65280; diff --git a/src/mbgl/text/glyph.hpp b/src/mbgl/text/glyph.hpp index 975dc4ad23..d07fbdff21 100644 --- a/src/mbgl/text/glyph.hpp +++ b/src/mbgl/text/glyph.hpp @@ -11,10 +11,10 @@ namespace mbgl { // Note: this only works for the BMP -GlyphRange getGlyphRange(char32_t glyph); +GlyphRange getGlyphRange(char16_t glyph); struct GlyphMetrics { - operator bool() const { + explicit operator bool() const { return !(width == 0 && height == 0 && advance == 0); } @@ -27,12 +27,20 @@ struct GlyphMetrics { }; +inline bool operator==(const GlyphMetrics& lhs, const GlyphMetrics& rhs) { + return lhs.width == rhs.width && + lhs.height == rhs.height && + lhs.left == rhs.left && + lhs.top == rhs.top && + lhs.advance == rhs.advance; +} + struct Glyph { explicit Glyph() : rect(0, 0, 0, 0), metrics() {} explicit Glyph(Rect<uint16_t> rect_, GlyphMetrics metrics_) : rect(std::move(rect_)), metrics(std::move(metrics_)) {} - operator bool() const { + explicit operator bool() const { return metrics || rect.hasArea(); } @@ -55,16 +63,16 @@ public: class Shaping { public: explicit Shaping() : top(0), bottom(0), left(0), right(0) {} - explicit Shaping(float x, float y, std::u32string text_) + explicit Shaping(float x, float y, std::u16string text_) : text(std::move(text_)), top(y), bottom(y), left(x), right(x) {} std::vector<PositionedGlyph> positionedGlyphs; - std::u32string text; + std::u16string text; int32_t top; int32_t bottom; int32_t left; int32_t right; - operator bool() const { return !positionedGlyphs.empty(); } + explicit operator bool() const { return !positionedGlyphs.empty(); } }; class SDFGlyph { diff --git a/src/mbgl/text/glyph_atlas.cpp b/src/mbgl/text/glyph_atlas.cpp index 2f8c44db59..5d30dacdce 100644 --- a/src/mbgl/text/glyph_atlas.cpp +++ b/src/mbgl/text/glyph_atlas.cpp @@ -1,10 +1,9 @@ #include <mbgl/text/glyph_atlas.hpp> #include <mbgl/text/glyph_atlas_observer.hpp> #include <mbgl/text/glyph_pbf.hpp> -#include <mbgl/gl/gl.hpp> #include <mbgl/gl/context.hpp> -#include <mbgl/platform/log.hpp> -#include <mbgl/platform/platform.hpp> +#include <mbgl/util/logging.hpp> +#include <mbgl/util/platform.hpp> #include <cassert> #include <algorithm> @@ -13,13 +12,11 @@ namespace mbgl { static GlyphAtlasObserver nullObserver; -GlyphAtlas::GlyphAtlas(uint16_t width_, uint16_t height_, FileSource& fileSource_) - : width(width_), - height(height_), - fileSource(fileSource_), +GlyphAtlas::GlyphAtlas(const Size size, FileSource& fileSource_) + : fileSource(fileSource_), observer(&nullObserver), - bin(width_, height_), - data(std::make_unique<uint8_t[]>(width_ * height_)), + bin(size.width, size.height), + image(size), dirty(true) { } @@ -84,7 +81,7 @@ void GlyphAtlas::setObserver(GlyphAtlasObserver* observer_) { } void GlyphAtlas::addGlyphs(uintptr_t tileUID, - const std::u32string& text, + const std::u16string& text, const FontStack& fontStack, const GlyphSet& glyphSet, GlyphPositions& face) @@ -93,7 +90,7 @@ void GlyphAtlas::addGlyphs(uintptr_t tileUID, const std::map<uint32_t, SDFGlyph>& sdfs = glyphSet.getSDFs(); - for (uint32_t chr : text) + for (char16_t chr : text) { auto sdf_it = sdfs.find(chr); if (sdf_it == sdfs.end()) { @@ -148,18 +145,18 @@ Rect<uint16_t> GlyphAtlas::addGlyph(uintptr_t tileUID, return rect; } - assert(rect.x + rect.w <= width); - assert(rect.y + rect.h <= height); + assert(rect.x + rect.w <= image.size.width); + assert(rect.y + rect.h <= image.size.height); face.emplace(glyph.id, GlyphValue { rect, tileUID }); // Copy the bitmap const uint8_t* source = reinterpret_cast<const uint8_t*>(glyph.bitmap.data()); for (uint32_t y = 0; y < buffered_height; y++) { - uint32_t y1 = width * (rect.y + y + padding) + rect.x + padding; + uint32_t y1 = image.size.width * (rect.y + y + padding) + rect.x + padding; uint32_t y2 = buffered_width * y; for (uint32_t x = 0; x < buffered_width; x++) { - data[y1 + x] = source[y2 + x]; + image.data[y1 + x] = source[y2 + x]; } } @@ -181,9 +178,9 @@ void GlyphAtlas::removeGlyphs(uintptr_t tileUID) { const Rect<uint16_t>& rect = value.rect; // Clear out the bitmap. - uint8_t *target = data.get(); + uint8_t *target = image.data.get(); for (uint32_t y = 0; y < rect.h; y++) { - uint32_t y1 = width * (rect.y + y) + rect.x; + uint32_t y1 = image.size.width * (rect.y + y) + rect.x; for (uint32_t x = 0; x < rect.w; x++) { target[y1 + x] = 0; } @@ -203,60 +200,25 @@ void GlyphAtlas::removeGlyphs(uintptr_t tileUID) { } } +Size GlyphAtlas::getSize() const { + return image.size; +} + void GlyphAtlas::upload(gl::Context& context, gl::TextureUnit unit) { - if (dirty) { - const bool first = !texture; - bind(context, unit); - - std::lock_guard<std::mutex> lock(mtx); - - context.activeTexture = unit; - if (first) { - MBGL_CHECK_ERROR(glTexImage2D( - GL_TEXTURE_2D, // GLenum target - 0, // GLint level - GL_ALPHA, // GLint internalformat - width, // GLsizei width - height, // GLsizei height - 0, // GLint border - GL_ALPHA, // GLenum format - GL_UNSIGNED_BYTE, // GLenum type - data.get() // const GLvoid* data - )); - } else { - MBGL_CHECK_ERROR(glTexSubImage2D( - GL_TEXTURE_2D, // GLenum target - 0, // GLint level - 0, // GLint xoffset - 0, // GLint yoffset - width, // GLsizei width - height, // GLsizei height - GL_ALPHA, // GLenum format - GL_UNSIGNED_BYTE, // GLenum type - data.get() // const GLvoid* data - )); - } + std::lock_guard<std::mutex> lock(mtx); - dirty = false; + if (!texture) { + texture = context.createTexture(image, unit); + } else if (dirty) { + context.updateTexture(*texture, image, unit); } + + dirty = false; } void GlyphAtlas::bind(gl::Context& context, gl::TextureUnit unit) { - if (!texture) { - texture = context.createTexture(); - context.activeTexture = unit; - context.texture[unit] = *texture; -#if not MBGL_USE_GLES2 - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); -#endif - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); - } else if (context.texture[unit] != *texture) { - context.activeTexture = unit; - context.texture[unit] = *texture; - } + upload(context, unit); + context.bindTexture(*texture, unit, gl::TextureFilter::Linear); } } // namespace mbgl diff --git a/src/mbgl/text/glyph_atlas.hpp b/src/mbgl/text/glyph_atlas.hpp index 84875bdd78..af14aace5b 100644 --- a/src/mbgl/text/glyph_atlas.hpp +++ b/src/mbgl/text/glyph_atlas.hpp @@ -8,6 +8,8 @@ #include <mbgl/util/font_stack.hpp> #include <mbgl/util/exclusive.hpp> #include <mbgl/util/work_queue.hpp> +#include <mbgl/util/image.hpp> +#include <mbgl/gl/texture.hpp> #include <mbgl/gl/object.hpp> #include <atomic> @@ -30,7 +32,7 @@ class Context; class GlyphAtlas : public util::noncopyable { public: - GlyphAtlas(uint16_t width, uint16_t height, FileSource&); + GlyphAtlas(Size, FileSource&); ~GlyphAtlas(); util::exclusive<GlyphSet> getGlyphSet(const FontStack&); @@ -53,7 +55,7 @@ public: void setObserver(GlyphAtlasObserver* observer); void addGlyphs(uintptr_t tileUID, - const std::u32string& text, + const std::u16string& text, const FontStack&, const GlyphSet&, GlyphPositions&); @@ -66,8 +68,7 @@ public: // the texture is only bound when the data is out of date (=dirty). void upload(gl::Context&, gl::TextureUnit unit); - const uint16_t width; - const uint16_t height; + Size getSize() const; private: void requestGlyphRange(const FontStack&, const GlyphRange&); @@ -100,9 +101,9 @@ private: std::mutex mtx; BinPack<uint16_t> bin; std::unordered_map<FontStack, std::map<uint32_t, GlyphValue>, FontStackHash> index; - const std::unique_ptr<uint8_t[]> data; + const AlphaImage image; std::atomic<bool> dirty; - mbgl::optional<gl::UniqueTexture> texture; + mbgl::optional<gl::Texture> texture; }; } // namespace mbgl diff --git a/src/mbgl/text/glyph_set.cpp b/src/mbgl/text/glyph_set.cpp index 0875a83850..f1cb85a03a 100644 --- a/src/mbgl/text/glyph_set.cpp +++ b/src/mbgl/text/glyph_set.cpp @@ -1,7 +1,11 @@ -#include <mbgl/text/glyph_set.hpp> -#include <mbgl/platform/log.hpp> #include <mbgl/math/minmax.hpp> +#include <mbgl/text/glyph_set.hpp> +#include <mbgl/util/i18n.hpp> +#include <mbgl/util/logging.hpp> + +#include <boost/algorithm/string.hpp> +#include <algorithm> #include <cassert> namespace mbgl { @@ -26,44 +30,47 @@ void GlyphSet::insert(uint32_t id, SDFGlyph&& glyph) { } } -const std::map<uint32_t, SDFGlyph> &GlyphSet::getSDFs() const { +const std::map<uint32_t, SDFGlyph>& GlyphSet::getSDFs() const { return sdfs; } -const Shaping GlyphSet::getShaping(const std::u32string &string, const float maxWidth, - const float lineHeight, const float horizontalAlign, - const float verticalAlign, const float justify, - const float spacing, const Point<float> &translate) const { - Shaping shaping(translate.x * 24, translate.y * 24, string); +const Shaping GlyphSet::getShaping(const std::u16string& logicalInput, + const float maxWidth, + const float lineHeight, + const float horizontalAlign, + const float verticalAlign, + const float justify, + const float spacing, + const Point<float>& translate, + BiDi& bidi) const { - // the y offset *should* be part of the font metadata - const int32_t yOffset = -17; + // The string stored in shaping.text is used for finding duplicates, but may end up quite + // different from the glyphs that get shown + Shaping shaping(translate.x * 24, translate.y * 24, logicalInput); - float x = 0; - const float y = yOffset; + ProcessedBiDiText processedText = bidi.processText(logicalInput); - // Loop through all characters of this label and shape. - for (uint32_t chr : string) { - auto it = sdfs.find(chr); - if (it != sdfs.end()) { - shaping.positionedGlyphs.emplace_back(chr, x, y); - x += it->second.metrics.advance + spacing; - } - } + std::vector<std::u16string> reorderedLines = + processedText.applyLineBreaking(determineLineBreaks(logicalInput, spacing, maxWidth)); - if (shaping.positionedGlyphs.empty()) - return shaping; - - lineWrap(shaping, lineHeight, maxWidth, horizontalAlign, verticalAlign, justify, translate); + shapeLines(shaping, reorderedLines, spacing, lineHeight, horizontalAlign, verticalAlign, + justify, translate); return shaping; } -void align(Shaping &shaping, const float justify, const float horizontalAlign, - const float verticalAlign, const uint32_t maxLineLength, const float lineHeight, - const uint32_t line, const Point<float> &translate) { - const float shiftX = (justify - horizontalAlign) * maxLineLength + ::round(translate.x * 24/* one em */); - const float shiftY = (-verticalAlign * (line + 1) + 0.5) * lineHeight + ::round(translate.y * 24/* one em */); +void align(Shaping& shaping, + const float justify, + const float horizontalAlign, + const float verticalAlign, + const float maxLineLength, + const float lineHeight, + const uint32_t lineCount, + const Point<float>& translate) { + const float shiftX = + (justify - horizontalAlign) * maxLineLength + ::round(translate.x * 24 /* one em */); + const float shiftY = + (-verticalAlign * lineCount + 0.5) * lineHeight + ::round(translate.y * 24 /* one em */); for (auto& glyph : shaping.positionedGlyphs) { glyph.x += shiftX; @@ -71,9 +78,16 @@ void align(Shaping &shaping, const float justify, const float horizontalAlign, } } -void justifyLine(std::vector<PositionedGlyph> &positionedGlyphs, const std::map<uint32_t, SDFGlyph> &sdfs, uint32_t start, - uint32_t end, float justify) { - PositionedGlyph &glyph = positionedGlyphs[end]; +// justify left = 0, right = 1, center = .5 +void justifyLine(std::vector<PositionedGlyph>& positionedGlyphs, + const std::map<uint32_t, SDFGlyph>& sdfs, + uint32_t start, + uint32_t end, + float justify) { + if (!justify) + return; + + PositionedGlyph& glyph = positionedGlyphs[end]; auto it = sdfs.find(glyph.glyph); if (it != sdfs.end()) { const uint32_t lastAdvance = it->second.metrics.advance; @@ -85,80 +99,122 @@ void justifyLine(std::vector<PositionedGlyph> &positionedGlyphs, const std::map< } } -void GlyphSet::lineWrap(Shaping &shaping, const float lineHeight, const float maxWidth, - const float horizontalAlign, const float verticalAlign, - const float justify, const Point<float> &translate) const { +float GlyphSet::determineIdeographicLineWidth(const std::u16string& logicalInput, + const float spacing, + float maxWidth) const { + float totalWidth = 0; + + // totalWidth doesn't include the last character for magical tuning reasons. This makes the + // algorithm a little + // more agressive about trying to fit the text into fewer lines, taking advantage of the + // tolerance for going a little + // over maxWidth + for (uint32_t i = 0; i < logicalInput.size() - 1; i++) { + auto it = sdfs.find(logicalInput[i]); + if (it != sdfs.end()) + totalWidth += it->second.metrics.advance + spacing; + } + + int32_t lineCount = std::fmax(1, std::ceil(totalWidth / maxWidth)); + return totalWidth / lineCount; +} + +// We determine line breaks based on shaped text in logical order. Working in visual order would be +// more intuitive, but we can't do that because the visual order may be changed by line breaks! +std::set<int32_t> GlyphSet::determineLineBreaks(const std::u16string& logicalInput, + const float spacing, + float maxWidth) const { + if (!maxWidth) + return {}; + + if (logicalInput.empty()) + return {}; + + if (util::i18n::allowsIdeographicBreaking(logicalInput)) + maxWidth = determineIdeographicLineWidth(logicalInput, spacing, maxWidth); + + std::set<int32_t> lineBreakPoints; + float currentX = 0; uint32_t lastSafeBreak = 0; + float lastSafeBreakX = 0; + + for (uint32_t i = 0; i < logicalInput.size(); i++) { + auto it = sdfs.find(logicalInput[i]); + if (it == sdfs.end()) + continue; + + const SDFGlyph& glyph = it->second; - uint32_t lengthBeforeCurrentLine = 0; - uint32_t lineStartIndex = 0; - uint32_t line = 0; - - uint32_t maxLineLength = 0; - - std::vector<PositionedGlyph> &positionedGlyphs = shaping.positionedGlyphs; - - if (maxWidth) { - for (uint32_t i = 0; i < positionedGlyphs.size(); i++) { - PositionedGlyph &shape = positionedGlyphs[i]; - - shape.x -= lengthBeforeCurrentLine; - shape.y += lineHeight * line; - - if (shape.x > maxWidth && lastSafeBreak > 0) { - - uint32_t lineLength = positionedGlyphs[lastSafeBreak + 1].x; - maxLineLength = util::max(lineLength, maxLineLength); - - for (uint32_t k = lastSafeBreak + 1; k <= i; k++) { - positionedGlyphs[k].y += lineHeight; - positionedGlyphs[k].x -= lineLength; - } - - if (justify) { - // Collapse invisible characters. - uint32_t breakGlyph = positionedGlyphs[lastSafeBreak].glyph; - uint32_t lineEnd = lastSafeBreak; - if (breakGlyph == 0x20 /* space */ - || breakGlyph == 0x200b /* zero-width space */) { - lineEnd--; - } - - justifyLine(positionedGlyphs, sdfs, lineStartIndex, lineEnd, justify); - } - - lineStartIndex = lastSafeBreak + 1; - lastSafeBreak = 0; - lengthBeforeCurrentLine += lineLength; - line++; - } - - // Spaces, plus word-breaking punctuation that often appears without surrounding spaces. - if (shape.glyph == 0x20 /* space */ - || shape.glyph == 0x26 /* ampersand */ - || shape.glyph == 0x2b /* plus sign */ - || shape.glyph == 0x2d /* hyphen-minus */ - || shape.glyph == 0x2f /* solidus */ - || shape.glyph == 0xad /* soft hyphen */ - || shape.glyph == 0xb7 /* middle dot */ - || shape.glyph == 0x200b /* zero-width space */ - || shape.glyph == 0x2010 /* hyphen */ - || shape.glyph == 0x2013 /* en dash */) { - lastSafeBreak = i; - } + // Ideographic characters, spaces, and word-breaking punctuation that often appear without + // surrounding spaces. + if (util::i18n::allowsWordBreaking(glyph.id) || + util::i18n::allowsIdeographicBreaking(glyph.id)) { + lastSafeBreak = i; + lastSafeBreakX = currentX; } + + if (currentX > maxWidth && lastSafeBreak > 0) { + lineBreakPoints.insert(lastSafeBreak); + currentX -= lastSafeBreakX; + lastSafeBreakX = 0; + } + + currentX += glyph.metrics.advance + spacing; } - const PositionedGlyph& lastPositionedGlyph = positionedGlyphs.back(); - const auto lastGlyphIt = sdfs.find(lastPositionedGlyph.glyph); - assert(lastGlyphIt != sdfs.end()); - const uint32_t lastLineLength = lastPositionedGlyph.x + lastGlyphIt->second.metrics.advance; - maxLineLength = std::max(maxLineLength, lastLineLength); + return lineBreakPoints; +} + +void GlyphSet::shapeLines(Shaping& shaping, + const std::vector<std::u16string>& lines, + const float spacing, + const float lineHeight, + const float horizontalAlign, + const float verticalAlign, + const float justify, + const Point<float>& translate) const { + + // the y offset *should* be part of the font metadata + const int32_t yOffset = -17; + + float x = 0; + float y = yOffset; + + float maxLineLength = 0; - const uint32_t height = (line + 1) * lineHeight; + for (std::u16string line : lines) { + // Collapse whitespace so it doesn't throw off justification + boost::algorithm::trim_if(line, boost::algorithm::is_any_of(u" \t\n\v\f\r")); + + if (line.empty()) + continue; + + uint32_t lineStartIndex = static_cast<uint32_t>(shaping.positionedGlyphs.size()); + for (char16_t chr : line) { + auto it = sdfs.find(chr); + if (it == sdfs.end()) + continue; + + const SDFGlyph& glyph = it->second; + shaping.positionedGlyphs.emplace_back(chr, x, y); + x += glyph.metrics.advance + spacing; + } + + if (static_cast<uint32_t>(shaping.positionedGlyphs.size()) == lineStartIndex) + continue; + + maxLineLength = util::max(x, maxLineLength); + + justifyLine(shaping.positionedGlyphs, sdfs, lineStartIndex, + static_cast<uint32_t>(shaping.positionedGlyphs.size()) - 1, justify); + + x = 0; + y += lineHeight; // Move to next line + } - justifyLine(positionedGlyphs, sdfs, lineStartIndex, uint32_t(positionedGlyphs.size()) - 1, justify); - align(shaping, justify, horizontalAlign, verticalAlign, maxLineLength, lineHeight, line, translate); + align(shaping, justify, horizontalAlign, verticalAlign, maxLineLength, lineHeight, + static_cast<uint32_t>(lines.size()), translate); + const uint32_t height = lines.size() * lineHeight; // Calculate the bounding box shaping.top += -verticalAlign * height; diff --git a/src/mbgl/text/glyph_set.hpp b/src/mbgl/text/glyph_set.hpp index 37ffdb070a..b48973b6ea 100644 --- a/src/mbgl/text/glyph_set.hpp +++ b/src/mbgl/text/glyph_set.hpp @@ -1,5 +1,6 @@ #pragma once +#include <mbgl/text/bidi.hpp> #include <mbgl/text/glyph.hpp> #include <mbgl/util/geometry.hpp> @@ -8,14 +9,34 @@ namespace mbgl { class GlyphSet { public: void insert(uint32_t id, SDFGlyph&&); - const std::map<uint32_t, SDFGlyph> &getSDFs() const; - const Shaping getShaping(const std::u32string &string, float maxWidth, float lineHeight, - float horizontalAlign, float verticalAlign, float justify, - float spacing, const Point<float> &translate) const; - void lineWrap(Shaping &shaping, float lineHeight, float maxWidth, float horizontalAlign, - float verticalAlign, float justify, const Point<float> &translate) const; + const std::map<uint32_t, SDFGlyph>& getSDFs() const; + const Shaping getShaping(const std::u16string& string, + float maxWidth, + float lineHeight, + float horizontalAlign, + float verticalAlign, + float justify, + float spacing, + const Point<float>& translate, + BiDi& bidi) const; private: + float determineIdeographicLineWidth(const std::u16string& logicalInput, + const float spacing, + float maxWidth) const; + std::set<int32_t> determineLineBreaks(const std::u16string& logicalInput, + const float spacing, + float maxWidth) const; + + void shapeLines(Shaping& shaping, + const std::vector<std::u16string>& lines, + const float spacing, + float lineHeight, + float horizontalAlign, + float verticalAlign, + float justify, + const Point<float>& translate) const; + std::map<uint32_t, SDFGlyph> sdfs; }; diff --git a/src/mbgl/text/quads.cpp b/src/mbgl/text/quads.cpp index 3f142cd908..1a05e6f94f 100644 --- a/src/mbgl/text/quads.cpp +++ b/src/mbgl/text/quads.cpp @@ -14,7 +14,7 @@ using namespace style; const float globalMinScale = 0.5f; // underscale by 1 zoom level SymbolQuads getIconQuads(Anchor& anchor, const PositionedIcon& shapedIcon, - const GeometryCoordinates& line, const SymbolLayoutProperties& layout, + const GeometryCoordinates& line, const SymbolLayoutProperties::Evaluated& layout, const style::SymbolPlacementType placement, const Shaping& shapedText) { auto image = *(shapedIcon.image); @@ -29,24 +29,24 @@ SymbolQuads getIconQuads(Anchor& anchor, const PositionedIcon& shapedIcon, Point<float> br; Point<float> bl; - if (layout.iconTextFit != IconTextFitType::None && shapedText) { + if (layout.get<IconTextFit>() != IconTextFitType::None && shapedText) { auto iconWidth = right - left; auto iconHeight = bottom - top; - auto size = layout.textSize / 24.0f; + auto size = layout.get<TextSize>() / 24.0f; auto textLeft = shapedText.left * size; auto textRight = shapedText.right * size; auto textTop = shapedText.top * size; auto textBottom = shapedText.bottom * size; auto textWidth = textRight - textLeft; auto textHeight = textBottom - textTop;; - auto padT = layout.iconTextFitPadding.value[0]; - auto padR = layout.iconTextFitPadding.value[1]; - auto padB = layout.iconTextFitPadding.value[2]; - auto padL = layout.iconTextFitPadding.value[3]; - auto offsetY = layout.iconTextFit == IconTextFitType::Width ? (textHeight - iconHeight) * 0.5 : 0; - auto offsetX = layout.iconTextFit == IconTextFitType::Height ? (textWidth - iconWidth) * 0.5 : 0; - auto width = layout.iconTextFit == IconTextFitType::Width || layout.iconTextFit == IconTextFitType::Both ? textWidth : iconWidth; - auto height = layout.iconTextFit == IconTextFitType::Height || layout.iconTextFit == IconTextFitType::Both ? textHeight : iconHeight; + auto padT = layout.get<IconTextFitPadding>()[0]; + auto padR = layout.get<IconTextFitPadding>()[1]; + auto padB = layout.get<IconTextFitPadding>()[2]; + auto padL = layout.get<IconTextFitPadding>()[3]; + auto offsetY = layout.get<IconTextFit>() == IconTextFitType::Width ? (textHeight - iconHeight) * 0.5 : 0; + auto offsetX = layout.get<IconTextFit>() == IconTextFitType::Height ? (textWidth - iconWidth) * 0.5 : 0; + auto width = layout.get<IconTextFit>() == IconTextFitType::Width || layout.get<IconTextFit>() == IconTextFitType::Both ? textWidth : iconWidth; + auto height = layout.get<IconTextFit>() == IconTextFitType::Height || layout.get<IconTextFit>() == IconTextFitType::Both ? textHeight : iconHeight; left = textLeft + offsetX - padL; top = textTop + offsetY - padT; right = textLeft + offsetX + padR + width; @@ -62,7 +62,7 @@ SymbolQuads getIconQuads(Anchor& anchor, const PositionedIcon& shapedIcon, bl = {left, bottom}; } - float angle = layout.iconRotate * util::DEG2RAD; + float angle = layout.get<IconRotate>() * util::DEG2RAD; if (placement == style::SymbolPlacementType::Line) { assert(static_cast<unsigned int>(anchor.segment) < line.size()); const GeometryCoordinate &prev= line[anchor.segment]; @@ -165,11 +165,11 @@ void getSegmentGlyphs(std::back_insert_iterator<GlyphInstances> glyphs, Anchor & } SymbolQuads getGlyphQuads(Anchor& anchor, const Shaping& shapedText, - const float boxScale, const GeometryCoordinates& line, const SymbolLayoutProperties& layout, + const float boxScale, const GeometryCoordinates& line, const SymbolLayoutProperties::Evaluated& layout, const style::SymbolPlacementType placement, const GlyphPositions& face) { - const float textRotate = layout.textRotate * util::DEG2RAD; - const bool keepUpright = layout.textKeepUpright; + const float textRotate = layout.get<TextRotate>() * util::DEG2RAD; + const bool keepUpright = layout.get<TextKeepUpright>(); SymbolQuads quads; diff --git a/src/mbgl/text/quads.hpp b/src/mbgl/text/quads.hpp index d4edbf9493..75fb53aade 100644 --- a/src/mbgl/text/quads.hpp +++ b/src/mbgl/text/quads.hpp @@ -2,6 +2,7 @@ #include <mbgl/text/glyph.hpp> #include <mbgl/style/types.hpp> +#include <mbgl/style/layers/symbol_layer_properties.hpp> #include <mbgl/tile/geometry_tile_data.hpp> #include <vector> @@ -11,10 +12,6 @@ namespace mbgl { struct Anchor; class PositionedIcon; -namespace style { -class SymbolLayoutProperties; -} // namespace style - struct SymbolQuad { explicit SymbolQuad(Point<float> tl_, Point<float> tr_, Point<float> bl_, Point<float> br_, Rect<uint16_t> tex_, float anchorAngle_, float glyphAngle_, Point<float> anchorPoint_, @@ -40,11 +37,11 @@ struct SymbolQuad { typedef std::vector<SymbolQuad> SymbolQuads; SymbolQuads getIconQuads(Anchor& anchor, const PositionedIcon& shapedIcon, - const GeometryCoordinates& line, const style::SymbolLayoutProperties&, + const GeometryCoordinates& line, const style::SymbolLayoutProperties::Evaluated&, style::SymbolPlacementType placement, const Shaping& shapedText); SymbolQuads getGlyphQuads(Anchor& anchor, const Shaping& shapedText, - const float boxScale, const GeometryCoordinates& line, const style::SymbolLayoutProperties&, + const float boxScale, const GeometryCoordinates& line, const style::SymbolLayoutProperties::Evaluated&, style::SymbolPlacementType placement, const GlyphPositions& face); } // namespace mbgl diff --git a/src/mbgl/text/shaping.cpp b/src/mbgl/text/shaping.cpp index 1091cd6e94..062066aaf4 100644 --- a/src/mbgl/text/shaping.cpp +++ b/src/mbgl/text/shaping.cpp @@ -3,9 +3,11 @@ namespace mbgl { -PositionedIcon shapeIcon(const SpriteAtlasElement& image, const style::SymbolLayoutProperties& layout) { - float dx = layout.iconOffset.value[0]; - float dy = layout.iconOffset.value[1]; +using namespace style; + +PositionedIcon shapeIcon(const SpriteAtlasElement& image, const SymbolLayoutProperties::Evaluated& layout) { + float dx = layout.get<IconOffset>()[0]; + float dy = layout.get<IconOffset>()[1]; float x1 = dx - image.spriteImage->getWidth() / 2.0f; float x2 = x1 + image.spriteImage->getWidth(); float y1 = dy - image.spriteImage->getHeight() / 2.0f; diff --git a/src/mbgl/text/shaping.hpp b/src/mbgl/text/shaping.hpp index cd5e8105fd..30375179b6 100644 --- a/src/mbgl/text/shaping.hpp +++ b/src/mbgl/text/shaping.hpp @@ -3,15 +3,12 @@ #include <mbgl/text/glyph.hpp> #include <mbgl/sprite/sprite_atlas.hpp> #include <mbgl/sprite/sprite_image.hpp> +#include <mbgl/style/layers/symbol_layer_properties.hpp> #include <mbgl/util/optional.hpp> namespace mbgl { -struct SpriteAtlasElement; - -namespace style { -class SymbolLayoutProperties; -} // namespace style +class SpriteAtlasElement; class PositionedIcon { public: @@ -26,9 +23,9 @@ class PositionedIcon { float left = 0; float right = 0; - operator bool() const { return image && (*image).pos.hasArea(); } + explicit operator bool() const { return image && (*image).pos.hasArea(); } }; -PositionedIcon shapeIcon(const SpriteAtlasElement& image, const style::SymbolLayoutProperties&); +PositionedIcon shapeIcon(const SpriteAtlasElement& image, const style::SymbolLayoutProperties::Evaluated&); } // namespace mbgl diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp index 84455e4787..10c0e1b244 100644 --- a/src/mbgl/tile/geometry_tile.cpp +++ b/src/mbgl/tile/geometry_tile.cpp @@ -61,6 +61,12 @@ void GeometryTile::setPlacementConfig(const PlacementConfig& desiredConfig) { return; } + // Mark the tile as pending again if it was complete before to prevent signaling a complete + // state despite pending parse operations. + if (availableData == DataAvailability::All) { + availableData = DataAvailability::Some; + } + ++correlationID; requestedConfig = desiredConfig; worker.invoke(&GeometryTileWorker::setPlacementConfig, desiredConfig, correlationID); diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp index abb3894d34..738c78572d 100644 --- a/src/mbgl/tile/geometry_tile_worker.cpp +++ b/src/mbgl/tile/geometry_tile_worker.cpp @@ -8,7 +8,7 @@ #include <mbgl/style/layers/symbol_layer.hpp> #include <mbgl/style/layers/symbol_layer_impl.hpp> #include <mbgl/renderer/symbol_bucket.hpp> -#include <mbgl/platform/log.hpp> +#include <mbgl/util/logging.hpp> #include <mbgl/util/constants.hpp> #include <mbgl/util/string.hpp> #include <mbgl/util/exception.hpp> diff --git a/src/mbgl/tile/tile.cpp b/src/mbgl/tile/tile.cpp index 1375263107..e84eaaf780 100644 --- a/src/mbgl/tile/tile.cpp +++ b/src/mbgl/tile/tile.cpp @@ -2,7 +2,7 @@ #include <mbgl/tile/tile_observer.hpp> #include <mbgl/renderer/debug_bucket.hpp> #include <mbgl/util/string.hpp> -#include <mbgl/platform/log.hpp> +#include <mbgl/util/logging.hpp> namespace mbgl { diff --git a/src/mbgl/tile/tile.hpp b/src/mbgl/tile/tile.hpp index eea89bd634..cebf913f56 100644 --- a/src/mbgl/tile/tile.hpp +++ b/src/mbgl/tile/tile.hpp @@ -75,9 +75,6 @@ public: bool isComplete() const { return availableData == DataAvailability::All; } - bool isIncomplete() const { - return availableData == DataAvailability::Some; - } void dumpDebugLogs() const; diff --git a/src/mbgl/util/default_styles.cpp b/src/mbgl/util/default_styles.cpp deleted file mode 100644 index 17cc2f5740..0000000000 --- a/src/mbgl/util/default_styles.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include <mbgl/util/default_styles.hpp> - -namespace mbgl { -namespace util { -namespace default_styles { - -const DefaultStyle streets = { "mapbox://styles/mapbox/streets-v9", "Streets" }; -const DefaultStyle outdoors = { "mapbox://styles/mapbox/outdoors-v9", "Outdoors" }; -const DefaultStyle light = { "mapbox://styles/mapbox/light-v9", "Light" }; -const DefaultStyle dark = { "mapbox://styles/mapbox/dark-v9", "Dark" }; -const DefaultStyle satellite = { "mapbox://styles/mapbox/satellite-v9", "Satellite" }; -const DefaultStyle satelliteStreets = { "mapbox://styles/mapbox/satellite-streets-v9", "Satellite Streets" }; - -} // namespace default_styles -} // end namespace util -} // end namespace mbgl diff --git a/src/mbgl/platform/event.cpp b/src/mbgl/util/event.cpp index 68d75a2941..3a3be20f5c 100644 --- a/src/mbgl/platform/event.cpp +++ b/src/mbgl/util/event.cpp @@ -1,4 +1,4 @@ -#include <mbgl/platform/event.hpp> +#include <mbgl/util/event.hpp> #include <mbgl/util/enum.hpp> namespace mbgl { diff --git a/src/mbgl/util/i18n.cpp b/src/mbgl/util/i18n.cpp new file mode 100644 index 0000000000..4be624d2e5 --- /dev/null +++ b/src/mbgl/util/i18n.cpp @@ -0,0 +1,355 @@ +#include "i18n.hpp" + +namespace { + +/** Defines a function that returns true if a codepoint is in a named block. + @param name The name of the block in CamelCase. + @param first The first codepoint in the block, inclusive. + @param last The last codepoint in the block, inclusive. + */ +#define DEFINE_IS_IN_UNICODE_BLOCK(name, first, last) \ + inline bool isIn##name(uint16_t codepoint) { \ + return codepoint >= first && codepoint <= last; \ + } + +// The following table comes from <http://www.unicode.org/Public/9.0.0/ucd/Blocks.txt>. +// Keep it synchronized with <http://www.unicode.org/Public/UCD/latest/ucd/Blocks.txt>. + +// DEFINE_IS_IN_UNICODE_BLOCK(BasicLatin, 0x0000, 0x007F) +// DEFINE_IS_IN_UNICODE_BLOCK(Latin1Supplement, 0x0080, 0x00FF) +// DEFINE_IS_IN_UNICODE_BLOCK(LatinExtendedA, 0x0100, 0x017F) +// DEFINE_IS_IN_UNICODE_BLOCK(LatinExtendedB, 0x0180, 0x024F) +// DEFINE_IS_IN_UNICODE_BLOCK(IPAExtensions, 0x0250, 0x02AF) +// DEFINE_IS_IN_UNICODE_BLOCK(SpacingModifierLetters, 0x02B0, 0x02FF) +// DEFINE_IS_IN_UNICODE_BLOCK(CombiningDiacriticalMarks, 0x0300, 0x036F) +// DEFINE_IS_IN_UNICODE_BLOCK(GreekandCoptic, 0x0370, 0x03FF) +// DEFINE_IS_IN_UNICODE_BLOCK(Cyrillic, 0x0400, 0x04FF) +// DEFINE_IS_IN_UNICODE_BLOCK(CyrillicSupplement, 0x0500, 0x052F) +// DEFINE_IS_IN_UNICODE_BLOCK(Armenian, 0x0530, 0x058F) +// DEFINE_IS_IN_UNICODE_BLOCK(Hebrew, 0x0590, 0x05FF) +// DEFINE_IS_IN_UNICODE_BLOCK(Arabic, 0x0600, 0x06FF) +// DEFINE_IS_IN_UNICODE_BLOCK(Syriac, 0x0700, 0x074F) +// DEFINE_IS_IN_UNICODE_BLOCK(ArabicSupplement, 0x0750, 0x077F) +// DEFINE_IS_IN_UNICODE_BLOCK(Thaana, 0x0780, 0x07BF) +// DEFINE_IS_IN_UNICODE_BLOCK(NKo, 0x07C0, 0x07FF) +// DEFINE_IS_IN_UNICODE_BLOCK(Samaritan, 0x0800, 0x083F) +// DEFINE_IS_IN_UNICODE_BLOCK(Mandaic, 0x0840, 0x085F) +// DEFINE_IS_IN_UNICODE_BLOCK(ArabicExtendedA, 0x08A0, 0x08FF) +// DEFINE_IS_IN_UNICODE_BLOCK(Devanagari, 0x0900, 0x097F) +// DEFINE_IS_IN_UNICODE_BLOCK(Bengali, 0x0980, 0x09FF) +// DEFINE_IS_IN_UNICODE_BLOCK(Gurmukhi, 0x0A00, 0x0A7F) +// DEFINE_IS_IN_UNICODE_BLOCK(Gujarati, 0x0A80, 0x0AFF) +// DEFINE_IS_IN_UNICODE_BLOCK(Oriya, 0x0B00, 0x0B7F) +// DEFINE_IS_IN_UNICODE_BLOCK(Tamil, 0x0B80, 0x0BFF) +// DEFINE_IS_IN_UNICODE_BLOCK(Telugu, 0x0C00, 0x0C7F) +// DEFINE_IS_IN_UNICODE_BLOCK(Kannada, 0x0C80, 0x0CFF) +// DEFINE_IS_IN_UNICODE_BLOCK(Malayalam, 0x0D00, 0x0D7F) +// DEFINE_IS_IN_UNICODE_BLOCK(Sinhala, 0x0D80, 0x0DFF) +// DEFINE_IS_IN_UNICODE_BLOCK(Thai, 0x0E00, 0x0E7F) +// DEFINE_IS_IN_UNICODE_BLOCK(Lao, 0x0E80, 0x0EFF) +// DEFINE_IS_IN_UNICODE_BLOCK(Tibetan, 0x0F00, 0x0FFF) +// DEFINE_IS_IN_UNICODE_BLOCK(Myanmar, 0x1000, 0x109F) +// DEFINE_IS_IN_UNICODE_BLOCK(Georgian, 0x10A0, 0x10FF) +// DEFINE_IS_IN_UNICODE_BLOCK(HangulJamo, 0x1100, 0x11FF) +// DEFINE_IS_IN_UNICODE_BLOCK(Ethiopic, 0x1200, 0x137F) +// DEFINE_IS_IN_UNICODE_BLOCK(EthiopicSupplement, 0x1380, 0x139F) +// DEFINE_IS_IN_UNICODE_BLOCK(Cherokee, 0x13A0, 0x13FF) +// DEFINE_IS_IN_UNICODE_BLOCK(UnifiedCanadianAboriginalSyllabics, 0x1400, 0x167F) +// DEFINE_IS_IN_UNICODE_BLOCK(Ogham, 0x1680, 0x169F) +// DEFINE_IS_IN_UNICODE_BLOCK(Runic, 0x16A0, 0x16FF) +// DEFINE_IS_IN_UNICODE_BLOCK(Tagalog, 0x1700, 0x171F) +// DEFINE_IS_IN_UNICODE_BLOCK(Hanunoo, 0x1720, 0x173F) +// DEFINE_IS_IN_UNICODE_BLOCK(Buhid, 0x1740, 0x175F) +// DEFINE_IS_IN_UNICODE_BLOCK(Tagbanwa, 0x1760, 0x177F) +// DEFINE_IS_IN_UNICODE_BLOCK(Khmer, 0x1780, 0x17FF) +// DEFINE_IS_IN_UNICODE_BLOCK(Mongolian, 0x1800, 0x18AF) +// DEFINE_IS_IN_UNICODE_BLOCK(UnifiedCanadianAboriginalSyllabicsExtended, 0x18B0, 0x18FF) +// DEFINE_IS_IN_UNICODE_BLOCK(Limbu, 0x1900, 0x194F) +// DEFINE_IS_IN_UNICODE_BLOCK(TaiLe, 0x1950, 0x197F) +// DEFINE_IS_IN_UNICODE_BLOCK(NewTaiLue, 0x1980, 0x19DF) +// DEFINE_IS_IN_UNICODE_BLOCK(KhmerSymbols, 0x19E0, 0x19FF) +// DEFINE_IS_IN_UNICODE_BLOCK(Buginese, 0x1A00, 0x1A1F) +// DEFINE_IS_IN_UNICODE_BLOCK(TaiTham, 0x1A20, 0x1AAF) +// DEFINE_IS_IN_UNICODE_BLOCK(CombiningDiacriticalMarksExtended, 0x1AB0, 0x1AFF) +// DEFINE_IS_IN_UNICODE_BLOCK(Balinese, 0x1B00, 0x1B7F) +// DEFINE_IS_IN_UNICODE_BLOCK(Sundanese, 0x1B80, 0x1BBF) +// DEFINE_IS_IN_UNICODE_BLOCK(Batak, 0x1BC0, 0x1BFF) +// DEFINE_IS_IN_UNICODE_BLOCK(Lepcha, 0x1C00, 0x1C4F) +// DEFINE_IS_IN_UNICODE_BLOCK(OlChiki, 0x1C50, 0x1C7F) +// DEFINE_IS_IN_UNICODE_BLOCK(CyrillicExtendedC, 0x1C80, 0x1C8F) +// DEFINE_IS_IN_UNICODE_BLOCK(SundaneseSupplement, 0x1CC0, 0x1CCF) +// DEFINE_IS_IN_UNICODE_BLOCK(VedicExtensions, 0x1CD0, 0x1CFF) +// DEFINE_IS_IN_UNICODE_BLOCK(PhoneticExtensions, 0x1D00, 0x1D7F) +// DEFINE_IS_IN_UNICODE_BLOCK(PhoneticExtensionsSupplement, 0x1D80, 0x1DBF) +// DEFINE_IS_IN_UNICODE_BLOCK(CombiningDiacriticalMarksSupplement, 0x1DC0, 0x1DFF) +// DEFINE_IS_IN_UNICODE_BLOCK(LatinExtendedAdditional, 0x1E00, 0x1EFF) +// DEFINE_IS_IN_UNICODE_BLOCK(GreekExtended, 0x1F00, 0x1FFF) +// DEFINE_IS_IN_UNICODE_BLOCK(GeneralPunctuation, 0x2000, 0x206F) +// DEFINE_IS_IN_UNICODE_BLOCK(SuperscriptsandSubscripts, 0x2070, 0x209F) +// DEFINE_IS_IN_UNICODE_BLOCK(CurrencySymbols, 0x20A0, 0x20CF) +// DEFINE_IS_IN_UNICODE_BLOCK(CombiningDiacriticalMarksforSymbols, 0x20D0, 0x20FF) +// DEFINE_IS_IN_UNICODE_BLOCK(LetterlikeSymbols, 0x2100, 0x214F) +// DEFINE_IS_IN_UNICODE_BLOCK(NumberForms, 0x2150, 0x218F) +// DEFINE_IS_IN_UNICODE_BLOCK(Arrows, 0x2190, 0x21FF) +// DEFINE_IS_IN_UNICODE_BLOCK(MathematicalOperators, 0x2200, 0x22FF) +// DEFINE_IS_IN_UNICODE_BLOCK(MiscellaneousTechnical, 0x2300, 0x23FF) +// DEFINE_IS_IN_UNICODE_BLOCK(ControlPictures, 0x2400, 0x243F) +// DEFINE_IS_IN_UNICODE_BLOCK(OpticalCharacterRecognition, 0x2440, 0x245F) +// DEFINE_IS_IN_UNICODE_BLOCK(EnclosedAlphanumerics, 0x2460, 0x24FF) +// DEFINE_IS_IN_UNICODE_BLOCK(BoxDrawing, 0x2500, 0x257F) +// DEFINE_IS_IN_UNICODE_BLOCK(BlockElements, 0x2580, 0x259F) +// DEFINE_IS_IN_UNICODE_BLOCK(GeometricShapes, 0x25A0, 0x25FF) +// DEFINE_IS_IN_UNICODE_BLOCK(MiscellaneousSymbols, 0x2600, 0x26FF) +// DEFINE_IS_IN_UNICODE_BLOCK(Dingbats, 0x2700, 0x27BF) +// DEFINE_IS_IN_UNICODE_BLOCK(MiscellaneousMathematicalSymbolsA, 0x27C0, 0x27EF) +// DEFINE_IS_IN_UNICODE_BLOCK(SupplementalArrowsA, 0x27F0, 0x27FF) +// DEFINE_IS_IN_UNICODE_BLOCK(BraillePatterns, 0x2800, 0x28FF) +// DEFINE_IS_IN_UNICODE_BLOCK(SupplementalArrowsB, 0x2900, 0x297F) +// DEFINE_IS_IN_UNICODE_BLOCK(MiscellaneousMathematicalSymbolsB, 0x2980, 0x29FF) +// DEFINE_IS_IN_UNICODE_BLOCK(SupplementalMathematicalOperators, 0x2A00, 0x2AFF) +// DEFINE_IS_IN_UNICODE_BLOCK(MiscellaneousSymbolsandArrows, 0x2B00, 0x2BFF) +// DEFINE_IS_IN_UNICODE_BLOCK(Glagolitic, 0x2C00, 0x2C5F) +// DEFINE_IS_IN_UNICODE_BLOCK(LatinExtendedC, 0x2C60, 0x2C7F) +// DEFINE_IS_IN_UNICODE_BLOCK(Coptic, 0x2C80, 0x2CFF) +// DEFINE_IS_IN_UNICODE_BLOCK(GeorgianSupplement, 0x2D00, 0x2D2F) +// DEFINE_IS_IN_UNICODE_BLOCK(Tifinagh, 0x2D30, 0x2D7F) +// DEFINE_IS_IN_UNICODE_BLOCK(EthiopicExtended, 0x2D80, 0x2DDF) +// DEFINE_IS_IN_UNICODE_BLOCK(CyrillicExtendedA, 0x2DE0, 0x2DFF) +// DEFINE_IS_IN_UNICODE_BLOCK(SupplementalPunctuation, 0x2E00, 0x2E7F) +DEFINE_IS_IN_UNICODE_BLOCK(CJKRadicalsSupplement, 0x2E80, 0x2EFF) +DEFINE_IS_IN_UNICODE_BLOCK(KangxiRadicals, 0x2F00, 0x2FDF) +DEFINE_IS_IN_UNICODE_BLOCK(IdeographicDescriptionCharacters, 0x2FF0, 0x2FFF) +DEFINE_IS_IN_UNICODE_BLOCK(CJKSymbolsandPunctuation, 0x3000, 0x303F) +DEFINE_IS_IN_UNICODE_BLOCK(Hiragana, 0x3040, 0x309F) +DEFINE_IS_IN_UNICODE_BLOCK(Katakana, 0x30A0, 0x30FF) +DEFINE_IS_IN_UNICODE_BLOCK(Bopomofo, 0x3100, 0x312F) +// DEFINE_IS_IN_UNICODE_BLOCK(HangulCompatibilityJamo, 0x3130, 0x318F) +// DEFINE_IS_IN_UNICODE_BLOCK(Kanbun, 0x3190, 0x319F) +DEFINE_IS_IN_UNICODE_BLOCK(BopomofoExtended, 0x31A0, 0x31BF) +DEFINE_IS_IN_UNICODE_BLOCK(CJKStrokes, 0x31C0, 0x31EF) +DEFINE_IS_IN_UNICODE_BLOCK(KatakanaPhoneticExtensions, 0x31F0, 0x31FF) +DEFINE_IS_IN_UNICODE_BLOCK(EnclosedCJKLettersandMonths, 0x3200, 0x32FF) +DEFINE_IS_IN_UNICODE_BLOCK(CJKCompatibility, 0x3300, 0x33FF) +DEFINE_IS_IN_UNICODE_BLOCK(CJKUnifiedIdeographsExtensionA, 0x3400, 0x4DBF) +// DEFINE_IS_IN_UNICODE_BLOCK(YijingHexagramSymbols, 0x4DC0, 0x4DFF) +DEFINE_IS_IN_UNICODE_BLOCK(CJKUnifiedIdeographs, 0x4E00, 0x9FFF) +DEFINE_IS_IN_UNICODE_BLOCK(YiSyllables, 0xA000, 0xA48F) +DEFINE_IS_IN_UNICODE_BLOCK(YiRadicals, 0xA490, 0xA4CF) +// DEFINE_IS_IN_UNICODE_BLOCK(Lisu, 0xA4D0, 0xA4FF) +// DEFINE_IS_IN_UNICODE_BLOCK(Vai, 0xA500, 0xA63F) +// DEFINE_IS_IN_UNICODE_BLOCK(CyrillicExtendedB, 0xA640, 0xA69F) +// DEFINE_IS_IN_UNICODE_BLOCK(Bamum, 0xA6A0, 0xA6FF) +// DEFINE_IS_IN_UNICODE_BLOCK(ModifierToneLetters, 0xA700, 0xA71F) +// DEFINE_IS_IN_UNICODE_BLOCK(LatinExtendedD, 0xA720, 0xA7FF) +// DEFINE_IS_IN_UNICODE_BLOCK(SylotiNagri, 0xA800, 0xA82F) +// DEFINE_IS_IN_UNICODE_BLOCK(CommonIndicNumberForms, 0xA830, 0xA83F) +// DEFINE_IS_IN_UNICODE_BLOCK(Phagspa, 0xA840, 0xA87F) +// DEFINE_IS_IN_UNICODE_BLOCK(Saurashtra, 0xA880, 0xA8DF) +// DEFINE_IS_IN_UNICODE_BLOCK(DevanagariExtended, 0xA8E0, 0xA8FF) +// DEFINE_IS_IN_UNICODE_BLOCK(KayahLi, 0xA900, 0xA92F) +// DEFINE_IS_IN_UNICODE_BLOCK(Rejang, 0xA930, 0xA95F) +// DEFINE_IS_IN_UNICODE_BLOCK(HangulJamoExtendedA, 0xA960, 0xA97F) +// DEFINE_IS_IN_UNICODE_BLOCK(Javanese, 0xA980, 0xA9DF) +// DEFINE_IS_IN_UNICODE_BLOCK(MyanmarExtendedB, 0xA9E0, 0xA9FF) +// DEFINE_IS_IN_UNICODE_BLOCK(Cham, 0xAA00, 0xAA5F) +// DEFINE_IS_IN_UNICODE_BLOCK(MyanmarExtendedA, 0xAA60, 0xAA7F) +// DEFINE_IS_IN_UNICODE_BLOCK(TaiViet, 0xAA80, 0xAADF) +// DEFINE_IS_IN_UNICODE_BLOCK(MeeteiMayekExtensions, 0xAAE0, 0xAAFF) +// DEFINE_IS_IN_UNICODE_BLOCK(EthiopicExtendedA, 0xAB00, 0xAB2F) +// DEFINE_IS_IN_UNICODE_BLOCK(LatinExtendedE, 0xAB30, 0xAB6F) +// DEFINE_IS_IN_UNICODE_BLOCK(CherokeeSupplement, 0xAB70, 0xABBF) +// DEFINE_IS_IN_UNICODE_BLOCK(MeeteiMayek, 0xABC0, 0xABFF) +// DEFINE_IS_IN_UNICODE_BLOCK(HangulSyllables, 0xAC00, 0xD7AF) +// DEFINE_IS_IN_UNICODE_BLOCK(HangulJamoExtendedB, 0xD7B0, 0xD7FF) +// DEFINE_IS_IN_UNICODE_BLOCK(HighSurrogates, 0xD800, 0xDB7F) +// DEFINE_IS_IN_UNICODE_BLOCK(HighPrivateUseSurrogates, 0xDB80, 0xDBFF) +// DEFINE_IS_IN_UNICODE_BLOCK(LowSurrogates, 0xDC00, 0xDFFF) +// DEFINE_IS_IN_UNICODE_BLOCK(PrivateUseArea, 0xE000, 0xF8FF) +DEFINE_IS_IN_UNICODE_BLOCK(CJKCompatibilityIdeographs, 0xF900, 0xFAFF) +// DEFINE_IS_IN_UNICODE_BLOCK(AlphabeticPresentationForms, 0xFB00, 0xFB4F) +// DEFINE_IS_IN_UNICODE_BLOCK(ArabicPresentationFormsA, 0xFB50, 0xFDFF) +// DEFINE_IS_IN_UNICODE_BLOCK(VariationSelectors, 0xFE00, 0xFE0F) +DEFINE_IS_IN_UNICODE_BLOCK(VerticalForms, 0xFE10, 0xFE1F) +// DEFINE_IS_IN_UNICODE_BLOCK(CombiningHalfMarks, 0xFE20, 0xFE2F) +DEFINE_IS_IN_UNICODE_BLOCK(CJKCompatibilityForms, 0xFE30, 0xFE4F) +// DEFINE_IS_IN_UNICODE_BLOCK(SmallFormVariants, 0xFE50, 0xFE6F) +// DEFINE_IS_IN_UNICODE_BLOCK(ArabicPresentationFormsB, 0xFE70, 0xFEFF) +DEFINE_IS_IN_UNICODE_BLOCK(HalfwidthandFullwidthForms, 0xFF00, 0xFFEF) +// DEFINE_IS_IN_UNICODE_BLOCK(Specials, 0xFFF0, 0xFFFF) +// DEFINE_IS_IN_UNICODE_BLOCK(LinearBSyllabary, 0x10000, 0x1007F) +// DEFINE_IS_IN_UNICODE_BLOCK(LinearBIdeograms, 0x10080, 0x100FF) +// DEFINE_IS_IN_UNICODE_BLOCK(AegeanNumbers, 0x10100, 0x1013F) +// DEFINE_IS_IN_UNICODE_BLOCK(AncientGreekNumbers, 0x10140, 0x1018F) +// DEFINE_IS_IN_UNICODE_BLOCK(AncientSymbols, 0x10190, 0x101CF) +// DEFINE_IS_IN_UNICODE_BLOCK(PhaistosDisc, 0x101D0, 0x101FF) +// DEFINE_IS_IN_UNICODE_BLOCK(Lycian, 0x10280, 0x1029F) +// DEFINE_IS_IN_UNICODE_BLOCK(Carian, 0x102A0, 0x102DF) +// DEFINE_IS_IN_UNICODE_BLOCK(CopticEpactNumbers, 0x102E0, 0x102FF) +// DEFINE_IS_IN_UNICODE_BLOCK(OldItalic, 0x10300, 0x1032F) +// DEFINE_IS_IN_UNICODE_BLOCK(Gothic, 0x10330, 0x1034F) +// DEFINE_IS_IN_UNICODE_BLOCK(OldPermic, 0x10350, 0x1037F) +// DEFINE_IS_IN_UNICODE_BLOCK(Ugaritic, 0x10380, 0x1039F) +// DEFINE_IS_IN_UNICODE_BLOCK(OldPersian, 0x103A0, 0x103DF) +// DEFINE_IS_IN_UNICODE_BLOCK(Deseret, 0x10400, 0x1044F) +// DEFINE_IS_IN_UNICODE_BLOCK(Shavian, 0x10450, 0x1047F) +// DEFINE_IS_IN_UNICODE_BLOCK(Osmanya, 0x10480, 0x104AF) +// DEFINE_IS_IN_UNICODE_BLOCK(Osage, 0x104B0, 0x104FF) +// DEFINE_IS_IN_UNICODE_BLOCK(Elbasan, 0x10500, 0x1052F) +// DEFINE_IS_IN_UNICODE_BLOCK(CaucasianAlbanian, 0x10530, 0x1056F) +// DEFINE_IS_IN_UNICODE_BLOCK(LinearA, 0x10600, 0x1077F) +// DEFINE_IS_IN_UNICODE_BLOCK(CypriotSyllabary, 0x10800, 0x1083F) +// DEFINE_IS_IN_UNICODE_BLOCK(ImperialAramaic, 0x10840, 0x1085F) +// DEFINE_IS_IN_UNICODE_BLOCK(Palmyrene, 0x10860, 0x1087F) +// DEFINE_IS_IN_UNICODE_BLOCK(Nabataean, 0x10880, 0x108AF) +// DEFINE_IS_IN_UNICODE_BLOCK(Hatran, 0x108E0, 0x108FF) +// DEFINE_IS_IN_UNICODE_BLOCK(Phoenician, 0x10900, 0x1091F) +// DEFINE_IS_IN_UNICODE_BLOCK(Lydian, 0x10920, 0x1093F) +// DEFINE_IS_IN_UNICODE_BLOCK(MeroiticHieroglyphs, 0x10980, 0x1099F) +// DEFINE_IS_IN_UNICODE_BLOCK(MeroiticCursive, 0x109A0, 0x109FF) +// DEFINE_IS_IN_UNICODE_BLOCK(Kharoshthi, 0x10A00, 0x10A5F) +// DEFINE_IS_IN_UNICODE_BLOCK(OldSouthArabian, 0x10A60, 0x10A7F) +// DEFINE_IS_IN_UNICODE_BLOCK(OldNorthArabian, 0x10A80, 0x10A9F) +// DEFINE_IS_IN_UNICODE_BLOCK(Manichaean, 0x10AC0, 0x10AFF) +// DEFINE_IS_IN_UNICODE_BLOCK(Avestan, 0x10B00, 0x10B3F) +// DEFINE_IS_IN_UNICODE_BLOCK(InscriptionalParthian, 0x10B40, 0x10B5F) +// DEFINE_IS_IN_UNICODE_BLOCK(InscriptionalPahlavi, 0x10B60, 0x10B7F) +// DEFINE_IS_IN_UNICODE_BLOCK(PsalterPahlavi, 0x10B80, 0x10BAF) +// DEFINE_IS_IN_UNICODE_BLOCK(OldTurkic, 0x10C00, 0x10C4F) +// DEFINE_IS_IN_UNICODE_BLOCK(OldHungarian, 0x10C80, 0x10CFF) +// DEFINE_IS_IN_UNICODE_BLOCK(RumiNumeralSymbols, 0x10E60, 0x10E7F) +// DEFINE_IS_IN_UNICODE_BLOCK(Brahmi, 0x11000, 0x1107F) +// DEFINE_IS_IN_UNICODE_BLOCK(Kaithi, 0x11080, 0x110CF) +// DEFINE_IS_IN_UNICODE_BLOCK(SoraSompeng, 0x110D0, 0x110FF) +// DEFINE_IS_IN_UNICODE_BLOCK(Chakma, 0x11100, 0x1114F) +// DEFINE_IS_IN_UNICODE_BLOCK(Mahajani, 0x11150, 0x1117F) +// DEFINE_IS_IN_UNICODE_BLOCK(Sharada, 0x11180, 0x111DF) +// DEFINE_IS_IN_UNICODE_BLOCK(SinhalaArchaicNumbers, 0x111E0, 0x111FF) +// DEFINE_IS_IN_UNICODE_BLOCK(Khojki, 0x11200, 0x1124F) +// DEFINE_IS_IN_UNICODE_BLOCK(Multani, 0x11280, 0x112AF) +// DEFINE_IS_IN_UNICODE_BLOCK(Khudawadi, 0x112B0, 0x112FF) +// DEFINE_IS_IN_UNICODE_BLOCK(Grantha, 0x11300, 0x1137F) +// DEFINE_IS_IN_UNICODE_BLOCK(Newa, 0x11400, 0x1147F) +// DEFINE_IS_IN_UNICODE_BLOCK(Tirhuta, 0x11480, 0x114DF) +// DEFINE_IS_IN_UNICODE_BLOCK(Siddham, 0x11580, 0x115FF) +// DEFINE_IS_IN_UNICODE_BLOCK(Modi, 0x11600, 0x1165F) +// DEFINE_IS_IN_UNICODE_BLOCK(MongolianSupplement, 0x11660, 0x1167F) +// DEFINE_IS_IN_UNICODE_BLOCK(Takri, 0x11680, 0x116CF) +// DEFINE_IS_IN_UNICODE_BLOCK(Ahom, 0x11700, 0x1173F) +// DEFINE_IS_IN_UNICODE_BLOCK(WarangCiti, 0x118A0, 0x118FF) +// DEFINE_IS_IN_UNICODE_BLOCK(PauCinHau, 0x11AC0, 0x11AFF) +// DEFINE_IS_IN_UNICODE_BLOCK(Bhaiksuki, 0x11C00, 0x11C6F) +// DEFINE_IS_IN_UNICODE_BLOCK(Marchen, 0x11C70, 0x11CBF) +// DEFINE_IS_IN_UNICODE_BLOCK(Cuneiform, 0x12000, 0x123FF) +// DEFINE_IS_IN_UNICODE_BLOCK(CuneiformNumbersandPunctuation, 0x12400, 0x1247F) +// DEFINE_IS_IN_UNICODE_BLOCK(EarlyDynasticCuneiform, 0x12480, 0x1254F) +// DEFINE_IS_IN_UNICODE_BLOCK(EgyptianHieroglyphs, 0x13000, 0x1342F) +// DEFINE_IS_IN_UNICODE_BLOCK(AnatolianHieroglyphs, 0x14400, 0x1467F) +// DEFINE_IS_IN_UNICODE_BLOCK(BamumSupplement, 0x16800, 0x16A3F) +// DEFINE_IS_IN_UNICODE_BLOCK(Mro, 0x16A40, 0x16A6F) +// DEFINE_IS_IN_UNICODE_BLOCK(BassaVah, 0x16AD0, 0x16AFF) +// DEFINE_IS_IN_UNICODE_BLOCK(PahawhHmong, 0x16B00, 0x16B8F) +// DEFINE_IS_IN_UNICODE_BLOCK(Miao, 0x16F00, 0x16F9F) +// DEFINE_IS_IN_UNICODE_BLOCK(IdeographicSymbolsandPunctuation, 0x16FE0, 0x16FFF) +// DEFINE_IS_IN_UNICODE_BLOCK(Tangut, 0x17000, 0x187FF) +// DEFINE_IS_IN_UNICODE_BLOCK(TangutComponents, 0x18800, 0x18AFF) +// DEFINE_IS_IN_UNICODE_BLOCK(KanaSupplement, 0x1B000, 0x1B0FF) +// DEFINE_IS_IN_UNICODE_BLOCK(Duployan, 0x1BC00, 0x1BC9F) +// DEFINE_IS_IN_UNICODE_BLOCK(ShorthandFormatControls, 0x1BCA0, 0x1BCAF) +// DEFINE_IS_IN_UNICODE_BLOCK(ByzantineMusicalSymbols, 0x1D000, 0x1D0FF) +// DEFINE_IS_IN_UNICODE_BLOCK(MusicalSymbols, 0x1D100, 0x1D1FF) +// DEFINE_IS_IN_UNICODE_BLOCK(AncientGreekMusicalNotation, 0x1D200, 0x1D24F) +// DEFINE_IS_IN_UNICODE_BLOCK(TaiXuanJingSymbols, 0x1D300, 0x1D35F) +// DEFINE_IS_IN_UNICODE_BLOCK(CountingRodNumerals, 0x1D360, 0x1D37F) +// DEFINE_IS_IN_UNICODE_BLOCK(MathematicalAlphanumericSymbols, 0x1D400, 0x1D7FF) +// DEFINE_IS_IN_UNICODE_BLOCK(SuttonSignWriting, 0x1D800, 0x1DAAF) +// DEFINE_IS_IN_UNICODE_BLOCK(GlagoliticSupplement, 0x1E000, 0x1E02F) +// DEFINE_IS_IN_UNICODE_BLOCK(MendeKikakui, 0x1E800, 0x1E8DF) +// DEFINE_IS_IN_UNICODE_BLOCK(Adlam, 0x1E900, 0x1E95F) +// DEFINE_IS_IN_UNICODE_BLOCK(ArabicMathematicalAlphabeticSymbols, 0x1EE00, 0x1EEFF) +// DEFINE_IS_IN_UNICODE_BLOCK(MahjongTiles, 0x1F000, 0x1F02F) +// DEFINE_IS_IN_UNICODE_BLOCK(DominoTiles, 0x1F030, 0x1F09F) +// DEFINE_IS_IN_UNICODE_BLOCK(PlayingCards, 0x1F0A0, 0x1F0FF) +// DEFINE_IS_IN_UNICODE_BLOCK(EnclosedAlphanumericSupplement, 0x1F100, 0x1F1FF) +// DEFINE_IS_IN_UNICODE_BLOCK(EnclosedIdeographicSupplement, 0x1F200, 0x1F2FF) +// DEFINE_IS_IN_UNICODE_BLOCK(MiscellaneousSymbolsandPictographs, 0x1F300, 0x1F5FF) +// DEFINE_IS_IN_UNICODE_BLOCK(Emoticons, 0x1F600, 0x1F64F) +// DEFINE_IS_IN_UNICODE_BLOCK(OrnamentalDingbats, 0x1F650, 0x1F67F) +// DEFINE_IS_IN_UNICODE_BLOCK(TransportandMapSymbols, 0x1F680, 0x1F6FF) +// DEFINE_IS_IN_UNICODE_BLOCK(AlchemicalSymbols, 0x1F700, 0x1F77F) +// DEFINE_IS_IN_UNICODE_BLOCK(GeometricShapesExtended, 0x1F780, 0x1F7FF) +// DEFINE_IS_IN_UNICODE_BLOCK(SupplementalArrowsC, 0x1F800, 0x1F8FF) +// DEFINE_IS_IN_UNICODE_BLOCK(SupplementalSymbolsandPictographs, 0x1F900, 0x1F9FF) +// DEFINE_IS_IN_UNICODE_BLOCK(CJKUnifiedIdeographsExtensionB, 0x20000, 0x2A6DF) +// DEFINE_IS_IN_UNICODE_BLOCK(CJKUnifiedIdeographsExtensionC, 0x2A700, 0x2B73F) +// DEFINE_IS_IN_UNICODE_BLOCK(CJKUnifiedIdeographsExtensionD, 0x2B740, 0x2B81F) +// DEFINE_IS_IN_UNICODE_BLOCK(CJKUnifiedIdeographsExtensionE, 0x2B820, 0x2CEAF) +// DEFINE_IS_IN_UNICODE_BLOCK(CJKCompatibilityIdeographsSupplement, 0x2F800, 0x2FA1F) +// DEFINE_IS_IN_UNICODE_BLOCK(Tags, 0xE0000, 0xE007F) +// DEFINE_IS_IN_UNICODE_BLOCK(VariationSelectorsSupplement, 0xE0100, 0xE01EF) +// DEFINE_IS_IN_UNICODE_BLOCK(SupplementaryPrivateUseAreaA, 0xF0000, 0xFFFFF) +// DEFINE_IS_IN_UNICODE_BLOCK(SupplementaryPrivateUseAreaB, 0x100000, 0x10FFFF) +} + +namespace mbgl { +namespace util { +namespace i18n { + +bool allowsWordBreaking(uint16_t chr) { + return (chr == 0x0a /* newline */ + || chr == 0x20 /* space */ + || chr == 0x26 /* ampersand */ + || chr == 0x2b /* plus sign */ + || chr == 0x2d /* hyphen-minus */ + || chr == 0x2f /* solidus */ + || chr == 0xad /* soft hyphen */ + || chr == 0xb7 /* middle dot */ + || chr == 0x200b /* zero-width space */ + || chr == 0x2010 /* hyphen */ + || chr == 0x2013 /* en dash */); +} + +bool allowsIdeographicBreaking(const std::u16string& string) { + for (uint16_t chr : string) { + if (!allowsIdeographicBreaking(chr)) { + return false; + } + } + return true; +} + +bool allowsIdeographicBreaking(uint16_t chr) { + // Allow U+2027 "Interpunct" for hyphenation of Chinese words + if (chr == 0x2027) + return true; + + // Return early for characters outside all ideographic ranges. + if (chr < 0x2E80) + return false; + + return (isInBopomofo(chr) || isInBopomofoExtended(chr) || isInCJKCompatibility(chr) || + isInCJKCompatibilityForms(chr) || isInCJKCompatibilityIdeographs(chr) || + isInCJKRadicalsSupplement(chr) || isInCJKStrokes(chr) || + isInCJKSymbolsandPunctuation(chr) || isInCJKUnifiedIdeographs(chr) || + isInCJKUnifiedIdeographsExtensionA(chr) || isInEnclosedCJKLettersandMonths(chr) || + isInHalfwidthandFullwidthForms(chr) || isInHiragana(chr) || + isInIdeographicDescriptionCharacters(chr) || isInKangxiRadicals(chr) || + isInKatakana(chr) || isInKatakanaPhoneticExtensions(chr) || isInVerticalForms(chr) || + isInYiRadicals(chr) || isInYiSyllables(chr)); + + // The following blocks also allow ideographic breaking; however, for other + // reasons, Mapbox GL lacks support for codepoints beyond U+FFFF. + // https://github.com/mapbox/mapbox-gl/issues/29 + // return (isInTangut(chr) + // || isInTangutComponents(chr) + // || isInIdeographicSymbolsandPunctuation(chr) + // || isInEnclosedIdeographicSupplement(chr) + // || isInCJKUnifiedIdeographsExtensionB(chr) + // || isInCJKUnifiedIdeographsExtensionC(chr) + // || isInCJKUnifiedIdeographsExtensionD(chr) + // || isInCJKUnifiedIdeographsExtensionE(chr) + // || isInCJKCompatibilityIdeographsSupplement(chr)); +} + +} // namespace i18n +} // namespace util +} // namespace mbgl diff --git a/src/mbgl/util/i18n.hpp b/src/mbgl/util/i18n.hpp new file mode 100644 index 0000000000..f1d3f53f72 --- /dev/null +++ b/src/mbgl/util/i18n.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include <string> + +namespace mbgl { +namespace util { +namespace i18n { + +/** Returns whether a line break can be inserted after the character indicated + by the given Unicode codepoint due to word breaking. */ +bool allowsWordBreaking(uint16_t chr); + +/** Returns whether a line break can be inserted after any character in the + given string. If false, line breaking should occur on word boundaries + instead. */ +bool allowsIdeographicBreaking(const std::u16string& string); + +/** Returns whether a line break can be inserted after the character indicated + by the given Unicode codepoint due to ideographic breaking. */ +bool allowsIdeographicBreaking(uint16_t chr); + +} // namespace i18n +} // namespace util +} // namespace mbgl diff --git a/src/mbgl/util/ignore.hpp b/src/mbgl/util/ignore.hpp new file mode 100644 index 0000000000..955b1de2fa --- /dev/null +++ b/src/mbgl/util/ignore.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include <initializer_list> + +namespace mbgl { +namespace util { + +// Accept any number of parameters of any types, and do nothing with them. +// Useful for providing a context for parameter pack expansion where a legal +// expansion context is not otherwise available. +// +// See https://github.com/mapbox/cpp/blob/master/C%2B%2B%20Structural%20Metaprogramming.md +// for more details. +// +template <class... Ts> void ignore(Ts&&...) {} + +// std::initializer_list overload, for situations where you need sequenced +// modifications. +// +template <class T> void ignore(const std::initializer_list<T>&) {} + +} // namespace util +} // namespace mbgl diff --git a/src/mbgl/util/indexed_tuple.hpp b/src/mbgl/util/indexed_tuple.hpp new file mode 100644 index 0000000000..110e7dce12 --- /dev/null +++ b/src/mbgl/util/indexed_tuple.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include <type_traits> +#include <tuple> + +namespace mbgl { + +template <class T, class... Ts> +struct TypeIndex; + +template <class T, class... Ts> +struct TypeIndex<T, T, Ts...> : std::integral_constant<std::size_t, 0> {}; + +template <class T, class U, class... Ts> +struct TypeIndex<T, U, Ts...> : std::integral_constant<std::size_t, 1 + TypeIndex<T, Ts...>::value> {}; + +template <class...> class TypeList {}; + +template <class...> class IndexedTuple; + +// A tuple of Ts, where individual members can be accessed via `t.get<I>()` for I ∈ Is. +// +// See https://github.com/mapbox/cpp/blob/master/C%2B%2B%20Structural%20Metaprogramming.md +// for motivation. +// +template <class... Is, class... Ts> +class IndexedTuple<TypeList<Is...>, TypeList<Ts...>> : public std::tuple<Ts...> { +public: + static_assert(sizeof...(Is) == sizeof...(Ts), "IndexedTuple size mismatch"); + + using std::tuple<Ts...>::tuple; + + template <class I> + static constexpr std::size_t Index = TypeIndex<I, Is...>::value; + + template <class I> + auto& get() { + return std::get<Index<I>>(*this); + } + + template <class I> + const auto& get() const { + return std::get<Index<I>>(*this); + } +}; + +} // namespace mbgl diff --git a/src/mbgl/platform/log.cpp b/src/mbgl/util/logging.cpp index b140485dd6..939f1def64 100644 --- a/src/mbgl/platform/log.cpp +++ b/src/mbgl/util/logging.cpp @@ -1,4 +1,4 @@ -#include <mbgl/platform/log.hpp> +#include <mbgl/util/logging.hpp> #include <mbgl/util/enum.hpp> #include <mbgl/util/thread.hpp> diff --git a/src/mbgl/util/mapbox.cpp b/src/mbgl/util/mapbox.cpp index 9cf250f7a3..839924d77c 100644 --- a/src/mbgl/util/mapbox.cpp +++ b/src/mbgl/util/mapbox.cpp @@ -1,11 +1,10 @@ #include <mbgl/util/mapbox.hpp> #include <mbgl/util/constants.hpp> -#include <mbgl/platform/log.hpp> +#include <mbgl/util/logging.hpp> #include <stdexcept> #include <vector> #include <iostream> -#include <regex> namespace { @@ -192,14 +191,22 @@ std::string canonicalizeTileURL(const std::string& url, SourceType type, uint16_ } result += "." + extension; - + // get the query and remove access_token, if more parameters exist, add them to the final result if (queryIdx != url.length()) { - const auto query = url.substr(queryIdx + 1); - std::regex re ("&?access_token=([^&]*)"); - std::string replace = std::regex_replace(query, re, ""); - std::string subQuery = (replace.find("&") == 0) ? replace.substr(1, replace.length()) : replace; - if (subQuery.length() > 0) result += "?" + subQuery; + auto idx = queryIdx; + bool hasQuery = false; + while (idx != std::string::npos) { + idx++; // skip & or ? + auto ampersandIdx = url.find("&", idx); + if (url.substr(idx, 13) != "access_token=") { + result += hasQuery ? "&" : "?"; + result += url.substr(idx, ampersandIdx != std::string::npos ? ampersandIdx - idx + : std::string::npos); + hasQuery = true; + } + idx = ampersandIdx; + } } return result; diff --git a/src/mbgl/util/math.hpp b/src/mbgl/util/math.hpp index 5d4220d0a2..f969ecaedd 100644 --- a/src/mbgl/util/math.hpp +++ b/src/mbgl/util/math.hpp @@ -106,11 +106,5 @@ T smoothstep(T edge0, T edge1, T x) { return t * t * (T(3) - T(2) * t); } -// Computes the log2(x) rounded up to the next integer. -// (== number of bits required to store x) -uint32_t ceil_log2(uint64_t x); - -double log2(double x); - } // namespace util } // namespace mbgl diff --git a/src/mbgl/util/offscreen_texture.cpp b/src/mbgl/util/offscreen_texture.cpp index 40bb70b70e..aad20e59d3 100644 --- a/src/mbgl/util/offscreen_texture.cpp +++ b/src/mbgl/util/offscreen_texture.cpp @@ -1,15 +1,14 @@ #include <mbgl/util/offscreen_texture.hpp> #include <mbgl/gl/context.hpp> -#include <mbgl/gl/gl.hpp> #include <cstring> #include <cassert> namespace mbgl { -OffscreenTexture::OffscreenTexture(gl::Context& context_, std::array<uint16_t, 2> size_) - : context(context_), size(std::move(size_)) { - assert(size[0] > 0 && size[1] > 0); +OffscreenTexture::OffscreenTexture(gl::Context& context_, const Size size_) + : size(std::move(size_)), context(context_) { + assert(size); } void OffscreenTexture::bind() { @@ -20,7 +19,7 @@ void OffscreenTexture::bind() { context.bindFramebuffer = framebuffer->framebuffer; } - context.viewport = { 0, 0, size[0], size[1] }; + context.viewport = { 0, 0, size }; } gl::Texture& OffscreenTexture::getTexture() { @@ -29,19 +28,7 @@ gl::Texture& OffscreenTexture::getTexture() { } PremultipliedImage OffscreenTexture::readStillImage() { - PremultipliedImage image { size[0], size[1] }; - MBGL_CHECK_ERROR(glReadPixels(0, 0, size[0], size[1], GL_RGBA, GL_UNSIGNED_BYTE, image.data.get())); - - const auto stride = image.stride(); - auto tmp = std::make_unique<uint8_t[]>(stride); - uint8_t* rgba = image.data.get(); - for (int i = 0, j = size[1] - 1; i < j; i++, j--) { - std::memcpy(tmp.get(), rgba + i * stride, stride); - std::memcpy(rgba + i * stride, rgba + j * stride, stride); - std::memcpy(rgba + j * stride, tmp.get(), stride); - } - - return image; + return context.readFramebuffer<PremultipliedImage>(size); } diff --git a/src/mbgl/util/offscreen_texture.hpp b/src/mbgl/util/offscreen_texture.hpp index 8928bc2434..64eb7bc565 100644 --- a/src/mbgl/util/offscreen_texture.hpp +++ b/src/mbgl/util/offscreen_texture.hpp @@ -14,7 +14,7 @@ class Context; class OffscreenTexture : public View { public: - OffscreenTexture(gl::Context&, std::array<uint16_t, 2> size = {{ 256, 256 }}); + OffscreenTexture(gl::Context&, Size size = { 256, 256 }); void bind() override; @@ -22,9 +22,11 @@ public: gl::Texture& getTexture(); +public: + const Size size; + private: gl::Context& context; - std::array<uint16_t, 2> size; optional<gl::Framebuffer> framebuffer; optional<gl::Texture> texture; }; diff --git a/src/mbgl/util/premultiply.cpp b/src/mbgl/util/premultiply.cpp index e0178fda33..219273d7cc 100644 --- a/src/mbgl/util/premultiply.cpp +++ b/src/mbgl/util/premultiply.cpp @@ -8,12 +8,11 @@ namespace util { PremultipliedImage premultiply(UnassociatedImage&& src) { PremultipliedImage dst; - dst.width = src.width; - dst.height = src.height; + dst.size = src.size; dst.data = std::move(src.data); uint8_t* data = dst.data.get(); - for (size_t i = 0; i < dst.size(); i += 4) { + for (size_t i = 0; i < dst.bytes(); i += 4) { uint8_t& r = data[i + 0]; uint8_t& g = data[i + 1]; uint8_t& b = data[i + 2]; @@ -29,12 +28,11 @@ PremultipliedImage premultiply(UnassociatedImage&& src) { UnassociatedImage unpremultiply(PremultipliedImage&& src) { UnassociatedImage dst; - dst.width = src.width; - dst.height = src.height; + dst.size = src.size; dst.data = std::move(src.data); uint8_t* data = dst.data.get(); - for (size_t i = 0; i < dst.size(); i += 4) { + for (size_t i = 0; i < dst.bytes(); i += 4) { uint8_t& r = data[i + 0]; uint8_t& g = data[i + 1]; uint8_t& b = data[i + 2]; diff --git a/src/mbgl/util/stopwatch.cpp b/src/mbgl/util/stopwatch.cpp index d588b79254..3883d8535f 100644 --- a/src/mbgl/util/stopwatch.cpp +++ b/src/mbgl/util/stopwatch.cpp @@ -2,7 +2,7 @@ #include <mbgl/util/stopwatch.hpp> #include <mbgl/util/string.hpp> #include <mbgl/util/chrono.hpp> -#include <mbgl/platform/log.hpp> +#include <mbgl/util/logging.hpp> #include <iostream> #include <atomic> diff --git a/src/mbgl/util/stopwatch.hpp b/src/mbgl/util/stopwatch.hpp index 74cc2c412d..6214dae958 100644 --- a/src/mbgl/util/stopwatch.hpp +++ b/src/mbgl/util/stopwatch.hpp @@ -1,6 +1,6 @@ #pragma once -#include <mbgl/platform/event.hpp> +#include <mbgl/util/event.hpp> #include <mbgl/util/chrono.hpp> #include <string> diff --git a/src/mbgl/util/thread.hpp b/src/mbgl/util/thread.hpp index 91eef745fa..8cfef8a764 100644 --- a/src/mbgl/util/thread.hpp +++ b/src/mbgl/util/thread.hpp @@ -8,7 +8,7 @@ #include <mbgl/util/run_loop.hpp> #include <mbgl/util/thread_context.hpp> -#include <mbgl/platform/platform.hpp> +#include <mbgl/util/platform.hpp> #include <pthread.h> diff --git a/src/mbgl/util/tile_cover.cpp b/src/mbgl/util/tile_cover.cpp index c6bf7d362a..2fb7371aba 100644 --- a/src/mbgl/util/tile_cover.cpp +++ b/src/mbgl/util/tile_cover.cpp @@ -157,8 +157,8 @@ std::vector<UnwrappedTileID> tileCover(const LatLngBounds& bounds_, int32_t z) { } std::vector<UnwrappedTileID> tileCover(const TransformState& state, int32_t z) { - const double w = state.getWidth(); - const double h = state.getHeight(); + const double w = state.getSize().width; + const double h = state.getSize().height; return tileCover( TileCoordinate::fromScreenCoordinate(state, z, { 0, 0 }).p, TileCoordinate::fromScreenCoordinate(state, z, { w, 0 }).p, diff --git a/src/mbgl/util/url.cpp b/src/mbgl/util/url.cpp index bf6fc70ff5..9831bc9038 100644 --- a/src/mbgl/util/url.cpp +++ b/src/mbgl/util/url.cpp @@ -1,12 +1,30 @@ #include <mbgl/util/url.hpp> -#include <cctype> #include <iomanip> #include <sstream> #include <string> #include <cstdlib> #include <algorithm> + +namespace { + +// std::alnum etc. suffer from locale-dependence. + +inline bool isAlphaCharacter(char c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); +} + +inline bool isAlphaNumericCharacter(char c) { + return isAlphaCharacter(c) || (c >= '0' && c <= '9'); +} + +inline bool isSchemeCharacter(char c) { + return isAlphaNumericCharacter(c) || c == '-' || c == '+' || c == '.'; +} + +} // namespace + namespace mbgl { namespace util { @@ -17,7 +35,7 @@ std::string percentEncode(const std::string& input) { encoded << std::hex; for (auto c : input) { - if (std::isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') { + if (isAlphaNumericCharacter(c) || c == '-' || c == '_' || c == '.' || c == '~') { encoded << c; } else { encoded << '%' << std::setw(2) << int(c); @@ -47,5 +65,18 @@ std::string percentDecode(const std::string& input) { return decoded; } +// Checks whether the input string contains ://, and the part before it is all alphanumeric ASCII. +bool isURL(const std::string& input) { + auto it = input.begin(); + // First character has to be alphabetic + if (it == input.end() || !isAlphaCharacter(*it++)) return false; + // The remaining characters of the scheme can be alphanumeric, or be one of +.- + while (it != input.end() && isSchemeCharacter(*it)) ++it; + // Check that :// follows + return (it != input.end() && *it++ == ':') && + (it != input.end() && *it++ == '/') && + (it != input.end() && *it++ == '/'); +} + } // namespace util } // namespace mbgl diff --git a/src/mbgl/util/url.hpp b/src/mbgl/util/url.hpp index b9c66261df..2d18f7476a 100644 --- a/src/mbgl/util/url.hpp +++ b/src/mbgl/util/url.hpp @@ -8,6 +8,7 @@ namespace util { std::string percentEncode(const std::string&); std::string percentDecode(const std::string&); +bool isURL(const std::string&); } // namespace util } // namespace mbgl diff --git a/src/mbgl/util/utf.hpp b/src/mbgl/util/utf.hpp index 560ca3ba7f..81330cfc83 100644 --- a/src/mbgl/util/utf.hpp +++ b/src/mbgl/util/utf.hpp @@ -2,18 +2,17 @@ #include <memory> -#include <boost/regex/pending/unicode_iterator.hpp> +#include <locale> +#include <codecvt> namespace mbgl { namespace util { -class utf8_to_utf32 { - public: - static std::u32string convert(std::string const& utf8) - { - boost::u8_to_u32_iterator<std::string::const_iterator> begin(utf8.begin()); - boost::u8_to_u32_iterator<std::string::const_iterator> end(utf8.end()); - return std::u32string(begin,end); +class utf8_to_utf16 { +public: + static std::u16string convert(std::string const& utf8) { + std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter; + return converter.from_bytes(utf8); } }; |