summaryrefslogtreecommitdiff
path: root/src/mbgl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl')
-rw-r--r--src/mbgl/annotation/annotation_manager.cpp4
-rw-r--r--src/mbgl/gl/attribute.cpp227
-rw-r--r--src/mbgl/gl/attribute.hpp185
-rw-r--r--src/mbgl/gl/context.cpp92
-rw-r--r--src/mbgl/gl/context.hpp41
-rw-r--r--src/mbgl/gl/debugging.cpp2
-rw-r--r--src/mbgl/gl/draw_mode.hpp19
-rw-r--r--src/mbgl/gl/normalization.hpp35
-rw-r--r--src/mbgl/gl/program.hpp42
-rw-r--r--src/mbgl/gl/segment.cpp7
-rw-r--r--src/mbgl/gl/segment.hpp43
-rw-r--r--src/mbgl/gl/types.hpp10
-rw-r--r--src/mbgl/gl/uniform.hpp33
-rw-r--r--src/mbgl/gl/vertex_array.hpp2
-rw-r--r--src/mbgl/layout/symbol_feature.hpp16
-rw-r--r--src/mbgl/layout/symbol_instance.cpp46
-rw-r--r--src/mbgl/layout/symbol_instance.hpp9
-rw-r--r--src/mbgl/layout/symbol_layout.cpp353
-rw-r--r--src/mbgl/layout/symbol_layout.hpp35
-rw-r--r--src/mbgl/map/backend_scope.cpp36
-rw-r--r--src/mbgl/map/map.cpp93
-rw-r--r--src/mbgl/map/transform.cpp80
-rw-r--r--src/mbgl/map/transform.hpp40
-rw-r--r--src/mbgl/programs/attributes.hpp206
-rw-r--r--src/mbgl/programs/circle_program.cpp2
-rw-r--r--src/mbgl/programs/circle_program.hpp34
-rw-r--r--src/mbgl/programs/collision_box_program.cpp2
-rw-r--r--src/mbgl/programs/collision_box_program.hpp23
-rw-r--r--src/mbgl/programs/debug_program.hpp14
-rw-r--r--src/mbgl/programs/fill_program.cpp8
-rw-r--r--src/mbgl/programs/fill_program.hpp72
-rw-r--r--src/mbgl/programs/line_program.cpp14
-rw-r--r--src/mbgl/programs/line_program.hpp90
-rw-r--r--src/mbgl/programs/program.hpp56
-rw-r--r--src/mbgl/programs/programs.hpp4
-rw-r--r--src/mbgl/programs/raster_program.cpp2
-rw-r--r--src/mbgl/programs/raster_program.hpp29
-rw-r--r--src/mbgl/programs/symbol_program.cpp90
-rw-r--r--src/mbgl/programs/symbol_program.hpp109
-rw-r--r--src/mbgl/renderer/bucket.hpp7
-rw-r--r--src/mbgl/renderer/circle_bucket.cpp29
-rw-r--r--src/mbgl/renderer/circle_bucket.hpp20
-rw-r--r--src/mbgl/renderer/debug_bucket.cpp4
-rw-r--r--src/mbgl/renderer/debug_bucket.hpp2
-rw-r--r--src/mbgl/renderer/fill_bucket.cpp30
-rw-r--r--src/mbgl/renderer/fill_bucket.hpp20
-rw-r--r--src/mbgl/renderer/frame_history.cpp2
-rw-r--r--src/mbgl/renderer/frame_history.hpp2
-rw-r--r--src/mbgl/renderer/line_bucket.cpp55
-rw-r--r--src/mbgl/renderer/line_bucket.hpp25
-rw-r--r--src/mbgl/renderer/painter.cpp26
-rw-r--r--src/mbgl/renderer/painter.hpp4
-rw-r--r--src/mbgl/renderer/painter_background.cpp33
-rw-r--r--src/mbgl/renderer/painter_circle.cpp12
-rw-r--r--src/mbgl/renderer/painter_clipping.cpp10
-rw-r--r--src/mbgl/renderer/painter_debug.cpp10
-rw-r--r--src/mbgl/renderer/painter_fill.cpp46
-rw-r--r--src/mbgl/renderer/painter_line.cpp11
-rw-r--r--src/mbgl/renderer/painter_raster.cpp6
-rw-r--r--src/mbgl/renderer/painter_symbol.cpp55
-rw-r--r--src/mbgl/renderer/symbol_bucket.cpp22
-rw-r--r--src/mbgl/renderer/symbol_bucket.hpp22
-rw-r--r--src/mbgl/shaders/circle.cpp191
-rw-r--r--src/mbgl/shaders/circle.hpp16
-rw-r--r--src/mbgl/shaders/collision_box.cpp128
-rw-r--r--src/mbgl/shaders/collision_box.hpp16
-rw-r--r--src/mbgl/shaders/debug.cpp100
-rw-r--r--src/mbgl/shaders/debug.hpp16
-rw-r--r--src/mbgl/shaders/fill.cpp120
-rw-r--r--src/mbgl/shaders/fill.hpp16
-rw-r--r--src/mbgl/shaders/fill_outline.cpp128
-rw-r--r--src/mbgl/shaders/fill_outline.hpp16
-rw-r--r--src/mbgl/shaders/fill_outline_pattern.cpp156
-rw-r--r--src/mbgl/shaders/fill_outline_pattern.hpp16
-rw-r--r--src/mbgl/shaders/fill_pattern.cpp145
-rw-r--r--src/mbgl/shaders/fill_pattern.hpp16
-rw-r--r--src/mbgl/shaders/line.cpp216
-rw-r--r--src/mbgl/shaders/line.hpp16
-rw-r--r--src/mbgl/shaders/line_pattern.cpp233
-rw-r--r--src/mbgl/shaders/line_pattern.hpp16
-rw-r--r--src/mbgl/shaders/line_sdf.cpp239
-rw-r--r--src/mbgl/shaders/line_sdf.hpp16
-rw-r--r--src/mbgl/shaders/raster.cpp150
-rw-r--r--src/mbgl/shaders/raster.hpp16
-rw-r--r--src/mbgl/shaders/symbol_icon.cpp151
-rw-r--r--src/mbgl/shaders/symbol_icon.hpp16
-rw-r--r--src/mbgl/shaders/symbol_sdf.cpp242
-rw-r--r--src/mbgl/shaders/symbol_sdf.hpp16
-rw-r--r--src/mbgl/sprite/sprite_atlas.cpp273
-rw-r--r--src/mbgl/sprite/sprite_atlas.hpp77
-rw-r--r--src/mbgl/sprite/sprite_parser.cpp11
-rw-r--r--src/mbgl/storage/local_file_source.hpp2
-rw-r--r--src/mbgl/style/bucket_parameters.cpp14
-rw-r--r--src/mbgl/style/bucket_parameters.hpp21
-rw-r--r--src/mbgl/style/conversion/stringify.hpp240
-rw-r--r--src/mbgl/style/cross_faded_property_evaluator.cpp19
-rw-r--r--src/mbgl/style/cross_faded_property_evaluator.hpp2
-rw-r--r--src/mbgl/style/data_driven_property_evaluator.hpp42
-rw-r--r--src/mbgl/style/function.cpp81
-rw-r--r--src/mbgl/style/function/categorical_stops.cpp38
-rw-r--r--src/mbgl/style/function/identity_stops.cpp61
-rw-r--r--src/mbgl/style/layer_impl.hpp2
-rw-r--r--src/mbgl/style/layer_observer.hpp1
-rw-r--r--src/mbgl/style/layers/background_layer.cpp12
-rw-r--r--src/mbgl/style/layers/background_layer_impl.cpp3
-rw-r--r--src/mbgl/style/layers/background_layer_impl.hpp2
-rw-r--r--src/mbgl/style/layers/background_layer_properties.hpp1
-rw-r--r--src/mbgl/style/layers/circle_layer.cpp124
-rw-r--r--src/mbgl/style/layers/circle_layer_impl.cpp25
-rw-r--r--src/mbgl/style/layers/circle_layer_impl.hpp2
-rw-r--r--src/mbgl/style/layers/circle_layer_properties.hpp15
-rw-r--r--src/mbgl/style/layers/custom_layer_impl.cpp3
-rw-r--r--src/mbgl/style/layers/custom_layer_impl.hpp2
-rw-r--r--src/mbgl/style/layers/fill_extrusion_layer.cpp64
-rw-r--r--src/mbgl/style/layers/fill_extrusion_layer_impl.cpp2
-rw-r--r--src/mbgl/style/layers/fill_extrusion_layer_impl.hpp2
-rw-r--r--src/mbgl/style/layers/fill_extrusion_layer_properties.hpp7
-rw-r--r--src/mbgl/style/layers/fill_layer.cpp64
-rw-r--r--src/mbgl/style/layers/fill_layer_impl.cpp21
-rw-r--r--src/mbgl/style/layers/fill_layer_impl.hpp2
-rw-r--r--src/mbgl/style/layers/fill_layer_properties.hpp7
-rw-r--r--src/mbgl/style/layers/layer.cpp.ejs24
-rw-r--r--src/mbgl/style/layers/layer_properties.hpp.ejs11
-rw-r--r--src/mbgl/style/layers/line_layer.cpp100
-rw-r--r--src/mbgl/style/layers/line_layer_impl.cpp35
-rw-r--r--src/mbgl/style/layers/line_layer_impl.hpp2
-rw-r--r--src/mbgl/style/layers/line_layer_properties.hpp11
-rw-r--r--src/mbgl/style/layers/raster_layer.cpp28
-rw-r--r--src/mbgl/style/layers/raster_layer_impl.cpp3
-rw-r--r--src/mbgl/style/layers/raster_layer_impl.hpp2
-rw-r--r--src/mbgl/style/layers/raster_layer_properties.hpp1
-rw-r--r--src/mbgl/style/layers/symbol_layer.cpp200
-rw-r--r--src/mbgl/style/layers/symbol_layer_impl.cpp105
-rw-r--r--src/mbgl/style/layers/symbol_layer_impl.hpp50
-rw-r--r--src/mbgl/style/layers/symbol_layer_properties.hpp29
-rw-r--r--src/mbgl/style/layout_property.hpp24
-rw-r--r--src/mbgl/style/paint_property.hpp97
-rw-r--r--src/mbgl/style/paint_property_binder.hpp287
-rw-r--r--src/mbgl/style/parser.cpp12
-rw-r--r--src/mbgl/style/possibly_evaluated_property_value.hpp67
-rw-r--r--src/mbgl/style/property_evaluator.hpp2
-rw-r--r--src/mbgl/style/source_impl.cpp6
-rw-r--r--src/mbgl/style/source_observer.hpp2
-rw-r--r--src/mbgl/style/sources/geojson_source_impl.cpp4
-rw-r--r--src/mbgl/style/style.cpp15
-rw-r--r--src/mbgl/style/style.hpp1
-rw-r--r--src/mbgl/style/tile_source_impl.hpp2
-rw-r--r--src/mbgl/text/glyph.hpp43
-rw-r--r--src/mbgl/text/glyph_atlas.cpp79
-rw-r--r--src/mbgl/text/glyph_atlas.hpp31
-rw-r--r--src/mbgl/text/glyph_pbf.cpp46
-rw-r--r--src/mbgl/text/glyph_set.cpp54
-rw-r--r--src/mbgl/text/glyph_set.hpp9
-rw-r--r--src/mbgl/text/quads.cpp27
-rw-r--r--src/mbgl/text/quads.hpp8
-rw-r--r--src/mbgl/text/shaping.cpp12
-rw-r--r--src/mbgl/text/shaping.hpp40
-rw-r--r--src/mbgl/tile/geojson_tile.cpp6
-rw-r--r--src/mbgl/tile/geojson_tile.hpp2
-rw-r--r--src/mbgl/tile/geometry_tile_data.cpp2
-rw-r--r--src/mbgl/tile/geometry_tile_worker.cpp27
-rw-r--r--src/mbgl/tile/raster_tile.cpp4
-rw-r--r--src/mbgl/tile/raster_tile_worker.cpp2
-rw-r--r--src/mbgl/tile/tile_id_hash.hpp6
-rw-r--r--src/mbgl/tile/vector_tile.cpp70
-rw-r--r--src/mbgl/util/chrono.cpp2
-rw-r--r--src/mbgl/util/http_header.cpp4
-rw-r--r--src/mbgl/util/http_header.hpp2
-rw-r--r--src/mbgl/util/http_timeout.cpp4
-rw-r--r--src/mbgl/util/i18n.cpp254
-rw-r--r--src/mbgl/util/i18n.hpp50
-rw-r--r--src/mbgl/util/ignore.hpp3
-rw-r--r--src/mbgl/util/indexed_tuple.hpp13
-rw-r--r--src/mbgl/util/interpolate.cpp19
-rw-r--r--src/mbgl/util/interpolate.hpp9
-rw-r--r--src/mbgl/util/thread.hpp45
-rw-r--r--src/mbgl/util/type_list.hpp40
-rw-r--r--src/mbgl/util/url.cpp6
-rw-r--r--src/mbgl/util/version.cpp9
-rw-r--r--src/mbgl/util/version.hpp9
-rw-r--r--src/mbgl/util/version_info.cpp14
181 files changed, 6528 insertions, 1850 deletions
diff --git a/src/mbgl/annotation/annotation_manager.cpp b/src/mbgl/annotation/annotation_manager.cpp
index f8c1c3adf7..ed1518fb7b 100644
--- a/src/mbgl/annotation/annotation_manager.cpp
+++ b/src/mbgl/annotation/annotation_manager.cpp
@@ -90,7 +90,7 @@ void AnnotationManager::add(const AnnotationID& id, const StyleSourcedAnnotation
Update AnnotationManager::update(const AnnotationID& id, const SymbolAnnotation& annotation, const uint8_t maxZoom) {
Update result = Update::Nothing;
-
+
auto it = symbolAnnotations.find(id);
if (it == symbolAnnotations.end()) {
assert(false); // Attempt to update a non-existent symbol annotation
@@ -222,12 +222,10 @@ void AnnotationManager::removeTile(AnnotationTile& tile) {
void AnnotationManager::addIcon(const std::string& name, std::shared_ptr<const SpriteImage> sprite) {
spriteAtlas.setSprite(name, sprite);
- spriteAtlas.updateDirty();
}
void AnnotationManager::removeIcon(const std::string& name) {
spriteAtlas.removeSprite(name);
- spriteAtlas.updateDirty();
}
double AnnotationManager::getTopOffsetPixelsForIcon(const std::string& name) {
diff --git a/src/mbgl/gl/attribute.cpp b/src/mbgl/gl/attribute.cpp
index 7432fff590..2c16dac3fc 100644
--- a/src/mbgl/gl/attribute.cpp
+++ b/src/mbgl/gl/attribute.cpp
@@ -1,29 +1,238 @@
#include <mbgl/gl/attribute.hpp>
+#include <mbgl/gl/context.hpp>
#include <mbgl/gl/gl.hpp>
+#include <mbgl/gl/normalization.hpp>
namespace mbgl {
namespace gl {
+static_assert(offsetof(Normalized<uint8_t>, value) == 0, "unexpected normalized offset");
+
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) {
+template <class T> DataType DataTypeOf = static_cast<DataType>(0);
+template <> DataType DataTypeOf< int8_t> = DataType::Byte;
+template <> DataType DataTypeOf<uint8_t> = DataType::UnsignedByte;
+template <> DataType DataTypeOf< int16_t> = DataType::Short;
+template <> DataType DataTypeOf<uint16_t> = DataType::UnsignedShort;
+template <> DataType DataTypeOf< int32_t> = DataType::Integer;
+template <> DataType DataTypeOf<uint32_t> = DataType::UnsignedInteger;
+template <> DataType DataTypeOf<float> = DataType::Float;
+
+template <class T> bool IsNormalized = false;
+template <class T> bool IsNormalized<Normalized<T>> = true;
+template <class T> DataType DataTypeOf<Normalized<T>> = DataTypeOf<T>;
+
+template <class T, std::size_t N>
+void VariableAttributeBinding<T, N>::bind(Context& context,
+ AttributeLocation location,
+ optional<VariableAttributeBinding<T, N>>& oldBinding,
+ std::size_t vertexOffset) const {
+ if (oldBinding == *this) {
+ return;
+ }
+ context.vertexBuffer = vertexBuffer;
MBGL_CHECK_ERROR(glEnableVertexAttribArray(location));
MBGL_CHECK_ERROR(glVertexAttribPointer(
location,
- static_cast<GLint>(count),
- static_cast<GLenum>(type),
- GL_FALSE,
+ static_cast<GLint>(N),
+ static_cast<GLenum>(DataTypeOf<T>),
+ static_cast<GLboolean>(IsNormalized<T>),
static_cast<GLsizei>(vertexSize),
reinterpret_cast<GLvoid*>(attributeOffset + (vertexSize * vertexOffset))));
}
+template class VariableAttributeBinding<uint8_t, 1>;
+template class VariableAttributeBinding<uint8_t, 2>;
+template class VariableAttributeBinding<uint8_t, 3>;
+template class VariableAttributeBinding<uint8_t, 4>;
+
+template class VariableAttributeBinding<Normalized<uint8_t>, 1>;
+template class VariableAttributeBinding<Normalized<uint8_t>, 2>;
+template class VariableAttributeBinding<Normalized<uint8_t>, 3>;
+template class VariableAttributeBinding<Normalized<uint8_t>, 4>;
+
+template class VariableAttributeBinding<uint16_t, 1>;
+template class VariableAttributeBinding<uint16_t, 2>;
+template class VariableAttributeBinding<uint16_t, 3>;
+template class VariableAttributeBinding<uint16_t, 4>;
+
+template class VariableAttributeBinding<int16_t, 1>;
+template class VariableAttributeBinding<int16_t, 2>;
+template class VariableAttributeBinding<int16_t, 3>;
+template class VariableAttributeBinding<int16_t, 4>;
+
+template class VariableAttributeBinding<float, 1>;
+template class VariableAttributeBinding<float, 2>;
+template class VariableAttributeBinding<float, 3>;
+template class VariableAttributeBinding<float, 4>;
+
+template <>
+void ConstantAttributeBinding<uint8_t, 1>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<uint8_t, 1>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib1f(location, value[0]));
+}
+
+template <>
+void ConstantAttributeBinding<uint8_t, 2>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<uint8_t, 2>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib2f(location, value[0], value[1]));
+}
+
+template <>
+void ConstantAttributeBinding<uint8_t, 3>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<uint8_t, 3>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib3f(location, value[0], value[1], value[2]));
+}
+
+template <>
+void ConstantAttributeBinding<uint8_t, 4>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<uint8_t, 4>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib4f(location, value[0], value[1], value[2], value[3]));
+}
+
+
+template <>
+void ConstantAttributeBinding<Normalized<uint8_t>, 1>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<Normalized<uint8_t>, 1>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib1f(location, value[0].denormalized()));
+}
+
+template <>
+void ConstantAttributeBinding<Normalized<uint8_t>, 2>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<Normalized<uint8_t>, 2>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib2f(location, value[0].denormalized(), value[1].denormalized()));
+}
+
+template <>
+void ConstantAttributeBinding<Normalized<uint8_t>, 3>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<Normalized<uint8_t>, 3>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib3f(location, value[0].denormalized(), value[1].denormalized(), value[2].denormalized()));
+}
+
+template <>
+void ConstantAttributeBinding<Normalized<uint8_t>, 4>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<Normalized<uint8_t>, 4>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib4f(location, value[0].denormalized(), value[1].denormalized(), value[2].denormalized(), value[3].denormalized()));
+}
+
+
+template <>
+void ConstantAttributeBinding<uint16_t, 1>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<uint16_t, 1>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib1f(location, value[0]));
+}
+
+template <>
+void ConstantAttributeBinding<uint16_t, 2>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<uint16_t, 2>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib2f(location, value[0], value[1]));
+}
+
+template <>
+void ConstantAttributeBinding<uint16_t, 3>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<uint16_t, 3>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib3f(location, value[0], value[1], value[2]));
+}
+
+template <>
+void ConstantAttributeBinding<uint16_t, 4>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<uint16_t, 4>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib4f(location, value[0], value[1], value[2], value[3]));
+}
+
+
+template <>
+void ConstantAttributeBinding<int16_t, 1>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<int16_t, 1>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib1f(location, value[0]));
+}
+
+template <>
+void ConstantAttributeBinding<int16_t, 2>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<int16_t, 2>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib2f(location, value[0], value[1]));
+}
+
+template <>
+void ConstantAttributeBinding<int16_t, 3>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<int16_t, 3>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib3f(location, value[0], value[1], value[2]));
+}
+
+template <>
+void ConstantAttributeBinding<int16_t, 4>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<int16_t, 4>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib4f(location, value[0], value[1], value[2], value[3]));
+}
+
+
+template <>
+void ConstantAttributeBinding<float, 1>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<float, 1>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib1f(location, value[0]));
+}
+
+template <>
+void ConstantAttributeBinding<float, 2>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<float, 2>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib2f(location, value[0], value[1]));
+}
+
+template <>
+void ConstantAttributeBinding<float, 3>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<float, 3>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib3f(location, value[0], value[1], value[2]));
+}
+
+template <>
+void ConstantAttributeBinding<float, 4>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<float, 4>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib4f(location, value[0], value[1], value[2], value[3]));
+}
+
} // namespace gl
} // namespace mbgl
diff --git a/src/mbgl/gl/attribute.hpp b/src/mbgl/gl/attribute.hpp
index e45014127b..6300ebb56b 100644
--- a/src/mbgl/gl/attribute.hpp
+++ b/src/mbgl/gl/attribute.hpp
@@ -1,8 +1,10 @@
#pragma once
#include <mbgl/gl/types.hpp>
+#include <mbgl/gl/segment.hpp>
#include <mbgl/util/ignore.hpp>
#include <mbgl/util/indexed_tuple.hpp>
+#include <mbgl/util/variant.hpp>
#include <cstddef>
#include <functional>
@@ -10,24 +12,79 @@
namespace mbgl {
namespace gl {
-template <class Tag, class T, std::size_t N>
+template <class T, std::size_t N>
+class VariableAttributeBinding {
+public:
+ VariableAttributeBinding(BufferID vertexBuffer_,
+ std::size_t vertexSize_,
+ std::size_t attributeOffset_)
+ : vertexBuffer(vertexBuffer_),
+ vertexSize(vertexSize_),
+ attributeOffset(attributeOffset_)
+ {}
+
+ void bind(Context&, AttributeLocation, optional<VariableAttributeBinding<T, N>>&, std::size_t vertexOffset) const;
+
+ friend bool operator==(const VariableAttributeBinding& lhs,
+ const VariableAttributeBinding& rhs) {
+ return lhs.vertexBuffer == rhs.vertexBuffer
+ && lhs.vertexSize == rhs.vertexSize
+ && lhs.attributeOffset == rhs.attributeOffset;
+ }
+
+private:
+ BufferID vertexBuffer;
+ std::size_t vertexSize;
+ std::size_t attributeOffset;
+};
+
+template <class T, std::size_t N>
+class ConstantAttributeBinding {
+public:
+ ConstantAttributeBinding() { value.fill(T()); }
+
+ explicit ConstantAttributeBinding(std::array<T, N> value_)
+ : value(std::move(value_))
+ {}
+
+ void bind(Context&, AttributeLocation, optional<VariableAttributeBinding<T, N>>&, std::size_t) const;
+
+ friend bool operator==(const ConstantAttributeBinding& lhs,
+ const ConstantAttributeBinding& rhs) {
+ return lhs.value == rhs.value;
+ }
+
+private:
+ std::array<T, N> value;
+};
+
+template <class T, std::size_t N>
class Attribute {
public:
- using Type = T[N];
+ using Value = std::array<T, N>;
+
+ using VariableBinding = VariableAttributeBinding<T, N>;
+ using ConstantBinding = ConstantAttributeBinding<T, N>;
- class State {
- public:
- explicit State(AttributeLocation location_)
- : location(location_) {}
+ using Location = AttributeLocation;
- AttributeLocation location;
- static constexpr std::size_t count = N;
- static constexpr DataType type = DataTypeOf<T>::value;
- };
+ using Binding = variant<
+ ConstantBinding,
+ VariableBinding>;
+
+ static void bind(Context& context,
+ const Location& location,
+ optional<VariableBinding>& oldBinding,
+ const Binding& newBinding,
+ std::size_t vertexOffset) {
+ Binding::visit(newBinding, [&] (const auto& binding) {
+ binding.bind(context, location, oldBinding, vertexOffset);
+ });
+ }
};
#define MBGL_DEFINE_ATTRIBUTE(type_, n_, name_) \
- struct name_ : ::mbgl::gl::Attribute<name_, type_, n_> { static constexpr auto name = #name_; }
+ struct name_ : ::mbgl::gl::Attribute<type_, n_> { static auto name() { return #name_; } }
namespace detail {
@@ -41,10 +98,16 @@ namespace detail {
template <class... As>
class Vertex;
+template <>
+class Vertex<> {
+public:
+ using VertexType = Vertex<>;
+};
+
template <class A1>
class Vertex<A1> {
public:
- typename A1::Type a1;
+ typename A1::Value a1;
using VertexType = Vertex<A1>;
static const std::size_t attributeOffsets[1];
@@ -53,8 +116,8 @@ public:
template <class A1, class A2>
class Vertex<A1, A2> {
public:
- typename A1::Type a1;
- typename A2::Type a2;
+ typename A1::Value a1;
+ typename A2::Value a2;
using VertexType = Vertex<A1, A2>;
static const std::size_t attributeOffsets[2];
@@ -63,9 +126,9 @@ public:
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;
+ typename A1::Value a1;
+ typename A2::Value a2;
+ typename A3::Value a3;
using VertexType = Vertex<A1, A2, A3>;
static const std::size_t attributeOffsets[3];
@@ -74,10 +137,10 @@ public:
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;
+ typename A1::Value a1;
+ typename A2::Value a2;
+ typename A3::Value a3;
+ typename A4::Value a4;
using VertexType = Vertex<A1, A2, A3, A4>;
static const std::size_t attributeOffsets[4];
@@ -86,11 +149,11 @@ public:
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;
+ typename A1::Value a1;
+ typename A2::Value a2;
+ typename A3::Value a3;
+ typename A4::Value a4;
+ typename A5::Value a5;
using VertexType = Vertex<A1, A2, A3, A4, A5>;
static const std::size_t attributeOffsets[5];
@@ -135,37 +198,71 @@ const std::size_t Vertex<A1, A2, A3, A4, A5>::attributeOffsets[5] = {
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 Types = TypeList<As...>;
+ using Locations = IndexedTuple<
+ TypeList<As...>,
+ TypeList<typename As::Location...>>;
+ using Bindings = IndexedTuple<
+ TypeList<As...>,
+ TypeList<typename As::Binding...>>;
+ using VariableBindings = IndexedTuple<
+ TypeList<As...>,
+ TypeList<optional<typename As::VariableBinding>...>>;
+
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 Locations locations(const ProgramID& id) {
+ return Locations { 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)... });
+ template <class DrawMode>
+ static Bindings allVariableBindings(const VertexBuffer<Vertex, DrawMode>& buffer) {
+ static_assert(std::is_standard_layout<Vertex>::value, "vertex type must use standard layout");
+
+ return Bindings {
+ typename As::VariableBinding {
+ buffer.buffer,
+ sizeof(Vertex),
+ Vertex::attributeOffsets[Index<As>]
+ }...
};
}
+
+ static void bind(Context& context,
+ const Locations& locations,
+ VariableBindings& oldBindings,
+ const Bindings& newBindings,
+ std::size_t vertexOffset) {
+ util::ignore({ (As::bind(context,
+ locations.template get<As>(),
+ oldBindings.template get<As>(),
+ newBindings.template get<As>(),
+ vertexOffset), 0)... });
+ }
};
+namespace detail {
+
+template <class...>
+struct ConcatenateAttributes;
+
+template <class... As, class... Bs>
+struct ConcatenateAttributes<TypeList<As...>, TypeList<Bs...>> {
+ using Type = Attributes<As..., Bs...>;
+};
+
+} // namespace detail
+
+template <class A, class B>
+using ConcatenateAttributes = typename detail::ConcatenateAttributes<
+ typename A::Types,
+ typename B::Types>::Type;
+
} // namespace gl
} // namespace mbgl
diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp
index 5048ffcd66..9c2031ccfd 100644
--- a/src/mbgl/gl/context.cpp
+++ b/src/mbgl/gl/context.cpp
@@ -122,6 +122,20 @@ UniqueTexture Context::createTexture() {
return UniqueTexture{ std::move(id), { this } };
}
+bool Context::supportsVertexArrays() const {
+ return gl::GenVertexArrays &&
+ gl::BindVertexArray &&
+ gl::DeleteVertexArrays &&
+ !disableVAOExtension;
+}
+
+UniqueVertexArray Context::createVertexArray() {
+ assert(supportsVertexArrays());
+ 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));
@@ -407,32 +421,26 @@ void Context::clear(optional<mbgl::Color> color,
}
#if not MBGL_USE_GLES2
-PrimitiveType Context::operator()(const Points& points) {
+void Context::setDrawMode(const Points& points) {
pointSize = points.pointSize;
- return PrimitiveType::Points;
}
#else
-PrimitiveType Context::operator()(const Points&) {
- return PrimitiveType::Points;
+void Context::setDrawMode(const Points&) {
}
#endif // MBGL_USE_GLES2
-PrimitiveType Context::operator()(const Lines& lines) {
+void Context::setDrawMode(const Lines& lines) {
lineWidth = lines.lineWidth;
- return PrimitiveType::Lines;
}
-PrimitiveType Context::operator()(const LineStrip& lineStrip) {
+void Context::setDrawMode(const LineStrip& lineStrip) {
lineWidth = lineStrip.lineWidth;
- return PrimitiveType::LineStrip;
}
-PrimitiveType Context::operator()(const Triangles&) {
- return PrimitiveType::Triangles;
+void Context::setDrawMode(const Triangles&) {
}
-PrimitiveType Context::operator()(const TriangleStrip&) {
- return PrimitiveType::TriangleStrip;
+void Context::setDrawMode(const TriangleStrip&) {
}
void Context::setDepthMode(const DepthMode& depth) {
@@ -474,57 +482,14 @@ void Context::setColorMode(const ColorMode& color) {
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::draw(PrimitiveType primitiveType,
+ std::size_t indexOffset,
+ std::size_t indexLength) {
+ MBGL_CHECK_ERROR(glDrawElements(
+ static_cast<GLenum>(primitiveType),
+ static_cast<GLsizei>(indexLength),
+ GL_UNSIGNED_SHORT,
+ reinterpret_cast<GLvoid*>(sizeof(uint16_t) * indexOffset)));
}
void Context::performCleanup() {
@@ -564,6 +529,7 @@ void Context::performCleanup() {
}
if (!abandonedVertexArrays.empty()) {
+ assert(supportsVertexArrays());
for (const auto id : abandonedVertexArrays) {
if (vertexArrayObject == id) {
vertexArrayObject.setDirty();
diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp
index 093afa20ed..9d3ecec662 100644
--- a/src/mbgl/gl/context.hpp
+++ b/src/mbgl/gl/context.hpp
@@ -13,7 +13,6 @@
#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>
@@ -41,6 +40,9 @@ public:
void linkProgram(ProgramID);
UniqueTexture createTexture();
+ bool supportsVertexArrays() const;
+ UniqueVertexArray createVertexArray();
+
template <class Vertex, class DrawMode>
VertexBuffer<Vertex, DrawMode> createVertexBuffer(VertexVector<Vertex, DrawMode>&& v) {
return VertexBuffer<Vertex, DrawMode> {
@@ -119,25 +121,20 @@ public:
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 setDrawMode(const Points&);
+ void setDrawMode(const Lines&);
+ void setDrawMode(const LineStrip&);
+ void setDrawMode(const Triangles&);
+ void setDrawMode(const TriangleStrip&);
void setDepthMode(const DepthMode&);
void setStencilMode(const StencilMode&);
void setColorMode(const ColorMode&);
+ void draw(PrimitiveType,
+ std::size_t indexOffset,
+ std::size_t indexLength);
+
// Actually remove the objects we marked as abandoned with the above methods.
// Only call this while the OpenGL context is exclusive to this thread.
void performCleanup();
@@ -164,6 +161,8 @@ public:
std::array<State<value::BindTexture>, 2> texture;
State<value::BindVertexArray> vertexArrayObject;
State<value::Program> program;
+ State<value::BindVertexBuffer> vertexBuffer;
+ State<value::BindElementBuffer> elementBuffer;
#if not MBGL_USE_GLES2
State<value::PixelZoom> pixelZoom;
@@ -196,8 +195,6 @@ private:
#if not MBGL_USE_GLES2
State<value::PointSize> pointSize;
#endif // MBGL_USE_GLES2
- State<value::BindVertexBuffer> vertexBuffer;
- State<value::BindElementBuffer> elementBuffer;
UniqueBuffer createVertexBuffer(const void* data, std::size_t size);
UniqueBuffer createIndexBuffer(const void* data, std::size_t size);
@@ -210,12 +207,6 @@ private:
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;
friend detail::BufferDeleter;
@@ -233,6 +224,10 @@ private:
std::vector<VertexArrayID> abandonedVertexArrays;
std::vector<FramebufferID> abandonedFramebuffers;
std::vector<RenderbufferID> abandonedRenderbuffers;
+
+public:
+ // For testing
+ bool disableVAOExtension = false;
};
} // namespace gl
diff --git a/src/mbgl/gl/debugging.cpp b/src/mbgl/gl/debugging.cpp
index f99308de7e..5ce3e606ee 100644
--- a/src/mbgl/gl/debugging.cpp
+++ b/src/mbgl/gl/debugging.cpp
@@ -132,7 +132,7 @@ void enable() {
}
// This will enable all messages including performance hints
- //MBGL_CHECK_ERROR(DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE));
+ // MBGL_CHECK_ERROR(DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE));
// This will only enable high and medium severity messages
MBGL_CHECK_ERROR(DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0, nullptr, GL_TRUE));
diff --git a/src/mbgl/gl/draw_mode.hpp b/src/mbgl/gl/draw_mode.hpp
index ab86d5e469..275eb25b89 100644
--- a/src/mbgl/gl/draw_mode.hpp
+++ b/src/mbgl/gl/draw_mode.hpp
@@ -1,7 +1,7 @@
#pragma once
+#include <mbgl/gl/types.hpp>
#include <mbgl/gl/primitives.hpp>
-#include <mbgl/util/variant.hpp>
#include <cassert>
@@ -11,7 +11,9 @@ namespace gl {
class Points {
public:
using Primitive = Point;
+
static constexpr std::size_t bufferGroupSize = 1;
+ static constexpr PrimitiveType primitiveType = PrimitiveType::Points;
explicit Points(float pointSize_) : pointSize(pointSize_) {}
@@ -21,7 +23,9 @@ public:
class Lines {
public:
using Primitive = Line;
+
static constexpr std::size_t bufferGroupSize = 2;
+ static constexpr PrimitiveType primitiveType = PrimitiveType::Lines;
explicit Lines(float lineWidth_) : lineWidth(lineWidth_) {
assert(lineWidth > 0);
@@ -35,7 +39,9 @@ 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;
+ static constexpr PrimitiveType primitiveType = PrimitiveType::LineStrip;
explicit LineStrip(float lineWidth_) : lineWidth(lineWidth_) {
assert(lineWidth > 0);
@@ -47,7 +53,9 @@ public:
class Triangles {
public:
using Primitive = Triangle;
+
static constexpr std::size_t bufferGroupSize = 3;
+ static constexpr PrimitiveType primitiveType = PrimitiveType::Triangles;
};
class TriangleStrip {
@@ -55,7 +63,9 @@ 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;
+ static constexpr PrimitiveType primitiveType = PrimitiveType::TriangleStrip;
};
// Special draw mode for use with VertexVector<Indexed, Vertex>, in which
@@ -65,12 +75,5 @@ 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/normalization.hpp b/src/mbgl/gl/normalization.hpp
new file mode 100644
index 0000000000..83fa67a3ec
--- /dev/null
+++ b/src/mbgl/gl/normalization.hpp
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <mbgl/math/clamp.hpp>
+
+#include <cassert>
+#include <limits>
+
+namespace mbgl {
+namespace gl {
+
+template <class T>
+class Normalized {
+public:
+ T value;
+
+ Normalized() : value(0) {}
+
+ explicit Normalized(float f)
+ : value(static_cast<T>(std::numeric_limits<T>::max() * util::clamp(f, 0.0f, 1.0f))) {
+ assert(f >= 0.0f);
+ assert(f <= 1.0f);
+ }
+
+ float denormalized() const {
+ return float(value) / std::numeric_limits<T>::max();
+ }
+};
+
+template <class T>
+bool operator==(const Normalized<T>& lhs, const Normalized<T>& rhs) {
+ return lhs.value == rhs.value;
+}
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/program.hpp b/src/mbgl/gl/program.hpp
index 33387e9d4e..fa0470796e 100644
--- a/src/mbgl/gl/program.hpp
+++ b/src/mbgl/gl/program.hpp
@@ -20,16 +20,14 @@ public:
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");
+ using AttributeBindings = typename Attributes::Bindings;
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)),
+ attributeLocations(Attributes::locations(program)),
uniformsState((context.linkProgram(program), Uniforms::state(program))) {}
template <class DrawMode>
@@ -39,22 +37,30 @@ public:
StencilMode stencilMode,
ColorMode colorMode,
UniformValues&& uniformValues,
- const VertexBuffer<Vertex>& vertexBuffer,
+ AttributeBindings&& attributeBindings,
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)
- });
+
+ context.setDrawMode(drawMode);
+ context.setDepthMode(depthMode);
+ context.setStencilMode(stencilMode);
+ context.setColorMode(colorMode);
+
+ context.program = program;
+
+ Uniforms::bind(uniformsState, std::move(uniformValues));
+
+ for (const auto& segment : segments) {
+ segment.bind(context,
+ indexBuffer.buffer,
+ attributeLocations,
+ attributeBindings);
+
+ context.draw(drawMode.primitiveType,
+ segment.indexOffset,
+ segment.indexLength);
+ }
}
private:
@@ -62,7 +68,7 @@ private:
UniqueShader fragmentShader;
UniqueProgram program;
- typename Attributes::State attributesState;
+ typename Attributes::Locations attributeLocations;
typename Uniforms::State uniformsState;
};
diff --git a/src/mbgl/gl/segment.cpp b/src/mbgl/gl/segment.cpp
new file mode 100644
index 0000000000..aabdc83cd4
--- /dev/null
+++ b/src/mbgl/gl/segment.cpp
@@ -0,0 +1,7 @@
+#include <mbgl/gl/segment.hpp>
+
+namespace mbgl {
+namespace gl {
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/segment.hpp b/src/mbgl/gl/segment.hpp
index 8f74afd237..bd4926476f 100644
--- a/src/mbgl/gl/segment.hpp
+++ b/src/mbgl/gl/segment.hpp
@@ -1,12 +1,18 @@
#pragma once
+#include <mbgl/gl/context.hpp>
+#include <mbgl/gl/vertex_buffer.hpp>
#include <mbgl/util/optional.hpp>
+#include <mbgl/util/logging.hpp>
+#include <mutex>
#include <cstddef>
+#include <vector>
namespace mbgl {
namespace gl {
+template <class Attributes>
class Segment {
public:
Segment(std::size_t vertexOffset_,
@@ -24,13 +30,46 @@ public:
std::size_t vertexLength;
std::size_t indexLength;
+ void bind(Context& context,
+ BufferID indexBuffer_,
+ const typename Attributes::Locations& attributeLocations,
+ const typename Attributes::Bindings& attributeBindings_) const {
+ if (context.supportsVertexArrays()) {
+ if (!vao) {
+ vao = context.createVertexArray();
+ context.vertexBuffer.setDirty();
+ }
+ context.vertexArrayObject = *vao;
+ if (indexBuffer != indexBuffer_) {
+ indexBuffer = indexBuffer_;
+ context.elementBuffer.setDirty();
+ context.elementBuffer = indexBuffer_;
+ }
+ } else {
+ // No VAO support. Force attributes to be rebound.
+ static std::once_flag reportedOnce;
+ std::call_once(reportedOnce, [] {
+ Log::Warning(Event::OpenGL, "Not using Vertex Array Objects");
+ });
+ context.elementBuffer = indexBuffer_;
+ variableBindings = {};
+ }
+
+ Attributes::bind(context,
+ attributeLocations,
+ variableBindings,
+ attributeBindings_,
+ vertexOffset);
+ }
+
private:
- friend class Context;
mutable optional<UniqueVertexArray> vao;
+ mutable optional<BufferID> indexBuffer;
+ mutable typename Attributes::VariableBindings variableBindings;
};
template <class Attributes>
-class SegmentVector : public std::vector<Segment> {
+class SegmentVector : public std::vector<Segment<Attributes>> {
public:
SegmentVector() = default;
};
diff --git a/src/mbgl/gl/types.hpp b/src/mbgl/gl/types.hpp
index 577629d5d3..565ca5754f 100644
--- a/src/mbgl/gl/types.hpp
+++ b/src/mbgl/gl/types.hpp
@@ -34,16 +34,6 @@ enum class DataType : uint32_t {
Float = 0x1406
};
-template <typename T> struct DataTypeOf;
-
-template <> struct DataTypeOf<int8_t> : std::integral_constant<DataType, DataType::Byte> {};
-template <> struct DataTypeOf<uint8_t> : std::integral_constant<DataType, DataType::UnsignedByte> {};
-template <> struct DataTypeOf<int16_t> : std::integral_constant<DataType, DataType::Short> {};
-template <> struct DataTypeOf<uint16_t> : std::integral_constant<DataType, DataType::UnsignedShort> {};
-template <> struct DataTypeOf<int32_t> : std::integral_constant<DataType, DataType::Integer> {};
-template <> struct DataTypeOf<uint32_t> : std::integral_constant<DataType, DataType::UnsignedInteger> {};
-template <> struct DataTypeOf<float> : std::integral_constant<DataType, DataType::Float> {};
-
enum class RenderbufferType : uint32_t {
RGBA = 0x8058,
DepthStencil = 0x88F0,
diff --git a/src/mbgl/gl/uniform.hpp b/src/mbgl/gl/uniform.hpp
index 726cd4fe10..92136b61c2 100644
--- a/src/mbgl/gl/uniform.hpp
+++ b/src/mbgl/gl/uniform.hpp
@@ -50,32 +50,49 @@ 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_; }
+ struct name_ : ::mbgl::gl::UniformScalar<name_, type_> { static auto name() { return #name_; } }
#define MBGL_DEFINE_UNIFORM_VECTOR(type_, n_, name_) \
- struct name_ : ::mbgl::gl::UniformVector<name_, type_, n_> { static constexpr auto name = #name_; }
+ struct name_ : ::mbgl::gl::UniformVector<name_, type_, n_> { static auto name() { return #name_; } }
#define MBGL_DEFINE_UNIFORM_MATRIX(type_, n_, name_) \
- struct name_ : ::mbgl::gl::UniformMatrix<name_, type_, n_> { static constexpr auto name = #name_; }
+ struct name_ : ::mbgl::gl::UniformMatrix<name_, type_, n_> { static auto name() { return #name_; } }
UniformLocation uniformLocation(ProgramID, const char * name);
template <class... Us>
class Uniforms {
public:
+ using Types = TypeList<Us...>;
using State = IndexedTuple<TypeList<Us...>, TypeList<typename Us::State...>>;
using Values = IndexedTuple<TypeList<Us...>, TypeList<typename Us::Value...>>;
static State state(const ProgramID& id) {
- return State { { uniformLocation(id, Us::name) }... };
+ return State { { uniformLocation(id, Us::name()) }... };
}
- 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)... });
- };
+ static void bind(State& state, Values&& values) {
+ util::ignore({ (state.template get<Us>() = values.template get<Us>(), 0)... });
}
};
+
+namespace detail {
+
+template <class...>
+struct ConcatenateUniforms;
+
+template <class... As, class... Bs>
+struct ConcatenateUniforms<TypeList<As...>, TypeList<Bs...>> {
+ using Type = Uniforms<As..., Bs...>;
+};
+
+} // namespace detail
+
+template <class A, class B>
+using ConcatenateUniforms = typename detail::ConcatenateUniforms<
+ typename A::Types,
+ typename B::Types>::Type;
+
} // namespace gl
} // namespace mbgl
diff --git a/src/mbgl/gl/vertex_array.hpp b/src/mbgl/gl/vertex_array.hpp
index 6215e56f21..6b6e11324f 100644
--- a/src/mbgl/gl/vertex_array.hpp
+++ b/src/mbgl/gl/vertex_array.hpp
@@ -11,4 +11,4 @@ extern ExtensionFunction<void(GLsizei n, const GLuint* arrays)> DeleteVertexArra
extern ExtensionFunction<void(GLsizei n, GLuint* arrays)> GenVertexArrays;
} // namespace gl
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/src/mbgl/layout/symbol_feature.hpp b/src/mbgl/layout/symbol_feature.hpp
index 5dd61d9156..f4dc1680bc 100644
--- a/src/mbgl/layout/symbol_feature.hpp
+++ b/src/mbgl/layout/symbol_feature.hpp
@@ -3,13 +3,25 @@
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/util/optional.hpp>
+#include <array>
#include <string>
namespace mbgl {
-class SymbolFeature {
+class SymbolFeature : public GeometryTileFeature {
public:
- FeatureType type;
+ SymbolFeature(std::unique_ptr<GeometryTileFeature> feature_) :
+ feature(std::move(feature_)),
+ geometry(feature->getGeometries()) // we need a mutable copy of the geometry for mergeLines()
+ {}
+
+ FeatureType getType() const override { return feature->getType(); }
+ optional<Value> getValue(const std::string& key) const override { return feature->getValue(key); };
+ std::unordered_map<std::string,Value> getProperties() const override { return feature->getProperties(); };
+ optional<FeatureIdentifier> getID() const override { return feature->getID(); };
+ GeometryCollection getGeometries() const override { return geometry; };
+
+ std::unique_ptr<GeometryTileFeature> feature;
GeometryCollection geometry;
optional<std::u16string> text;
optional<std::string> icon;
diff --git a/src/mbgl/layout/symbol_instance.cpp b/src/mbgl/layout/symbol_instance.cpp
index fafcc7c15d..d81783b2f6 100644
--- a/src/mbgl/layout/symbol_instance.cpp
+++ b/src/mbgl/layout/symbol_instance.cpp
@@ -6,29 +6,45 @@ namespace mbgl {
using namespace style;
SymbolInstance::SymbolInstance(Anchor& anchor, const GeometryCoordinates& line,
- const Shaping& shapedText, const PositionedIcon& shapedIcon,
+ const std::pair<Shaping, Shaping>& shapedTextOrientations, const PositionedIcon& shapedIcon,
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) :
+ const GlyphPositions& face, const IndexedSubfeature& indexedFeature, const std::size_t featureIndex_) :
point(anchor.point),
index(index_),
- hasText(shapedText),
+ hasText(shapedTextOrientations.first || shapedTextOrientations.second),
hasIcon(shapedIcon),
- // Create the quads used for rendering the glyphs.
- glyphQuads(addToBuffers && shapedText ?
- getGlyphQuads(anchor, shapedText, textBoxScale, line, layout, textPlacement, face) :
- SymbolQuads()),
+ // Create the collision features that will be used to check whether this symbol instance can be placed
+ textCollisionFeature(line, anchor, shapedTextOrientations.second ?: shapedTextOrientations.first, textBoxScale, textPadding, textPlacement, indexedFeature),
+ iconCollisionFeature(line, anchor, shapedIcon, iconBoxScale, iconPadding, iconPlacement, indexedFeature),
+ featureIndex(featureIndex_) {
- // Create the quad used for rendering the icon.
- iconQuads(addToBuffers && shapedIcon ?
- getIconQuads(anchor, shapedIcon, line, layout, iconPlacement, shapedText) :
- SymbolQuads()),
+ // Create the quads used for rendering the icon and glyphs.
+ if (addToBuffers) {
+ if (shapedIcon) {
+ iconQuad = getIconQuad(anchor, shapedIcon, line, layout, iconPlacement, shapedTextOrientations.first);
+ }
+ if (shapedTextOrientations.first) {
+ auto quads = getGlyphQuads(anchor, shapedTextOrientations.first, textBoxScale, line, layout, textPlacement, face);
+ glyphQuads.insert(glyphQuads.end(), quads.begin(), quads.end());
+ }
+ if (shapedTextOrientations.second) {
+ auto quads = getGlyphQuads(anchor, shapedTextOrientations.second, textBoxScale, line, layout, textPlacement, face);
+ glyphQuads.insert(glyphQuads.end(), quads.begin(), quads.end());
+ }
+ }
- // Create the collision features that will be used to check whether this symbol instance can be placed
- textCollisionFeature(line, anchor, shapedText, textBoxScale, textPadding, textPlacement, indexedFeature),
- iconCollisionFeature(line, anchor, shapedIcon, iconBoxScale, iconPadding, iconPlacement, indexedFeature)
- {}
+ if (shapedTextOrientations.first && shapedTextOrientations.second) {
+ writingModes = WritingModeType::Horizontal | WritingModeType::Vertical;
+ } else if (shapedTextOrientations.first) {
+ writingModes = WritingModeType::Horizontal;
+ } else if (shapedTextOrientations.second) {
+ writingModes = WritingModeType::Vertical;
+ } else {
+ writingModes = WritingModeType::None;
+ }
+}
} // namespace mbgl
diff --git a/src/mbgl/layout/symbol_instance.hpp b/src/mbgl/layout/symbol_instance.hpp
index 508c11a394..532a4d30d8 100644
--- a/src/mbgl/layout/symbol_instance.hpp
+++ b/src/mbgl/layout/symbol_instance.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <mbgl/text/quads.hpp>
+#include <mbgl/text/glyph.hpp>
#include <mbgl/text/collision_feature.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
@@ -12,20 +13,22 @@ class IndexedSubfeature;
class SymbolInstance {
public:
explicit SymbolInstance(Anchor& anchor, const GeometryCoordinates& line,
- const Shaping& shapedText, const PositionedIcon& shapedIcon,
+ const std::pair<Shaping, Shaping>& shapedTextOrientations, const PositionedIcon& shapedIcon,
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);
+ const GlyphPositions& face, const IndexedSubfeature& indexedfeature, const std::size_t featureIndex);
Point<float> point;
uint32_t index;
bool hasText;
bool hasIcon;
SymbolQuads glyphQuads;
- SymbolQuads iconQuads;
+ optional<SymbolQuad> iconQuad;
CollisionFeature textCollisionFeature;
CollisionFeature iconCollisionFeature;
+ WritingModeType writingModes;
+ std::size_t featureIndex;
};
} // namespace mbgl
diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp
index eaa0332995..3a2c082ad8 100644
--- a/src/mbgl/layout/symbol_layout.cpp
+++ b/src/mbgl/layout/symbol_layout.cpp
@@ -3,7 +3,9 @@
#include <mbgl/layout/clip_lines.hpp>
#include <mbgl/renderer/symbol_bucket.hpp>
#include <mbgl/style/filter_evaluator.hpp>
-#include <mbgl/style/layer.hpp>
+#include <mbgl/style/bucket_parameters.hpp>
+#include <mbgl/style/layers/symbol_layer.hpp>
+#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/text/glyph_atlas.hpp>
#include <mbgl/text/get_anchors.hpp>
@@ -15,6 +17,7 @@
#include <mbgl/util/std.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/string.hpp>
+#include <mbgl/util/i18n.hpp>
#include <mbgl/math/clamp.hpp>
#include <mbgl/math/minmax.hpp>
#include <mbgl/math/log2.hpp>
@@ -27,48 +30,82 @@ namespace mbgl {
using namespace style;
-SymbolLayout::SymbolLayout(std::vector<std::string> layerIDs_,
- std::string sourceLayerName_,
- uint32_t overscaling_,
- float zoom_,
- const MapMode mode_,
- const GeometryTileLayer& layer,
- const style::Filter& filter,
- style::SymbolLayoutProperties::Evaluated layout_,
- float textMaxSize_,
+SymbolLayout::SymbolLayout(const BucketParameters& parameters,
+ const std::vector<const Layer*>& layers,
+ const GeometryTileLayer& sourceLayer,
SpriteAtlas& spriteAtlas_)
- : layerIDs(std::move(layerIDs_)),
- sourceLayerName(std::move(sourceLayerName_)),
- overscaling(overscaling_),
- zoom(zoom_),
- mode(mode_),
- layout(std::move(layout_)),
- textMaxSize(textMaxSize_),
+ : sourceLayerName(sourceLayer.getName()),
+ bucketName(layers.at(0)->getID()),
+ overscaling(parameters.tileID.overscaleFactor()),
+ zoom(parameters.tileID.overscaledZ),
+ mode(parameters.mode),
spriteAtlas(spriteAtlas_),
- tileSize(util::tileSize * overscaling_),
+ tileSize(util::tileSize * overscaling),
tilePixelRatio(float(util::EXTENT) / tileSize) {
- const bool hasText = !layout.get<TextField>().empty() && !layout.get<TextFont>().empty();
+ const SymbolLayer::Impl& leader = *layers.at(0)->as<SymbolLayer>()->impl;
+
+ layout = leader.layout.evaluate(PropertyEvaluationParameters(zoom));
+
+ if (layout.get<IconRotationAlignment>() == AlignmentType::Auto) {
+ if (layout.get<SymbolPlacement>() == SymbolPlacementType::Line) {
+ layout.get<IconRotationAlignment>() = AlignmentType::Map;
+ } else {
+ layout.get<IconRotationAlignment>() = AlignmentType::Viewport;
+ }
+ }
+
+ if (layout.get<TextRotationAlignment>() == AlignmentType::Auto) {
+ if (layout.get<SymbolPlacement>() == SymbolPlacementType::Line) {
+ layout.get<TextRotationAlignment>() = AlignmentType::Map;
+ } else {
+ layout.get<TextRotationAlignment>() = AlignmentType::Viewport;
+ }
+ }
+
+ // If unspecified `text-pitch-alignment` inherits `text-rotation-alignment`
+ if (layout.get<TextPitchAlignment>() == AlignmentType::Auto) {
+ layout.get<TextPitchAlignment>() = layout.get<TextRotationAlignment>();
+ }
+
+ textMaxSize = leader.layout.evaluate<TextSize>(PropertyEvaluationParameters(18));
+
+ layout.get<IconSize>() = leader.layout.evaluate<IconSize>(PropertyEvaluationParameters(zoom + 1));
+ layout.get<TextSize>() = leader.layout.evaluate<TextSize>(PropertyEvaluationParameters(zoom + 1));
+
+ const bool hasTextField = layout.get<TextField>().match(
+ [&] (const std::string& s) { return !s.empty(); },
+ [&] (const auto&) { return true; }
+ );
+
+ const bool hasText = !layout.get<TextFont>().empty() && hasTextField;
+
const bool hasIcon = !layout.get<IconImage>().empty();
if (!hasText && !hasIcon) {
return;
}
- auto layerName = layer.getName();
+ for (const auto& layer : layers) {
+ layerPaintProperties.emplace(layer->getID(), std::make_pair(
+ layer->as<SymbolLayer>()->impl->iconPaintProperties(),
+ layer->as<SymbolLayer>()->impl->textPaintProperties()
+ ));
+ }
// Determine and load glyph ranges
- const size_t featureCount = layer.featureCount();
+ const size_t featureCount = sourceLayer.featureCount();
for (size_t i = 0; i < featureCount; ++i) {
- auto feature = layer.getFeature(i);
- if (!filter(feature->getType(), feature->getID(), [&] (const auto& key) { return feature->getValue(key); }))
+ auto feature = sourceLayer.getFeature(i);
+ if (!leader.filter(feature->getType(), feature->getID(), [&] (const auto& key) { return feature->getValue(key); }))
continue;
+
+ SymbolFeature ft(std::move(feature));
- SymbolFeature ft;
ft.index = i;
- auto getValue = [&feature](const std::string& key) -> std::string {
- auto value = feature->getValue(key);
+ auto getValue = [&ft](const std::string& key) -> std::string {
+ auto value = ft.getValue(key);
if (!value)
return std::string();
if (value->is<std::string>())
@@ -83,13 +120,18 @@ SymbolLayout::SymbolLayout(std::vector<std::string> layerIDs_,
return util::toString(value->get<double>());
return "null";
};
-
+
if (hasText) {
- std::string u8string = util::replaceTokens(layout.get<TextField>(), getValue);
+ std::string u8string = layout.evaluate<TextField>(zoom, ft);
+ if (layout.get<TextField>().isConstant()) {
+ u8string = util::replaceTokens(u8string, getValue);
+ }
+
+ auto textTransform = layout.evaluate<TextTransform>(zoom, ft);
- if (layout.get<TextTransform>() == TextTransformType::Uppercase) {
+ if (textTransform == TextTransformType::Uppercase) {
u8string = platform::uppercase(u8string);
- } else if (layout.get<TextTransform>() == TextTransformType::Lowercase) {
+ } else if (textTransform == TextTransformType::Lowercase) {
u8string = platform::lowercase(u8string);
}
@@ -98,6 +140,9 @@ SymbolLayout::SymbolLayout(std::vector<std::string> layerIDs_,
// Loop through all characters of this text and collect unique codepoints.
for (char16_t chr : *ft.text) {
ranges.insert(getGlyphRange(chr));
+ if (char16_t verticalChr = util::i18n::verticalizePunctuation(chr)) {
+ ranges.insert(getGlyphRange(verticalChr));
+ }
}
}
@@ -106,8 +151,6 @@ SymbolLayout::SymbolLayout(std::vector<std::string> layerIDs_,
}
if (ft.text || ft.icon) {
- ft.type = feature->getType();
- ft.geometry = feature->getGeometries();
features.push_back(std::move(ft));
}
}
@@ -122,7 +165,12 @@ bool SymbolLayout::hasSymbolInstances() const {
}
bool SymbolLayout::canPrepare(GlyphAtlas& glyphAtlas) {
- if (!layout.get<TextField>().empty() && !layout.get<TextFont>().empty() && !glyphAtlas.hasGlyphRanges(layout.get<TextFont>(), ranges)) {
+ const bool hasTextField = layout.get<TextField>().match(
+ [&] (const std::string& s) { return !s.empty(); },
+ [&] (const auto&) { return true; }
+ );
+
+ if (hasTextField && !layout.get<TextFont>().empty() && !glyphAtlas.hasGlyphRanges(layout.get<TextFont>(), ranges)) {
return false;
}
@@ -178,61 +226,83 @@ void SymbolLayout::prepare(uintptr_t tileUID,
auto glyphSet = glyphAtlas.getGlyphSet(layout.get<TextFont>());
- for (const auto& feature : features) {
+ const bool textAlongLine = layout.get<TextRotationAlignment>() == AlignmentType::Map &&
+ layout.get<SymbolPlacement>() == SymbolPlacementType::Line;
+
+ for (auto it = features.begin(); it != features.end(); ++it) {
+ auto& feature = *it;
if (feature.geometry.empty()) continue;
- Shaping shapedText;
+ std::pair<Shaping, Shaping> shapedTextOrientations;
PositionedIcon shapedIcon;
GlyphPositions face;
// if feature has text, shape the text
if (feature.text) {
- shapedText = glyphSet->getShaping(
- /* string */ *feature.text,
- /* 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.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.get<TextFont>(), **glyphSet, face);
+ auto getShaping = [&] (const std::u16string& text, WritingModeType writingMode) {
+ const float oneEm = 24.0f;
+ const Shaping result = glyphSet->getShaping(
+ /* string */ text,
+ /* maxWidth: ems */ layout.get<SymbolPlacement>() != SymbolPlacementType::Line ?
+ layout.get<TextMaxWidth>() * oneEm : 0,
+ /* lineHeight: ems */ layout.get<TextLineHeight>() * oneEm,
+ /* horizontalAlign */ horizontalAlign,
+ /* verticalAlign */ verticalAlign,
+ /* justify */ justify,
+ /* spacing: ems */ layout.get<TextLetterSpacing>() * oneEm,
+ /* translate */ Point<float>(layout.get<TextOffset>()[0], layout.get<TextOffset>()[1]),
+ /* verticalHeight */ oneEm,
+ /* writingMode */ writingMode,
+ /* bidirectional algorithm object */ bidi);
+
+ // Add the glyphs we need for this label to the glyph atlas.
+ if (result) {
+ glyphAtlas.addGlyphs(tileUID, text, layout.get<TextFont>(), glyphSet, face);
+ }
+
+ return result;
+ };
+
+ shapedTextOrientations.first = getShaping(*feature.text, WritingModeType::Horizontal);
+
+ if (util::i18n::allowsVerticalWritingMode(*feature.text) && textAlongLine) {
+ shapedTextOrientations.second = getShaping(util::i18n::verticalizePunctuation(*feature.text), WritingModeType::Vertical);
}
}
// if feature has icon, get sprite atlas position
if (feature.icon) {
- auto image = spriteAtlas.getImage(*feature.icon, SpritePatternMode::Single);
+ auto image = spriteAtlas.getIcon(*feature.icon);
if (image) {
- shapedIcon = shapeIcon(*image, layout);
+ shapedIcon = shapeIcon(*image,
+ layout.evaluate<IconOffset>(zoom, feature),
+ layout.evaluate<IconRotate>(zoom, feature) * util::DEG2RAD);
assert((*image).spriteImage);
if ((*image).spriteImage->sdf) {
sdfIcons = true;
}
if ((*image).relativePixelRatio != 1.0f) {
iconsNeedLinear = true;
- } else if (layout.get<IconRotate>() != 0) {
+ } else if (layout.get<IconRotate>().constantOr(1) != 0) {
iconsNeedLinear = true;
}
}
}
// if either shapedText or icon position is present, add the feature
- if (shapedText || shapedIcon) {
- addFeature(feature, shapedText, shapedIcon, face);
+ if (shapedTextOrientations.first || shapedIcon) {
+ addFeature(std::distance(features.begin(), it), feature, shapedTextOrientations, shapedIcon, face);
}
+
+ feature.geometry.clear();
}
- features.clear();
+ compareText.clear();
}
-void SymbolLayout::addFeature(const SymbolFeature& feature,
- const Shaping& shapedText,
+void SymbolLayout::addFeature(const std::size_t index,
+ const SymbolFeature& feature,
+ const std::pair<Shaping, Shaping>& shapedTextOrientations,
const PositionedIcon& shapedIcon,
const GlyphPositions& face) {
const float minScale = 0.5f;
@@ -254,7 +324,7 @@ void SymbolLayout::addFeature(const SymbolFeature& feature,
? SymbolPlacementType::Point
: layout.get<SymbolPlacement>();
const float textRepeatDistance = symbolSpacing / 2;
- IndexedSubfeature indexedFeature = {feature.index, sourceLayerName, layerIDs.at(0), symbolInstances.size()};
+ 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
@@ -277,11 +347,13 @@ void SymbolLayout::addFeature(const SymbolFeature& feature,
const bool addToBuffers = mode == MapMode::Still || withinPlus0;
- symbolInstances.emplace_back(anchor, line, shapedText, shapedIcon, layout, addToBuffers, symbolInstances.size(),
+ symbolInstances.emplace_back(anchor, line, shapedTextOrientations, shapedIcon, layout, addToBuffers, symbolInstances.size(),
textBoxScale, textPadding, textPlacement,
iconBoxScale, iconPadding, iconPlacement,
- face, indexedFeature);
+ face, indexedFeature, index);
};
+
+ const auto& type = feature.getType();
if (layout.get<SymbolPlacement>() == SymbolPlacementType::Line) {
auto clippedLines = util::clipLines(feature.geometry, 0, 0, util::EXTENT, util::EXTENT);
@@ -289,8 +361,8 @@ void SymbolLayout::addFeature(const SymbolFeature& feature,
Anchors anchors = getAnchors(line,
symbolSpacing,
textMaxAngle,
- shapedText.left,
- shapedText.right,
+ (shapedTextOrientations.second ?: shapedTextOrientations.first).left,
+ (shapedTextOrientations.second ?: shapedTextOrientations.first).right,
shapedIcon.left,
shapedIcon.right,
glyphSize,
@@ -298,12 +370,12 @@ void SymbolLayout::addFeature(const SymbolFeature& feature,
overscaling);
for (auto& anchor : anchors) {
- if (!shapedText || !anchorIsTooClose(shapedText.text, textRepeatDistance, anchor)) {
+ if (!feature.text || !anchorIsTooClose(*feature.text, textRepeatDistance, anchor)) {
addSymbolInstance(line, anchor);
}
}
}
- } else if (feature.type == FeatureType::Polygon) {
+ } else if (type == FeatureType::Polygon) {
for (const auto& polygon : classifyRings(feature.geometry)) {
Polygon<double> poly;
for (const auto& ring : polygon) {
@@ -319,12 +391,12 @@ void SymbolLayout::addFeature(const SymbolFeature& feature,
Anchor anchor(poi.x, poi.y, 0, minScale);
addSymbolInstance(polygon[0], anchor);
}
- } else if (feature.type == FeatureType::LineString) {
+ } else if (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) {
+ } else if (type == FeatureType::Point) {
for (const auto& points : feature.geometry) {
for (const auto& point : points) {
Anchor anchor(point.x, point.y, 0, minScale);
@@ -350,7 +422,7 @@ bool SymbolLayout::anchorIsTooClose(const std::u16string& text, const float repe
}
std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile) {
- auto bucket = std::make_unique<SymbolBucket>(mode, layout, sdfIcons, iconsNeedLinear);
+ auto bucket = std::make_unique<SymbolBucket>(layout, layerPaintProperties, zoom, sdfIcons, iconsNeedLinear);
// Calculate which labels can be shown and when they can be shown and
// create the bufers used for rendering.
@@ -365,6 +437,8 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile)
const bool mayOverlap = layout.get<TextAllowOverlap>() || layout.get<IconAllowOverlap>() ||
layout.get<TextIgnorePlacement>() || layout.get<IconIgnorePlacement>();
+ const bool keepUpright = layout.get<TextKeepUpright>();
+
// Sort symbols by their y position on the canvas so that they lower symbols
// are drawn on top of higher symbols.
// Don't sort symbols that won't overlap because it isn't necessary and
@@ -416,22 +490,32 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile)
// Insert final placement into collision tree and add glyphs/icons to buffers
if (hasText) {
+ const float placementZoom = util::max(util::log2(glyphScale) + zoom, 0.0f);
collisionTile.insertFeature(symbolInstance.textCollisionFeature, glyphScale, layout.get<TextIgnorePlacement>());
if (glyphScale < collisionTile.maxScale) {
- addSymbols(
- bucket->text, symbolInstance.glyphQuads, glyphScale,
- layout.get<TextKeepUpright>(), textPlacement, collisionTile.config.angle);
+ for (const auto& symbol : symbolInstance.glyphQuads) {
+ addSymbol(
+ bucket->text, symbol, placementZoom,
+ keepUpright, textPlacement, collisionTile.config.angle, symbolInstance.writingModes);
+ }
}
}
if (hasIcon) {
+ const float placementZoom = util::max(util::log2(iconScale) + zoom, 0.0f);
collisionTile.insertFeature(symbolInstance.iconCollisionFeature, iconScale, layout.get<IconIgnorePlacement>());
- if (iconScale < collisionTile.maxScale) {
- addSymbols(
- bucket->icon, symbolInstance.iconQuads, iconScale,
- layout.get<IconKeepUpright>(), iconPlacement, collisionTile.config.angle);
+ if (iconScale < collisionTile.maxScale && symbolInstance.iconQuad) {
+ addSymbol(
+ bucket->icon, *symbolInstance.iconQuad, placementZoom,
+ keepUpright, iconPlacement, collisionTile.config.angle, symbolInstance.writingModes);
}
}
+
+ const auto& feature = features.at(symbolInstance.featureIndex);
+ for (auto& pair : bucket->paintPropertyBinders) {
+ pair.second.first.populateVertexVectors(feature, bucket->icon.vertices.vertexSize());
+ pair.second.second.populateVertexVectors(feature, bucket->text.vertices.vertexSize());
+ }
}
if (collisionTile.config.debug) {
@@ -442,67 +526,76 @@ 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) {
+void SymbolLayout::addSymbol(Buffer& buffer,
+ const SymbolQuad& symbol,
+ const float placementZoom,
+ const bool keepUpright,
+ const style::SymbolPlacementType placement,
+ const float placementAngle,
+ const WritingModeType writingModes) {
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;
- const auto &tr = symbol.tr;
- const auto &bl = symbol.bl;
- const auto &br = symbol.br;
- const auto &tex = symbol.tex;
-
- 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
- const float a = std::fmod(symbol.anchorAngle + placementAngle + M_PI, M_PI * 2);
- if (keepUpright && placement == style::SymbolPlacementType::Line &&
- (a <= M_PI / 2 || a > M_PI * 3 / 2)) {
- continue;
- }
- if (maxZoom <= minZoom)
- continue;
+ const auto &tl = symbol.tl;
+ const auto &tr = symbol.tr;
+ const auto &bl = symbol.bl;
+ const auto &br = symbol.br;
+ const auto &tex = symbol.tex;
+
+ 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 incorrectly oriented glyphs
+ const float a = std::fmod(symbol.anchorAngle + placementAngle + M_PI, M_PI * 2);
+ if (writingModes & WritingModeType::Vertical) {
+ if (placement == style::SymbolPlacementType::Line && symbol.writingMode == WritingModeType::Vertical) {
+ if (keepUpright && placement == style::SymbolPlacementType::Line && (a <= (M_PI * 5 / 4) || a > (M_PI * 7 / 4)))
+ return;
+ } else if (keepUpright && placement == style::SymbolPlacementType::Line && (a <= (M_PI * 3 / 4) || a > (M_PI * 5 / 4)))
+ return;
+ } else if (keepUpright && placement == style::SymbolPlacementType::Line &&
+ (a <= M_PI / 2 || a > M_PI * 3 / 2)) {
+ return;
+ }
- // Lower min zoom so that while fading out the label
- // it can be shown outside of collision-free zoom levels
- if (minZoom == placementZoom) {
- minZoom = 0;
- }
+ if (maxZoom <= minZoom)
+ return;
- 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());
- }
+ // Lower min zoom so that while fading out the label
+ // it can be shown outside of collision-free zoom levels
+ if (minZoom == placementZoom) {
+ minZoom = 0;
+ }
- // We're generating triangle fans, so we always start with the first
- // coordinate in this polygon.
- 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(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(index + 0, index + 1, index + 2);
- buffer.triangles.emplace_back(index + 1, index + 2, index + 3);
-
- segment.vertexLength += vertexLength;
- segment.indexLength += 6;
+ 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& 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(SymbolLayoutAttributes::vertex(anchorPoint, tl, tex.x, tex.y,
+ minZoom, maxZoom, placementZoom, glyphAngle));
+ buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, tr, tex.x + tex.w, tex.y,
+ minZoom, maxZoom, placementZoom, glyphAngle));
+ buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, bl, tex.x, tex.y + tex.h,
+ minZoom, maxZoom, placementZoom, glyphAngle));
+ buffer.vertices.emplace_back(SymbolLayoutAttributes::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(index + 0, index + 1, index + 2);
+ buffer.triangles.emplace_back(index + 1, index + 2, index + 3);
+
+ segment.vertexLength += vertexLength;
+ segment.indexLength += 6;
}
void SymbolLayout::addToDebugBuffers(CollisionTile& collisionTile, SymbolBucket& bucket) {
diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp
index c89b791ccc..491d0078da 100644
--- a/src/mbgl/layout/symbol_layout.hpp
+++ b/src/mbgl/layout/symbol_layout.hpp
@@ -5,6 +5,7 @@
#include <mbgl/layout/symbol_feature.hpp>
#include <mbgl/layout/symbol_instance.hpp>
#include <mbgl/text/bidi.hpp>
+#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <memory>
#include <map>
@@ -20,6 +21,7 @@ class GlyphAtlas;
class SymbolBucket;
namespace style {
+class BucketParameters;
class Filter;
class Layer;
} // namespace style
@@ -28,15 +30,9 @@ struct Anchor;
class SymbolLayout {
public:
- SymbolLayout(std::vector<std::string> layerIDs_,
- std::string sourceLayerName_,
- uint32_t overscaling,
- float zoom,
- const MapMode,
+ SymbolLayout(const style::BucketParameters&,
+ const std::vector<const style::Layer*>&,
const GeometryTileLayer&,
- const style::Filter&,
- style::SymbolLayoutProperties::Evaluated,
- float textMaxSize,
SpriteAtlas&);
bool canPrepare(GlyphAtlas&);
@@ -56,12 +52,13 @@ public:
State state = Pending;
- const std::vector<std::string> layerIDs;
- const std::string sourceLayerName;
+ std::unordered_map<std::string,
+ std::pair<style::IconPaintProperties::Evaluated, style::TextPaintProperties::Evaluated>> layerPaintProperties;
private:
- void addFeature(const SymbolFeature&,
- const Shaping& shapedText,
+ void addFeature(const size_t,
+ const SymbolFeature&,
+ const std::pair<Shaping, Shaping>& shapedTextOrientations,
const PositionedIcon& shapedIcon,
const GlyphPositions& face);
@@ -72,14 +69,18 @@ private:
// Adds placed items to the buffer.
template <typename Buffer>
- void addSymbols(Buffer&, const SymbolQuads&, float scale,
- const bool keepUpright, const style::SymbolPlacementType, const float placementAngle);
+ void addSymbol(Buffer&, const SymbolQuad&, float scale,
+ const bool keepUpright, const style::SymbolPlacementType, const float placementAngle,
+ WritingModeType writingModes);
+ const std::string sourceLayerName;
+ const std::string bucketName;
const float overscaling;
const float zoom;
const MapMode mode;
- const style::SymbolLayoutProperties::Evaluated layout;
- const float textMaxSize;
+
+ style::SymbolLayoutProperties::Evaluated layout;
+ float textMaxSize;
SpriteAtlas& spriteAtlas;
@@ -92,7 +93,7 @@ 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
};
diff --git a/src/mbgl/map/backend_scope.cpp b/src/mbgl/map/backend_scope.cpp
new file mode 100644
index 0000000000..98775ceadb
--- /dev/null
+++ b/src/mbgl/map/backend_scope.cpp
@@ -0,0 +1,36 @@
+#include <mbgl/map/backend_scope.hpp>
+#include <mbgl/map/backend.hpp>
+#include <mbgl/util/thread_local.hpp>
+
+#include <cassert>
+
+namespace mbgl {
+
+static util::ThreadLocal<BackendScope> currentScope;
+
+BackendScope::BackendScope(Backend& backend_)
+ : priorScope(currentScope.get()),
+ nextScope(nullptr),
+ backend(backend_) {
+ if (priorScope) {
+ assert(priorScope->nextScope == nullptr);
+ priorScope->nextScope = this;
+ }
+ backend.activate();
+ currentScope.set(this);
+}
+
+BackendScope::~BackendScope() {
+ assert(nextScope == nullptr);
+ if (priorScope) {
+ priorScope->backend.activate();
+ currentScope.set(priorScope);
+ assert(priorScope->nextScope == this);
+ priorScope->nextScope = nullptr;
+ } else {
+ backend.deactivate();
+ currentScope.set(nullptr);
+ }
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp
index e9d4d9e247..857f088b62 100644
--- a/src/mbgl/map/map.cpp
+++ b/src/mbgl/map/map.cpp
@@ -2,6 +2,7 @@
#include <mbgl/map/camera.hpp>
#include <mbgl/map/view.hpp>
#include <mbgl/map/backend.hpp>
+#include <mbgl/map/backend_scope.hpp>
#include <mbgl/map/transform.hpp>
#include <mbgl/map/transform_state.hpp>
#include <mbgl/annotation/annotation_manager.hpp>
@@ -24,6 +25,7 @@
#include <mbgl/util/tile_coordinate.hpp>
#include <mbgl/actor/scheduler.hpp>
#include <mbgl/util/logging.hpp>
+#include <mbgl/util/string.hpp>
#include <mbgl/math/log2.hpp>
namespace mbgl {
@@ -314,10 +316,15 @@ void Map::Impl::render(View& view) {
contextMode,
debugOptions };
- painter->render(*style,
- frameData,
- view,
- annotationManager->getSpriteAtlas());
+ try {
+ painter->render(*style,
+ frameData,
+ view,
+ annotationManager->getSpriteAtlas());
+ } catch (...) {
+ Log::Error(Event::General, "Exception in render: %s", util::toString(std::current_exception()).c_str());
+ exit(1);
+ }
auto request = std::move(stillImageRequest);
request->callback(nullptr);
@@ -471,26 +478,26 @@ void Map::flyTo(const CameraOptions& camera, const AnimationOptions& animation)
#pragma mark - Position
-void Map::moveBy(const ScreenCoordinate& point, const Duration& duration) {
+void Map::moveBy(const ScreenCoordinate& point, const AnimationOptions& animation) {
impl->cameraMutated = true;
- impl->transform.moveBy(point, duration);
+ impl->transform.moveBy(point, animation);
impl->onUpdate(Update::Repaint);
}
-void Map::setLatLng(const LatLng& latLng, const Duration& duration) {
+void Map::setLatLng(const LatLng& latLng, const AnimationOptions& animation) {
impl->cameraMutated = true;
- setLatLng(latLng, optional<ScreenCoordinate> {}, duration);
+ setLatLng(latLng, optional<ScreenCoordinate> {}, animation);
}
-void Map::setLatLng(const LatLng& latLng, optional<EdgeInsets> padding, const Duration& duration) {
+void Map::setLatLng(const LatLng& latLng, optional<EdgeInsets> padding, const AnimationOptions& animation) {
impl->cameraMutated = true;
- impl->transform.setLatLng(latLng, padding, duration);
+ impl->transform.setLatLng(latLng, padding, animation);
impl->onUpdate(Update::Repaint);
}
-void Map::setLatLng(const LatLng& latLng, optional<ScreenCoordinate> anchor, const Duration& duration) {
+void Map::setLatLng(const LatLng& latLng, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
impl->cameraMutated = true;
- impl->transform.setLatLng(latLng, anchor, duration);
+ impl->transform.setLatLng(latLng, anchor, animation);
impl->onUpdate(Update::Repaint);
}
@@ -513,15 +520,15 @@ void Map::resetPosition(optional<EdgeInsets> padding) {
#pragma mark - Scale
-void Map::scaleBy(double ds, optional<ScreenCoordinate> anchor, const Duration& duration) {
+void Map::scaleBy(double ds, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
impl->cameraMutated = true;
- impl->transform.scaleBy(ds, anchor, duration);
+ impl->transform.scaleBy(ds, anchor, animation);
impl->onUpdate(Update::RecalculateStyle);
}
-void Map::setScale(double scale, optional<ScreenCoordinate> anchor, const Duration& duration) {
+void Map::setScale(double scale, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
impl->cameraMutated = true;
- impl->transform.setScale(scale, anchor, duration);
+ impl->transform.setScale(scale, anchor, animation);
impl->onUpdate(Update::RecalculateStyle);
}
@@ -529,14 +536,20 @@ double Map::getScale() const {
return impl->transform.getScale();
}
-void Map::setZoom(double zoom, const Duration& duration) {
+void Map::setZoom(double zoom, const AnimationOptions& animation) {
impl->cameraMutated = true;
- setZoom(zoom, {}, duration);
+ setZoom(zoom, optional<EdgeInsets> {}, animation);
}
-void Map::setZoom(double zoom, optional<EdgeInsets> padding, const Duration& duration) {
+void Map::setZoom(double zoom, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
impl->cameraMutated = true;
- impl->transform.setZoom(zoom, padding, duration);
+ impl->transform.setZoom(zoom, anchor, animation);
+ impl->onUpdate(Update::RecalculateStyle);
+}
+
+void Map::setZoom(double zoom, optional<EdgeInsets> padding, const AnimationOptions& animation) {
+ impl->cameraMutated = true;
+ impl->transform.setZoom(zoom, padding, animation);
impl->onUpdate(Update::RecalculateStyle);
}
@@ -544,14 +557,14 @@ double Map::getZoom() const {
return impl->transform.getZoom();
}
-void Map::setLatLngZoom(const LatLng& latLng, double zoom, const Duration& duration) {
+void Map::setLatLngZoom(const LatLng& latLng, double zoom, const AnimationOptions& animation) {
impl->cameraMutated = true;
- setLatLngZoom(latLng, zoom, {}, duration);
+ setLatLngZoom(latLng, zoom, {}, animation);
}
-void Map::setLatLngZoom(const LatLng& latLng, double zoom, optional<EdgeInsets> padding, const Duration& duration) {
+void Map::setLatLngZoom(const LatLng& latLng, double zoom, optional<EdgeInsets> padding, const AnimationOptions& animation) {
impl->cameraMutated = true;
- impl->transform.setLatLngZoom(latLng, zoom, padding, duration);
+ impl->transform.setLatLngZoom(latLng, zoom, padding, animation);
impl->onUpdate(Update::RecalculateStyle);
}
@@ -661,26 +674,26 @@ Size Map::getSize() const {
#pragma mark - Rotation
-void Map::rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const Duration& duration) {
+void Map::rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const AnimationOptions& animation) {
impl->cameraMutated = true;
- impl->transform.rotateBy(first, second, duration);
+ impl->transform.rotateBy(first, second, animation);
impl->onUpdate(Update::Repaint);
}
-void Map::setBearing(double degrees, const Duration& duration) {
+void Map::setBearing(double degrees, const AnimationOptions& animation) {
impl->cameraMutated = true;
- setBearing(degrees, EdgeInsets(), duration);
+ setBearing(degrees, EdgeInsets(), animation);
}
-void Map::setBearing(double degrees, optional<ScreenCoordinate> anchor, const Duration& duration) {
+void Map::setBearing(double degrees, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
impl->cameraMutated = true;
- impl->transform.setAngle(-degrees * util::DEG2RAD, anchor, duration);
+ impl->transform.setAngle(-degrees * util::DEG2RAD, anchor, animation);
impl->onUpdate(Update::Repaint);
}
-void Map::setBearing(double degrees, optional<EdgeInsets> padding, const Duration& duration) {
+void Map::setBearing(double degrees, optional<EdgeInsets> padding, const AnimationOptions& animation) {
impl->cameraMutated = true;
- impl->transform.setAngle(-degrees * util::DEG2RAD, padding, duration);
+ impl->transform.setAngle(-degrees * util::DEG2RAD, padding, animation);
impl->onUpdate(Update::Repaint);
}
@@ -688,22 +701,22 @@ double Map::getBearing() const {
return -impl->transform.getAngle() * util::RAD2DEG;
}
-void Map::resetNorth(const Duration& duration) {
+void Map::resetNorth(const AnimationOptions& animation) {
impl->cameraMutated = true;
- impl->transform.setAngle(0, duration);
+ impl->transform.setAngle(0, animation);
impl->onUpdate(Update::Repaint);
}
#pragma mark - Pitch
-void Map::setPitch(double pitch, const Duration& duration) {
+void Map::setPitch(double pitch, const AnimationOptions& animation) {
impl->cameraMutated = true;
- setPitch(pitch, {}, duration);
+ setPitch(pitch, {}, animation);
}
-void Map::setPitch(double pitch, optional<ScreenCoordinate> anchor, const Duration& duration) {
+void Map::setPitch(double pitch, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
impl->cameraMutated = true;
- impl->transform.setPitch(pitch * util::DEG2RAD, anchor, duration);
+ impl->transform.setPitch(pitch * util::DEG2RAD, anchor, animation);
impl->onUpdate(Update::Repaint);
}
@@ -912,8 +925,6 @@ void Map::addImage(const std::string& name, std::unique_ptr<const SpriteImage> i
impl->styleMutated = true;
impl->style->spriteAtlas->setSprite(name, std::move(image));
- impl->style->spriteAtlas->updateDirty();
-
impl->onUpdate(Update::Repaint);
}
@@ -924,8 +935,6 @@ void Map::removeImage(const std::string& name) {
impl->styleMutated = true;
impl->style->spriteAtlas->removeSprite(name);
- impl->style->spriteAtlas->updateDirty();
-
impl->onUpdate(Update::Repaint);
}
diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp
index ba5e205301..eab9e97bc0 100644
--- a/src/mbgl/map/transform.cpp
+++ b/src/mbgl/map/transform.cpp
@@ -322,7 +322,7 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
#pragma mark - Position
-void Transform::moveBy(const ScreenCoordinate& offset, const Duration& duration) {
+void Transform::moveBy(const ScreenCoordinate& offset, const AnimationOptions& animation) {
ScreenCoordinate centerOffset = {
offset.x,
-offset.y,
@@ -331,22 +331,22 @@ void Transform::moveBy(const ScreenCoordinate& offset, const Duration& duration)
CameraOptions camera;
camera.center = state.screenCoordinateToLatLng(centerPoint);
- easeTo(camera, duration);
+ easeTo(camera, animation);
}
-void Transform::setLatLng(const LatLng& latLng, const Duration& duration) {
- setLatLng(latLng, optional<ScreenCoordinate> {}, duration);
+void Transform::setLatLng(const LatLng& latLng, const AnimationOptions& animation) {
+ setLatLng(latLng, optional<ScreenCoordinate> {}, animation);
}
-void Transform::setLatLng(const LatLng& latLng, optional<EdgeInsets> padding, const Duration& duration) {
+void Transform::setLatLng(const LatLng& latLng, optional<EdgeInsets> padding, const AnimationOptions& animation) {
if (!latLng) return;
CameraOptions camera;
camera.center = latLng;
camera.padding = padding;
- easeTo(camera, duration);
+ easeTo(camera, animation);
}
-void Transform::setLatLng(const LatLng& latLng, optional<ScreenCoordinate> anchor, const Duration& duration) {
+void Transform::setLatLng(const LatLng& latLng, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
if (!latLng) return;
CameraOptions camera;
camera.center = latLng;
@@ -358,21 +358,21 @@ void Transform::setLatLng(const LatLng& latLng, optional<ScreenCoordinate> ancho
padding.right = state.size.width - anchor->x;
if (padding) camera.padding = padding;
}
- easeTo(camera, duration);
+ easeTo(camera, animation);
}
-void Transform::setLatLngZoom(const LatLng& latLng, double zoom, const Duration& duration) {
- setLatLngZoom(latLng, zoom, EdgeInsets {}, duration);
+void Transform::setLatLngZoom(const LatLng& latLng, double zoom, const AnimationOptions& animation) {
+ setLatLngZoom(latLng, zoom, EdgeInsets {}, animation);
}
-void Transform::setLatLngZoom(const LatLng& latLng, double zoom, optional<EdgeInsets> padding, const Duration& duration) {
+void Transform::setLatLngZoom(const LatLng& latLng, double zoom, optional<EdgeInsets> padding, const AnimationOptions& animation) {
if (!latLng || std::isnan(zoom)) return;
CameraOptions camera;
camera.center = latLng;
camera.padding = padding;
camera.zoom = zoom;
- easeTo(camera, duration);
+ easeTo(camera, animation);
}
LatLng Transform::getLatLng(optional<EdgeInsets> padding) const {
@@ -394,26 +394,26 @@ ScreenCoordinate Transform::getScreenCoordinate(optional<EdgeInsets> padding) co
#pragma mark - Zoom
-void Transform::scaleBy(double ds, const Duration& duration) {
- scaleBy(ds, optional<ScreenCoordinate> {}, duration);
+void Transform::scaleBy(double ds, const AnimationOptions& animation) {
+ scaleBy(ds, optional<ScreenCoordinate> {}, animation);
}
-void Transform::scaleBy(double ds, optional<ScreenCoordinate> anchor, const Duration& duration) {
+void Transform::scaleBy(double ds, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
if (std::isnan(ds)) return;
double scale = util::clamp(state.scale * ds, state.min_scale, state.max_scale);
- setScale(scale, anchor, duration);
+ setScale(scale, anchor, animation);
}
-void Transform::setZoom(double zoom, const Duration& duration) {
- setZoom(zoom, optional<ScreenCoordinate> {}, duration);
+void Transform::setZoom(double zoom, const AnimationOptions& animation) {
+ setZoom(zoom, optional<ScreenCoordinate> {}, animation);
}
-void Transform::setZoom(double zoom, optional<ScreenCoordinate> anchor, const Duration& duration) {
- setScale(state.zoomScale(zoom), anchor, duration);
+void Transform::setZoom(double zoom, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
+ setScale(state.zoomScale(zoom), anchor, animation);
}
-void Transform::setZoom(double zoom, optional<EdgeInsets> padding, const Duration& duration) {
- setScale(state.zoomScale(zoom), padding, duration);
+void Transform::setZoom(double zoom, optional<EdgeInsets> padding, const AnimationOptions& animation) {
+ setScale(state.zoomScale(zoom), padding, animation);
}
double Transform::getZoom() const {
@@ -424,22 +424,22 @@ double Transform::getScale() const {
return state.scale;
}
-void Transform::setScale(double scale, const Duration& duration) {
- setScale(scale, optional<ScreenCoordinate> {}, duration);
+void Transform::setScale(double scale, const AnimationOptions& animation) {
+ setScale(scale, optional<ScreenCoordinate> {}, animation);
}
-void Transform::setScale(double scale, optional<ScreenCoordinate> anchor, const Duration& duration) {
+void Transform::setScale(double scale, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
if (std::isnan(scale)) return;
CameraOptions camera;
camera.zoom = state.scaleZoom(scale);
camera.anchor = anchor;
- easeTo(camera, duration);
+ easeTo(camera, animation);
}
-void Transform::setScale(double scale, optional<EdgeInsets> padding, const Duration& duration) {
+void Transform::setScale(double scale, optional<EdgeInsets> padding, const AnimationOptions& animation) {
optional<ScreenCoordinate> anchor;
if (padding) anchor = getScreenCoordinate(padding);
- setScale(scale, anchor, duration);
+ setScale(scale, anchor, animation);
}
void Transform::setMinZoom(const double minZoom) {
@@ -454,7 +454,7 @@ void Transform::setMaxZoom(const double maxZoom) {
#pragma mark - Angle
-void Transform::rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const Duration& duration) {
+void Transform::rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const AnimationOptions& animation) {
ScreenCoordinate center = getScreenCoordinate();
const ScreenCoordinate offset = first - center;
const double distance = std::sqrt(std::pow(2, offset.x) + std::pow(2, offset.y));
@@ -470,25 +470,25 @@ void Transform::rotateBy(const ScreenCoordinate& first, const ScreenCoordinate&
CameraOptions camera;
camera.angle = state.angle + util::angle_between(first - center, second - center);
- easeTo(camera, duration);
+ easeTo(camera, animation);
}
-void Transform::setAngle(double angle, const Duration& duration) {
- setAngle(angle, optional<ScreenCoordinate> {}, duration);
+void Transform::setAngle(double angle, const AnimationOptions& animation) {
+ setAngle(angle, optional<ScreenCoordinate> {}, animation);
}
-void Transform::setAngle(double angle, optional<ScreenCoordinate> anchor, const Duration& duration) {
+void Transform::setAngle(double angle, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
if (std::isnan(angle)) return;
CameraOptions camera;
camera.angle = angle;
camera.anchor = anchor;
- easeTo(camera, duration);
+ easeTo(camera, animation);
}
-void Transform::setAngle(double angle, optional<EdgeInsets> padding, const Duration& duration) {
+void Transform::setAngle(double angle, optional<EdgeInsets> padding, const AnimationOptions& animation) {
optional<ScreenCoordinate> anchor;
if (padding && *padding) anchor = getScreenCoordinate(padding);
- setAngle(angle, anchor, duration);
+ setAngle(angle, anchor, animation);
}
double Transform::getAngle() const {
@@ -497,16 +497,16 @@ double Transform::getAngle() const {
#pragma mark - Pitch
-void Transform::setPitch(double pitch, const Duration& duration) {
- setPitch(pitch, optional<ScreenCoordinate> {}, duration);
+void Transform::setPitch(double pitch, const AnimationOptions& animation) {
+ setPitch(pitch, optional<ScreenCoordinate> {}, animation);
}
-void Transform::setPitch(double pitch, optional<ScreenCoordinate> anchor, const Duration& duration) {
+void Transform::setPitch(double pitch, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
if (std::isnan(pitch)) return;
CameraOptions camera;
camera.pitch = pitch;
camera.anchor = anchor;
- easeTo(camera, duration);
+ easeTo(camera, animation);
}
double Transform::getPitch() const {
diff --git a/src/mbgl/map/transform.hpp b/src/mbgl/map/transform.hpp
index febe71035d..66c9915715 100644
--- a/src/mbgl/map/transform.hpp
+++ b/src/mbgl/map/transform.hpp
@@ -44,12 +44,12 @@ public:
/** Pans the map by the given amount.
@param offset The distance to pan the map by, measured in pixels from
top to bottom and from left to right. */
- void moveBy(const ScreenCoordinate& offset, const Duration& = Duration::zero());
- void setLatLng(const LatLng&, const Duration& = Duration::zero());
- void setLatLng(const LatLng&, optional<EdgeInsets>, const Duration& = Duration::zero());
- void setLatLng(const LatLng&, optional<ScreenCoordinate>, const Duration& = Duration::zero());
- void setLatLngZoom(const LatLng&, double zoom, const Duration& = Duration::zero());
- void setLatLngZoom(const LatLng&, double zoom, optional<EdgeInsets>, const Duration& = Duration::zero());
+ void moveBy(const ScreenCoordinate& offset, const AnimationOptions& = {});
+ void setLatLng(const LatLng&, const AnimationOptions& = {});
+ void setLatLng(const LatLng&, optional<EdgeInsets>, const AnimationOptions& = {});
+ void setLatLng(const LatLng&, optional<ScreenCoordinate>, const AnimationOptions& = {});
+ void setLatLngZoom(const LatLng&, double zoom, const AnimationOptions& = {});
+ void setLatLngZoom(const LatLng&, double zoom, optional<EdgeInsets>, const AnimationOptions& = {});
LatLng getLatLng(optional<EdgeInsets> = {}) const;
ScreenCoordinate getScreenCoordinate(optional<EdgeInsets> = {}) const;
@@ -57,36 +57,36 @@ public:
/** Scales the map, keeping the given point fixed within the view.
@param ds The difference in scale factors to scale the map by. */
- void scaleBy(double ds, const Duration& = Duration::zero());
+ void scaleBy(double ds, const AnimationOptions& = {});
/** Scales the map, keeping the given point fixed within the view.
@param ds The difference in scale factors to scale the map by.
@param anchor A point relative to the top-left corner of the view.
If unspecified, the center point is fixed within the view. */
- void scaleBy(double ds, optional<ScreenCoordinate> anchor, const Duration& = Duration::zero());
+ void scaleBy(double ds, optional<ScreenCoordinate> anchor, const AnimationOptions& = {});
/** Sets the scale factor, keeping the given point fixed within the view.
@param scale The new scale factor. */
- void setScale(double scale, const Duration& = Duration::zero());
+ void setScale(double scale, const AnimationOptions& = {});
/** Sets the scale factor, keeping the given point fixed within the view.
@param scale The new scale factor.
@param anchor A point relative to the top-left corner of the view.
If unspecified, the center point is fixed within the view. */
- void setScale(double scale, optional<ScreenCoordinate> anchor, const Duration& = Duration::zero());
+ void setScale(double scale, optional<ScreenCoordinate> anchor, const AnimationOptions& = {});
/** Sets the scale factor, keeping the center point fixed within the inset view.
@param scale The new scale factor.
@param padding The viewport padding that affects the fixed center point. */
- void setScale(double scale, optional<EdgeInsets> padding, const Duration& = Duration::zero());
+ void setScale(double scale, optional<EdgeInsets> padding, const AnimationOptions& = {});
/** Sets the zoom level, keeping the given point fixed within the view.
@param zoom The new zoom level. */
- void setZoom(double zoom, const Duration& = Duration::zero());
+ void setZoom(double zoom, const AnimationOptions& = {});
/** Sets the zoom level, keeping the given point fixed within the view.
@param zoom The new zoom level.
@param anchor A point relative to the top-left corner of the view.
If unspecified, the center point is fixed within the view. */
- void setZoom(double zoom, optional<ScreenCoordinate> anchor, const Duration& = Duration::zero());
+ void setZoom(double zoom, optional<ScreenCoordinate> anchor, const AnimationOptions& = {});
/** Sets the zoom level, keeping the center point fixed within the inset view.
@param zoom The new zoom level.
@param padding The viewport padding that affects the fixed center point. */
- void setZoom(double zoom, optional<EdgeInsets> padding, const Duration& = Duration::zero());
+ void setZoom(double zoom, optional<EdgeInsets> padding, const AnimationOptions& = {});
/** Returns the zoom level. */
double getZoom() const;
/** Returns the scale factor. */
@@ -97,21 +97,21 @@ public:
// Angle
- void rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const Duration& = Duration::zero());
+ void rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const AnimationOptions& = {});
/** Sets the angle of rotation.
@param angle The new angle of rotation, measured in radians
counterclockwise from true north. */
- void setAngle(double angle, const Duration& = Duration::zero());
+ void setAngle(double angle, const AnimationOptions& = {});
/** Sets the angle of rotation, keeping the given point fixed within the view.
@param angle The new angle of rotation, measured in radians
counterclockwise from true north.
@param anchor A point relative to the top-left corner of the view. */
- void setAngle(double angle, optional<ScreenCoordinate> anchor, const Duration& = Duration::zero());
+ void setAngle(double angle, optional<ScreenCoordinate> anchor, const AnimationOptions& = {});
/** Sets the angle of rotation, keeping the center point fixed within the inset view.
@param angle The new angle of rotation, measured in radians
counterclockwise from true north.
@param padding The viewport padding that affects the fixed center point. */
- void setAngle(double angle, optional<EdgeInsets> padding, const Duration& = Duration::zero());
+ void setAngle(double angle, optional<EdgeInsets> padding, const AnimationOptions& = {});
/** Returns the angle of rotation.
@return The angle of rotation, measured in radians counterclockwise from
true north. */
@@ -121,12 +121,12 @@ public:
/** Sets the pitch angle.
@param angle The new pitch angle, measured in radians toward the
horizon. */
- void setPitch(double pitch, const Duration& = Duration::zero());
+ void setPitch(double pitch, const AnimationOptions& = {});
/** Sets the pitch angle, keeping the given point fixed within the view.
@param angle The new pitch angle, measured in radians toward the
horizon.
@param anchor A point relative to the top-left corner of the view. */
- void setPitch(double pitch, optional<ScreenCoordinate> anchor, const Duration& = Duration::zero());
+ void setPitch(double pitch, optional<ScreenCoordinate> anchor, const AnimationOptions& = {});
double getPitch() const;
// North Orientation
diff --git a/src/mbgl/programs/attributes.hpp b/src/mbgl/programs/attributes.hpp
index 38bbe89377..bb90f2c13c 100644
--- a/src/mbgl/programs/attributes.hpp
+++ b/src/mbgl/programs/attributes.hpp
@@ -1,23 +1,221 @@
#pragma once
#include <mbgl/gl/attribute.hpp>
+#include <mbgl/gl/uniform.hpp>
+#include <mbgl/gl/normalization.hpp>
#include <cstdint>
namespace mbgl {
namespace attributes {
-// Attributes common to several shaders.
+// Layout attributes
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";
+struct a_data : gl::Attribute<uint8_t, N> {
+ static auto name() { return "a_data"; }
};
+template <std::size_t N>
+struct a_offset : gl::Attribute<int16_t, N> {
+ static auto name() { return "a_offset"; }
+};
+
+// Paint attributes
+
+template <class Attr>
+struct Min : Attr {
+ static auto name() {
+ static const std::string name = Attr::name() + std::string("_min");
+ return name.c_str();
+ }
+};
+
+template <class Attr>
+struct Max : Attr {
+ static auto name() {
+ static const std::string name = Attr::name() + std::string("_max");
+ return name.c_str();
+ }
+};
+
+template <class Attr>
+struct InterpolationUniform : gl::UniformScalar<InterpolationUniform<Attr>, float> {
+ static auto name() {
+ static const std::string name = Attr::name() + std::string("_t");
+ return name.c_str();
+ }
+};
+
+struct a_color : gl::Attribute<gl::Normalized<uint8_t>, 4> {
+ static auto name() { return "a_color"; }
+
+ static Value value(const Color& color) {
+ return {{
+ gl::Normalized<uint8_t>(color.r),
+ gl::Normalized<uint8_t>(color.g),
+ gl::Normalized<uint8_t>(color.b),
+ gl::Normalized<uint8_t>(color.a)
+ }};
+ }
+};
+
+// used in the symbol sdf shader
+struct a_fill_color : gl::Attribute<gl::Normalized<uint8_t>, 4> {
+ static auto name() { return "a_fill_color"; }
+
+ static Value value(const Color& color) {
+ return {{
+ gl::Normalized<uint8_t>(color.r),
+ gl::Normalized<uint8_t>(color.g),
+ gl::Normalized<uint8_t>(color.b),
+ gl::Normalized<uint8_t>(color.a)
+ }};
+ }
+};
+
+// used in the symbol sdf shader
+struct a_halo_color : gl::Attribute<gl::Normalized<uint8_t>, 4> {
+ static auto name() { return "a_halo_color"; }
+
+ static Value value(const Color& color) {
+ return {{
+ gl::Normalized<uint8_t>(color.r),
+ gl::Normalized<uint8_t>(color.g),
+ gl::Normalized<uint8_t>(color.b),
+ gl::Normalized<uint8_t>(color.a)
+ }};
+ }
+};
+
+struct a_stroke_color : gl::Attribute<gl::Normalized<uint8_t>, 4> {
+ static auto name() { return "a_stroke_color"; }
+
+ static Value value(const Color& color) {
+ return {{
+ gl::Normalized<uint8_t>(color.r),
+ gl::Normalized<uint8_t>(color.g),
+ gl::Normalized<uint8_t>(color.b),
+ gl::Normalized<uint8_t>(color.a)
+ }};
+ }
+};
+
+struct a_outline_color : gl::Attribute<gl::Normalized<uint8_t>, 4> {
+ static auto name() { return "a_outline_color"; }
+
+ static Value value(const Color& color) {
+ return {{
+ gl::Normalized<uint8_t>(color.r),
+ gl::Normalized<uint8_t>(color.g),
+ gl::Normalized<uint8_t>(color.b),
+ gl::Normalized<uint8_t>(color.a)
+ }};
+ }
+};
+
+struct a_opacity : gl::Attribute<gl::Normalized<uint8_t>, 1> {
+ static auto name() { return "a_opacity"; }
+
+ static Value value(float opacity) {
+ return {{ gl::Normalized<uint8_t>(opacity) }};
+ }
+};
+
+struct a_stroke_opacity : gl::Attribute<gl::Normalized<uint8_t>, 1> {
+ static auto name() { return "a_stroke_opacity"; }
+
+ static Value value(float opacity) {
+ return {{ gl::Normalized<uint8_t>(opacity) }};
+ }
+};
+
+struct a_blur : gl::Attribute<float, 1> {
+ static auto name() { return "a_blur"; }
+
+ static Value value(float blur) {
+ return {{ blur }};
+ }
+};
+
+struct a_radius : gl::Attribute<float, 1> {
+ static auto name() { return "a_radius"; }
+
+ static Value value(float radius) {
+ return {{ radius }};
+ }
+};
+
+struct a_width : gl::Attribute<float, 1> {
+ static auto name() { return "a_width"; }
+
+ static Value value(float width) {
+ return {{ width }};
+ }
+};
+
+struct a_height : gl::Attribute<float, 1> {
+ static auto name() { return "a_height"; }
+
+ static Value value(float width) {
+ return {{ width }};
+ }
+};
+
+struct a_base : gl::Attribute<float, 1> {
+ static auto name() { return "a_base"; }
+
+ static Value value(float width) {
+ return {{ width }};
+ }
+};
+
+struct a_gap_width : gl::Attribute<float, 1> {
+ static auto name() { return "a_gapwidth"; }
+
+ static Value value(float width) {
+ return {{ width }};
+ }
+};
+
+struct a_stroke_width : gl::Attribute<float, 1> {
+ static auto name() { return "a_stroke_width"; }
+
+ static Value value(float width) {
+ return {{ width }};
+ }
+};
+
+template <>
+struct a_offset<1> : gl::Attribute<float, 1> {
+ static auto name() { return "a_offset"; }
+
+ static Value value(float offset) {
+ return {{ offset }};
+ }
+};
+
+struct a_halo_width : gl::Attribute<float, 1> {
+ static auto name() { return "a_halo_width"; }
+
+ static Value value(float width) {
+ return {{ width }};
+ }
+};
+
+struct a_halo_blur : gl::Attribute<float, 1> {
+ static auto name() { return "a_halo_blur"; }
+
+ static Value value(float blur) {
+ return {{ blur }};
+ }
+};
+
+
+
} // namespace attributes
} // namespace mbgl
diff --git a/src/mbgl/programs/circle_program.cpp b/src/mbgl/programs/circle_program.cpp
index d6bc439feb..99b47dd5c0 100644
--- a/src/mbgl/programs/circle_program.cpp
+++ b/src/mbgl/programs/circle_program.cpp
@@ -2,6 +2,6 @@
namespace mbgl {
-static_assert(sizeof(CircleProgram::Vertex) == 4, "expected CircleVertex size");
+static_assert(sizeof(CircleLayoutVertex) == 4, "expected CircleLayoutVertex size");
} // namespace mbgl
diff --git a/src/mbgl/programs/circle_program.hpp b/src/mbgl/programs/circle_program.hpp
index c9aea1d137..8f056048b1 100644
--- a/src/mbgl/programs/circle_program.hpp
+++ b/src/mbgl/programs/circle_program.hpp
@@ -3,37 +3,26 @@
#include <mbgl/programs/program.hpp>
#include <mbgl/programs/attributes.hpp>
#include <mbgl/programs/uniforms.hpp>
-#include <mbgl/shader/circle.hpp>
+#include <mbgl/shaders/circle.hpp>
#include <mbgl/util/geometry.hpp>
+#include <mbgl/style/layers/circle_layer_properties.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::Attributes<
+ attributes::a_pos>,
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>>
+ uniforms::u_extrude_scale>,
+ style::CirclePaintProperties>
{
public:
using Program::Program;
@@ -44,16 +33,17 @@ public:
* @param {number} ex extrude normal
* @param {number} ey extrude normal
*/
- static Vertex vertex(Point<int16_t> p, float ex, float ey) {
- return Vertex {
- {
+ static LayoutVertex vertex(Point<int16_t> p, float ex, float ey) {
+ return LayoutVertex {
+ {{
static_cast<int16_t>((p.x * 2) + ((ex + 1) / 2)),
static_cast<int16_t>((p.y * 2) + ((ey + 1) / 2))
- }
+ }}
};
}
};
-using CircleVertex = CircleProgram::Vertex;
+using CircleLayoutVertex = CircleProgram::LayoutVertex;
+using CircleAttributes = CircleProgram::Attributes;
} // namespace mbgl
diff --git a/src/mbgl/programs/collision_box_program.cpp b/src/mbgl/programs/collision_box_program.cpp
index d6a36e54a1..a3dc01ebe4 100644
--- a/src/mbgl/programs/collision_box_program.cpp
+++ b/src/mbgl/programs/collision_box_program.cpp
@@ -2,6 +2,6 @@
namespace mbgl {
-static_assert(sizeof(CollisionBoxProgram::Vertex) == 10, "expected CollisionBoxVertex size");
+static_assert(sizeof(CollisionBoxProgram::LayoutVertex) == 10, "expected CollisionBoxVertex size");
} // namespace mbgl
diff --git a/src/mbgl/programs/collision_box_program.hpp b/src/mbgl/programs/collision_box_program.hpp
index 26e38419a4..78ed6aa0c9 100644
--- a/src/mbgl/programs/collision_box_program.hpp
+++ b/src/mbgl/programs/collision_box_program.hpp
@@ -3,7 +3,7 @@
#include <mbgl/programs/program.hpp>
#include <mbgl/programs/attributes.hpp>
#include <mbgl/programs/uniforms.hpp>
-#include <mbgl/shader/collision_box.hpp>
+#include <mbgl/shaders/collision_box.hpp>
#include <mbgl/util/geometry.hpp>
#include <cmath>
@@ -28,29 +28,30 @@ class CollisionBoxProgram : public Program<
uniforms::u_matrix,
uniforms::u_scale,
uniforms::u_zoom,
- uniforms::u_maxzoom>>
+ uniforms::u_maxzoom>,
+ style::PaintProperties<>>
{
public:
using Program::Program;
- static Vertex vertex(Point<float> a, Point<float> o, float maxzoom, float placementZoom) {
- return Vertex {
- {
+ static LayoutVertex vertex(Point<float> a, Point<float> o, float maxzoom, float placementZoom) {
+ return LayoutVertex {
+ {{
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;
+using CollisionBoxVertex = CollisionBoxProgram::LayoutVertex;
} // namespace mbgl
diff --git a/src/mbgl/programs/debug_program.hpp b/src/mbgl/programs/debug_program.hpp
index cd4e08b1bc..de1666b4a8 100644
--- a/src/mbgl/programs/debug_program.hpp
+++ b/src/mbgl/programs/debug_program.hpp
@@ -3,25 +3,25 @@
#include <mbgl/programs/program.hpp>
#include <mbgl/programs/attributes.hpp>
#include <mbgl/programs/uniforms.hpp>
-#include <mbgl/shader/debug.hpp>
+#include <mbgl/shaders/debug.hpp>
namespace mbgl {
-using DebugAttributes = gl::Attributes<
- attributes::a_pos>;
-
class DebugProgram : public Program<
shaders::debug,
gl::Line,
- DebugAttributes,
+ gl::Attributes<
+ attributes::a_pos>,
gl::Uniforms<
uniforms::u_matrix,
- uniforms::u_color>>
+ uniforms::u_color>,
+ style::PaintProperties<>>
{
public:
using Program::Program;
};
-using DebugVertex = DebugProgram::Vertex;
+using DebugLayoutVertex = DebugProgram::LayoutVertex;
+using DebugAttributes = DebugProgram::Attributes;
} // namespace mbgl
diff --git a/src/mbgl/programs/fill_program.cpp b/src/mbgl/programs/fill_program.cpp
index a8154d08f9..eebcffd2cb 100644
--- a/src/mbgl/programs/fill_program.cpp
+++ b/src/mbgl/programs/fill_program.cpp
@@ -8,14 +8,13 @@ namespace mbgl {
using namespace style;
-static_assert(sizeof(FillAttributes::Vertex) == 4, "expected FillVertex size");
+static_assert(sizeof(FillLayoutVertex) == 4, "expected FillLayoutVertex size");
FillPatternUniforms::Values
FillPatternUniforms::values(mat4 matrix,
- float opacity,
Size framebufferSize,
- const SpriteAtlasPosition& a,
- const SpriteAtlasPosition& b,
+ const SpriteAtlasElement& a,
+ const SpriteAtlasElement& b,
const Faded<std::string>& fading,
const UnwrappedTileID& tileID,
const TransformState& state)
@@ -26,7 +25,6 @@ FillPatternUniforms::values(mat4 matrix,
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 },
diff --git a/src/mbgl/programs/fill_program.hpp b/src/mbgl/programs/fill_program.hpp
index d885215c59..84ca2748d6 100644
--- a/src/mbgl/programs/fill_program.hpp
+++ b/src/mbgl/programs/fill_program.hpp
@@ -3,19 +3,20 @@
#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/shaders/fill.hpp>
+#include <mbgl/shaders/fill_pattern.hpp>
+#include <mbgl/shaders/fill_outline.hpp>
+#include <mbgl/shaders/fill_outline_pattern.hpp>
#include <mbgl/util/geometry.hpp>
#include <mbgl/util/mat4.hpp>
#include <mbgl/util/size.hpp>
+#include <mbgl/style/layers/fill_layer_properties.hpp>
#include <string>
namespace mbgl {
-class SpriteAtlasPosition;
+class SpriteAtlasElement;
class UnwrappedTileID;
class TransformState;
@@ -25,7 +26,6 @@ template <class> class Faded;
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);
@@ -33,32 +33,17 @@ 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<
+struct FillLayoutAttributes : 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,
@@ -75,10 +60,9 @@ struct FillPatternUniforms : gl::Uniforms<
uniforms::u_tile_units_to_pixels>
{
static Values values(mat4 matrix,
- float opacity,
Size framebufferSize,
- const SpriteAtlasPosition&,
- const SpriteAtlasPosition&,
+ const SpriteAtlasElement&,
+ const SpriteAtlasElement&,
const style::Faded<std::string>&,
const UnwrappedTileID&,
const TransformState&);
@@ -87,37 +71,57 @@ struct FillPatternUniforms : gl::Uniforms<
class FillProgram : public Program<
shaders::fill,
gl::Triangle,
- FillAttributes,
- FillUniforms>
+ FillLayoutAttributes,
+ FillUniforms,
+ style::FillPaintProperties>
{
+public:
using Program::Program;
+
+ static LayoutVertex layoutVertex(Point<int16_t> p) {
+ return LayoutVertex {
+ {{
+ p.x,
+ p.y
+ }}
+ };
+ }
};
class FillPatternProgram : public Program<
shaders::fill_pattern,
gl::Triangle,
- FillAttributes,
- FillPatternUniforms>
+ FillLayoutAttributes,
+ FillPatternUniforms,
+ style::FillPaintProperties>
{
+public:
using Program::Program;
};
class FillOutlineProgram : public Program<
shaders::fill_outline,
gl::Line,
- FillAttributes,
- FillUniforms>
+ FillLayoutAttributes,
+ FillUniforms,
+ style::FillPaintProperties>
{
+public:
using Program::Program;
};
class FillOutlinePatternProgram : public Program<
shaders::fill_outline_pattern,
gl::Line,
- FillAttributes,
- FillPatternUniforms>
+ FillLayoutAttributes,
+ FillPatternUniforms,
+ style::FillPaintProperties>
{
+public:
using Program::Program;
};
+using FillLayoutVertex = FillProgram::LayoutVertex;
+using FillAttributes = FillProgram::Attributes;
+
} // namespace mbgl
diff --git a/src/mbgl/programs/line_program.cpp b/src/mbgl/programs/line_program.cpp
index f7054d3398..d9778ba7ce 100644
--- a/src/mbgl/programs/line_program.cpp
+++ b/src/mbgl/programs/line_program.cpp
@@ -10,7 +10,7 @@ namespace mbgl {
using namespace style;
-static_assert(sizeof(LineAttributes::Vertex) == 8, "expected LineVertex size");
+static_assert(sizeof(LineLayoutVertex) == 8, "expected LineLayoutVertex size");
template <class Values, class...Args>
Values makeValues(const LinePaintProperties::Evaluated& properties,
@@ -25,11 +25,7 @@ Values makeValues(const LinePaintProperties::Evaluated& properties,
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_ratio::Value{ 1.0f / tile.id.pixelsToTileUnits(1.0, state.getZoom()) },
uniforms::u_gl_units_to_pixels::Value{{{ 1.0f / pixelsToGLUnits[0], 1.0f / pixelsToGLUnits[1] }}},
std::forward<Args>(args)...
@@ -45,8 +41,7 @@ LineProgram::uniformValues(const LinePaintProperties::Evaluated& properties,
properties,
tile,
state,
- pixelsToGLUnits,
- uniforms::u_color::Value{ properties.get<LineColor>() }
+ pixelsToGLUnits
);
}
@@ -78,7 +73,6 @@ LineSDFProgram::uniformValues(const LinePaintProperties::Evaluated& properties,
tile,
state,
pixelsToGLUnits,
- 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 },
@@ -94,8 +88,8 @@ LinePatternProgram::uniformValues(const LinePaintProperties::Evaluated& properti
const RenderTile& tile,
const TransformState& state,
const std::array<float, 2>& pixelsToGLUnits,
- const SpriteAtlasPosition& posA,
- const SpriteAtlasPosition& posB) {
+ const SpriteAtlasElement& posA,
+ const SpriteAtlasElement& posB) {
std::array<float, 2> sizeA {{
tile.id.pixelsToTileUnits(posA.size[0] * properties.get<LinePattern>().fromScale, state.getIntegerZoom()),
posA.size[1]
diff --git a/src/mbgl/programs/line_program.hpp b/src/mbgl/programs/line_program.hpp
index 9b97cc47a9..842b4cc602 100644
--- a/src/mbgl/programs/line_program.hpp
+++ b/src/mbgl/programs/line_program.hpp
@@ -3,11 +3,11 @@
#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/shaders/line.hpp>
+#include <mbgl/shaders/line_pattern.hpp>
+#include <mbgl/shaders/line_sdf.hpp>
#include <mbgl/util/geometry.hpp>
+#include <mbgl/style/layers/line_layer_properties.hpp>
#include <cmath>
@@ -16,13 +16,11 @@ namespace mbgl {
class RenderTile;
class TransformState;
class LinePatternPos;
-class SpriteAtlasPosition;
+class SpriteAtlasElement;
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_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);
@@ -32,24 +30,39 @@ MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_patternscale_b);
MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_gl_units_to_pixels);
} // namespace uniforms
-struct LineAttributes : gl::Attributes<
+struct LineLayoutAttributes : gl::Attributes<
attributes::a_pos,
attributes::a_data<4>>
+{};
+
+class LineProgram : public Program<
+ shaders::line,
+ gl::Triangle,
+ LineLayoutAttributes,
+ gl::Uniforms<
+ uniforms::u_matrix,
+ uniforms::u_width,
+ uniforms::u_ratio,
+ uniforms::u_gl_units_to_pixels>,
+ style::LinePaintProperties>
{
+public:
+ using Program::Program;
+
/*
* @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 LayoutVertex layoutVertex(Point<int16_t> p, Point<double> e, Point<bool> t, int8_t dir, int32_t linesofar = 0) {
+ return LayoutVertex {
+ {{
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
+ }},
+ {{
+ // add 128 to store a byte in an unsigned byte
static_cast<uint8_t>(::round(extrudeScale * e.x) + 128),
static_cast<uint8_t>(::round(extrudeScale * e.y) + 128),
@@ -65,7 +78,7 @@ struct LineAttributes : gl::Attributes<
// 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)
- }
+ }}
};
}
@@ -77,27 +90,6 @@ struct LineAttributes : gl::Attributes<
* 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_ratio,
- uniforms::u_gl_units_to_pixels,
- uniforms::u_color>>
-{
-public:
- using Program::Program;
static UniformValues uniformValues(const style::LinePaintProperties::Evaluated&,
const RenderTile&,
@@ -108,14 +100,10 @@ public:
class LinePatternProgram : public Program<
shaders::line_pattern,
gl::Triangle,
- LineAttributes,
+ LineLayoutAttributes,
gl::Uniforms<
uniforms::u_matrix,
- uniforms::u_opacity,
uniforms::u_width,
- uniforms::u_gapwidth,
- uniforms::u_blur,
- uniforms::u_offset,
uniforms::u_ratio,
uniforms::u_gl_units_to_pixels,
uniforms::u_pattern_tl_a,
@@ -125,7 +113,8 @@ class LinePatternProgram : public Program<
uniforms::u_pattern_size_a,
uniforms::u_pattern_size_b,
uniforms::u_fade,
- uniforms::u_image>>
+ uniforms::u_image>,
+ style::LinePaintProperties>
{
public:
using Program::Program;
@@ -134,31 +123,27 @@ public:
const RenderTile&,
const TransformState&,
const std::array<float, 2>& pixelsToGLUnits,
- const SpriteAtlasPosition& posA,
- const SpriteAtlasPosition& posB);
+ const SpriteAtlasElement& posA,
+ const SpriteAtlasElement& posB);
};
class LineSDFProgram : public Program<
shaders::line_sdf,
gl::Triangle,
- LineAttributes,
+ LineLayoutAttributes,
gl::Uniforms<
uniforms::u_matrix,
- uniforms::u_opacity,
uniforms::u_width,
- uniforms::u_gapwidth,
- uniforms::u_blur,
- uniforms::u_offset,
uniforms::u_ratio,
uniforms::u_gl_units_to_pixels,
- 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>>
+ uniforms::u_image>,
+ style::LinePaintProperties>
{
public:
using Program::Program;
@@ -174,4 +159,7 @@ public:
float atlasWidth);
};
+using LineLayoutVertex = LineProgram::LayoutVertex;
+using LineAttributes = LineProgram::Attributes;
+
} // namespace mbgl
diff --git a/src/mbgl/programs/program.hpp b/src/mbgl/programs/program.hpp
index e5aae24997..e75dbebf18 100644
--- a/src/mbgl/programs/program.hpp
+++ b/src/mbgl/programs/program.hpp
@@ -2,21 +2,40 @@
#include <mbgl/gl/program.hpp>
#include <mbgl/programs/program_parameters.hpp>
+#include <mbgl/programs/attributes.hpp>
+#include <mbgl/style/paint_property.hpp>
#include <sstream>
#include <cassert>
namespace mbgl {
-template <class Shaders, class Primitive, class Attributes, class Uniforms>
-class Program : public gl::Program<Primitive, Attributes, Uniforms> {
+template <class Shaders,
+ class Primitive,
+ class LayoutAttrs,
+ class Uniforms,
+ class PaintProperties>
+class Program {
public:
- using ParentType = gl::Program<Primitive, Attributes, Uniforms>;
+ using LayoutAttributes = LayoutAttrs;
+ using LayoutVertex = typename LayoutAttributes::Vertex;
+
+ using PaintPropertyBinders = typename PaintProperties::Binders;
+ using PaintAttributes = typename PaintPropertyBinders::Attributes;
+ using Attributes = gl::ConcatenateAttributes<LayoutAttributes, PaintAttributes>;
+
+ using UniformValues = typename Uniforms::Values;
+ using PaintUniforms = typename PaintPropertyBinders::Uniforms;
+ using AllUniforms = gl::ConcatenateUniforms<Uniforms, PaintUniforms>;
+
+ using ProgramType = gl::Program<Primitive, Attributes, AllUniforms>;
+
+ ProgramType program;
Program(gl::Context& context, const ProgramParameters& programParameters)
- : ParentType(context, vertexSource(programParameters), fragmentSource(programParameters))
+ : program(context, vertexSource(programParameters), fragmentSource(programParameters))
{}
-
+
static std::string pixelRatioDefine(const ProgramParameters& parameters) {
std::ostringstream pixelRatioSS;
pixelRatioSS.imbue(std::locale("C"));
@@ -38,6 +57,33 @@ public:
return pixelRatioDefine(parameters) + Shaders::vertexSource;
}
+ template <class DrawMode>
+ void draw(gl::Context& context,
+ DrawMode drawMode,
+ gl::DepthMode depthMode,
+ gl::StencilMode stencilMode,
+ gl::ColorMode colorMode,
+ UniformValues&& uniformValues,
+ const gl::VertexBuffer<LayoutVertex>& layoutVertexBuffer,
+ const gl::IndexBuffer<DrawMode>& indexBuffer,
+ const gl::SegmentVector<Attributes>& segments,
+ const PaintPropertyBinders& paintPropertyBinders,
+ const typename PaintProperties::Evaluated& currentProperties,
+ float currentZoom) {
+ program.draw(
+ context,
+ std::move(drawMode),
+ std::move(depthMode),
+ std::move(stencilMode),
+ std::move(colorMode),
+ uniformValues
+ .concat(paintPropertyBinders.uniformValues(currentZoom)),
+ LayoutAttributes::allVariableBindings(layoutVertexBuffer)
+ .concat(paintPropertyBinders.attributeBindings(currentProperties)),
+ indexBuffer,
+ segments
+ );
+ }
};
} // namespace mbgl
diff --git a/src/mbgl/programs/programs.hpp b/src/mbgl/programs/programs.hpp
index dd71c2ce97..742c5a221b 100644
--- a/src/mbgl/programs/programs.hpp
+++ b/src/mbgl/programs/programs.hpp
@@ -40,8 +40,8 @@ public:
LinePatternProgram linePattern;
RasterProgram raster;
SymbolIconProgram symbolIcon;
- SymbolSDFProgram symbolIconSDF;
- SymbolSDFProgram symbolGlyph;
+ SymbolSDFIconProgram symbolIconSDF;
+ SymbolSDFTextProgram symbolGlyph;
DebugProgram debug;
CollisionBoxProgram collisionBox;
diff --git a/src/mbgl/programs/raster_program.cpp b/src/mbgl/programs/raster_program.cpp
index ebec4c68cc..6906903e6b 100644
--- a/src/mbgl/programs/raster_program.cpp
+++ b/src/mbgl/programs/raster_program.cpp
@@ -2,6 +2,6 @@
namespace mbgl {
-static_assert(sizeof(RasterProgram::Vertex) == 8, "expected RasterVertex size");
+static_assert(sizeof(RasterLayoutVertex) == 8, "expected RasterLayoutVertex size");
} // namespace mbgl
diff --git a/src/mbgl/programs/raster_program.hpp b/src/mbgl/programs/raster_program.hpp
index 9aa25cf90c..09cb94ac17 100644
--- a/src/mbgl/programs/raster_program.hpp
+++ b/src/mbgl/programs/raster_program.hpp
@@ -3,8 +3,9 @@
#include <mbgl/programs/program.hpp>
#include <mbgl/programs/attributes.hpp>
#include <mbgl/programs/uniforms.hpp>
-#include <mbgl/shader/raster.hpp>
+#include <mbgl/shaders/raster.hpp>
#include <mbgl/util/geometry.hpp>
+#include <mbgl/style/layers/raster_layer_properties.hpp>
namespace mbgl {
@@ -22,14 +23,12 @@ 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::Attributes<
+ attributes::a_pos,
+ attributes::a_texture_pos>,
gl::Uniforms<
uniforms::u_matrix,
uniforms::u_image0,
@@ -43,25 +42,27 @@ class RasterProgram : public Program<
uniforms::u_spin_weights,
uniforms::u_buffer_scale,
uniforms::u_scale_parent,
- uniforms::u_tl_parent>>
+ uniforms::u_tl_parent>,
+ style::RasterPaintProperties>
{
public:
using Program::Program;
- static Vertex vertex(Point<int16_t> p, Point<uint16_t> t) {
- return Vertex {
- {
+ static LayoutVertex layoutVertex(Point<int16_t> p, Point<uint16_t> t) {
+ return LayoutVertex {
+ {{
p.x,
p.y
- },
- {
+ }},
+ {{
t.x,
t.y
- }
+ }}
};
}
};
-using RasterVertex = RasterProgram::Vertex;
+using RasterLayoutVertex = RasterProgram::LayoutVertex;
+using RasterAttributes = RasterProgram::Attributes;
} // namespace mbgl
diff --git a/src/mbgl/programs/symbol_program.cpp b/src/mbgl/programs/symbol_program.cpp
index d609dada8d..19fe2bc2f6 100644
--- a/src/mbgl/programs/symbol_program.cpp
+++ b/src/mbgl/programs/symbol_program.cpp
@@ -2,12 +2,13 @@
#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/map/transform_state.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
+#include <mbgl/util/enum.hpp>
namespace mbgl {
using namespace style;
-static_assert(sizeof(SymbolAttributes::Vertex) == 16, "expected SymbolVertex size");
+static_assert(sizeof(SymbolLayoutVertex) == 16, "expected SymbolLayoutVertex size");
template <class Values, class...Args>
Values makeValues(const style::SymbolPropertyValues& values,
@@ -19,6 +20,7 @@ Values makeValues(const style::SymbolPropertyValues& values,
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 {
@@ -27,7 +29,7 @@ Values makeValues(const style::SymbolPropertyValues& values,
pixelsToGLUnits[1] * scale * state.getCameraToCenterDistance()
}};
}
-
+
// adjust min/max zooms for variable font sies
float zoomAdjust = std::log(values.paintSize / values.layoutSize) / std::log(2);
@@ -35,7 +37,6 @@ Values makeValues(const style::SymbolPropertyValues& 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) },
@@ -62,84 +63,37 @@ SymbolIconProgram::uniformValues(const style::SymbolPropertyValues& values,
);
}
-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) / state.getCameraToCenterDistance();
-
- 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,
+template <class PaintProperties>
+typename SymbolSDFProgram<PaintProperties>::UniformValues SymbolSDFProgram<PaintProperties>::uniformValues(const style::SymbolPropertyValues& values,
const Size& texsize,
const std::array<float, 2>& pixelsToGLUnits,
const RenderTile& tile,
const TransformState& state,
- float pixelRatio)
+ const SymbolSDFPart part)
{
const float scale = values.paintSize / values.sdfScale;
- const float sdfPx = 8.0f;
- const float blurOffset = 1.19f;
- const float haloOffset = 6.0f;
-
- return makeSDFValues(
+
+ const float gammaScale = scale * (values.pitchAlignment == AlignmentType::Map
+ ? std::cos(state.getPitch())
+ : 1.0) * state.getCameraToCenterDistance();
+
+ return makeValues<SymbolSDFProgram<PaintProperties>::UniformValues>(
values,
texsize,
pixelsToGLUnits,
tile,
state,
- pixelRatio,
- values.haloColor,
- (haloOffset - values.haloWidth / scale) / sdfPx,
- values.haloBlur * blurOffset / scale / sdfPx
+ uniforms::u_font_scale::Value{ scale },
+ uniforms::u_gamma_scale::Value{ 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 },
+ uniforms::u_is_halo::Value{ part == SymbolSDFPart::Halo }
);
}
-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
- );
-}
+template class SymbolSDFProgram<style::IconPaintProperties>;
+template class SymbolSDFProgram<style::TextPaintProperties>;
} // namespace mbgl
diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp
index be987551c0..0537c25a2c 100644
--- a/src/mbgl/programs/symbol_program.hpp
+++ b/src/mbgl/programs/symbol_program.hpp
@@ -3,10 +3,12 @@
#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/shaders/symbol_icon.hpp>
+#include <mbgl/shaders/symbol_sdf.hpp>
#include <mbgl/util/geometry.hpp>
#include <mbgl/util/size.hpp>
+#include <mbgl/style/layers/symbol_layer_properties.hpp>
+#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <cmath>
#include <array>
@@ -26,14 +28,15 @@ 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);
+MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_halo);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_font_scale);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_gamma_scale);
} // namespace uniforms
-struct SymbolAttributes : gl::Attributes<
+struct SymbolLayoutAttributes : gl::Attributes<
attributes::a_pos,
- attributes::a_offset,
+ attributes::a_offset<2>,
attributes::a_texture_pos,
attributes::a_data<4>>
{
@@ -46,43 +49,41 @@ struct SymbolAttributes : gl::Attributes<
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,
+ SymbolLayoutAttributes,
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_fadetexture>,
+ style::IconPaintProperties>
{
public:
using Program::Program;
@@ -94,43 +95,73 @@ public:
const TransformState&);
};
+enum class SymbolSDFPart {
+ Fill = 1,
+ Halo = 0
+};
+
+template <class PaintProperties>
class SymbolSDFProgram : public Program<
shaders::symbol_sdf,
gl::Triangle,
- SymbolAttributes,
+ SymbolLayoutAttributes,
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_font_scale,
+ uniforms::u_gamma_scale,
uniforms::u_pitch,
uniforms::u_bearing,
uniforms::u_aspect_ratio,
- uniforms::u_pitch_with_map>>
+ uniforms::u_pitch_with_map,
+ uniforms::u_is_halo>,
+ PaintProperties>
{
public:
- using Program::Program;
+ using BaseProgram = Program<shaders::symbol_sdf,
+ gl::Triangle,
+ SymbolLayoutAttributes,
+ gl::Uniforms<
+ uniforms::u_matrix,
+ uniforms::u_extrude_scale,
+ uniforms::u_texsize,
+ uniforms::u_zoom,
+ uniforms::u_rotate_with_map,
+ uniforms::u_texture,
+ uniforms::u_fadetexture,
+ uniforms::u_font_scale,
+ uniforms::u_gamma_scale,
+ uniforms::u_pitch,
+ uniforms::u_bearing,
+ uniforms::u_aspect_ratio,
+ uniforms::u_pitch_with_map,
+ uniforms::u_is_halo>,
+ PaintProperties>;
+
+ using UniformValues = typename BaseProgram::UniformValues;
+
+
+
+ using BaseProgram::BaseProgram;
- 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);
+ static UniformValues uniformValues(const style::SymbolPropertyValues&,
+ const Size& texsize,
+ const std::array<float, 2>& pixelsToGLUnits,
+ const RenderTile&,
+ const TransformState&,
+ const SymbolSDFPart);
};
+using SymbolSDFIconProgram = SymbolSDFProgram<style::IconPaintProperties>;
+using SymbolSDFTextProgram = SymbolSDFProgram<style::TextPaintProperties>;
+
+using SymbolLayoutVertex = SymbolLayoutAttributes::Vertex;
+using SymbolIconAttributes = SymbolIconProgram::Attributes;
+using SymbolTextAttributes = SymbolSDFTextProgram::Attributes;
+
} // namespace mbgl
diff --git a/src/mbgl/renderer/bucket.hpp b/src/mbgl/renderer/bucket.hpp
index 49619c14f7..294e50dd8c 100644
--- a/src/mbgl/renderer/bucket.hpp
+++ b/src/mbgl/renderer/bucket.hpp
@@ -2,6 +2,7 @@
#include <mbgl/renderer/render_pass.hpp>
#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
#include <atomic>
@@ -22,6 +23,10 @@ class Layer;
class Bucket : private util::noncopyable {
public:
Bucket() = default;
+ virtual ~Bucket() = default;
+
+ virtual void addFeature(const GeometryTileFeature&,
+ const GeometryCollection&) {};
// As long as this bucket has a Prepare render pass, this function is getting called. Typically,
// this only happens once when the bucket is being rendered for the first time.
@@ -31,8 +36,6 @@ public:
// once or twice (for Opaque and Transparent render passes).
virtual void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) = 0;
- virtual ~Bucket() = default;
-
virtual bool hasData() const = 0;
bool needsUpload() const {
diff --git a/src/mbgl/renderer/circle_bucket.cpp b/src/mbgl/renderer/circle_bucket.cpp
index ba2285c4eb..6722d04497 100644
--- a/src/mbgl/renderer/circle_bucket.cpp
+++ b/src/mbgl/renderer/circle_bucket.cpp
@@ -1,26 +1,38 @@
#include <mbgl/renderer/circle_bucket.hpp>
#include <mbgl/renderer/painter.hpp>
-#include <mbgl/gl/context.hpp>
-
#include <mbgl/programs/circle_program.hpp>
+#include <mbgl/style/bucket_parameters.hpp>
#include <mbgl/style/layers/circle_layer.hpp>
+#include <mbgl/style/layers/circle_layer_impl.hpp>
#include <mbgl/util/constants.hpp>
namespace mbgl {
using namespace style;
-CircleBucket::CircleBucket(MapMode mode_) : mode(mode_) {
+CircleBucket::CircleBucket(const BucketParameters& parameters, const std::vector<const Layer*>& layers)
+ : mode(parameters.mode) {
+ for (const auto& layer : layers) {
+ paintPropertyBinders.emplace(layer->getID(),
+ CircleProgram::PaintPropertyBinders(
+ layer->as<CircleLayer>()->impl->paint.evaluated,
+ parameters.tileID.overscaledZ));
+ }
}
void CircleBucket::upload(gl::Context& context) {
vertexBuffer = context.createVertexBuffer(std::move(vertices));
indexBuffer = context.createIndexBuffer(std::move(triangles));
+
+ for (auto& pair : paintPropertyBinders) {
+ pair.second.upload(context);
+ }
+
uploaded = true;
}
void CircleBucket::render(Painter& painter,
- PaintParameters& parameters,
+ PaintParameters& parameters,
const Layer& layer,
const RenderTile& tile) {
painter.renderCircle(parameters, *this, *layer.as<CircleLayer>(), tile);
@@ -30,10 +42,11 @@ bool CircleBucket::hasData() const {
return !segments.empty();
}
-void CircleBucket::addGeometry(const GeometryCollection& geometryCollection) {
+void CircleBucket::addFeature(const GeometryTileFeature& feature,
+ const GeometryCollection& geometry) {
constexpr const uint16_t vertexLength = 4;
- for (auto& circle : geometryCollection) {
+ for (auto& circle : geometry) {
for(auto& point : circle) {
auto x = point.x;
auto y = point.y;
@@ -76,6 +89,10 @@ void CircleBucket::addGeometry(const GeometryCollection& geometryCollection) {
segment.indexLength += 6;
}
}
+
+ for (auto& pair : paintPropertyBinders) {
+ pair.second.populateVertexVectors(feature, vertices.vertexSize());
+ }
}
} // namespace mbgl
diff --git a/src/mbgl/renderer/circle_bucket.hpp b/src/mbgl/renderer/circle_bucket.hpp
index af7041a238..412db53f65 100644
--- a/src/mbgl/renderer/circle_bucket.hpp
+++ b/src/mbgl/renderer/circle_bucket.hpp
@@ -7,26 +7,34 @@
#include <mbgl/gl/index_buffer.hpp>
#include <mbgl/gl/segment.hpp>
#include <mbgl/programs/circle_program.hpp>
+#include <mbgl/style/layers/circle_layer_properties.hpp>
namespace mbgl {
+namespace style {
+class BucketParameters;
+} // namespace style
+
class CircleBucket : public Bucket {
public:
- CircleBucket(const MapMode);
+ CircleBucket(const style::BucketParameters&, const std::vector<const style::Layer*>&);
+
+ void addFeature(const GeometryTileFeature&,
+ const GeometryCollection&) override;
+ bool hasData() const override;
void upload(gl::Context&) override;
void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override;
- bool hasData() const override;
- void addGeometry(const GeometryCollection&);
-
- gl::VertexVector<CircleVertex> vertices;
+ gl::VertexVector<CircleLayoutVertex> vertices;
gl::IndexVector<gl::Triangles> triangles;
gl::SegmentVector<CircleAttributes> segments;
- optional<gl::VertexBuffer<CircleVertex>> vertexBuffer;
+ optional<gl::VertexBuffer<CircleLayoutVertex>> vertexBuffer;
optional<gl::IndexBuffer<gl::Triangles>> indexBuffer;
+ std::unordered_map<std::string, CircleProgram::PaintPropertyBinders> paintPropertyBinders;
+
const MapMode mode;
};
diff --git a/src/mbgl/renderer/debug_bucket.cpp b/src/mbgl/renderer/debug_bucket.cpp
index 167df4376f..2a514989cf 100644
--- a/src/mbgl/renderer/debug_bucket.cpp
+++ b/src/mbgl/renderer/debug_bucket.cpp
@@ -23,7 +23,7 @@ DebugBucket::DebugBucket(const OverscaledTileID& id,
expires(std::move(expires_)),
debugMode(debugMode_) {
- gl::VertexVector<FillVertex> vertices;
+ gl::VertexVector<FillLayoutVertex> vertices;
gl::IndexVector<gl::Lines> indices;
auto addText = [&] (const std::string& text, double left, double baseline, double scale) {
@@ -43,7 +43,7 @@ DebugBucket::DebugBucket(const OverscaledTileID& id,
int16_t(::round(baseline - glyph.data[j + 1] * scale))
};
- vertices.emplace_back(FillAttributes::vertex(p));
+ vertices.emplace_back(FillProgram::layoutVertex(p));
if (prev) {
indices.emplace_back(vertices.vertexSize() - 2,
diff --git a/src/mbgl/renderer/debug_bucket.hpp b/src/mbgl/renderer/debug_bucket.hpp
index 4676381789..756e58a6de 100644
--- a/src/mbgl/renderer/debug_bucket.hpp
+++ b/src/mbgl/renderer/debug_bucket.hpp
@@ -34,7 +34,7 @@ public:
const MapDebugOptions debugMode;
gl::SegmentVector<DebugAttributes> segments;
- optional<gl::VertexBuffer<DebugVertex>> vertexBuffer;
+ optional<gl::VertexBuffer<DebugLayoutVertex>> vertexBuffer;
optional<gl::IndexBuffer<gl::Lines>> indexBuffer;
};
diff --git a/src/mbgl/renderer/fill_bucket.cpp b/src/mbgl/renderer/fill_bucket.cpp
index b89e982057..64efafb108 100644
--- a/src/mbgl/renderer/fill_bucket.cpp
+++ b/src/mbgl/renderer/fill_bucket.cpp
@@ -1,8 +1,9 @@
#include <mbgl/renderer/fill_bucket.hpp>
-#include <mbgl/style/layers/fill_layer.hpp>
#include <mbgl/renderer/painter.hpp>
#include <mbgl/programs/fill_program.hpp>
-#include <mbgl/util/logging.hpp>
+#include <mbgl/style/bucket_parameters.hpp>
+#include <mbgl/style/layers/fill_layer.hpp>
+#include <mbgl/style/layers/fill_layer_impl.hpp>
#include <mapbox/earcut.hpp>
@@ -26,7 +27,17 @@ using namespace style;
struct GeometryTooLongException : std::exception {};
-void FillBucket::addGeometry(const GeometryCollection& geometry) {
+FillBucket::FillBucket(const BucketParameters& parameters, const std::vector<const Layer*>& layers) {
+ for (const auto& layer : layers) {
+ paintPropertyBinders.emplace(layer->getID(),
+ FillProgram::PaintPropertyBinders(
+ layer->as<FillLayer>()->impl->paint.evaluated,
+ parameters.tileID.overscaledZ));
+ }
+}
+
+void FillBucket::addFeature(const GeometryTileFeature& feature,
+ const GeometryCollection& geometry) {
for (auto& polygon : classifyRings(geometry)) {
// Optimize polygons with many interior rings for earcut tesselation.
limitHoles(polygon, 500);
@@ -55,11 +66,11 @@ void FillBucket::addGeometry(const GeometryCollection& geometry) {
assert(lineSegment.vertexLength <= std::numeric_limits<uint16_t>::max());
uint16_t lineIndex = lineSegment.vertexLength;
- vertices.emplace_back(FillAttributes::vertex(ring[0]));
+ vertices.emplace_back(FillProgram::layoutVertex(ring[0]));
lines.emplace_back(lineIndex + nVertices - 1, lineIndex);
for (uint32_t i = 1; i < nVertices; i++) {
- vertices.emplace_back(FillAttributes::vertex(ring[i]));
+ vertices.emplace_back(FillProgram::layoutVertex(ring[i]));
lines.emplace_back(lineIndex + i - 1, lineIndex + i);
}
@@ -89,6 +100,10 @@ void FillBucket::addGeometry(const GeometryCollection& geometry) {
triangleSegment.vertexLength += totalVertices;
triangleSegment.indexLength += nIndicies;
}
+
+ for (auto& pair : paintPropertyBinders) {
+ pair.second.populateVertexVectors(feature, vertices.vertexSize());
+ }
}
void FillBucket::upload(gl::Context& context) {
@@ -96,7 +111,10 @@ void FillBucket::upload(gl::Context& context) {
lineIndexBuffer = context.createIndexBuffer(std::move(lines));
triangleIndexBuffer = context.createIndexBuffer(std::move(triangles));
- // From now on, we're going to render during the opaque and translucent pass.
+ for (auto& pair : paintPropertyBinders) {
+ pair.second.upload(context);
+ }
+
uploaded = true;
}
diff --git a/src/mbgl/renderer/fill_bucket.hpp b/src/mbgl/renderer/fill_bucket.hpp
index edb1521c1d..b403e1053b 100644
--- a/src/mbgl/renderer/fill_bucket.hpp
+++ b/src/mbgl/renderer/fill_bucket.hpp
@@ -6,28 +6,38 @@
#include <mbgl/gl/index_buffer.hpp>
#include <mbgl/gl/segment.hpp>
#include <mbgl/programs/fill_program.hpp>
+#include <mbgl/style/layers/fill_layer_properties.hpp>
#include <vector>
namespace mbgl {
+namespace style {
+class BucketParameters;
+} // namespace style
+
class FillBucket : public Bucket {
public:
- void upload(gl::Context&) override;
- void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override;
+ FillBucket(const style::BucketParameters&, const std::vector<const style::Layer*>&);
+
+ void addFeature(const GeometryTileFeature&,
+ const GeometryCollection&) override;
bool hasData() const override;
- void addGeometry(const GeometryCollection&);
+ void upload(gl::Context&) override;
+ void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override;
- gl::VertexVector<FillVertex> vertices;
+ gl::VertexVector<FillLayoutVertex> 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::VertexBuffer<FillLayoutVertex>> vertexBuffer;
optional<gl::IndexBuffer<gl::Lines>> lineIndexBuffer;
optional<gl::IndexBuffer<gl::Triangles>> triangleIndexBuffer;
+
+ std::unordered_map<std::string, FillProgram::PaintPropertyBinders> paintPropertyBinders;
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/frame_history.cpp b/src/mbgl/renderer/frame_history.cpp
index 1ee53d87b2..a933a9004a 100644
--- a/src/mbgl/renderer/frame_history.cpp
+++ b/src/mbgl/renderer/frame_history.cpp
@@ -8,7 +8,7 @@ namespace mbgl {
FrameHistory::FrameHistory() {
changeOpacities.fill(0);
- std::fill(opacities.data.get(), opacities.data.get() + opacities.bytes(), 0);
+ opacities.fill(0);
}
void FrameHistory::record(const TimePoint& now, float zoom, const Duration& duration) {
diff --git a/src/mbgl/renderer/frame_history.hpp b/src/mbgl/renderer/frame_history.hpp
index fffbd113ed..f2b11f5f41 100644
--- a/src/mbgl/renderer/frame_history.hpp
+++ b/src/mbgl/renderer/frame_history.hpp
@@ -26,7 +26,7 @@ public:
private:
std::array<TimePoint, 256> changeTimes;
std::array<uint8_t, 256> changeOpacities;
- const AlphaImage opacities{ { 256, 1 } };
+ AlphaImage opacities{ { 256, 1 } };
int16_t previousZoomIndex = 0;
TimePoint previousTime;
diff --git a/src/mbgl/renderer/line_bucket.cpp b/src/mbgl/renderer/line_bucket.cpp
index 007060bd1b..50a70c0fd4 100644
--- a/src/mbgl/renderer/line_bucket.cpp
+++ b/src/mbgl/renderer/line_bucket.cpp
@@ -1,6 +1,8 @@
#include <mbgl/renderer/line_bucket.hpp>
-#include <mbgl/style/layers/line_layer.hpp>
#include <mbgl/renderer/painter.hpp>
+#include <mbgl/style/layers/line_layer.hpp>
+#include <mbgl/style/bucket_parameters.hpp>
+#include <mbgl/style/layers/line_layer_impl.hpp>
#include <mbgl/util/math.hpp>
#include <mbgl/util/constants.hpp>
@@ -10,19 +12,29 @@ namespace mbgl {
using namespace style;
-LineBucket::LineBucket(uint32_t overscaling_) : overscaling(overscaling_) {
-}
-
-LineBucket::~LineBucket() {
- // Do not remove. header file only contains forward definitions to unique pointers.
+LineBucket::LineBucket(const BucketParameters& parameters,
+ const std::vector<const Layer*>& layers,
+ const style::LineLayoutProperties& layout_)
+ : layout(layout_.evaluate(PropertyEvaluationParameters(parameters.tileID.overscaledZ))),
+ overscaling(parameters.tileID.overscaleFactor()) {
+ for (const auto& layer : layers) {
+ paintPropertyBinders.emplace(layer->getID(),
+ LineProgram::PaintPropertyBinders(
+ layer->as<LineLayer>()->impl->paint.evaluated,
+ parameters.tileID.overscaledZ));
+ }
}
-void LineBucket::addGeometry(const GeometryCollection& geometryCollection) {
+void LineBucket::addFeature(const GeometryTileFeature& feature,
+ const GeometryCollection& geometryCollection) {
for (auto& line : geometryCollection) {
addGeometry(line);
}
-}
+ for (auto& pair : paintPropertyBinders) {
+ pair.second.populateVertexVectors(feature, vertices.vertexSize());
+ }
+}
/*
* Sharp corners cause dashed lines to tilt because the distance along the line
@@ -139,7 +151,14 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates) {
// Determine the normal of the join extrusion. It is the angle bisector
// of the segments between the previous line and the next line.
- Point<double> joinNormal = util::unit(*prevNormal + *nextNormal);
+ // In the case of 180° angles, the prev and next normals cancel each other out:
+ // prevNormal + nextNormal = (0, 0), its magnitude is 0, so the unit vector would be
+ // undefined. In that case, we're keeping the joinNormal at (0, 0), so that the cosHalfAngle
+ // below will also become 0 and miterLength will become Infinity.
+ Point<double> joinNormal = *prevNormal + *nextNormal;
+ if (joinNormal.x != 0 || joinNormal.y != 0) {
+ joinNormal = util::unit(joinNormal);
+ }
/* joinNormal prevNormal
* ↖ ↑
@@ -155,7 +174,8 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates) {
// Find the cosine of the angle between the next and join normals
// using dot product. The inverse of that is the miter length.
const double cosHalfAngle = joinNormal.x * nextNormal->x + joinNormal.y * nextNormal->y;
- const double miterLength = cosHalfAngle != 0 ? 1 / cosHalfAngle: 1;
+ const double miterLength =
+ cosHalfAngle != 0 ? 1 / cosHalfAngle : std::numeric_limits<double>::infinity();
const bool isSharpCorner = cosHalfAngle < COS_HALF_SHARP_CORNER && prevCoordinate && nextCoordinate;
@@ -189,7 +209,7 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates) {
if (currentJoin == LineJoinType::Bevel) {
// The maximum extrude length is 128 / 63 = 2 times the width of the line
- // so if miterLength >= 2 we need to draw a different type of bevel where.
+ // so if miterLength >= 2 we need to draw a different type of bevel here.
if (miterLength > 2) {
currentJoin = LineJoinType::FlipBevel;
}
@@ -216,7 +236,7 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates) {
if (miterLength > 100) {
// Almost parallel lines
- joinNormal = *nextNormal;
+ joinNormal = *nextNormal * -1.0;
} else {
const double direction = prevNormal->x * nextNormal->y - prevNormal->y * nextNormal->x > 0 ? -1 : 1;
const double bevelLength = miterLength * util::mag(*prevNormal + *nextNormal) /
@@ -375,7 +395,7 @@ void LineBucket::addCurrentVertex(const GeometryCoordinate& currentCoordinate,
Point<double> extrude = normal;
if (endLeft)
extrude = extrude - (util::perp(normal) * endLeft);
- vertices.emplace_back(LineAttributes::vertex(currentCoordinate, extrude, { round, false }, endLeft, distance * LINE_DISTANCE_SCALE));
+ vertices.emplace_back(LineProgram::layoutVertex(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);
@@ -386,7 +406,7 @@ void LineBucket::addCurrentVertex(const GeometryCoordinate& currentCoordinate,
extrude = normal * -1.0;
if (endRight)
extrude = extrude - (util::perp(normal) * endRight);
- vertices.emplace_back(LineAttributes::vertex(currentCoordinate, extrude, { round, true }, -endRight, distance * LINE_DISTANCE_SCALE));
+ vertices.emplace_back(LineProgram::layoutVertex(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);
@@ -411,7 +431,7 @@ void LineBucket::addPieSliceVertex(const GeometryCoordinate& currentVertex,
std::size_t startVertex,
std::vector<TriangleElement>& triangleStore) {
Point<double> flippedExtrude = extrude * (lineTurnsLeft ? -1.0 : 1.0);
- vertices.emplace_back(LineAttributes::vertex(currentVertex, flippedExtrude, { false, lineTurnsLeft }, 0, distance * LINE_DISTANCE_SCALE));
+ vertices.emplace_back(LineProgram::layoutVertex(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);
@@ -428,7 +448,10 @@ void LineBucket::upload(gl::Context& context) {
vertexBuffer = context.createVertexBuffer(std::move(vertices));
indexBuffer = context.createIndexBuffer(std::move(triangles));
- // From now on, we're only going to render during the translucent pass.
+ for (auto& pair : paintPropertyBinders) {
+ pair.second.upload(context);
+ }
+
uploaded = true;
}
diff --git a/src/mbgl/renderer/line_bucket.hpp b/src/mbgl/renderer/line_bucket.hpp
index d11d78ff69..78293d75f9 100644
--- a/src/mbgl/renderer/line_bucket.hpp
+++ b/src/mbgl/renderer/line_bucket.hpp
@@ -12,28 +12,37 @@
namespace mbgl {
+namespace style {
+class BucketParameters;
+} // namespace style
+
class LineBucket : public Bucket {
public:
- LineBucket(uint32_t overscaling);
- ~LineBucket() override;
+ LineBucket(const style::BucketParameters&,
+ const std::vector<const style::Layer*>&,
+ const style::LineLayoutProperties&);
- void upload(gl::Context&) override;
- void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override;
+ void addFeature(const GeometryTileFeature&,
+ const GeometryCollection&) override;
bool hasData() const override;
- void addGeometry(const GeometryCollection&);
- void addGeometry(const GeometryCoordinates& line);
+ void upload(gl::Context&) override;
+ void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override;
style::LineLayoutProperties::Evaluated layout;
- gl::VertexVector<LineVertex> vertices;
+ gl::VertexVector<LineLayoutVertex> vertices;
gl::IndexVector<gl::Triangles> triangles;
gl::SegmentVector<LineAttributes> segments;
- optional<gl::VertexBuffer<LineVertex>> vertexBuffer;
+ optional<gl::VertexBuffer<LineLayoutVertex>> vertexBuffer;
optional<gl::IndexBuffer<gl::Triangles>> indexBuffer;
+ std::unordered_map<std::string, LineProgram::PaintPropertyBinders> paintPropertyBinders;
+
private:
+ void addGeometry(const GeometryCoordinates& line);
+
struct TriangleElement {
TriangleElement(uint16_t a_, uint16_t b_, uint16_t c_) : a(a_), b(b_), c(c_) {}
uint16_t a, b, c;
diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp
index 505007304d..27d24d14a9 100644
--- a/src/mbgl/renderer/painter.cpp
+++ b/src/mbgl/renderer/painter.cpp
@@ -42,12 +42,12 @@ namespace mbgl {
using namespace style;
-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 }));
+static gl::VertexVector<FillLayoutVertex> tileVertices() {
+ gl::VertexVector<FillLayoutVertex> result;
+ result.emplace_back(FillProgram::layoutVertex({ 0, 0 }));
+ result.emplace_back(FillProgram::layoutVertex({ util::EXTENT, 0 }));
+ result.emplace_back(FillProgram::layoutVertex({ 0, util::EXTENT }));
+ result.emplace_back(FillProgram::layoutVertex({ util::EXTENT, util::EXTENT }));
return result;
}
@@ -68,12 +68,12 @@ static gl::IndexVector<gl::LineStrip> tileLineStripIndices() {
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 }));
+static gl::VertexVector<RasterLayoutVertex> rasterVertices() {
+ gl::VertexVector<RasterLayoutVertex> result;
+ result.emplace_back(RasterProgram::layoutVertex({ 0, 0 }, { 0, 0 }));
+ result.emplace_back(RasterProgram::layoutVertex({ util::EXTENT, 0 }, { 32767, 0 }));
+ result.emplace_back(RasterProgram::layoutVertex({ 0, util::EXTENT }, { 0, 32767 }));
+ result.emplace_back(RasterProgram::layoutVertex({ util::EXTENT, util::EXTENT }, { 32767, 32767 }));
return result;
}
@@ -94,7 +94,7 @@ Painter::Painter(gl::Context& context_, const TransformState& state_, float pixe
ProgramParameters programParameters{ pixelRatio, false };
programs = std::make_unique<Programs>(context, programParameters);
#ifndef NDEBUG
-
+
ProgramParameters programParametersOverdraw{ pixelRatio, true };
overdrawPrograms = std::make_unique<Programs>(context, programParametersOverdraw);
#endif
diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp
index dec7fa57fd..91f329a6eb 100644
--- a/src/mbgl/renderer/painter.hpp
+++ b/src/mbgl/renderer/painter.hpp
@@ -158,8 +158,8 @@ private:
std::unique_ptr<Programs> overdrawPrograms;
#endif
- gl::VertexBuffer<FillVertex> tileVertexBuffer;
- gl::VertexBuffer<RasterVertex> rasterVertexBuffer;
+ gl::VertexBuffer<FillLayoutVertex> tileVertexBuffer;
+ gl::VertexBuffer<RasterLayoutVertex> rasterVertexBuffer;
gl::IndexBuffer<gl::Triangles> tileTriangleIndexBuffer;
gl::IndexBuffer<gl::LineStrip> tileBorderIndexBuffer;
diff --git a/src/mbgl/renderer/painter_background.cpp b/src/mbgl/renderer/painter_background.cpp
index 4a3e41701d..4ac414335b 100644
--- a/src/mbgl/renderer/painter_background.cpp
+++ b/src/mbgl/renderer/painter_background.cpp
@@ -14,13 +14,18 @@ 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::Evaluated& properties = layer.impl->paint.evaluated;
+ const BackgroundPaintProperties::Evaluated& background = layer.impl->paint.evaluated;
- 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);
+ style::FillPaintProperties::Evaluated properties;
+ properties.get<FillPattern>() = background.get<BackgroundPattern>();
+ properties.get<FillOpacity>() = { background.get<BackgroundOpacity>() };
+ properties.get<FillColor>() = { background.get<BackgroundColor>() };
+
+ const FillProgram::PaintPropertyBinders paintAttibuteData(properties, 0);
+
+ if (!background.get<BackgroundPattern>().to.empty()) {
+ optional<SpriteAtlasElement> imagePosA = spriteAtlas->getPattern(background.get<BackgroundPattern>().from);
+ optional<SpriteAtlasElement> imagePosB = spriteAtlas->getPattern(background.get<BackgroundPattern>().to);
if (!imagePosA || !imagePosB)
return;
@@ -36,17 +41,19 @@ void Painter::renderBackground(PaintParameters& parameters, const BackgroundLaye
colorModeForRenderPass(),
FillPatternUniforms::values(
matrixForTile(tileID),
- properties.get<BackgroundOpacity>(),
context.viewport.getCurrentValue().size,
*imagePosA,
*imagePosB,
- properties.get<BackgroundPattern>(),
+ background.get<BackgroundPattern>(),
tileID,
state
),
tileVertexBuffer,
tileTriangleIndexBuffer,
- tileTriangleSegments
+ tileTriangleSegments,
+ paintAttibuteData,
+ properties,
+ state.getZoom()
);
}
} else {
@@ -59,14 +66,14 @@ void Painter::renderBackground(PaintParameters& parameters, const BackgroundLaye
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
+ tileTriangleSegments,
+ paintAttibuteData,
+ properties,
+ state.getZoom()
);
}
}
diff --git a/src/mbgl/renderer/painter_circle.cpp b/src/mbgl/renderer/painter_circle.cpp
index 966d58b59b..8d47e75f71 100644
--- a/src/mbgl/renderer/painter_circle.cpp
+++ b/src/mbgl/renderer/painter_circle.cpp
@@ -37,13 +37,6 @@ void Painter::renderCircle(PaintParameters& parameters,
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> {{
@@ -54,7 +47,10 @@ void Painter::renderCircle(PaintParameters& parameters,
},
*bucket.vertexBuffer,
*bucket.indexBuffer,
- bucket.segments
+ bucket.segments,
+ bucket.paintPropertyBinders.at(layer.getID()),
+ properties,
+ state.getZoom()
);
}
diff --git a/src/mbgl/renderer/painter_clipping.cpp b/src/mbgl/renderer/painter_clipping.cpp
index a2529561fe..70df9837e8 100644
--- a/src/mbgl/renderer/painter_clipping.cpp
+++ b/src/mbgl/renderer/painter_clipping.cpp
@@ -6,6 +6,8 @@
namespace mbgl {
void Painter::renderClippingMask(const UnwrappedTileID& tileID, const ClipID& clip) {
+ static const style::FillPaintProperties::Evaluated properties {};
+ static const FillProgram::PaintPropertyBinders paintAttibuteData(properties, 0);
programs->fill.draw(
context,
gl::Triangles(),
@@ -21,14 +23,14 @@ void Painter::renderClippingMask(const UnwrappedTileID& tileID, const ClipID& cl
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
+ tileTriangleSegments,
+ paintAttibuteData,
+ properties,
+ state.getZoom()
);
}
diff --git a/src/mbgl/renderer/painter_debug.cpp b/src/mbgl/renderer/painter_debug.cpp
index 2b838dec0e..5b347884bf 100644
--- a/src/mbgl/renderer/painter_debug.cpp
+++ b/src/mbgl/renderer/painter_debug.cpp
@@ -12,12 +12,17 @@
namespace mbgl {
+using namespace style;
+
void Painter::renderTileDebug(const RenderTile& renderTile) {
if (frame.debugOptions == MapDebugOptions::NoDebug)
return;
MBGL_DEBUG_GROUP(std::string { "debug " } + util::toString(renderTile.id));
+ static const style::PaintProperties<>::Evaluated properties {};
+ static const DebugProgram::PaintPropertyBinders paintAttibuteData(properties, 0);
+
auto draw = [&] (Color color, const auto& vertexBuffer, const auto& indexBuffer, const auto& segments, auto drawMode) {
programs->debug.draw(
context,
@@ -31,7 +36,10 @@ void Painter::renderTileDebug(const RenderTile& renderTile) {
},
vertexBuffer,
indexBuffer,
- segments
+ segments,
+ paintAttibuteData,
+ properties,
+ state.getZoom()
);
};
diff --git a/src/mbgl/renderer/painter_fill.cpp b/src/mbgl/renderer/painter_fill.cpp
index 356ccfc0b2..4276bd06ed 100644
--- a/src/mbgl/renderer/painter_fill.cpp
+++ b/src/mbgl/renderer/painter_fill.cpp
@@ -24,10 +24,8 @@ void Painter::renderFill(PaintParameters& parameters,
return;
}
- optional<SpriteAtlasPosition> imagePosA = spriteAtlas->getPosition(
- properties.get<FillPattern>().from, SpritePatternMode::Repeating);
- optional<SpriteAtlasPosition> imagePosB = spriteAtlas->getPosition(
- properties.get<FillPattern>().to, SpritePatternMode::Repeating);
+ optional<SpriteAtlasElement> imagePosA = spriteAtlas->getPattern(properties.get<FillPattern>().from);
+ optional<SpriteAtlasElement> imagePosB = spriteAtlas->getPattern(properties.get<FillPattern>().to);
if (!imagePosA || !imagePosB) {
return;
@@ -38,7 +36,6 @@ void Painter::renderFill(PaintParameters& parameters,
auto draw = [&] (uint8_t sublayer,
auto& program,
const auto& drawMode,
- const auto& vertexBuffer,
const auto& indexBuffer,
const auto& segments) {
program.draw(
@@ -51,7 +48,6 @@ void Painter::renderFill(PaintParameters& parameters,
tile.translatedMatrix(properties.get<FillTranslate>(),
properties.get<FillTranslateAnchor>(),
state),
- properties.get<FillOpacity>(),
context.viewport.getCurrentValue().size,
*imagePosA,
*imagePosB,
@@ -59,16 +55,18 @@ void Painter::renderFill(PaintParameters& parameters,
tile.id,
state
),
- vertexBuffer,
+ *bucket.vertexBuffer,
indexBuffer,
- segments
+ segments,
+ bucket.paintPropertyBinders.at(layer.getID()),
+ properties,
+ state.getZoom()
);
};
draw(0,
parameters.programs.fillPattern,
gl::Triangles(),
- *bucket.vertexBuffer,
*bucket.triangleIndexBuffer,
bucket.triangleSegments);
@@ -79,15 +77,12 @@ void Painter::renderFill(PaintParameters& parameters,
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(
@@ -97,38 +92,37 @@ void Painter::renderFill(PaintParameters& parameters,
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_matrix::Value{
+ tile.translatedMatrix(properties.get<FillTranslate>(),
+ properties.get<FillTranslateAnchor>(),
+ state)
+ },
uniforms::u_world::Value{ context.viewport.getCurrentValue().size },
},
- vertexBuffer,
+ *bucket.vertexBuffer,
indexBuffer,
- segments
+ segments,
+ bucket.paintPropertyBinders.at(layer.getID()),
+ properties,
+ state.getZoom()
);
};
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);
}
// 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)) {
+ if ((properties.get<FillColor>().constantOr(Color()).a >= 1.0f
+ && properties.get<FillOpacity>().constantOr(0) >= 1.0f) == (pass == RenderPass::Opaque)) {
draw(1,
parameters.programs.fill,
- properties.get<FillOutlineColor>(),
gl::Triangles(),
- *bucket.vertexBuffer,
*bucket.triangleIndexBuffer,
bucket.triangleSegments);
}
@@ -136,9 +130,7 @@ void Painter::renderFill(PaintParameters& parameters,
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 012746d2f2..4e19f841b1 100644
--- a/src/mbgl/renderer/painter_line.cpp
+++ b/src/mbgl/renderer/painter_line.cpp
@@ -33,7 +33,10 @@ void Painter::renderLine(PaintParameters& parameters,
std::move(uniformValues),
*bucket.vertexBuffer,
*bucket.indexBuffer,
- bucket.segments
+ bucket.segments,
+ bucket.paintPropertyBinders.at(layer.getID()),
+ properties,
+ state.getZoom()
);
};
@@ -58,10 +61,8 @@ void Painter::renderLine(PaintParameters& parameters,
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);
+ optional<SpriteAtlasElement> posA = spriteAtlas->getPattern(properties.get<LinePattern>().from);
+ optional<SpriteAtlasElement> posB = spriteAtlas->getPattern(properties.get<LinePattern>().to);
if (!posA || !posB)
return;
diff --git a/src/mbgl/renderer/painter_raster.cpp b/src/mbgl/renderer/painter_raster.cpp
index dcf2644140..c216955db8 100644
--- a/src/mbgl/renderer/painter_raster.cpp
+++ b/src/mbgl/renderer/painter_raster.cpp
@@ -49,6 +49,7 @@ void Painter::renderRaster(PaintParameters& parameters,
return;
const RasterPaintProperties::Evaluated& properties = layer.impl->paint.evaluated;
+ const RasterProgram::PaintPropertyBinders paintAttributeData(properties, 0);
assert(bucket.texture);
context.bindTexture(*bucket.texture, 0, gl::TextureFilter::Linear);
@@ -77,7 +78,10 @@ void Painter::renderRaster(PaintParameters& parameters,
},
rasterVertexBuffer,
tileTriangleIndexBuffer,
- rasterSegments
+ rasterSegments,
+ paintAttributeData,
+ properties,
+ state.getZoom()
);
}
diff --git a/src/mbgl/renderer/painter_symbol.cpp b/src/mbgl/renderer/painter_symbol.cpp
index 39075976a0..48c2e7ff66 100644
--- a/src/mbgl/renderer/painter_symbol.cpp
+++ b/src/mbgl/renderer/painter_symbol.cpp
@@ -33,7 +33,9 @@ void Painter::renderSymbol(PaintParameters& parameters,
auto draw = [&] (auto& program,
auto&& uniformValues,
const auto& buffers,
- const SymbolPropertyValues& values_)
+ const SymbolPropertyValues& values_,
+ const auto& binders,
+ const auto& paintProperties)
{
// We clip symbols to their tile extent in still mode.
const bool needsClipping = frame.mapMode == MapMode::Still;
@@ -51,12 +53,16 @@ void Painter::renderSymbol(PaintParameters& parameters,
std::move(uniformValues),
*buffers.vertexBuffer,
*buffers.indexBuffer,
- buffers.segments
+ buffers.segments,
+ binders,
+ paintProperties,
+ state.getZoom()
);
};
if (bucket.hasIconData()) {
auto values = layer.impl->iconPropertyValues(layout);
+ auto paintPropertyValues = layer.impl->iconPaintProperties();
SpriteAtlas& atlas = *layer.impl->spriteAtlas;
const bool iconScaled = values.paintSize != 1.0f || frame.pixelRatio != atlas.getPixelRatio() || bucket.iconsNeedLinear;
@@ -66,24 +72,30 @@ void Painter::renderSymbol(PaintParameters& parameters,
const Size texsize = atlas.getSize();
if (bucket.sdfIcons) {
- if (values.hasHalo()) {
+ if (values.hasHalo) {
draw(parameters.programs.symbolIconSDF,
- SymbolSDFProgram::haloUniformValues(values, texsize, pixelsToGLUnits, tile, state, frame.pixelRatio),
+ SymbolSDFIconProgram::uniformValues(values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Halo),
bucket.icon,
- values);
+ values,
+ bucket.paintPropertyBinders.at(layer.getID()).first,
+ paintPropertyValues);
}
- if (values.hasForeground()) {
+ if (values.hasFill) {
draw(parameters.programs.symbolIconSDF,
- SymbolSDFProgram::foregroundUniformValues(values, texsize, pixelsToGLUnits, tile, state, frame.pixelRatio),
+ SymbolSDFIconProgram::uniformValues(values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Fill),
bucket.icon,
- values);
+ values,
+ bucket.paintPropertyBinders.at(layer.getID()).first,
+ paintPropertyValues);
}
} else {
draw(parameters.programs.symbolIcon,
SymbolIconProgram::uniformValues(values, texsize, pixelsToGLUnits, tile, state),
bucket.icon,
- values);
+ values,
+ bucket.paintPropertyBinders.at(layer.getID()).first,
+ paintPropertyValues);
}
}
@@ -91,25 +103,33 @@ void Painter::renderSymbol(PaintParameters& parameters,
glyphAtlas->bind(context, 0);
auto values = layer.impl->textPropertyValues(layout);
+ auto paintPropertyValues = layer.impl->textPaintProperties();
const Size texsize = glyphAtlas->getSize();
- if (values.hasHalo()) {
+ if (values.hasHalo) {
draw(parameters.programs.symbolGlyph,
- SymbolSDFProgram::haloUniformValues(values, texsize, pixelsToGLUnits, tile, state, frame.pixelRatio),
+ SymbolSDFTextProgram::uniformValues(values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Halo),
bucket.text,
- values);
+ values,
+ bucket.paintPropertyBinders.at(layer.getID()).second,
+ paintPropertyValues);
}
- if (values.hasForeground()) {
+ if (values.hasFill) {
draw(parameters.programs.symbolGlyph,
- SymbolSDFProgram::foregroundUniformValues(values, texsize, pixelsToGLUnits, tile, state, frame.pixelRatio),
+ SymbolSDFTextProgram::uniformValues(values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Fill),
bucket.text,
- values);
+ values,
+ bucket.paintPropertyBinders.at(layer.getID()).second,
+ paintPropertyValues);
}
}
if (bucket.hasCollisionBoxData()) {
+ static const style::PaintProperties<>::Evaluated properties {};
+ static const CollisionBoxProgram::PaintPropertyBinders paintAttributeData(properties, 0);
+
programs->collisionBox.draw(
context,
gl::Lines { 1.0f },
@@ -124,7 +144,10 @@ void Painter::renderSymbol(PaintParameters& parameters,
},
*bucket.collisionBox.vertexBuffer,
*bucket.collisionBox.indexBuffer,
- bucket.collisionBox.segments
+ bucket.collisionBox.segments,
+ paintAttributeData,
+ properties,
+ state.getZoom()
);
}
}
diff --git a/src/mbgl/renderer/symbol_bucket.cpp b/src/mbgl/renderer/symbol_bucket.cpp
index 0f2c89339f..fa4178dda1 100644
--- a/src/mbgl/renderer/symbol_bucket.cpp
+++ b/src/mbgl/renderer/symbol_bucket.cpp
@@ -1,19 +1,28 @@
#include <mbgl/renderer/symbol_bucket.hpp>
#include <mbgl/renderer/painter.hpp>
+#include <mbgl/style/bucket_parameters.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
+#include <mbgl/style/layers/symbol_layer_impl.hpp>
namespace mbgl {
using namespace style;
-SymbolBucket::SymbolBucket(const MapMode mode_,
- style::SymbolLayoutProperties::Evaluated layout_,
+SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::Evaluated layout_,
+ const std::unordered_map<std::string, std::pair<
+ style::IconPaintProperties::Evaluated, style::TextPaintProperties::Evaluated>>& layerPaintProperties,
+ float zoom,
bool sdfIcons_,
bool iconsNeedLinear_)
- : mode(mode_),
- layout(std::move(layout_)),
+ : layout(std::move(layout_)),
sdfIcons(sdfIcons_),
iconsNeedLinear(iconsNeedLinear_) {
+ for (const auto& pair : layerPaintProperties) {
+ paintPropertyBinders.emplace(pair.first, std::make_pair(
+ SymbolIconProgram::PaintPropertyBinders(pair.second.first, zoom),
+ SymbolSDFTextProgram::PaintPropertyBinders(pair.second.second, zoom)
+ ));
+ }
}
void SymbolBucket::upload(gl::Context& context) {
@@ -32,6 +41,11 @@ void SymbolBucket::upload(gl::Context& context) {
collisionBox.indexBuffer = context.createIndexBuffer(std::move(collisionBox.lines));
}
+ for (auto& pair : paintPropertyBinders) {
+ pair.second.first.upload(context);
+ pair.second.second.upload(context);
+ }
+
uploaded = true;
}
diff --git a/src/mbgl/renderer/symbol_bucket.hpp b/src/mbgl/renderer/symbol_bucket.hpp
index d62a61aab7..dcf3f5f495 100644
--- a/src/mbgl/renderer/symbol_bucket.hpp
+++ b/src/mbgl/renderer/symbol_bucket.hpp
@@ -16,8 +16,9 @@ namespace mbgl {
class SymbolBucket : public Bucket {
public:
- SymbolBucket(const MapMode,
- style::SymbolLayoutProperties::Evaluated,
+ SymbolBucket(style::SymbolLayoutProperties::Evaluated,
+ const std::unordered_map<std::string, std::pair<style::IconPaintProperties::Evaluated, style::TextPaintProperties::Evaluated>>&,
+ float zoom,
bool sdfIcons,
bool iconsNeedLinear);
@@ -28,26 +29,29 @@ public:
bool hasIconData() const;
bool hasCollisionBoxData() const;
- const MapMode mode;
const style::SymbolLayoutProperties::Evaluated layout;
const bool sdfIcons;
const bool iconsNeedLinear;
+ std::unordered_map<std::string, std::pair<
+ SymbolIconProgram::PaintPropertyBinders,
+ SymbolSDFTextProgram::PaintPropertyBinders>> paintPropertyBinders;
+
struct TextBuffer {
- gl::VertexVector<SymbolVertex> vertices;
+ gl::VertexVector<SymbolLayoutVertex> vertices;
gl::IndexVector<gl::Triangles> triangles;
- gl::SegmentVector<SymbolAttributes> segments;
+ gl::SegmentVector<SymbolTextAttributes> segments;
- optional<gl::VertexBuffer<SymbolVertex>> vertexBuffer;
+ optional<gl::VertexBuffer<SymbolLayoutVertex>> vertexBuffer;
optional<gl::IndexBuffer<gl::Triangles>> indexBuffer;
} text;
struct IconBuffer {
- gl::VertexVector<SymbolVertex> vertices;
+ gl::VertexVector<SymbolLayoutVertex> vertices;
gl::IndexVector<gl::Triangles> triangles;
- gl::SegmentVector<SymbolAttributes> segments;
+ gl::SegmentVector<SymbolIconAttributes> segments;
- optional<gl::VertexBuffer<SymbolVertex>> vertexBuffer;
+ optional<gl::VertexBuffer<SymbolLayoutVertex>> vertexBuffer;
optional<gl::IndexBuffer<gl::Triangles>> indexBuffer;
} icon;
diff --git a/src/mbgl/shaders/circle.cpp b/src/mbgl/shaders/circle.cpp
new file mode 100644
index 0000000000..592a883fb3
--- /dev/null
+++ b/src/mbgl/shaders/circle.cpp
@@ -0,0 +1,191 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/circle.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* circle::name = "circle";
+const char* circle::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+uniform mat4 u_matrix;
+uniform bool u_scale_with_map;
+uniform vec2 u_extrude_scale;
+
+attribute vec2 a_pos;
+
+uniform lowp float a_color_t;
+attribute lowp vec4 a_color_min;
+attribute lowp vec4 a_color_max;
+varying lowp vec4 color;
+uniform lowp float a_radius_t;
+attribute mediump float a_radius_min;
+attribute mediump float a_radius_max;
+varying mediump float radius;
+uniform lowp float a_blur_t;
+attribute lowp float a_blur_min;
+attribute lowp float a_blur_max;
+varying lowp float blur;
+uniform lowp float a_opacity_t;
+attribute lowp float a_opacity_min;
+attribute lowp float a_opacity_max;
+varying lowp float opacity;
+uniform lowp float a_stroke_color_t;
+attribute lowp vec4 a_stroke_color_min;
+attribute lowp vec4 a_stroke_color_max;
+varying lowp vec4 stroke_color;
+uniform lowp float a_stroke_width_t;
+attribute mediump float a_stroke_width_min;
+attribute mediump float a_stroke_width_max;
+varying mediump float stroke_width;
+uniform lowp float a_stroke_opacity_t;
+attribute lowp float a_stroke_opacity_min;
+attribute lowp float a_stroke_opacity_max;
+varying lowp float stroke_opacity;
+
+varying vec2 v_extrude;
+varying lowp float v_antialiasblur;
+
+void main(void) {
+ color = mix(a_color_min, a_color_max, a_color_t);
+ radius = mix(a_radius_min, a_radius_max, a_radius_t);
+ blur = mix(a_blur_min, a_blur_max, a_blur_t);
+ opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
+ stroke_color = mix(a_stroke_color_min, a_stroke_color_max, a_stroke_color_t);
+ stroke_width = mix(a_stroke_width_min, a_stroke_width_max, a_stroke_width_t);
+ stroke_opacity = mix(a_stroke_opacity_min, a_stroke_opacity_max, a_stroke_opacity_t);
+
+ // unencode the extrusion vector that we snuck into the a_pos vector
+ v_extrude = vec2(mod(a_pos, 2.0) * 2.0 - 1.0);
+
+ vec2 extrude = v_extrude * (radius + stroke_width) * u_extrude_scale;
+ // multiply a_pos by 0.5, since we had it * 2 in order to sneak
+ // in extrusion data
+ gl_Position = u_matrix * vec4(floor(a_pos * 0.5), 0, 1);
+
+ if (u_scale_with_map) {
+ gl_Position.xy += extrude;
+ } else {
+ gl_Position.xy += extrude * gl_Position.w;
+ }
+
+ // This is a minimum blur distance that serves as a faux-antialiasing for
+ // the circle. since blur is a ratio of the circle's size and the intent is
+ // to keep the blur at roughly 1px, the two are inversely related.
+ v_antialiasblur = 1.0 / DEVICE_PIXEL_RATIO / (radius + stroke_width);
+}
+
+)MBGL_SHADER";
+const char* circle::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+varying lowp vec4 color;
+varying mediump float radius;
+varying lowp float blur;
+varying lowp float opacity;
+varying lowp vec4 stroke_color;
+varying mediump float stroke_width;
+varying lowp float stroke_opacity;
+
+varying vec2 v_extrude;
+varying lowp float v_antialiasblur;
+
+void main() {
+
+
+
+
+
+
+
+
+ float extrude_length = length(v_extrude);
+ float antialiased_blur = -max(blur, v_antialiasblur);
+
+ float opacity_t = smoothstep(0.0, antialiased_blur, extrude_length - 1.0);
+
+ float color_t = stroke_width < 0.01 ? 0.0 : smoothstep(
+ antialiased_blur,
+ 0.0,
+ extrude_length - radius / (radius + stroke_width)
+ );
+
+ gl_FragColor = opacity_t * mix(color * opacity, stroke_color * stroke_opacity, color_t);
+
+#ifdef OVERDRAW_INSPECTOR
+ gl_FragColor = vec4(1.0);
+#endif
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/circle.hpp b/src/mbgl/shaders/circle.hpp
new file mode 100644
index 0000000000..d14b26b783
--- /dev/null
+++ b/src/mbgl/shaders/circle.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class circle {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/collision_box.cpp b/src/mbgl/shaders/collision_box.cpp
new file mode 100644
index 0000000000..6f2b9f3824
--- /dev/null
+++ b/src/mbgl/shaders/collision_box.cpp
@@ -0,0 +1,128 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/collision_box.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* collision_box::name = "collision_box";
+const char* collision_box::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+attribute vec2 a_pos;
+attribute vec2 a_extrude;
+attribute vec2 a_data;
+
+uniform mat4 u_matrix;
+uniform float u_scale;
+
+varying float v_max_zoom;
+varying float v_placement_zoom;
+
+void main() {
+ gl_Position = u_matrix * vec4(a_pos + a_extrude / u_scale, 0.0, 1.0);
+
+ v_max_zoom = a_data.x;
+ v_placement_zoom = a_data.y;
+}
+
+)MBGL_SHADER";
+const char* collision_box::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+uniform float u_zoom;
+uniform float u_maxzoom;
+
+varying float v_max_zoom;
+varying float v_placement_zoom;
+
+void main() {
+
+ float alpha = 0.5;
+
+ gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0) * alpha;
+
+ if (v_placement_zoom > u_zoom) {
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0) * alpha;
+ }
+
+ if (u_zoom >= v_max_zoom) {
+ gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0) * alpha * 0.25;
+ }
+
+ if (v_placement_zoom >= u_maxzoom) {
+ gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0) * alpha * 0.2;
+ }
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/collision_box.hpp b/src/mbgl/shaders/collision_box.hpp
new file mode 100644
index 0000000000..e0f70c7968
--- /dev/null
+++ b/src/mbgl/shaders/collision_box.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class collision_box {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/debug.cpp b/src/mbgl/shaders/debug.cpp
new file mode 100644
index 0000000000..2659b2ca79
--- /dev/null
+++ b/src/mbgl/shaders/debug.cpp
@@ -0,0 +1,100 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/debug.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* debug::name = "debug";
+const char* debug::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+attribute vec2 a_pos;
+
+uniform mat4 u_matrix;
+
+void main() {
+ gl_Position = u_matrix * vec4(a_pos, step(32767.0, a_pos.x), 1);
+}
+
+)MBGL_SHADER";
+const char* debug::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+uniform lowp vec4 u_color;
+
+void main() {
+ gl_FragColor = u_color;
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/debug.hpp b/src/mbgl/shaders/debug.hpp
new file mode 100644
index 0000000000..207c7bf075
--- /dev/null
+++ b/src/mbgl/shaders/debug.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class debug {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/fill.cpp b/src/mbgl/shaders/fill.cpp
new file mode 100644
index 0000000000..066adee447
--- /dev/null
+++ b/src/mbgl/shaders/fill.cpp
@@ -0,0 +1,120 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/fill.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* fill::name = "fill";
+const char* fill::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+attribute vec2 a_pos;
+
+uniform mat4 u_matrix;
+
+uniform lowp float a_color_t;
+attribute lowp vec4 a_color_min;
+attribute lowp vec4 a_color_max;
+varying lowp vec4 color;
+uniform lowp float a_opacity_t;
+attribute lowp float a_opacity_min;
+attribute lowp float a_opacity_max;
+varying lowp float opacity;
+
+void main() {
+ color = mix(a_color_min, a_color_max, a_color_t);
+ opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
+
+ gl_Position = u_matrix * vec4(a_pos, 0, 1);
+}
+
+)MBGL_SHADER";
+const char* fill::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+varying lowp vec4 color;
+varying lowp float opacity;
+
+void main() {
+
+
+
+ gl_FragColor = color * opacity;
+
+#ifdef OVERDRAW_INSPECTOR
+ gl_FragColor = vec4(1.0);
+#endif
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/fill.hpp b/src/mbgl/shaders/fill.hpp
new file mode 100644
index 0000000000..29fede7b55
--- /dev/null
+++ b/src/mbgl/shaders/fill.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class fill {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/fill_outline.cpp b/src/mbgl/shaders/fill_outline.cpp
new file mode 100644
index 0000000000..0f0f3806a9
--- /dev/null
+++ b/src/mbgl/shaders/fill_outline.cpp
@@ -0,0 +1,128 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/fill_outline.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* fill_outline::name = "fill_outline";
+const char* fill_outline::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+attribute vec2 a_pos;
+
+uniform mat4 u_matrix;
+uniform vec2 u_world;
+
+varying vec2 v_pos;
+
+uniform lowp float a_outline_color_t;
+attribute lowp vec4 a_outline_color_min;
+attribute lowp vec4 a_outline_color_max;
+varying lowp vec4 outline_color;
+uniform lowp float a_opacity_t;
+attribute lowp float a_opacity_min;
+attribute lowp float a_opacity_max;
+varying lowp float opacity;
+
+void main() {
+ outline_color = mix(a_outline_color_min, a_outline_color_max, a_outline_color_t);
+ opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
+
+ gl_Position = u_matrix * vec4(a_pos, 0, 1);
+ v_pos = (gl_Position.xy / gl_Position.w + 1.0) / 2.0 * u_world;
+}
+
+)MBGL_SHADER";
+const char* fill_outline::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+varying lowp vec4 outline_color;
+varying lowp float opacity;
+
+varying vec2 v_pos;
+
+void main() {
+
+
+
+ float dist = length(v_pos - gl_FragCoord.xy);
+ float alpha = smoothstep(1.0, 0.0, dist);
+ gl_FragColor = outline_color * (alpha * opacity);
+
+#ifdef OVERDRAW_INSPECTOR
+ gl_FragColor = vec4(1.0);
+#endif
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/fill_outline.hpp b/src/mbgl/shaders/fill_outline.hpp
new file mode 100644
index 0000000000..ef685e62fa
--- /dev/null
+++ b/src/mbgl/shaders/fill_outline.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class fill_outline {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/fill_outline_pattern.cpp b/src/mbgl/shaders/fill_outline_pattern.cpp
new file mode 100644
index 0000000000..3921a83e6b
--- /dev/null
+++ b/src/mbgl/shaders/fill_outline_pattern.cpp
@@ -0,0 +1,156 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/fill_outline_pattern.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* fill_outline_pattern::name = "fill_outline_pattern";
+const char* fill_outline_pattern::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+uniform mat4 u_matrix;
+uniform vec2 u_world;
+uniform vec2 u_pattern_size_a;
+uniform vec2 u_pattern_size_b;
+uniform vec2 u_pixel_coord_upper;
+uniform vec2 u_pixel_coord_lower;
+uniform float u_scale_a;
+uniform float u_scale_b;
+uniform float u_tile_units_to_pixels;
+
+attribute vec2 a_pos;
+
+varying vec2 v_pos_a;
+varying vec2 v_pos_b;
+varying vec2 v_pos;
+
+uniform lowp float a_opacity_t;
+attribute lowp float a_opacity_min;
+attribute lowp float a_opacity_max;
+varying lowp float opacity;
+
+void main() {
+ opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
+
+ gl_Position = u_matrix * vec4(a_pos, 0, 1);
+
+ v_pos_a = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_a * u_pattern_size_a, u_tile_units_to_pixels, a_pos);
+ v_pos_b = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_b * u_pattern_size_b, u_tile_units_to_pixels, a_pos);
+
+ v_pos = (gl_Position.xy / gl_Position.w + 1.0) / 2.0 * u_world;
+}
+
+)MBGL_SHADER";
+const char* fill_outline_pattern::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+uniform vec2 u_pattern_tl_a;
+uniform vec2 u_pattern_br_a;
+uniform vec2 u_pattern_tl_b;
+uniform vec2 u_pattern_br_b;
+uniform float u_mix;
+
+uniform sampler2D u_image;
+
+varying vec2 v_pos_a;
+varying vec2 v_pos_b;
+varying vec2 v_pos;
+
+varying lowp float opacity;
+
+void main() {
+
+
+ vec2 imagecoord = mod(v_pos_a, 1.0);
+ vec2 pos = mix(u_pattern_tl_a, u_pattern_br_a, imagecoord);
+ vec4 color1 = texture2D(u_image, pos);
+
+ vec2 imagecoord_b = mod(v_pos_b, 1.0);
+ vec2 pos2 = mix(u_pattern_tl_b, u_pattern_br_b, imagecoord_b);
+ vec4 color2 = texture2D(u_image, pos2);
+
+ // find distance to outline for alpha interpolation
+
+ float dist = length(v_pos - gl_FragCoord.xy);
+ float alpha = smoothstep(1.0, 0.0, dist);
+
+
+ gl_FragColor = mix(color1, color2, u_mix) * alpha * opacity;
+
+#ifdef OVERDRAW_INSPECTOR
+ gl_FragColor = vec4(1.0);
+#endif
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/fill_outline_pattern.hpp b/src/mbgl/shaders/fill_outline_pattern.hpp
new file mode 100644
index 0000000000..e1c7a173f4
--- /dev/null
+++ b/src/mbgl/shaders/fill_outline_pattern.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class fill_outline_pattern {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/fill_pattern.cpp b/src/mbgl/shaders/fill_pattern.cpp
new file mode 100644
index 0000000000..822a0f7b8f
--- /dev/null
+++ b/src/mbgl/shaders/fill_pattern.cpp
@@ -0,0 +1,145 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/fill_pattern.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* fill_pattern::name = "fill_pattern";
+const char* fill_pattern::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+uniform mat4 u_matrix;
+uniform vec2 u_pattern_size_a;
+uniform vec2 u_pattern_size_b;
+uniform vec2 u_pixel_coord_upper;
+uniform vec2 u_pixel_coord_lower;
+uniform float u_scale_a;
+uniform float u_scale_b;
+uniform float u_tile_units_to_pixels;
+
+attribute vec2 a_pos;
+
+varying vec2 v_pos_a;
+varying vec2 v_pos_b;
+
+uniform lowp float a_opacity_t;
+attribute lowp float a_opacity_min;
+attribute lowp float a_opacity_max;
+varying lowp float opacity;
+
+void main() {
+ opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
+
+ gl_Position = u_matrix * vec4(a_pos, 0, 1);
+
+ v_pos_a = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_a * u_pattern_size_a, u_tile_units_to_pixels, a_pos);
+ v_pos_b = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_b * u_pattern_size_b, u_tile_units_to_pixels, a_pos);
+}
+
+)MBGL_SHADER";
+const char* fill_pattern::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+uniform vec2 u_pattern_tl_a;
+uniform vec2 u_pattern_br_a;
+uniform vec2 u_pattern_tl_b;
+uniform vec2 u_pattern_br_b;
+uniform float u_mix;
+
+uniform sampler2D u_image;
+
+varying vec2 v_pos_a;
+varying vec2 v_pos_b;
+
+varying lowp float opacity;
+
+void main() {
+
+
+ vec2 imagecoord = mod(v_pos_a, 1.0);
+ vec2 pos = mix(u_pattern_tl_a, u_pattern_br_a, imagecoord);
+ vec4 color1 = texture2D(u_image, pos);
+
+ vec2 imagecoord_b = mod(v_pos_b, 1.0);
+ vec2 pos2 = mix(u_pattern_tl_b, u_pattern_br_b, imagecoord_b);
+ vec4 color2 = texture2D(u_image, pos2);
+
+ gl_FragColor = mix(color1, color2, u_mix) * opacity;
+
+#ifdef OVERDRAW_INSPECTOR
+ gl_FragColor = vec4(1.0);
+#endif
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/fill_pattern.hpp b/src/mbgl/shaders/fill_pattern.hpp
new file mode 100644
index 0000000000..4d09519ed8
--- /dev/null
+++ b/src/mbgl/shaders/fill_pattern.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class fill_pattern {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/line.cpp b/src/mbgl/shaders/line.cpp
new file mode 100644
index 0000000000..59fa9f0cf2
--- /dev/null
+++ b/src/mbgl/shaders/line.cpp
@@ -0,0 +1,216 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/line.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* line::name = "line";
+const char* line::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+
+
+// the distance over which the line edge fades out.
+// Retina devices need a smaller distance to avoid aliasing.
+#define ANTIALIASING 1.0 / DEVICE_PIXEL_RATIO / 2.0
+
+// floor(127 / 2) == 63.0
+// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is
+// stored in a byte (-128..127). we scale regular normals up to length 63, but
+// there are also "special" normals that have a bigger length (of up to 126 in
+// this case).
+// #define scale 63.0
+#define scale 0.015873016
+
+attribute vec2 a_pos;
+attribute vec4 a_data;
+
+uniform mat4 u_matrix;
+uniform mediump float u_ratio;
+uniform mediump float u_width;
+uniform vec2 u_gl_units_to_pixels;
+
+varying vec2 v_normal;
+varying vec2 v_width2;
+varying float v_gamma_scale;
+
+uniform lowp float a_color_t;
+attribute lowp vec4 a_color_min;
+attribute lowp vec4 a_color_max;
+varying lowp vec4 color;
+uniform lowp float a_blur_t;
+attribute lowp float a_blur_min;
+attribute lowp float a_blur_max;
+varying lowp float blur;
+uniform lowp float a_opacity_t;
+attribute lowp float a_opacity_min;
+attribute lowp float a_opacity_max;
+varying lowp float opacity;
+uniform lowp float a_gapwidth_t;
+attribute mediump float a_gapwidth_min;
+attribute mediump float a_gapwidth_max;
+varying mediump float gapwidth;
+uniform lowp float a_offset_t;
+attribute lowp float a_offset_min;
+attribute lowp float a_offset_max;
+varying lowp float offset;
+
+void main() {
+ color = mix(a_color_min, a_color_max, a_color_t);
+ blur = mix(a_blur_min, a_blur_max, a_blur_t);
+ opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
+ gapwidth = mix(a_gapwidth_min, a_gapwidth_max, a_gapwidth_t);
+ offset = mix(a_offset_min, a_offset_max, a_offset_t);
+
+ vec2 a_extrude = a_data.xy - 128.0;
+ float a_direction = mod(a_data.z, 4.0) - 1.0;
+
+ // We store the texture normals in the most insignificant bit
+ // transform y so that 0 => -1 and 1 => 1
+ // In the texture normal, x is 0 if the normal points straight up/down and 1 if it's a round cap
+ // y is 1 if the normal points up, and -1 if it points down
+ mediump vec2 normal = mod(a_pos, 2.0);
+ normal.y = sign(normal.y - 0.5);
+ v_normal = normal;
+
+
+ // these transformations used to be applied in the JS and native code bases.
+ // moved them into the shader for clarity and simplicity.
+ gapwidth = gapwidth / 2.0;
+ float width = u_width / 2.0;
+ offset = -1.0 * offset;
+
+ float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0);
+ float outset = gapwidth + width * (gapwidth > 0.0 ? 2.0 : 1.0) + ANTIALIASING;
+
+ // Scale the extrusion vector down to a normal and then up by the line width
+ // of this vertex.
+ mediump vec2 dist = outset * a_extrude * scale;
+
+ // Calculate the offset when drawing a line that is to the side of the actual line.
+ // We do this by creating a vector that points towards the extrude, but rotate
+ // it when we're drawing round end points (a_direction = -1 or 1) since their
+ // extrude vector points in another direction.
+ mediump float u = 0.5 * a_direction;
+ mediump float t = 1.0 - abs(u);
+ mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t);
+
+ // Remove the texture normal bit to get the position
+ vec2 pos = floor(a_pos * 0.5);
+
+ vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0);
+ gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude;
+
+ // calculate how much the perspective view squishes or stretches the extrude
+ float extrude_length_without_perspective = length(dist);
+ float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_gl_units_to_pixels);
+ v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective;
+
+ v_width2 = vec2(outset, inset);
+}
+
+)MBGL_SHADER";
+const char* line::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+varying lowp vec4 color;
+varying lowp float blur;
+varying lowp float opacity;
+
+varying vec2 v_width2;
+varying vec2 v_normal;
+varying float v_gamma_scale;
+
+void main() {
+
+
+
+
+ // Calculate the distance of the pixel from the line in pixels.
+ float dist = length(v_normal) * v_width2.s;
+
+ // Calculate the antialiasing fade factor. This is either when fading in
+ // the line in case of an offset line (v_width2.t) or when fading out
+ // (v_width2.s)
+ float blur2 = (blur + 1.0 / DEVICE_PIXEL_RATIO) * v_gamma_scale;
+ float alpha = clamp(min(dist - (v_width2.t - blur2), v_width2.s - dist) / blur2, 0.0, 1.0);
+
+ gl_FragColor = color * (alpha * opacity);
+
+#ifdef OVERDRAW_INSPECTOR
+ gl_FragColor = vec4(1.0);
+#endif
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/line.hpp b/src/mbgl/shaders/line.hpp
new file mode 100644
index 0000000000..c0d81e6202
--- /dev/null
+++ b/src/mbgl/shaders/line.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class line {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/line_pattern.cpp b/src/mbgl/shaders/line_pattern.cpp
new file mode 100644
index 0000000000..7f2a31ee44
--- /dev/null
+++ b/src/mbgl/shaders/line_pattern.cpp
@@ -0,0 +1,233 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/line_pattern.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* line_pattern::name = "line_pattern";
+const char* line_pattern::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+// floor(127 / 2) == 63.0
+// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is
+// stored in a byte (-128..127). we scale regular normals up to length 63, but
+// there are also "special" normals that have a bigger length (of up to 126 in
+// this case).
+// #define scale 63.0
+#define scale 0.015873016
+
+// We scale the distance before adding it to the buffers so that we can store
+// long distances for long segments. Use this value to unscale the distance.
+#define LINE_DISTANCE_SCALE 2.0
+
+// the distance over which the line edge fades out.
+// Retina devices need a smaller distance to avoid aliasing.
+#define ANTIALIASING 1.0 / DEVICE_PIXEL_RATIO / 2.0
+
+attribute vec2 a_pos;
+attribute vec4 a_data;
+
+uniform mat4 u_matrix;
+uniform mediump float u_ratio;
+uniform mediump float u_width;
+uniform vec2 u_gl_units_to_pixels;
+
+varying vec2 v_normal;
+varying vec2 v_width2;
+varying float v_linesofar;
+varying float v_gamma_scale;
+
+uniform lowp float a_blur_t;
+attribute lowp float a_blur_min;
+attribute lowp float a_blur_max;
+varying lowp float blur;
+uniform lowp float a_opacity_t;
+attribute lowp float a_opacity_min;
+attribute lowp float a_opacity_max;
+varying lowp float opacity;
+uniform lowp float a_offset_t;
+attribute lowp float a_offset_min;
+attribute lowp float a_offset_max;
+varying lowp float offset;
+uniform lowp float a_gapwidth_t;
+attribute mediump float a_gapwidth_min;
+attribute mediump float a_gapwidth_max;
+varying mediump float gapwidth;
+
+void main() {
+ blur = mix(a_blur_min, a_blur_max, a_blur_t);
+ opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
+ offset = mix(a_offset_min, a_offset_max, a_offset_t);
+ gapwidth = mix(a_gapwidth_min, a_gapwidth_max, a_gapwidth_t);
+
+ vec2 a_extrude = a_data.xy - 128.0;
+ float a_direction = mod(a_data.z, 4.0) - 1.0;
+ float a_linesofar = (floor(a_data.z / 4.0) + a_data.w * 64.0) * LINE_DISTANCE_SCALE;
+
+ // We store the texture normals in the most insignificant bit
+ // transform y so that 0 => -1 and 1 => 1
+ // In the texture normal, x is 0 if the normal points straight up/down and 1 if it's a round cap
+ // y is 1 if the normal points up, and -1 if it points down
+ mediump vec2 normal = mod(a_pos, 2.0);
+ normal.y = sign(normal.y - 0.5);
+ v_normal = normal;
+
+ // these transformations used to be applied in the JS and native code bases.
+ // moved them into the shader for clarity and simplicity.
+ gapwidth = gapwidth / 2.0;
+ float width = u_width / 2.0;
+ offset = -1.0 * offset;
+
+ float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0);
+ float outset = gapwidth + width * (gapwidth > 0.0 ? 2.0 : 1.0) + ANTIALIASING;
+
+ // Scale the extrusion vector down to a normal and then up by the line width
+ // of this vertex.
+ mediump vec2 dist = outset * a_extrude * scale;
+
+ // Calculate the offset when drawing a line that is to the side of the actual line.
+ // We do this by creating a vector that points towards the extrude, but rotate
+ // it when we're drawing round end points (a_direction = -1 or 1) since their
+ // extrude vector points in another direction.
+ mediump float u = 0.5 * a_direction;
+ mediump float t = 1.0 - abs(u);
+ mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t);
+
+ // Remove the texture normal bit to get the position
+ vec2 pos = floor(a_pos * 0.5);
+
+ vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0);
+ gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude;
+
+ // calculate how much the perspective view squishes or stretches the extrude
+ float extrude_length_without_perspective = length(dist);
+ float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_gl_units_to_pixels);
+ v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective;
+
+ v_linesofar = a_linesofar;
+ v_width2 = vec2(outset, inset);
+}
+
+)MBGL_SHADER";
+const char* line_pattern::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+uniform vec2 u_pattern_size_a;
+uniform vec2 u_pattern_size_b;
+uniform vec2 u_pattern_tl_a;
+uniform vec2 u_pattern_br_a;
+uniform vec2 u_pattern_tl_b;
+uniform vec2 u_pattern_br_b;
+uniform float u_fade;
+
+uniform sampler2D u_image;
+
+varying vec2 v_normal;
+varying vec2 v_width2;
+varying float v_linesofar;
+varying float v_gamma_scale;
+
+varying lowp float blur;
+varying lowp float opacity;
+
+void main() {
+
+
+
+ // Calculate the distance of the pixel from the line in pixels.
+ float dist = length(v_normal) * v_width2.s;
+
+ // Calculate the antialiasing fade factor. This is either when fading in
+ // the line in case of an offset line (v_width2.t) or when fading out
+ // (v_width2.s)
+ float blur2 = (blur + 1.0 / DEVICE_PIXEL_RATIO) * v_gamma_scale;
+ float alpha = clamp(min(dist - (v_width2.t - blur2), v_width2.s - dist) / blur2, 0.0, 1.0);
+
+ float x_a = mod(v_linesofar / u_pattern_size_a.x, 1.0);
+ float x_b = mod(v_linesofar / u_pattern_size_b.x, 1.0);
+ float y_a = 0.5 + (v_normal.y * v_width2.s / u_pattern_size_a.y);
+ float y_b = 0.5 + (v_normal.y * v_width2.s / u_pattern_size_b.y);
+ vec2 pos_a = mix(u_pattern_tl_a, u_pattern_br_a, vec2(x_a, y_a));
+ vec2 pos_b = mix(u_pattern_tl_b, u_pattern_br_b, vec2(x_b, y_b));
+
+ vec4 color = mix(texture2D(u_image, pos_a), texture2D(u_image, pos_b), u_fade);
+
+ gl_FragColor = color * alpha * opacity;
+
+#ifdef OVERDRAW_INSPECTOR
+ gl_FragColor = vec4(1.0);
+#endif
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/line_pattern.hpp b/src/mbgl/shaders/line_pattern.hpp
new file mode 100644
index 0000000000..0394e83fe0
--- /dev/null
+++ b/src/mbgl/shaders/line_pattern.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class line_pattern {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/line_sdf.cpp b/src/mbgl/shaders/line_sdf.cpp
new file mode 100644
index 0000000000..011c1c3738
--- /dev/null
+++ b/src/mbgl/shaders/line_sdf.cpp
@@ -0,0 +1,239 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/line_sdf.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* line_sdf::name = "line_sdf";
+const char* line_sdf::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+// floor(127 / 2) == 63.0
+// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is
+// stored in a byte (-128..127). we scale regular normals up to length 63, but
+// there are also "special" normals that have a bigger length (of up to 126 in
+// this case).
+// #define scale 63.0
+#define scale 0.015873016
+
+// We scale the distance before adding it to the buffers so that we can store
+// long distances for long segments. Use this value to unscale the distance.
+#define LINE_DISTANCE_SCALE 2.0
+
+// the distance over which the line edge fades out.
+// Retina devices need a smaller distance to avoid aliasing.
+#define ANTIALIASING 1.0 / DEVICE_PIXEL_RATIO / 2.0
+
+attribute vec2 a_pos;
+attribute vec4 a_data;
+
+uniform mat4 u_matrix;
+uniform mediump float u_ratio;
+uniform vec2 u_patternscale_a;
+uniform float u_tex_y_a;
+uniform vec2 u_patternscale_b;
+uniform float u_tex_y_b;
+uniform vec2 u_gl_units_to_pixels;
+uniform mediump float u_width;
+
+varying vec2 v_normal;
+varying vec2 v_width2;
+varying vec2 v_tex_a;
+varying vec2 v_tex_b;
+varying float v_gamma_scale;
+
+uniform lowp float a_color_t;
+attribute lowp vec4 a_color_min;
+attribute lowp vec4 a_color_max;
+varying lowp vec4 color;
+uniform lowp float a_blur_t;
+attribute lowp float a_blur_min;
+attribute lowp float a_blur_max;
+varying lowp float blur;
+uniform lowp float a_opacity_t;
+attribute lowp float a_opacity_min;
+attribute lowp float a_opacity_max;
+varying lowp float opacity;
+uniform lowp float a_gapwidth_t;
+attribute mediump float a_gapwidth_min;
+attribute mediump float a_gapwidth_max;
+varying mediump float gapwidth;
+uniform lowp float a_offset_t;
+attribute lowp float a_offset_min;
+attribute lowp float a_offset_max;
+varying lowp float offset;
+
+void main() {
+ color = mix(a_color_min, a_color_max, a_color_t);
+ blur = mix(a_blur_min, a_blur_max, a_blur_t);
+ opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
+ gapwidth = mix(a_gapwidth_min, a_gapwidth_max, a_gapwidth_t);
+ offset = mix(a_offset_min, a_offset_max, a_offset_t);
+
+ vec2 a_extrude = a_data.xy - 128.0;
+ float a_direction = mod(a_data.z, 4.0) - 1.0;
+ float a_linesofar = (floor(a_data.z / 4.0) + a_data.w * 64.0) * LINE_DISTANCE_SCALE;
+
+ // We store the texture normals in the most insignificant bit
+ // transform y so that 0 => -1 and 1 => 1
+ // In the texture normal, x is 0 if the normal points straight up/down and 1 if it's a round cap
+ // y is 1 if the normal points up, and -1 if it points down
+ mediump vec2 normal = mod(a_pos, 2.0);
+ normal.y = sign(normal.y - 0.5);
+ v_normal = normal;
+
+ // these transformations used to be applied in the JS and native code bases.
+ // moved them into the shader for clarity and simplicity.
+ gapwidth = gapwidth / 2.0;
+ float width = u_width / 2.0;
+ offset = -1.0 * offset;
+
+ float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0);
+ float outset = gapwidth + width * (gapwidth > 0.0 ? 2.0 : 1.0) + ANTIALIASING;
+
+ // Scale the extrusion vector down to a normal and then up by the line width
+ // of this vertex.
+ mediump vec2 dist =outset * a_extrude * scale;
+
+ // Calculate the offset when drawing a line that is to the side of the actual line.
+ // We do this by creating a vector that points towards the extrude, but rotate
+ // it when we're drawing round end points (a_direction = -1 or 1) since their
+ // extrude vector points in another direction.
+ mediump float u = 0.5 * a_direction;
+ mediump float t = 1.0 - abs(u);
+ mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t);
+
+ // Remove the texture normal bit to get the position
+ vec2 pos = floor(a_pos * 0.5);
+
+ vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0);
+ gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude;
+
+ // calculate how much the perspective view squishes or stretches the extrude
+ float extrude_length_without_perspective = length(dist);
+ float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_gl_units_to_pixels);
+ v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective;
+
+ v_tex_a = vec2(a_linesofar * u_patternscale_a.x, normal.y * u_patternscale_a.y + u_tex_y_a);
+ v_tex_b = vec2(a_linesofar * u_patternscale_b.x, normal.y * u_patternscale_b.y + u_tex_y_b);
+
+ v_width2 = vec2(outset, inset);
+}
+
+)MBGL_SHADER";
+const char* line_sdf::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+uniform sampler2D u_image;
+uniform float u_sdfgamma;
+uniform float u_mix;
+
+varying vec2 v_normal;
+varying vec2 v_width2;
+varying vec2 v_tex_a;
+varying vec2 v_tex_b;
+varying float v_gamma_scale;
+
+varying lowp vec4 color;
+varying lowp float blur;
+varying lowp float opacity;
+
+void main() {
+
+
+
+
+ // Calculate the distance of the pixel from the line in pixels.
+ float dist = length(v_normal) * v_width2.s;
+
+ // Calculate the antialiasing fade factor. This is either when fading in
+ // the line in case of an offset line (v_width2.t) or when fading out
+ // (v_width2.s)
+ float blur2 = (blur + 1.0 / DEVICE_PIXEL_RATIO) * v_gamma_scale;
+ float alpha = clamp(min(dist - (v_width2.t - blur2), v_width2.s - dist) / blur2, 0.0, 1.0);
+
+ float sdfdist_a = texture2D(u_image, v_tex_a).a;
+ float sdfdist_b = texture2D(u_image, v_tex_b).a;
+ float sdfdist = mix(sdfdist_a, sdfdist_b, u_mix);
+ alpha *= smoothstep(0.5 - u_sdfgamma, 0.5 + u_sdfgamma, sdfdist);
+
+ gl_FragColor = color * (alpha * opacity);
+
+#ifdef OVERDRAW_INSPECTOR
+ gl_FragColor = vec4(1.0);
+#endif
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/line_sdf.hpp b/src/mbgl/shaders/line_sdf.hpp
new file mode 100644
index 0000000000..1d4b566f25
--- /dev/null
+++ b/src/mbgl/shaders/line_sdf.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class line_sdf {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/raster.cpp b/src/mbgl/shaders/raster.cpp
new file mode 100644
index 0000000000..ba0aa5cd05
--- /dev/null
+++ b/src/mbgl/shaders/raster.cpp
@@ -0,0 +1,150 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/raster.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* raster::name = "raster";
+const char* raster::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+uniform mat4 u_matrix;
+uniform vec2 u_tl_parent;
+uniform float u_scale_parent;
+uniform float u_buffer_scale;
+
+attribute vec2 a_pos;
+attribute vec2 a_texture_pos;
+
+varying vec2 v_pos0;
+varying vec2 v_pos1;
+
+void main() {
+ gl_Position = u_matrix * vec4(a_pos, 0, 1);
+ v_pos0 = (((a_texture_pos / 32767.0) - 0.5) / u_buffer_scale ) + 0.5;
+ v_pos1 = (v_pos0 * u_scale_parent) + u_tl_parent;
+}
+
+)MBGL_SHADER";
+const char* raster::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+uniform float u_fade_t;
+uniform float u_opacity;
+uniform sampler2D u_image0;
+uniform sampler2D u_image1;
+varying vec2 v_pos0;
+varying vec2 v_pos1;
+
+uniform float u_brightness_low;
+uniform float u_brightness_high;
+
+uniform float u_saturation_factor;
+uniform float u_contrast_factor;
+uniform vec3 u_spin_weights;
+
+void main() {
+
+ // read and cross-fade colors from the main and parent tiles
+ vec4 color0 = texture2D(u_image0, v_pos0);
+ vec4 color1 = texture2D(u_image1, v_pos1);
+ vec4 color = mix(color0, color1, u_fade_t);
+ color.a *= u_opacity;
+ vec3 rgb = color.rgb;
+
+ // spin
+ rgb = vec3(
+ dot(rgb, u_spin_weights.xyz),
+ dot(rgb, u_spin_weights.zxy),
+ dot(rgb, u_spin_weights.yzx));
+
+ // saturation
+ float average = (color.r + color.g + color.b) / 3.0;
+ rgb += (average - rgb) * u_saturation_factor;
+
+ // contrast
+ rgb = (rgb - 0.5) * u_contrast_factor + 0.5;
+
+ // brightness
+ vec3 u_high_vec = vec3(u_brightness_low, u_brightness_low, u_brightness_low);
+ vec3 u_low_vec = vec3(u_brightness_high, u_brightness_high, u_brightness_high);
+
+ gl_FragColor = vec4(mix(u_high_vec, u_low_vec, rgb) * color.a, color.a);
+
+#ifdef OVERDRAW_INSPECTOR
+ gl_FragColor = vec4(1.0);
+#endif
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/raster.hpp b/src/mbgl/shaders/raster.hpp
new file mode 100644
index 0000000000..791e2c8be0
--- /dev/null
+++ b/src/mbgl/shaders/raster.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class raster {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/symbol_icon.cpp b/src/mbgl/shaders/symbol_icon.cpp
new file mode 100644
index 0000000000..e6728e15de
--- /dev/null
+++ b/src/mbgl/shaders/symbol_icon.cpp
@@ -0,0 +1,151 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/symbol_icon.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* symbol_icon::name = "symbol_icon";
+const char* symbol_icon::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+attribute vec2 a_pos;
+attribute vec2 a_offset;
+attribute vec2 a_texture_pos;
+attribute vec4 a_data;
+
+uniform lowp float a_opacity_t;
+attribute lowp float a_opacity_min;
+attribute lowp float a_opacity_max;
+varying lowp float opacity;
+
+// matrix is for the vertex position.
+uniform mat4 u_matrix;
+
+uniform mediump float u_zoom;
+uniform bool u_rotate_with_map;
+uniform vec2 u_extrude_scale;
+
+uniform vec2 u_texsize;
+
+varying vec2 v_tex;
+varying vec2 v_fade_tex;
+
+void main() {
+ opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
+
+ vec2 a_tex = a_texture_pos.xy;
+ mediump float a_labelminzoom = a_data[0];
+ mediump vec2 a_zoom = a_data.pq;
+ mediump float a_minzoom = a_zoom[0];
+ mediump float a_maxzoom = a_zoom[1];
+
+ // u_zoom is the current zoom level adjusted for the change in font size
+ mediump float z = 2.0 - step(a_minzoom, u_zoom) - (1.0 - step(a_maxzoom, u_zoom));
+
+ vec2 extrude = u_extrude_scale * (a_offset / 64.0);
+ if (u_rotate_with_map) {
+ gl_Position = u_matrix * vec4(a_pos + extrude, 0, 1);
+ gl_Position.z += z * gl_Position.w;
+ } else {
+ gl_Position = u_matrix * vec4(a_pos, 0, 1) + vec4(extrude, 0, 0);
+ }
+
+ v_tex = a_tex / u_texsize;
+ v_fade_tex = vec2(a_labelminzoom / 255.0, 0.0);
+}
+
+)MBGL_SHADER";
+const char* symbol_icon::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+uniform sampler2D u_texture;
+uniform sampler2D u_fadetexture;
+
+varying lowp float opacity;
+
+varying vec2 v_tex;
+varying vec2 v_fade_tex;
+
+void main() {
+
+
+ lowp float alpha = texture2D(u_fadetexture, v_fade_tex).a * opacity;
+ gl_FragColor = texture2D(u_texture, v_tex) * alpha;
+
+#ifdef OVERDRAW_INSPECTOR
+ gl_FragColor = vec4(1.0);
+#endif
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/symbol_icon.hpp b/src/mbgl/shaders/symbol_icon.hpp
new file mode 100644
index 0000000000..eccf17602d
--- /dev/null
+++ b/src/mbgl/shaders/symbol_icon.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class symbol_icon {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/symbol_sdf.cpp b/src/mbgl/shaders/symbol_sdf.cpp
new file mode 100644
index 0000000000..e087242bf8
--- /dev/null
+++ b/src/mbgl/shaders/symbol_sdf.cpp
@@ -0,0 +1,242 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/symbol_sdf.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* symbol_sdf::name = "symbol_sdf";
+const char* symbol_sdf::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+const float PI = 3.141592653589793;
+
+attribute vec2 a_pos;
+attribute vec2 a_offset;
+attribute vec2 a_texture_pos;
+attribute vec4 a_data;
+
+uniform lowp float a_fill_color_t;
+attribute lowp vec4 a_fill_color_min;
+attribute lowp vec4 a_fill_color_max;
+varying lowp vec4 fill_color;
+uniform lowp float a_halo_color_t;
+attribute lowp vec4 a_halo_color_min;
+attribute lowp vec4 a_halo_color_max;
+varying lowp vec4 halo_color;
+uniform lowp float a_opacity_t;
+attribute lowp float a_opacity_min;
+attribute lowp float a_opacity_max;
+varying lowp float opacity;
+uniform lowp float a_halo_width_t;
+attribute lowp float a_halo_width_min;
+attribute lowp float a_halo_width_max;
+varying lowp float halo_width;
+uniform lowp float a_halo_blur_t;
+attribute lowp float a_halo_blur_min;
+attribute lowp float a_halo_blur_max;
+varying lowp float halo_blur;
+
+// matrix is for the vertex position.
+uniform mat4 u_matrix;
+
+uniform mediump float u_zoom;
+uniform bool u_rotate_with_map;
+uniform bool u_pitch_with_map;
+uniform mediump float u_pitch;
+uniform mediump float u_bearing;
+uniform mediump float u_aspect_ratio;
+uniform vec2 u_extrude_scale;
+
+uniform vec2 u_texsize;
+
+varying vec2 v_tex;
+varying vec2 v_fade_tex;
+varying float v_gamma_scale;
+
+void main() {
+ fill_color = mix(a_fill_color_min, a_fill_color_max, a_fill_color_t);
+ halo_color = mix(a_halo_color_min, a_halo_color_max, a_halo_color_t);
+ opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
+ halo_width = mix(a_halo_width_min, a_halo_width_max, a_halo_width_t);
+ halo_blur = mix(a_halo_blur_min, a_halo_blur_max, a_halo_blur_t);
+
+ vec2 a_tex = a_texture_pos.xy;
+ mediump float a_labelminzoom = a_data[0];
+ mediump vec2 a_zoom = a_data.pq;
+ mediump float a_minzoom = a_zoom[0];
+ mediump float a_maxzoom = a_zoom[1];
+
+ // u_zoom is the current zoom level adjusted for the change in font size
+ mediump float z = 2.0 - step(a_minzoom, u_zoom) - (1.0 - step(a_maxzoom, u_zoom));
+
+ // pitch-alignment: map
+ // rotation-alignment: map | viewport
+ if (u_pitch_with_map) {
+ lowp float angle = u_rotate_with_map ? (a_data[1] / 256.0 * 2.0 * PI) : u_bearing;
+ lowp float asin = sin(angle);
+ lowp float acos = cos(angle);
+ mat2 RotationMatrix = mat2(acos, asin, -1.0 * asin, acos);
+ vec2 offset = RotationMatrix * a_offset;
+ vec2 extrude = u_extrude_scale * (offset / 64.0);
+ gl_Position = u_matrix * vec4(a_pos + extrude, 0, 1);
+ gl_Position.z += z * gl_Position.w;
+ // pitch-alignment: viewport
+ // rotation-alignment: map
+ } else if (u_rotate_with_map) {
+ // foreshortening factor to apply on pitched maps
+ // as a label goes from horizontal <=> vertical in angle
+ // it goes from 0% foreshortening to up to around 70% foreshortening
+ lowp float pitchfactor = 1.0 - cos(u_pitch * sin(u_pitch * 0.75));
+
+ lowp float lineangle = a_data[1] / 256.0 * 2.0 * PI;
+
+ // use the lineangle to position points a,b along the line
+ // project the points and calculate the label angle in projected space
+ // this calculation allows labels to be rendered unskewed on pitched maps
+ vec4 a = u_matrix * vec4(a_pos, 0, 1);
+ vec4 b = u_matrix * vec4(a_pos + vec2(cos(lineangle),sin(lineangle)), 0, 1);
+ lowp float angle = atan((b[1]/b[3] - a[1]/a[3])/u_aspect_ratio, b[0]/b[3] - a[0]/a[3]);
+ lowp float asin = sin(angle);
+ lowp float acos = cos(angle);
+ mat2 RotationMatrix = mat2(acos, -1.0 * asin, asin, acos);
+
+ vec2 offset = RotationMatrix * (vec2((1.0-pitchfactor)+(pitchfactor*cos(angle*2.0)), 1.0) * a_offset);
+ vec2 extrude = u_extrude_scale * (offset / 64.0);
+ gl_Position = u_matrix * vec4(a_pos, 0, 1) + vec4(extrude, 0, 0);
+ gl_Position.z += z * gl_Position.w;
+ // pitch-alignment: viewport
+ // rotation-alignment: viewport
+ } else {
+ vec2 extrude = u_extrude_scale * (a_offset / 64.0);
+ gl_Position = u_matrix * vec4(a_pos, 0, 1) + vec4(extrude, 0, 0);
+ }
+
+ v_gamma_scale = gl_Position.w;
+
+ v_tex = a_tex / u_texsize;
+ v_fade_tex = vec2(a_labelminzoom / 255.0, 0.0);
+}
+
+)MBGL_SHADER";
+const char* symbol_sdf::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+#define SDF_PX 8.0
+#define EDGE_GAMMA 0.105/DEVICE_PIXEL_RATIO
+
+uniform bool u_is_halo;
+varying lowp vec4 fill_color;
+varying lowp vec4 halo_color;
+varying lowp float opacity;
+varying lowp float halo_width;
+varying lowp float halo_blur;
+
+uniform sampler2D u_texture;
+uniform sampler2D u_fadetexture;
+uniform lowp float u_font_scale;
+uniform highp float u_gamma_scale;
+
+varying vec2 v_tex;
+varying vec2 v_fade_tex;
+varying float v_gamma_scale;
+
+void main() {
+
+
+
+
+
+
+ lowp vec4 color = fill_color;
+ lowp float gamma = EDGE_GAMMA / u_gamma_scale;
+ lowp float buff = (256.0 - 64.0) / 256.0;
+ if (u_is_halo) {
+ color = halo_color;
+ gamma = (halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / u_gamma_scale;
+ buff = (6.0 - halo_width / u_font_scale) / SDF_PX;
+ }
+
+ lowp float dist = texture2D(u_texture, v_tex).a;
+ lowp float fade_alpha = texture2D(u_fadetexture, v_fade_tex).a;
+ highp float gamma_scaled = gamma * v_gamma_scale;
+ highp float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist) * fade_alpha;
+
+ gl_FragColor = color * (alpha * opacity);
+
+#ifdef OVERDRAW_INSPECTOR
+ gl_FragColor = vec4(1.0);
+#endif
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/symbol_sdf.hpp b/src/mbgl/shaders/symbol_sdf.hpp
new file mode 100644
index 0000000000..d5761d5fdb
--- /dev/null
+++ b/src/mbgl/shaders/symbol_sdf.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class symbol_sdf {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/sprite/sprite_atlas.cpp b/src/mbgl/sprite/sprite_atlas.cpp
index ea055ce5ec..2bf8a3095a 100644
--- a/src/mbgl/sprite/sprite_atlas.cpp
+++ b/src/mbgl/sprite/sprite_atlas.cpp
@@ -27,6 +27,23 @@ struct SpriteAtlas::Loader {
std::unique_ptr<AsyncRequest> spriteRequest;
};
+SpriteAtlasElement::SpriteAtlasElement(Rect<uint16_t> rect_,
+ std::shared_ptr<const SpriteImage> image_,
+ Size size_, float pixelRatio)
+ : pos(std::move(rect_)),
+ spriteImage(std::move(image_)),
+ relativePixelRatio(spriteImage->pixelRatio / pixelRatio) {
+
+ const float padding = 1;
+
+ const float w = spriteImage->getWidth() * relativePixelRatio;
+ const float h = spriteImage->getHeight() * relativePixelRatio;
+
+ size = {{ float(spriteImage->getWidth()), spriteImage->getHeight() }};
+ tl = {{ float(pos.x + padding) / size_.width, float(pos.y + padding) / size_.height }};
+ br = {{ float(pos.x + padding + w) / size_.width, float(pos.y + padding + h) / size_.height }};
+}
+
SpriteAtlas::SpriteAtlas(Size size_, float pixelRatio_)
: size(std::move(size_)),
pixelRatio(pixelRatio_),
@@ -115,85 +132,112 @@ void SpriteAtlas::setSprite(const std::string& name, std::shared_ptr<const Sprit
void SpriteAtlas::removeSprite(const std::string& name) {
std::lock_guard<std::mutex> lock(mutex);
- _setSprite(name);
+
+ auto it = entries.find(name);
+ if (it == entries.end()) {
+ return;
+ }
+
+ Entry& entry = it->second;
+
+ if (entry.iconRect) {
+ bin.release(*entry.iconRect);
+ }
+
+ if (entry.patternRect) {
+ bin.release(*entry.patternRect);
+ }
+
+ entries.erase(it);
}
void SpriteAtlas::_setSprite(const std::string& name,
const std::shared_ptr<const SpriteImage>& sprite) {
- if (sprite) {
- auto it = sprites.find(name);
- if (it != sprites.end()) {
- // There is already a sprite with that name in our store.
- if (it->second->image.size != sprite->image.size) {
- Log::Warning(Event::Sprite, "Can't change sprite dimensions for '%s'", name.c_str());
- return;
- }
- it->second = sprite;
- } else {
- sprites.emplace(name, sprite);
- }
+ if (!sprite->image.valid()) {
+ Log::Warning(Event::Sprite, "invalid sprite image '%s'", name.c_str());
+ return;
+ }
- // Always add/replace the value in the dirty list.
- auto dirty_it = dirtySprites.find(name);
- if (dirty_it != dirtySprites.end()) {
- dirty_it->second = sprite;
- } else {
- dirtySprites.emplace(name, sprite);
- }
- } else if (sprites.erase(name) > 0) {
- dirtySprites.emplace(name, nullptr);
+ auto it = entries.find(name);
+ if (it == entries.end()) {
+ entries.emplace(name, Entry { sprite, {}, {} });
+ return;
+ }
+
+ Entry& entry = it->second;
+
+ // There is already a sprite with that name in our store.
+ if (entry.spriteImage->image.size != sprite->image.size) {
+ Log::Warning(Event::Sprite, "Can't change sprite dimensions for '%s'", name.c_str());
+ return;
+ }
+
+ entry.spriteImage = sprite;
+
+ if (entry.iconRect) {
+ copy(entry, &Entry::iconRect);
+ }
+
+ if (entry.patternRect) {
+ copy(entry, &Entry::patternRect);
}
}
std::shared_ptr<const SpriteImage> SpriteAtlas::getSprite(const std::string& name) {
std::lock_guard<std::mutex> lock(mutex);
- const auto it = sprites.find(name);
- if (it != sprites.end()) {
- return it->second;
+ const auto it = entries.find(name);
+ if (it != entries.end()) {
+ return it->second.spriteImage;
} else {
- if (!sprites.empty()) {
+ if (!entries.empty()) {
Log::Info(Event::Sprite, "Can't find sprite named '%s'", name.c_str());
}
return nullptr;
}
}
-Rect<uint16_t> SpriteAtlas::allocateImage(const SpriteImage& spriteImage) {
-
- 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
- // into 2 bytes rather than 4 bytes.
- const uint16_t pack_width = (pixel_width + 1) + (4 - (pixel_width + 1) % 4);
- const uint16_t pack_height = (pixel_height + 1) + (4 - (pixel_height + 1) % 4);
-
- // 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<uint16_t> rect = bin.allocate(pack_width, pack_height);
- if (rect.w == 0) {
- return rect;
- }
+optional<SpriteAtlasElement> SpriteAtlas::getIcon(const std::string& name) {
+ return getImage(name, &Entry::iconRect);
+}
- return rect;
+optional<SpriteAtlasElement> SpriteAtlas::getPattern(const std::string& name) {
+ return getImage(name, &Entry::patternRect);
}
optional<SpriteAtlasElement> SpriteAtlas::getImage(const std::string& name,
- const SpritePatternMode mode) {
- std::lock_guard<std::recursive_mutex> lock(mtx);
+ optional<Rect<uint16_t>> Entry::*entryRect) {
+ std::lock_guard<std::mutex> lock(mutex);
- auto rect_it = images.find({ name, mode });
- if (rect_it != images.end()) {
- return SpriteAtlasElement { rect_it->second.pos, rect_it->second.spriteImage, rect_it->second.spriteImage->pixelRatio / pixelRatio };
+ auto it = entries.find(name);
+ if (it == entries.end()) {
+ if (!entries.empty()) {
+ Log::Info(Event::Sprite, "Can't find sprite named '%s'", name.c_str());
+ }
+ return {};
}
- auto sprite = getSprite(name);
- if (!sprite) {
- return {};
+ Entry& entry = it->second;
+
+ if (entry.*entryRect) {
+ return SpriteAtlasElement {
+ *(entry.*entryRect),
+ entry.spriteImage,
+ size,
+ pixelRatio
+ };
}
- Rect<uint16_t> rect = allocateImage(*sprite);
+ const uint16_t pixelWidth = std::ceil(entry.spriteImage->image.size.width / pixelRatio);
+ const uint16_t pixelHeight = std::ceil(entry.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
+ // into 2 bytes rather than 4 bytes.
+ const uint16_t packWidth = (pixelWidth + 1) + (4 - (pixelWidth + 1) % 4);
+ const uint16_t packHeight = (pixelHeight + 1) + (4 - (pixelHeight + 1) % 4);
+
+ // We have to allocate a new area in the bin, and store an empty image in it.
+ Rect<uint16_t> rect = bin.allocate(packWidth, packHeight);
if (rect.w == 0) {
if (debug::spriteWarnings) {
Log::Warning(Event::Sprite, "sprite atlas bitmap overflow");
@@ -201,112 +245,44 @@ optional<SpriteAtlasElement> SpriteAtlas::getImage(const std::string& name,
return {};
}
- const Holder& holder = images.emplace(Key{ name, mode }, Holder{ sprite, rect }).first->second;
- copy(holder, mode);
-
- return SpriteAtlasElement { rect, sprite, sprite->pixelRatio / pixelRatio };
-}
-
-optional<SpriteAtlasPosition> SpriteAtlas::getPosition(const std::string& name,
- const SpritePatternMode mode) {
- std::lock_guard<std::recursive_mutex> lock(mtx);
-
- auto img = getImage(name, mode);
- if (!img) {
- return {};
- }
-
- auto rect = (*img).pos;
-
- const float padding = 1;
- auto spriteImage = (*img).spriteImage;
-
- const float w = spriteImage->getWidth() * (*img).relativePixelRatio;
- const float h = spriteImage->getHeight() * (*img).relativePixelRatio;
+ entry.*entryRect = rect;
+ copy(entry, entryRect);
- return SpriteAtlasPosition {
- {{ float(spriteImage->getWidth()), spriteImage->getHeight() }},
- {{ 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 }}
+ return SpriteAtlasElement {
+ rect,
+ entry.spriteImage,
+ size,
+ pixelRatio
};
}
-void copyBitmap(const uint32_t *src, const uint32_t srcStride, const uint32_t srcX, const uint32_t srcY,
- uint32_t *const dst, const uint32_t dstStride, const uint32_t dstX, const uint32_t dstY, int dstSize,
- const int width, const int height, const SpritePatternMode mode) {
-
- int srcI = srcY * srcStride + srcX;
- int dstI = dstY * dstStride + dstX;
- int x, y;
-
- if (mode == SpritePatternMode::Repeating) {
- // add 1 pixel wrapped padding on each side of the image
- dstI -= dstStride;
- for (y = -1; y <= height; y++, srcI = ((y + height) % height + srcY) * srcStride + srcX, dstI += dstStride) {
- for (x = -1; x <= width; x++) {
- const int dstIndex = (dstI + x + dstSize) % dstSize;
- dst[dstIndex] = src[srcI + ((x + width) % width)];
- }
- }
-
- } else {
- for (y = 0; y < height; y++, srcI += srcStride, dstI += dstStride) {
- for (x = 0; x < width; x++) {
- const int dstIndex = (dstI + x + dstSize) % dstSize;
- dst[dstIndex] = src[srcI + x];
- }
- }
- }
-}
-
-void SpriteAtlas::copy(const Holder& holder, const SpritePatternMode mode) {
+void SpriteAtlas::copy(const Entry& entry, optional<Rect<uint16_t>> Entry::*entryRect) {
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);
+ image.fill(0);
}
- const uint32_t* srcData =
- reinterpret_cast<const uint32_t*>(holder.spriteImage->image.data.get());
- if (!srcData) return;
- uint32_t* const dstData = reinterpret_cast<uint32_t*>(image.data.get());
-
- const int padding = 1;
+ const PremultipliedImage& src = entry.spriteImage->image;
+ const Rect<uint16_t>& rect = *(entry.*entryRect);
- 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);
+ const uint32_t padding = 1;
+ const uint32_t x = (rect.x + padding) * pixelRatio;
+ const uint32_t y = (rect.y + padding) * pixelRatio;
+ const uint32_t w = src.size.width;
+ const uint32_t h = src.size.height;
- dirty = true;
-}
-
-void SpriteAtlas::updateDirty() {
- std::lock_guard<std::recursive_mutex> lock(mtx);
+ PremultipliedImage::copy(src, image, { 0, 0 }, { x, y }, { w, h });
- auto imageIterator = images.begin();
- auto spriteIterator = dirtySprites.begin();
- while (imageIterator != images.end() && spriteIterator != dirtySprites.end()) {
- if (imageIterator->first.first < spriteIterator->first) {
- ++imageIterator;
- } else if (spriteIterator->first < imageIterator->first.first) {
- ++spriteIterator;
- } else {
- // The two names match;
- Holder& holder = imageIterator->second;
- holder.spriteImage = spriteIterator->second;
- if (holder.spriteImage != nullptr) {
- copy(holder, imageIterator->first.second);
- ++imageIterator;
- } else {
- images.erase(imageIterator++);
- }
- // Don't advance the spriteIterator because there might be another sprite with the same
- // name, but a different wrap value.
- }
+ if (entryRect == &Entry::patternRect) {
+ // Add 1 pixel wrapped padding on each side of the image.
+ PremultipliedImage::copy(src, image, { 0, h - 1 }, { x, y - 1 }, { w, 1 }); // T
+ PremultipliedImage::copy(src, image, { 0, 0 }, { x, y + h }, { w, 1 }); // B
+ PremultipliedImage::copy(src, image, { w - 1, 0 }, { x - 1, y }, { 1, h }); // L
+ PremultipliedImage::copy(src, image, { 0, 0 }, { x + w, y }, { 1, h }); // R
}
- dirtySprites.clear();
+ dirty = true;
}
void SpriteAtlas::upload(gl::Context& context, gl::TextureUnit unit) {
@@ -333,11 +309,4 @@ void SpriteAtlas::bind(bool linear, gl::Context& context, gl::TextureUnit unit)
linear ? gl::TextureFilter::Linear : gl::TextureFilter::Nearest);
}
-SpriteAtlas::Holder::Holder(std::shared_ptr<const SpriteImage> spriteImage_, Rect<uint16_t> pos_)
- : spriteImage(std::move(spriteImage_)), pos(std::move(pos_)) {
-}
-
-SpriteAtlas::Holder::Holder(Holder&& h) : spriteImage(std::move(h.spriteImage)), pos(h.pos) {
-}
-
} // namespace mbgl
diff --git a/src/mbgl/sprite/sprite_atlas.hpp b/src/mbgl/sprite/sprite_atlas.hpp
index c79aec135e..c7b266376b 100644
--- a/src/mbgl/sprite/sprite_atlas.hpp
+++ b/src/mbgl/sprite/sprite_atlas.hpp
@@ -10,7 +10,7 @@
#include <string>
#include <map>
#include <mutex>
-#include <unordered_set>
+#include <unordered_map>
#include <array>
#include <memory>
@@ -23,26 +23,17 @@ namespace gl {
class Context;
} // namespace gl
-class SpriteImage;
-class SpritePosition;
-
-class SpriteAtlasPosition {
-public:
- std::array<float, 2> size = {{ 0, 0 }};
- std::array<float, 2> tl = {{ 0, 0 }};
- std::array<float, 2> br = {{ 0, 0 }};
-};
-
class SpriteAtlasElement {
public:
+ SpriteAtlasElement(Rect<uint16_t>, std::shared_ptr<const SpriteImage>, Size size, float pixelRatio);
+
Rect<uint16_t> pos;
std::shared_ptr<const SpriteImage> spriteImage;
- float relativePixelRatio;
-};
-enum class SpritePatternMode : bool {
- Single = false,
- Repeating = true,
+ float relativePixelRatio;
+ std::array<float, 2> size;
+ std::array<float, 2> tl;
+ std::array<float, 2> br;
};
class SpriteAtlas : public util::noncopyable {
@@ -62,32 +53,17 @@ public:
void setObserver(SpriteAtlasObserver*);
- // Adds/replaces a Sprite image.
void setSprite(const std::string&, std::shared_ptr<const SpriteImage>);
-
- // Adds/replaces mutliple Sprite images.
- void setSprites(const Sprites& sprites);
-
- // Removes a Sprite.
void removeSprite(const std::string&);
- // Obtains a Sprite image.
std::shared_ptr<const SpriteImage> getSprite(const std::string&);
- // If the sprite is loaded, copies the requsted image from it into the atlas and returns
- // the resulting icon measurements. If not, returns an empty optional.
- optional<SpriteAtlasElement> getImage(const std::string& name, SpritePatternMode mode);
-
- // This function is used for getting the position during render time.
- optional<SpriteAtlasPosition> getPosition(const std::string& name,
- SpritePatternMode mode = SpritePatternMode::Single);
+ optional<SpriteAtlasElement> getIcon(const std::string& name);
+ optional<SpriteAtlasElement> getPattern(const std::string& name);
// Binds the atlas texture to the GPU, and uploads data if it is out of date.
void bind(bool linear, gl::Context&, gl::TextureUnit unit);
- // Updates sprites in the atlas texture that may have changed.
- void updateDirty();
-
// Uploads the texture to the GPU to be available when we need it. This is a lazy operation;
// the texture is only bound when the data is out of date (=dirty).
void upload(gl::Context&, gl::TextureUnit unit);
@@ -96,6 +72,7 @@ public:
float getPixelRatio() const { return pixelRatio; }
// Only for use in tests.
+ void setSprites(const Sprites& sprites);
const PremultipliedImage& getAtlasImage() const {
return image;
}
@@ -104,6 +81,7 @@ private:
void _setSprite(const std::string&, const std::shared_ptr<const SpriteImage>& = nullptr);
void emitSpriteLoadedIfComplete();
+
const Size size;
const float pixelRatio;
@@ -114,35 +92,26 @@ private:
SpriteAtlasObserver* observer = nullptr;
- // Lock for sprites and dirty maps.
- std::mutex mutex;
-
- // Stores all current sprites.
- Sprites sprites;
-
- // Stores all Sprite IDs that changed since the last invocation.
- Sprites dirtySprites;
-
- struct Holder : private util::noncopyable {
- Holder(std::shared_ptr<const SpriteImage>, Rect<uint16_t>);
- Holder(Holder&&);
+ struct Entry {
std::shared_ptr<const SpriteImage> spriteImage;
- const Rect<uint16_t> pos;
- };
- using Key = std::pair<std::string, SpritePatternMode>;
+ // One sprite image might be used as both an icon image and a pattern image. If so,
+ // it must have two distinct entries in the texture. The one for the icon image has
+ // a single pixel transparent border, and the one for the pattern image has a single
+ // pixel border wrapped from the opposite side.
+ optional<Rect<uint16_t>> iconRect;
+ optional<Rect<uint16_t>> patternRect;
+ };
- Rect<uint16_t> allocateImage(const SpriteImage&);
- void copy(const Holder& holder, SpritePatternMode mode);
+ optional<SpriteAtlasElement> getImage(const std::string& name, optional<Rect<uint16_t>> Entry::*rect);
+ void copy(const Entry&, optional<Rect<uint16_t>> Entry::*rect);
- std::recursive_mutex mtx;
+ std::mutex mutex;
+ std::unordered_map<std::string, Entry> entries;
BinPack<uint16_t> bin;
- std::map<Key, Holder> images;
- std::unordered_set<std::string> uninitialized;
PremultipliedImage image;
mbgl::optional<gl::Texture> texture;
std::atomic<bool> dirty;
- static const int buffer = 1;
};
} // namespace mbgl
diff --git a/src/mbgl/sprite/sprite_parser.cpp b/src/mbgl/sprite/sprite_parser.cpp
index 9de8515e14..66b5ec0606 100644
--- a/src/mbgl/sprite/sprite_parser.cpp
+++ b/src/mbgl/sprite/sprite_parser.cpp
@@ -34,17 +34,8 @@ SpriteImagePtr createSpriteImage(const PremultipliedImage& image,
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 (uint32_t y = 0; y < height; ++y) {
- const auto dstRow = y * width;
- const auto srcRow = (y + srcY) * image.size.width + srcX;
- for (uint32_t x = 0; x < width; ++x) {
- dstData[dstRow + x] = srcData[srcRow + x];
- }
- }
+ PremultipliedImage::copy(image, dstImage, { srcX, srcY }, { 0, 0 }, { width, height });
return std::make_unique<const SpriteImage>(std::move(dstImage), ratio, sdf);
}
diff --git a/src/mbgl/storage/local_file_source.hpp b/src/mbgl/storage/local_file_source.hpp
index 5d665c3848..43319bc06e 100644
--- a/src/mbgl/storage/local_file_source.hpp
+++ b/src/mbgl/storage/local_file_source.hpp
@@ -14,7 +14,7 @@ public:
~LocalFileSource() override;
std::unique_ptr<AsyncRequest> request(const Resource&, Callback) override;
-
+
static bool acceptsURL(const std::string& url);
private:
diff --git a/src/mbgl/style/bucket_parameters.cpp b/src/mbgl/style/bucket_parameters.cpp
index e641120c5e..2b02ac4a4a 100644
--- a/src/mbgl/style/bucket_parameters.cpp
+++ b/src/mbgl/style/bucket_parameters.cpp
@@ -1,21 +1,7 @@
#include <mbgl/style/bucket_parameters.hpp>
-#include <mbgl/style/filter_evaluator.hpp>
-#include <mbgl/tile/geometry_tile_data.hpp>
namespace mbgl {
namespace style {
-void BucketParameters::eachFilteredFeature(const Filter& filter,
- const GeometryTileLayer& layer,
- std::function<void (const GeometryTileFeature&, std::size_t index, const std::string& layerName)> function) {
- auto name = layer.getName();
- for (std::size_t i = 0; !cancelled() && i < layer.featureCount(); i++) {
- auto feature = layer.getFeature(i);
- if (!filter(feature->getType(), feature->getID(), [&] (const auto& key) { return feature->getValue(key); }))
- continue;
- function(*feature, i, name);
- }
-}
-
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/bucket_parameters.hpp b/src/mbgl/style/bucket_parameters.hpp
index d5e05c5dd2..d0edbcac30 100644
--- a/src/mbgl/style/bucket_parameters.hpp
+++ b/src/mbgl/style/bucket_parameters.hpp
@@ -2,33 +2,14 @@
#include <mbgl/map/mode.hpp>
#include <mbgl/tile/tile_id.hpp>
-#include <mbgl/style/filter.hpp>
-
-#include <atomic>
-#include <functional>
namespace mbgl {
-
-class GeometryTileLayer;
-class GeometryTileFeature;
-class FeatureIndex;
-
namespace style {
class BucketParameters {
public:
- const OverscaledTileID& tileID;
- const std::atomic<bool>& obsolete;
- FeatureIndex& featureIndex;
+ const OverscaledTileID tileID;
const MapMode mode;
-
- bool cancelled() const {
- return obsolete;
- }
-
- void eachFilteredFeature(const Filter&,
- const GeometryTileLayer&,
- std::function<void (const GeometryTileFeature&, std::size_t index, const std::string& layerName)>);
};
} // namespace style
diff --git a/src/mbgl/style/conversion/stringify.hpp b/src/mbgl/style/conversion/stringify.hpp
index d06b2f2814..4afbf198e5 100644
--- a/src/mbgl/style/conversion/stringify.hpp
+++ b/src/mbgl/style/conversion/stringify.hpp
@@ -103,6 +103,29 @@ void stringify(Writer& writer, const Value& v) {
}
template <class Writer>
+void stringify(Writer& writer, FeatureType type) {
+ switch (type) {
+ case FeatureType::Unknown:
+ writer.String("Unknown");
+ break;
+ case FeatureType::Point:
+ writer.String("Point");
+ break;
+ case FeatureType::LineString:
+ writer.String("LineString");
+ break;
+ case FeatureType::Polygon:
+ writer.String("Polygon");
+ break;
+ }
+}
+
+template <class Writer>
+void stringify(Writer& writer, const FeatureIdentifier& id) {
+ FeatureIdentifier::visit(id, [&] (const auto& id_) { stringify(writer, id_); });
+}
+
+template <class Writer>
class StringifyFilter {
public:
Writer& writer;
@@ -156,28 +179,78 @@ public:
}
void operator()(const HasFilter& f) {
- stringifyUnaryFilter(f, "has");
+ stringifyUnaryFilter("has", f.key);
}
void operator()(const NotHasFilter& f) {
- stringifyUnaryFilter(f, "!has");
+ stringifyUnaryFilter("!has", f.key);
+ }
+
+ void operator()(const TypeEqualsFilter& f) {
+ stringifyBinaryFilter(f, "==", "$type");
+ }
+
+ void operator()(const TypeNotEqualsFilter& f) {
+ stringifyBinaryFilter(f, "!=", "$type");
+ }
+
+ void operator()(const TypeInFilter& f) {
+ stringifySetFilter(f, "in", "$type");
+ }
+
+ void operator()(const TypeNotInFilter& f) {
+ stringifySetFilter(f, "!in", "$type");
+ }
+
+ void operator()(const IdentifierEqualsFilter& f) {
+ stringifyBinaryFilter(f, "==", "$id");
+ }
+
+ void operator()(const IdentifierNotEqualsFilter& f) {
+ stringifyBinaryFilter(f, "!=", "$id");
+ }
+
+ void operator()(const IdentifierInFilter& f) {
+ stringifySetFilter(f, "in", "$id");
+ }
+
+ void operator()(const IdentifierNotInFilter& f) {
+ stringifySetFilter(f, "!in", "$id");
+ }
+
+ void operator()(const HasIdentifierFilter&) {
+ stringifyUnaryFilter("has", "$id");
+ }
+
+ void operator()(const NotHasIdentifierFilter&) {
+ stringifyUnaryFilter("!has", "$id");
}
private:
template <class F>
void stringifyBinaryFilter(const F& f, const char * op) {
+ stringifyBinaryFilter(f, op, f.key);
+ }
+
+ template <class F>
+ void stringifyBinaryFilter(const F& f, const char * op, const std::string& key) {
writer.StartArray();
writer.String(op);
- writer.String(f.key);
+ writer.String(key);
stringify(writer, f.value);
writer.EndArray();
}
template <class F>
void stringifySetFilter(const F& f, const char * op) {
+ stringifySetFilter(f, op, f.key);
+ }
+
+ template <class F>
+ void stringifySetFilter(const F& f, const char * op, const std::string& key) {
writer.StartArray();
writer.String(op);
- writer.String(f.key);
+ writer.String(key);
for (const auto& value : f.values) {
stringify(writer, value);
}
@@ -194,11 +267,10 @@ private:
writer.EndArray();
}
- template <class F>
- void stringifyUnaryFilter(const F& f, const char * op) {
+ void stringifyUnaryFilter(const char * op, const std::string& key) {
writer.StartArray();
writer.String(op);
- writer.String(f.key);
+ writer.String(key);
writer.EndArray();
}
};
@@ -214,20 +286,137 @@ void stringify(Writer& writer, const Undefined&) {
writer.Null();
}
-template <class Writer, class T>
-void stringify(Writer& writer, const Function<T>& f) {
- writer.StartObject();
- writer.Key("base");
- writer.Double(f.getBase());
- writer.Key("stops");
- writer.StartArray();
- for (const auto& stop : f.getStops()) {
+template <class Writer>
+void stringify(Writer& writer, const CategoricalValue& v) {
+ CategoricalValue::visit(v, [&] (const auto& v_) { stringify(writer, v_); });
+}
+
+template <class Writer>
+class StringifyStops {
+public:
+ Writer& writer;
+
+ template <class T>
+ void operator()(const ExponentialStops<T>& f) {
+ writer.Key("type");
+ writer.String("exponential");
+ writer.Key("base");
+ writer.Double(f.base);
+ writer.Key("stops");
+ stringifyStops(f.stops);
+ }
+
+ template <class T>
+ void operator()(const IntervalStops<T>& f) {
+ writer.Key("type");
+ writer.String("interval");
+ writer.Key("stops");
+ stringifyStops(f.stops);
+ }
+
+ template <class T>
+ void operator()(const CategoricalStops<T>& f) {
+ writer.Key("type");
+ writer.String("categorical");
+ writer.Key("stops");
+ stringifyStops(f.stops);
+ }
+
+ template <class T>
+ void operator()(const IdentityStops<T>&) {
+ writer.Key("type");
+ writer.String("identity");
+ }
+
+ template <class T>
+ void operator()(const CompositeExponentialStops<T>& f) {
+ writer.Key("type");
+ writer.String("exponential");
+ writer.Key("base");
+ writer.Double(f.base);
+ writer.Key("stops");
+ stringifyCompositeStops(f.stops);
+ }
+
+ template <class T>
+ void operator()(const CompositeIntervalStops<T>& f) {
+ writer.Key("type");
+ writer.String("interval");
+ writer.Key("stops");
+ stringifyCompositeStops(f.stops);
+ }
+
+ template <class T>
+ void operator()(const CompositeCategoricalStops<T>& f) {
+ writer.Key("type");
+ writer.String("categorical");
+ writer.Key("stops");
+ stringifyCompositeStops(f.stops);
+ }
+
+private:
+ template <class K, class V>
+ void stringifyStops(const std::map<K, V>& stops) {
writer.StartArray();
- writer.Double(stop.first);
- stringify(writer, stop.second);
+ for (const auto& stop : stops) {
+ writer.StartArray();
+ stringify(writer, stop.first);
+ stringify(writer, stop.second);
+ writer.EndArray();
+ }
writer.EndArray();
}
- writer.EndArray();
+
+ template <class InnerStops>
+ void stringifyCompositeStops(const std::map<float, InnerStops>& stops) {
+ writer.StartArray();
+ for (const auto& outer : stops) {
+ for (const auto& inner : outer.second) {
+ writer.StartArray();
+ writer.StartObject();
+ writer.Key("zoom");
+ writer.Double(outer.first);
+ writer.Key("value");
+ stringify(writer, inner.first);
+ writer.EndObject();
+ stringify(writer, inner.second);
+ writer.EndArray();
+ }
+ }
+ writer.EndArray();
+ }
+};
+
+template <class Writer, class T>
+void stringify(Writer& writer, const CameraFunction<T>& f) {
+ writer.StartObject();
+ CameraFunction<T>::Stops::visit(f.stops, StringifyStops<Writer> { writer });
+ writer.EndObject();
+}
+
+template <class Writer, class T>
+void stringify(Writer& writer, const SourceFunction<T>& f) {
+ writer.StartObject();
+ writer.Key("property");
+ writer.String(f.property);
+ SourceFunction<T>::Stops::visit(f.stops, StringifyStops<Writer> { writer });
+ if (f.defaultValue) {
+ writer.Key("default");
+ stringify(writer, *f.defaultValue);
+ }
+ writer.EndObject();
+}
+
+template <class Writer, class T>
+void stringify(Writer& writer, const CompositeFunction<T>& f) {
+ writer.StartObject();
+ writer.Key("property");
+ writer.String(f.property);
+ CompositeFunction<T>::Stops::visit(f.stops, StringifyStops<Writer> { writer });
+ if (f.defaultValue) {
+ writer.Key("default");
+ stringify(writer, *f.defaultValue);
+ }
writer.EndObject();
}
@@ -238,7 +427,20 @@ void stringify(Writer& writer, const PropertyValue<T>& v) {
template <class Property, class Writer, class T>
void stringify(Writer& writer, const PropertyValue<T>& value) {
- if (value) {
+ if (!value.isUndefined()) {
+ writer.Key(Property::key);
+ stringify(writer, value);
+ }
+}
+
+template <class Writer, class T>
+void stringify(Writer& writer, const DataDrivenPropertyValue<T>& v) {
+ v.evaluate([&] (const auto& v_) { stringify(writer, v_); });
+}
+
+template <class Property, class Writer, class T>
+void stringify(Writer& writer, const DataDrivenPropertyValue<T>& value) {
+ if (!value.isUndefined()) {
writer.Key(Property::key);
stringify(writer, value);
}
diff --git a/src/mbgl/style/cross_faded_property_evaluator.cpp b/src/mbgl/style/cross_faded_property_evaluator.cpp
index 4de939576e..796ca00bbf 100644
--- a/src/mbgl/style/cross_faded_property_evaluator.cpp
+++ b/src/mbgl/style/cross_faded_property_evaluator.cpp
@@ -17,21 +17,10 @@ Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const T& constant) const {
}
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));
+Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const CameraFunction<T>& function) const {
+ return calculate(function.evaluate(parameters.z - 1.0f),
+ function.evaluate(parameters.z),
+ function.evaluate(parameters.z + 1.0f));
}
template <typename T>
diff --git a/src/mbgl/style/cross_faded_property_evaluator.hpp b/src/mbgl/style/cross_faded_property_evaluator.hpp
index 70c8c0c978..c5642f5cfb 100644
--- a/src/mbgl/style/cross_faded_property_evaluator.hpp
+++ b/src/mbgl/style/cross_faded_property_evaluator.hpp
@@ -28,7 +28,7 @@ public:
Faded<T> operator()(const Undefined&) const;
Faded<T> operator()(const T& constant) const;
- Faded<T> operator()(const Function<T>&) const;
+ Faded<T> operator()(const CameraFunction<T>&) const;
private:
Faded<T> calculate(const T& min, const T& mid, const T& max) const;
diff --git a/src/mbgl/style/data_driven_property_evaluator.hpp b/src/mbgl/style/data_driven_property_evaluator.hpp
new file mode 100644
index 0000000000..7a0ff9a094
--- /dev/null
+++ b/src/mbgl/style/data_driven_property_evaluator.hpp
@@ -0,0 +1,42 @@
+#pragma once
+
+#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/property_evaluation_parameters.hpp>
+#include <mbgl/style/possibly_evaluated_property_value.hpp>
+
+namespace mbgl {
+namespace style {
+
+template <typename T>
+class DataDrivenPropertyEvaluator {
+public:
+ using ResultType = PossiblyEvaluatedPropertyValue<T>;
+
+ DataDrivenPropertyEvaluator(const PropertyEvaluationParameters& parameters_, T defaultValue_)
+ : parameters(parameters_),
+ defaultValue(std::move(defaultValue_)) {}
+
+ ResultType operator()(const Undefined&) const {
+ return ResultType(defaultValue);
+ }
+
+ ResultType operator()(const T& constant) const {
+ return ResultType(constant);
+ }
+
+ ResultType operator()(const CameraFunction<T>& function) const {
+ return ResultType(function.evaluate(parameters.z));
+ }
+
+ template <class Function>
+ ResultType operator()(const Function& function) const {
+ return ResultType(function);
+ }
+
+private:
+ const PropertyEvaluationParameters& parameters;
+ T defaultValue;
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/function.cpp b/src/mbgl/style/function.cpp
deleted file mode 100644
index 02750c7d2e..0000000000
--- a/src/mbgl/style/function.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-#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/function/categorical_stops.cpp b/src/mbgl/style/function/categorical_stops.cpp
new file mode 100644
index 0000000000..2984c3832f
--- /dev/null
+++ b/src/mbgl/style/function/categorical_stops.cpp
@@ -0,0 +1,38 @@
+#include <mbgl/style/function/categorical_stops.hpp>
+#include <mbgl/style/types.hpp>
+#include <mbgl/util/color.hpp>
+
+#include <array>
+
+namespace mbgl {
+namespace style {
+
+optional<CategoricalValue> categoricalValue(const Value& value) {
+ return value.match(
+ [] (bool t) { return optional<CategoricalValue>(t); },
+ [] (uint64_t t) { return optional<CategoricalValue>(int64_t(t)); },
+ [] (int64_t t) { return optional<CategoricalValue>(t); },
+ [] (double t) { return optional<CategoricalValue>(int64_t(t)); },
+ [] (const std::string& t) { return optional<CategoricalValue>(t); },
+ [] (const auto&) { return optional<CategoricalValue>(); }
+ );
+}
+
+template <class T>
+optional<T> CategoricalStops<T>::evaluate(const Value& value) const {
+ auto v = categoricalValue(value);
+ if (!v) {
+ return {};
+ }
+ auto it = stops.find(*v);
+ return it == stops.end() ? optional<T>() : it->second;
+}
+
+template class CategoricalStops<float>;
+template class CategoricalStops<Color>;
+template class CategoricalStops<std::array<float, 2>>;
+template class CategoricalStops<std::string>;
+template class CategoricalStops<TextTransformType>;
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/function/identity_stops.cpp b/src/mbgl/style/function/identity_stops.cpp
new file mode 100644
index 0000000000..dfb34e9dd4
--- /dev/null
+++ b/src/mbgl/style/function/identity_stops.cpp
@@ -0,0 +1,61 @@
+#include <mbgl/style/function/identity_stops.hpp>
+#include <mbgl/style/types.hpp>
+#include <mbgl/util/enum.hpp>
+#include <mbgl/util/color.hpp>
+
+#include <array>
+
+namespace mbgl {
+namespace style {
+
+template <>
+optional<float> IdentityStops<float>::evaluate(const Value& value) const {
+ return numericValue<float>(value);
+}
+
+template <>
+optional<std::string> IdentityStops<std::string>::evaluate(const Value& value) const {
+ if (!value.is<std::string>()) {
+ return {};
+ }
+
+ return value.get<std::string>();
+}
+
+template <>
+optional<Color> IdentityStops<Color>::evaluate(const Value& value) const {
+ if (!value.is<std::string>()) {
+ return {};
+ }
+
+ return Color::parse(value.get<std::string>());
+}
+
+template <>
+optional<TextTransformType> IdentityStops<TextTransformType>::evaluate(const Value& value) const {
+ if (!value.is<std::string>()) {
+ return {};
+ }
+
+ return Enum<TextTransformType>::toEnum(value.get<std::string>());
+}
+
+template <>
+optional<std::array<float, 2>> IdentityStops<std::array<float, 2>>::evaluate(const Value& value) const {
+ if (!value.is<std::vector<Value>>()) {
+ return {};
+ }
+
+ const std::vector<Value>& vector = value.get<std::vector<Value>>();
+ if (vector.size() != 2 || !numericValue<float>(vector[0]) || !numericValue<float>(vector[1])) {
+ return {};
+ }
+
+ return {{{
+ *numericValue<float>(vector[0]),
+ *numericValue<float>(vector[1])
+ }}};
+}
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/layer_impl.hpp b/src/mbgl/style/layer_impl.hpp
index 0fea70c10b..9b2bfe4d2c 100644
--- a/src/mbgl/style/layer_impl.hpp
+++ b/src/mbgl/style/layer_impl.hpp
@@ -61,7 +61,7 @@ public:
// Returns true if any paint properties have active transitions.
virtual bool evaluate(const PropertyEvaluationParameters&) = 0;
- virtual std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const = 0;
+ virtual std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const = 0;
// Checks whether this layer needs to be rendered in the given render pass.
bool hasRenderPass(RenderPass) const;
diff --git a/src/mbgl/style/layer_observer.hpp b/src/mbgl/style/layer_observer.hpp
index a3f9ca7528..2fa1c39660 100644
--- a/src/mbgl/style/layer_observer.hpp
+++ b/src/mbgl/style/layer_observer.hpp
@@ -12,6 +12,7 @@ public:
virtual void onLayerFilterChanged(Layer&) {}
virtual void onLayerVisibilityChanged(Layer&) {}
virtual void onLayerPaintPropertyChanged(Layer&) {}
+ virtual void onLayerDataDrivenPaintPropertyChanged(Layer&) {}
virtual void onLayerLayoutPropertyChanged(Layer&, const char *) {}
};
diff --git a/src/mbgl/style/layers/background_layer.cpp b/src/mbgl/style/layers/background_layer.cpp
index a75038bfa0..5a903f1b6b 100644
--- a/src/mbgl/style/layers/background_layer.cpp
+++ b/src/mbgl/style/layers/background_layer.cpp
@@ -55,6 +55,10 @@ void BackgroundLayer::setBackgroundColor(PropertyValue<Color> value, const optio
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void BackgroundLayer::setBackgroundColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<BackgroundColor>(value, klass);
+}
+
PropertyValue<std::string> BackgroundLayer::getDefaultBackgroundPattern() {
return { "" };
}
@@ -70,6 +74,10 @@ void BackgroundLayer::setBackgroundPattern(PropertyValue<std::string> value, con
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void BackgroundLayer::setBackgroundPatternTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<BackgroundPattern>(value, klass);
+}
+
PropertyValue<float> BackgroundLayer::getDefaultBackgroundOpacity() {
return { 1 };
}
@@ -85,5 +93,9 @@ void BackgroundLayer::setBackgroundOpacity(PropertyValue<float> value, const opt
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void BackgroundLayer::setBackgroundOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<BackgroundOpacity>(value, klass);
+}
+
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layers/background_layer_impl.cpp b/src/mbgl/style/layers/background_layer_impl.cpp
index 4a8fe39c9a..f25ba9cfb4 100644
--- a/src/mbgl/style/layers/background_layer_impl.cpp
+++ b/src/mbgl/style/layers/background_layer_impl.cpp
@@ -16,7 +16,8 @@ bool BackgroundLayer::Impl::evaluate(const PropertyEvaluationParameters& paramet
return paint.hasTransition();
}
-std::unique_ptr<Bucket> BackgroundLayer::Impl::createBucket(BucketParameters&, const GeometryTileLayer&) const {
+std::unique_ptr<Bucket> BackgroundLayer::Impl::createBucket(const BucketParameters&, const std::vector<const Layer*>&) const {
+ assert(false);
return nullptr;
}
diff --git a/src/mbgl/style/layers/background_layer_impl.hpp b/src/mbgl/style/layers/background_layer_impl.hpp
index 4629217e6d..02a8c423d6 100644
--- a/src/mbgl/style/layers/background_layer_impl.hpp
+++ b/src/mbgl/style/layers/background_layer_impl.hpp
@@ -16,7 +16,7 @@ public:
void cascade(const CascadeParameters&) override;
bool evaluate(const PropertyEvaluationParameters&) override;
- std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const override;
+ std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const override;
BackgroundPaintProperties paint;
};
diff --git a/src/mbgl/style/layers/background_layer_properties.hpp b/src/mbgl/style/layers/background_layer_properties.hpp
index 792bf3de94..fae6c26a4b 100644
--- a/src/mbgl/style/layers/background_layer_properties.hpp
+++ b/src/mbgl/style/layers/background_layer_properties.hpp
@@ -5,6 +5,7 @@
#include <mbgl/style/types.hpp>
#include <mbgl/style/layout_property.hpp>
#include <mbgl/style/paint_property.hpp>
+#include <mbgl/programs/attributes.hpp>
namespace mbgl {
namespace style {
diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp
index 389ab93403..53248e9397 100644
--- a/src/mbgl/style/layers/circle_layer.cpp
+++ b/src/mbgl/style/layers/circle_layer.cpp
@@ -65,64 +65,96 @@ const Filter& CircleLayer::getFilter() const {
// Paint properties
-PropertyValue<float> CircleLayer::getDefaultCircleRadius() {
+DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleRadius() {
return { 5 };
}
-PropertyValue<float> CircleLayer::getCircleRadius(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> CircleLayer::getCircleRadius(const optional<std::string>& klass) const {
return impl->paint.get<CircleRadius>(klass);
}
-void CircleLayer::setCircleRadius(PropertyValue<float> value, const optional<std::string>& klass) {
+void CircleLayer::setCircleRadius(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getCircleRadius(klass))
return;
impl->paint.set<CircleRadius>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void CircleLayer::setCircleRadiusTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<CircleRadius>(value, klass);
}
-PropertyValue<Color> CircleLayer::getDefaultCircleColor() {
+DataDrivenPropertyValue<Color> CircleLayer::getDefaultCircleColor() {
return { Color::black() };
}
-PropertyValue<Color> CircleLayer::getCircleColor(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<Color> CircleLayer::getCircleColor(const optional<std::string>& klass) const {
return impl->paint.get<CircleColor>(klass);
}
-void CircleLayer::setCircleColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+void CircleLayer::setCircleColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getCircleColor(klass))
return;
impl->paint.set<CircleColor>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
}
-PropertyValue<float> CircleLayer::getDefaultCircleBlur() {
+void CircleLayer::setCircleColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<CircleColor>(value, klass);
+}
+
+DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleBlur() {
return { 0 };
}
-PropertyValue<float> CircleLayer::getCircleBlur(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> CircleLayer::getCircleBlur(const optional<std::string>& klass) const {
return impl->paint.get<CircleBlur>(klass);
}
-void CircleLayer::setCircleBlur(PropertyValue<float> value, const optional<std::string>& klass) {
+void CircleLayer::setCircleBlur(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getCircleBlur(klass))
return;
impl->paint.set<CircleBlur>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
}
-PropertyValue<float> CircleLayer::getDefaultCircleOpacity() {
+void CircleLayer::setCircleBlurTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<CircleBlur>(value, klass);
+}
+
+DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleOpacity() {
return { 1 };
}
-PropertyValue<float> CircleLayer::getCircleOpacity(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> CircleLayer::getCircleOpacity(const optional<std::string>& klass) const {
return impl->paint.get<CircleOpacity>(klass);
}
-void CircleLayer::setCircleOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
+void CircleLayer::setCircleOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getCircleOpacity(klass))
return;
impl->paint.set<CircleOpacity>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void CircleLayer::setCircleOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<CircleOpacity>(value, klass);
}
PropertyValue<std::array<float, 2>> CircleLayer::getDefaultCircleTranslate() {
@@ -140,6 +172,10 @@ void CircleLayer::setCircleTranslate(PropertyValue<std::array<float, 2>> value,
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void CircleLayer::setCircleTranslateTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<CircleTranslate>(value, klass);
+}
+
PropertyValue<TranslateAnchorType> CircleLayer::getDefaultCircleTranslateAnchor() {
return { TranslateAnchorType::Map };
}
@@ -155,6 +191,10 @@ void CircleLayer::setCircleTranslateAnchor(PropertyValue<TranslateAnchorType> va
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void CircleLayer::setCircleTranslateAnchorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<CircleTranslateAnchor>(value, klass);
+}
+
PropertyValue<CirclePitchScaleType> CircleLayer::getDefaultCirclePitchScale() {
return { CirclePitchScaleType::Map };
}
@@ -170,49 +210,77 @@ void CircleLayer::setCirclePitchScale(PropertyValue<CirclePitchScaleType> value,
impl->observer->onLayerPaintPropertyChanged(*this);
}
-PropertyValue<float> CircleLayer::getDefaultCircleStrokeWidth() {
+void CircleLayer::setCirclePitchScaleTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<CirclePitchScale>(value, klass);
+}
+
+DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleStrokeWidth() {
return { 0 };
}
-PropertyValue<float> CircleLayer::getCircleStrokeWidth(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<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) {
+void CircleLayer::setCircleStrokeWidth(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getCircleStrokeWidth(klass))
return;
impl->paint.set<CircleStrokeWidth>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void CircleLayer::setCircleStrokeWidthTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<CircleStrokeWidth>(value, klass);
}
-PropertyValue<Color> CircleLayer::getDefaultCircleStrokeColor() {
+DataDrivenPropertyValue<Color> CircleLayer::getDefaultCircleStrokeColor() {
return { Color::black() };
}
-PropertyValue<Color> CircleLayer::getCircleStrokeColor(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<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) {
+void CircleLayer::setCircleStrokeColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getCircleStrokeColor(klass))
return;
impl->paint.set<CircleStrokeColor>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void CircleLayer::setCircleStrokeColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<CircleStrokeColor>(value, klass);
}
-PropertyValue<float> CircleLayer::getDefaultCircleStrokeOpacity() {
+DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleStrokeOpacity() {
return { 1 };
}
-PropertyValue<float> CircleLayer::getCircleStrokeOpacity(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<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) {
+void CircleLayer::setCircleStrokeOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getCircleStrokeOpacity(klass))
return;
impl->paint.set<CircleStrokeOpacity>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void CircleLayer::setCircleStrokeOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<CircleStrokeOpacity>(value, klass);
}
} // namespace style
diff --git a/src/mbgl/style/layers/circle_layer_impl.cpp b/src/mbgl/style/layers/circle_layer_impl.cpp
index 136522e41c..ea1d4eeb65 100644
--- a/src/mbgl/style/layers/circle_layer_impl.cpp
+++ b/src/mbgl/style/layers/circle_layer_impl.cpp
@@ -1,5 +1,4 @@
#include <mbgl/style/layers/circle_layer_impl.hpp>
-#include <mbgl/style/bucket_parameters.hpp>
#include <mbgl/renderer/circle_bucket.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/util/math.hpp>
@@ -15,27 +14,25 @@ void CircleLayer::Impl::cascade(const CascadeParameters& parameters) {
bool CircleLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) {
paint.evaluate(parameters);
- passes = (paint.evaluated.get<CircleRadius>() > 0 && paint.evaluated.get<CircleColor>().a > 0 && paint.evaluated.get<CircleOpacity>() > 0)
+ passes = ((paint.evaluated.get<CircleRadius>().constantOr(1) > 0 ||
+ paint.evaluated.get<CircleStrokeWidth>().constantOr(1) > 0)
+ && (paint.evaluated.get<CircleColor>().constantOr(Color::black()).a > 0 ||
+ paint.evaluated.get<CircleStrokeColor>().constantOr(Color::black()).a > 0)
+ && (paint.evaluated.get<CircleOpacity>().constantOr(1) > 0 ||
+ paint.evaluated.get<CircleStrokeOpacity>().constantOr(1) > 0))
? RenderPass::Translucent : RenderPass::None;
return paint.hasTransition();
}
-std::unique_ptr<Bucket> CircleLayer::Impl::createBucket(BucketParameters& parameters, const GeometryTileLayer& layer) const {
- auto bucket = std::make_unique<CircleBucket>(parameters.mode);
-
- parameters.eachFilteredFeature(filter, layer, [&] (const auto& feature, std::size_t index, const std::string& layerName) {
- auto geometries = feature.getGeometries();
- bucket->addGeometry(geometries);
- parameters.featureIndex.insert(geometries, index, layerName, id);
- });
-
- return std::move(bucket);
+std::unique_ptr<Bucket> CircleLayer::Impl::createBucket(const BucketParameters& parameters, const std::vector<const Layer*>& layers) const {
+ return std::make_unique<CircleBucket>(parameters, layers);
}
float CircleLayer::Impl::getQueryRadius() const {
const std::array<float, 2>& translate = paint.evaluated.get<CircleTranslate>();
- return paint.evaluated.get<CircleRadius>() + util::length(translate[0], translate[1]);
+ return paint.evaluated.get<CircleRadius>().constantOr(CircleRadius::defaultValue())
+ + util::length(translate[0], translate[1]);
}
bool CircleLayer::Impl::queryIntersectsGeometry(
@@ -47,7 +44,7 @@ bool CircleLayer::Impl::queryIntersectsGeometry(
auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry(
queryGeometry, paint.evaluated.get<CircleTranslate>(), paint.evaluated.get<CircleTranslateAnchor>(), bearing, pixelsToTileUnits);
- auto circleRadius = paint.evaluated.get<CircleRadius>() * pixelsToTileUnits;
+ auto circleRadius = paint.evaluated.get<CircleRadius>().constantOr(CircleRadius::defaultValue()) * 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 744a56898c..0f9611d589 100644
--- a/src/mbgl/style/layers/circle_layer_impl.hpp
+++ b/src/mbgl/style/layers/circle_layer_impl.hpp
@@ -16,7 +16,7 @@ public:
void cascade(const CascadeParameters&) override;
bool evaluate(const PropertyEvaluationParameters&) override;
- std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const override;
+ std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const override;
float getQueryRadius() const override;
bool queryIntersectsGeometry(
diff --git a/src/mbgl/style/layers/circle_layer_properties.hpp b/src/mbgl/style/layers/circle_layer_properties.hpp
index ea36b31949..1cb4f5a635 100644
--- a/src/mbgl/style/layers/circle_layer_properties.hpp
+++ b/src/mbgl/style/layers/circle_layer_properties.hpp
@@ -5,23 +5,24 @@
#include <mbgl/style/types.hpp>
#include <mbgl/style/layout_property.hpp>
#include <mbgl/style/paint_property.hpp>
+#include <mbgl/programs/attributes.hpp>
namespace mbgl {
namespace style {
-struct CircleRadius : PaintProperty<float> {
+struct CircleRadius : DataDrivenPaintProperty<float, attributes::a_radius> {
static float defaultValue() { return 5; }
};
-struct CircleColor : PaintProperty<Color> {
+struct CircleColor : DataDrivenPaintProperty<Color, attributes::a_color> {
static Color defaultValue() { return Color::black(); }
};
-struct CircleBlur : PaintProperty<float> {
+struct CircleBlur : DataDrivenPaintProperty<float, attributes::a_blur> {
static float defaultValue() { return 0; }
};
-struct CircleOpacity : PaintProperty<float> {
+struct CircleOpacity : DataDrivenPaintProperty<float, attributes::a_opacity> {
static float defaultValue() { return 1; }
};
@@ -37,15 +38,15 @@ struct CirclePitchScale : PaintProperty<CirclePitchScaleType> {
static CirclePitchScaleType defaultValue() { return CirclePitchScaleType::Map; }
};
-struct CircleStrokeWidth : PaintProperty<float> {
+struct CircleStrokeWidth : DataDrivenPaintProperty<float, attributes::a_stroke_width> {
static float defaultValue() { return 0; }
};
-struct CircleStrokeColor : PaintProperty<Color> {
+struct CircleStrokeColor : DataDrivenPaintProperty<Color, attributes::a_stroke_color> {
static Color defaultValue() { return Color::black(); }
};
-struct CircleStrokeOpacity : PaintProperty<float> {
+struct CircleStrokeOpacity : DataDrivenPaintProperty<float, attributes::a_stroke_opacity> {
static float defaultValue() { return 1; }
};
diff --git a/src/mbgl/style/layers/custom_layer_impl.cpp b/src/mbgl/style/layers/custom_layer_impl.cpp
index cecd60a296..379de25e8f 100644
--- a/src/mbgl/style/layers/custom_layer_impl.cpp
+++ b/src/mbgl/style/layers/custom_layer_impl.cpp
@@ -70,7 +70,8 @@ bool CustomLayer::Impl::evaluate(const PropertyEvaluationParameters&) {
return false;
}
-std::unique_ptr<Bucket> CustomLayer::Impl::createBucket(BucketParameters&, const GeometryTileLayer&) const {
+std::unique_ptr<Bucket> CustomLayer::Impl::createBucket(const BucketParameters&, const std::vector<const Layer*>&) const {
+ assert(false);
return nullptr;
}
diff --git a/src/mbgl/style/layers/custom_layer_impl.hpp b/src/mbgl/style/layers/custom_layer_impl.hpp
index 71fb46d0d9..33eb86828c 100644
--- a/src/mbgl/style/layers/custom_layer_impl.hpp
+++ b/src/mbgl/style/layers/custom_layer_impl.hpp
@@ -32,7 +32,7 @@ private:
void cascade(const CascadeParameters&) final {}
bool evaluate(const PropertyEvaluationParameters&) final;
- std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const final;
+ std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const final;
CustomLayerInitializeFunction initializeFn = nullptr;
CustomLayerRenderFunction renderFn = nullptr;
diff --git a/src/mbgl/style/layers/fill_extrusion_layer.cpp b/src/mbgl/style/layers/fill_extrusion_layer.cpp
index 34f0267d16..4672ede9b8 100644
--- a/src/mbgl/style/layers/fill_extrusion_layer.cpp
+++ b/src/mbgl/style/layers/fill_extrusion_layer.cpp
@@ -80,19 +80,31 @@ void FillExtrusionLayer::setFillExtrusionOpacity(PropertyValue<float> value, con
impl->observer->onLayerPaintPropertyChanged(*this);
}
-PropertyValue<Color> FillExtrusionLayer::getDefaultFillExtrusionColor() {
+void FillExtrusionLayer::setFillExtrusionOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillExtrusionOpacity>(value, klass);
+}
+
+DataDrivenPropertyValue<Color> FillExtrusionLayer::getDefaultFillExtrusionColor() {
return { Color::black() };
}
-PropertyValue<Color> FillExtrusionLayer::getFillExtrusionColor(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<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) {
+void FillExtrusionLayer::setFillExtrusionColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getFillExtrusionColor(klass))
return;
impl->paint.set<FillExtrusionColor>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void FillExtrusionLayer::setFillExtrusionColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillExtrusionColor>(value, klass);
}
PropertyValue<std::array<float, 2>> FillExtrusionLayer::getDefaultFillExtrusionTranslate() {
@@ -110,6 +122,10 @@ void FillExtrusionLayer::setFillExtrusionTranslate(PropertyValue<std::array<floa
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void FillExtrusionLayer::setFillExtrusionTranslateTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillExtrusionTranslate>(value, klass);
+}
+
PropertyValue<TranslateAnchorType> FillExtrusionLayer::getDefaultFillExtrusionTranslateAnchor() {
return { TranslateAnchorType::Map };
}
@@ -125,6 +141,10 @@ void FillExtrusionLayer::setFillExtrusionTranslateAnchor(PropertyValue<Translate
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void FillExtrusionLayer::setFillExtrusionTranslateAnchorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillExtrusionTranslateAnchor>(value, klass);
+}
+
PropertyValue<std::string> FillExtrusionLayer::getDefaultFillExtrusionPattern() {
return { "" };
}
@@ -140,34 +160,54 @@ void FillExtrusionLayer::setFillExtrusionPattern(PropertyValue<std::string> valu
impl->observer->onLayerPaintPropertyChanged(*this);
}
-PropertyValue<float> FillExtrusionLayer::getDefaultFillExtrusionHeight() {
+void FillExtrusionLayer::setFillExtrusionPatternTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillExtrusionPattern>(value, klass);
+}
+
+DataDrivenPropertyValue<float> FillExtrusionLayer::getDefaultFillExtrusionHeight() {
return { 0 };
}
-PropertyValue<float> FillExtrusionLayer::getFillExtrusionHeight(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<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) {
+void FillExtrusionLayer::setFillExtrusionHeight(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getFillExtrusionHeight(klass))
return;
impl->paint.set<FillExtrusionHeight>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void FillExtrusionLayer::setFillExtrusionHeightTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillExtrusionHeight>(value, klass);
}
-PropertyValue<float> FillExtrusionLayer::getDefaultFillExtrusionBase() {
+DataDrivenPropertyValue<float> FillExtrusionLayer::getDefaultFillExtrusionBase() {
return { 0 };
}
-PropertyValue<float> FillExtrusionLayer::getFillExtrusionBase(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<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) {
+void FillExtrusionLayer::setFillExtrusionBase(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getFillExtrusionBase(klass))
return;
impl->paint.set<FillExtrusionBase>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void FillExtrusionLayer::setFillExtrusionBaseTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillExtrusionBase>(value, klass);
}
} // namespace style
diff --git a/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp b/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp
index ebe9009312..a809820644 100644
--- a/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp
+++ b/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp
@@ -11,7 +11,7 @@ bool FillExtrusionLayer::Impl::evaluate(const PropertyEvaluationParameters&) {
return false;
}
-std::unique_ptr<Bucket> FillExtrusionLayer::Impl::createBucket(BucketParameters&, const GeometryTileLayer&) const {
+std::unique_ptr<Bucket> FillExtrusionLayer::Impl::createBucket(const BucketParameters&, const std::vector<const Layer*>&) const {
return nullptr;
}
diff --git a/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp b/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp
index 3dd8bb270a..ed7ef747fb 100644
--- a/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp
+++ b/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp
@@ -16,7 +16,7 @@ public:
void cascade(const CascadeParameters&) override;
bool evaluate(const PropertyEvaluationParameters&) override;
- std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const override;
+ std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const override;
FillExtrusionPaintProperties paint;
};
diff --git a/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp b/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp
index a2d01199a5..c1dd3b079d 100644
--- a/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp
+++ b/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp
@@ -5,6 +5,7 @@
#include <mbgl/style/types.hpp>
#include <mbgl/style/layout_property.hpp>
#include <mbgl/style/paint_property.hpp>
+#include <mbgl/programs/attributes.hpp>
namespace mbgl {
namespace style {
@@ -13,7 +14,7 @@ struct FillExtrusionOpacity : PaintProperty<float> {
static float defaultValue() { return 1; }
};
-struct FillExtrusionColor : PaintProperty<Color> {
+struct FillExtrusionColor : DataDrivenPaintProperty<Color, attributes::a_color> {
static Color defaultValue() { return Color::black(); }
};
@@ -29,11 +30,11 @@ struct FillExtrusionPattern : CrossFadedPaintProperty<std::string> {
static std::string defaultValue() { return ""; }
};
-struct FillExtrusionHeight : PaintProperty<float> {
+struct FillExtrusionHeight : DataDrivenPaintProperty<float, attributes::a_height> {
static float defaultValue() { return 0; }
};
-struct FillExtrusionBase : PaintProperty<float> {
+struct FillExtrusionBase : DataDrivenPaintProperty<float, attributes::a_base> {
static float defaultValue() { return 0; }
};
diff --git a/src/mbgl/style/layers/fill_layer.cpp b/src/mbgl/style/layers/fill_layer.cpp
index b8fa8cad8b..dfa88b5b0f 100644
--- a/src/mbgl/style/layers/fill_layer.cpp
+++ b/src/mbgl/style/layers/fill_layer.cpp
@@ -80,49 +80,77 @@ void FillLayer::setFillAntialias(PropertyValue<bool> value, const optional<std::
impl->observer->onLayerPaintPropertyChanged(*this);
}
-PropertyValue<float> FillLayer::getDefaultFillOpacity() {
+void FillLayer::setFillAntialiasTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillAntialias>(value, klass);
+}
+
+DataDrivenPropertyValue<float> FillLayer::getDefaultFillOpacity() {
return { 1 };
}
-PropertyValue<float> FillLayer::getFillOpacity(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> FillLayer::getFillOpacity(const optional<std::string>& klass) const {
return impl->paint.get<FillOpacity>(klass);
}
-void FillLayer::setFillOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
+void FillLayer::setFillOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getFillOpacity(klass))
return;
impl->paint.set<FillOpacity>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void FillLayer::setFillOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillOpacity>(value, klass);
}
-PropertyValue<Color> FillLayer::getDefaultFillColor() {
+DataDrivenPropertyValue<Color> FillLayer::getDefaultFillColor() {
return { Color::black() };
}
-PropertyValue<Color> FillLayer::getFillColor(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<Color> FillLayer::getFillColor(const optional<std::string>& klass) const {
return impl->paint.get<FillColor>(klass);
}
-void FillLayer::setFillColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+void FillLayer::setFillColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getFillColor(klass))
return;
impl->paint.set<FillColor>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void FillLayer::setFillColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillColor>(value, klass);
}
-PropertyValue<Color> FillLayer::getDefaultFillOutlineColor() {
+DataDrivenPropertyValue<Color> FillLayer::getDefaultFillOutlineColor() {
return { {} };
}
-PropertyValue<Color> FillLayer::getFillOutlineColor(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<Color> FillLayer::getFillOutlineColor(const optional<std::string>& klass) const {
return impl->paint.get<FillOutlineColor>(klass);
}
-void FillLayer::setFillOutlineColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+void FillLayer::setFillOutlineColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getFillOutlineColor(klass))
return;
impl->paint.set<FillOutlineColor>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void FillLayer::setFillOutlineColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillOutlineColor>(value, klass);
}
PropertyValue<std::array<float, 2>> FillLayer::getDefaultFillTranslate() {
@@ -140,6 +168,10 @@ void FillLayer::setFillTranslate(PropertyValue<std::array<float, 2>> value, cons
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void FillLayer::setFillTranslateTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillTranslate>(value, klass);
+}
+
PropertyValue<TranslateAnchorType> FillLayer::getDefaultFillTranslateAnchor() {
return { TranslateAnchorType::Map };
}
@@ -155,6 +187,10 @@ void FillLayer::setFillTranslateAnchor(PropertyValue<TranslateAnchorType> value,
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void FillLayer::setFillTranslateAnchorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillTranslateAnchor>(value, klass);
+}
+
PropertyValue<std::string> FillLayer::getDefaultFillPattern() {
return { "" };
}
@@ -170,5 +206,9 @@ void FillLayer::setFillPattern(PropertyValue<std::string> value, const optional<
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void FillLayer::setFillPatternTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillPattern>(value, klass);
+}
+
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layers/fill_layer_impl.cpp b/src/mbgl/style/layers/fill_layer_impl.cpp
index 51636820f0..c7c89f8c20 100644
--- a/src/mbgl/style/layers/fill_layer_impl.cpp
+++ b/src/mbgl/style/layers/fill_layer_impl.cpp
@@ -1,5 +1,4 @@
#include <mbgl/style/layers/fill_layer_impl.hpp>
-#include <mbgl/style/bucket_parameters.hpp>
#include <mbgl/renderer/fill_bucket.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/util/math.hpp>
@@ -15,13 +14,19 @@ void FillLayer::Impl::cascade(const CascadeParameters& parameters) {
bool FillLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) {
paint.evaluate(parameters);
+ if (paint.unevaluated.get<FillOutlineColor>().isUndefined()) {
+ paint.evaluated.get<FillOutlineColor>() = paint.evaluated.get<FillColor>();
+ }
+
passes = RenderPass::None;
if (paint.evaluated.get<FillAntialias>()) {
passes |= RenderPass::Translucent;
}
- if (!paint.evaluated.get<FillPattern>().from.empty() || (paint.evaluated.get<FillColor>().a * paint.evaluated.get<FillOpacity>()) < 1.0f) {
+ if (!paint.unevaluated.get<FillPattern>().isUndefined()
+ || paint.evaluated.get<FillColor>().constantOr(Color()).a < 1.0f
+ || paint.evaluated.get<FillOpacity>().constantOr(0) < 1.0f) {
passes |= RenderPass::Translucent;
} else {
passes |= RenderPass::Opaque;
@@ -30,16 +35,8 @@ bool FillLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) {
return paint.hasTransition();
}
-std::unique_ptr<Bucket> FillLayer::Impl::createBucket(BucketParameters& parameters, const GeometryTileLayer& layer) const {
- auto bucket = std::make_unique<FillBucket>();
-
- parameters.eachFilteredFeature(filter, layer, [&] (const auto& feature, std::size_t index, const std::string& layerName) {
- auto geometries = feature.getGeometries();
- bucket->addGeometry(geometries);
- parameters.featureIndex.insert(geometries, index, layerName, id);
- });
-
- return std::move(bucket);
+std::unique_ptr<Bucket> FillLayer::Impl::createBucket(const BucketParameters& parameters, const std::vector<const Layer*>& layers) const {
+ return std::make_unique<FillBucket>(parameters, layers);
}
float FillLayer::Impl::getQueryRadius() const {
diff --git a/src/mbgl/style/layers/fill_layer_impl.hpp b/src/mbgl/style/layers/fill_layer_impl.hpp
index 28e2fa7edc..bd25a8bebf 100644
--- a/src/mbgl/style/layers/fill_layer_impl.hpp
+++ b/src/mbgl/style/layers/fill_layer_impl.hpp
@@ -16,7 +16,7 @@ public:
void cascade(const CascadeParameters&) override;
bool evaluate(const PropertyEvaluationParameters&) override;
- std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const override;
+ std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const override;
float getQueryRadius() const override;
bool queryIntersectsGeometry(
diff --git a/src/mbgl/style/layers/fill_layer_properties.hpp b/src/mbgl/style/layers/fill_layer_properties.hpp
index b2d926c31e..f44a18d0e0 100644
--- a/src/mbgl/style/layers/fill_layer_properties.hpp
+++ b/src/mbgl/style/layers/fill_layer_properties.hpp
@@ -5,6 +5,7 @@
#include <mbgl/style/types.hpp>
#include <mbgl/style/layout_property.hpp>
#include <mbgl/style/paint_property.hpp>
+#include <mbgl/programs/attributes.hpp>
namespace mbgl {
namespace style {
@@ -13,15 +14,15 @@ struct FillAntialias : PaintProperty<bool> {
static bool defaultValue() { return true; }
};
-struct FillOpacity : PaintProperty<float> {
+struct FillOpacity : DataDrivenPaintProperty<float, attributes::a_opacity> {
static float defaultValue() { return 1; }
};
-struct FillColor : PaintProperty<Color> {
+struct FillColor : DataDrivenPaintProperty<Color, attributes::a_color> {
static Color defaultValue() { return Color::black(); }
};
-struct FillOutlineColor : PaintProperty<Color> {
+struct FillOutlineColor : DataDrivenPaintProperty<Color, attributes::a_outline_color> {
static Color defaultValue() { return {}; }
};
diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs
index e730e3a29b..335573abf3 100644
--- a/src/mbgl/style/layers/layer.cpp.ejs
+++ b/src/mbgl/style/layers/layer.cpp.ejs
@@ -86,15 +86,15 @@ const Filter& <%- camelize(type) %>Layer::getFilter() const {
// Layout properties
<% for (const property of layoutProperties) { -%>
-PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::getDefault<%- camelize(property.name) %>() {
+<%- propertyValueType(property) %> <%- camelize(type) %>Layer::getDefault<%- camelize(property.name) %>() {
return <%- camelize(property.name) %>::defaultValue();
}
-PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>() const {
+<%- propertyValueType(property) %> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>() const {
return impl->layout.unevaluated.get<<%- camelize(property.name) %>>();
}
-void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(PropertyValue<<%- propertyType(property) %>> value) {
+void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(<%- propertyValueType(property) %> value) {
if (value == get<%- camelize(property.name) %>())
return;
impl->layout.unevaluated.get<<%- camelize(property.name) %>>() = value;
@@ -104,19 +104,31 @@ void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(PropertyValue
// Paint properties
<% for (const property of paintProperties) { %>
-PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::getDefault<%- camelize(property.name) %>() {
+<%- propertyValueType(property) %> <%- camelize(type) %>Layer::getDefault<%- camelize(property.name) %>() {
return { <%- defaultValue(property) %> };
}
-PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>(const optional<std::string>& klass) const {
+<%- propertyValueType(property) %> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>(const optional<std::string>& klass) const {
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) {
+void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(<%- propertyValueType(property) %> value, const optional<std::string>& klass) {
if (value == get<%- camelize(property.name) %>(klass))
return;
impl->paint.set<<%- camelize(property.name) %>>(value, klass);
+<% if (isDataDriven(property)) { -%>
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+<% } else { -%>
impl->observer->onLayerPaintPropertyChanged(*this);
+<% } -%>
+}
+
+void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>Transition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<<%- camelize(property.name) %>>(value, klass);
}
<% } -%>
diff --git a/src/mbgl/style/layers/layer_properties.hpp.ejs b/src/mbgl/style/layers/layer_properties.hpp.ejs
index d18ad44efd..2a736ca388 100644
--- a/src/mbgl/style/layers/layer_properties.hpp.ejs
+++ b/src/mbgl/style/layers/layer_properties.hpp.ejs
@@ -10,22 +10,21 @@
#include <mbgl/style/types.hpp>
#include <mbgl/style/layout_property.hpp>
#include <mbgl/style/paint_property.hpp>
+#include <mbgl/programs/attributes.hpp>
namespace mbgl {
namespace style {
<% for (const property of layoutProperties) { -%>
-struct <%- camelize(property.name) %> : LayoutProperty<<%- propertyType(property) %>> {
+struct <%- camelize(property.name) %> : <%- layoutPropertyType(property, type) %> {
static constexpr const char * key = "<%- property.name %>";
- static <%- propertyType(property) %> defaultValue() { return <%- defaultValue(property) %>; }
+ static <%- evaluatedType(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) %>; }
+struct <%- camelize(property.name) %> : <%- paintPropertyType(property, type) %> {
+ static <%- evaluatedType(property) %> defaultValue() { return <%- defaultValue(property) %>; }
};
<% } -%>
diff --git a/src/mbgl/style/layers/line_layer.cpp b/src/mbgl/style/layers/line_layer.cpp
index 7f6c148cd1..eaaa0fcd45 100644
--- a/src/mbgl/style/layers/line_layer.cpp
+++ b/src/mbgl/style/layers/line_layer.cpp
@@ -122,34 +122,50 @@ void LineLayer::setLineRoundLimit(PropertyValue<float> value) {
// Paint properties
-PropertyValue<float> LineLayer::getDefaultLineOpacity() {
+DataDrivenPropertyValue<float> LineLayer::getDefaultLineOpacity() {
return { 1 };
}
-PropertyValue<float> LineLayer::getLineOpacity(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> LineLayer::getLineOpacity(const optional<std::string>& klass) const {
return impl->paint.get<LineOpacity>(klass);
}
-void LineLayer::setLineOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
+void LineLayer::setLineOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getLineOpacity(klass))
return;
impl->paint.set<LineOpacity>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void LineLayer::setLineOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<LineOpacity>(value, klass);
}
-PropertyValue<Color> LineLayer::getDefaultLineColor() {
+DataDrivenPropertyValue<Color> LineLayer::getDefaultLineColor() {
return { Color::black() };
}
-PropertyValue<Color> LineLayer::getLineColor(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<Color> LineLayer::getLineColor(const optional<std::string>& klass) const {
return impl->paint.get<LineColor>(klass);
}
-void LineLayer::setLineColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+void LineLayer::setLineColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getLineColor(klass))
return;
impl->paint.set<LineColor>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void LineLayer::setLineColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<LineColor>(value, klass);
}
PropertyValue<std::array<float, 2>> LineLayer::getDefaultLineTranslate() {
@@ -167,6 +183,10 @@ void LineLayer::setLineTranslate(PropertyValue<std::array<float, 2>> value, cons
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void LineLayer::setLineTranslateTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<LineTranslate>(value, klass);
+}
+
PropertyValue<TranslateAnchorType> LineLayer::getDefaultLineTranslateAnchor() {
return { TranslateAnchorType::Map };
}
@@ -182,6 +202,10 @@ void LineLayer::setLineTranslateAnchor(PropertyValue<TranslateAnchorType> value,
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void LineLayer::setLineTranslateAnchorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<LineTranslateAnchor>(value, klass);
+}
+
PropertyValue<float> LineLayer::getDefaultLineWidth() {
return { 1 };
}
@@ -197,49 +221,77 @@ void LineLayer::setLineWidth(PropertyValue<float> value, const optional<std::str
impl->observer->onLayerPaintPropertyChanged(*this);
}
-PropertyValue<float> LineLayer::getDefaultLineGapWidth() {
+void LineLayer::setLineWidthTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<LineWidth>(value, klass);
+}
+
+DataDrivenPropertyValue<float> LineLayer::getDefaultLineGapWidth() {
return { 0 };
}
-PropertyValue<float> LineLayer::getLineGapWidth(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> LineLayer::getLineGapWidth(const optional<std::string>& klass) const {
return impl->paint.get<LineGapWidth>(klass);
}
-void LineLayer::setLineGapWidth(PropertyValue<float> value, const optional<std::string>& klass) {
+void LineLayer::setLineGapWidth(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getLineGapWidth(klass))
return;
impl->paint.set<LineGapWidth>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
}
-PropertyValue<float> LineLayer::getDefaultLineOffset() {
+void LineLayer::setLineGapWidthTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<LineGapWidth>(value, klass);
+}
+
+DataDrivenPropertyValue<float> LineLayer::getDefaultLineOffset() {
return { 0 };
}
-PropertyValue<float> LineLayer::getLineOffset(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> LineLayer::getLineOffset(const optional<std::string>& klass) const {
return impl->paint.get<LineOffset>(klass);
}
-void LineLayer::setLineOffset(PropertyValue<float> value, const optional<std::string>& klass) {
+void LineLayer::setLineOffset(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getLineOffset(klass))
return;
impl->paint.set<LineOffset>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
}
-PropertyValue<float> LineLayer::getDefaultLineBlur() {
+void LineLayer::setLineOffsetTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<LineOffset>(value, klass);
+}
+
+DataDrivenPropertyValue<float> LineLayer::getDefaultLineBlur() {
return { 0 };
}
-PropertyValue<float> LineLayer::getLineBlur(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> LineLayer::getLineBlur(const optional<std::string>& klass) const {
return impl->paint.get<LineBlur>(klass);
}
-void LineLayer::setLineBlur(PropertyValue<float> value, const optional<std::string>& klass) {
+void LineLayer::setLineBlur(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getLineBlur(klass))
return;
impl->paint.set<LineBlur>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void LineLayer::setLineBlurTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<LineBlur>(value, klass);
}
PropertyValue<std::vector<float>> LineLayer::getDefaultLineDasharray() {
@@ -257,6 +309,10 @@ void LineLayer::setLineDasharray(PropertyValue<std::vector<float>> value, const
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void LineLayer::setLineDasharrayTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<LineDasharray>(value, klass);
+}
+
PropertyValue<std::string> LineLayer::getDefaultLinePattern() {
return { "" };
}
@@ -272,5 +328,9 @@ void LineLayer::setLinePattern(PropertyValue<std::string> value, const optional<
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void LineLayer::setLinePatternTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<LinePattern>(value, klass);
+}
+
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layers/line_layer_impl.cpp b/src/mbgl/style/layers/line_layer_impl.cpp
index 477579a43c..ef0131e3d5 100644
--- a/src/mbgl/style/layers/line_layer_impl.cpp
+++ b/src/mbgl/style/layers/line_layer_impl.cpp
@@ -1,5 +1,5 @@
#include <mbgl/style/layers/line_layer_impl.hpp>
-#include <mbgl/style/bucket_parameters.hpp>
+#include <mbgl/style/property_evaluation_parameters.hpp>
#include <mbgl/renderer/line_bucket.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/util/math.hpp>
@@ -20,31 +20,25 @@ bool LineLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) {
paint.evaluate(parameters);
- passes = (paint.evaluated.get<LineOpacity>() > 0 && paint.evaluated.get<LineColor>().a > 0 && paint.evaluated.get<LineWidth>() > 0)
+ passes = (paint.evaluated.get<LineOpacity>().constantOr(1.0) > 0
+ && paint.evaluated.get<LineColor>().constantOr(Color::black()).a > 0
+ && paint.evaluated.get<LineWidth>() > 0)
? RenderPass::Translucent : RenderPass::None;
return paint.hasTransition();
}
-std::unique_ptr<Bucket> LineLayer::Impl::createBucket(BucketParameters& parameters, const GeometryTileLayer& layer) const {
- auto bucket = std::make_unique<LineBucket>(parameters.tileID.overscaleFactor());
-
- bucket->layout = layout.evaluate(PropertyEvaluationParameters(parameters.tileID.overscaledZ));
-
- parameters.eachFilteredFeature(filter, layer, [&] (const auto& feature, std::size_t index, const std::string& layerName) {
- auto geometries = feature.getGeometries();
- bucket->addGeometry(geometries);
- parameters.featureIndex.insert(geometries, index, layerName, id);
- });
-
- return std::move(bucket);
+std::unique_ptr<Bucket> LineLayer::Impl::createBucket(const BucketParameters& parameters, const std::vector<const Layer*>& layers) const {
+ return std::make_unique<LineBucket>(parameters, layers, layout);
}
float LineLayer::Impl::getLineWidth() const {
- if (paint.evaluated.get<LineGapWidth>() > 0) {
- return paint.evaluated.get<LineGapWidth>() + 2 * paint.evaluated.get<LineWidth>();
+ float lineWidth = paint.evaluated.get<LineWidth>();
+ float gapWidth = paint.evaluated.get<LineGapWidth>().constantOr(0);
+ if (gapWidth) {
+ return gapWidth + 2 * lineWidth;
} else {
- return paint.evaluated.get<LineWidth>();
+ return lineWidth;
}
}
@@ -80,7 +74,8 @@ optional<GeometryCollection> offsetLine(const GeometryCollection& rings, const d
float LineLayer::Impl::getQueryRadius() const {
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]);
+ auto offset = paint.evaluated.get<LineOffset>().constantOr(LineOffset::defaultValue());
+ return getLineWidth() / 2.0 + std::abs(offset) + util::length(translate[0], translate[1]);
}
bool LineLayer::Impl::queryIntersectsGeometry(
@@ -93,7 +88,9 @@ bool LineLayer::Impl::queryIntersectsGeometry(
auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry(
queryGeometry, paint.evaluated.get<LineTranslate>(), paint.evaluated.get<LineTranslateAnchor>(), bearing, pixelsToTileUnits);
- auto offsetGeometry = offsetLine(geometry, paint.evaluated.get<LineOffset>() * pixelsToTileUnits);
+
+ auto offset = paint.evaluated.get<LineOffset>().constantOr(LineOffset::defaultValue());
+ auto offsetGeometry = offsetLine(geometry, offset * 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 1955c019af..67e793f2ea 100644
--- a/src/mbgl/style/layers/line_layer_impl.hpp
+++ b/src/mbgl/style/layers/line_layer_impl.hpp
@@ -16,7 +16,7 @@ public:
void cascade(const CascadeParameters&) override;
bool evaluate(const PropertyEvaluationParameters&) override;
- std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const override;
+ std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const override;
float getQueryRadius() const override;
bool queryIntersectsGeometry(
diff --git a/src/mbgl/style/layers/line_layer_properties.hpp b/src/mbgl/style/layers/line_layer_properties.hpp
index 2ea7f6b125..724026e3a6 100644
--- a/src/mbgl/style/layers/line_layer_properties.hpp
+++ b/src/mbgl/style/layers/line_layer_properties.hpp
@@ -5,6 +5,7 @@
#include <mbgl/style/types.hpp>
#include <mbgl/style/layout_property.hpp>
#include <mbgl/style/paint_property.hpp>
+#include <mbgl/programs/attributes.hpp>
namespace mbgl {
namespace style {
@@ -29,11 +30,11 @@ struct LineRoundLimit : LayoutProperty<float> {
static float defaultValue() { return 1; }
};
-struct LineOpacity : PaintProperty<float> {
+struct LineOpacity : DataDrivenPaintProperty<float, attributes::a_opacity> {
static float defaultValue() { return 1; }
};
-struct LineColor : PaintProperty<Color> {
+struct LineColor : DataDrivenPaintProperty<Color, attributes::a_color> {
static Color defaultValue() { return Color::black(); }
};
@@ -49,15 +50,15 @@ struct LineWidth : PaintProperty<float> {
static float defaultValue() { return 1; }
};
-struct LineGapWidth : PaintProperty<float> {
+struct LineGapWidth : DataDrivenPaintProperty<float, attributes::a_gap_width> {
static float defaultValue() { return 0; }
};
-struct LineOffset : PaintProperty<float> {
+struct LineOffset : DataDrivenPaintProperty<float, attributes::a_offset<1>> {
static float defaultValue() { return 0; }
};
-struct LineBlur : PaintProperty<float> {
+struct LineBlur : DataDrivenPaintProperty<float, attributes::a_blur> {
static float defaultValue() { return 0; }
};
diff --git a/src/mbgl/style/layers/raster_layer.cpp b/src/mbgl/style/layers/raster_layer.cpp
index 0fda27f0dc..2108a5c49f 100644
--- a/src/mbgl/style/layers/raster_layer.cpp
+++ b/src/mbgl/style/layers/raster_layer.cpp
@@ -62,6 +62,10 @@ void RasterLayer::setRasterOpacity(PropertyValue<float> value, const optional<st
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void RasterLayer::setRasterOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<RasterOpacity>(value, klass);
+}
+
PropertyValue<float> RasterLayer::getDefaultRasterHueRotate() {
return { 0 };
}
@@ -77,6 +81,10 @@ void RasterLayer::setRasterHueRotate(PropertyValue<float> value, const optional<
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void RasterLayer::setRasterHueRotateTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<RasterHueRotate>(value, klass);
+}
+
PropertyValue<float> RasterLayer::getDefaultRasterBrightnessMin() {
return { 0 };
}
@@ -92,6 +100,10 @@ void RasterLayer::setRasterBrightnessMin(PropertyValue<float> value, const optio
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void RasterLayer::setRasterBrightnessMinTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<RasterBrightnessMin>(value, klass);
+}
+
PropertyValue<float> RasterLayer::getDefaultRasterBrightnessMax() {
return { 1 };
}
@@ -107,6 +119,10 @@ void RasterLayer::setRasterBrightnessMax(PropertyValue<float> value, const optio
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void RasterLayer::setRasterBrightnessMaxTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<RasterBrightnessMax>(value, klass);
+}
+
PropertyValue<float> RasterLayer::getDefaultRasterSaturation() {
return { 0 };
}
@@ -122,6 +138,10 @@ void RasterLayer::setRasterSaturation(PropertyValue<float> value, const optional
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void RasterLayer::setRasterSaturationTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<RasterSaturation>(value, klass);
+}
+
PropertyValue<float> RasterLayer::getDefaultRasterContrast() {
return { 0 };
}
@@ -137,6 +157,10 @@ void RasterLayer::setRasterContrast(PropertyValue<float> value, const optional<s
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void RasterLayer::setRasterContrastTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<RasterContrast>(value, klass);
+}
+
PropertyValue<float> RasterLayer::getDefaultRasterFadeDuration() {
return { 300 };
}
@@ -152,5 +176,9 @@ void RasterLayer::setRasterFadeDuration(PropertyValue<float> value, const option
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void RasterLayer::setRasterFadeDurationTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<RasterFadeDuration>(value, klass);
+}
+
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layers/raster_layer_impl.cpp b/src/mbgl/style/layers/raster_layer_impl.cpp
index a78614aee9..a667ccb5a8 100644
--- a/src/mbgl/style/layers/raster_layer_impl.cpp
+++ b/src/mbgl/style/layers/raster_layer_impl.cpp
@@ -16,7 +16,8 @@ bool RasterLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters)
return paint.hasTransition();
}
-std::unique_ptr<Bucket> RasterLayer::Impl::createBucket(BucketParameters&, const GeometryTileLayer&) const {
+std::unique_ptr<Bucket> RasterLayer::Impl::createBucket(const BucketParameters&, const std::vector<const Layer*>&) const {
+ assert(false);
return nullptr;
}
diff --git a/src/mbgl/style/layers/raster_layer_impl.hpp b/src/mbgl/style/layers/raster_layer_impl.hpp
index 8e69c21ca8..42985ce0f1 100644
--- a/src/mbgl/style/layers/raster_layer_impl.hpp
+++ b/src/mbgl/style/layers/raster_layer_impl.hpp
@@ -16,7 +16,7 @@ public:
void cascade(const CascadeParameters&) override;
bool evaluate(const PropertyEvaluationParameters&) override;
- std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const override;
+ std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const override;
RasterPaintProperties paint;
};
diff --git a/src/mbgl/style/layers/raster_layer_properties.hpp b/src/mbgl/style/layers/raster_layer_properties.hpp
index caa6d0c58d..219fe34d8c 100644
--- a/src/mbgl/style/layers/raster_layer_properties.hpp
+++ b/src/mbgl/style/layers/raster_layer_properties.hpp
@@ -5,6 +5,7 @@
#include <mbgl/style/types.hpp>
#include <mbgl/style/layout_property.hpp>
#include <mbgl/style/paint_property.hpp>
+#include <mbgl/programs/attributes.hpp>
namespace mbgl {
namespace style {
diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp
index c9014e7ee7..d85b8c00e6 100644
--- a/src/mbgl/style/layers/symbol_layer.cpp
+++ b/src/mbgl/style/layers/symbol_layer.cpp
@@ -217,15 +217,15 @@ void SymbolLayer::setIconImage(PropertyValue<std::string> value) {
impl->layout.unevaluated.get<IconImage>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "icon-image");
}
-PropertyValue<float> SymbolLayer::getDefaultIconRotate() {
+DataDrivenPropertyValue<float> SymbolLayer::getDefaultIconRotate() {
return IconRotate::defaultValue();
}
-PropertyValue<float> SymbolLayer::getIconRotate() const {
+DataDrivenPropertyValue<float> SymbolLayer::getIconRotate() const {
return impl->layout.unevaluated.get<IconRotate>();
}
-void SymbolLayer::setIconRotate(PropertyValue<float> value) {
+void SymbolLayer::setIconRotate(DataDrivenPropertyValue<float> value) {
if (value == getIconRotate())
return;
impl->layout.unevaluated.get<IconRotate>() = value;
@@ -259,15 +259,15 @@ void SymbolLayer::setIconKeepUpright(PropertyValue<bool> value) {
impl->layout.unevaluated.get<IconKeepUpright>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "icon-keep-upright");
}
-PropertyValue<std::array<float, 2>> SymbolLayer::getDefaultIconOffset() {
+DataDrivenPropertyValue<std::array<float, 2>> SymbolLayer::getDefaultIconOffset() {
return IconOffset::defaultValue();
}
-PropertyValue<std::array<float, 2>> SymbolLayer::getIconOffset() const {
+DataDrivenPropertyValue<std::array<float, 2>> SymbolLayer::getIconOffset() const {
return impl->layout.unevaluated.get<IconOffset>();
}
-void SymbolLayer::setIconOffset(PropertyValue<std::array<float, 2>> value) {
+void SymbolLayer::setIconOffset(DataDrivenPropertyValue<std::array<float, 2>> value) {
if (value == getIconOffset())
return;
impl->layout.unevaluated.get<IconOffset>() = value;
@@ -301,15 +301,15 @@ void SymbolLayer::setTextRotationAlignment(PropertyValue<AlignmentType> value) {
impl->layout.unevaluated.get<TextRotationAlignment>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "text-rotation-alignment");
}
-PropertyValue<std::string> SymbolLayer::getDefaultTextField() {
+DataDrivenPropertyValue<std::string> SymbolLayer::getDefaultTextField() {
return TextField::defaultValue();
}
-PropertyValue<std::string> SymbolLayer::getTextField() const {
+DataDrivenPropertyValue<std::string> SymbolLayer::getTextField() const {
return impl->layout.unevaluated.get<TextField>();
}
-void SymbolLayer::setTextField(PropertyValue<std::string> value) {
+void SymbolLayer::setTextField(DataDrivenPropertyValue<std::string> value) {
if (value == getTextField())
return;
impl->layout.unevaluated.get<TextField>() = value;
@@ -469,15 +469,15 @@ void SymbolLayer::setTextKeepUpright(PropertyValue<bool> value) {
impl->layout.unevaluated.get<TextKeepUpright>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "text-keep-upright");
}
-PropertyValue<TextTransformType> SymbolLayer::getDefaultTextTransform() {
+DataDrivenPropertyValue<TextTransformType> SymbolLayer::getDefaultTextTransform() {
return TextTransform::defaultValue();
}
-PropertyValue<TextTransformType> SymbolLayer::getTextTransform() const {
+DataDrivenPropertyValue<TextTransformType> SymbolLayer::getTextTransform() const {
return impl->layout.unevaluated.get<TextTransform>();
}
-void SymbolLayer::setTextTransform(PropertyValue<TextTransformType> value) {
+void SymbolLayer::setTextTransform(DataDrivenPropertyValue<TextTransformType> value) {
if (value == getTextTransform())
return;
impl->layout.unevaluated.get<TextTransform>() = value;
@@ -542,79 +542,119 @@ void SymbolLayer::setTextOptional(PropertyValue<bool> value) {
// Paint properties
-PropertyValue<float> SymbolLayer::getDefaultIconOpacity() {
+DataDrivenPropertyValue<float> SymbolLayer::getDefaultIconOpacity() {
return { 1 };
}
-PropertyValue<float> SymbolLayer::getIconOpacity(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> SymbolLayer::getIconOpacity(const optional<std::string>& klass) const {
return impl->paint.get<IconOpacity>(klass);
}
-void SymbolLayer::setIconOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
+void SymbolLayer::setIconOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getIconOpacity(klass))
return;
impl->paint.set<IconOpacity>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void SymbolLayer::setIconOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<IconOpacity>(value, klass);
}
-PropertyValue<Color> SymbolLayer::getDefaultIconColor() {
+DataDrivenPropertyValue<Color> SymbolLayer::getDefaultIconColor() {
return { Color::black() };
}
-PropertyValue<Color> SymbolLayer::getIconColor(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<Color> SymbolLayer::getIconColor(const optional<std::string>& klass) const {
return impl->paint.get<IconColor>(klass);
}
-void SymbolLayer::setIconColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+void SymbolLayer::setIconColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getIconColor(klass))
return;
impl->paint.set<IconColor>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void SymbolLayer::setIconColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<IconColor>(value, klass);
}
-PropertyValue<Color> SymbolLayer::getDefaultIconHaloColor() {
+DataDrivenPropertyValue<Color> SymbolLayer::getDefaultIconHaloColor() {
return { {} };
}
-PropertyValue<Color> SymbolLayer::getIconHaloColor(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<Color> SymbolLayer::getIconHaloColor(const optional<std::string>& klass) const {
return impl->paint.get<IconHaloColor>(klass);
}
-void SymbolLayer::setIconHaloColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+void SymbolLayer::setIconHaloColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getIconHaloColor(klass))
return;
impl->paint.set<IconHaloColor>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
}
-PropertyValue<float> SymbolLayer::getDefaultIconHaloWidth() {
+void SymbolLayer::setIconHaloColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<IconHaloColor>(value, klass);
+}
+
+DataDrivenPropertyValue<float> SymbolLayer::getDefaultIconHaloWidth() {
return { 0 };
}
-PropertyValue<float> SymbolLayer::getIconHaloWidth(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> SymbolLayer::getIconHaloWidth(const optional<std::string>& klass) const {
return impl->paint.get<IconHaloWidth>(klass);
}
-void SymbolLayer::setIconHaloWidth(PropertyValue<float> value, const optional<std::string>& klass) {
+void SymbolLayer::setIconHaloWidth(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getIconHaloWidth(klass))
return;
impl->paint.set<IconHaloWidth>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
}
-PropertyValue<float> SymbolLayer::getDefaultIconHaloBlur() {
+void SymbolLayer::setIconHaloWidthTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<IconHaloWidth>(value, klass);
+}
+
+DataDrivenPropertyValue<float> SymbolLayer::getDefaultIconHaloBlur() {
return { 0 };
}
-PropertyValue<float> SymbolLayer::getIconHaloBlur(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> SymbolLayer::getIconHaloBlur(const optional<std::string>& klass) const {
return impl->paint.get<IconHaloBlur>(klass);
}
-void SymbolLayer::setIconHaloBlur(PropertyValue<float> value, const optional<std::string>& klass) {
+void SymbolLayer::setIconHaloBlur(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getIconHaloBlur(klass))
return;
impl->paint.set<IconHaloBlur>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void SymbolLayer::setIconHaloBlurTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<IconHaloBlur>(value, klass);
}
PropertyValue<std::array<float, 2>> SymbolLayer::getDefaultIconTranslate() {
@@ -632,6 +672,10 @@ void SymbolLayer::setIconTranslate(PropertyValue<std::array<float, 2>> value, co
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void SymbolLayer::setIconTranslateTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<IconTranslate>(value, klass);
+}
+
PropertyValue<TranslateAnchorType> SymbolLayer::getDefaultIconTranslateAnchor() {
return { TranslateAnchorType::Map };
}
@@ -647,79 +691,123 @@ void SymbolLayer::setIconTranslateAnchor(PropertyValue<TranslateAnchorType> valu
impl->observer->onLayerPaintPropertyChanged(*this);
}
-PropertyValue<float> SymbolLayer::getDefaultTextOpacity() {
+void SymbolLayer::setIconTranslateAnchorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<IconTranslateAnchor>(value, klass);
+}
+
+DataDrivenPropertyValue<float> SymbolLayer::getDefaultTextOpacity() {
return { 1 };
}
-PropertyValue<float> SymbolLayer::getTextOpacity(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> SymbolLayer::getTextOpacity(const optional<std::string>& klass) const {
return impl->paint.get<TextOpacity>(klass);
}
-void SymbolLayer::setTextOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
+void SymbolLayer::setTextOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getTextOpacity(klass))
return;
impl->paint.set<TextOpacity>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void SymbolLayer::setTextOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<TextOpacity>(value, klass);
}
-PropertyValue<Color> SymbolLayer::getDefaultTextColor() {
+DataDrivenPropertyValue<Color> SymbolLayer::getDefaultTextColor() {
return { Color::black() };
}
-PropertyValue<Color> SymbolLayer::getTextColor(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<Color> SymbolLayer::getTextColor(const optional<std::string>& klass) const {
return impl->paint.get<TextColor>(klass);
}
-void SymbolLayer::setTextColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+void SymbolLayer::setTextColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getTextColor(klass))
return;
impl->paint.set<TextColor>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void SymbolLayer::setTextColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<TextColor>(value, klass);
}
-PropertyValue<Color> SymbolLayer::getDefaultTextHaloColor() {
+DataDrivenPropertyValue<Color> SymbolLayer::getDefaultTextHaloColor() {
return { {} };
}
-PropertyValue<Color> SymbolLayer::getTextHaloColor(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<Color> SymbolLayer::getTextHaloColor(const optional<std::string>& klass) const {
return impl->paint.get<TextHaloColor>(klass);
}
-void SymbolLayer::setTextHaloColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+void SymbolLayer::setTextHaloColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getTextHaloColor(klass))
return;
impl->paint.set<TextHaloColor>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
}
-PropertyValue<float> SymbolLayer::getDefaultTextHaloWidth() {
+void SymbolLayer::setTextHaloColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<TextHaloColor>(value, klass);
+}
+
+DataDrivenPropertyValue<float> SymbolLayer::getDefaultTextHaloWidth() {
return { 0 };
}
-PropertyValue<float> SymbolLayer::getTextHaloWidth(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> SymbolLayer::getTextHaloWidth(const optional<std::string>& klass) const {
return impl->paint.get<TextHaloWidth>(klass);
}
-void SymbolLayer::setTextHaloWidth(PropertyValue<float> value, const optional<std::string>& klass) {
+void SymbolLayer::setTextHaloWidth(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getTextHaloWidth(klass))
return;
impl->paint.set<TextHaloWidth>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
}
-PropertyValue<float> SymbolLayer::getDefaultTextHaloBlur() {
+void SymbolLayer::setTextHaloWidthTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<TextHaloWidth>(value, klass);
+}
+
+DataDrivenPropertyValue<float> SymbolLayer::getDefaultTextHaloBlur() {
return { 0 };
}
-PropertyValue<float> SymbolLayer::getTextHaloBlur(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> SymbolLayer::getTextHaloBlur(const optional<std::string>& klass) const {
return impl->paint.get<TextHaloBlur>(klass);
}
-void SymbolLayer::setTextHaloBlur(PropertyValue<float> value, const optional<std::string>& klass) {
+void SymbolLayer::setTextHaloBlur(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getTextHaloBlur(klass))
return;
impl->paint.set<TextHaloBlur>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void SymbolLayer::setTextHaloBlurTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<TextHaloBlur>(value, klass);
}
PropertyValue<std::array<float, 2>> SymbolLayer::getDefaultTextTranslate() {
@@ -737,6 +825,10 @@ void SymbolLayer::setTextTranslate(PropertyValue<std::array<float, 2>> value, co
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void SymbolLayer::setTextTranslateTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<TextTranslate>(value, klass);
+}
+
PropertyValue<TranslateAnchorType> SymbolLayer::getDefaultTextTranslateAnchor() {
return { TranslateAnchorType::Map };
}
@@ -752,5 +844,9 @@ void SymbolLayer::setTextTranslateAnchor(PropertyValue<TranslateAnchorType> valu
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void SymbolLayer::setTextTranslateAnchorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<TextTranslateAnchor>(value, klass);
+}
+
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layers/symbol_layer_impl.cpp b/src/mbgl/style/layers/symbol_layer_impl.cpp
index f058598f5f..ff59b14d65 100644
--- a/src/mbgl/style/layers/symbol_layer_impl.cpp
+++ b/src/mbgl/style/layers/symbol_layer_impl.cpp
@@ -1,5 +1,5 @@
#include <mbgl/style/layers/symbol_layer_impl.hpp>
-#include <mbgl/style/bucket_parameters.hpp>
+#include <mbgl/style/property_evaluation_parameters.hpp>
#include <mbgl/layout/symbol_layout.hpp>
#include <mbgl/renderer/bucket.hpp>
@@ -16,77 +16,70 @@ bool SymbolLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters)
// text-size and icon-size are layout properties but they also need to be evaluated as paint properties:
iconSize = layout.evaluate<IconSize>(parameters);
textSize = layout.evaluate<TextSize>(parameters);
-
- 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))
+
+ auto hasIconOpacity = paint.evaluated.get<IconColor>().constantOr(Color::black()).a > 0 ||
+ paint.evaluated.get<IconHaloColor>().constantOr(Color::black()).a > 0;
+ auto hasTextOpacity = paint.evaluated.get<TextColor>().constantOr(Color::black()).a > 0 ||
+ paint.evaluated.get<TextHaloColor>().constantOr(Color::black()).a > 0;
+
+ passes = ((paint.evaluated.get<IconOpacity>().constantOr(1) > 0 && hasIconOpacity && iconSize > 0)
+ || (paint.evaluated.get<TextOpacity>().constantOr(1) > 0 && hasTextOpacity && textSize > 0))
? RenderPass::Translucent : RenderPass::None;
return paint.hasTransition();
}
-std::unique_ptr<Bucket> SymbolLayer::Impl::createBucket(BucketParameters&, const GeometryTileLayer&) const {
+std::unique_ptr<Bucket> SymbolLayer::Impl::createBucket(const BucketParameters&, const std::vector<const Layer*>&) const {
assert(false); // Should be calling createLayout() instead.
return nullptr;
}
-std::unique_ptr<SymbolLayout> SymbolLayer::Impl::createLayout(BucketParameters& parameters,
- const GeometryTileLayer& layer,
- std::vector<std::string> group) const {
- PropertyEvaluationParameters p(parameters.tileID.overscaledZ);
- SymbolLayoutProperties::Evaluated evaluated = layout.evaluate(p);
-
- if (evaluated.get<IconRotationAlignment>() == AlignmentType::Auto) {
- if (evaluated.get<SymbolPlacement>() == SymbolPlacementType::Line) {
- evaluated.get<IconRotationAlignment>() = AlignmentType::Map;
- } else {
- evaluated.get<IconRotationAlignment>() = AlignmentType::Viewport;
- }
- }
-
- if (evaluated.get<TextRotationAlignment>() == AlignmentType::Auto) {
- if (evaluated.get<SymbolPlacement>() == SymbolPlacementType::Line) {
- evaluated.get<TextRotationAlignment>() = AlignmentType::Map;
- } else {
- evaluated.get<TextRotationAlignment>() = AlignmentType::Viewport;
- }
- }
-
- // If unspecified `text-pitch-alignment` inherits `text-rotation-alignment`
- if (evaluated.get<TextPitchAlignment>() == AlignmentType::Auto) {
- evaluated.get<TextPitchAlignment>() = evaluated.get<TextRotationAlignment>();
- }
-
- float textMaxSize = layout.evaluate<TextSize>(PropertyEvaluationParameters(18));
-
- 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>(std::move(group),
- layer.getName(),
- parameters.tileID.overscaleFactor(),
- parameters.tileID.overscaledZ,
- parameters.mode,
+std::unique_ptr<SymbolLayout> SymbolLayer::Impl::createLayout(const BucketParameters& parameters,
+ const std::vector<const Layer*>& group,
+ const GeometryTileLayer& layer) const {
+ return std::make_unique<SymbolLayout>(parameters,
+ group,
layer,
- filter,
- 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>(),
+IconPaintProperties::Evaluated SymbolLayer::Impl::iconPaintProperties() const {
+ return IconPaintProperties::Evaluated {
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>()
+ };
+}
+
+TextPaintProperties::Evaluated SymbolLayer::Impl::textPaintProperties() const {
+ return TextPaintProperties::Evaluated {
+ 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>()
+ };
+}
+
+
+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<IconTranslate>(),
paint.evaluated.get<IconTranslateAnchor>(),
iconSize,
- 1.0f
+ 1.0f,
+ paint.evaluated.get<IconHaloColor>().constantOr(Color::black()).a > 0 &&
+ paint.evaluated.get<IconHaloWidth>().constantOr(1),
+ paint.evaluated.get<IconColor>().constantOr(Color::black()).a > 0
};
}
@@ -95,15 +88,13 @@ SymbolPropertyValues SymbolLayer::Impl::textPropertyValues(const SymbolLayoutPro
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
+ 24.0f,
+ paint.evaluated.get<TextHaloColor>().constantOr(Color::black()).a > 0 &&
+ paint.evaluated.get<TextHaloWidth>().constantOr(1),
+ paint.evaluated.get<TextColor>().constantOr(Color::black()).a > 0
};
}
diff --git a/src/mbgl/style/layers/symbol_layer_impl.hpp b/src/mbgl/style/layers/symbol_layer_impl.hpp
index db18da07e2..1e9f05e4c7 100644
--- a/src/mbgl/style/layers/symbol_layer_impl.hpp
+++ b/src/mbgl/style/layers/symbol_layer_impl.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include <mbgl/util/variant.hpp>
#include <mbgl/style/layer_impl.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
@@ -10,6 +11,30 @@ class SpriteAtlas;
class SymbolLayout;
namespace style {
+
+
+// {icon,text}-specific paint-property packs for use in the symbol Programs.
+// Since each program deals either with icons or text, using a smaller property set
+// lets us avoid unnecessarily binding attributes for properties the program wouldn't use.
+class IconPaintProperties : public PaintProperties<
+ IconOpacity,
+ IconColor,
+ IconHaloColor,
+ IconHaloWidth,
+ IconHaloBlur,
+ IconTranslate,
+ IconTranslateAnchor
+> {};
+
+class TextPaintProperties : public PaintProperties<
+ TextOpacity,
+ TextColor,
+ TextHaloColor,
+ TextHaloWidth,
+ TextHaloBlur,
+ TextTranslate,
+ TextTranslateAnchor
+> {};
// Repackaging evaluated values from SymbolLayoutProperties + SymbolPaintProperties
// for genericity over icons vs. text.
@@ -21,24 +46,14 @@ public:
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;
- }
+
+ bool hasHalo;
+ bool hasFill;
};
class SymbolLayer::Impl : public Layer::Impl {
@@ -50,10 +65,13 @@ public:
void cascade(const CascadeParameters&) override;
bool evaluate(const PropertyEvaluationParameters&) override;
- std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const override;
- std::unique_ptr<SymbolLayout> createLayout(BucketParameters&, const GeometryTileLayer&,
- std::vector<std::string>) const;
+ std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const override;
+ std::unique_ptr<SymbolLayout> createLayout(const BucketParameters&, const std::vector<const Layer*>&,
+ const GeometryTileLayer&) const;
+ IconPaintProperties::Evaluated iconPaintProperties() const;
+ TextPaintProperties::Evaluated textPaintProperties() const;
+
SymbolPropertyValues iconPropertyValues(const SymbolLayoutProperties::Evaluated&) const;
SymbolPropertyValues textPropertyValues(const SymbolLayoutProperties::Evaluated&) const;
diff --git a/src/mbgl/style/layers/symbol_layer_properties.hpp b/src/mbgl/style/layers/symbol_layer_properties.hpp
index f5fd6ce3df..f2b7bfa00f 100644
--- a/src/mbgl/style/layers/symbol_layer_properties.hpp
+++ b/src/mbgl/style/layers/symbol_layer_properties.hpp
@@ -5,6 +5,7 @@
#include <mbgl/style/types.hpp>
#include <mbgl/style/layout_property.hpp>
#include <mbgl/style/paint_property.hpp>
+#include <mbgl/programs/attributes.hpp>
namespace mbgl {
namespace style {
@@ -64,7 +65,7 @@ struct IconImage : LayoutProperty<std::string> {
static std::string defaultValue() { return ""; }
};
-struct IconRotate : LayoutProperty<float> {
+struct IconRotate : DataDrivenLayoutProperty<float> {
static constexpr const char * key = "icon-rotate";
static float defaultValue() { return 0; }
};
@@ -79,7 +80,7 @@ struct IconKeepUpright : LayoutProperty<bool> {
static bool defaultValue() { return false; }
};
-struct IconOffset : LayoutProperty<std::array<float, 2>> {
+struct IconOffset : DataDrivenLayoutProperty<std::array<float, 2>> {
static constexpr const char * key = "icon-offset";
static std::array<float, 2> defaultValue() { return {{ 0, 0 }}; }
};
@@ -94,7 +95,7 @@ struct TextRotationAlignment : LayoutProperty<AlignmentType> {
static AlignmentType defaultValue() { return AlignmentType::Auto; }
};
-struct TextField : LayoutProperty<std::string> {
+struct TextField : DataDrivenLayoutProperty<std::string> {
static constexpr const char * key = "text-field";
static std::string defaultValue() { return ""; }
};
@@ -154,7 +155,7 @@ struct TextKeepUpright : LayoutProperty<bool> {
static bool defaultValue() { return true; }
};
-struct TextTransform : LayoutProperty<TextTransformType> {
+struct TextTransform : DataDrivenLayoutProperty<TextTransformType> {
static constexpr const char * key = "text-transform";
static TextTransformType defaultValue() { return TextTransformType::None; }
};
@@ -179,23 +180,23 @@ struct TextOptional : LayoutProperty<bool> {
static bool defaultValue() { return false; }
};
-struct IconOpacity : PaintProperty<float> {
+struct IconOpacity : DataDrivenPaintProperty<float, attributes::a_opacity> {
static float defaultValue() { return 1; }
};
-struct IconColor : PaintProperty<Color> {
+struct IconColor : DataDrivenPaintProperty<Color, attributes::a_fill_color> {
static Color defaultValue() { return Color::black(); }
};
-struct IconHaloColor : PaintProperty<Color> {
+struct IconHaloColor : DataDrivenPaintProperty<Color, attributes::a_halo_color> {
static Color defaultValue() { return {}; }
};
-struct IconHaloWidth : PaintProperty<float> {
+struct IconHaloWidth : DataDrivenPaintProperty<float, attributes::a_halo_width> {
static float defaultValue() { return 0; }
};
-struct IconHaloBlur : PaintProperty<float> {
+struct IconHaloBlur : DataDrivenPaintProperty<float, attributes::a_halo_blur> {
static float defaultValue() { return 0; }
};
@@ -207,23 +208,23 @@ struct IconTranslateAnchor : PaintProperty<TranslateAnchorType> {
static TranslateAnchorType defaultValue() { return TranslateAnchorType::Map; }
};
-struct TextOpacity : PaintProperty<float> {
+struct TextOpacity : DataDrivenPaintProperty<float, attributes::a_opacity> {
static float defaultValue() { return 1; }
};
-struct TextColor : PaintProperty<Color> {
+struct TextColor : DataDrivenPaintProperty<Color, attributes::a_fill_color> {
static Color defaultValue() { return Color::black(); }
};
-struct TextHaloColor : PaintProperty<Color> {
+struct TextHaloColor : DataDrivenPaintProperty<Color, attributes::a_halo_color> {
static Color defaultValue() { return {}; }
};
-struct TextHaloWidth : PaintProperty<float> {
+struct TextHaloWidth : DataDrivenPaintProperty<float, attributes::a_halo_width> {
static float defaultValue() { return 0; }
};
-struct TextHaloBlur : PaintProperty<float> {
+struct TextHaloBlur : DataDrivenPaintProperty<float, attributes::a_halo_blur> {
static float defaultValue() { return 0; }
};
diff --git a/src/mbgl/style/layout_property.hpp b/src/mbgl/style/layout_property.hpp
index 6ea06ce556..25cff4b92d 100644
--- a/src/mbgl/style/layout_property.hpp
+++ b/src/mbgl/style/layout_property.hpp
@@ -1,6 +1,9 @@
#pragma once
+#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
#include <mbgl/style/property_evaluator.hpp>
+#include <mbgl/style/data_driven_property_evaluator.hpp>
#include <mbgl/util/indexed_tuple.hpp>
namespace mbgl {
@@ -11,9 +14,19 @@ class PropertyEvaluationParameters;
template <class T>
class LayoutProperty {
public:
- using EvaluatorType = PropertyEvaluator<T>;
using UnevaluatedType = PropertyValue<T>;
+ using EvaluatorType = PropertyEvaluator<T>;
using EvaluatedType = T;
+ using Type = T;
+};
+
+template <class T>
+class DataDrivenLayoutProperty {
+public:
+ using UnevaluatedType = DataDrivenPropertyValue<T>;
+ using EvaluatorType = DataDrivenPropertyEvaluator<T>;
+ using EvaluatedType = PossiblyEvaluatedPropertyValue<T>;
+ using Type = T;
};
template <class... Ps>
@@ -29,6 +42,15 @@ public:
class Evaluated : public Tuple<EvaluatedTypes> {
public:
using Tuple<EvaluatedTypes>::Tuple;
+
+ template <class P>
+ typename P::Type evaluate(float z, const GeometryTileFeature& feature) const {
+ using T = typename P::Type;
+ return this->template get<P>().match(
+ [&] (const T& t) { return t; },
+ [&] (const SourceFunction<T>& t) { return t.evaluate(feature, P::defaultValue()); },
+ [&] (const CompositeFunction<T>& t) { return t.evaluate(z, feature, P::defaultValue()); });
+ }
};
class Unevaluated : public Tuple<UnevaluatedTypes> {
diff --git a/src/mbgl/style/paint_property.hpp b/src/mbgl/style/paint_property.hpp
index 7b56f6415d..1fa2390f33 100644
--- a/src/mbgl/style/paint_property.hpp
+++ b/src/mbgl/style/paint_property.hpp
@@ -1,11 +1,15 @@
#pragma once
#include <mbgl/style/class_dictionary.hpp>
+#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
#include <mbgl/style/property_evaluator.hpp>
#include <mbgl/style/cross_faded_property_evaluator.hpp>
+#include <mbgl/style/data_driven_property_evaluator.hpp>
+#include <mbgl/style/property_evaluation_parameters.hpp>
#include <mbgl/style/transition_options.hpp>
#include <mbgl/style/cascade_parameters.hpp>
-#include <mbgl/style/property_evaluation_parameters.hpp>
+#include <mbgl/style/paint_property_binder.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/interpolate.hpp>
#include <mbgl/util/indexed_tuple.hpp>
@@ -15,17 +19,18 @@
#include <utility>
namespace mbgl {
+
+class GeometryTileFeature;
+
namespace style {
-template <class T, class Evaluator>
+template <class Value>
class UnevaluatedPaintProperty {
public:
- using Result = typename Evaluator::ResultType;
-
UnevaluatedPaintProperty() = default;
- UnevaluatedPaintProperty(PropertyValue<T> value_,
- UnevaluatedPaintProperty<T, Evaluator> prior_,
+ UnevaluatedPaintProperty(Value value_,
+ UnevaluatedPaintProperty<Value> prior_,
TransitionOptions transition,
TimePoint now)
: begin(now + transition.delay.value_or(Duration::zero())),
@@ -36,22 +41,23 @@ public:
}
}
- Result evaluate(const PropertyEvaluationParameters& parameters, T defaultValue) {
- Result finalValue = value.evaluate(Evaluator(parameters, defaultValue));
+ template <class Evaluator>
+ auto evaluate(const Evaluator& evaluator, TimePoint now) {
+ auto finalValue = value.evaluate(evaluator);
if (!prior) {
// No prior value.
return finalValue;
- } else if (parameters.now >= end) {
+ } else if (now >= end) {
// Transition from prior value is now complete.
prior = {};
return finalValue;
- } else if (parameters.now < begin) {
+ } else if (now < begin) {
// Transition hasn't started yet.
- return prior->get().evaluate(parameters, defaultValue);
+ return prior->get().evaluate(evaluator, now);
} 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));
+ float t = std::chrono::duration<float>(now - begin) / (end - begin);
+ return util::interpolate(prior->get().evaluate(evaluator, now), finalValue, util::DEFAULT_TRANSITION_EASE.solve(t, 0.001));
}
}
@@ -63,30 +69,40 @@ public:
return value.isUndefined();
}
+ const Value& getValue() const {
+ return value;
+ }
+
private:
- optional<mapbox::util::recursive_wrapper<UnevaluatedPaintProperty<T, Evaluator>>> prior;
+ optional<mapbox::util::recursive_wrapper<UnevaluatedPaintProperty<Value>>> prior;
TimePoint begin;
TimePoint end;
- PropertyValue<T> value;
+ Value value;
};
-template <class T>
+template <class Value>
class CascadingPaintProperty {
public:
bool isUndefined() const {
return values.find(ClassID::Default) == values.end();
}
- const PropertyValue<T>& get(const optional<std::string>& klass) const {
- static const PropertyValue<T> staticValue;
+ const Value& get(const optional<std::string>& klass) const {
+ static const Value staticValue{};
const auto it = values.find(klass ? ClassDictionary::Get().lookup(*klass) : ClassID::Default);
return it == values.end() ? staticValue : it->second;
}
- void set(const PropertyValue<T>& value_, const optional<std::string>& klass) {
+ void set(const Value& value_, const optional<std::string>& klass) {
values[klass ? ClassDictionary::Get().lookup(*klass) : ClassID::Default] = value_;
}
+ const TransitionOptions& getTransition(const optional<std::string>& klass) const {
+ static const TransitionOptions staticValue{};
+ const auto it = transitions.find(klass ? ClassDictionary::Get().lookup(*klass) : ClassID::Default);
+ return it == transitions.end() ? staticValue : it->second;
+ }
+
void setTransition(const TransitionOptions& transition, const optional<std::string>& klass) {
transitions[klass ? ClassDictionary::Get().lookup(*klass) : ClassID::Default] = transition;
}
@@ -94,7 +110,7 @@ public:
template <class UnevaluatedPaintProperty>
UnevaluatedPaintProperty cascade(const CascadeParameters& params, UnevaluatedPaintProperty prior) const {
TransitionOptions transition;
- PropertyValue<T> value;
+ Value value;
for (const auto classID : params.classes) {
if (values.find(classID) != values.end()) {
@@ -117,7 +133,7 @@ public:
}
private:
- std::unordered_map<ClassID, PropertyValue<T>> values;
+ std::unordered_map<ClassID, Value> values;
std::unordered_map<ClassID, TransitionOptions> transitions;
};
@@ -125,26 +141,48 @@ template <class T>
class PaintProperty {
public:
using ValueType = PropertyValue<T>;
- using CascadingType = CascadingPaintProperty<T>;
+ using CascadingType = CascadingPaintProperty<ValueType>;
+ using UnevaluatedType = UnevaluatedPaintProperty<ValueType>;
using EvaluatorType = PropertyEvaluator<T>;
- using UnevaluatedType = UnevaluatedPaintProperty<T, EvaluatorType>;
using EvaluatedType = T;
+ static constexpr bool IsDataDriven = false;
+};
+
+template <class T, class A>
+class DataDrivenPaintProperty {
+public:
+ using ValueType = DataDrivenPropertyValue<T>;
+ using CascadingType = CascadingPaintProperty<ValueType>;
+ using UnevaluatedType = UnevaluatedPaintProperty<ValueType>;
+ using EvaluatorType = DataDrivenPropertyEvaluator<T>;
+ using EvaluatedType = PossiblyEvaluatedPropertyValue<T>;
+ static constexpr bool IsDataDriven = true;
+
+ using Type = T;
+ using Attribute = A;
};
template <class T>
class CrossFadedPaintProperty {
public:
using ValueType = PropertyValue<T>;
- using CascadingType = CascadingPaintProperty<T>;
+ using CascadingType = CascadingPaintProperty<ValueType>;
+ using UnevaluatedType = UnevaluatedPaintProperty<ValueType>;
using EvaluatorType = CrossFadedPropertyEvaluator<T>;
- using UnevaluatedType = UnevaluatedPaintProperty<T, EvaluatorType>;
using EvaluatedType = Faded<T>;
+ static constexpr bool IsDataDriven = false;
};
+template <class P>
+struct IsDataDriven : std::integral_constant<bool, P::IsDataDriven> {};
+
template <class... Ps>
class PaintProperties {
public:
using Properties = TypeList<Ps...>;
+ using DataDrivenProperties = FilteredTypeList<Properties, IsDataDriven>;
+ using Binders = PaintPropertyBinders<DataDrivenProperties>;
+
using EvaluatedTypes = TypeList<typename Ps::EvaluatedType...>;
using UnevaluatedTypes = TypeList<typename Ps::UnevaluatedType...>;
using CascadingTypes = TypeList<typename Ps::CascadingType...>;
@@ -177,6 +215,11 @@ public:
cascading.template get<P>().set(value, klass);
}
+ template <class P>
+ void setTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ cascading.template get<P>().setTransition(value, klass);
+ }
+
void cascade(const CascadeParameters& parameters) {
unevaluated = Unevaluated {
cascading.template get<Ps>().cascade(parameters,
@@ -186,7 +229,9 @@ public:
template <class P>
auto evaluate(const PropertyEvaluationParameters& parameters) {
- return unevaluated.template get<P>().evaluate(parameters, P::defaultValue());
+ using Evaluator = typename P::EvaluatorType;
+ return unevaluated.template get<P>()
+ .evaluate(Evaluator(parameters, P::defaultValue()), parameters.now);
}
void evaluate(const PropertyEvaluationParameters& parameters) {
diff --git a/src/mbgl/style/paint_property_binder.hpp b/src/mbgl/style/paint_property_binder.hpp
new file mode 100644
index 0000000000..79c7692b2f
--- /dev/null
+++ b/src/mbgl/style/paint_property_binder.hpp
@@ -0,0 +1,287 @@
+#pragma once
+
+#include <mbgl/programs/attributes.hpp>
+#include <mbgl/gl/attribute.hpp>
+#include <mbgl/gl/uniform.hpp>
+#include <mbgl/util/type_list.hpp>
+
+namespace mbgl {
+namespace style {
+
+template <class T, class A>
+class ConstantPaintPropertyBinder {
+public:
+ using Attribute = A;
+ using AttributeValue = typename Attribute::Value;
+ using AttributeBinding = typename Attribute::Binding;
+
+ ConstantPaintPropertyBinder(T constant_)
+ : constant(std::move(constant_)) {
+ }
+
+ void populateVertexVector(const GeometryTileFeature&, std::size_t) {}
+ void upload(gl::Context&) {}
+
+ AttributeBinding minAttributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const {
+ return typename Attribute::ConstantBinding {
+ Attribute::value(currentValue.constantOr(constant))
+ };
+ }
+
+ AttributeBinding maxAttributeBinding(const PossiblyEvaluatedPropertyValue<T>&) const {
+ return AttributeBinding();
+ }
+
+ float interpolationFactor(float) const {
+ return 0.0f;
+ }
+
+private:
+ T constant;
+};
+
+template <class T, class A>
+class SourceFunctionPaintPropertyBinder {
+public:
+ using Attribute = A;
+ using AttributeValue = typename Attribute::Value;
+ using AttributeBinding = typename Attribute::Binding;
+
+ using Attributes = gl::Attributes<Attribute>;
+ using Vertex = typename Attributes::Vertex;
+
+ SourceFunctionPaintPropertyBinder(SourceFunction<T> function_, T defaultValue_)
+ : function(std::move(function_)),
+ defaultValue(std::move(defaultValue_)) {
+ }
+
+ void populateVertexVector(const GeometryTileFeature& feature, std::size_t length) {
+ AttributeValue value = Attribute::value(function.evaluate(feature, defaultValue));
+ for (std::size_t i = vertexVector.vertexSize(); i < length; ++i) {
+ vertexVector.emplace_back(Vertex { value });
+ }
+ }
+
+ void upload(gl::Context& context) {
+ vertexBuffer = context.createVertexBuffer(std::move(vertexVector));
+ }
+
+ AttributeBinding minAttributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const {
+ if (currentValue.isConstant()) {
+ return typename Attribute::ConstantBinding {
+ Attribute::value(*currentValue.constant())
+ };
+ } else {
+ return Attributes::allVariableBindings(*vertexBuffer)
+ .template get<Attribute>();
+ }
+ }
+
+ AttributeBinding maxAttributeBinding(const PossiblyEvaluatedPropertyValue<T>&) const {
+ return AttributeBinding();
+ }
+
+ float interpolationFactor(float) const {
+ return 0.0f;
+ }
+
+private:
+ SourceFunction<T> function;
+ T defaultValue;
+ gl::VertexVector<Vertex> vertexVector;
+ optional<gl::VertexBuffer<Vertex>> vertexBuffer;
+};
+
+template <class T, class A>
+class CompositeFunctionPaintPropertyBinder {
+public:
+ using Attribute = A;
+ using AttributeValue = typename Attribute::Value;
+ using AttributeBinding = typename Attribute::Binding;
+
+ using MinAttribute = attributes::Min<Attribute>;
+ using MaxAttribute = attributes::Max<Attribute>;
+
+ using Attributes = gl::Attributes<MinAttribute, MaxAttribute>;
+ using Vertex = typename Attributes::Vertex;
+
+ CompositeFunctionPaintPropertyBinder(CompositeFunction<T> function_, float zoom, T defaultValue_)
+ : function(std::move(function_)),
+ defaultValue(std::move(defaultValue_)),
+ coveringRanges(function.coveringRanges(zoom)) {
+ }
+
+ void populateVertexVector(const GeometryTileFeature& feature, std::size_t length) {
+ Range<T> range = function.evaluate(std::get<1>(coveringRanges), feature, defaultValue);
+ AttributeValue min = Attribute::value(range.min);
+ AttributeValue max = Attribute::value(range.max);
+ for (std::size_t i = vertexVector.vertexSize(); i < length; ++i) {
+ vertexVector.emplace_back(Vertex { min, max });
+ }
+ }
+
+ void upload(gl::Context& context) {
+ vertexBuffer = context.createVertexBuffer(std::move(vertexVector));
+ }
+
+ AttributeBinding minAttributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const {
+ if (currentValue.isConstant()) {
+ return typename Attribute::ConstantBinding {
+ Attribute::value(*currentValue.constant())
+ };
+ } else {
+ return Attributes::allVariableBindings(*vertexBuffer)
+ .template get<MinAttribute>();
+ }
+ }
+
+ AttributeBinding maxAttributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const {
+ if (currentValue.isConstant()) {
+ return AttributeBinding();
+ } else {
+ return Attributes::allVariableBindings(*vertexBuffer)
+ .template get<MaxAttribute>();
+ }
+ }
+
+ float interpolationFactor(float currentZoom) const {
+ return util::interpolationFactor(1.0f, std::get<0>(coveringRanges), currentZoom);
+ }
+
+private:
+ using InnerStops = typename CompositeFunction<T>::InnerStops;
+ CompositeFunction<T> function;
+ T defaultValue;
+ std::tuple<Range<float>, Range<InnerStops>> coveringRanges;
+ gl::VertexVector<Vertex> vertexVector;
+ optional<gl::VertexBuffer<Vertex>> vertexBuffer;
+};
+
+template <class PaintProperty>
+class PaintPropertyBinder {
+public:
+ using Type = typename PaintProperty::Type;
+ using Attribute = typename PaintProperty::Attribute;
+ using PropertyValue = typename PaintProperty::EvaluatedType;
+
+ using Binder = variant<
+ ConstantPaintPropertyBinder<Type, Attribute>,
+ SourceFunctionPaintPropertyBinder<Type, Attribute>,
+ CompositeFunctionPaintPropertyBinder<Type, Attribute>>;
+
+ PaintPropertyBinder(const PropertyValue& value, float zoom)
+ : binder(value.match(
+ [&] (const Type& constant) -> Binder {
+ return ConstantPaintPropertyBinder<Type, Attribute>(constant);
+ },
+ [&] (const SourceFunction<Type>& function) {
+ return SourceFunctionPaintPropertyBinder<Type, Attribute>(function, PaintProperty::defaultValue());
+ },
+ [&] (const CompositeFunction<Type>& function) {
+ return CompositeFunctionPaintPropertyBinder<Type, Attribute>(function, zoom, PaintProperty::defaultValue());
+ }
+ )) {
+ }
+
+ void populateVertexVector(const GeometryTileFeature& feature, std::size_t length) {
+ binder.match([&] (auto& b) {
+ b.populateVertexVector(feature, length);
+ });
+ }
+
+ void upload(gl::Context& context) {
+ binder.match([&] (auto& b) {
+ b.upload(context);
+ });
+ }
+
+ using MinAttribute = attributes::Min<Attribute>;
+ using MaxAttribute = attributes::Max<Attribute>;
+ using AttributeBinding = typename Attribute::Binding;
+
+ AttributeBinding minAttributeBinding(const PropertyValue& currentValue) const {
+ return binder.match([&] (const auto& b) {
+ return b.minAttributeBinding(currentValue);
+ });
+ }
+
+ AttributeBinding maxAttributeBinding(const PropertyValue& currentValue) const {
+ return binder.match([&] (const auto& b) {
+ return b.maxAttributeBinding(currentValue);
+ });
+ }
+
+ using InterpolationUniform = attributes::InterpolationUniform<Attribute>;
+ using InterpolationUniformValue = typename InterpolationUniform::Value;
+
+ InterpolationUniformValue interpolationUniformValue(float currentZoom) const {
+ return InterpolationUniformValue {
+ binder.match([&] (const auto& b) {
+ return b.interpolationFactor(currentZoom);
+ })
+ };
+ }
+
+private:
+ Binder binder;
+};
+
+template <class Ps>
+class PaintPropertyBinders;
+
+template <class... Ps>
+class PaintPropertyBinders<TypeList<Ps...>> {
+public:
+ using Binders = IndexedTuple<TypeList<Ps...>, TypeList<PaintPropertyBinder<Ps>...>>;
+
+ template <class EvaluatedProperties>
+ PaintPropertyBinders(const EvaluatedProperties& properties, float z)
+ : binders(PaintPropertyBinder<Ps>(properties.template get<Ps>(), z)...) {
+ (void)z; // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56958
+ }
+
+ void populateVertexVectors(const GeometryTileFeature& feature, std::size_t length) {
+ util::ignore({
+ (binders.template get<Ps>().populateVertexVector(feature, length), 0)...
+ });
+ }
+
+ void upload(gl::Context& context) {
+ util::ignore({
+ (binders.template get<Ps>().upload(context), 0)...
+ });
+ }
+
+ using MinAttributes = gl::Attributes<typename PaintPropertyBinder<Ps>::MinAttribute...>;
+ using MaxAttributes = gl::Attributes<typename PaintPropertyBinder<Ps>::MaxAttribute...>;
+
+ using Attributes = gl::ConcatenateAttributes<MinAttributes, MaxAttributes>;
+ using AttributeBindings = typename Attributes::Bindings;
+
+ template <class EvaluatedProperties>
+ AttributeBindings attributeBindings(const EvaluatedProperties& currentProperties) const {
+ const typename MinAttributes::Bindings min {
+ binders.template get<Ps>().minAttributeBinding(currentProperties.template get<Ps>())...
+ };
+ const typename MaxAttributes::Bindings max {
+ binders.template get<Ps>().maxAttributeBinding(currentProperties.template get<Ps>())...
+ };
+ return min.concat(max);
+ }
+
+ using Uniforms = gl::Uniforms<typename PaintPropertyBinder<Ps>::InterpolationUniform...>;
+ using UniformValues = typename Uniforms::Values;
+
+ UniformValues uniformValues(float currentZoom) const {
+ (void)currentZoom; // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56958
+ return UniformValues {
+ binders.template get<Ps>().interpolationUniformValue(currentZoom)...
+ };
+ }
+
+private:
+ Binders binders;
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/parser.cpp b/src/mbgl/style/parser.cpp
index c6c6e50dd7..926c243733 100644
--- a/src/mbgl/style/parser.cpp
+++ b/src/mbgl/style/parser.cpp
@@ -241,10 +241,14 @@ std::vector<FontStack> Parser::fontStacks() const {
result.insert({"Open Sans Regular", "Arial Unicode MS Regular"});
} else if (textFont.isConstant()) {
result.insert(textFont.asConstant());
- } else if (textFont.isFunction()) {
- for (const auto& stop : textFont.asFunction().getStops()) {
- result.insert(stop.second);
- }
+ } else if (textFont.isCameraFunction()) {
+ textFont.asCameraFunction().stops.match(
+ [&] (const auto& stops) {
+ for (const auto& stop : stops.stops) {
+ result.insert(stop.second);
+ }
+ }
+ );
}
}
}
diff --git a/src/mbgl/style/possibly_evaluated_property_value.hpp b/src/mbgl/style/possibly_evaluated_property_value.hpp
new file mode 100644
index 0000000000..8c3f1780a6
--- /dev/null
+++ b/src/mbgl/style/possibly_evaluated_property_value.hpp
@@ -0,0 +1,67 @@
+#pragma once
+
+#include <mbgl/style/function/source_function.hpp>
+#include <mbgl/style/function/composite_function.hpp>
+#include <mbgl/util/interpolate.hpp>
+#include <mbgl/util/variant.hpp>
+
+namespace mbgl {
+
+class GeometryTileFeature;
+
+namespace style {
+
+template <class T>
+class PossiblyEvaluatedPropertyValue {
+private:
+ using Value = variant<
+ T,
+ SourceFunction<T>,
+ CompositeFunction<T>>;
+
+ Value value;
+
+public:
+ PossiblyEvaluatedPropertyValue() = default;
+ PossiblyEvaluatedPropertyValue(Value v) : value(std::move(v)) {}
+
+ bool isConstant() const {
+ return value.template is<T>();
+ }
+
+ optional<T> constant() const {
+ return value.match(
+ [&] (const T& t) { return optional<T>(t); },
+ [&] (const auto&) { return optional<T>(); });
+ }
+
+ T constantOr(const T& t) const {
+ return constant().value_or(t);
+ }
+
+ template <class... Ts>
+ auto match(Ts&&... ts) const {
+ return value.match(std::forward<Ts>(ts)...);
+ }
+};
+
+} // namespace style
+
+namespace util {
+
+template <typename T>
+struct Interpolator<style::PossiblyEvaluatedPropertyValue<T>> {
+ style::PossiblyEvaluatedPropertyValue<T> operator()(const style::PossiblyEvaluatedPropertyValue<T>& a,
+ const style::PossiblyEvaluatedPropertyValue<T>& b,
+ const double t) const {
+ if (a.isConstant() && b.isConstant()) {
+ return { interpolate(*a.constant(), *b.constant(), t) };
+ } else {
+ return { a };
+ }
+ }
+};
+
+} // namespace util
+
+} // namespace mbgl
diff --git a/src/mbgl/style/property_evaluator.hpp b/src/mbgl/style/property_evaluator.hpp
index ca4962d948..3f629ada4f 100644
--- a/src/mbgl/style/property_evaluator.hpp
+++ b/src/mbgl/style/property_evaluator.hpp
@@ -17,7 +17,7 @@ public:
T operator()(const Undefined&) const { return defaultValue; }
T operator()(const T& constant) const { return constant; }
- T operator()(const Function<T>& fn) const { return fn.evaluate(parameters.z); }
+ T operator()(const CameraFunction<T>& fn) const { return fn.evaluate(parameters.z); }
private:
const PropertyEvaluationParameters& parameters;
diff --git a/src/mbgl/style/source_impl.cpp b/src/mbgl/style/source_impl.cpp
index 624fee8ee5..003df4f6b1 100644
--- a/src/mbgl/style/source_impl.cpp
+++ b/src/mbgl/style/source_impl.cpp
@@ -139,10 +139,10 @@ void Source::Impl::updateTiles(const UpdateParameters& parameters) {
algorithm::updateRenderables(getTileFn, createTileFn, retainTileFn, renderTileFn,
idealTiles, zoomRange, tileZoom);
- if (type != SourceType::Annotations && cache.getSize() == 0) {
+ if (type != SourceType::Annotations) {
size_t conservativeCacheSize =
- std::max((float)parameters.transformState.getSize().width / util::tileSize, 1.0f) *
- std::max((float)parameters.transformState.getSize().height / util::tileSize, 1.0f) *
+ std::max((float)parameters.transformState.getSize().width / tileSize, 1.0f) *
+ std::max((float)parameters.transformState.getSize().height / tileSize, 1.0f) *
(parameters.transformState.getMaxZoom() - parameters.transformState.getMinZoom() + 1) *
0.5;
cache.setSize(conservativeCacheSize);
diff --git a/src/mbgl/style/source_observer.hpp b/src/mbgl/style/source_observer.hpp
index dcbcaeabaf..9be7c67960 100644
--- a/src/mbgl/style/source_observer.hpp
+++ b/src/mbgl/style/source_observer.hpp
@@ -20,7 +20,7 @@ public:
virtual void onSourceAttributionChanged(Source&, const std::string&) {}
virtual void onSourceError(Source&, std::exception_ptr) {}
- //Source description needs to be reloaded
+ // Source description needs to be reloaded
virtual void onSourceDescriptionChanged(Source&) {}
virtual void onTileChanged(Source&, const OverscaledTileID&) {}
diff --git a/src/mbgl/style/sources/geojson_source_impl.cpp b/src/mbgl/style/sources/geojson_source_impl.cpp
index 3f3bc879f7..c7c3753076 100644
--- a/src/mbgl/style/sources/geojson_source_impl.cpp
+++ b/src/mbgl/style/sources/geojson_source_impl.cpp
@@ -39,7 +39,7 @@ GeoJSONSource::Impl::~Impl() = default;
void GeoJSONSource::Impl::setURL(std::string url_) {
url = std::move(url_);
- //Signal that the source description needs a reload
+ // Signal that the source description needs a reload
if (loaded || req) {
loaded = false;
req.reset();
@@ -57,7 +57,7 @@ void GeoJSONSource::Impl::setGeoJSON(const GeoJSON& geoJSON) {
_setGeoJSON(geoJSON);
}
-//Private implementation
+// Private implementation
void GeoJSONSource::Impl::_setGeoJSON(const GeoJSON& geoJSON) {
double scale = util::EXTENT / util::tileSize;
diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp
index 0b516f7b9f..b6f14ecf4b 100644
--- a/src/mbgl/style/style.cpp
+++ b/src/mbgl/style/style.cpp
@@ -134,12 +134,12 @@ void Style::setJSON(const std::string& json) {
spriteAtlas->load(parser.spriteURL, fileSource);
loaded = true;
-
+
observer->onStyleLoaded();
}
void Style::addSource(std::unique_ptr<Source> source) {
- //Guard against duplicate source ids
+ // Guard against duplicate source ids
auto it = std::find_if(sources.begin(), sources.end(), [&](const auto& existing) {
return existing->getID() == source->getID();
});
@@ -159,7 +159,7 @@ std::unique_ptr<Source> Style::removeSource(const std::string& id) {
});
if (it == sources.end()) {
- throw std::runtime_error("no such source");
+ return nullptr;
}
auto source = std::move(*it);
@@ -231,7 +231,7 @@ std::unique_ptr<Layer> Style::removeLayer(const std::string& id) {
});
if (it == layers.end())
- throw std::runtime_error("no such layer");
+ return nullptr;
auto layer = std::move(*it);
@@ -662,12 +662,17 @@ void Style::onLayerPaintPropertyChanged(Layer&) {
observer->onUpdate(Update::RecalculateStyle | Update::Classes);
}
+void Style::onLayerDataDrivenPaintPropertyChanged(Layer& layer) {
+ layer.accept(QueueSourceReloadVisitor { updateBatch });
+ observer->onUpdate(Update::RecalculateStyle | Update::Classes | Update::Layout);
+}
+
void Style::onLayerLayoutPropertyChanged(Layer& layer, const char * property) {
layer.accept(QueueSourceReloadVisitor { updateBatch });
auto update = Update::Layout;
- //Recalculate the style for certain properties
+ // Recalculate the style for certain properties
bool needsRecalculation = strcmp(property, "icon-size") == 0 || strcmp(property, "text-size") == 0;
if (needsRecalculation) {
update |= Update::RecalculateStyle;
diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp
index d46e80e8bf..4c4bcec63a 100644
--- a/src/mbgl/style/style.hpp
+++ b/src/mbgl/style/style.hpp
@@ -146,6 +146,7 @@ private:
void onLayerFilterChanged(Layer&) override;
void onLayerVisibilityChanged(Layer&) override;
void onLayerPaintPropertyChanged(Layer&) override;
+ void onLayerDataDrivenPaintPropertyChanged(Layer&) override;
void onLayerLayoutPropertyChanged(Layer&, const char *) override;
Observer nullObserver;
diff --git a/src/mbgl/style/tile_source_impl.hpp b/src/mbgl/style/tile_source_impl.hpp
index 366e0b60a2..2b17872d2b 100644
--- a/src/mbgl/style/tile_source_impl.hpp
+++ b/src/mbgl/style/tile_source_impl.hpp
@@ -33,7 +33,7 @@ public:
const variant<std::string, Tileset>& getURLOrTileset() const {
return urlOrTileset;
}
-
+
optional<std::string> getAttribution() const override;
protected:
diff --git a/src/mbgl/text/glyph.hpp b/src/mbgl/text/glyph.hpp
index 2bf1448492..175a36f0fa 100644
--- a/src/mbgl/text/glyph.hpp
+++ b/src/mbgl/text/glyph.hpp
@@ -2,6 +2,8 @@
#include <mbgl/text/glyph_range.hpp>
#include <mbgl/util/rect.hpp>
+#include <mbgl/util/traits.hpp>
+#include <mbgl/util/image.hpp>
#include <cstdint>
#include <vector>
@@ -52,25 +54,28 @@ typedef std::map<uint32_t, Glyph> GlyphPositions;
class PositionedGlyph {
public:
- explicit PositionedGlyph(uint32_t glyph_, float x_, float y_)
- : glyph(glyph_), x(x_), y(y_) {}
+ explicit PositionedGlyph(uint32_t glyph_, float x_, float y_, float angle_)
+ : glyph(glyph_), x(x_), y(y_), angle(angle_) {}
uint32_t glyph = 0;
float x = 0;
float y = 0;
+ float angle = 0;
};
+enum class WritingModeType : uint8_t;
+
class Shaping {
public:
explicit Shaping() : top(0), bottom(0), left(0), right(0) {}
- explicit Shaping(float x, float y, std::u16string text_)
- : text(std::move(text_)), top(y), bottom(y), left(x), right(x) {}
+ explicit Shaping(float x, float y, WritingModeType writingMode_)
+ : top(y), bottom(y), left(x), right(x), writingMode(writingMode_) {}
std::vector<PositionedGlyph> positionedGlyphs;
- std::u16string text;
int32_t top;
int32_t bottom;
int32_t left;
int32_t right;
+ WritingModeType writingMode;
explicit operator bool() const { return !positionedGlyphs.empty(); }
};
@@ -84,10 +89,36 @@ public:
uint32_t id = 0;
// A signed distance field of the glyph with a border (see above).
- std::string bitmap;
+ AlphaImage bitmap;
// Glyph metrics
GlyphMetrics metrics;
};
+enum class WritingModeType : uint8_t {
+ None = 0,
+ Horizontal = 1 << 0,
+ Vertical = 1 << 1,
+};
+
+constexpr WritingModeType operator|(WritingModeType a, WritingModeType b) {
+ return WritingModeType(mbgl::underlying_type(a) | mbgl::underlying_type(b));
+}
+
+constexpr WritingModeType& operator|=(WritingModeType& a, WritingModeType b) {
+ return (a = a | b);
+}
+
+constexpr bool operator&(WritingModeType lhs, WritingModeType rhs) {
+ return mbgl::underlying_type(lhs) & mbgl::underlying_type(rhs);
+}
+
+constexpr WritingModeType& operator&=(WritingModeType& lhs, WritingModeType rhs) {
+ return (lhs = WritingModeType(mbgl::underlying_type(lhs) & mbgl::underlying_type(rhs)));
+}
+
+constexpr WritingModeType operator~(WritingModeType value) {
+ return WritingModeType(~mbgl::underlying_type(value));
+}
+
} // end namespace mbgl
diff --git a/src/mbgl/text/glyph_atlas.cpp b/src/mbgl/text/glyph_atlas.cpp
index dc1fe2b1d9..1b3f7518b5 100644
--- a/src/mbgl/text/glyph_atlas.cpp
+++ b/src/mbgl/text/glyph_atlas.cpp
@@ -23,16 +23,17 @@ GlyphAtlas::GlyphAtlas(const Size size, FileSource& fileSource_)
GlyphAtlas::~GlyphAtlas() = default;
void GlyphAtlas::requestGlyphRange(const FontStack& fontStack, const GlyphRange& range) {
- std::lock_guard<std::mutex> lock(rangesMutex);
- auto& rangeSets = ranges[fontStack];
+ std::lock_guard<std::mutex> lock(mutex);
+ auto& rangeSets = entries[fontStack].ranges;
const auto& rangeSetsIt = rangeSets.find(range);
if (rangeSetsIt != rangeSets.end()) {
return;
}
- rangeSets.emplace(range,
- std::make_unique<GlyphPBF>(this, fontStack, range, observer, fileSource));
+ rangeSets.emplace(std::piecewise_construct,
+ std::forward_as_tuple(range),
+ std::forward_as_tuple(this, fontStack, range, observer, fileSource));
}
bool GlyphAtlas::hasGlyphRanges(const FontStack& fontStack, const GlyphRangeSet& glyphRanges) {
@@ -40,8 +41,8 @@ bool GlyphAtlas::hasGlyphRanges(const FontStack& fontStack, const GlyphRangeSet&
return true;
}
- std::lock_guard<std::mutex> lock(rangesMutex);
- const auto& rangeSets = ranges[fontStack];
+ std::lock_guard<std::mutex> lock(mutex);
+ const auto& rangeSets = entries[fontStack].ranges;
bool hasRanges = true;
for (const auto& range : glyphRanges) {
@@ -55,7 +56,7 @@ bool GlyphAtlas::hasGlyphRanges(const FontStack& fontStack, const GlyphRangeSet&
continue;
}
- if (!rangeSetsIt->second->isParsed()) {
+ if (!rangeSetsIt->second.isParsed()) {
hasRanges = false;
}
}
@@ -64,16 +65,8 @@ bool GlyphAtlas::hasGlyphRanges(const FontStack& fontStack, const GlyphRangeSet&
}
util::exclusive<GlyphSet> GlyphAtlas::getGlyphSet(const FontStack& fontStack) {
- auto lock = std::make_unique<std::lock_guard<std::mutex>>(glyphSetsMutex);
-
- auto it = glyphSets.find(fontStack);
- if (it == glyphSets.end()) {
- it = glyphSets.emplace(fontStack, std::make_unique<GlyphSet>()).first;
- }
-
- // FIXME: We lock all GlyphSets, but what we should
- // really do is lock only the one we are returning.
- return { it->second.get(), std::move(lock) };
+ auto lock = std::make_unique<std::lock_guard<std::mutex>>(mutex);
+ return { &entries[fontStack].glyphSet, std::move(lock) };
}
void GlyphAtlas::setObserver(GlyphAtlasObserver* observer_) {
@@ -83,12 +76,10 @@ void GlyphAtlas::setObserver(GlyphAtlasObserver* observer_) {
void GlyphAtlas::addGlyphs(uintptr_t tileUID,
const std::u16string& text,
const FontStack& fontStack,
- const GlyphSet& glyphSet,
+ const util::exclusive<GlyphSet>& glyphSet,
GlyphPositions& face)
{
- std::lock_guard<std::mutex> lock(mtx);
-
- const std::map<uint32_t, SDFGlyph>& sdfs = glyphSet.getSDFs();
+ const std::map<uint32_t, SDFGlyph>& sdfs = glyphSet->getSDFs();
for (char16_t chr : text)
{
@@ -107,7 +98,7 @@ Rect<uint16_t> GlyphAtlas::addGlyph(uintptr_t tileUID,
const FontStack& fontStack,
const SDFGlyph& glyph)
{
- std::map<uint32_t, GlyphValue>& face = index[fontStack];
+ std::map<uint32_t, GlyphValue>& face = entries[fontStack].glyphValues;
auto it = face.find(glyph.id);
// The glyph is already in this texture.
@@ -124,48 +115,26 @@ Rect<uint16_t> GlyphAtlas::addGlyph(uintptr_t tileUID,
return Rect<uint16_t>{ 0, 0, 0, 0 };
}
- uint16_t buffered_width = glyph.metrics.width + SDFGlyph::borderSize * 2;
- uint16_t buffered_height = glyph.metrics.height + SDFGlyph::borderSize * 2;
-
- // Guard against mismatches between the glyph bitmap size and the size mandated by
- // its metrics.
- if (size_t(buffered_width * buffered_height) != glyph.bitmap.size()) {
- return Rect<uint16_t>{ 0, 0, 0, 0 };
- }
-
// Add a 1px border around every image.
- const uint16_t padding = 1;
- uint16_t pack_width = buffered_width + 2 * padding;
- uint16_t pack_height = buffered_height + 2 * padding;
+ const uint32_t padding = 1;
+ uint16_t width = glyph.bitmap.size.width + 2 * padding;
+ uint16_t height = glyph.bitmap.size.height + 2 * padding;
// Increase to next number divisible by 4, but at least 1.
// This is so we can scale down the texture coordinates and pack them
// into 2 bytes rather than 4 bytes.
- pack_width += (4 - pack_width % 4);
- pack_height += (4 - pack_height % 4);
+ width += (4 - width % 4);
+ height += (4 - height % 4);
- Rect<uint16_t> rect = bin.allocate(pack_width, pack_height);
+ Rect<uint16_t> rect = bin.allocate(width, height);
if (rect.w == 0) {
Log::Error(Event::OpenGL, "glyph bitmap overflow");
return rect;
}
- // Verify that binpack didn't produce a rect that goes beyond the size of the image.
- // This should never happen.
- 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 = 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++) {
- image.data[y1 + x] = source[y2 + x];
- }
- }
+ AlphaImage::copy(glyph.bitmap, image, { 0, 0 }, { rect.x + padding, rect.y + padding }, glyph.bitmap.size);
dirty = true;
@@ -173,10 +142,10 @@ Rect<uint16_t> GlyphAtlas::addGlyph(uintptr_t tileUID,
}
void GlyphAtlas::removeGlyphs(uintptr_t tileUID) {
- std::lock_guard<std::mutex> lock(mtx);
+ std::lock_guard<std::mutex> lock(mutex);
- for (auto& faces : index) {
- std::map<uint32_t, GlyphValue>& face = faces.second;
+ for (auto& entry : entries) {
+ std::map<uint32_t, GlyphValue>& face = entry.second.glyphValues;
for (auto it = face.begin(); it != face.end(); /* we advance in the body */) {
GlyphValue& value = it->second;
value.ids.erase(tileUID);
@@ -212,8 +181,6 @@ Size GlyphAtlas::getSize() const {
}
void GlyphAtlas::upload(gl::Context& context, gl::TextureUnit unit) {
- std::lock_guard<std::mutex> lock(mtx);
-
if (!texture) {
texture = context.createTexture(image, unit);
} else if (dirty) {
diff --git a/src/mbgl/text/glyph_atlas.hpp b/src/mbgl/text/glyph_atlas.hpp
index af14aace5b..8267630096 100644
--- a/src/mbgl/text/glyph_atlas.hpp
+++ b/src/mbgl/text/glyph_atlas.hpp
@@ -17,8 +17,6 @@
#include <unordered_set>
#include <unordered_map>
#include <mutex>
-#include <exception>
-#include <vector>
namespace mbgl {
@@ -57,7 +55,7 @@ public:
void addGlyphs(uintptr_t tileUID,
const std::u16string& text,
const FontStack&,
- const GlyphSet&,
+ const util::exclusive<GlyphSet>&,
GlyphPositions&);
void removeGlyphs(uintptr_t tileUID);
@@ -77,20 +75,9 @@ private:
const FontStack&,
const SDFGlyph&);
-
FileSource& fileSource;
std::string glyphURL;
- std::unordered_map<FontStack, std::map<GlyphRange, std::unique_ptr<GlyphPBF>>, FontStackHash> ranges;
- std::mutex rangesMutex;
-
- std::unordered_map<FontStack, std::unique_ptr<GlyphSet>, FontStackHash> glyphSets;
- std::mutex glyphSetsMutex;
-
- util::WorkQueue workQueue;
-
- GlyphAtlasObserver* observer = nullptr;
-
struct GlyphValue {
GlyphValue(Rect<uint16_t> rect_, uintptr_t id)
: rect(std::move(rect_)), ids({ id }) {}
@@ -98,10 +85,20 @@ private:
std::unordered_set<uintptr_t> ids;
};
- std::mutex mtx;
+ struct Entry {
+ std::map<GlyphRange, GlyphPBF> ranges;
+ GlyphSet glyphSet;
+ std::map<uint32_t, GlyphValue> glyphValues;
+ };
+
+ std::unordered_map<FontStack, Entry, FontStackHash> entries;
+ std::mutex mutex;
+
+ util::WorkQueue workQueue;
+ GlyphAtlasObserver* observer = nullptr;
+
BinPack<uint16_t> bin;
- std::unordered_map<FontStack, std::map<uint32_t, GlyphValue>, FontStackHash> index;
- const AlphaImage image;
+ AlphaImage image;
std::atomic<bool> dirty;
mbgl::optional<gl::Texture> texture;
};
diff --git a/src/mbgl/text/glyph_pbf.cpp b/src/mbgl/text/glyph_pbf.cpp
index cdeac57984..5c57d278db 100644
--- a/src/mbgl/text/glyph_pbf.cpp
+++ b/src/mbgl/text/glyph_pbf.cpp
@@ -25,6 +25,7 @@ void parseGlyphPBF(GlyphSet& glyphSet, const GlyphRange& glyphRange, const std::
auto glyph_pbf = fontstack_pbf.get_message();
SDFGlyph glyph;
+ protozero::data_view glyphData;
bool hasID = false, hasWidth = false, hasHeight = false, hasLeft = false,
hasTop = false, hasAdvance = false;
@@ -36,7 +37,7 @@ void parseGlyphPBF(GlyphSet& glyphSet, const GlyphRange& glyphRange, const std::
hasID = true;
break;
case 2: // bitmap
- glyph.bitmap = glyph_pbf.get_string();
+ glyphData = glyph_pbf.get_view();
break;
case 3: // width
glyph.metrics.width = glyph_pbf.get_uint32();
@@ -64,26 +65,35 @@ void parseGlyphPBF(GlyphSet& glyphSet, const GlyphRange& glyphRange, const std::
}
}
+ // Only treat this glyph as a correct glyph if it has all required fields. It also
+ // needs to satisfy a few metrics conditions that ensure that the glyph isn't bogus.
+ // All other glyphs are malformed. We're also discarding all glyphs that are outside
+ // the expected glyph range.
+ if (!hasID || !hasWidth || !hasHeight || !hasLeft || !hasTop || !hasAdvance ||
+ glyph.metrics.width >= 256 || glyph.metrics.height >= 256 ||
+ glyph.metrics.left < -128 || glyph.metrics.left >= 128 ||
+ glyph.metrics.top < -128 || glyph.metrics.top >= 128 ||
+ glyph.metrics.advance >= 256 ||
+ glyph.id < glyphRange.first || glyph.id > glyphRange.second) {
+ continue;
+ }
+
// If the area of width/height is non-zero, we need to adjust the expected size
// with the implicit border size, otherwise we expect there to be no bitmap at all.
- const uint32_t expectedBitmapSize =
- glyph.metrics.width && glyph.metrics.height
- ? (glyph.metrics.width + 2 * SDFGlyph::borderSize) *
- (glyph.metrics.height + 2 * SDFGlyph::borderSize)
- : 0;
-
- // Only treat this glyph as a correct glyph if it has all required fields, and if
- // the bitmap has the correct length. It also needs to satisfy a few metrics conditions
- // that ensure that the glyph isn't bogus. All other glyphs are malformed.
- // We're also discarding all glyphs that are outside the expected glyph range.
- if (hasID && hasWidth && hasHeight && hasLeft && hasTop && hasAdvance &&
- glyph.metrics.width < 256 && glyph.metrics.height < 256 &&
- glyph.metrics.left >= -128 && glyph.metrics.left < 128 &&
- glyph.metrics.top >= -128 && glyph.metrics.top < 128 &&
- glyph.metrics.advance < 256 && glyph.bitmap.size() == expectedBitmapSize &&
- glyph.id >= glyphRange.first && glyph.id <= glyphRange.second) {
- glyphSet.insert(glyph.id, std::move(glyph));
+ if (glyph.metrics.width && glyph.metrics.height) {
+ const Size size {
+ glyph.metrics.width + 2 * SDFGlyph::borderSize,
+ glyph.metrics.height + 2 * SDFGlyph::borderSize
+ };
+
+ if (size.area() != glyphData.size()) {
+ continue;
+ }
+
+ glyph.bitmap = AlphaImage(size, reinterpret_cast<const uint8_t*>(glyphData.data()), glyphData.size());
}
+
+ glyphSet.insert(glyph.id, std::move(glyph));
}
}
}
diff --git a/src/mbgl/text/glyph_set.cpp b/src/mbgl/text/glyph_set.cpp
index f9a90f9bb0..19a6e2cddd 100644
--- a/src/mbgl/text/glyph_set.cpp
+++ b/src/mbgl/text/glyph_set.cpp
@@ -42,18 +42,17 @@ const Shaping GlyphSet::getShaping(const std::u16string& logicalInput,
const float justify,
const float spacing,
const Point<float>& translate,
+ const float verticalHeight,
+ const WritingModeType writingMode,
BiDi& bidi) const {
-
- // 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);
+ Shaping shaping(translate.x * 24, translate.y * 24, writingMode);
std::vector<std::u16string> reorderedLines =
bidi.processText(logicalInput,
- determineLineBreaks(logicalInput, spacing, maxWidth));
+ determineLineBreaks(logicalInput, spacing, maxWidth, writingMode));
shapeLines(shaping, reorderedLines, spacing, lineHeight, horizontalAlign, verticalAlign,
- justify, translate);
+ justify, translate, verticalHeight, writingMode);
return shaping;
}
@@ -114,7 +113,7 @@ float GlyphSet::determineAverageLineWidth(const std::u16string& logicalInput,
int32_t targetLineCount = std::fmax(1, std::ceil(totalWidth / maxWidth));
return totalWidth / targetLineCount;
}
-
+
float calculateBadness(const float lineWidth, const float targetWidth, const float penalty, const bool isLastBreak) {
const float raggedness = std::pow(lineWidth - targetWidth, 2);
if (isLastBreak) {
@@ -130,7 +129,7 @@ float calculateBadness(const float lineWidth, const float targetWidth, const flo
}
return raggedness + std::pow(penalty, 2);
}
-
+
float calculatePenalty(char16_t codePoint, char16_t nextCodePoint) {
float penalty = 0;
// Force break on newline
@@ -146,28 +145,28 @@ float calculatePenalty(char16_t codePoint, char16_t nextCodePoint) {
if (nextCodePoint == 0x29 || nextCodePoint == 0xff09) {
penalty += 50;
}
-
+
return penalty;
}
-
+
struct PotentialBreak {
PotentialBreak(const std::size_t p_index, const float p_x, const PotentialBreak* p_priorBreak, const float p_badness)
: index(p_index), x(p_x), priorBreak(p_priorBreak), badness(p_badness)
{}
-
+
const std::size_t index;
const float x;
const PotentialBreak* priorBreak;
const float badness;
};
-
+
PotentialBreak evaluateBreak(const std::size_t breakIndex, const float breakX, const float targetWidth, const std::list<PotentialBreak>& potentialBreaks, const float penalty, const bool isLastBreak) {
// We could skip evaluating breaks where the line length (breakX - priorBreak.x) > maxWidth
// ...but in fact we allow lines longer than maxWidth (if there's no break points)
// ...and when targetWidth and maxWidth are close, strictly enforcing maxWidth can give
// more lopsided results.
-
+
const PotentialBreak* bestPriorBreak = nullptr;
float bestBreakBadness = calculateBadness(breakX, targetWidth, penalty, isLastBreak);
for (const auto& potentialBreak : potentialBreaks) {
@@ -182,7 +181,7 @@ PotentialBreak evaluateBreak(const std::size_t breakIndex, const float breakX, c
return PotentialBreak(breakIndex, breakX, bestPriorBreak, bestBreakBadness);
}
-
+
std::set<std::size_t> leastBadBreaks(const PotentialBreak& lastLineBreak) {
std::set<std::size_t> leastBadBreaks = { lastLineBreak.index };
const PotentialBreak* priorBreak = lastLineBreak.priorBreak;
@@ -198,17 +197,18 @@ std::set<std::size_t> leastBadBreaks(const PotentialBreak& lastLineBreak) {
// more intuitive, but we can't do that because the visual order may be changed by line breaks!
std::set<std::size_t> GlyphSet::determineLineBreaks(const std::u16string& logicalInput,
const float spacing,
- float maxWidth) const {
- if (!maxWidth) {
+ float maxWidth,
+ const WritingModeType writingMode) const {
+ if (!maxWidth || writingMode != WritingModeType::Horizontal) {
return {};
}
if (logicalInput.empty()) {
return {};
}
-
+
const float targetWidth = determineAverageLineWidth(logicalInput, spacing, maxWidth);
-
+
std::list<PotentialBreak> potentialBreaks;
float currentX = 0;
@@ -218,7 +218,7 @@ std::set<std::size_t> GlyphSet::determineLineBreaks(const std::u16string& logica
if (it != sdfs.end() && !boost::algorithm::is_any_of(u" \t\n\v\f\r")(codePoint)) {
currentX += it->second.metrics.advance + spacing;
}
-
+
// Ideographic characters, spaces, and word-breaking punctuation that often appear without
// surrounding spaces.
if ((i < logicalInput.size() - 1) &&
@@ -239,7 +239,9 @@ void GlyphSet::shapeLines(Shaping& shaping,
const float horizontalAlign,
const float verticalAlign,
const float justify,
- const Point<float>& translate) const {
+ const Point<float>& translate,
+ const float verticalHeight,
+ const WritingModeType writingMode) const {
// the y offset *should* be part of the font metadata
const int32_t yOffset = -17;
@@ -266,15 +268,21 @@ void GlyphSet::shapeLines(Shaping& shaping,
}
const SDFGlyph& glyph = it->second;
- shaping.positionedGlyphs.emplace_back(chr, x, y);
- x += glyph.metrics.advance + spacing;
+
+ if (writingMode == WritingModeType::Horizontal || !util::i18n::hasUprightVerticalOrientation(chr)) {
+ shaping.positionedGlyphs.emplace_back(chr, x, y, 0);
+ x += glyph.metrics.advance + spacing;
+ } else {
+ shaping.positionedGlyphs.emplace_back(chr, x, 0, -M_PI_2);
+ x += verticalHeight + spacing;
+ }
}
// Only justify if we placed at least one glyph
if (shaping.positionedGlyphs.size() != lineStartIndex) {
float lineLength = x - spacing; // Don't count trailing spacing
maxLineLength = util::max(lineLength, maxLineLength);
-
+
justifyLine(shaping.positionedGlyphs, sdfs, lineStartIndex,
shaping.positionedGlyphs.size() - 1, justify);
}
diff --git a/src/mbgl/text/glyph_set.hpp b/src/mbgl/text/glyph_set.hpp
index 3037cefca0..0342c82eb5 100644
--- a/src/mbgl/text/glyph_set.hpp
+++ b/src/mbgl/text/glyph_set.hpp
@@ -18,6 +18,8 @@ public:
float justify,
float spacing,
const Point<float>& translate,
+ float verticalHeight,
+ const WritingModeType,
BiDi& bidi) const;
private:
@@ -26,7 +28,8 @@ private:
float maxWidth) const;
std::set<std::size_t> determineLineBreaks(const std::u16string& logicalInput,
const float spacing,
- float maxWidth) const;
+ float maxWidth,
+ const WritingModeType) const;
void shapeLines(Shaping& shaping,
const std::vector<std::u16string>& lines,
@@ -35,7 +38,9 @@ private:
float horizontalAlign,
float verticalAlign,
float justify,
- const Point<float>& translate) const;
+ const Point<float>& translate,
+ float verticalHeight,
+ const WritingModeType) const;
std::map<uint32_t, SDFGlyph> sdfs;
};
diff --git a/src/mbgl/text/quads.cpp b/src/mbgl/text/quads.cpp
index 1a05e6f94f..6113d1f5d4 100644
--- a/src/mbgl/text/quads.cpp
+++ b/src/mbgl/text/quads.cpp
@@ -13,7 +13,7 @@ using namespace style;
const float globalMinScale = 0.5f; // underscale by 1 zoom level
-SymbolQuads getIconQuads(Anchor& anchor, const PositionedIcon& shapedIcon,
+SymbolQuad getIconQuad(Anchor& anchor, const PositionedIcon& shapedIcon,
const GeometryCoordinates& line, const SymbolLayoutProperties::Evaluated& layout,
const style::SymbolPlacementType placement, const Shaping& shapedText) {
@@ -62,7 +62,7 @@ SymbolQuads getIconQuads(Anchor& anchor, const PositionedIcon& shapedIcon,
bl = {left, bottom};
}
- float angle = layout.get<IconRotate>() * util::DEG2RAD;
+ float angle = shapedIcon.angle;
if (placement == style::SymbolPlacementType::Line) {
assert(static_cast<unsigned int>(anchor.segment) < line.size());
const GeometryCoordinate &prev= line[anchor.segment];
@@ -88,9 +88,7 @@ SymbolQuads getIconQuads(Anchor& anchor, const PositionedIcon& shapedIcon,
br = util::matrixMultiply(matrix, br);
}
- SymbolQuads quads;
- quads.emplace_back(tl, tr, bl, br, image.pos, 0, 0, anchor.point, globalMinScale, std::numeric_limits<float>::infinity());
- return quads;
+ return SymbolQuad { tl, tr, bl, br, image.pos, 0, 0, anchor.point, globalMinScale, std::numeric_limits<float>::infinity(), shapedText.writingMode };
}
struct GlyphInstance {
@@ -207,10 +205,19 @@ SymbolQuads getGlyphQuads(Anchor& anchor, const Shaping& shapedText,
const float x2 = x1 + rect.w;
const float y2 = y1 + rect.h;
- const Point<float> otl{x1, y1};
- const Point<float> otr{x2, y1};
- const Point<float> obl{x1, y2};
- const Point<float> obr{x2, y2};
+ const Point<float> center{positionedGlyph.x, static_cast<float>(static_cast<float>(glyph.metrics.advance) / 2.0)};
+
+ Point<float> otl{x1, y1};
+ Point<float> otr{x2, y1};
+ Point<float> obl{x1, y2};
+ Point<float> obr{x2, y2};
+
+ if (positionedGlyph.angle != 0) {
+ otl = util::rotate(otl - center, positionedGlyph.angle) + center;
+ otr = util::rotate(otr - center, positionedGlyph.angle) + center;
+ obl = util::rotate(obl - center, positionedGlyph.angle) + center;
+ obr = util::rotate(obr - center, positionedGlyph.angle) + center;
+ }
for (const GlyphInstance &instance : glyphInstances) {
@@ -236,7 +243,7 @@ SymbolQuads getGlyphQuads(Anchor& anchor, const Shaping& shapedText,
const float anchorAngle = std::fmod((anchor.angle + instance.offset + 2 * M_PI), (2 * M_PI));
const float glyphAngle = std::fmod((instance.angle + instance.offset + 2 * M_PI), (2 * M_PI));
- quads.emplace_back(tl, tr, bl, br, rect, anchorAngle, glyphAngle, instance.anchorPoint, glyphMinScale, instance.maxScale);
+ quads.emplace_back(tl, tr, bl, br, rect, anchorAngle, glyphAngle, instance.anchorPoint, glyphMinScale, instance.maxScale, shapedText.writingMode);
}
diff --git a/src/mbgl/text/quads.hpp b/src/mbgl/text/quads.hpp
index 75fb53aade..07a94c763b 100644
--- a/src/mbgl/text/quads.hpp
+++ b/src/mbgl/text/quads.hpp
@@ -15,7 +15,7 @@ class PositionedIcon;
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_,
- float minScale_, float maxScale_)
+ float minScale_, float maxScale_, WritingModeType writingMode_)
: tl(std::move(tl_)),
tr(std::move(tr_)),
bl(std::move(bl_)),
@@ -25,18 +25,20 @@ struct SymbolQuad {
glyphAngle(glyphAngle_),
anchorPoint(std::move(anchorPoint_)),
minScale(minScale_),
- maxScale(maxScale_) {}
+ maxScale(maxScale_),
+ writingMode(writingMode_) {}
Point<float> tl, tr, bl, br;
Rect<uint16_t> tex;
float anchorAngle, glyphAngle;
Point<float> anchorPoint;
float minScale, maxScale;
+ WritingModeType writingMode;
};
typedef std::vector<SymbolQuad> SymbolQuads;
-SymbolQuads getIconQuads(Anchor& anchor, const PositionedIcon& shapedIcon,
+SymbolQuad getIconQuad(Anchor& anchor, const PositionedIcon& shapedIcon,
const GeometryCoordinates& line, const style::SymbolLayoutProperties::Evaluated&,
style::SymbolPlacementType placement, const Shaping& shapedText);
diff --git a/src/mbgl/text/shaping.cpp b/src/mbgl/text/shaping.cpp
index 062066aaf4..e68566d419 100644
--- a/src/mbgl/text/shaping.cpp
+++ b/src/mbgl/text/shaping.cpp
@@ -1,19 +1,17 @@
#include <mbgl/text/shaping.hpp>
-#include <mbgl/style/layers/symbol_layer_properties.hpp>
+#include <mbgl/layout/symbol_feature.hpp>
namespace mbgl {
-using namespace style;
-
-PositionedIcon shapeIcon(const SpriteAtlasElement& image, const SymbolLayoutProperties::Evaluated& layout) {
- float dx = layout.get<IconOffset>()[0];
- float dy = layout.get<IconOffset>()[1];
+PositionedIcon shapeIcon(const SpriteAtlasElement& image, const std::array<float, 2>& iconOffset, const float iconRotation) {
+ float dx = iconOffset[0];
+ float dy = iconOffset[1];
float x1 = dx - image.spriteImage->getWidth() / 2.0f;
float x2 = x1 + image.spriteImage->getWidth();
float y1 = dy - image.spriteImage->getHeight() / 2.0f;
float y2 = y1 + image.spriteImage->getHeight();
- return PositionedIcon(image, y1, y2, x1, x2);
+ return PositionedIcon(image, y1, y2, x1, x2, iconRotation);
}
} // namespace mbgl
diff --git a/src/mbgl/text/shaping.hpp b/src/mbgl/text/shaping.hpp
index 30375179b6..1b7b8b2733 100644
--- a/src/mbgl/text/shaping.hpp
+++ b/src/mbgl/text/shaping.hpp
@@ -3,29 +3,39 @@
#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 {
class SpriteAtlasElement;
+class SymbolFeature;
class PositionedIcon {
- public:
- explicit PositionedIcon() {}
- explicit PositionedIcon(const SpriteAtlasElement& _image,
- float _top, float _bottom, float _left, float _right) :
- image(_image), top(_top), bottom(_bottom), left(_left), right(_right) {}
-
- optional<SpriteAtlasElement> image;
- float top = 0;
- float bottom = 0;
- float left = 0;
- float right = 0;
-
- explicit operator bool() const { return image && (*image).pos.hasArea(); }
+public:
+ PositionedIcon() = default;
+ PositionedIcon(const SpriteAtlasElement& image_,
+ float top_,
+ float bottom_,
+ float left_,
+ float right_,
+ float angle_)
+ : image(image_),
+ top(top_),
+ bottom(bottom_),
+ left(left_),
+ right(right_),
+ angle(angle_) {}
+
+ optional<SpriteAtlasElement> image;
+ float top = 0;
+ float bottom = 0;
+ float left = 0;
+ float right = 0;
+ float angle = 0;
+
+ explicit operator bool() const { return image && (*image).pos.hasArea(); }
};
-PositionedIcon shapeIcon(const SpriteAtlasElement& image, const style::SymbolLayoutProperties::Evaluated&);
+PositionedIcon shapeIcon(const SpriteAtlasElement&, const std::array<float, 2>& iconOffset, const float iconRotation);
} // namespace mbgl
diff --git a/src/mbgl/tile/geojson_tile.cpp b/src/mbgl/tile/geojson_tile.cpp
index 61437b79b1..85d8b75619 100644
--- a/src/mbgl/tile/geojson_tile.cpp
+++ b/src/mbgl/tile/geojson_tile.cpp
@@ -25,6 +25,10 @@ public:
return feature.properties;
}
+ optional<FeatureIdentifier> getID() const override {
+ return feature.id;
+ }
+
GeometryCollection getGeometries() const override {
GeometryCollection geometry = apply_visitor(ToGeometryCollection(), feature.geometry);
@@ -80,7 +84,7 @@ GeoJSONTile::GeoJSONTile(const OverscaledTileID& overscaledTileID,
const style::UpdateParameters& parameters)
: GeometryTile(overscaledTileID, sourceID_, parameters) {
}
-
+
void GeoJSONTile::updateData(const mapbox::geometry::feature_collection<int16_t>& features) {
setData(std::make_unique<GeoJSONTileData>(features));
}
diff --git a/src/mbgl/tile/geojson_tile.hpp b/src/mbgl/tile/geojson_tile.hpp
index 2880408736..6ddc6ea482 100644
--- a/src/mbgl/tile/geojson_tile.hpp
+++ b/src/mbgl/tile/geojson_tile.hpp
@@ -16,7 +16,7 @@ public:
const style::UpdateParameters&);
void updateData(const mapbox::geometry::feature_collection<int16_t>&);
-
+
void setNecessity(Necessity) final;
};
diff --git a/src/mbgl/tile/geometry_tile_data.cpp b/src/mbgl/tile/geometry_tile_data.cpp
index 2e465a6f65..ebf27e7858 100644
--- a/src/mbgl/tile/geometry_tile_data.cpp
+++ b/src/mbgl/tile/geometry_tile_data.cpp
@@ -127,7 +127,7 @@ void limitHoles(GeometryCollection& polygon, uint32_t maxHoles) {
polygon.begin() + 1 + maxHoles,
polygon.end(),
[] (const auto& a, const auto& b) {
- return signedArea(a) > signedArea(b);
+ return std::fabs(signedArea(a)) > std::fabs(signedArea(b));
});
polygon.resize(1 + maxHoles);
}
diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp
index 2a86b7feda..b1fd7a852e 100644
--- a/src/mbgl/tile/geometry_tile_worker.cpp
+++ b/src/mbgl/tile/geometry_tile_worker.cpp
@@ -6,6 +6,8 @@
#include <mbgl/layout/symbol_layout.hpp>
#include <mbgl/style/bucket_parameters.hpp>
#include <mbgl/style/group_by_layout.hpp>
+#include <mbgl/style/filter.hpp>
+#include <mbgl/style/filter_evaluator.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <mbgl/renderer/symbol_bucket.hpp>
@@ -212,7 +214,7 @@ void GeometryTileWorker::redoLayout() {
std::unordered_map<std::string, std::unique_ptr<SymbolLayout>> symbolLayoutMap;
std::unordered_map<std::string, std::shared_ptr<Bucket>> buckets;
auto featureIndex = std::make_unique<FeatureIndex>();
- BucketParameters parameters { id, obsolete, *featureIndex, mode };
+ BucketParameters parameters { id, mode };
std::vector<std::vector<const Layer*>> groups = groupByLayout(*layers);
for (auto& group : groups) {
@@ -240,12 +242,27 @@ void GeometryTileWorker::redoLayout() {
if (leader.is<SymbolLayer>()) {
symbolLayoutMap.emplace(leader.getID(),
- leader.as<SymbolLayer>()->impl->createLayout(parameters, *geometryLayer, layerIDs));
+ leader.as<SymbolLayer>()->impl->createLayout(parameters, group, *geometryLayer));
} else {
- std::shared_ptr<Bucket> bucket = leader.baseImpl->createBucket(parameters, *geometryLayer);
+ const Filter& filter = leader.baseImpl->filter;
+ const std::string& sourceLayerID = leader.baseImpl->sourceLayer;
+ std::shared_ptr<Bucket> bucket = leader.baseImpl->createBucket(parameters, group);
+
+ for (std::size_t i = 0; !obsolete && i < geometryLayer->featureCount(); i++) {
+ std::unique_ptr<GeometryTileFeature> feature = geometryLayer->getFeature(i);
+
+ if (!filter(feature->getType(), feature->getID(), [&] (const auto& key) { return feature->getValue(key); }))
+ continue;
+
+ GeometryCollection geometries = feature->getGeometries();
+ bucket->addFeature(*feature, geometries);
+ featureIndex->insert(geometries, i, sourceLayerID, leader.getID());
+ }
+
if (!bucket->hasData()) {
continue;
}
+
for (const auto& layer : group) {
buckets.emplace(layer->getID(), bucket);
}
@@ -324,8 +341,8 @@ void GeometryTileWorker::attemptPlacement() {
}
std::shared_ptr<Bucket> bucket = symbolLayout->place(*collisionTile);
- for (const auto& layerID : symbolLayout->layerIDs) {
- buckets.emplace(layerID, bucket);
+ for (const auto& pair : symbolLayout->layerPaintProperties) {
+ buckets.emplace(pair.first, bucket);
}
}
diff --git a/src/mbgl/tile/raster_tile.cpp b/src/mbgl/tile/raster_tile.cpp
index c7a051f841..2347f8c881 100644
--- a/src/mbgl/tile/raster_tile.cpp
+++ b/src/mbgl/tile/raster_tile.cpp
@@ -41,13 +41,13 @@ void RasterTile::setData(std::shared_ptr<const std::string> data,
void RasterTile::onParsed(std::unique_ptr<Bucket> result) {
bucket = std::move(result);
- availableData = DataAvailability::All;
+ availableData = bucket ? DataAvailability::All : DataAvailability::None;
observer->onTileChanged(*this);
}
void RasterTile::onError(std::exception_ptr err) {
bucket.reset();
- availableData = DataAvailability::All;
+ availableData = DataAvailability::None;
observer->onTileError(*this, err);
}
diff --git a/src/mbgl/tile/raster_tile_worker.cpp b/src/mbgl/tile/raster_tile_worker.cpp
index 219e9a2e41..8c1fc2f673 100644
--- a/src/mbgl/tile/raster_tile_worker.cpp
+++ b/src/mbgl/tile/raster_tile_worker.cpp
@@ -1,6 +1,6 @@
#include <mbgl/tile/raster_tile_worker.hpp>
#include <mbgl/tile/raster_tile.hpp>
-#include <mbgl/renderer/raster_bucket.cpp>
+#include <mbgl/renderer/raster_bucket.hpp>
#include <mbgl/actor/actor.hpp>
#include <mbgl/util/premultiply.hpp>
diff --git a/src/mbgl/tile/tile_id_hash.hpp b/src/mbgl/tile/tile_id_hash.hpp
index 0f52d9816f..f978f20e55 100644
--- a/src/mbgl/tile/tile_id_hash.hpp
+++ b/src/mbgl/tile/tile_id_hash.hpp
@@ -14,7 +14,7 @@ template <> struct hash<mbgl::CanonicalTileID> {
return seed;
}
};
-
+
template <> struct hash<mbgl::UnwrappedTileID> {
size_t operator()(const mbgl::UnwrappedTileID &id) const {
std::size_t seed = 0;
@@ -23,7 +23,7 @@ template <> struct hash<mbgl::UnwrappedTileID> {
return seed;
}
};
-
+
template <> struct hash<mbgl::OverscaledTileID> {
size_t operator()(const mbgl::OverscaledTileID &id) const {
std::size_t seed = 0;
@@ -33,5 +33,5 @@ template <> struct hash<mbgl::OverscaledTileID> {
}
};
-} // namespace std
+} // namespace std
diff --git a/src/mbgl/tile/vector_tile.cpp b/src/mbgl/tile/vector_tile.cpp
index a195885415..68f48e81fd 100644
--- a/src/mbgl/tile/vector_tile.cpp
+++ b/src/mbgl/tile/vector_tile.cpp
@@ -15,9 +15,23 @@ class VectorTileLayer;
using packed_iter_type = protozero::iterator_range<protozero::pbf_reader::const_uint32_iterator>;
+struct VectorTileLayerData {
+ VectorTileLayerData(std::shared_ptr<const std::string>);
+
+ // Hold a reference to the underlying pbf data that backs the lazily-built
+ // components of the owning VectorTileLayer and VectorTileFeature objects
+ std::shared_ptr<const std::string> data;
+
+ uint32_t version = 1;
+ uint32_t extent = 4096;
+ std::unordered_map<std::string, uint32_t> keysMap;
+ std::vector<std::reference_wrapper<const std::string>> keys;
+ std::vector<Value> values;
+};
+
class VectorTileFeature : public GeometryTileFeature {
public:
- VectorTileFeature(protozero::pbf_reader, const VectorTileLayer&);
+ VectorTileFeature(protozero::pbf_reader, std::shared_ptr<VectorTileLayerData> layerData);
FeatureType getType() const override { return type; }
optional<Value> getValue(const std::string&) const override;
@@ -26,16 +40,16 @@ public:
GeometryCollection getGeometries() const override;
private:
- const VectorTileLayer& layer;
+ std::shared_ptr<VectorTileLayerData> layerData;
optional<FeatureIdentifier> id;
FeatureType type = FeatureType::Unknown;
packed_iter_type tags_iter;
packed_iter_type geometry_iter;
};
-
+
class VectorTileLayer : public GeometryTileLayer {
public:
- VectorTileLayer(protozero::pbf_reader);
+ VectorTileLayer(protozero::pbf_reader, std::shared_ptr<const std::string>);
std::size_t featureCount() const override { return features.size(); }
std::unique_ptr<GeometryTileFeature> getFeature(std::size_t) const override;
@@ -46,12 +60,8 @@ private:
friend class VectorTileFeature;
std::string name;
- uint32_t version = 1;
- uint32_t extent = 4096;
- std::unordered_map<std::string, uint32_t> keysMap;
- std::vector<std::reference_wrapper<const std::string>> keys;
- std::vector<Value> values;
std::vector<protozero::pbf_reader> features;
+ std::shared_ptr<VectorTileLayerData> data;
};
class VectorTileData : public GeometryTileData {
@@ -117,8 +127,8 @@ Value parseValue(protozero::pbf_reader data) {
return false;
}
-VectorTileFeature::VectorTileFeature(protozero::pbf_reader feature_pbf, const VectorTileLayer& layer_)
- : layer(layer_) {
+VectorTileFeature::VectorTileFeature(protozero::pbf_reader feature_pbf, std::shared_ptr<VectorTileLayerData> layerData_)
+ : layerData(std::move(layerData_)) {
while (feature_pbf.next()) {
switch (feature_pbf.tag()) {
case 1: // id
@@ -141,8 +151,8 @@ VectorTileFeature::VectorTileFeature(protozero::pbf_reader feature_pbf, const Ve
}
optional<Value> VectorTileFeature::getValue(const std::string& key) const {
- auto keyIter = layer.keysMap.find(key);
- if (keyIter == layer.keysMap.end()) {
+ auto keyIter = layerData->keysMap.find(key);
+ if (keyIter == layerData->keysMap.end()) {
return optional<Value>();
}
@@ -151,7 +161,7 @@ optional<Value> VectorTileFeature::getValue(const std::string& key) const {
while (start_itr != end_itr) {
uint32_t tag_key = static_cast<uint32_t>(*start_itr++);
- if (layer.keysMap.size() <= tag_key) {
+ if (layerData->keysMap.size() <= tag_key) {
throw std::runtime_error("feature referenced out of range key");
}
@@ -160,12 +170,12 @@ optional<Value> VectorTileFeature::getValue(const std::string& key) const {
}
uint32_t tag_val = static_cast<uint32_t>(*start_itr++);;
- if (layer.values.size() <= tag_val) {
+ if (layerData->values.size() <= tag_val) {
throw std::runtime_error("feature referenced out of range value");
}
if (tag_key == keyIter->second) {
- return layer.values[tag_val];
+ return layerData->values[tag_val];
}
}
@@ -182,7 +192,7 @@ std::unordered_map<std::string,Value> VectorTileFeature::getProperties() const {
throw std::runtime_error("uneven number of feature tag ids");
}
uint32_t tag_val = static_cast<uint32_t>(*start_itr++);
- properties[layer.keys.at(tag_key)] = layer.values.at(tag_val);
+ properties[layerData->keys.at(tag_key)] = layerData->values.at(tag_val);
}
return properties;
}
@@ -196,7 +206,7 @@ GeometryCollection VectorTileFeature::getGeometries() const {
uint32_t length = 0;
int32_t x = 0;
int32_t y = 0;
- const float scale = float(util::EXTENT) / layer.extent;
+ const float scale = float(util::EXTENT) / layerData->extent;
GeometryCollection lines;
@@ -234,7 +244,7 @@ GeometryCollection VectorTileFeature::getGeometries() const {
}
}
- if (layer.version >= 2 || type != FeatureType::Polygon) {
+ if (layerData->version >= 2 || type != FeatureType::Polygon) {
return lines;
}
@@ -250,7 +260,7 @@ const GeometryTileLayer* VectorTileData::getLayer(const std::string& name) const
parsed = true;
protozero::pbf_reader tile_pbf(*data);
while (tile_pbf.next(3)) {
- VectorTileLayer layer(tile_pbf.get_message());
+ VectorTileLayer layer(tile_pbf.get_message(), data);
layers.emplace(layer.name, std::move(layer));
}
}
@@ -262,7 +272,13 @@ const GeometryTileLayer* VectorTileData::getLayer(const std::string& name) const
return nullptr;
}
-VectorTileLayer::VectorTileLayer(protozero::pbf_reader layer_pbf) {
+VectorTileLayerData::VectorTileLayerData(std::shared_ptr<const std::string> pbfData) :
+ data(std::move(pbfData))
+{}
+
+VectorTileLayer::VectorTileLayer(protozero::pbf_reader layer_pbf, std::shared_ptr<const std::string> pbfData)
+ : data(std::make_shared<VectorTileLayerData>(std::move(pbfData)))
+{
while (layer_pbf.next()) {
switch (layer_pbf.tag()) {
case 1: // name
@@ -273,18 +289,18 @@ VectorTileLayer::VectorTileLayer(protozero::pbf_reader layer_pbf) {
break;
case 3: // keys
{
- auto iter = keysMap.emplace(layer_pbf.get_string(), keysMap.size());
- keys.emplace_back(std::reference_wrapper<const std::string>(iter.first->first));
+ auto iter = data->keysMap.emplace(layer_pbf.get_string(), data->keysMap.size());
+ data->keys.emplace_back(std::reference_wrapper<const std::string>(iter.first->first));
}
break;
case 4: // values
- values.emplace_back(parseValue(layer_pbf.get_message()));
+ data->values.emplace_back(parseValue(layer_pbf.get_message()));
break;
case 5: // extent
- extent = layer_pbf.get_uint32();
+ data->extent = layer_pbf.get_uint32();
break;
case 15: // version
- version = layer_pbf.get_uint32();
+ data->version = layer_pbf.get_uint32();
break;
default:
layer_pbf.skip();
@@ -294,7 +310,7 @@ VectorTileLayer::VectorTileLayer(protozero::pbf_reader layer_pbf) {
}
std::unique_ptr<GeometryTileFeature> VectorTileLayer::getFeature(std::size_t i) const {
- return std::make_unique<VectorTileFeature>(features.at(i), *this);
+ return std::make_unique<VectorTileFeature>(features.at(i), data);
}
std::string VectorTileLayer::getName() const {
diff --git a/src/mbgl/util/chrono.cpp b/src/mbgl/util/chrono.cpp
index f338f524b9..5c8fd3c0ff 100644
--- a/src/mbgl/util/chrono.cpp
+++ b/src/mbgl/util/chrono.cpp
@@ -33,7 +33,7 @@ std::string iso8601(Timestamp timestamp) {
Timestamp parseTimestamp(const char* timestamp) {
return std::chrono::time_point_cast<Seconds>(std::chrono::system_clock::from_time_t(parse_date(timestamp)));
}
-
+
Timestamp parseTimestamp(const int32_t timestamp) {
return std::chrono::time_point_cast<Seconds>(std::chrono::system_clock::from_time_t(timestamp));
}
diff --git a/src/mbgl/util/http_header.cpp b/src/mbgl/util/http_header.cpp
index e337d4c8ab..40711232ff 100644
--- a/src/mbgl/util/http_header.cpp
+++ b/src/mbgl/util/http_header.cpp
@@ -28,7 +28,7 @@ CacheControl CacheControl::parse(const std::string& value) {
optional<Timestamp> CacheControl::toTimePoint() const {
return maxAge ? util::now() + Seconds(*maxAge) : optional<Timestamp>{};
}
-
+
optional<Timestamp> parseRetryHeaders(const optional<std::string>& retryAfter,
const optional<std::string>& xRateLimitReset) {
if (retryAfter) {
@@ -45,7 +45,7 @@ optional<Timestamp> parseRetryHeaders(const optional<std::string>& retryAfter,
return {};
}
}
-
+
return {};
}
diff --git a/src/mbgl/util/http_header.hpp b/src/mbgl/util/http_header.hpp
index fa76cb724e..23da2c9ea4 100644
--- a/src/mbgl/util/http_header.hpp
+++ b/src/mbgl/util/http_header.hpp
@@ -17,7 +17,7 @@ public:
optional<Timestamp> toTimePoint() const;
};
-
+
optional<Timestamp> parseRetryHeaders(const optional<std::string>& retryAfter,
const optional<std::string>& xRateLimitReset);
diff --git a/src/mbgl/util/http_timeout.cpp b/src/mbgl/util/http_timeout.cpp
index ded0128ac9..ca9a93498f 100644
--- a/src/mbgl/util/http_timeout.cpp
+++ b/src/mbgl/util/http_timeout.cpp
@@ -17,7 +17,7 @@ Duration errorRetryTimeout(Response::Error::Reason failedRequestReason, uint32_t
if (retryAfter) {
return *retryAfter - util::now();
} else {
- //Default
+ // Default
return Seconds(util::DEFAULT_RATE_LIMIT_TIMEOUT);
}
} else {
@@ -34,7 +34,7 @@ Duration expirationTimeout(optional<Timestamp> expires, uint32_t expiredRequests
} else {
return Duration::max();
}
-}
+}
} // namespace http
} // namespace mbgl
diff --git a/src/mbgl/util/i18n.cpp b/src/mbgl/util/i18n.cpp
index 33ce5e22de..8e56877a64 100644
--- a/src/mbgl/util/i18n.cpp
+++ b/src/mbgl/util/i18n.cpp
@@ -1,5 +1,7 @@
#include "i18n.hpp"
+#include <map>
+
namespace {
/** Defines a function that returns true if a codepoint is in a named block.
@@ -8,7 +10,7 @@ namespace {
@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) { \
+ inline bool isIn##name(char16_t codepoint) { \
return codepoint >= first && codepoint <= last; \
}
@@ -16,7 +18,7 @@ namespace {
// 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(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)
@@ -50,11 +52,11 @@ namespace {
// 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(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(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)
@@ -63,7 +65,7 @@ namespace {
// 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(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)
@@ -84,22 +86,22 @@ namespace {
// 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(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(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(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(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)
@@ -123,15 +125,15 @@ 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(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(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)
@@ -148,7 +150,7 @@ DEFINE_IS_IN_UNICODE_BLOCK(YiRadicals, 0xA490, 0xA4CF)
// 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(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)
@@ -159,12 +161,12 @@ DEFINE_IS_IN_UNICODE_BLOCK(YiRadicals, 0xA490, 0xA4CF)
// 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(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(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)
@@ -172,7 +174,7 @@ DEFINE_IS_IN_UNICODE_BLOCK(CJKCompatibilityIdeographs, 0xF900, 0xFAFF)
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(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)
@@ -288,13 +290,33 @@ DEFINE_IS_IN_UNICODE_BLOCK(HalfwidthandFullwidthForms, 0xFF00, 0xFFEF)
// DEFINE_IS_IN_UNICODE_BLOCK(VariationSelectorsSupplement, 0xE0100, 0xE01EF)
// DEFINE_IS_IN_UNICODE_BLOCK(SupplementaryPrivateUseAreaA, 0xF0000, 0xFFFFF)
// DEFINE_IS_IN_UNICODE_BLOCK(SupplementaryPrivateUseAreaB, 0x100000, 0x10FFFF)
+
+const std::map<char16_t, char16_t> verticalPunctuation = {
+ { u'!', u'︕' }, { u'#', u'#' }, { u'$', u'$' }, { u'%', u'%' }, { u'&', u'&' },
+ { u'(', u'︵' }, { u')', u'︶' }, { u'*', u'*' }, { u'+', u'+' }, { u',', u'︐' },
+ { u'-', u'︲' }, { u'.', u'・' }, { u'/', u'/' }, { u':', u'︓' }, { u';', u'︔' },
+ { u'<', u'︿' }, { u'=', u'=' }, { u'>', u'﹀' }, { u'?', u'︖' }, { u'@', u'@' },
+ { u'[', u'﹇' }, { u'\\', u'\' }, { u']', u'﹈' }, { u'^', u'^' }, { u'_', u'︳' },
+ { u'`', u'`' }, { u'{', u'︷' }, { u'|', u'―' }, { u'}', u'︸' }, { u'~', u'~' },
+ { u'¢', u'¢' }, { u'£', u'£' }, { u'¥', u'¥' }, { u'¦', u'¦' }, { u'¬', u'¬' },
+ { u'¯', u' ̄' }, { u'–', u'︲' }, { u'—', u'︱' }, { u'‘', u'﹃' }, { u'’', u'﹄' },
+ { u'“', u'﹁' }, { u'”', u'﹂' }, { u'…', u'︙' }, { u'‧', u'・' }, { u'₩', u'₩' },
+ { u'、', u'︑' }, { u'。', u'︒' }, { u'〈', u'︿' }, { u'〉', u'﹀' }, { u'《', u'︽' },
+ { u'》', u'︾' }, { u'「', u'﹁' }, { u'」', u'﹂' }, { u'『', u'﹃' }, { u'』', u'﹄' },
+ { u'【', u'︻' }, { u'】', u'︼' }, { u'〔', u'︹' }, { u'〕', u'︺' }, { u'〖', u'︗' },
+ { u'〗', u'︘' }, { u'!', u'︕' }, { u'(', u'︵' }, { u')', u'︶' }, { u',', u'︐' },
+ { u'-', u'︲' }, { u'.', u'・' }, { u':', u'︓' }, { u';', u'︔' }, { u'<', u'︿' },
+ { u'>', u'﹀' }, { u'?', u'︖' }, { u'[', u'﹇' }, { u']', u'﹈' }, { u'_', u'︳' },
+ { u'{', u'︷' }, { u'|', u'―' }, { u'}', u'︸' }, { u'⦅', u'︵' }, { u'⦆', u'︶' },
+ { u'。', u'︒' }, { u'「', u'﹁' }, { u'」', u'﹂' },
+};
}
namespace mbgl {
namespace util {
namespace i18n {
-bool allowsWordBreaking(uint16_t chr) {
+bool allowsWordBreaking(char16_t chr) {
return (chr == 0x0a /* newline */
|| chr == 0x20 /* space */
|| chr == 0x26 /* ampersand */
@@ -311,7 +333,7 @@ bool allowsWordBreaking(uint16_t chr) {
}
bool allowsIdeographicBreaking(const std::u16string& string) {
- for (uint16_t chr : string) {
+ for (char16_t chr : string) {
if (!allowsIdeographicBreaking(chr)) {
return false;
}
@@ -319,7 +341,7 @@ bool allowsIdeographicBreaking(const std::u16string& string) {
return true;
}
-bool allowsIdeographicBreaking(uint16_t chr) {
+bool allowsIdeographicBreaking(char16_t chr) {
// Allow U+2027 "Interpunct" for hyphenation of Chinese words
if (chr == 0x2027)
return true;
@@ -352,6 +374,188 @@ bool allowsIdeographicBreaking(uint16_t chr) {
// || isInCJKCompatibilityIdeographsSupplement(chr));
}
+bool allowsVerticalWritingMode(const std::u16string& string) {
+ for (char32_t chr : string) {
+ if (hasUprightVerticalOrientation(chr)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// The following logic comes from
+// <http://www.unicode.org/Public/vertical/revision-16/VerticalOrientation-16.txt>.
+// The data file denotes with “U” or “Tu” any codepoint that may be drawn
+// upright in vertical text but does not distinguish between upright and
+// “neutral” characters.
+
+bool hasUprightVerticalOrientation(char16_t chr) {
+ if (chr == u'˪' || chr == u'˫')
+ return true;
+
+ // Return early for characters outside all ranges whose characters remain
+ // upright in vertical writing mode.
+ if (chr < 0x1100)
+ return false;
+
+ if (isInBopomofo(chr) || isInBopomofoExtended(chr))
+ return true;
+ if (isInCJKCompatibilityForms(chr)) {
+ if (!(chr >= u'﹉' && chr <= u'﹏'))
+ return true;
+ }
+ if (isInCJKCompatibility(chr) || isInCJKCompatibilityIdeographs(chr) ||
+ isInCJKRadicalsSupplement(chr) || isInCJKStrokes(chr))
+ return true;
+ if (isInCJKSymbolsandPunctuation(chr)) {
+ if (!(chr >= u'〈' && chr <= u'】') && !(chr >= u'〔' && chr <= u'〟') && chr != u'〰')
+ return true;
+ }
+ if (isInCJKUnifiedIdeographs(chr) || isInCJKUnifiedIdeographsExtensionA(chr) ||
+ isInEnclosedCJKLettersandMonths(chr) || isInHangulCompatibilityJamo(chr) ||
+ isInHangulJamo(chr) || isInHangulJamoExtendedA(chr) || isInHangulJamoExtendedB(chr) ||
+ isInHangulSyllables(chr) || isInHiragana(chr) ||
+ isInIdeographicDescriptionCharacters(chr) || isInKanbun(chr) || isInKangxiRadicals(chr))
+ return true;
+ if (isInKatakana(chr)) {
+ if (chr != u'ー')
+ return true;
+ }
+ if (isInKatakanaPhoneticExtensions(chr))
+ return true;
+ if (isInHalfwidthandFullwidthForms(chr)) {
+ if (chr != u'(' && chr != u')' && chr != u'-' && !(chr >= u':' && chr <= u'>') &&
+ chr != u'[' && chr != u']' && chr != u'_' && !(chr >= u'{' && chr <= 0xFFDF) &&
+ chr != u' ̄' && !(chr >= u'│' && chr <= 0xFFEF))
+ return true;
+ }
+ if (isInSmallFormVariants(chr)) {
+ if (!(chr >= u'﹘' && chr <= u'﹞') && !(chr >= u'﹣' && chr <= u'﹦'))
+ return true;
+ }
+ if (isInUnifiedCanadianAboriginalSyllabics(chr) ||
+ isInUnifiedCanadianAboriginalSyllabicsExtended(chr) || isInVerticalForms(chr) ||
+ isInYijingHexagramSymbols(chr) || isInYiSyllables(chr) || isInYiRadicals(chr))
+ return true;
+
+ // https://github.com/mapbox/mapbox-gl/issues/29
+
+ // if (isInMeroiticHieroglyphs(chr)) return true;
+ // if (isInSiddham(chr)) return true;
+ // if (isInEgyptianHieroglyphs(chr)) return true;
+ // if (isInAnatolianHieroglyphs(chr)) return true;
+ // if (isInIdeographicSymbolsandPunctuation(chr)) return true;
+ // if (isInTangut(chr)) return true;
+ // if (isInTangutComponents(chr)) return true;
+ // if (isInKanaSupplement(chr)) return true;
+ // if (isInByzantineMusicalSymbols(chr)) return true;
+ // if (isInMusicalSymbols(chr)) return true;
+ // if (isInTaiXuanJingSymbols(chr)) return true;
+ // if (isInCountingRodNumerals(chr)) return true;
+ // if (isInSuttonSignWriting(chr)) return true;
+ // if (isInMahjongTiles(chr)) return true;
+ // if (isInDominoTiles(chr)) return true;
+ // if (isInPlayingCards(chr)) return true;
+ // if (isInEnclosedAlphanumericSupplement(chr)) return true;
+ // if (isInEnclosedIdeographicSupplement(chr)) return true;
+ // if (isInMiscellaneousSymbolsandPictographs(chr)) return true;
+ // if (isInEmoticons(chr)) return true;
+ // if (isInOrnamentalDingbats(chr)) return true;
+ // if (isInTransportandMapSymbols(chr)) return true;
+ // if (isInAlchemicalSymbols(chr)) return true;
+ // if (isInGeometricShapesExtended(chr)) return true;
+ // if (isInSupplementalSymbolsandPictographs(chr)) return true;
+ // if (isInCJKUnifiedIdeographsExtensionB(chr)) return true;
+ // if (isInCJKUnifiedIdeographsExtensionC(chr)) return true;
+ // if (isInCJKUnifiedIdeographsExtensionD(chr)) return true;
+ // if (isInCJKUnifiedIdeographsExtensionE(chr)) return true;
+ // if (isInCJKCompatibilityIdeographsSupplement(chr)) return true;
+
+ return false;
+}
+
+bool hasNeutralVerticalOrientation(char16_t chr) {
+ if (isInLatin1Supplement(chr)) {
+ if (chr == u'§' || chr == u'©' || chr == u'®' || chr == u'±' || chr == u'¼' ||
+ chr == u'½' || chr == u'¾' || chr == u'×' || chr == u'÷') {
+ return true;
+ }
+ }
+ if (isInGeneralPunctuation(chr)) {
+ if (chr == u'‖' || chr == u'†' || chr == u'‡' || chr == u'‰' || chr == u'‱' ||
+ chr == u'※' || chr == u'‼' || chr == u'⁂' || chr == u'⁇' || chr == u'⁈' ||
+ chr == u'⁉' || chr == u'⁑') {
+ return true;
+ }
+ }
+ if (isInLetterlikeSymbols(chr) || isInNumberForms(chr)) {
+ return true;
+ }
+ if (isInMiscellaneousTechnical(chr)) {
+ if ((chr >= u'⌀' && chr <= u'⌇') || (chr >= u'⌌' && chr <= u'⌟') ||
+ (chr >= u'⌤' && chr <= u'⌨') || chr == u'⌫' || (chr >= u'⍽' && chr <= u'⎚') ||
+ (chr >= u'⎾' && chr <= u'⏍') || chr == u'⏏' || (chr >= u'⏑' && chr <= u'⏛') ||
+ (chr >= u'⏢' && chr <= 0x23FF)) {
+ return true;
+ }
+ }
+ if (isInControlPictures(chr) || isInOpticalCharacterRecognition(chr) ||
+ isInEnclosedAlphanumerics(chr) || isInGeometricShapes(chr)) {
+ return true;
+ }
+ if (isInMiscellaneousSymbols(chr)) {
+ if ((chr >= u'⬒' && chr <= u'⬯') ||
+ (chr >= u'⭐' && chr <= 0x2B59 /* heavy circled saltire */) ||
+ (chr >= 0x2BB8 /* upwards white arrow from bar with horizontal bar */ &&
+ chr <= 0x2BEB)) {
+ return true;
+ }
+ }
+ if (isInCJKSymbolsandPunctuation(chr) || isInKatakana(chr) || isInPrivateUseArea(chr) ||
+ isInCJKCompatibilityForms(chr) || isInSmallFormVariants(chr) ||
+ isInHalfwidthandFullwidthForms(chr)) {
+ return true;
+ }
+ if (chr == u'∞' || chr == u'∴' || chr == u'∵' ||
+ (chr >= 0x2700 /* black safety scissors */ && chr <= u'❧') ||
+ (chr >= u'❶' && chr <= u'➓') || chr == 0xFFFC /* object replacement character */ ||
+ chr == 0xFFFD /* replacement character */) {
+ return true;
+ }
+ return false;
+}
+
+bool hasRotatedVerticalOrientation(char16_t chr) {
+ return !(hasUprightVerticalOrientation(chr) || hasNeutralVerticalOrientation(chr));
+}
+
+std::u16string verticalizePunctuation(const std::u16string& input) {
+ std::u16string output;
+
+ for (size_t i = 0; i < input.size(); i++) {
+ char16_t nextCharCode = i < input.size() ? input[i + 1] : 0;
+ char16_t prevCharCode = i ? input[i - 1] : 0;
+
+ bool canReplacePunctuation =
+ ((!nextCharCode || !hasRotatedVerticalOrientation(nextCharCode) ||
+ verticalPunctuation.count(input[i + 1])) &&
+ (!prevCharCode || !hasRotatedVerticalOrientation(prevCharCode) ||
+ verticalPunctuation.count(input[i - 1])));
+
+ if (char16_t repl = canReplacePunctuation ? verticalizePunctuation(input[i]) : 0) {
+ output += repl;
+ } else {
+ output += input[i];
+ }
+ }
+
+ return output;
+}
+
+char16_t verticalizePunctuation(char16_t chr) {
+ return verticalPunctuation.count(chr) ? verticalPunctuation.at(chr) : 0;
+}
+
} // namespace i18n
} // namespace util
} // namespace mbgl
diff --git a/src/mbgl/util/i18n.hpp b/src/mbgl/util/i18n.hpp
index f1d3f53f72..186212f50d 100644
--- a/src/mbgl/util/i18n.hpp
+++ b/src/mbgl/util/i18n.hpp
@@ -8,7 +8,7 @@ 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);
+bool allowsWordBreaking(char16_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
@@ -17,7 +17,53 @@ 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);
+bool allowsIdeographicBreaking(char16_t chr);
+
+/** Returns whether any substring of the given string can be drawn as vertical
+ text with upright glyphs. */
+bool allowsVerticalWritingMode(const std::u16string& string);
+
+/** Returns true if the given Unicode codepoint identifies a character with
+ upright orientation.
+
+ A character has upright orientation if it is drawn upright (unrotated)
+ whether the line is oriented horizontally or vertically, even if both
+ adjacent characters can be rotated. For example, a Chinese character is
+ always drawn upright. An uprightly oriented character causes an adjacent
+ “neutral” character to be drawn upright as well. */
+bool hasUprightVerticalOrientation(char16_t chr);
+
+/** Returns true if the given Unicode codepoint identifies a character with
+ neutral orientation.
+
+ A character has neutral orientation if it may be drawn rotated or unrotated
+ when the line is oriented vertically, depending on the orientation of the
+ adjacent characters. For example, along a verticlly oriented line, the
+ vulgar fraction ½ is drawn upright among Chinese characters but rotated
+ among Latin letters. A neutrally oriented character does not influence
+ whether an adjacent character is drawn upright or rotated.
+ */
+bool hasNeutralVerticalOrientation(char16_t chr);
+
+/** Returns true if the given Unicode codepoint identifies a character with
+ rotated orientation.
+
+ A character has rotated orientation if it is drawn rotated when the line is
+ oriented vertically, even if both adjacent characters are upright. For
+ example, a Latin letter is drawn rotated along a vertical line. A rotated
+ character causes an adjacent “neutral” character to be drawn rotated as
+ well.
+ */
+bool hasRotatedVerticalOrientation(char16_t chr);
+
+/** Returns a copy of the given string with punctuation characters replaced with
+ their vertical forms wherever applicable. */
+std::u16string verticalizePunctuation(const std::u16string& input);
+
+/** Returns the form of the given character appropriate for vertical text.
+
+ @return The character’s specialized vertical form; 0 if not applicable. */
+char16_t verticalizePunctuation(char16_t chr);
} // namespace i18n
} // namespace util
diff --git a/src/mbgl/util/ignore.hpp b/src/mbgl/util/ignore.hpp
index 955b1de2fa..577bcf4d91 100644
--- a/src/mbgl/util/ignore.hpp
+++ b/src/mbgl/util/ignore.hpp
@@ -19,5 +19,8 @@ template <class... Ts> void ignore(Ts&&...) {}
//
template <class T> void ignore(const std::initializer_list<T>&) {}
+// Handle the zero-argument case.
+inline void ignore(const std::initializer_list<int>&) {}
+
} // namespace util
} // namespace mbgl
diff --git a/src/mbgl/util/indexed_tuple.hpp b/src/mbgl/util/indexed_tuple.hpp
index 110e7dce12..a414639530 100644
--- a/src/mbgl/util/indexed_tuple.hpp
+++ b/src/mbgl/util/indexed_tuple.hpp
@@ -1,5 +1,7 @@
#pragma once
+#include <mbgl/util/type_list.hpp>
+
#include <type_traits>
#include <tuple>
@@ -14,8 +16,6 @@ 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.
@@ -42,6 +42,15 @@ public:
const auto& get() const {
return std::get<Index<I>>(*this);
}
+
+ template <class... Js, class... Us>
+ IndexedTuple<TypeList<Is..., Js...>, TypeList<Ts..., Us...>>
+ concat(const IndexedTuple<TypeList<Js...>, TypeList<Us...>>& other) const {
+ return IndexedTuple<TypeList<Is..., Js...>, TypeList<Ts..., Us...>> {
+ get<Is>()...,
+ other.template get<Js>()...
+ };
+ }
};
} // namespace mbgl
diff --git a/src/mbgl/util/interpolate.cpp b/src/mbgl/util/interpolate.cpp
new file mode 100644
index 0000000000..306a5c6630
--- /dev/null
+++ b/src/mbgl/util/interpolate.cpp
@@ -0,0 +1,19 @@
+#include <mbgl/util/interpolate.hpp>
+
+#include <cmath>
+
+namespace mbgl {
+namespace util {
+
+float interpolationFactor(float base, Range<float> range, float z) {
+ const float zoomDiff = range.max - range.min;
+ const float zoomProgress = z - range.min;
+ if (base == 1.0f) {
+ return zoomProgress / zoomDiff;
+ } else {
+ return (std::pow(base, zoomProgress) - 1) / (std::pow(base, zoomDiff) - 1);
+ }
+}
+
+} // namespace util
+} // namespace mbgl
diff --git a/src/mbgl/util/interpolate.hpp b/src/mbgl/util/interpolate.hpp
index ef066377da..d463ffc056 100644
--- a/src/mbgl/util/interpolate.hpp
+++ b/src/mbgl/util/interpolate.hpp
@@ -1,15 +1,19 @@
#pragma once
+#include <mbgl/util/color.hpp>
+#include <mbgl/util/range.hpp>
+
#include <array>
#include <vector>
#include <string>
#include <type_traits>
#include <utility>
-#include <mbgl/util/color.hpp>
namespace mbgl {
namespace util {
+float interpolationFactor(float base, Range<float> range, float z);
+
template <class T, class Enabled = void>
struct Interpolator;
@@ -78,5 +82,8 @@ template <class T>
struct Interpolator<std::vector<T>>
: Uninterpolated {};
+template <class T>
+constexpr bool Interpolatable = !std::is_base_of<Uninterpolated, Interpolator<T>>::value;
+
} // namespace util
} // namespace mbgl
diff --git a/src/mbgl/util/thread.hpp b/src/mbgl/util/thread.hpp
index b03c7f3e7c..184c6a8a12 100644
--- a/src/mbgl/util/thread.hpp
+++ b/src/mbgl/util/thread.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include <cassert>
#include <future>
#include <thread>
#include <atomic>
@@ -9,6 +10,7 @@
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/thread_context.hpp>
#include <mbgl/util/platform.hpp>
+#include <mbgl/util/util.hpp>
namespace mbgl {
namespace util {
@@ -47,6 +49,8 @@ public:
// Invoke object->fn(args...) asynchronously, but wait for the result.
template <typename Fn, class... Args>
auto invokeSync(Fn fn, Args&&... args) {
+ assert(!paused);
+
using R = std::result_of_t<Fn(Object, Args&&...)>;
std::packaged_task<R ()> task(std::bind(fn, object, args...));
std::future<R> future = task.get_future();
@@ -54,7 +58,39 @@ public:
return future.get();
}
+ void pause() {
+ MBGL_VERIFY_THREAD(tid);
+
+ assert(!paused);
+
+ paused = std::make_unique<std::promise<void>>();
+ resumed = std::make_unique<std::promise<void>>();
+
+ auto pausing = paused->get_future();
+
+ loop->invoke([this] {
+ auto resuming = resumed->get_future();
+ paused->set_value();
+ resuming.get();
+ });
+
+ pausing.get();
+ }
+
+ void resume() {
+ MBGL_VERIFY_THREAD(tid);
+
+ assert(paused);
+
+ resumed->set_value();
+
+ resumed.reset();
+ paused.reset();
+ }
+
private:
+ MBGL_STORE_THREAD(tid);
+
Thread(const Thread&) = delete;
Thread(Thread&&) = delete;
Thread& operator=(const Thread&) = delete;
@@ -73,6 +109,9 @@ private:
std::promise<void> running;
std::promise<void> joinable;
+ std::unique_ptr<std::promise<void>> paused;
+ std::unique_ptr<std::promise<void>> resumed;
+
std::thread thread;
Object* object = nullptr;
@@ -119,6 +158,12 @@ void Thread<Object>::run(P&& params, std::index_sequence<I...>) {
template <class Object>
Thread<Object>::~Thread() {
+ MBGL_VERIFY_THREAD(tid);
+
+ if (paused) {
+ resume();
+ }
+
loop->stop();
joinable.set_value();
thread.join();
diff --git a/src/mbgl/util/type_list.hpp b/src/mbgl/util/type_list.hpp
new file mode 100644
index 0000000000..4a5e95c8a4
--- /dev/null
+++ b/src/mbgl/util/type_list.hpp
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <type_traits>
+#include <tuple>
+
+namespace mbgl {
+
+template <class...>
+class TypeList {};
+
+namespace detail {
+
+template <class, class>
+struct TypeCons;
+
+template <class T, class... Ts>
+struct TypeCons<T, TypeList<Ts...>> {
+ using Type = TypeList<T, Ts...>;
+};
+
+template <class, template <class> class>
+struct TypeFilter;
+
+template <template <class> class Predicate>
+struct TypeFilter<TypeList<>, Predicate> {
+ using Type = TypeList<>;
+};
+
+template <template <class> class Predicate, class T, class... Ts>
+struct TypeFilter<TypeList<T, Ts...>, Predicate> {
+ using Tail = typename TypeFilter<TypeList<Ts...>, Predicate>::Type;
+ using Type = std::conditional_t<Predicate<T>::value, typename TypeCons<T, Tail>::Type, Tail>;
+};
+
+} // namespace detail
+
+template <class TypeList, template <class> class Predicate>
+using FilteredTypeList = typename detail::TypeFilter<TypeList, Predicate>::Type;
+
+} // namespace mbgl
diff --git a/src/mbgl/util/url.cpp b/src/mbgl/util/url.cpp
index 0a7d096ec0..3f36bc676f 100644
--- a/src/mbgl/util/url.cpp
+++ b/src/mbgl/util/url.cpp
@@ -89,8 +89,10 @@ URL::URL(const std::string& str)
return { queryPos, (hashPos != std::string::npos ? hashPos : str.size()) - queryPos };
}()),
scheme([&]() -> Segment {
- auto schemeEnd = str.find(':');
- return { 0, schemeEnd == std::string::npos || schemeEnd > query.first ? 0 : schemeEnd };
+ if (str.empty() || !isAlphaCharacter(str.front())) return { 0, 0 };
+ size_t schemeEnd = 0;
+ while (schemeEnd < query.first && isSchemeCharacter(str[schemeEnd])) ++schemeEnd;
+ return { 0, str[schemeEnd] == ':' ? schemeEnd : 0 };
}()),
domain([&]() -> Segment {
auto domainPos = scheme.first + scheme.second;
diff --git a/src/mbgl/util/version.cpp b/src/mbgl/util/version.cpp
new file mode 100644
index 0000000000..fcb31f0b71
--- /dev/null
+++ b/src/mbgl/util/version.cpp
@@ -0,0 +1,9 @@
+#include <mbgl/util/version.hpp>
+
+namespace mbgl {
+namespace version {
+
+const char* revision = MBGL_VERSION_REV;
+
+} // namespace version
+} // namespace mbgl
diff --git a/src/mbgl/util/version.hpp b/src/mbgl/util/version.hpp
new file mode 100644
index 0000000000..e652016485
--- /dev/null
+++ b/src/mbgl/util/version.hpp
@@ -0,0 +1,9 @@
+#pragma once
+
+namespace mbgl {
+namespace version {
+
+extern const char* revision;
+
+} // namespace version
+} // namespace mbgl
diff --git a/src/mbgl/util/version_info.cpp b/src/mbgl/util/version_info.cpp
deleted file mode 100644
index f0fb139bca..0000000000
--- a/src/mbgl/util/version_info.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#include <mbgl/util/version.hpp>
-
-namespace mbgl {
-namespace version {
-
-const int major = MBGL_VERSION_MAJOR;
-const int minor = MBGL_VERSION_MINOR;
-const int patch = MBGL_VERSION_PATCH;
-const char *revision = MBGL_VERSION_REV;
-const char *string = MBGL_VERSION_STRING;
-const unsigned int number = MBGL_VERSION;
-
-} // namespace version
-} // namespace mbgl