summaryrefslogtreecommitdiff
path: root/src/mbgl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl')
-rw-r--r--src/mbgl/actor/actor.hpp77
-rw-r--r--src/mbgl/actor/actor_ref.hpp43
-rw-r--r--src/mbgl/actor/mailbox.cpp28
-rw-r--r--src/mbgl/actor/message.hpp48
-rw-r--r--src/mbgl/annotation/annotation_manager.cpp117
-rw-r--r--src/mbgl/annotation/annotation_manager.hpp27
-rw-r--r--src/mbgl/annotation/annotation_source.cpp13
-rw-r--r--src/mbgl/annotation/annotation_source.hpp11
-rw-r--r--src/mbgl/annotation/annotation_tile.cpp101
-rw-r--r--src/mbgl/annotation/annotation_tile.hpp49
-rw-r--r--src/mbgl/annotation/fill_annotation_impl.cpp6
-rw-r--r--src/mbgl/annotation/fill_annotation_impl.hpp2
-rw-r--r--src/mbgl/annotation/line_annotation_impl.cpp6
-rw-r--r--src/mbgl/annotation/line_annotation_impl.hpp2
-rw-r--r--src/mbgl/annotation/render_annotation_source.cpp63
-rw-r--r--src/mbgl/annotation/render_annotation_source.hpp34
-rw-r--r--src/mbgl/annotation/shape_annotation_impl.cpp4
-rw-r--r--src/mbgl/annotation/shape_annotation_impl.hpp7
-rw-r--r--src/mbgl/annotation/style_sourced_annotation_impl.cpp43
-rw-r--r--src/mbgl/annotation/style_sourced_annotation_impl.hpp19
-rw-r--r--src/mbgl/annotation/symbol_annotation_impl.cpp2
-rw-r--r--src/mbgl/annotation/symbol_annotation_impl.hpp47
-rw-r--r--src/mbgl/geometry/anchor.hpp2
-rw-r--r--src/mbgl/geometry/binpack.hpp101
-rw-r--r--src/mbgl/geometry/feature_index.cpp14
-rw-r--r--src/mbgl/geometry/feature_index.hpp9
-rw-r--r--src/mbgl/gl/attribute.cpp222
-rw-r--r--src/mbgl/gl/attribute.hpp101
-rw-r--r--src/mbgl/gl/context.cpp15
-rw-r--r--src/mbgl/gl/context.hpp6
-rw-r--r--src/mbgl/gl/debugging.cpp8
-rw-r--r--src/mbgl/gl/debugging_extension.hpp14
-rw-r--r--src/mbgl/gl/index_buffer.hpp1
-rw-r--r--src/mbgl/gl/program.hpp12
-rw-r--r--src/mbgl/gl/segment.hpp6
-rw-r--r--src/mbgl/gl/types.hpp24
-rw-r--r--src/mbgl/gl/uniform.cpp93
-rw-r--r--src/mbgl/gl/uniform.hpp31
-rw-r--r--src/mbgl/gl/value.cpp68
-rw-r--r--src/mbgl/gl/value.hpp35
-rw-r--r--src/mbgl/gl/vertex_buffer.hpp1
-rw-r--r--src/mbgl/layout/symbol_instance.cpp6
-rw-r--r--src/mbgl/layout/symbol_instance.hpp4
-rw-r--r--src/mbgl/layout/symbol_layout.cpp121
-rw-r--r--src/mbgl/layout/symbol_layout.hpp16
-rw-r--r--src/mbgl/map/backend.cpp19
-rw-r--r--src/mbgl/map/map.cpp455
-rw-r--r--src/mbgl/map/transform.cpp5
-rw-r--r--src/mbgl/map/transform_state.cpp2
-rw-r--r--src/mbgl/map/update.hpp2
-rw-r--r--src/mbgl/map/zoom_history.hpp7
-rw-r--r--src/mbgl/programs/attributes.hpp7
-rw-r--r--src/mbgl/programs/binary_program.cpp5
-rw-r--r--src/mbgl/programs/binary_program.hpp2
-rw-r--r--src/mbgl/programs/collision_box_program.hpp3
-rw-r--r--src/mbgl/programs/debug_program.hpp3
-rw-r--r--src/mbgl/programs/extrusion_texture_program.hpp3
-rw-r--r--src/mbgl/programs/fill_extrusion_program.cpp20
-rw-r--r--src/mbgl/programs/fill_extrusion_program.hpp8
-rw-r--r--src/mbgl/programs/fill_program.cpp20
-rw-r--r--src/mbgl/programs/fill_program.hpp8
-rw-r--r--src/mbgl/programs/line_program.cpp38
-rw-r--r--src/mbgl/programs/line_program.hpp27
-rw-r--r--src/mbgl/programs/program.hpp6
-rw-r--r--src/mbgl/programs/symbol_program.cpp2
-rw-r--r--src/mbgl/programs/symbol_program.hpp48
-rw-r--r--src/mbgl/programs/uniforms.hpp13
-rw-r--r--src/mbgl/renderer/bucket_parameters.hpp1
-rw-r--r--src/mbgl/renderer/buckets/circle_bucket.cpp (renamed from src/mbgl/renderer/circle_bucket.cpp)4
-rw-r--r--src/mbgl/renderer/buckets/circle_bucket.hpp (renamed from src/mbgl/renderer/circle_bucket.hpp)0
-rw-r--r--src/mbgl/renderer/buckets/debug_bucket.cpp (renamed from src/mbgl/renderer/debug_bucket.cpp)2
-rw-r--r--src/mbgl/renderer/buckets/debug_bucket.hpp (renamed from src/mbgl/renderer/debug_bucket.hpp)0
-rw-r--r--src/mbgl/renderer/buckets/fill_bucket.cpp (renamed from src/mbgl/renderer/fill_bucket.cpp)4
-rw-r--r--src/mbgl/renderer/buckets/fill_bucket.hpp (renamed from src/mbgl/renderer/fill_bucket.hpp)0
-rw-r--r--src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp (renamed from src/mbgl/renderer/fill_extrusion_bucket.cpp)4
-rw-r--r--src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp (renamed from src/mbgl/renderer/fill_extrusion_bucket.hpp)0
-rw-r--r--src/mbgl/renderer/buckets/line_bucket.cpp (renamed from src/mbgl/renderer/line_bucket.cpp)12
-rw-r--r--src/mbgl/renderer/buckets/line_bucket.hpp (renamed from src/mbgl/renderer/line_bucket.hpp)2
-rw-r--r--src/mbgl/renderer/buckets/raster_bucket.cpp53
-rw-r--r--src/mbgl/renderer/buckets/raster_bucket.hpp40
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.cpp (renamed from src/mbgl/renderer/symbol_bucket.cpp)8
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.hpp (renamed from src/mbgl/renderer/symbol_bucket.hpp)5
-rw-r--r--src/mbgl/renderer/data_driven_property_evaluator.hpp10
-rw-r--r--src/mbgl/renderer/frame_history.cpp6
-rw-r--r--src/mbgl/renderer/group_by_layout.cpp14
-rw-r--r--src/mbgl/renderer/image_atlas.cpp60
-rw-r--r--src/mbgl/renderer/image_atlas.hpp51
-rw-r--r--src/mbgl/renderer/image_manager.cpp166
-rw-r--r--src/mbgl/renderer/image_manager.hpp94
-rw-r--r--src/mbgl/renderer/layers/render_background_layer.cpp (renamed from src/mbgl/renderer/render_background_layer.cpp)18
-rw-r--r--src/mbgl/renderer/layers/render_background_layer.hpp (renamed from src/mbgl/renderer/render_background_layer.hpp)15
-rw-r--r--src/mbgl/renderer/layers/render_circle_layer.cpp (renamed from src/mbgl/renderer/render_circle_layer.cpp)20
-rw-r--r--src/mbgl/renderer/layers/render_circle_layer.hpp (renamed from src/mbgl/renderer/render_circle_layer.hpp)15
-rw-r--r--src/mbgl/renderer/layers/render_custom_layer.cpp76
-rw-r--r--src/mbgl/renderer/layers/render_custom_layer.hpp (renamed from src/mbgl/renderer/render_custom_layer.hpp)19
-rw-r--r--src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp (renamed from src/mbgl/renderer/render_fill_extrusion_layer.cpp)18
-rw-r--r--src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp (renamed from src/mbgl/renderer/render_fill_extrusion_layer.hpp)13
-rw-r--r--src/mbgl/renderer/layers/render_fill_layer.cpp (renamed from src/mbgl/renderer/render_fill_layer.cpp)20
-rw-r--r--src/mbgl/renderer/layers/render_fill_layer.hpp (renamed from src/mbgl/renderer/render_fill_layer.hpp)13
-rw-r--r--src/mbgl/renderer/layers/render_line_layer.cpp (renamed from src/mbgl/renderer/render_line_layer.cpp)34
-rw-r--r--src/mbgl/renderer/layers/render_line_layer.hpp (renamed from src/mbgl/renderer/render_line_layer.hpp)26
-rw-r--r--src/mbgl/renderer/layers/render_raster_layer.cpp50
-rw-r--r--src/mbgl/renderer/layers/render_raster_layer.hpp (renamed from src/mbgl/renderer/render_raster_layer.hpp)15
-rw-r--r--src/mbgl/renderer/layers/render_symbol_layer.cpp (renamed from src/mbgl/renderer/render_symbol_layer.cpp)38
-rw-r--r--src/mbgl/renderer/layers/render_symbol_layer.hpp (renamed from src/mbgl/renderer/render_symbol_layer.hpp)33
-rw-r--r--src/mbgl/renderer/paint_property_binder.hpp28
-rw-r--r--src/mbgl/renderer/painter.cpp84
-rw-r--r--src/mbgl/renderer/painter.hpp33
-rw-r--r--src/mbgl/renderer/painters/painter_background.cpp (renamed from src/mbgl/renderer/painter_background.cpp)15
-rw-r--r--src/mbgl/renderer/painters/painter_circle.cpp (renamed from src/mbgl/renderer/painter_circle.cpp)6
-rw-r--r--src/mbgl/renderer/painters/painter_clipping.cpp (renamed from src/mbgl/renderer/painter_clipping.cpp)2
-rw-r--r--src/mbgl/renderer/painters/painter_debug.cpp (renamed from src/mbgl/renderer/painter_debug.cpp)32
-rw-r--r--src/mbgl/renderer/painters/painter_fill.cpp (renamed from src/mbgl/renderer/painter_fill.cpp)15
-rw-r--r--src/mbgl/renderer/painters/painter_fill_extrusion.cpp (renamed from src/mbgl/renderer/painter_fill_extrusion.cpp)17
-rw-r--r--src/mbgl/renderer/painters/painter_line.cpp (renamed from src/mbgl/renderer/painter_line.cpp)16
-rw-r--r--src/mbgl/renderer/painters/painter_raster.cpp (renamed from src/mbgl/renderer/painter_raster.cpp)17
-rw-r--r--src/mbgl/renderer/painters/painter_symbol.cpp (renamed from src/mbgl/renderer/painter_symbol.cpp)29
-rw-r--r--src/mbgl/renderer/possibly_evaluated_property_value.hpp12
-rw-r--r--src/mbgl/renderer/property_evaluation_parameters.hpp10
-rw-r--r--src/mbgl/renderer/raster_bucket.cpp30
-rw-r--r--src/mbgl/renderer/raster_bucket.hpp22
-rw-r--r--src/mbgl/renderer/render_custom_layer.cpp29
-rw-r--r--src/mbgl/renderer/render_item.hpp10
-rw-r--r--src/mbgl/renderer/render_layer.cpp70
-rw-r--r--src/mbgl/renderer/render_layer.hpp31
-rw-r--r--src/mbgl/renderer/render_light.cpp20
-rw-r--r--src/mbgl/renderer/render_light.hpp85
-rw-r--r--src/mbgl/renderer/render_raster_layer.cpp35
-rw-r--r--src/mbgl/renderer/render_source.cpp36
-rw-r--r--src/mbgl/renderer/render_source.hpp53
-rw-r--r--src/mbgl/renderer/render_style.cpp450
-rw-r--r--src/mbgl/renderer/render_style.hpp92
-rw-r--r--src/mbgl/renderer/render_style_observer.hpp14
-rw-r--r--src/mbgl/renderer/render_tile.cpp16
-rw-r--r--src/mbgl/renderer/render_tile.hpp6
-rw-r--r--src/mbgl/renderer/sources/render_geojson_source.cpp76
-rw-r--r--src/mbgl/renderer/sources/render_geojson_source.hpp35
-rw-r--r--src/mbgl/renderer/sources/render_image_source.cpp180
-rw-r--r--src/mbgl/renderer/sources/render_image_source.hpp64
-rw-r--r--src/mbgl/renderer/sources/render_raster_source.cpp74
-rw-r--r--src/mbgl/renderer/sources/render_raster_source.hpp35
-rw-r--r--src/mbgl/renderer/sources/render_vector_source.cpp79
-rw-r--r--src/mbgl/renderer/sources/render_vector_source.hpp35
-rw-r--r--src/mbgl/renderer/style_diff.cpp79
-rw-r--r--src/mbgl/renderer/style_diff.hpp48
-rw-r--r--src/mbgl/renderer/tile_parameters.hpp28
-rw-r--r--src/mbgl/renderer/tile_pyramid.cpp67
-rw-r--r--src/mbgl/renderer/tile_pyramid.hpp32
-rw-r--r--src/mbgl/renderer/transition_parameters.hpp (renamed from src/mbgl/renderer/cascade_parameters.hpp)4
-rw-r--r--src/mbgl/renderer/transitioning_property.hpp75
-rw-r--r--src/mbgl/renderer/update_parameters.hpp20
-rw-r--r--src/mbgl/shaders/fill_extrusion_pattern.cpp5
-rw-r--r--src/mbgl/shaders/fill_outline.cpp2
-rw-r--r--src/mbgl/shaders/fill_outline_pattern.cpp7
-rw-r--r--src/mbgl/shaders/fill_pattern.cpp5
-rw-r--r--src/mbgl/shaders/line.cpp18
-rw-r--r--src/mbgl/shaders/line_pattern.cpp23
-rw-r--r--src/mbgl/shaders/line_sdf.cpp59
-rw-r--r--src/mbgl/sprite/sprite_atlas.cpp340
-rw-r--r--src/mbgl/sprite/sprite_atlas.hpp140
-rw-r--r--src/mbgl/sprite/sprite_atlas_observer.hpp15
-rw-r--r--src/mbgl/sprite/sprite_loader.cpp104
-rw-r--r--src/mbgl/sprite/sprite_loader.hpp44
-rw-r--r--src/mbgl/sprite/sprite_loader_observer.hpp21
-rw-r--r--src/mbgl/sprite/sprite_loader_worker.cpp (renamed from src/mbgl/sprite/sprite_atlas_worker.cpp)12
-rw-r--r--src/mbgl/sprite/sprite_loader_worker.hpp (renamed from src/mbgl/sprite/sprite_atlas_worker.hpp)8
-rw-r--r--src/mbgl/sprite/sprite_parser.cpp25
-rw-r--r--src/mbgl/sprite/sprite_parser.hpp24
-rw-r--r--src/mbgl/storage/asset_file_source.hpp3
-rw-r--r--src/mbgl/storage/file_source_request.cpp37
-rw-r--r--src/mbgl/storage/file_source_request.hpp31
-rw-r--r--src/mbgl/storage/local_file_source.hpp3
-rw-r--r--src/mbgl/storage/resource.cpp7
-rw-r--r--src/mbgl/storage/resource_transform.cpp13
-rw-r--r--src/mbgl/style/class_dictionary.cpp51
-rw-r--r--src/mbgl/style/class_dictionary.hpp52
-rw-r--r--src/mbgl/style/collection.hpp141
-rw-r--r--src/mbgl/style/conversion/stringify.hpp9
-rw-r--r--src/mbgl/style/function/identity_stops.cpp7
-rw-r--r--src/mbgl/style/image.cpp36
-rw-r--r--src/mbgl/style/image_impl.cpp24
-rw-r--r--src/mbgl/style/image_impl.hpp32
-rw-r--r--src/mbgl/style/layer.cpp30
-rw-r--r--src/mbgl/style/layer_impl.cpp14
-rw-r--r--src/mbgl/style/layer_impl.hpp28
-rw-r--r--src/mbgl/style/layer_observer.hpp6
-rw-r--r--src/mbgl/style/layers/background_layer.cpp126
-rw-r--r--src/mbgl/style/layers/background_layer_impl.cpp5
-rw-r--r--src/mbgl/style/layers/background_layer_impl.hpp9
-rw-r--r--src/mbgl/style/layers/background_layer_properties.hpp4
-rw-r--r--src/mbgl/style/layers/circle_layer.cpp339
-rw-r--r--src/mbgl/style/layers/circle_layer_impl.cpp9
-rw-r--r--src/mbgl/style/layers/circle_layer_impl.hpp9
-rw-r--r--src/mbgl/style/layers/circle_layer_properties.hpp3
-rw-r--r--src/mbgl/style/layers/custom_layer.cpp49
-rw-r--r--src/mbgl/style/layers/custom_layer_impl.cpp58
-rw-r--r--src/mbgl/style/layers/custom_layer_impl.hpp13
-rw-r--r--src/mbgl/style/layers/fill_extrusion_layer.cpp251
-rw-r--r--src/mbgl/style/layers/fill_extrusion_layer_impl.cpp9
-rw-r--r--src/mbgl/style/layers/fill_extrusion_layer_impl.hpp9
-rw-r--r--src/mbgl/style/layers/fill_extrusion_layer_properties.hpp3
-rw-r--r--src/mbgl/style/layers/fill_layer.cpp251
-rw-r--r--src/mbgl/style/layers/fill_layer_impl.cpp9
-rw-r--r--src/mbgl/style/layers/fill_layer_impl.hpp9
-rw-r--r--src/mbgl/style/layers/fill_layer_properties.hpp3
-rw-r--r--src/mbgl/style/layers/layer.cpp.ejs117
-rw-r--r--src/mbgl/style/layers/layer_properties.hpp.ejs6
-rw-r--r--src/mbgl/style/layers/line_layer.cpp367
-rw-r--r--src/mbgl/style/layers/line_layer_impl.cpp10
-rw-r--r--src/mbgl/style/layers/line_layer_impl.hpp11
-rw-r--r--src/mbgl/style/layers/line_layer_properties.hpp9
-rw-r--r--src/mbgl/style/layers/raster_layer.cpp225
-rw-r--r--src/mbgl/style/layers/raster_layer_impl.cpp5
-rw-r--r--src/mbgl/style/layers/raster_layer_impl.hpp9
-rw-r--r--src/mbgl/style/layers/raster_layer_properties.hpp4
-rw-r--r--src/mbgl/style/layers/symbol_layer.cpp721
-rw-r--r--src/mbgl/style/layers/symbol_layer_impl.cpp10
-rw-r--r--src/mbgl/style/layers/symbol_layer_impl.hpp13
-rw-r--r--src/mbgl/style/layers/symbol_layer_properties.hpp5
-rw-r--r--src/mbgl/style/layout_property.hpp95
-rw-r--r--src/mbgl/style/light.cpp79
-rw-r--r--src/mbgl/style/light.cpp.ejs31
-rw-r--r--src/mbgl/style/light_impl.cpp4
-rw-r--r--src/mbgl/style/light_impl.hpp53
-rw-r--r--src/mbgl/style/light_observer.hpp4
-rw-r--r--src/mbgl/style/light_properties.hpp51
-rw-r--r--src/mbgl/style/observer.hpp9
-rw-r--r--src/mbgl/style/paint_property.hpp161
-rw-r--r--src/mbgl/style/parser.cpp28
-rw-r--r--src/mbgl/style/parser.hpp2
-rw-r--r--src/mbgl/style/properties.hpp248
-rw-r--r--src/mbgl/style/rapidjson_conversion.hpp7
-rw-r--r--src/mbgl/style/source.cpp24
-rw-r--r--src/mbgl/style/source_impl.cpp19
-rw-r--r--src/mbgl/style/source_impl.hpp21
-rw-r--r--src/mbgl/style/sources/geojson_source.cpp70
-rw-r--r--src/mbgl/style/sources/geojson_source_impl.cpp85
-rw-r--r--src/mbgl/style/sources/geojson_source_impl.hpp16
-rw-r--r--src/mbgl/style/sources/image_source.cpp85
-rw-r--r--src/mbgl/style/sources/image_source_impl.cpp38
-rw-r--r--src/mbgl/style/sources/image_source_impl.hpp30
-rw-r--r--src/mbgl/style/sources/raster_source.cpp74
-rw-r--r--src/mbgl/style/sources/raster_source_impl.cpp29
-rw-r--r--src/mbgl/style/sources/raster_source_impl.hpp16
-rw-r--r--src/mbgl/style/sources/vector_source.cpp71
-rw-r--r--src/mbgl/style/sources/vector_source_impl.cpp22
-rw-r--r--src/mbgl/style/sources/vector_source_impl.hpp14
-rw-r--r--src/mbgl/style/style.cpp814
-rw-r--r--src/mbgl/style/style.hpp192
-rw-r--r--src/mbgl/style/style_impl.cpp371
-rw-r--r--src/mbgl/style/style_impl.hpp148
-rw-r--r--src/mbgl/style/tile_source_impl.cpp78
-rw-r--r--src/mbgl/style/tile_source_impl.hpp47
-rw-r--r--src/mbgl/style/types.cpp1
-rw-r--r--src/mbgl/style/update_batch.hpp15
-rw-r--r--src/mbgl/text/collision_feature.cpp2
-rw-r--r--src/mbgl/text/collision_feature.hpp2
-rw-r--r--src/mbgl/text/collision_tile.hpp9
-rw-r--r--src/mbgl/text/get_anchors.cpp2
-rw-r--r--src/mbgl/text/glyph.hpp39
-rw-r--r--src/mbgl/text/glyph_atlas.cpp285
-rw-r--r--src/mbgl/text/glyph_atlas.hpp107
-rw-r--r--src/mbgl/text/glyph_manager.cpp145
-rw-r--r--src/mbgl/text/glyph_manager.hpp68
-rw-r--r--src/mbgl/text/glyph_manager_observer.hpp (renamed from src/mbgl/text/glyph_atlas_observer.hpp)4
-rw-r--r--src/mbgl/text/glyph_pbf.cpp10
-rw-r--r--src/mbgl/text/glyph_pbf.hpp18
-rw-r--r--src/mbgl/text/glyph_range.hpp4
-rw-r--r--src/mbgl/text/quads.cpp36
-rw-r--r--src/mbgl/text/quads.hpp6
-rw-r--r--src/mbgl/text/shaping.cpp34
-rw-r--r--src/mbgl/text/shaping.hpp17
-rw-r--r--src/mbgl/tile/geojson_tile.cpp47
-rw-r--r--src/mbgl/tile/geometry_tile.cpp114
-rw-r--r--src/mbgl/tile/geometry_tile.hpp49
-rw-r--r--src/mbgl/tile/geometry_tile_data.hpp9
-rw-r--r--src/mbgl/tile/geometry_tile_worker.cpp94
-rw-r--r--src/mbgl/tile/geometry_tile_worker.hpp26
-rw-r--r--src/mbgl/tile/raster_tile.cpp10
-rw-r--r--src/mbgl/tile/raster_tile.hpp4
-rw-r--r--src/mbgl/tile/raster_tile_worker.cpp2
-rw-r--r--src/mbgl/tile/tile.cpp3
-rw-r--r--src/mbgl/tile/tile.hpp14
-rw-r--r--src/mbgl/tile/vector_tile.cpp299
-rw-r--r--src/mbgl/tile/vector_tile_data.cpp89
-rw-r--r--src/mbgl/tile/vector_tile_data.hpp54
-rw-r--r--src/mbgl/util/i18n.cpp2
-rw-r--r--src/mbgl/util/intersection_tests.cpp2
-rw-r--r--src/mbgl/util/logging.cpp2
-rw-r--r--src/mbgl/util/longest_common_subsequence.hpp106
-rw-r--r--src/mbgl/util/mat2.hpp2
-rw-r--r--src/mbgl/util/offscreen_texture.cpp1
-rw-r--r--src/mbgl/util/offscreen_texture.hpp2
-rw-r--r--src/mbgl/util/premultiply.cpp2
-rw-r--r--src/mbgl/util/std.hpp8
-rw-r--r--src/mbgl/util/thread.hpp208
-rw-r--r--src/mbgl/util/thread_context.cpp13
-rw-r--r--src/mbgl/util/thread_context.hpp22
-rw-r--r--src/mbgl/util/thread_local.hpp2
-rw-r--r--src/mbgl/util/work_queue.cpp38
-rw-r--r--src/mbgl/util/work_queue.hpp40
301 files changed, 7876 insertions, 6851 deletions
diff --git a/src/mbgl/actor/actor.hpp b/src/mbgl/actor/actor.hpp
deleted file mode 100644
index 810114c513..0000000000
--- a/src/mbgl/actor/actor.hpp
+++ /dev/null
@@ -1,77 +0,0 @@
-#pragma once
-
-#include <mbgl/actor/mailbox.hpp>
-#include <mbgl/actor/message.hpp>
-#include <mbgl/actor/actor_ref.hpp>
-#include <mbgl/util/noncopyable.hpp>
-
-#include <memory>
-
-namespace mbgl {
-
-/*
- An `Actor<O>` is an owning reference to an asynchronous object of type `O`: an "actor".
- Communication with an actor happens via message passing: you send a message to the object
- (using `invoke`), passing a pointer to the member function to call and arguments which
- are then forwarded to the actor.
-
- The actor receives messages sent to it asynchronously, in a manner defined its `Scheduler`.
- To store incoming messages before their receipt, each actor has a `Mailbox`, which acts as
- a FIFO queue. Messages sent from actor S to actor R are guaranteed to be processed in the
- order sent. However, relative order of messages sent by two *different* actors S1 and S2
- to R is *not* guaranteed (and can't be: S1 and S2 may be acting asynchronously with respect
- to each other).
-
- An `Actor<O>` can be converted to an `ActorRef<O>`, a non-owning value object representing
- a (weak) reference to the actor. Messages can be sent via the `Ref` as well.
-
- It's safe -- and encouraged -- to pass `Ref`s between actors via messages. This is how two-way
- communication and other forms of collaboration between multiple actors is accomplished.
-
- It's safe for a `Ref` to outlive its `Actor` -- the reference is "weak", and does not extend
- the lifetime of the owning Actor, and sending a message to a `Ref` whose `Actor` has died is
- a no-op. (In the future, a dead-letters queue or log may be implemented.)
-
- Construction and destruction of an actor is currently synchronous: the corresponding `O`
- object is constructed synchronously by the `Actor` constructor, and destructed synchronously
- by the `~Actor` destructor, after ensuring that the `O` is not currently receiving an
- asynchronous message. (Construction and destruction may change to be asynchronous in the
- future.) The constructor of `O` is passed an `ActorRef<O>` referring to itself (which it
- can use to self-send messages), followed by the forwarded arguments passed to `Actor<O>`.
-
- Please don't send messages that contain shared pointers or references. That subverts the
- purpose of the actor model: prohibiting direct concurrent access to shared state.
-*/
-
-template <class Object>
-class Actor : public util::noncopyable {
-public:
- template <class... Args>
- Actor(Scheduler& scheduler, Args&&... args_)
- : mailbox(std::make_shared<Mailbox>(scheduler)),
- object(self(), std::forward<Args>(args_)...) {
- }
-
- ~Actor() {
- mailbox->close();
- }
-
- template <typename Fn, class... Args>
- void invoke(Fn fn, Args&&... args) {
- mailbox->push(actor::makeMessage(object, fn, std::forward<Args>(args)...));
- }
-
- ActorRef<std::decay_t<Object>> self() {
- return ActorRef<std::decay_t<Object>>(object, mailbox);
- }
-
- operator ActorRef<std::decay_t<Object>>() {
- return self();
- }
-
-private:
- std::shared_ptr<Mailbox> mailbox;
- Object object;
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/actor/actor_ref.hpp b/src/mbgl/actor/actor_ref.hpp
deleted file mode 100644
index 9d858d823f..0000000000
--- a/src/mbgl/actor/actor_ref.hpp
+++ /dev/null
@@ -1,43 +0,0 @@
-#pragma once
-
-#include <mbgl/actor/mailbox.hpp>
-#include <mbgl/actor/message.hpp>
-
-#include <memory>
-
-namespace mbgl {
-
-/*
- An `ActorRef<O>` is a *non*-owning, weak reference to an actor of type `O`. You can send it
- messages just like an `Actor<O>`. It's a value object: safe to copy and pass between actors
- via messages.
-
- An `ActorRef<O>` does not extend the lifetime of the corresponding `Actor<O>`. That's determined
- entirely by whichever object owns the `Actor<O>` -- the actor's "supervisor".
-
- It's safe for a `Ref` to outlive its `Actor` -- the reference is "weak", and does not extend
- the lifetime of the owning Actor, and sending a message to a `Ref` whose `Actor` has died is
- a no-op. (In the future, a dead-letters queue or log may be implemented.)
-*/
-
-template <class Object>
-class ActorRef {
-public:
- ActorRef(Object& object_, std::weak_ptr<Mailbox> weakMailbox_)
- : object(object_),
- weakMailbox(std::move(weakMailbox_)) {
- }
-
- template <typename Fn, class... Args>
- void invoke(Fn fn, Args&&... args) {
- if (auto mailbox = weakMailbox.lock()) {
- mailbox->push(actor::makeMessage(object, fn, std::forward<Args>(args)...));
- }
- }
-
-private:
- Object& object;
- std::weak_ptr<Mailbox> weakMailbox;
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/actor/mailbox.cpp b/src/mbgl/actor/mailbox.cpp
index 5f60629833..373c24275f 100644
--- a/src/mbgl/actor/mailbox.cpp
+++ b/src/mbgl/actor/mailbox.cpp
@@ -10,8 +10,24 @@ Mailbox::Mailbox(Scheduler& scheduler_)
: scheduler(scheduler_) {
}
+void Mailbox::close() {
+ // Block until neither receive() nor push() are in progress. Two mutexes are used because receive()
+ // must not block send(). Of the two, the receiving mutex must be acquired first, because that is
+ // the order that an actor will obtain them when it self-sends a message, and consistent lock
+ // acquisition order prevents deadlocks.
+ // The receiving mutex is recursive to allow a mailbox (and thus the actor) to close itself.
+ std::lock_guard<std::recursive_mutex> receivingLock(receivingMutex);
+ std::lock_guard<std::mutex> pushingLock(pushingMutex);
+
+ closed = true;
+}
+
void Mailbox::push(std::unique_ptr<Message> message) {
- assert(!closing);
+ std::lock_guard<std::mutex> pushingLock(pushingMutex);
+
+ if (closed) {
+ return;
+ }
std::lock_guard<std::mutex> queueLock(queueMutex);
bool wasEmpty = queue.empty();
@@ -21,16 +37,10 @@ void Mailbox::push(std::unique_ptr<Message> message) {
}
}
-void Mailbox::close() {
- // Block until the scheduler is guaranteed not to be executing receive().
- std::lock_guard<std::mutex> closingLock(closingMutex);
- closing = true;
-}
-
void Mailbox::receive() {
- std::lock_guard<std::mutex> closingLock(closingMutex);
+ std::lock_guard<std::recursive_mutex> receivingLock(receivingMutex);
- if (closing) {
+ if (closed) {
return;
}
diff --git a/src/mbgl/actor/message.hpp b/src/mbgl/actor/message.hpp
deleted file mode 100644
index cf071d4933..0000000000
--- a/src/mbgl/actor/message.hpp
+++ /dev/null
@@ -1,48 +0,0 @@
-#pragma once
-
-#include <utility>
-
-namespace mbgl {
-
-// A movable type-erasing function wrapper. This allows to store arbitrary invokable
-// things (like std::function<>, or the result of a movable-only std::bind()) in the queue.
-// Source: http://stackoverflow.com/a/29642072/331379
-class Message {
-public:
- virtual ~Message() = default;
- virtual void operator()() = 0;
-};
-
-template <class Object, class MemberFn, class ArgsTuple>
-class MessageImpl : public Message {
-public:
- MessageImpl(Object& object_, MemberFn memberFn_, ArgsTuple argsTuple_)
- : object(object_),
- memberFn(memberFn_),
- argsTuple(std::move(argsTuple_)) {
- }
-
- void operator()() override {
- invoke(std::make_index_sequence<std::tuple_size<ArgsTuple>::value>());
- }
-
- template <std::size_t... I>
- void invoke(std::index_sequence<I...>) {
- (object.*memberFn)(std::move(std::get<I>(argsTuple))...);
- }
-
- Object& object;
- MemberFn memberFn;
- ArgsTuple argsTuple;
-};
-
-namespace actor {
-
-template <class Object, class MemberFn, class... Args>
-std::unique_ptr<Message> makeMessage(Object& object, MemberFn memberFn, Args&&... args) {
- auto tuple = std::make_tuple(std::forward<Args>(args)...);
- return std::make_unique<MessageImpl<Object, MemberFn, decltype(tuple)>>(object, memberFn, std::move(tuple));
-}
-
-} // namespace actor
-} // namespace mbgl
diff --git a/src/mbgl/annotation/annotation_manager.cpp b/src/mbgl/annotation/annotation_manager.cpp
index 88153f5fb7..a69dba1bf2 100644
--- a/src/mbgl/annotation/annotation_manager.cpp
+++ b/src/mbgl/annotation/annotation_manager.cpp
@@ -4,8 +4,7 @@
#include <mbgl/annotation/symbol_annotation_impl.hpp>
#include <mbgl/annotation/line_annotation_impl.hpp>
#include <mbgl/annotation/fill_annotation_impl.hpp>
-#include <mbgl/annotation/style_sourced_annotation_impl.hpp>
-#include <mbgl/style/style.hpp>
+#include <mbgl/style/style_impl.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <mbgl/storage/file_source.hpp>
@@ -19,16 +18,11 @@ using namespace style;
const std::string AnnotationManager::SourceID = "com.mapbox.annotations";
const std::string AnnotationManager::PointLayerID = "com.mapbox.annotations.points";
-AnnotationManager::AnnotationManager(float pixelRatio)
- : spriteAtlas({ 1024, 1024 }, pixelRatio) {
- // This is a special atlas, holding only images added via addIcon, so we always treat it as
- // loaded.
- spriteAtlas.markAsLoaded();
-}
-
+AnnotationManager::AnnotationManager() = default;
AnnotationManager::~AnnotationManager() = default;
AnnotationID AnnotationManager::addAnnotation(const Annotation& annotation, const uint8_t maxZoom) {
+ std::lock_guard<std::mutex> lock(mutex);
AnnotationID id = nextID++;
Annotation::visit(annotation, [&] (const auto& annotation_) {
this->add(id, annotation_, maxZoom);
@@ -37,21 +31,15 @@ AnnotationID AnnotationManager::addAnnotation(const Annotation& annotation, cons
}
Update AnnotationManager::updateAnnotation(const AnnotationID& id, const Annotation& annotation, const uint8_t maxZoom) {
+ std::lock_guard<std::mutex> lock(mutex);
return Annotation::visit(annotation, [&] (const auto& annotation_) {
return this->update(id, annotation_, maxZoom);
});
}
void AnnotationManager::removeAnnotation(const AnnotationID& id) {
- if (symbolAnnotations.find(id) != symbolAnnotations.end()) {
- symbolTree.remove(symbolAnnotations.at(id));
- symbolAnnotations.erase(id);
- } else if (shapeAnnotations.find(id) != shapeAnnotations.end()) {
- obsoleteShapeAnnotationLayers.insert(shapeAnnotations.at(id)->layerID);
- shapeAnnotations.erase(id);
- } else {
- assert(false); // Should never happen
- }
+ std::lock_guard<std::mutex> lock(mutex);
+ remove(id);
}
void AnnotationManager::add(const AnnotationID& id, const SymbolAnnotation& annotation, const uint8_t) {
@@ -72,12 +60,6 @@ void AnnotationManager::add(const AnnotationID& id, const FillAnnotation& annota
obsoleteShapeAnnotationLayers.erase(impl.layerID);
}
-void AnnotationManager::add(const AnnotationID& id, const StyleSourcedAnnotation& annotation, const uint8_t maxZoom) {
- ShapeAnnotationImpl& impl = *shapeAnnotations.emplace(id,
- std::make_unique<StyleSourcedAnnotationImpl>(id, annotation, maxZoom)).first->second;
- obsoleteShapeAnnotationLayers.erase(impl.layerID);
-}
-
Update AnnotationManager::update(const AnnotationID& id, const SymbolAnnotation& annotation, const uint8_t maxZoom) {
Update result = Update::Nothing;
@@ -110,6 +92,7 @@ Update AnnotationManager::update(const AnnotationID& id, const LineAnnotation& a
assert(false); // Attempt to update a non-existent shape annotation
return Update::Nothing;
}
+
removeAndAdd(id, annotation, maxZoom);
return Update::AnnotationData | Update::AnnotationStyle;
}
@@ -120,40 +103,43 @@ Update AnnotationManager::update(const AnnotationID& id, const FillAnnotation& a
assert(false); // Attempt to update a non-existent shape annotation
return Update::Nothing;
}
- removeAndAdd(id, annotation, maxZoom);
- return Update::AnnotationData | Update::AnnotationStyle;
-}
-Update AnnotationManager::update(const AnnotationID& id, const StyleSourcedAnnotation& annotation, const uint8_t maxZoom) {
- auto it = shapeAnnotations.find(id);
- if (it == shapeAnnotations.end()) {
- assert(false); // Attempt to update a non-existent shape annotation
- return Update::Nothing;
- }
removeAndAdd(id, annotation, maxZoom);
return Update::AnnotationData | Update::AnnotationStyle;
}
void AnnotationManager::removeAndAdd(const AnnotationID& id, const Annotation& annotation, const uint8_t maxZoom) {
- removeAnnotation(id);
+ remove(id);
Annotation::visit(annotation, [&] (const auto& annotation_) {
this->add(id, annotation_, maxZoom);
});
}
+void AnnotationManager::remove(const AnnotationID& id) {
+ if (symbolAnnotations.find(id) != symbolAnnotations.end()) {
+ symbolTree.remove(symbolAnnotations.at(id));
+ symbolAnnotations.erase(id);
+ } else if (shapeAnnotations.find(id) != shapeAnnotations.end()) {
+ obsoleteShapeAnnotationLayers.insert(shapeAnnotations.at(id)->layerID);
+ shapeAnnotations.erase(id);
+ } else {
+ assert(false); // Should never happen
+ }
+}
+
std::unique_ptr<AnnotationTileData> AnnotationManager::getTileData(const CanonicalTileID& tileID) {
if (symbolAnnotations.empty() && shapeAnnotations.empty())
return nullptr;
auto tileData = std::make_unique<AnnotationTileData>();
- AnnotationTileLayer& pointLayer = tileData->layers.emplace(PointLayerID, PointLayerID).first->second;
+ auto pointLayer = tileData->addLayer(PointLayerID);
LatLngBounds tileBounds(tileID);
symbolTree.query(boost::geometry::index::intersects(tileBounds),
boost::make_function_output_iterator([&](const auto& val){
- val->updateLayer(tileID, pointLayer);
+ val->updateLayer(tileID, *pointLayer);
}));
for (const auto& shape : shapeAnnotations) {
@@ -163,60 +149,99 @@ std::unique_ptr<AnnotationTileData> AnnotationManager::getTileData(const Canonic
return tileData;
}
-void AnnotationManager::updateStyle(Style& style) {
- // Create annotation source, point layer, and point bucket
+void AnnotationManager::updateStyle(Style::Impl& style) {
+ // Create annotation source, point layer, and point bucket. We do everything via Style::Impl
+ // because we don't want annotation mutations to trigger Style::Impl::styleMutated to be set.
if (!style.getSource(SourceID)) {
style.addSource(std::make_unique<AnnotationSource>());
std::unique_ptr<SymbolLayer> layer = std::make_unique<SymbolLayer>(PointLayerID, SourceID);
layer->setSourceLayer(PointLayerID);
- layer->setIconImage({"{sprite}"});
+ layer->setIconImage({SourceID + ".{sprite}"});
layer->setIconAllowOverlap(true);
layer->setIconIgnorePlacement(true);
style.addLayer(std::move(layer));
}
+ std::lock_guard<std::mutex> lock(mutex);
+
for (const auto& shape : shapeAnnotations) {
shape.second->updateStyle(style);
}
+ for (const auto& image : images) {
+ // Call addImage even for images we may have previously added, because we must support
+ // addAnnotationImage being used to update an existing image. Creating a new image is
+ // relatively cheap, as it copies only the Immutable reference. (We can't keep track
+ // of which images need to be added because we don't know if the style is the same
+ // instance as in the last updateStyle call. If it's a new style, we need to add all
+ // images.)
+ style.addImage(std::make_unique<style::Image>(image.second));
+ }
+
for (const auto& layer : obsoleteShapeAnnotationLayers) {
if (style.getLayer(layer)) {
style.removeLayer(layer);
}
}
+ for (const auto& image : obsoleteImages) {
+ if (style.getImage(image)) {
+ style.removeImage(image);
+ }
+ }
+
obsoleteShapeAnnotationLayers.clear();
+ obsoleteImages.clear();
}
void AnnotationManager::updateData() {
+ std::lock_guard<std::mutex> lock(mutex);
for (auto& tile : tiles) {
tile->setData(getTileData(tile->id.canonical));
}
}
void AnnotationManager::addTile(AnnotationTile& tile) {
+ std::lock_guard<std::mutex> lock(mutex);
tiles.insert(&tile);
tile.setData(getTileData(tile.id.canonical));
}
void AnnotationManager::removeTile(AnnotationTile& tile) {
+ std::lock_guard<std::mutex> lock(mutex);
tiles.erase(&tile);
}
-void AnnotationManager::addImage(const std::string& id, std::unique_ptr<style::Image> image) {
- spriteAtlas.addImage(id, std::move(image));
+// To ensure that annotation images do not collide with images from the style,
+// we prefix input image IDs with "com.mapbox.annotations".
+static std::string prefixedImageID(const std::string& id) {
+ return AnnotationManager::SourceID + "." + id;
+}
+
+void AnnotationManager::addImage(std::unique_ptr<style::Image> image) {
+ std::lock_guard<std::mutex> lock(mutex);
+ const std::string id = prefixedImageID(image->getID());
+ images.erase(id);
+ images.emplace(id,
+ style::Image(id, image->getImage().clone(), image->getPixelRatio(), image->isSdf()));
+ obsoleteImages.erase(id);
}
-void AnnotationManager::removeImage(const std::string& id) {
- spriteAtlas.removeImage(id);
+void AnnotationManager::removeImage(const std::string& id_) {
+ std::lock_guard<std::mutex> lock(mutex);
+ const std::string id = prefixedImageID(id_);
+ images.erase(id);
+ obsoleteImages.insert(id);
}
-double AnnotationManager::getTopOffsetPixelsForImage(const std::string& id) {
- const style::Image* image = spriteAtlas.getImage(id);
- return image ? -(image->image.size.height / image->pixelRatio) / 2 : 0;
+double AnnotationManager::getTopOffsetPixelsForImage(const std::string& id_) {
+ std::lock_guard<std::mutex> lock(mutex);
+ const std::string id = prefixedImageID(id_);
+ auto it = images.find(id);
+ return it != images.end() ? -(it->second.getImage().size.height / it->second.getPixelRatio()) / 2 : 0;
}
} // namespace mbgl
diff --git a/src/mbgl/annotation/annotation_manager.hpp b/src/mbgl/annotation/annotation_manager.hpp
index 0ab43bec15..6906791db7 100644
--- a/src/mbgl/annotation/annotation_manager.hpp
+++ b/src/mbgl/annotation/annotation_manager.hpp
@@ -2,13 +2,16 @@
#include <mbgl/annotation/annotation.hpp>
#include <mbgl/annotation/symbol_annotation_impl.hpp>
-#include <mbgl/sprite/sprite_atlas.hpp>
+#include <mbgl/style/image.hpp>
#include <mbgl/map/update.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/util/noncopyable.hpp>
+#include <mutex>
#include <string>
#include <vector>
#include <unordered_set>
+#include <unordered_map>
namespace mbgl {
@@ -18,26 +21,20 @@ class AnnotationTileData;
class SymbolAnnotationImpl;
class ShapeAnnotationImpl;
-namespace style {
-class Style;
-class Image;
-} // namespace style
-
class AnnotationManager : private util::noncopyable {
public:
- AnnotationManager(float pixelRatio);
+ AnnotationManager();
~AnnotationManager();
AnnotationID addAnnotation(const Annotation&, const uint8_t maxZoom);
Update updateAnnotation(const AnnotationID&, const Annotation&, const uint8_t maxZoom);
void removeAnnotation(const AnnotationID&);
- void addImage(const std::string&, std::unique_ptr<style::Image>);
+ void addImage(std::unique_ptr<style::Image>);
void removeImage(const std::string&);
double getTopOffsetPixelsForImage(const std::string&);
- SpriteAtlas& getSpriteAtlas() { return spriteAtlas; }
- void updateStyle(style::Style&);
+ void updateStyle(style::Style::Impl&);
void updateData();
void addTile(AnnotationTile&);
@@ -50,17 +47,19 @@ private:
void add(const AnnotationID&, const SymbolAnnotation&, const uint8_t);
void add(const AnnotationID&, const LineAnnotation&, const uint8_t);
void add(const AnnotationID&, const FillAnnotation&, const uint8_t);
- void add(const AnnotationID&, const StyleSourcedAnnotation&, const uint8_t);
Update update(const AnnotationID&, const SymbolAnnotation&, const uint8_t);
Update update(const AnnotationID&, const LineAnnotation&, const uint8_t);
Update update(const AnnotationID&, const FillAnnotation&, const uint8_t);
- Update update(const AnnotationID&, const StyleSourcedAnnotation&, const uint8_t);
void removeAndAdd(const AnnotationID&, const Annotation&, const uint8_t);
+ void remove(const AnnotationID&);
+
std::unique_ptr<AnnotationTileData> getTileData(const CanonicalTileID&);
+ std::mutex mutex;
+
AnnotationID nextID = 0;
using SymbolAnnotationTree = boost::geometry::index::rtree<std::shared_ptr<const SymbolAnnotationImpl>, boost::geometry::index::rstar<16, 4>>;
@@ -68,13 +67,15 @@ private:
// <https://github.com/mapbox/mapbox-gl-native/issues/5691>
using SymbolAnnotationMap = std::map<AnnotationID, std::shared_ptr<SymbolAnnotationImpl>>;
using ShapeAnnotationMap = std::map<AnnotationID, std::unique_ptr<ShapeAnnotationImpl>>;
+ using ImageMap = std::unordered_map<std::string, style::Image>;
SymbolAnnotationTree symbolTree;
SymbolAnnotationMap symbolAnnotations;
ShapeAnnotationMap shapeAnnotations;
+ ImageMap images;
std::unordered_set<std::string> obsoleteShapeAnnotationLayers;
+ std::unordered_set<std::string> obsoleteImages;
std::unordered_set<AnnotationTile*> tiles;
- SpriteAtlas spriteAtlas;
friend class AnnotationTile;
};
diff --git a/src/mbgl/annotation/annotation_source.cpp b/src/mbgl/annotation/annotation_source.cpp
index 9956140179..68f36f2d3a 100644
--- a/src/mbgl/annotation/annotation_source.cpp
+++ b/src/mbgl/annotation/annotation_source.cpp
@@ -1,25 +1,24 @@
#include <mbgl/annotation/annotation_source.hpp>
#include <mbgl/annotation/annotation_manager.hpp>
-#include <mbgl/annotation/render_annotation_source.hpp>
namespace mbgl {
using namespace style;
AnnotationSource::AnnotationSource()
- : Source(SourceType::Annotations, std::make_unique<Impl>(*this)) {
+ : Source(makeMutable<Impl>()) {
}
-AnnotationSource::Impl::Impl(Source& base_)
- : Source::Impl(SourceType::Annotations, AnnotationManager::SourceID, base_) {
+AnnotationSource::Impl::Impl()
+ : Source::Impl(SourceType::Annotations, AnnotationManager::SourceID) {
}
-void AnnotationSource::Impl::loadDescription(FileSource&) {
+void AnnotationSource::loadDescription(FileSource&) {
loaded = true;
}
-std::unique_ptr<RenderSource> AnnotationSource::Impl::createRenderSource() const {
- return std::make_unique<RenderAnnotationSource>(*this);
+optional<std::string> AnnotationSource::Impl::getAttribution() const {
+ return {};
}
} // namespace mbgl
diff --git a/src/mbgl/annotation/annotation_source.hpp b/src/mbgl/annotation/annotation_source.hpp
index 46c9564443..0728f3207e 100644
--- a/src/mbgl/annotation/annotation_source.hpp
+++ b/src/mbgl/annotation/annotation_source.hpp
@@ -10,14 +10,19 @@ public:
AnnotationSource();
class Impl;
+ const Impl& impl() const;
+
+private:
+ void loadDescription(FileSource&) final;
+
+ Mutable<Impl> mutableImpl() const;
};
class AnnotationSource::Impl : public style::Source::Impl {
public:
- Impl(Source&);
+ Impl();
- void loadDescription(FileSource&) final;
- std::unique_ptr<RenderSource> createRenderSource() const final;
+ optional<std::string> getAttribution() const final;
};
} // namespace mbgl
diff --git a/src/mbgl/annotation/annotation_tile.cpp b/src/mbgl/annotation/annotation_tile.cpp
index 1253681414..0596d60f4f 100644
--- a/src/mbgl/annotation/annotation_tile.cpp
+++ b/src/mbgl/annotation/annotation_tile.cpp
@@ -3,7 +3,6 @@
#include <mbgl/util/constants.hpp>
#include <mbgl/storage/file_source.hpp>
#include <mbgl/renderer/tile_parameters.hpp>
-#include <mbgl/style/style.hpp>
#include <utility>
@@ -11,9 +10,7 @@ namespace mbgl {
AnnotationTile::AnnotationTile(const OverscaledTileID& overscaledTileID,
const TileParameters& parameters)
- : GeometryTile(overscaledTileID, AnnotationManager::SourceID, parameters,
- *parameters.style.glyphAtlas,
- parameters.annotationManager.spriteAtlas),
+ : GeometryTile(overscaledTileID, AnnotationManager::SourceID, parameters),
annotationManager(parameters.annotationManager) {
annotationManager.addTile(*this);
}
@@ -22,37 +19,105 @@ AnnotationTile::~AnnotationTile() {
annotationManager.removeTile(*this);
}
-void AnnotationTile::setNecessity(Necessity) {}
+void AnnotationTile::setNecessity(Necessity) {
+}
+
+class AnnotationTileFeatureData {
+public:
+ AnnotationTileFeatureData(const AnnotationID id_,
+ FeatureType type_,
+ GeometryCollection&& geometries_,
+ std::unordered_map<std::string, std::string>&& properties_)
+ : id(id_),
+ type(type_),
+ geometries(std::move(geometries_)),
+ properties(std::move(properties_)) {
+ }
+
+ AnnotationID id;
+ FeatureType type;
+ GeometryCollection geometries;
+ std::unordered_map<std::string, std::string> properties;
+};
-AnnotationTileFeature::AnnotationTileFeature(const AnnotationID id_,
- FeatureType type_, GeometryCollection geometries_,
- std::unordered_map<std::string, std::string> properties_)
- : id(id_),
- type(type_),
- properties(std::move(properties_)),
- geometries(std::move(geometries_)) {}
+AnnotationTileFeature::AnnotationTileFeature(std::shared_ptr<const AnnotationTileFeatureData> data_)
+ : data(std::move(data_)) {
+}
+
+AnnotationTileFeature::~AnnotationTileFeature() = default;
+
+FeatureType AnnotationTileFeature::getType() const {
+ return data->type;
+}
optional<Value> AnnotationTileFeature::getValue(const std::string& key) const {
- auto it = properties.find(key);
- if (it != properties.end()) {
+ auto it = data->properties.find(key);
+ if (it != data->properties.end()) {
return optional<Value>(it->second);
}
return optional<Value>();
}
-AnnotationTileLayer::AnnotationTileLayer(std::string name_)
- : name(std::move(name_)) {}
+optional<FeatureIdentifier> AnnotationTileFeature::getID() const {
+ return { static_cast<uint64_t>(data->id) };
+}
+
+GeometryCollection AnnotationTileFeature::getGeometries() const {
+ return data->geometries;
+}
+
+class AnnotationTileLayerData {
+public:
+ AnnotationTileLayerData(const std::string& name_) : name(name_) {
+ }
+
+ const std::string name;
+ std::vector<std::shared_ptr<const AnnotationTileFeatureData>> features;
+};
+
+AnnotationTileLayer::AnnotationTileLayer(std::shared_ptr<AnnotationTileLayerData> layer_) : layer(std::move(layer_)) {
+}
+
+std::size_t AnnotationTileLayer::featureCount() const {
+ return layer->features.size();
+}
+
+std::unique_ptr<GeometryTileFeature> AnnotationTileLayer::getFeature(std::size_t i) const {
+ return std::make_unique<AnnotationTileFeature>(layer->features.at(i));
+}
+
+std::string AnnotationTileLayer::getName() const {
+ return layer->name;
+}
+
+void AnnotationTileLayer::addFeature(const AnnotationID id,
+ FeatureType type,
+ GeometryCollection geometries,
+ std::unordered_map<std::string, std::string> properties) {
+
+ layer->features.emplace_back(std::make_shared<AnnotationTileFeatureData>(
+ id, type, std::move(geometries), std::move(properties)));
+}
std::unique_ptr<GeometryTileData> AnnotationTileData::clone() const {
return std::make_unique<AnnotationTileData>(*this);
}
-const GeometryTileLayer* AnnotationTileData::getLayer(const std::string& name) const {
+std::unique_ptr<GeometryTileLayer> AnnotationTileData::getLayer(const std::string& name) const {
auto it = layers.find(name);
if (it != layers.end()) {
- return &it->second;
+ return std::make_unique<AnnotationTileLayer>(it->second);
}
return nullptr;
}
+std::unique_ptr<AnnotationTileLayer> AnnotationTileData::addLayer(const std::string& name) {
+ // Only constructs a new layer if it doesn't yet exist, otherwise, we'll use the existing one.
+ auto it = layers.find(name);
+ if (it == layers.end()) {
+ it = layers.emplace(name, std::make_shared<AnnotationTileLayerData>(name)).first;
+ }
+ return std::make_unique<AnnotationTileLayer>(it->second);
+}
+
} // namespace mbgl
diff --git a/src/mbgl/annotation/annotation_tile.hpp b/src/mbgl/annotation/annotation_tile.hpp
index ea4ff5ebd5..88505c50e3 100644
--- a/src/mbgl/annotation/annotation_tile.hpp
+++ b/src/mbgl/annotation/annotation_tile.hpp
@@ -11,8 +11,7 @@ class TileParameters;
class AnnotationTile : public GeometryTile {
public:
- AnnotationTile(const OverscaledTileID&,
- const TileParameters&);
+ AnnotationTile(const OverscaledTileID&, const TileParameters&);
~AnnotationTile() override;
void setNecessity(Necessity) final;
@@ -21,46 +20,50 @@ private:
AnnotationManager& annotationManager;
};
+class AnnotationTileFeatureData;
+
class AnnotationTileFeature : public GeometryTileFeature {
public:
- AnnotationTileFeature(AnnotationID, FeatureType, GeometryCollection,
- std::unordered_map<std::string, std::string> properties = {{}});
+ AnnotationTileFeature(std::shared_ptr<const AnnotationTileFeatureData>);
+ ~AnnotationTileFeature() override;
- FeatureType getType() const override { return type; }
+ FeatureType getType() const override;
optional<Value> getValue(const std::string&) const override;
- optional<FeatureIdentifier> getID() const override { return { static_cast<uint64_t>(id) }; }
- GeometryCollection getGeometries() const override { return geometries; }
+ optional<FeatureIdentifier> getID() const override;
+ GeometryCollection getGeometries() const override;
- const AnnotationID id;
- const FeatureType type;
- const std::unordered_map<std::string, std::string> properties;
- const GeometryCollection geometries;
+private:
+ std::shared_ptr<const AnnotationTileFeatureData> data;
};
+class AnnotationTileLayerData;
+
class AnnotationTileLayer : public GeometryTileLayer {
public:
- AnnotationTileLayer(std::string);
-
- std::size_t featureCount() const override { return features.size(); }
+ AnnotationTileLayer(std::shared_ptr<AnnotationTileLayerData>);
- std::unique_ptr<GeometryTileFeature> getFeature(std::size_t i) const override {
- return std::make_unique<AnnotationTileFeature>(features.at(i));
- }
+ std::size_t featureCount() const override;
+ std::unique_ptr<GeometryTileFeature> getFeature(std::size_t i) const override;
+ std::string getName() const override;
- std::string getName() const override { return name; };
-
- std::vector<AnnotationTileFeature> features;
+ void addFeature(const AnnotationID,
+ FeatureType,
+ GeometryCollection,
+ std::unordered_map<std::string, std::string> properties = { {} });
private:
- std::string name;
+ std::shared_ptr<AnnotationTileLayerData> layer;
};
class AnnotationTileData : public GeometryTileData {
public:
std::unique_ptr<GeometryTileData> clone() const override;
- const GeometryTileLayer* getLayer(const std::string&) const override;
+ std::unique_ptr<GeometryTileLayer> getLayer(const std::string&) const override;
+
+ std::unique_ptr<AnnotationTileLayer> addLayer(const std::string&);
- std::unordered_map<std::string, AnnotationTileLayer> layers;
+private:
+ std::unordered_map<std::string, std::shared_ptr<AnnotationTileLayerData>> layers;
};
} // namespace mbgl
diff --git a/src/mbgl/annotation/fill_annotation_impl.cpp b/src/mbgl/annotation/fill_annotation_impl.cpp
index 3e91524e86..5dc36edab0 100644
--- a/src/mbgl/annotation/fill_annotation_impl.cpp
+++ b/src/mbgl/annotation/fill_annotation_impl.cpp
@@ -1,6 +1,6 @@
#include <mbgl/annotation/fill_annotation_impl.hpp>
#include <mbgl/annotation/annotation_manager.hpp>
-#include <mbgl/style/style.hpp>
+#include <mbgl/style/style_impl.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
namespace mbgl {
@@ -12,7 +12,7 @@ FillAnnotationImpl::FillAnnotationImpl(AnnotationID id_, FillAnnotation annotati
annotation({ ShapeAnnotationGeometry::visit(annotation_.geometry, CloseShapeAnnotation{}), annotation_.opacity, annotation_.color, annotation_.outlineColor }) {
}
-void FillAnnotationImpl::updateStyle(Style& style) const {
+void FillAnnotationImpl::updateStyle(Style::Impl& style) const {
Layer* layer = style.getLayer(layerID);
if (!layer) {
@@ -21,7 +21,7 @@ void FillAnnotationImpl::updateStyle(Style& style) const {
layer = style.addLayer(std::move(newLayer), AnnotationManager::PointLayerID);
}
- FillLayer* fillLayer = layer->as<FillLayer>();
+ auto* fillLayer = layer->as<FillLayer>();
fillLayer->setFillOpacity(annotation.opacity);
fillLayer->setFillColor(annotation.color);
fillLayer->setFillOutlineColor(annotation.outlineColor);
diff --git a/src/mbgl/annotation/fill_annotation_impl.hpp b/src/mbgl/annotation/fill_annotation_impl.hpp
index 6376eee880..5c49e447b8 100644
--- a/src/mbgl/annotation/fill_annotation_impl.hpp
+++ b/src/mbgl/annotation/fill_annotation_impl.hpp
@@ -9,7 +9,7 @@ class FillAnnotationImpl : public ShapeAnnotationImpl {
public:
FillAnnotationImpl(AnnotationID, FillAnnotation, uint8_t maxZoom);
- void updateStyle(style::Style&) const final;
+ void updateStyle(style::Style::Impl&) const final;
const ShapeAnnotationGeometry& geometry() const final;
private:
diff --git a/src/mbgl/annotation/line_annotation_impl.cpp b/src/mbgl/annotation/line_annotation_impl.cpp
index 15fa2c67f3..8954ecfa58 100644
--- a/src/mbgl/annotation/line_annotation_impl.cpp
+++ b/src/mbgl/annotation/line_annotation_impl.cpp
@@ -1,6 +1,6 @@
#include <mbgl/annotation/line_annotation_impl.hpp>
#include <mbgl/annotation/annotation_manager.hpp>
-#include <mbgl/style/style.hpp>
+#include <mbgl/style/style_impl.hpp>
#include <mbgl/style/layers/line_layer.hpp>
namespace mbgl {
@@ -12,7 +12,7 @@ LineAnnotationImpl::LineAnnotationImpl(AnnotationID id_, LineAnnotation annotati
annotation({ ShapeAnnotationGeometry::visit(annotation_.geometry, CloseShapeAnnotation{}), annotation_.opacity, annotation_.width, annotation_.color }) {
}
-void LineAnnotationImpl::updateStyle(Style& style) const {
+void LineAnnotationImpl::updateStyle(Style::Impl& style) const {
Layer* layer = style.getLayer(layerID);
if (!layer) {
@@ -22,7 +22,7 @@ void LineAnnotationImpl::updateStyle(Style& style) const {
layer = style.addLayer(std::move(newLayer), AnnotationManager::PointLayerID);
}
- LineLayer* lineLayer = layer->as<LineLayer>();
+ auto* lineLayer = layer->as<LineLayer>();
lineLayer->setLineOpacity(annotation.opacity);
lineLayer->setLineWidth(annotation.width);
lineLayer->setLineColor(annotation.color);
diff --git a/src/mbgl/annotation/line_annotation_impl.hpp b/src/mbgl/annotation/line_annotation_impl.hpp
index 7945da5d97..548a094d53 100644
--- a/src/mbgl/annotation/line_annotation_impl.hpp
+++ b/src/mbgl/annotation/line_annotation_impl.hpp
@@ -9,7 +9,7 @@ class LineAnnotationImpl : public ShapeAnnotationImpl {
public:
LineAnnotationImpl(AnnotationID, LineAnnotation, uint8_t maxZoom);
- void updateStyle(style::Style&) const final;
+ void updateStyle(style::Style::Impl&) const final;
const ShapeAnnotationGeometry& geometry() const final;
private:
diff --git a/src/mbgl/annotation/render_annotation_source.cpp b/src/mbgl/annotation/render_annotation_source.cpp
index a62d2d51d3..8fb11785fd 100644
--- a/src/mbgl/annotation/render_annotation_source.cpp
+++ b/src/mbgl/annotation/render_annotation_source.cpp
@@ -1,6 +1,7 @@
#include <mbgl/annotation/render_annotation_source.hpp>
#include <mbgl/annotation/annotation_tile.hpp>
#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/painter.hpp>
#include <mbgl/algorithm/generate_clip_ids.hpp>
#include <mbgl/algorithm/generate_clip_ids_impl.hpp>
@@ -9,22 +10,43 @@ namespace mbgl {
using namespace style;
-RenderAnnotationSource::RenderAnnotationSource(const AnnotationSource::Impl& impl_)
+RenderAnnotationSource::RenderAnnotationSource(Immutable<AnnotationSource::Impl> impl_)
: RenderSource(impl_) {
tilePyramid.setObserver(this);
}
+const AnnotationSource::Impl& RenderAnnotationSource::impl() const {
+ return static_cast<const AnnotationSource::Impl&>(*baseImpl);
+}
+
bool RenderAnnotationSource::isLoaded() const {
return tilePyramid.isLoaded();
}
-void RenderAnnotationSource::invalidateTiles() {
- tilePyramid.invalidateTiles();
+void RenderAnnotationSource::update(Immutable<style::Source::Impl> baseImpl_,
+ const std::vector<Immutable<Layer::Impl>>& layers,
+ const bool needsRendering,
+ const bool needsRelayout,
+ const TileParameters& parameters) {
+ std::swap(baseImpl, baseImpl_);
+
+ enabled = needsRendering;
+
+ tilePyramid.update(layers,
+ needsRendering,
+ needsRelayout,
+ parameters,
+ SourceType::Annotations,
+ util::tileSize,
+ { 0, 22 },
+ [&] (const OverscaledTileID& tileID) {
+ return std::make_unique<AnnotationTile>(tileID, parameters);
+ });
}
-void RenderAnnotationSource::startRender(algorithm::ClipIDGenerator& generator, const mat4& projMatrix, const mat4& clipMatrix, const TransformState& transform) {
- generator.update(tilePyramid.getRenderTiles());
- tilePyramid.startRender(projMatrix, clipMatrix, transform);
+void RenderAnnotationSource::startRender(Painter& painter) {
+ painter.clipIDGenerator.update(tilePyramid.getRenderTiles());
+ tilePyramid.startRender(painter);
}
void RenderAnnotationSource::finishRender(Painter& painter) {
@@ -35,39 +57,18 @@ std::map<UnwrappedTileID, RenderTile>& RenderAnnotationSource::getRenderTiles()
return tilePyramid.getRenderTiles();
}
-void RenderAnnotationSource::updateTiles(const TileParameters& parameters) {
- tilePyramid.updateTiles(parameters,
- SourceType::Annotations,
- util::tileSize,
- { 0, 22 },
- [&] (const OverscaledTileID& tileID) {
- return std::make_unique<AnnotationTile>(tileID, parameters);
- });
-}
-
-void RenderAnnotationSource::removeTiles() {
- tilePyramid.removeTiles();
-}
-
-void RenderAnnotationSource::reloadTiles() {
- tilePyramid.reloadTiles();
-}
-
std::unordered_map<std::string, std::vector<Feature>>
RenderAnnotationSource::queryRenderedFeatures(const ScreenLineString& geometry,
- const TransformState& transformState,
- const RenderedQueryOptions& options) const {
- return tilePyramid.queryRenderedFeatures(geometry, transformState, options);
+ const TransformState& transformState,
+ const RenderStyle& style,
+ const RenderedQueryOptions& options) const {
+ return tilePyramid.queryRenderedFeatures(geometry, transformState, style, options);
}
std::vector<Feature> RenderAnnotationSource::querySourceFeatures(const SourceQueryOptions&) const {
return {};
}
-void RenderAnnotationSource::setCacheSize(size_t size) {
- tilePyramid.setCacheSize(size);
-}
-
void RenderAnnotationSource::onLowMemory() {
tilePyramid.onLowMemory();
}
diff --git a/src/mbgl/annotation/render_annotation_source.hpp b/src/mbgl/annotation/render_annotation_source.hpp
index 9ae9340477..7231452d4f 100644
--- a/src/mbgl/annotation/render_annotation_source.hpp
+++ b/src/mbgl/annotation/render_annotation_source.hpp
@@ -8,28 +8,17 @@ namespace mbgl {
class RenderAnnotationSource : public RenderSource {
public:
- RenderAnnotationSource(const AnnotationSource::Impl&);
+ RenderAnnotationSource(Immutable<AnnotationSource::Impl>);
bool isLoaded() const final;
- // Called when the camera has changed. May load new tiles, unload obsolete tiles, or
- // trigger re-placement of existing complete tiles.
- void updateTiles(const TileParameters&) final;
+ void update(Immutable<style::Source::Impl>,
+ const std::vector<Immutable<style::Layer::Impl>>&,
+ bool needsRendering,
+ bool needsRelayout,
+ const TileParameters&) final;
- // Removes all tiles (by putting them into the cache).
- void removeTiles() final;
-
- // Remove all tiles and clear the cache.
- void invalidateTiles() final;
-
- // Request that all loaded tiles re-run the layout operation on the existing source
- // data with fresh style information.
- void reloadTiles() final;
-
- void startRender(algorithm::ClipIDGenerator&,
- const mat4& projMatrix,
- const mat4& clipMatrix,
- const TransformState&) final;
+ void startRender(Painter&) final;
void finishRender(Painter&) final;
std::map<UnwrappedTileID, RenderTile>& getRenderTiles() final;
@@ -37,17 +26,24 @@ public:
std::unordered_map<std::string, std::vector<Feature>>
queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
+ const RenderStyle& style,
const RenderedQueryOptions& options) const final;
std::vector<Feature>
querySourceFeatures(const SourceQueryOptions&) const final;
- void setCacheSize(size_t) final;
void onLowMemory() final;
void dumpDebugLogs() const final;
private:
+ const AnnotationSource::Impl& impl() const;
+
TilePyramid tilePyramid;
};
+template <>
+inline bool RenderSource::is<RenderAnnotationSource>() const {
+ return baseImpl->type == SourceType::Annotations;
+}
+
} // namespace mbgl
diff --git a/src/mbgl/annotation/shape_annotation_impl.cpp b/src/mbgl/annotation/shape_annotation_impl.cpp
index d3ddf62b9e..0c1a631ad8 100644
--- a/src/mbgl/annotation/shape_annotation_impl.cpp
+++ b/src/mbgl/annotation/shape_annotation_impl.cpp
@@ -38,7 +38,7 @@ void ShapeAnnotationImpl::updateTileData(const CanonicalTileID& tileID, Annotati
if (shapeTile.features.empty())
return;
- AnnotationTileLayer& layer = data.layers.emplace(layerID, layerID).first->second;
+ auto layer = data.addLayer(layerID);
ToGeometryCollection toGeometryCollection;
ToFeatureType toFeatureType;
@@ -53,7 +53,7 @@ void ShapeAnnotationImpl::updateTileData(const CanonicalTileID& tileID, Annotati
renderGeometry = fixupPolygons(renderGeometry);
}
- layer.features.emplace_back(id, featureType, renderGeometry);
+ layer->addFeature(id, featureType, renderGeometry);
}
}
diff --git a/src/mbgl/annotation/shape_annotation_impl.hpp b/src/mbgl/annotation/shape_annotation_impl.hpp
index 800b4ec313..ed9e8d015a 100644
--- a/src/mbgl/annotation/shape_annotation_impl.hpp
+++ b/src/mbgl/annotation/shape_annotation_impl.hpp
@@ -4,6 +4,7 @@
#include <mbgl/annotation/annotation.hpp>
#include <mbgl/util/geometry.hpp>
+#include <mbgl/style/style.hpp>
#include <string>
#include <memory>
@@ -13,16 +14,12 @@ namespace mbgl {
class AnnotationTileData;
class CanonicalTileID;
-namespace style {
-class Style;
-} // namespace style
-
class ShapeAnnotationImpl {
public:
ShapeAnnotationImpl(const AnnotationID, const uint8_t maxZoom);
virtual ~ShapeAnnotationImpl() = default;
- virtual void updateStyle(style::Style&) const = 0;
+ virtual void updateStyle(style::Style::Impl&) const = 0;
virtual const ShapeAnnotationGeometry& geometry() const = 0;
void updateTileData(const CanonicalTileID&, AnnotationTileData&);
diff --git a/src/mbgl/annotation/style_sourced_annotation_impl.cpp b/src/mbgl/annotation/style_sourced_annotation_impl.cpp
deleted file mode 100644
index cb664cf15d..0000000000
--- a/src/mbgl/annotation/style_sourced_annotation_impl.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-#include <mbgl/annotation/style_sourced_annotation_impl.hpp>
-#include <mbgl/annotation/annotation_manager.hpp>
-#include <mbgl/style/style.hpp>
-#include <mbgl/style/layer.hpp>
-#include <mbgl/style/layer_impl.hpp>
-#include <mbgl/style/layers/line_layer.hpp>
-#include <mbgl/style/layers/fill_layer.hpp>
-
-namespace mbgl {
-
-using namespace style;
-
-StyleSourcedAnnotationImpl::StyleSourcedAnnotationImpl(AnnotationID id_, StyleSourcedAnnotation annotation_, uint8_t maxZoom_)
- : ShapeAnnotationImpl(id_, maxZoom_),
- annotation(std::move(annotation_)) {
-}
-
-void StyleSourcedAnnotationImpl::updateStyle(Style& style) const {
- if (style.getLayer(layerID))
- return;
-
- const Layer* sourceLayer = style.getLayer(annotation.layerID);
- if (!sourceLayer)
- return;
-
- if (sourceLayer->is<LineLayer>()) {
- std::unique_ptr<Layer> layer = sourceLayer->baseImpl->copy(layerID, AnnotationManager::SourceID);
- layer->as<LineLayer>()->setSourceLayer(layerID);
- layer->as<LineLayer>()->setVisibility(VisibilityType::Visible);
- style.addLayer(std::move(layer), sourceLayer->getID());
- } else if (sourceLayer->is<FillLayer>()) {
- std::unique_ptr<Layer> layer = sourceLayer->baseImpl->copy(layerID, AnnotationManager::SourceID);
- layer->as<FillLayer>()->setSourceLayer(layerID);
- layer->as<FillLayer>()->setVisibility(VisibilityType::Visible);
- style.addLayer(std::move(layer), sourceLayer->getID());
- }
-}
-
-const ShapeAnnotationGeometry& StyleSourcedAnnotationImpl::geometry() const {
- return annotation.geometry;
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/annotation/style_sourced_annotation_impl.hpp b/src/mbgl/annotation/style_sourced_annotation_impl.hpp
deleted file mode 100644
index 82b947302d..0000000000
--- a/src/mbgl/annotation/style_sourced_annotation_impl.hpp
+++ /dev/null
@@ -1,19 +0,0 @@
-#pragma once
-
-#include <mbgl/annotation/shape_annotation_impl.hpp>
-#include <mbgl/annotation/annotation.hpp>
-
-namespace mbgl {
-
-class StyleSourcedAnnotationImpl : public ShapeAnnotationImpl {
-public:
- StyleSourcedAnnotationImpl(AnnotationID, StyleSourcedAnnotation, uint8_t maxZoom);
-
- void updateStyle(style::Style&) const final;
- const ShapeAnnotationGeometry& geometry() const final;
-
-private:
- const StyleSourcedAnnotation annotation;
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/annotation/symbol_annotation_impl.cpp b/src/mbgl/annotation/symbol_annotation_impl.cpp
index e5ae5f4b91..c95eb481b5 100644
--- a/src/mbgl/annotation/symbol_annotation_impl.cpp
+++ b/src/mbgl/annotation/symbol_annotation_impl.cpp
@@ -18,7 +18,7 @@ void SymbolAnnotationImpl::updateLayer(const CanonicalTileID& tileID, Annotation
LatLng latLng { annotation.geometry.y, annotation.geometry.x };
TileCoordinate coordinate = TileCoordinate::fromLatLng(0, latLng);
GeometryCoordinate tilePoint = TileCoordinate::toGeometryCoordinate(UnwrappedTileID(0, tileID), coordinate.p);
- layer.features.emplace_back(id, FeatureType::Point, GeometryCollection {{ {{ tilePoint }} }}, featureProperties);
+ layer.addFeature(id, FeatureType::Point, GeometryCollection {{ {{ tilePoint }} }}, featureProperties);
}
} // namespace mbgl
diff --git a/src/mbgl/annotation/symbol_annotation_impl.hpp b/src/mbgl/annotation/symbol_annotation_impl.hpp
index c9a99ffb8d..9270acb857 100644
--- a/src/mbgl/annotation/symbol_annotation_impl.hpp
+++ b/src/mbgl/annotation/symbol_annotation_impl.hpp
@@ -18,6 +18,7 @@
#pragma GCC diagnostic ignored "-Wshorten-64-to-32"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#pragma GCC diagnostic ignored "-Wmisleading-indentation"
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/box.hpp>
@@ -26,10 +27,6 @@
#include <boost/geometry/index/rtree.hpp>
#pragma GCC diagnostic pop
-// Make Boost Geometry aware of our LatLng type
-BOOST_GEOMETRY_REGISTER_POINT_2D_CONST(mbgl::LatLng, double, boost::geometry::cs::cartesian, longitude(), latitude())
-BOOST_GEOMETRY_REGISTER_BOX(mbgl::LatLngBounds, mbgl::LatLng, southwest(), northeast())
-
namespace mbgl {
class AnnotationTileLayer;
@@ -47,9 +44,42 @@ public:
} // namespace mbgl
-// Tell Boost Geometry how to access a std::shared_ptr<mbgl::SymbolAnnotation> object.
namespace boost {
namespace geometry {
+
+// Make Boost Geometry aware of our LatLng type
+namespace traits {
+
+template<> struct tag<mbgl::LatLng> { using type = point_tag; };
+template<> struct dimension<mbgl::LatLng> : boost::mpl::int_<2> {};
+template<> struct coordinate_type<mbgl::LatLng> { using type = double; };
+template<> struct coordinate_system<mbgl::LatLng> { using type = boost::geometry::cs::cartesian; };
+
+template<> struct access<mbgl::LatLng, 0> { static inline double get(mbgl::LatLng const& p) { return p.longitude(); } };
+template<> struct access<mbgl::LatLng, 1> { static inline double get(mbgl::LatLng const& p) { return p.latitude(); } };
+
+template<> struct tag<mbgl::LatLngBounds> { using type = box_tag; };
+template<> struct point_type<mbgl::LatLngBounds> { using type = mbgl::LatLng; };
+
+template <size_t D>
+struct indexed_access<mbgl::LatLngBounds, min_corner, D>
+{
+ using ct = coordinate_type<mbgl::LatLng>::type;
+ static inline ct get(mbgl::LatLngBounds const& b) { return geometry::get<D>(b.southwest()); }
+ static inline void set(mbgl::LatLngBounds& b, ct const& value) { geometry::set<D>(b.southwest(), value); }
+};
+
+template <size_t D>
+struct indexed_access<mbgl::LatLngBounds, max_corner, D>
+{
+ using ct = coordinate_type<mbgl::LatLng>::type;
+ static inline ct get(mbgl::LatLngBounds const& b) { return geometry::get<D>(b.northeast()); }
+ static inline void set(mbgl::LatLngBounds& b, ct const& value) { geometry::set<D>(b.northeast(), value); }
+};
+
+} // namespace traits
+
+// Tell Boost Geometry how to access a std::shared_ptr<mbgl::SymbolAnnotation> object.
namespace index {
template <>
@@ -61,6 +91,7 @@ struct indexable<std::shared_ptr<const mbgl::SymbolAnnotationImpl>> {
}
};
-} // end namespace index
-} // end namespace geometry
-} // end namespace boost
+} // namespace index
+
+} // namespace geometry
+} // namespace boost
diff --git a/src/mbgl/geometry/anchor.hpp b/src/mbgl/geometry/anchor.hpp
index 3ed2b23e1b..b24d8d04e0 100644
--- a/src/mbgl/geometry/anchor.hpp
+++ b/src/mbgl/geometry/anchor.hpp
@@ -17,6 +17,6 @@ public:
: point(x_, y_), angle(angle_), scale(scale_), segment(segment_) {}
};
-typedef std::vector<Anchor> Anchors;
+using Anchors = std::vector<Anchor>;
} // namespace mbgl
diff --git a/src/mbgl/geometry/binpack.hpp b/src/mbgl/geometry/binpack.hpp
deleted file mode 100644
index b715cbc2be..0000000000
--- a/src/mbgl/geometry/binpack.hpp
+++ /dev/null
@@ -1,101 +0,0 @@
-#pragma once
-
-#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/util/rect.hpp>
-#include <cstdint>
-#include <list>
-
-namespace mbgl {
-
-template <typename T>
-class BinPack : private util::noncopyable {
-public:
- BinPack(T width, T height)
- : free(1, Rect<uint16_t>{ 0, 0, width, height }) {}
-public:
- Rect<T> allocate(T width, T height) {
- // Find the smallest free rect angle
- auto smallest = free.end();
- for (auto it = free.begin(); it != free.end(); ++it) {
- const Rect<T>& ref = *it;
- const Rect<T>& rect = *smallest;
- if (width <= ref.w && height <= ref.h) {
- if (smallest == free.end() || (ref.y <= rect.y && ref.x <= rect.x)) {
- smallest = it;
- } else {
- // Our current "smallest" rect is already closer to 0/0.
- }
- } else {
- // The rect in the free list is not big enough.
- }
- }
-
- if (smallest == free.end()) {
- // There's no space left for this char.
- return Rect<uint16_t>{ 0, 0, 0, 0 };
- } else {
- Rect<T> rect = *smallest;
- free.erase(smallest);
-
- // Shorter/Longer Axis Split Rule (SAS)
- // http://clb.demon.fi/files/RectangleBinPack.pdf p. 15
- // Ignore the dimension of R and just split long the shorter dimension
- // See Also: http://www.cs.princeton.edu/~chazelle/pubs/blbinpacking.pdf
- if (rect.w < rect.h) {
- // split horizontally
- // +--+---+
- // |__|___| <-- b1
- // +------+ <-- b2
- if (rect.w > width) free.emplace_back(rect.x + width, rect.y, rect.w - width, height);
- if (rect.h > height) free.emplace_back(rect.x, rect.y + height, rect.w, rect.h - height);
- } else {
- // split vertically
- // +--+---+
- // |__| | <-- b1
- // +--|---+ <-- b2
- if (rect.w > width) free.emplace_back(rect.x + width, rect.y, rect.w - width, rect.h);
- if (rect.h > height) free.emplace_back(rect.x, rect.y + height, width, rect.h - height);
- }
-
- return Rect<uint16_t>{ rect.x, rect.y, width, height };
- }
- }
-
-
- void release(Rect<T> rect) {
- // Simple algorithm to recursively merge the newly released cell with its
- // neighbor. This doesn't merge more than two cells at a time, and fails
- // for complicated merges.
- for (auto it = free.begin(); it != free.end(); ++it) {
- Rect<T> ref = *it;
- if (ref.y == rect.y && ref.h == rect.h && ref.x + ref.w == rect.x) {
- ref.w += rect.w;
- }
- else if (ref.x == rect.x && ref.w == rect.w && ref.y + ref.h == rect.y) {
- ref.h += rect.h;
- }
- else if (rect.y == ref.y && rect.h == ref.h && rect.x + rect.w == ref.x) {
- ref.x = rect.x;
- ref.w += rect.w;
- }
- else if (rect.x == ref.x && rect.w == ref.w && rect.y + rect.h == ref.y) {
- ref.y = rect.y;
- ref.h += rect.h;
- } else {
- continue;
- }
-
- free.erase(it);
- release(ref);
- return;
-
- }
-
- free.emplace_back(rect);
- };
-
-private:
- std::list<Rect<T>> free;
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/geometry/feature_index.cpp b/src/mbgl/geometry/feature_index.cpp
index 8251e4d03a..b1594388c4 100644
--- a/src/mbgl/geometry/feature_index.cpp
+++ b/src/mbgl/geometry/feature_index.cpp
@@ -1,7 +1,7 @@
#include <mbgl/geometry/feature_index.hpp>
-#include <mbgl/style/style.hpp>
+#include <mbgl/renderer/render_style.hpp>
#include <mbgl/renderer/render_layer.hpp>
-#include <mbgl/renderer/render_symbol_layer.hpp>
+#include <mbgl/renderer/layers/render_symbol_layer.hpp>
#include <mbgl/text/collision_tile.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/math.hpp>
@@ -54,14 +54,14 @@ static bool topDownSymbols(const IndexedSubfeature& a, const IndexedSubfeature&
}
static int16_t getAdditionalQueryRadius(const RenderedQueryOptions& queryOptions,
- const style::Style& style,
+ const RenderStyle& style,
const GeometryTile& tile,
const float pixelsToTileUnits) {
// Determine the additional radius needed factoring in property functions
float additionalRadius = 0;
auto getQueryRadius = [&](const RenderLayer& layer) {
- auto bucket = tile.getBucket(layer);
+ auto bucket = tile.getBucket(*layer.baseImpl);
if (bucket) {
additionalRadius = std::max(additionalRadius, bucket->getQueryRadius(layer) * pixelsToTileUnits);
}
@@ -69,7 +69,7 @@ static int16_t getAdditionalQueryRadius(const RenderedQueryOptions& queryOptions
if (queryOptions.layerIDs) {
for (const auto& layerID : *queryOptions.layerIDs) {
- RenderLayer* layer = style.getRenderLayer(layerID);
+ const RenderLayer* layer = style.getRenderLayer(layerID);
if (layer) {
getQueryRadius(*layer);
}
@@ -92,7 +92,7 @@ void FeatureIndex::query(
const RenderedQueryOptions& queryOptions,
const GeometryTileData& geometryTileData,
const CanonicalTileID& tileID,
- const style::Style& style,
+ const RenderStyle& style,
const CollisionTile* collisionTile,
const GeometryTile& tile) const {
@@ -135,7 +135,7 @@ void FeatureIndex::addFeature(
const RenderedQueryOptions& options,
const GeometryTileData& geometryTileData,
const CanonicalTileID& tileID,
- const style::Style& style,
+ const RenderStyle& style,
const float bearing,
const float pixelsToTileUnits) const {
diff --git a/src/mbgl/geometry/feature_index.hpp b/src/mbgl/geometry/feature_index.hpp
index f7aa0182e4..83f339a9de 100644
--- a/src/mbgl/geometry/feature_index.hpp
+++ b/src/mbgl/geometry/feature_index.hpp
@@ -13,10 +13,7 @@ namespace mbgl {
class GeometryTile;
class RenderedQueryOptions;
-
-namespace style {
-class Style;
-} // namespace style
+class RenderStyle;
class CollisionTile;
class CanonicalTileID;
@@ -45,7 +42,7 @@ public:
const RenderedQueryOptions& options,
const GeometryTileData&,
const CanonicalTileID&,
- const style::Style&,
+ const RenderStyle&,
const CollisionTile*,
const GeometryTile& tile) const;
@@ -66,7 +63,7 @@ private:
const RenderedQueryOptions& options,
const GeometryTileData&,
const CanonicalTileID&,
- const style::Style&,
+ const RenderStyle&,
const float bearing,
const float pixelsToTileUnits) const;
diff --git a/src/mbgl/gl/attribute.cpp b/src/mbgl/gl/attribute.cpp
index 8c52121f6e..4e6f78e689 100644
--- a/src/mbgl/gl/attribute.cpp
+++ b/src/mbgl/gl/attribute.cpp
@@ -2,14 +2,59 @@
#include <mbgl/gl/context.hpp>
#include <mbgl/gl/gl.hpp>
+#include <cstring>
+
namespace mbgl {
namespace gl {
AttributeLocation bindAttributeLocation(ProgramID id, AttributeLocation location, const char* name) {
+ assert(location < 8);
MBGL_CHECK_ERROR(glBindAttribLocation(id, location, name));
return location;
}
+int32_t getActiveAttributeCount(ProgramID id) {
+ GLint numAttributes;
+ MBGL_CHECK_ERROR(glGetProgramiv(id, GL_ACTIVE_ATTRIBUTES, &numAttributes));
+ return numAttributes;
+}
+
+int32_t getMaxAttributeNameLength(ProgramID id) {
+ GLint nameLength;
+ MBGL_CHECK_ERROR(glGetProgramiv(id, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &nameLength));
+ return nameLength;
+}
+
+std::string getAttributeName(ProgramID id, int32_t maxLength, AttributeLocation location) {
+ std::string attributeName;
+ attributeName.resize(maxLength);
+ GLsizei actualLength;
+ GLint size;
+ GLenum type;
+ MBGL_CHECK_ERROR(glGetActiveAttrib(id, static_cast<GLuint>(location),
+ static_cast<GLsizei>(maxLength), &actualLength, &size, &type,
+ const_cast<char*>(attributeName.data())));
+ attributeName.resize(actualLength);
+ return attributeName;
+}
+
+std::set<std::string> getActiveAttributes(ProgramID id) {
+ std::set<std::string> activeAttributes;
+
+ GLint attributeCount = getActiveAttributeCount(id);
+ GLint maxAttributeLength = getMaxAttributeNameLength(id);
+
+ for (int32_t i = 0; i < attributeCount; i++) {
+ activeAttributes.emplace(getAttributeName(id, maxAttributeLength, i));
+ }
+
+ return activeAttributes;
+}
+
+void DisabledAttribute::bind(Context&, AttributeLocation location, std::size_t) const {
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+}
+
template <class T> DataType DataTypeOf = static_cast<DataType>(0);
template <> DataType DataTypeOf< int8_t> = DataType::Byte;
template <> DataType DataTypeOf<uint8_t> = DataType::UnsignedByte;
@@ -20,16 +65,14 @@ template <> DataType DataTypeOf<uint32_t> = DataType::UnsignedInteger;
template <> DataType DataTypeOf<float> = DataType::Float;
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;
- }
+void AttributeBinding<T, N>::bind(Context& context, AttributeLocation location, std::size_t vertexOffset) const {
+ // FillProgram will attempt to bind at location -1 because it includes
+ // a fill-outline-color paint property but does not use it or have an
+ // a_outline_color shader attribute - in this case, we have nothing to bind.
+ if (location == -1) return;
+
context.vertexBuffer = vertexBuffer;
MBGL_CHECK_ERROR(glEnableVertexAttribArray(location));
- oldBinding = *this;
MBGL_CHECK_ERROR(glVertexAttribPointer(
location,
static_cast<GLint>(attributeSize),
@@ -39,156 +82,25 @@ void VariableAttributeBinding<T, N>::bind(Context& context,
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<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 class AttributeBinding<uint8_t, 1>;
+template class AttributeBinding<uint8_t, 2>;
+template class AttributeBinding<uint8_t, 3>;
+template class AttributeBinding<uint8_t, 4>;
+template class AttributeBinding<uint16_t, 1>;
+template class AttributeBinding<uint16_t, 2>;
+template class AttributeBinding<uint16_t, 3>;
+template class AttributeBinding<uint16_t, 4>;
-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 class AttributeBinding<int16_t, 1>;
+template class AttributeBinding<int16_t, 2>;
+template class AttributeBinding<int16_t, 3>;
+template class AttributeBinding<int16_t, 4>;
-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]));
-}
+template class AttributeBinding<float, 1>;
+template class AttributeBinding<float, 2>;
+template class AttributeBinding<float, 3>;
+template class AttributeBinding<float, 4>;
} // namespace gl
} // namespace mbgl
diff --git a/src/mbgl/gl/attribute.hpp b/src/mbgl/gl/attribute.hpp
index d5e8edfc70..f018a1d261 100644
--- a/src/mbgl/gl/attribute.hpp
+++ b/src/mbgl/gl/attribute.hpp
@@ -8,28 +8,39 @@
#include <cstddef>
#include <vector>
+#include <set>
#include <functional>
namespace mbgl {
namespace gl {
+class DisabledAttribute {
+public:
+ void bind(Context&, AttributeLocation, std::size_t vertexOffset) const;
+
+ friend bool operator==(const DisabledAttribute&,
+ const DisabledAttribute&) {
+ return true;
+ }
+};
+
template <class T, std::size_t N>
-class VariableAttributeBinding {
+class AttributeBinding {
public:
- VariableAttributeBinding(BufferID vertexBuffer_,
- std::size_t vertexSize_,
- std::size_t attributeOffset_,
- std::size_t attributeSize_ = N)
+ AttributeBinding(BufferID vertexBuffer_,
+ std::size_t vertexSize_,
+ std::size_t attributeOffset_,
+ std::size_t attributeSize_ = N)
: vertexBuffer(vertexBuffer_),
vertexSize(vertexSize_),
attributeOffset(attributeOffset_),
attributeSize(attributeSize_)
{}
- void bind(Context&, AttributeLocation, optional<VariableAttributeBinding<T, N>>&, std::size_t vertexOffset) const;
+ void bind(Context&, AttributeLocation, std::size_t vertexOffset) const;
- friend bool operator==(const VariableAttributeBinding& lhs,
- const VariableAttributeBinding& rhs) {
+ friend bool operator==(const AttributeBinding& lhs,
+ const AttributeBinding& rhs) {
return lhs.vertexBuffer == rhs.vertexBuffer
&& lhs.vertexSize == rhs.vertexSize
&& lhs.attributeOffset == rhs.attributeOffset
@@ -43,28 +54,8 @@ private:
std::size_t attributeSize;
};
-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;
-};
-
/*
- gl::Attribute<T,N> manages the binding of a constant value or vertex buffer to a GL program attribute.
+ gl::Attribute<T,N> manages the binding of a vertex buffer to a GL program attribute.
- T is the underlying primitive type (exposed as Attribute<T,N>::ValueType)
- N is the number of components in the attribute declared in the shader (exposed as Attribute<T,N>::Dimensions)
*/
@@ -75,27 +66,23 @@ public:
static constexpr size_t Dimensions = N;
using Value = std::array<T, N>;
- using VariableBinding = VariableAttributeBinding<T, N>;
- using ConstantBinding = ConstantAttributeBinding<T, N>;
-
using Location = AttributeLocation;
using Binding = variant<
- ConstantBinding,
- VariableBinding>;
+ DisabledAttribute,
+ AttributeBinding<T, N>>;
/*
- Create a variable (i.e. data-driven) binding for this attribute. The `attributeSize`
- parameter may be used to override the number of components available in the buffer for
- each vertex. Thus, a buffer with only one float for each vertex can be bound to a
- `vec2` attribute
+ Create a binding for this attribute. The `attributeSize` parameter may be used to
+ override the number of components available in the buffer for each vertex. Thus,
+ a buffer with only one float for each vertex can be bound to a `vec2` attribute
*/
template <class Vertex, class DrawMode>
- static VariableBinding variableBinding(const VertexBuffer<Vertex, DrawMode>& buffer,
- std::size_t attributeIndex,
- std::size_t attributeSize = N) {
+ static Binding binding(const VertexBuffer<Vertex, DrawMode>& buffer,
+ std::size_t attributeIndex,
+ std::size_t attributeSize = N) {
static_assert(std::is_standard_layout<Vertex>::value, "vertex type must use standard layout");
- return VariableBinding {
+ return AttributeBinding<T, N> {
buffer.buffer,
sizeof(Vertex),
Vertex::attributeOffsets[attributeIndex],
@@ -105,12 +92,18 @@ public:
static void bind(Context& context,
const Location& location,
- optional<VariableBinding>& oldBinding,
+ Binding& oldBinding,
const Binding& newBinding,
std::size_t vertexOffset) {
+ if (oldBinding == newBinding) {
+ return;
+ }
+
Binding::visit(newBinding, [&] (const auto& binding) {
- binding.bind(context, location, oldBinding, vertexOffset);
+ binding.bind(context, location, vertexOffset);
});
+
+ oldBinding = newBinding;
}
};
@@ -231,6 +224,7 @@ const std::size_t Vertex<A1, A2, A3, A4, A5>::attributeOffsets[5] = {
} // namespace detail
AttributeLocation bindAttributeLocation(ProgramID, AttributeLocation, const char * name);
+std::set<std::string> getActiveAttributes(ProgramID);
template <class... As>
class Attributes {
@@ -242,9 +236,6 @@ public:
using Bindings = IndexedTuple<
TypeList<As...>,
TypeList<typename As::Type::Binding...>>;
- using VariableBindings = IndexedTuple<
- TypeList<As...>,
- TypeList<optional<typename As::Type::VariableBinding>...>>;
using NamedLocations = std::vector<std::pair<const std::string, AttributeLocation>>;
using Vertex = detail::Vertex<typename As::Type...>;
@@ -253,7 +244,15 @@ public:
static constexpr std::size_t Index = TypeIndex<A, As...>::value;
static Locations bindLocations(const ProgramID& id) {
- return Locations { bindAttributeLocation(id, Index<As>, As::name())... };
+ std::set<std::string> activeAttributes = getActiveAttributes(id);
+
+ AttributeLocation location = -1;
+ auto bindAndIncrement = [&](const char* name) {
+ location++;
+ return bindAttributeLocation(id, location, name);
+ };
+ return Locations{ (activeAttributes.count(As::name()) ? bindAndIncrement(As::name())
+ : -1)... };
}
template <class Program>
@@ -266,13 +265,13 @@ public:
}
template <class DrawMode>
- static Bindings allVariableBindings(const VertexBuffer<Vertex, DrawMode>& buffer) {
- return Bindings { As::Type::variableBinding(buffer, Index<As>)... };
+ static Bindings bindings(const VertexBuffer<Vertex, DrawMode>& buffer) {
+ return Bindings { As::Type::binding(buffer, Index<As>)... };
}
static void bind(Context& context,
const Locations& locations,
- VariableBindings& oldBindings,
+ Bindings& oldBindings,
const Bindings& newBindings,
std::size_t vertexOffset) {
util::ignore({ (As::Type::bind(context,
diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp
index 3ab1260d27..1b4d6fbcb7 100644
--- a/src/mbgl/gl/context.cpp
+++ b/src/mbgl/gl/context.cpp
@@ -45,7 +45,7 @@ Context::~Context() {
}
void Context::initializeExtensions(const std::function<gl::ProcAddress(const char*)>& getProcAddress) {
- if (const char* extensions =
+ if (const auto* extensions =
reinterpret_cast<const char*>(MBGL_CHECK_ERROR(glGetString(GL_EXTENSIONS)))) {
auto fn = [&](
@@ -94,7 +94,7 @@ UniqueShader Context::createShader(ShaderType type, const std::string& source) {
UniqueShader result { MBGL_CHECK_ERROR(glCreateShader(static_cast<GLenum>(type))), { this } };
const GLchar* sources = source.data();
- const GLsizei lengths = static_cast<GLsizei>(source.length());
+ const auto lengths = static_cast<GLsizei>(source.length());
MBGL_CHECK_ERROR(glShaderSource(result, 1, &sources, &lengths));
MBGL_CHECK_ERROR(glCompileShader(result));
@@ -258,11 +258,9 @@ std::unique_ptr<uint8_t[]> Context::readFramebuffer(const Size size, const Textu
const size_t stride = size.width * (format == TextureFormat::RGBA ? 4 : 1);
auto data = std::make_unique<uint8_t[]>(stride * size.height);
-#if not MBGL_USE_GLES2
// When reading data from the framebuffer, make sure that we are storing the values
// tightly packed into the buffer to avoid buffer overruns.
pixelStorePack = { 1 };
-#endif // MBGL_USE_GLES2
MBGL_CHECK_ERROR(glReadPixels(0, 0, size.width, size.height, static_cast<GLenum>(format),
GL_UNSIGNED_BYTE, data.get()));
@@ -399,6 +397,7 @@ Context::createFramebuffer(const Texture& color,
UniqueTexture
Context::createTexture(const Size size, const void* data, TextureFormat format, TextureUnit unit) {
auto obj = createTexture();
+ pixelStoreUnpack = { 1 };
updateTexture(obj, size, data, format, unit);
// We are using clamp to edge here since OpenGL ES doesn't allow GL_REPEAT on NPOT textures.
// We use those when the pixelRatio isn't a power of two, e.g. on iPhone 6 Plus.
@@ -468,8 +467,8 @@ void Context::reset() {
}
void Context::setDirtyState() {
- // Note: does not set viewport/bindFramebuffer to dirty since they are handled separately in
- // the view object.
+ // Note: does not set viewport/scissorTest/bindFramebuffer to dirty
+ // since they are handled separately in the view object.
stencilFunc.setDirty();
stencilMask.setDirty();
stencilTest.setDirty();
@@ -489,12 +488,12 @@ void Context::setDirtyState() {
program.setDirty();
lineWidth.setDirty();
activeTexture.setDirty();
+ pixelStorePack.setDirty();
+ pixelStoreUnpack.setDirty();
#if not MBGL_USE_GLES2
pointSize.setDirty();
pixelZoom.setDirty();
rasterPos.setDirty();
- pixelStorePack.setDirty();
- pixelStoreUnpack.setDirty();
pixelTransferDepth.setDirty();
pixelTransferStencil.setDirty();
#endif // MBGL_USE_GLES2
diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp
index 56c0618989..4f5b4c797c 100644
--- a/src/mbgl/gl/context.hpp
+++ b/src/mbgl/gl/context.hpp
@@ -199,17 +199,19 @@ public:
State<value::ActiveTexture> activeTexture;
State<value::BindFramebuffer> bindFramebuffer;
State<value::Viewport> viewport;
+ State<value::ScissorTest> scissorTest;
std::array<State<value::BindTexture>, 2> texture;
State<value::BindVertexArray, const Context&> vertexArrayObject { *this };
State<value::Program> program;
State<value::BindVertexBuffer> vertexBuffer;
State<value::BindElementBuffer> elementBuffer;
+ State<value::PixelStorePack> pixelStorePack;
+ State<value::PixelStoreUnpack> pixelStoreUnpack;
+
#if not MBGL_USE_GLES2
State<value::PixelZoom> pixelZoom;
State<value::RasterPos> rasterPos;
- State<value::PixelStorePack> pixelStorePack;
- State<value::PixelStoreUnpack> pixelStoreUnpack;
State<value::PixelTransferDepth> pixelTransferDepth;
State<value::PixelTransferStencil> pixelTransferStencil;
#endif // MBGL_USE_GLES2
diff --git a/src/mbgl/gl/debugging.cpp b/src/mbgl/gl/debugging.cpp
index 0d69d58be5..366b4d63c7 100644
--- a/src/mbgl/gl/debugging.cpp
+++ b/src/mbgl/gl/debugging.cpp
@@ -10,9 +10,9 @@ namespace gl {
DebugGroup::DebugGroup(const Context& context_, const std::string& name) : context(context_) {
if (auto debugging = context.getDebuggingExtension()) {
if (debugging->pushDebugGroup) {
- debugging->pushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, GLsizei(name.size()), name.c_str());
+ MBGL_CHECK_ERROR(debugging->pushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, GLsizei(name.size()), name.c_str()));
} else if (debugging->pushGroupMarkerEXT) {
- debugging->pushGroupMarkerEXT(GLsizei(name.size() + 1), name.c_str());
+ MBGL_CHECK_ERROR(debugging->pushGroupMarkerEXT(GLsizei(name.size() + 1), name.c_str()));
}
}
}
@@ -20,9 +20,9 @@ DebugGroup::DebugGroup(const Context& context_, const std::string& name) : conte
DebugGroup::~DebugGroup() {
if (auto debugging = context.getDebuggingExtension()) {
if (debugging->popDebugGroup) {
- debugging->popDebugGroup();
+ MBGL_CHECK_ERROR(debugging->popDebugGroup());
} else if (debugging->popGroupMarkerEXT) {
- debugging->popGroupMarkerEXT();
+ MBGL_CHECK_ERROR(debugging->popGroupMarkerEXT());
}
}
}
diff --git a/src/mbgl/gl/debugging_extension.hpp b/src/mbgl/gl/debugging_extension.hpp
index c1835cfcdd..5657bbde88 100644
--- a/src/mbgl/gl/debugging_extension.hpp
+++ b/src/mbgl/gl/debugging_extension.hpp
@@ -53,13 +53,13 @@ namespace extension {
class Debugging {
public:
- typedef void (*Callback)(GLenum source,
- GLenum type,
- GLuint id,
- GLenum severity,
- GLsizei length,
- const GLchar* message,
- const void* userParam);
+ using Callback = void (*)(GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ GLsizei length,
+ const GLchar* message,
+ const void* userParam);
static void DebugCallback(GLenum source,
GLenum type,
diff --git a/src/mbgl/gl/index_buffer.hpp b/src/mbgl/gl/index_buffer.hpp
index b3610f4154..1e57fb11f2 100644
--- a/src/mbgl/gl/index_buffer.hpp
+++ b/src/mbgl/gl/index_buffer.hpp
@@ -24,6 +24,7 @@ public:
std::size_t byteSize() const { return v.size() * sizeof(uint16_t); }
bool empty() const { return v.empty(); }
+ void clear() { v.clear(); }
const uint16_t* data() const { return v.data(); }
private:
diff --git a/src/mbgl/gl/program.hpp b/src/mbgl/gl/program.hpp
index 47ad39de7c..583d53e4ec 100644
--- a/src/mbgl/gl/program.hpp
+++ b/src/mbgl/gl/program.hpp
@@ -33,15 +33,17 @@ public:
: program(
context.createProgram(context.createShader(ShaderType::Vertex, vertexSource),
context.createShader(ShaderType::Fragment, fragmentSource))),
- attributeLocations(Attributes::bindLocations(program)),
- uniformsState((context.linkProgram(program), Uniforms::bindLocations(program))) {
+ uniformsState((context.linkProgram(program), Uniforms::bindLocations(program))),
+ attributeLocations(Attributes::bindLocations(program)) {
+ // Re-link program after manually binding only active attributes in Attributes::bindLocations
+ context.linkProgram(program);
}
template <class BinaryProgram>
Program(Context& context, const BinaryProgram& binaryProgram)
: program(context.createProgram(binaryProgram.format(), binaryProgram.code())),
- attributeLocations(Attributes::loadNamedLocations(binaryProgram)),
- uniformsState(Uniforms::loadNamedLocations(binaryProgram)) {
+ uniformsState(Uniforms::loadNamedLocations(binaryProgram)),
+ attributeLocations(Attributes::loadNamedLocations(binaryProgram)) {
}
static Program createProgram(gl::Context& context,
@@ -144,8 +146,8 @@ public:
private:
UniqueProgram program;
- typename Attributes::Locations attributeLocations;
typename Uniforms::State uniformsState;
+ typename Attributes::Locations attributeLocations;
};
} // namespace gl
diff --git a/src/mbgl/gl/segment.hpp b/src/mbgl/gl/segment.hpp
index 45c81973f2..fe0658bf8e 100644
--- a/src/mbgl/gl/segment.hpp
+++ b/src/mbgl/gl/segment.hpp
@@ -47,12 +47,12 @@ public:
} else {
// No VAO support. Force attributes to be rebound.
context.elementBuffer = indexBuffer_;
- variableBindings = {};
+ attributeBindings = {};
}
Attributes::bind(context,
attributeLocations,
- variableBindings,
+ attributeBindings,
attributeBindings_,
vertexOffset);
}
@@ -60,7 +60,7 @@ public:
private:
mutable optional<UniqueVertexArray> vao;
mutable optional<BufferID> indexBuffer;
- mutable typename Attributes::VariableBindings variableBindings;
+ mutable typename Attributes::Bindings attributeBindings;
};
template <class Attributes>
diff --git a/src/mbgl/gl/types.hpp b/src/mbgl/gl/types.hpp
index 0595419674..74ce67fba6 100644
--- a/src/mbgl/gl/types.hpp
+++ b/src/mbgl/gl/types.hpp
@@ -66,8 +66,6 @@ enum class PrimitiveType {
TriangleFan = 0x0006
};
-#if not MBGL_USE_GLES2
-
struct PixelStorageType {
int32_t alignment;
};
@@ -76,9 +74,27 @@ constexpr bool operator!=(const PixelStorageType& a, const PixelStorageType& b)
return a.alignment != b.alignment;
}
-#endif // MBGL_USE_GLES2
-
using BinaryProgramFormat = uint32_t;
+enum class UniformDataType : uint32_t {
+ Float = 0x1406,
+ FloatVec2 = 0x8B50,
+ FloatVec3 = 0x8B51,
+ FloatVec4 = 0x8B52,
+ Int = 0x1404,
+ IntVec2 = 0x8B53,
+ IntVec3 = 0x8B54,
+ IntVec4 = 0x8B55,
+ Bool = 0x8B56,
+ BoolVec2 = 0x8B57,
+ BoolVec3 = 0x8B58,
+ BoolVec4 = 0x8B59,
+ FloatMat2 = 0x8B5A,
+ FloatMat3 = 0x8B5B,
+ FloatMat4 = 0x8B5C,
+ Sampler2D = 0x8B5E,
+ SamplerCube = 0x8B60,
+};
+
} // namespace gl
} // namespace mbgl
diff --git a/src/mbgl/gl/uniform.cpp b/src/mbgl/gl/uniform.cpp
index 7b674f2cde..2946980c19 100644
--- a/src/mbgl/gl/uniform.cpp
+++ b/src/mbgl/gl/uniform.cpp
@@ -4,6 +4,8 @@
#include <mbgl/util/size.hpp>
#include <mbgl/util/convert.hpp>
+#include <memory>
+
namespace mbgl {
namespace gl {
@@ -79,5 +81,96 @@ void bindUniform<std::array<uint16_t, 2>>(UniformLocation location, const std::a
// Add more as needed.
+#ifndef NDEBUG
+
+ActiveUniforms activeUniforms(ProgramID id) {
+ ActiveUniforms active;
+
+ GLint count;
+ GLint maxLength;
+ MBGL_CHECK_ERROR(glGetProgramiv(id, GL_ACTIVE_UNIFORMS, &count));
+ MBGL_CHECK_ERROR(glGetProgramiv(id, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength));
+
+ auto name = std::make_unique<GLchar[]>(maxLength);
+ GLsizei length;
+ GLint size;
+ GLenum type;
+ for (GLint index = 0; index < count; index++) {
+ MBGL_CHECK_ERROR(
+ glGetActiveUniform(id, index, maxLength, &length, &size, &type, name.get()));
+ active.emplace(
+ std::string{ name.get(), static_cast<size_t>(length) },
+ ActiveUniform{ static_cast<size_t>(size), static_cast<UniformDataType>(type) });
+ }
+
+ return active;
+}
+
+template <>
+bool verifyUniform<float>(const ActiveUniform& uniform) {
+ assert(uniform.size == 1 && uniform.type == UniformDataType::Float);
+ return true;
+}
+
+template <>
+bool verifyUniform<std::array<float, 2>>(const ActiveUniform& uniform) {
+ assert(uniform.size == 1 && uniform.type == UniformDataType::FloatVec2);
+ return true;
+}
+
+template <>
+bool verifyUniform<std::array<float, 3>>(const ActiveUniform& uniform) {
+ assert(uniform.size == 1 && uniform.type == UniformDataType::FloatVec3);
+ return true;
+}
+
+template <>
+bool verifyUniform<std::array<double, 16>>(const ActiveUniform& uniform) {
+ assert(uniform.size == 1 && uniform.type == UniformDataType::FloatMat4);
+ return true;
+}
+
+template <>
+bool verifyUniform<bool>(const ActiveUniform& uniform) {
+ assert(uniform.size == 1 &&
+ (uniform.type == UniformDataType::Bool ||
+ uniform.type == UniformDataType::Int ||
+ uniform.type == UniformDataType::Float));
+ return true;
+}
+
+template <>
+bool verifyUniform<uint8_t>(const ActiveUniform& uniform) {
+ assert(uniform.size == 1 &&
+ (uniform.type == UniformDataType::Int ||
+ uniform.type == UniformDataType::Float ||
+ uniform.type == UniformDataType::Sampler2D));
+ return true;
+}
+
+template <>
+bool verifyUniform<Color>(const ActiveUniform& uniform) {
+ assert(uniform.size == 1 && uniform.type == UniformDataType::FloatVec4);
+ return true;
+}
+
+template <>
+bool verifyUniform<Size>(const ActiveUniform& uniform) {
+ assert(uniform.size == 1 && uniform.type == UniformDataType::FloatVec2);
+ return true;
+}
+
+template <>
+bool verifyUniform<std::array<uint16_t, 2>>(const ActiveUniform& uniform) {
+ assert(uniform.size == 1 &&
+ (uniform.type == UniformDataType::IntVec2 ||
+ uniform.type == UniformDataType::FloatVec2));
+ return true;
+}
+
+// Add more as needed.
+
+#endif
+
} // namespace gl
} // namespace mbgl
diff --git a/src/mbgl/gl/uniform.hpp b/src/mbgl/gl/uniform.hpp
index bb3453b2d8..829192bcca 100644
--- a/src/mbgl/gl/uniform.hpp
+++ b/src/mbgl/gl/uniform.hpp
@@ -7,6 +7,7 @@
#include <array>
#include <vector>
+#include <map>
#include <functional>
namespace mbgl {
@@ -22,11 +23,29 @@ public:
T t;
};
+class ActiveUniform {
+public:
+ std::size_t size;
+ UniformDataType type;
+};
+
+#ifndef NDEBUG
+
+template <class T>
+bool verifyUniform(const ActiveUniform&);
+
+using ActiveUniforms = std::map<std::string, ActiveUniform>;
+ActiveUniforms activeUniforms(ProgramID);
+
+#endif
+
template <class Tag, class T>
class Uniform {
public:
using Value = UniformValue<Tag, T>;
+ using Type = T;
+
class State {
public:
void operator=(const Value& value) {
@@ -70,6 +89,18 @@ public:
using NamedLocations = std::vector<std::pair<const std::string, UniformLocation>>;
static State bindLocations(const ProgramID& id) {
+#ifndef NDEBUG
+ // Verify active uniform types match the enum
+ const auto active = activeUniforms(id);
+
+ util::ignore(
+ { // Some shader programs have uniforms declared, but not used, so they're not active.
+ // Therefore, we'll only verify them when they are indeed active.
+ (active.find(Us::name()) != active.end()
+ ? verifyUniform<typename Us::Type>(active.at(Us::name()))
+ : false)... });
+#endif
+
return State { { uniformLocation(id, Us::name()) }... };
}
diff --git a/src/mbgl/gl/value.cpp b/src/mbgl/gl/value.cpp
index c081c941f5..2b825fb2bd 100644
--- a/src/mbgl/gl/value.cpp
+++ b/src/mbgl/gl/value.cpp
@@ -267,6 +267,18 @@ Viewport::Type Viewport::Get() {
{ static_cast<uint32_t>(viewport[2]), static_cast<uint32_t>(viewport[3]) } };
}
+const constexpr ScissorTest::Type ScissorTest::Default;
+
+void ScissorTest::Set(const Type& value) {
+ MBGL_CHECK_ERROR(value ? glEnable(GL_SCISSOR_TEST) : glDisable(GL_SCISSOR_TEST));
+}
+
+ScissorTest::Type ScissorTest::Get() {
+ Type scissorTest;
+ MBGL_CHECK_ERROR(scissorTest = glIsEnabled(GL_SCISSOR_TEST));
+ return scissorTest;
+}
+
const constexpr BindFramebuffer::Type BindFramebuffer::Default;
void BindFramebuffer::Set(const Type& value) {
@@ -353,6 +365,34 @@ BindVertexArray::Type BindVertexArray::Get(const Context& context) {
return binding;
}
+const constexpr PixelStorePack::Type PixelStorePack::Default;
+
+void PixelStorePack::Set(const Type& value) {
+ assert(value.alignment == 1 || value.alignment == 2 || value.alignment == 4 ||
+ value.alignment == 8);
+ MBGL_CHECK_ERROR(glPixelStorei(GL_PACK_ALIGNMENT, value.alignment));
+}
+
+PixelStorePack::Type PixelStorePack::Get() {
+ Type value;
+ MBGL_CHECK_ERROR(glGetIntegerv(GL_PACK_ALIGNMENT, &value.alignment));
+ return value;
+}
+
+const constexpr PixelStoreUnpack::Type PixelStoreUnpack::Default;
+
+void PixelStoreUnpack::Set(const Type& value) {
+ assert(value.alignment == 1 || value.alignment == 2 || value.alignment == 4 ||
+ value.alignment == 8);
+ MBGL_CHECK_ERROR(glPixelStorei(GL_UNPACK_ALIGNMENT, value.alignment));
+}
+
+PixelStoreUnpack::Type PixelStoreUnpack::Get() {
+ Type value;
+ MBGL_CHECK_ERROR(glGetIntegerv(GL_UNPACK_ALIGNMENT, &value.alignment));
+ return value;
+}
+
#if not MBGL_USE_GLES2
const constexpr PointSize::Type PointSize::Default;
@@ -392,34 +432,6 @@ RasterPos::Type RasterPos::Get() {
return { pos[0], pos[1], pos[2], pos[3] };
}
-const constexpr PixelStorePack::Type PixelStorePack::Default;
-
-void PixelStorePack::Set(const Type& value) {
- assert(value.alignment == 1 || value.alignment == 2 || value.alignment == 4 ||
- value.alignment == 8);
- MBGL_CHECK_ERROR(glPixelStorei(GL_PACK_ALIGNMENT, value.alignment));
-}
-
-PixelStorePack::Type PixelStorePack::Get() {
- Type value;
- MBGL_CHECK_ERROR(glGetIntegerv(GL_PACK_ALIGNMENT, &value.alignment));
- return value;
-}
-
-const constexpr PixelStoreUnpack::Type PixelStoreUnpack::Default;
-
-void PixelStoreUnpack::Set(const Type& value) {
- assert(value.alignment == 1 || value.alignment == 2 || value.alignment == 4 ||
- value.alignment == 8);
- MBGL_CHECK_ERROR(glPixelStorei(GL_UNPACK_ALIGNMENT, value.alignment));
-}
-
-PixelStoreUnpack::Type PixelStoreUnpack::Get() {
- Type value;
- MBGL_CHECK_ERROR(glGetIntegerv(GL_UNPACK_ALIGNMENT, &value.alignment));
- return value;
-}
-
const constexpr PixelTransferDepth::Type PixelTransferDepth::Default;
void PixelTransferDepth::Set(const Type& value) {
diff --git a/src/mbgl/gl/value.hpp b/src/mbgl/gl/value.hpp
index aa5cca6fec..d4c7b5cdc3 100644
--- a/src/mbgl/gl/value.hpp
+++ b/src/mbgl/gl/value.hpp
@@ -182,6 +182,13 @@ struct Viewport {
static Type Get();
};
+struct ScissorTest {
+ using Type = bool;
+ static const constexpr Type Default = false;
+ static void Set(const Type&);
+ static Type Get();
+};
+
constexpr bool operator!=(const Viewport::Type& a, const Viewport::Type& b) {
return a.x != b.x || a.y != b.y || a.size != b.size;
}
@@ -232,6 +239,20 @@ struct BindVertexArray {
static Type Get(const Context&);
};
+struct PixelStorePack {
+ using Type = PixelStorageType;
+ static const constexpr Type Default = { 4 };
+ static void Set(const Type&);
+ static Type Get();
+};
+
+struct PixelStoreUnpack {
+ using Type = PixelStorageType;
+ static const constexpr Type Default = { 4 };
+ static void Set(const Type&);
+ static Type Get();
+};
+
#if not MBGL_USE_GLES2
struct PointSize {
@@ -271,20 +292,6 @@ constexpr bool operator!=(const RasterPos::Type& a, const RasterPos::Type& b) {
return a.x != b.x || a.y != b.y || a.z != b.z || a.w != b.w;
}
-struct PixelStorePack {
- using Type = PixelStorageType;
- static const constexpr Type Default = { 4 };
- static void Set(const Type&);
- static Type Get();
-};
-
-struct PixelStoreUnpack {
- using Type = PixelStorageType;
- static const constexpr Type Default = { 4 };
- static void Set(const Type&);
- static Type Get();
-};
-
struct PixelTransferDepth {
struct Type {
float scale;
diff --git a/src/mbgl/gl/vertex_buffer.hpp b/src/mbgl/gl/vertex_buffer.hpp
index c9bc01f3e8..4808803d00 100644
--- a/src/mbgl/gl/vertex_buffer.hpp
+++ b/src/mbgl/gl/vertex_buffer.hpp
@@ -26,6 +26,7 @@ public:
std::size_t byteSize() const { return v.size() * sizeof(Vertex); }
bool empty() const { return v.empty(); }
+ void clear() { v.clear(); }
const Vertex* data() const { return v.data(); }
private:
diff --git a/src/mbgl/layout/symbol_instance.cpp b/src/mbgl/layout/symbol_instance.cpp
index 8816f4c95c..ffb70c7ca2 100644
--- a/src/mbgl/layout/symbol_instance.cpp
+++ b/src/mbgl/layout/symbol_instance.cpp
@@ -19,7 +19,7 @@ SymbolInstance::SymbolInstance(Anchor& anchor,
const float iconBoxScale,
const float iconPadding,
const SymbolPlacementType iconPlacement,
- const GlyphPositions& face,
+ const GlyphPositionMap& positions,
const IndexedSubfeature& indexedFeature,
const std::size_t featureIndex_) :
point(anchor.point),
@@ -38,11 +38,11 @@ SymbolInstance::SymbolInstance(Anchor& anchor,
iconQuad = getIconQuad(anchor, *shapedIcon, line, layout, layoutTextSize, iconPlacement, shapedTextOrientations.first);
}
if (shapedTextOrientations.first) {
- auto quads = getGlyphQuads(anchor, shapedTextOrientations.first, textBoxScale, line, layout, textPlacement, face);
+ auto quads = getGlyphQuads(anchor, shapedTextOrientations.first, textBoxScale, line, layout, textPlacement, positions);
glyphQuads.insert(glyphQuads.end(), quads.begin(), quads.end());
}
if (shapedTextOrientations.second) {
- auto quads = getGlyphQuads(anchor, shapedTextOrientations.second, textBoxScale, line, layout, textPlacement, face);
+ auto quads = getGlyphQuads(anchor, shapedTextOrientations.second, textBoxScale, line, layout, textPlacement, positions);
glyphQuads.insert(glyphQuads.end(), quads.begin(), quads.end());
}
}
diff --git a/src/mbgl/layout/symbol_instance.hpp b/src/mbgl/layout/symbol_instance.hpp
index eadbf67475..f199d929df 100644
--- a/src/mbgl/layout/symbol_instance.hpp
+++ b/src/mbgl/layout/symbol_instance.hpp
@@ -1,7 +1,7 @@
#pragma once
#include <mbgl/text/quads.hpp>
-#include <mbgl/text/glyph.hpp>
+#include <mbgl/text/glyph_atlas.hpp>
#include <mbgl/text/collision_feature.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
@@ -26,7 +26,7 @@ public:
const float iconBoxScale,
const float iconPadding,
style::SymbolPlacementType iconPlacement,
- const GlyphPositions& face,
+ const GlyphPositionMap&,
const IndexedSubfeature&,
const std::size_t featureIndex);
diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp
index 2accac281b..adc7eaaed8 100644
--- a/src/mbgl/layout/symbol_layout.cpp
+++ b/src/mbgl/layout/symbol_layout.cpp
@@ -1,12 +1,12 @@
#include <mbgl/layout/symbol_layout.hpp>
#include <mbgl/layout/merge_lines.hpp>
#include <mbgl/layout/clip_lines.hpp>
-#include <mbgl/renderer/symbol_bucket.hpp>
+#include <mbgl/renderer/buckets/symbol_bucket.hpp>
#include <mbgl/style/filter_evaluator.hpp>
#include <mbgl/renderer/bucket_parameters.hpp>
-#include <mbgl/renderer/render_symbol_layer.hpp>
+#include <mbgl/renderer/layers/render_symbol_layer.hpp>
+#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
-#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/text/get_anchors.hpp>
#include <mbgl/text/collision_tile.hpp>
#include <mbgl/text/shaping.hpp>
@@ -40,21 +40,22 @@ static bool has(const style::SymbolLayoutProperties::PossiblyEvaluated& layout)
SymbolLayout::SymbolLayout(const BucketParameters& parameters,
const std::vector<const RenderLayer*>& layers,
- const GeometryTileLayer& sourceLayer,
- IconDependencies& iconDependencies,
+ std::unique_ptr<GeometryTileLayer> sourceLayer_,
+ ImageDependencies& imageDependencies,
GlyphDependencies& glyphDependencies)
- : sourceLayerName(sourceLayer.getName()),
+ : sourceLayer(std::move(sourceLayer_)),
bucketName(layers.at(0)->getID()),
overscaling(parameters.tileID.overscaleFactor()),
zoom(parameters.tileID.overscaledZ),
mode(parameters.mode),
+ pixelRatio(parameters.pixelRatio),
tileSize(util::tileSize * overscaling),
tilePixelRatio(float(util::EXTENT) / tileSize),
- textSize(layers.at(0)->as<RenderSymbolLayer>()->impl->layout.unevaluated.get<TextSize>()),
- iconSize(layers.at(0)->as<RenderSymbolLayer>()->impl->layout.unevaluated.get<IconSize>())
+ textSize(layers.at(0)->as<RenderSymbolLayer>()->impl().layout.get<TextSize>()),
+ iconSize(layers.at(0)->as<RenderSymbolLayer>()->impl().layout.get<IconSize>())
{
- const SymbolLayer::Impl& leader = *layers.at(0)->as<RenderSymbolLayer>()->impl;
+ const SymbolLayer::Impl& leader = layers.at(0)->as<RenderSymbolLayer>()->impl();
layout = leader.layout.evaluate(PropertyEvaluationParameters(zoom));
@@ -94,9 +95,9 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
}
// Determine glyph dependencies
- const size_t featureCount = sourceLayer.featureCount();
+ const size_t featureCount = sourceLayer->featureCount();
for (size_t i = 0; i < featureCount; ++i) {
- auto feature = sourceLayer.getFeature(i);
+ auto feature = sourceLayer->getFeature(i);
if (!leader.filter(feature->getType(), feature->getID(), [&] (const auto& key) { return feature->getValue(key); }))
continue;
@@ -136,12 +137,17 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
}
ft.text = applyArabicShaping(util::utf8_to_utf16::convert(u8string));
+ const bool canVerticalizeText = layout.get<TextRotationAlignment>() == AlignmentType::Map
+ && layout.get<SymbolPlacement>() == SymbolPlacementType::Line
+ && util::i18n::allowsVerticalWritingMode(*ft.text);
// Loop through all characters of this text and collect unique codepoints.
for (char16_t chr : *ft.text) {
glyphDependencies[layout.get<TextFont>()].insert(chr);
- if (char16_t verticalChr = util::i18n::verticalizePunctuation(chr)) {
- glyphDependencies[layout.get<TextFont>()].insert(verticalChr);
+ if (canVerticalizeText) {
+ if (char16_t verticalChr = util::i18n::verticalizePunctuation(chr)) {
+ glyphDependencies[layout.get<TextFont>()].insert(verticalChr);
+ }
}
}
}
@@ -152,7 +158,7 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
icon = util::replaceTokens(icon, getValue);
}
ft.icon = icon;
- iconDependencies.insert(*ft.icon);
+ imageDependencies.insert(*ft.icon);
}
if (ft.text || ft.icon) {
@@ -169,7 +175,8 @@ bool SymbolLayout::hasSymbolInstances() const {
return !symbolInstances.empty();
}
-void SymbolLayout::prepare(const GlyphPositionMap& glyphs, const IconMap& icons) {
+void SymbolLayout::prepare(const GlyphMap& glyphMap, const GlyphPositions& glyphPositions,
+ const ImageMap& imageMap, const ImagePositions& imagePositions) {
float horizontalAlign = 0.5;
float verticalAlign = 0.5;
@@ -211,61 +218,65 @@ void SymbolLayout::prepare(const GlyphPositionMap& glyphs, const IconMap& icons)
layout.get<TextJustify>() == TextJustifyType::Left ? 0 :
0.5;
-
const bool textAlongLine = layout.get<TextRotationAlignment>() == AlignmentType::Map &&
layout.get<SymbolPlacement>() == SymbolPlacementType::Line;
+ auto glyphMapIt = glyphMap.find(layout.get<TextFont>());
+ const Glyphs& glyphs = glyphMapIt != glyphMap.end()
+ ? glyphMapIt->second : Glyphs();
+
+ auto glyphPositionsIt = glyphPositions.find(layout.get<TextFont>());
+ const GlyphPositionMap& glyphPositionMap = glyphPositionsIt != glyphPositions.end()
+ ? glyphPositionsIt->second : GlyphPositionMap();
+
for (auto it = features.begin(); it != features.end(); ++it) {
auto& feature = *it;
if (feature.geometry.empty()) continue;
std::pair<Shaping, Shaping> shapedTextOrientations;
optional<PositionedIcon> shapedIcon;
- GlyphPositions face;
// if feature has text, shape the text
if (feature.text) {
- auto glyphPositions = glyphs.find(layout.get<TextFont>());
- if (glyphPositions != glyphs.end()) { // If there are no glyphs available for this feature, skip shaping
- auto applyShaping = [&] (const std::u16string& text, WritingModeType writingMode) {
- const float oneEm = 24.0f;
- const Shaping result = 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 */ util::i18n::allowsLetterSpacing(*feature.text) ? layout.get<TextLetterSpacing>() * oneEm : 0.0f,
- /* translate */ Point<float>(layout.evaluate<TextOffset>(zoom, feature)[0] * oneEm, layout.evaluate<TextOffset>(zoom, feature)[1] * oneEm),
- /* verticalHeight */ oneEm,
- /* writingMode */ writingMode,
- /* bidirectional algorithm object */ bidi,
- /* glyphs */ glyphPositions->second);
-
- return result;
- };
-
- shapedTextOrientations.first = applyShaping(*feature.text, WritingModeType::Horizontal);
-
- if (util::i18n::allowsVerticalWritingMode(*feature.text) && textAlongLine) {
- shapedTextOrientations.second = applyShaping(util::i18n::verticalizePunctuation(*feature.text), WritingModeType::Vertical);
- }
+ auto applyShaping = [&] (const std::u16string& text, WritingModeType writingMode) {
+ const float oneEm = 24.0f;
+ const Shaping result = 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 */ util::i18n::allowsLetterSpacing(*feature.text) ? layout.get<TextLetterSpacing>() * oneEm : 0.0f,
+ /* translate */ Point<float>(layout.evaluate<TextOffset>(zoom, feature)[0] * oneEm, layout.evaluate<TextOffset>(zoom, feature)[1] * oneEm),
+ /* verticalHeight */ oneEm,
+ /* writingMode */ writingMode,
+ /* bidirectional algorithm object */ bidi,
+ /* glyphs */ glyphs);
+
+ return result;
+ };
+
+ shapedTextOrientations.first = applyShaping(*feature.text, WritingModeType::Horizontal);
+
+ if (util::i18n::allowsVerticalWritingMode(*feature.text) && textAlongLine) {
+ shapedTextOrientations.second = applyShaping(util::i18n::verticalizePunctuation(*feature.text), WritingModeType::Vertical);
}
}
// if feature has icon, get sprite atlas position
if (feature.icon) {
- auto image = icons.find(*feature.icon);
- if (image != icons.end()) {
- shapedIcon = PositionedIcon::shapeIcon(image->second,
+ auto image = imageMap.find(*feature.icon);
+ if (image != imageMap.end()) {
+ shapedIcon = PositionedIcon::shapeIcon(
+ imagePositions.at(*feature.icon),
layout.evaluate<IconOffset>(zoom, feature),
layout.evaluate<IconRotate>(zoom, feature) * util::DEG2RAD);
- if (image->second.sdf) {
+ if (image->second->sdf) {
sdfIcons = true;
}
- if (image->second.relativePixelRatio != 1.0f) {
+ if (image->second->pixelRatio != pixelRatio) {
iconsNeedLinear = true;
} else if (layout.get<IconRotate>().constantOr(1) != 0) {
iconsNeedLinear = true;
@@ -275,8 +286,7 @@ void SymbolLayout::prepare(const GlyphPositionMap& glyphs, const IconMap& icons)
// if either shapedText or icon position is present, add the feature
if (shapedTextOrientations.first || shapedIcon) {
- auto glyphPositionsIt = glyphs.find(layout.get<TextFont>());
- addFeature(std::distance(features.begin(), it), feature, shapedTextOrientations, shapedIcon, glyphPositionsIt == glyphs.end() ? GlyphPositions() : glyphPositionsIt->second);
+ addFeature(std::distance(features.begin(), it), feature, shapedTextOrientations, shapedIcon, glyphPositionMap);
}
feature.geometry.clear();
@@ -289,7 +299,7 @@ void SymbolLayout::addFeature(const std::size_t index,
const SymbolFeature& feature,
const std::pair<Shaping, Shaping>& shapedTextOrientations,
optional<PositionedIcon> shapedIcon,
- const GlyphPositions& glyphs) {
+ const GlyphPositionMap& glyphPositionMap) {
const float minScale = 0.5f;
const float glyphSize = 24.0f;
@@ -318,8 +328,9 @@ void SymbolLayout::addFeature(const std::size_t index,
? SymbolPlacementType::Point
: layout.get<SymbolPlacement>();
const float textRepeatDistance = symbolSpacing / 2;
- IndexedSubfeature indexedFeature = {feature.index, sourceLayerName, bucketName, symbolInstances.size()};
-
+ IndexedSubfeature indexedFeature = { feature.index, sourceLayer->getName(), bucketName,
+ symbolInstances.size() };
+
auto addSymbolInstance = [&] (const GeometryCoordinates& line, Anchor& anchor) {
// https://github.com/mapbox/vector-tile-spec/tree/master/2.1#41-layers
// +-------------------+ Symbols with anchors located on tile edges
@@ -346,7 +357,7 @@ void SymbolLayout::addFeature(const std::size_t index,
addToBuffers, symbolInstances.size(),
textBoxScale, textPadding, textPlacement,
iconBoxScale, iconPadding, iconPlacement,
- glyphs, indexedFeature, index);
+ glyphPositionMap, indexedFeature, index);
};
const auto& type = feature.getType();
diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp
index 7d19aba671..8cdaadff00 100644
--- a/src/mbgl/layout/symbol_layout.hpp
+++ b/src/mbgl/layout/symbol_layout.hpp
@@ -29,11 +29,12 @@ class SymbolLayout {
public:
SymbolLayout(const BucketParameters&,
const std::vector<const RenderLayer*>&,
- const GeometryTileLayer&,
- IconDependencies&,
+ std::unique_ptr<GeometryTileLayer>,
+ ImageDependencies&,
GlyphDependencies&);
- void prepare(const GlyphPositionMap& glyphs, const IconMap& icons);
+ void prepare(const GlyphMap&, const GlyphPositions&,
+ const ImageMap&, const ImagePositions&);
std::unique_ptr<SymbolBucket> place(CollisionTile&);
@@ -47,14 +48,14 @@ public:
State state = Pending;
std::map<std::string,
- std::pair<style::IconPaintProperties::Evaluated, style::TextPaintProperties::Evaluated>> layerPaintProperties;
+ std::pair<style::IconPaintProperties::PossiblyEvaluated, style::TextPaintProperties::PossiblyEvaluated>> layerPaintProperties;
private:
void addFeature(const size_t,
const SymbolFeature&,
const std::pair<Shaping, Shaping>& shapedTextOrientations,
optional<PositionedIcon> shapedIcon,
- const GlyphPositions& face);
+ const GlyphPositionMap&);
bool anchorIsTooClose(const std::u16string& text, const float repeatDistance, const Anchor&);
std::map<std::u16string, std::vector<Anchor>> compareText;
@@ -73,11 +74,14 @@ private:
const float placementAngle,
WritingModeType writingModes);
- const std::string sourceLayerName;
+ // Stores the layer so that we can hold on to GeometryTileFeature instances in SymbolFeature,
+ // which may reference data from this object.
+ const std::unique_ptr<GeometryTileLayer> sourceLayer;
const std::string bucketName;
const float overscaling;
const float zoom;
const MapMode mode;
+ const float pixelRatio;
style::SymbolLayoutProperties::PossiblyEvaluated layout;
diff --git a/src/mbgl/map/backend.cpp b/src/mbgl/map/backend.cpp
index 0b4fd01050..83c2fed00b 100644
--- a/src/mbgl/map/backend.cpp
+++ b/src/mbgl/map/backend.cpp
@@ -32,11 +32,17 @@ void Backend::assumeFramebufferBinding(const gl::FramebufferID fbo) {
assert(gl::value::BindFramebuffer::Get() == getContext().bindFramebuffer.getCurrentValue());
}
}
-void Backend::assumeViewportSize(const Size& size) {
- getContext().viewport.setCurrentValue({ 0, 0, size });
+
+void Backend::assumeViewport(int32_t x, int32_t y, const Size& size) {
+ getContext().viewport.setCurrentValue({ x, y, size });
assert(gl::value::Viewport::Get() == getContext().viewport.getCurrentValue());
}
+void Backend::assumeScissorTest(bool enabled) {
+ getContext().scissorTest.setCurrentValue(enabled);
+ assert(gl::value::ScissorTest::Get() == getContext().scissorTest.getCurrentValue());
+}
+
bool Backend::implicitFramebufferBound() {
return getContext().bindFramebuffer.getCurrentValue() == ImplicitFramebufferBinding;
}
@@ -48,11 +54,16 @@ void Backend::setFramebufferBinding(const gl::FramebufferID fbo) {
}
}
-void Backend::setViewportSize(const Size& size) {
- getContext().viewport = { 0, 0, size };
+void Backend::setViewport(int32_t x, int32_t y, const Size& size) {
+ getContext().viewport = { x, y, size };
assert(gl::value::Viewport::Get() == getContext().viewport.getCurrentValue());
}
+void Backend::setScissorTest(bool enabled) {
+ getContext().scissorTest = enabled;
+ assert(gl::value::ScissorTest::Get() == getContext().scissorTest.getCurrentValue());
+}
+
Backend::~Backend() = default;
} // namespace mbgl
diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp
index 35457f3a5b..034e43f260 100644
--- a/src/mbgl/map/map.cpp
+++ b/src/mbgl/map/map.cpp
@@ -6,18 +6,13 @@
#include <mbgl/map/transform.hpp>
#include <mbgl/map/transform_state.hpp>
#include <mbgl/annotation/annotation_manager.hpp>
-#include <mbgl/style/style.hpp>
-#include <mbgl/style/source.hpp>
-#include <mbgl/style/layer.hpp>
-#include <mbgl/style/light.hpp>
+#include <mbgl/style/style_impl.hpp>
#include <mbgl/style/observer.hpp>
-#include <mbgl/style/transition_options.hpp>
#include <mbgl/renderer/update_parameters.hpp>
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/render_source.hpp>
-#include <mbgl/storage/file_source.hpp>
-#include <mbgl/storage/resource.hpp>
-#include <mbgl/storage/response.hpp>
+#include <mbgl/renderer/render_style.hpp>
+#include <mbgl/renderer/render_style_observer.hpp>
#include <mbgl/util/exception.hpp>
#include <mbgl/util/math.hpp>
#include <mbgl/util/exception.hpp>
@@ -27,6 +22,7 @@
#include <mbgl/actor/scheduler.hpp>
#include <mbgl/util/logging.hpp>
#include <mbgl/math/log2.hpp>
+#include <utility>
namespace mbgl {
@@ -47,7 +43,8 @@ struct StillImageRequest {
Map::StillImageCallback callback;
};
-class Map::Impl : public style::Observer {
+class Map::Impl : public style::Observer,
+ public RenderStyleObserver {
public:
Impl(Map&,
Backend&,
@@ -62,6 +59,8 @@ public:
void onSourceChanged(style::Source&) override;
void onUpdate(Update) override;
+ void onInvalidate() override;
+ void onStyleLoading() override;
void onStyleLoaded() override;
void onStyleError(std::exception_ptr) override;
void onResourceError(std::exception_ptr) override;
@@ -69,8 +68,6 @@ public:
void render(View&);
void renderStill();
- void loadStyleJSON(const std::string&);
-
Map& map;
MapObserver& observer;
Backend& backend;
@@ -89,18 +86,12 @@ public:
Update updateFlags = Update::Nothing;
- std::unique_ptr<AnnotationManager> annotationManager;
+ AnnotationManager annotationManager;
std::unique_ptr<Painter> painter;
std::unique_ptr<Style> style;
+ std::unique_ptr<RenderStyle> renderStyle;
- std::string styleURL;
- std::string styleJSON;
- bool styleMutated = false;
bool cameraMutated = false;
-
- std::unique_ptr<AsyncRequest> styleRequest;
-
- size_t sourceCacheSize;
bool loading = false;
util::AsyncTask asyncInvalidate;
@@ -151,8 +142,7 @@ Map::Impl::Impl(Map& map_,
mode(mode_),
contextMode(contextMode_),
pixelRatio(pixelRatio_),
- programCacheDir(programCacheDir_),
- annotationManager(std::make_unique<AnnotationManager>(pixelRatio)),
+ programCacheDir(std::move(programCacheDir_)),
asyncInvalidate([this] {
if (mode == MapMode::Continuous) {
backend.invalidate();
@@ -160,17 +150,16 @@ Map::Impl::Impl(Map& map_,
renderStill();
}
}) {
+ style = std::make_unique<Style>(scheduler, fileSource, pixelRatio);
+ style->impl->setObserver(this);
}
Map::~Map() {
BackendScope guard(impl->backend);
- impl->styleRequest = nullptr;
-
// Explicit resets currently necessary because these abandon resources that need to be
// cleaned up by context.reset();
- impl->style.reset();
- impl->annotationManager.reset();
+ impl->renderStyle.reset();
impl->painter.reset();
}
@@ -190,13 +179,8 @@ void Map::renderStill(View& view, StillImageCallback callback) {
return;
}
- if (!impl->style) {
- callback(std::make_exception_ptr(util::MisuseException("Map doesn't have a style")));
- return;
- }
-
- if (impl->style->getLastError()) {
- callback(impl->style->getLastError());
+ if (impl->style->impl->getLastError()) {
+ callback(impl->style->impl->getLastError());
return;
}
@@ -223,42 +207,48 @@ void Map::render(View& view) {
}
void Map::Impl::render(View& view) {
- if (!style) {
- return;
- }
-
TimePoint timePoint = mode == MapMode::Continuous
? Clock::now()
: Clock::time_point::max();
transform.updateTransitions(timePoint);
- if (style->loaded && updateFlags & Update::AnnotationStyle) {
- annotationManager->updateStyle(*style);
+ if (style->impl->loaded && updateFlags & Update::AnnotationStyle) {
+ annotationManager.updateStyle(*style->impl);
}
if (updateFlags & Update::AnnotationData) {
- annotationManager->updateData();
+ annotationManager.updateData();
}
- style->update({
+ updateFlags = Update::Nothing;
+
+ gl::Context& context = backend.getContext();
+ if (!painter) {
+ renderStyle = std::make_unique<RenderStyle>(scheduler, fileSource);
+ renderStyle->setObserver(this);
+ painter = std::make_unique<Painter>(context, transform.getState(), pixelRatio, programCacheDir);
+ }
+
+ renderStyle->update({
mode,
- updateFlags,
pixelRatio,
debugOptions,
timePoint,
transform.getState(),
+ style->impl->getGlyphURL(),
+ style->impl->spriteLoaded,
+ style->impl->getTransitionOptions(),
+ style->impl->getLight()->impl,
+ style->impl->getImageImpls(),
+ style->impl->getSourceImpls(),
+ style->impl->getLayerImpls(),
scheduler,
fileSource,
- *annotationManager
+ annotationManager
});
- updateFlags = Update::Nothing;
-
- gl::Context& context = backend.getContext();
- if (!painter) {
- painter = std::make_unique<Painter>(context, transform.getState(), pixelRatio, programCacheDir);
- }
+ bool loaded = style->impl->isLoaded() && renderStyle->isLoaded();
if (mode == MapMode::Continuous) {
if (renderState == RenderState::Never) {
@@ -275,16 +265,17 @@ void Map::Impl::render(View& view) {
backend.updateAssumedState();
- painter->render(*style,
+ painter->render(*renderStyle,
frameData,
- view,
- annotationManager->getSpriteAtlas());
+ view);
painter->cleanup();
- observer.onDidFinishRenderingFrame(style->isLoaded() ? MapObserver::RenderMode::Full : MapObserver::RenderMode::Partial);
+ observer.onDidFinishRenderingFrame(loaded
+ ? MapObserver::RenderMode::Full
+ : MapObserver::RenderMode::Partial);
- if (!style->isLoaded()) {
+ if (!loaded) {
renderState = RenderState::Partial;
} else if (renderState != RenderState::Fully) {
renderState = RenderState::Fully;
@@ -297,10 +288,10 @@ void Map::Impl::render(View& view) {
// Schedule an update if we need to paint another frame due to transitions or
// animations that are still in progress
- if (style->hasTransitions() || painter->needsAnimation() || transform.inTransition()) {
+ if (renderStyle->hasTransitions() || painter->needsAnimation() || transform.inTransition()) {
onUpdate(Update::Repaint);
}
- } else if (stillImageRequest && style->isLoaded()) {
+ } else if (stillImageRequest && loaded) {
FrameData frameData { timePoint,
pixelRatio,
mode,
@@ -309,10 +300,9 @@ void Map::Impl::render(View& view) {
backend.updateAssumedState();
- painter->render(*style,
+ painter->render(*renderStyle,
frameData,
- view,
- annotationManager->getSpriteAtlas());
+ view);
auto request = std::move(stillImageRequest);
request->callback(nullptr);
@@ -323,93 +313,17 @@ void Map::Impl::render(View& view) {
#pragma mark - Style
-void Map::setStyleURL(const std::string& url) {
- if (impl->styleURL == url) {
- return;
- }
-
- impl->loading = true;
-
- impl->observer.onWillStartLoadingMap();
-
- impl->styleRequest = nullptr;
- impl->styleURL = url;
- impl->styleJSON.clear();
- impl->styleMutated = false;
-
- impl->style = std::make_unique<Style>(impl->scheduler, impl->fileSource, impl->pixelRatio);
-
- impl->styleRequest = impl->fileSource.request(Resource::style(impl->styleURL), [this](Response res) {
- // Once we get a fresh style, or the style is mutated, stop revalidating.
- if (res.isFresh() || impl->styleMutated) {
- impl->styleRequest.reset();
- }
-
- // Don't allow a loaded, mutated style to be overwritten with a new version.
- if (impl->styleMutated && impl->style->loaded) {
- return;
- }
-
- if (res.error) {
- if (res.error->reason == Response::Error::Reason::NotFound &&
- util::mapbox::isMapboxURL(impl->styleURL)) {
- const std::string message = "style " + impl->styleURL + " could not be found or is an incompatible legacy map or style";
- Log::Error(Event::Setup, message.c_str());
- impl->onStyleError(std::make_exception_ptr(util::NotFoundException(message)));
- } else {
- const std::string message = "loading style failed: " + res.error->message;
- Log::Error(Event::Setup, message.c_str());
- impl->onStyleError(std::make_exception_ptr(util::StyleLoadException(message)));
- }
- impl->onResourceError(std::make_exception_ptr(std::runtime_error(res.error->message)));
- } else if (res.notModified || res.noContent) {
- return;
- } else {
- impl->loadStyleJSON(*res.data);
- }
- });
+style::Style& Map::getStyle() {
+ return *impl->style;
}
-void Map::setStyleJSON(const std::string& json) {
- if (impl->styleJSON == json) {
- return;
- }
-
- impl->loading = true;
-
- impl->observer.onWillStartLoadingMap();
-
- impl->styleURL.clear();
- impl->styleJSON.clear();
- impl->styleMutated = false;
-
- impl->style = std::make_unique<Style>(impl->scheduler, impl->fileSource, impl->pixelRatio);
-
- impl->loadStyleJSON(json);
-}
-
-void Map::Impl::loadStyleJSON(const std::string& json) {
- style->setObserver(this);
- style->setJSON(json);
- styleJSON = json;
-
- if (!cameraMutated) {
- // Zoom first because it may constrain subsequent operations.
- map.setZoom(map.getDefaultZoom());
- map.setLatLng(map.getDefaultLatLng());
- map.setBearing(map.getDefaultBearing());
- map.setPitch(map.getDefaultPitch());
- }
-
- onUpdate(Update::Classes | Update::AnnotationStyle);
-}
-
-std::string Map::getStyleURL() const {
- return impl->styleURL;
+const style::Style& Map::getStyle() const {
+ return *impl->style;
}
-std::string Map::getStyleJSON() const {
- return impl->styleJSON;
+void Map::setStyle(std::unique_ptr<Style> style) {
+ impl->onStyleLoading();
+ impl->style = std::move(style);
}
#pragma mark - Transitions
@@ -787,39 +701,41 @@ LatLng Map::latLngForPixel(const ScreenCoordinate& pixel) const {
#pragma mark - Annotations
-void Map::addAnnotationImage(const std::string& id, std::unique_ptr<style::Image> image) {
- impl->annotationManager->addImage(id, std::move(image));
+void Map::addAnnotationImage(std::unique_ptr<style::Image> image) {
+ impl->annotationManager.addImage(std::move(image));
+ impl->onUpdate(Update::AnnotationStyle);
}
void Map::removeAnnotationImage(const std::string& id) {
- impl->annotationManager->removeImage(id);
+ impl->annotationManager.removeImage(id);
+ impl->onUpdate(Update::AnnotationStyle);
}
double Map::getTopOffsetPixelsForAnnotationImage(const std::string& id) {
- return impl->annotationManager->getTopOffsetPixelsForImage(id);
+ return impl->annotationManager.getTopOffsetPixelsForImage(id);
}
AnnotationID Map::addAnnotation(const Annotation& annotation) {
- auto result = impl->annotationManager->addAnnotation(annotation, getMaxZoom());
+ auto result = impl->annotationManager.addAnnotation(annotation, getMaxZoom());
impl->onUpdate(Update::AnnotationStyle | Update::AnnotationData);
return result;
}
void Map::updateAnnotation(AnnotationID id, const Annotation& annotation) {
- impl->onUpdate(impl->annotationManager->updateAnnotation(id, annotation, getMaxZoom()));
+ impl->onUpdate(impl->annotationManager.updateAnnotation(id, annotation, getMaxZoom()));
}
void Map::removeAnnotation(AnnotationID annotation) {
- impl->annotationManager->removeAnnotation(annotation);
+ impl->annotationManager.removeAnnotation(annotation);
impl->onUpdate(Update::AnnotationStyle | Update::AnnotationData);
}
#pragma mark - Feature query api
std::vector<Feature> Map::queryRenderedFeatures(const ScreenCoordinate& point, const RenderedQueryOptions& options) {
- if (!impl->style) return {};
+ if (!impl->renderStyle) return {};
- return impl->style->queryRenderedFeatures(
+ return impl->renderStyle->queryRenderedFeatures(
{ point },
impl->transform.getState(),
options
@@ -827,9 +743,9 @@ std::vector<Feature> Map::queryRenderedFeatures(const ScreenCoordinate& point, c
}
std::vector<Feature> Map::queryRenderedFeatures(const ScreenBox& box, const RenderedQueryOptions& options) {
- if (!impl->style) return {};
+ if (!impl->renderStyle) return {};
- return impl->style->queryRenderedFeatures(
+ return impl->renderStyle->queryRenderedFeatures(
{
box.min,
{ box.max.x, box.min.y },
@@ -843,9 +759,9 @@ std::vector<Feature> Map::queryRenderedFeatures(const ScreenBox& box, const Rend
}
std::vector<Feature> Map::querySourceFeatures(const std::string& sourceID, const SourceQueryOptions& options) {
- if (!impl->style) return {};
+ if (!impl->renderStyle) return {};
- const RenderSource* source = impl->style->getRenderSource(sourceID);
+ const RenderSource* source = impl->renderStyle->getRenderSource(sourceID);
if (!source) return {};
return source->querySourceFeatures(options);
@@ -868,153 +784,6 @@ AnnotationIDs Map::queryPointAnnotations(const ScreenBox& box) {
return ids;
}
-#pragma mark - Style API
-
-std::vector<style::Source*> Map::getSources() {
- return impl->style ? impl->style->getSources() : std::vector<style::Source*>();
-}
-
-style::Source* Map::getSource(const std::string& sourceID) {
- if (impl->style) {
- impl->styleMutated = true;
- return impl->style->getSource(sourceID);
- }
- return nullptr;
-}
-
-void Map::addSource(std::unique_ptr<style::Source> source) {
- if (impl->style) {
- impl->styleMutated = true;
- impl->style->addSource(std::move(source));
- }
-}
-
-std::unique_ptr<Source> Map::removeSource(const std::string& sourceID) {
- if (impl->style) {
- impl->styleMutated = true;
- return impl->style->removeSource(sourceID);
- }
- return nullptr;
-}
-
-std::vector<style::Layer*> Map::getLayers() {
- return impl->style ? impl->style->getLayers() : std::vector<style::Layer*>();
-}
-
-Layer* Map::getLayer(const std::string& layerID) {
- if (impl->style) {
- impl->styleMutated = true;
- return impl->style->getLayer(layerID);
- }
- return nullptr;
-}
-
-void Map::addLayer(std::unique_ptr<Layer> layer, const optional<std::string>& before) {
- if (!impl->style) {
- return;
- }
-
- impl->styleMutated = true;
- BackendScope guard(impl->backend);
-
- impl->style->addLayer(std::move(layer), before);
- impl->onUpdate(Update::Classes);
-}
-
-std::unique_ptr<Layer> Map::removeLayer(const std::string& id) {
- if (!impl->style) {
- return nullptr;
- }
-
- impl->styleMutated = true;
- BackendScope guard(impl->backend);
-
- auto removedLayer = impl->style->removeLayer(id);
- impl->onUpdate(Update::Repaint);
-
- return removedLayer;
-}
-
-void Map::addImage(const std::string& id, std::unique_ptr<style::Image> image) {
- if (!impl->style) {
- return;
- }
-
- impl->styleMutated = true;
- impl->style->spriteAtlas->addImage(id, std::move(image));
- impl->onUpdate(Update::Repaint);
-}
-
-void Map::removeImage(const std::string& id) {
- if (!impl->style) {
- return;
- }
-
- impl->styleMutated = true;
- impl->style->spriteAtlas->removeImage(id);
- impl->onUpdate(Update::Repaint);
-}
-
-const style::Image* Map::getImage(const std::string& id) {
- if (impl->style) {
- return impl->style->spriteAtlas->getImage(id);
- }
- return nullptr;
-}
-
-void Map::setLight(std::unique_ptr<style::Light> light) {
- if (!impl->style) {
- return;
- }
-
- impl->style->setLight(std::move(light));
-}
-
-style::Light* Map::getLight() {
- if (!impl->style) {
- return nullptr;
- }
-
- return impl->style->getLight();
-}
-
-#pragma mark - Defaults
-
-std::string Map::getStyleName() const {
- if (impl->style) {
- return impl->style->getName();
- }
- return {};
-}
-
-LatLng Map::getDefaultLatLng() const {
- if (impl->style) {
- return impl->style->getDefaultLatLng();
- }
- return {};
-}
-
-double Map::getDefaultZoom() const {
- if (impl->style) {
- return impl->style->getDefaultZoom();
- }
- return {};
-}
-
-double Map::getDefaultBearing() const {
- if (impl->style) {
- return impl->style->getDefaultBearing();
- }
- return {};
-}
-
-double Map::getDefaultPitch() const {
- if (impl->style) {
- return impl->style->getDefaultPitch();
- }
- return {};
-}
-
#pragma mark - Toggles
void Map::setDebug(MapDebugOptions debugOptions) {
@@ -1051,59 +820,7 @@ MapDebugOptions Map::getDebug() const {
}
bool Map::isFullyLoaded() const {
- return impl->style ? impl->style->isLoaded() : false;
-}
-
-void Map::addClass(const std::string& className) {
- if (impl->style && impl->style->addClass(className)) {
- impl->onUpdate(Update::Classes);
- }
-}
-
-void Map::removeClass(const std::string& className) {
- if (impl->style && impl->style->removeClass(className)) {
- impl->onUpdate(Update::Classes);
- }
-}
-
-void Map::setClasses(const std::vector<std::string>& classNames) {
- if (impl->style) {
- impl->style->setClasses(classNames);
- impl->onUpdate(Update::Classes);
- }
-}
-
-style::TransitionOptions Map::getTransitionOptions() const {
- if (impl->style) {
- return impl->style->getTransitionOptions();
- }
- return {};
-}
-
-void Map::setTransitionOptions(const style::TransitionOptions& options) {
- if (impl->style) {
- impl->style->setTransitionOptions(options);
- }
-}
-
-bool Map::hasClass(const std::string& className) const {
- return impl->style ? impl->style->hasClass(className) : false;
-}
-
-std::vector<std::string> Map::getClasses() const {
- if (impl->style) {
- return impl->style->getClasses();
- }
- return {};
-}
-
-void Map::setSourceTileCacheSize(size_t size) {
- if (size != impl->sourceCacheSize) {
- impl->sourceCacheSize = size;
- if (!impl->style) return;
- impl->style->setSourceTileCacheSize(size);
- impl->backend.invalidate();
- }
+ return impl->style->impl->isLoaded() && impl->renderStyle && impl->renderStyle->isLoaded();
}
void Map::onLowMemory() {
@@ -1111,8 +828,8 @@ void Map::onLowMemory() {
BackendScope guard(impl->backend);
impl->painter->cleanup();
}
- if (impl->style) {
- impl->style->onLowMemory();
+ if (impl->renderStyle) {
+ impl->renderStyle->onLowMemory();
impl->backend.invalidate();
}
}
@@ -1126,7 +843,25 @@ void Map::Impl::onUpdate(Update flags) {
asyncInvalidate.send();
}
+void Map::Impl::onInvalidate() {
+ onUpdate(Update::Repaint);
+}
+
+void Map::Impl::onStyleLoading() {
+ loading = true;
+ observer.onWillStartLoadingMap();
+}
+
void Map::Impl::onStyleLoaded() {
+ if (!cameraMutated) {
+ // Zoom first because it may constrain subsequent operations.
+ map.setZoom(style->getDefaultZoom());
+ map.setLatLng(style->getDefaultLatLng());
+ map.setBearing(style->getDefaultBearing());
+ map.setPitch(style->getDefaultPitch());
+ }
+
+ onUpdate(Update::AnnotationStyle);
observer.onDidFinishLoadingStyle();
}
@@ -1143,11 +878,9 @@ void Map::Impl::onResourceError(std::exception_ptr error) {
void Map::dumpDebugLogs() const {
Log::Info(Event::General, "--------------------------------------------------------------------------------");
- Log::Info(Event::General, "MapContext::styleURL: %s", impl->styleURL.c_str());
- if (impl->style) {
- impl->style->dumpDebugLogs();
- } else {
- Log::Info(Event::General, "no style loaded");
+ impl->style->impl->dumpDebugLogs();
+ if (impl->renderStyle) {
+ impl->renderStyle->dumpDebugLogs();
}
Log::Info(Event::General, "--------------------------------------------------------------------------------");
}
diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp
index 8d05bc0e91..50f979437d 100644
--- a/src/mbgl/map/transform.cpp
+++ b/src/mbgl/map/transform.cpp
@@ -293,6 +293,11 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
Point<double> framePoint = util::interpolate(startPoint, endPoint, us);
double frameZoom = startZoom + state.scaleZoom(1 / w(s));
+ // Zoom can be NaN if size is empty.
+ if (std::isnan(frameZoom)) {
+ frameZoom = zoom;
+ }
+
// Convert to geographic coordinates and set the new viewpoint.
LatLng frameLatLng = Projection::unproject(framePoint, startScale);
state.setLatLngZoom(frameLatLng, frameZoom);
diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp
index bbf7e22b31..f052e30a6b 100644
--- a/src/mbgl/map/transform_state.cpp
+++ b/src/mbgl/map/transform_state.cpp
@@ -358,7 +358,7 @@ void TransformState::setLatLngZoom(const LatLng& latLng, double zoom) {
constrained = bounds->constrain(latLng);
}
- double newScale = zoomScale(zoom);
+ double newScale = util::clamp(zoomScale(zoom), min_scale, max_scale);
const double newWorldSize = newScale * util::tileSize;
Bc = newWorldSize / util::DEGREES_MAX;
Cc = newWorldSize / util::M2PI;
diff --git a/src/mbgl/map/update.hpp b/src/mbgl/map/update.hpp
index 5e87515eac..82d98284f5 100644
--- a/src/mbgl/map/update.hpp
+++ b/src/mbgl/map/update.hpp
@@ -7,8 +7,6 @@ namespace mbgl {
enum class Update {
Nothing = 0,
Repaint = 1 << 0,
- Classes = 1 << 2,
- RecalculateStyle = 1 << 3,
AnnotationStyle = 1 << 6,
AnnotationData = 1 << 7
};
diff --git a/src/mbgl/map/zoom_history.hpp b/src/mbgl/map/zoom_history.hpp
index 308846b1e3..697e28573c 100644
--- a/src/mbgl/map/zoom_history.hpp
+++ b/src/mbgl/map/zoom_history.hpp
@@ -13,19 +13,20 @@ struct ZoomHistory {
bool first = true;
bool update(float z, const TimePoint& now) {
+ constexpr TimePoint zero = TimePoint(Duration::zero());
if (first) {
first = false;
lastIntegerZoom = std::floor(z);
- lastIntegerZoomTime = TimePoint(Duration::zero());
+ lastIntegerZoomTime = zero;
lastZoom = z;
return true;
} else {
if (std::floor(lastZoom) < std::floor(z)) {
lastIntegerZoom = std::floor(z);
- lastIntegerZoomTime = now;
+ lastIntegerZoomTime = now == Clock::time_point::max() ? zero : now;
} else if (std::floor(lastZoom) > std::floor(z)) {
lastIntegerZoom = std::floor(z + 1);
- lastIntegerZoomTime = now;
+ lastIntegerZoomTime = now == Clock::time_point::max() ? zero : now;
}
if (z != lastZoom) {
diff --git a/src/mbgl/programs/attributes.hpp b/src/mbgl/programs/attributes.hpp
index cfd6a629de..8f2751080f 100644
--- a/src/mbgl/programs/attributes.hpp
+++ b/src/mbgl/programs/attributes.hpp
@@ -96,6 +96,11 @@ struct a_width {
using Type = gl::Attribute<float, 1>;
};
+struct a_floorwidth {
+ static auto name() { return "a_floorwidth"; }
+ using Type = gl::Attribute<float, 1>;
+};
+
struct a_height {
static auto name() { return "a_height"; }
using Type = gl::Attribute<float, 1>;
@@ -106,7 +111,7 @@ struct a_base {
using Type = gl::Attribute<float, 1>;
};
-struct a_gap_width {
+struct a_gapwidth {
static auto name() { return "a_gapwidth"; }
using Type = gl::Attribute<float, 1>;
};
diff --git a/src/mbgl/programs/binary_program.cpp b/src/mbgl/programs/binary_program.cpp
index 3b37cfa442..09b9acc514 100644
--- a/src/mbgl/programs/binary_program.cpp
+++ b/src/mbgl/programs/binary_program.cpp
@@ -2,6 +2,7 @@
#include <protozero/pbf_reader.hpp>
#include <protozero/pbf_writer.hpp>
+#include <utility>
template <class Binding>
static std::pair<const std::string, Binding> parseBinding(protozero::pbf_reader&& pbf) {
@@ -64,12 +65,12 @@ BinaryProgram::BinaryProgram(std::string&& data) {
BinaryProgram::BinaryProgram(
gl::BinaryProgramFormat binaryFormat_,
std::string&& binaryCode_,
- const std::string& binaryIdentifier_,
+ std::string binaryIdentifier_,
std::vector<std::pair<const std::string, gl::AttributeLocation>>&& attributes_,
std::vector<std::pair<const std::string, gl::UniformLocation>>&& uniforms_)
: binaryFormat(binaryFormat_),
binaryCode(std::move(binaryCode_)),
- binaryIdentifier(binaryIdentifier_),
+ binaryIdentifier(std::move(binaryIdentifier_)),
attributes(std::move(attributes_)),
uniforms(std::move(uniforms_)) {
}
diff --git a/src/mbgl/programs/binary_program.hpp b/src/mbgl/programs/binary_program.hpp
index 8ff3863dc1..b77cf1a510 100644
--- a/src/mbgl/programs/binary_program.hpp
+++ b/src/mbgl/programs/binary_program.hpp
@@ -14,7 +14,7 @@ public:
BinaryProgram(gl::BinaryProgramFormat,
std::string&& binaryCode,
- const std::string& binaryIdentifier,
+ std::string binaryIdentifier,
std::vector<std::pair<const std::string, gl::AttributeLocation>>&&,
std::vector<std::pair<const std::string, gl::UniformLocation>>&&);
diff --git a/src/mbgl/programs/collision_box_program.hpp b/src/mbgl/programs/collision_box_program.hpp
index 89b69484fd..160fd42814 100644
--- a/src/mbgl/programs/collision_box_program.hpp
+++ b/src/mbgl/programs/collision_box_program.hpp
@@ -4,6 +4,7 @@
#include <mbgl/programs/attributes.hpp>
#include <mbgl/programs/uniforms.hpp>
#include <mbgl/shaders/collision_box.hpp>
+#include <mbgl/style/properties.hpp>
#include <mbgl/util/geometry.hpp>
#include <cmath>
@@ -29,7 +30,7 @@ class CollisionBoxProgram : public Program<
uniforms::u_scale,
uniforms::u_zoom,
uniforms::u_maxzoom>,
- style::PaintProperties<>>
+ style::Properties<>>
{
public:
using Program::Program;
diff --git a/src/mbgl/programs/debug_program.hpp b/src/mbgl/programs/debug_program.hpp
index de1666b4a8..7a6d075cdb 100644
--- a/src/mbgl/programs/debug_program.hpp
+++ b/src/mbgl/programs/debug_program.hpp
@@ -4,6 +4,7 @@
#include <mbgl/programs/attributes.hpp>
#include <mbgl/programs/uniforms.hpp>
#include <mbgl/shaders/debug.hpp>
+#include <mbgl/style/properties.hpp>
namespace mbgl {
@@ -15,7 +16,7 @@ class DebugProgram : public Program<
gl::Uniforms<
uniforms::u_matrix,
uniforms::u_color>,
- style::PaintProperties<>>
+ style::Properties<>>
{
public:
using Program::Program;
diff --git a/src/mbgl/programs/extrusion_texture_program.hpp b/src/mbgl/programs/extrusion_texture_program.hpp
index 1519aa095d..bd82208885 100644
--- a/src/mbgl/programs/extrusion_texture_program.hpp
+++ b/src/mbgl/programs/extrusion_texture_program.hpp
@@ -4,6 +4,7 @@
#include <mbgl/programs/attributes.hpp>
#include <mbgl/programs/uniforms.hpp>
#include <mbgl/shaders/extrusion_texture.hpp>
+#include <mbgl/style/properties.hpp>
#include <mbgl/util/geometry.hpp>
namespace mbgl {
@@ -17,7 +18,7 @@ class ExtrusionTextureProgram : public Program<
uniforms::u_world,
uniforms::u_image,
uniforms::u_opacity>,
- style::PaintProperties<>> {
+ style::Properties<>> {
public:
using Program::Program;
diff --git a/src/mbgl/programs/fill_extrusion_program.cpp b/src/mbgl/programs/fill_extrusion_program.cpp
index 63d1cbeb59..aaf192a843 100644
--- a/src/mbgl/programs/fill_extrusion_program.cpp
+++ b/src/mbgl/programs/fill_extrusion_program.cpp
@@ -1,5 +1,5 @@
#include <mbgl/programs/fill_extrusion_program.hpp>
-#include <mbgl/sprite/sprite_atlas.hpp>
+#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/renderer/cross_faded_property_evaluator.hpp>
#include <mbgl/tile/tile_id.hpp>
#include <mbgl/map/transform_state.hpp>
@@ -45,8 +45,9 @@ FillExtrusionUniforms::values(mat4 matrix,
FillExtrusionPatternUniforms::Values
FillExtrusionPatternUniforms::values(mat4 matrix,
- const SpriteAtlasElement& a,
- const SpriteAtlasElement& b,
+ Size atlasSize,
+ const ImagePosition& a,
+ const ImagePosition& b,
const Faded<std::string>& fading,
const UnwrappedTileID& tileID,
const TransformState& state,
@@ -58,14 +59,15 @@ FillExtrusionPatternUniforms::values(mat4 matrix,
return FillExtrusionPatternUniforms::Values{
uniforms::u_matrix::Value{ matrix },
- uniforms::u_pattern_tl_a::Value{ a.tl },
- uniforms::u_pattern_br_a::Value{ a.br },
- uniforms::u_pattern_tl_b::Value{ b.tl },
- uniforms::u_pattern_br_b::Value{ b.br },
- uniforms::u_pattern_size_a::Value{ a.size },
- uniforms::u_pattern_size_b::Value{ b.size },
+ uniforms::u_pattern_tl_a::Value{ a.tl() },
+ uniforms::u_pattern_br_a::Value{ a.br() },
+ uniforms::u_pattern_tl_b::Value{ b.tl() },
+ uniforms::u_pattern_br_b::Value{ b.br() },
+ uniforms::u_pattern_size_a::Value{ a.displaySize() },
+ uniforms::u_pattern_size_b::Value{ b.displaySize() },
uniforms::u_scale_a::Value{ fading.fromScale },
uniforms::u_scale_b::Value{ fading.toScale },
+ uniforms::u_texsize::Value{ atlasSize },
uniforms::u_mix::Value{ fading.t },
uniforms::u_image::Value{ 0 },
uniforms::u_pixel_coord_upper::Value{ std::array<float, 2>{{ float(pixelX >> 16), float(pixelY >> 16) }} },
diff --git a/src/mbgl/programs/fill_extrusion_program.hpp b/src/mbgl/programs/fill_extrusion_program.hpp
index 48fca44ee8..820670068e 100644
--- a/src/mbgl/programs/fill_extrusion_program.hpp
+++ b/src/mbgl/programs/fill_extrusion_program.hpp
@@ -16,7 +16,7 @@
namespace mbgl {
-class SpriteAtlasElement;
+class ImagePosition;
class UnwrappedTileID;
class TransformState;
template <class> class Faded;
@@ -55,6 +55,7 @@ struct FillExtrusionPatternUniforms : gl::Uniforms<
uniforms::u_pattern_size_b,
uniforms::u_scale_a,
uniforms::u_scale_b,
+ uniforms::u_texsize,
uniforms::u_mix,
uniforms::u_image,
uniforms::u_pixel_coord_upper,
@@ -66,8 +67,9 @@ struct FillExtrusionPatternUniforms : gl::Uniforms<
uniforms::u_lightintensity>
{
static Values values(mat4,
- const SpriteAtlasElement&,
- const SpriteAtlasElement&,
+ Size atlasSize,
+ const ImagePosition&,
+ const ImagePosition&,
const Faded<std::string>&,
const UnwrappedTileID&,
const TransformState&,
diff --git a/src/mbgl/programs/fill_program.cpp b/src/mbgl/programs/fill_program.cpp
index 4310f01164..46dc830102 100644
--- a/src/mbgl/programs/fill_program.cpp
+++ b/src/mbgl/programs/fill_program.cpp
@@ -1,5 +1,5 @@
#include <mbgl/programs/fill_program.hpp>
-#include <mbgl/sprite/sprite_atlas.hpp>
+#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/renderer/cross_faded_property_evaluator.hpp>
#include <mbgl/tile/tile_id.hpp>
#include <mbgl/map/transform_state.hpp>
@@ -13,8 +13,9 @@ static_assert(sizeof(FillLayoutVertex) == 4, "expected FillLayoutVertex size");
FillPatternUniforms::Values
FillPatternUniforms::values(mat4 matrix,
Size framebufferSize,
- const SpriteAtlasElement& a,
- const SpriteAtlasElement& b,
+ Size atlasSize,
+ const ImagePosition& a,
+ const ImagePosition& b,
const Faded<std::string>& fading,
const UnwrappedTileID& tileID,
const TransformState& state)
@@ -26,12 +27,13 @@ FillPatternUniforms::values(mat4 matrix,
return FillPatternUniforms::Values {
uniforms::u_matrix::Value{ matrix },
uniforms::u_world::Value{ framebufferSize },
- uniforms::u_pattern_tl_a::Value{ a.tl },
- uniforms::u_pattern_br_a::Value{ a.br },
- uniforms::u_pattern_tl_b::Value{ b.tl },
- uniforms::u_pattern_br_b::Value{ b.br },
- uniforms::u_pattern_size_a::Value{ a.size },
- uniforms::u_pattern_size_b::Value{ b.size },
+ uniforms::u_texsize::Value{ atlasSize },
+ uniforms::u_pattern_tl_a::Value{ a.tl() },
+ uniforms::u_pattern_br_a::Value{ a.br() },
+ uniforms::u_pattern_tl_b::Value{ b.tl() },
+ uniforms::u_pattern_br_b::Value{ b.br() },
+ uniforms::u_pattern_size_a::Value{ a.displaySize() },
+ uniforms::u_pattern_size_b::Value{ b.displaySize() },
uniforms::u_scale_a::Value{ fading.fromScale },
uniforms::u_scale_b::Value{ fading.toScale },
uniforms::u_mix::Value{ fading.t },
diff --git a/src/mbgl/programs/fill_program.hpp b/src/mbgl/programs/fill_program.hpp
index 63751e740a..2dfeea3279 100644
--- a/src/mbgl/programs/fill_program.hpp
+++ b/src/mbgl/programs/fill_program.hpp
@@ -16,7 +16,7 @@
namespace mbgl {
-class SpriteAtlasElement;
+class ImagePosition;
class UnwrappedTileID;
class TransformState;
template <class> class Faded;
@@ -33,6 +33,7 @@ struct FillUniforms : gl::Uniforms<
struct FillPatternUniforms : gl::Uniforms<
uniforms::u_matrix,
uniforms::u_world,
+ uniforms::u_texsize,
uniforms::u_pattern_tl_a,
uniforms::u_pattern_br_a,
uniforms::u_pattern_tl_b,
@@ -49,8 +50,9 @@ struct FillPatternUniforms : gl::Uniforms<
{
static Values values(mat4 matrix,
Size framebufferSize,
- const SpriteAtlasElement&,
- const SpriteAtlasElement&,
+ Size atlasSize,
+ const ImagePosition&,
+ const ImagePosition&,
const Faded<std::string>&,
const UnwrappedTileID&,
const TransformState&);
diff --git a/src/mbgl/programs/line_program.cpp b/src/mbgl/programs/line_program.cpp
index d9778ba7ce..db5c916d32 100644
--- a/src/mbgl/programs/line_program.cpp
+++ b/src/mbgl/programs/line_program.cpp
@@ -1,9 +1,9 @@
#include <mbgl/programs/line_program.hpp>
#include <mbgl/style/layers/line_layer_properties.hpp>
#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/map/transform_state.hpp>
#include <mbgl/util/mat2.hpp>
-#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/geometry/line_atlas.hpp>
namespace mbgl {
@@ -13,7 +13,7 @@ using namespace style;
static_assert(sizeof(LineLayoutVertex) == 8, "expected LineLayoutVertex size");
template <class Values, class...Args>
-Values makeValues(const LinePaintProperties::Evaluated& properties,
+Values makeValues(const RenderLinePaintProperties::PossiblyEvaluated& properties,
const RenderTile& tile,
const TransformState& state,
const std::array<float, 2>& pixelsToGLUnits,
@@ -25,7 +25,6 @@ Values makeValues(const LinePaintProperties::Evaluated& properties,
properties.get<LineTranslateAnchor>(),
state)
},
- uniforms::u_width::Value{ properties.get<LineWidth>() },
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)...
@@ -33,7 +32,7 @@ Values makeValues(const LinePaintProperties::Evaluated& properties,
}
LineProgram::UniformValues
-LineProgram::uniformValues(const LinePaintProperties::Evaluated& properties,
+LineProgram::uniformValues(const RenderLinePaintProperties::PossiblyEvaluated& properties,
const RenderTile& tile,
const TransformState& state,
const std::array<float, 2>& pixelsToGLUnits) {
@@ -46,17 +45,16 @@ LineProgram::uniformValues(const LinePaintProperties::Evaluated& properties,
}
LineSDFProgram::UniformValues
-LineSDFProgram::uniformValues(const LinePaintProperties::Evaluated& properties,
+LineSDFProgram::uniformValues(const RenderLinePaintProperties::PossiblyEvaluated& properties,
float pixelRatio,
const RenderTile& tile,
const TransformState& state,
const std::array<float, 2>& pixelsToGLUnits,
const LinePatternPos& posA,
const LinePatternPos& posB,
- float dashLineWidth,
float atlasWidth) {
- const float widthA = posA.width * properties.get<LineDasharray>().fromScale * dashLineWidth;
- const float widthB = posB.width * properties.get<LineDasharray>().toScale * dashLineWidth;
+ const float widthA = posA.width * properties.get<LineDasharray>().fromScale;
+ const float widthB = posB.width * properties.get<LineDasharray>().toScale;
std::array<float, 2> scaleA {{
1.0f / tile.id.pixelsToTileUnits(widthA, state.getIntegerZoom()),
@@ -84,20 +82,21 @@ LineSDFProgram::uniformValues(const LinePaintProperties::Evaluated& properties,
}
LinePatternProgram::UniformValues
-LinePatternProgram::uniformValues(const LinePaintProperties::Evaluated& properties,
+LinePatternProgram::uniformValues(const RenderLinePaintProperties::PossiblyEvaluated& properties,
const RenderTile& tile,
const TransformState& state,
const std::array<float, 2>& pixelsToGLUnits,
- const SpriteAtlasElement& posA,
- const SpriteAtlasElement& posB) {
+ const Size atlasSize,
+ const ImagePosition& posA,
+ const ImagePosition& posB) {
std::array<float, 2> sizeA {{
- tile.id.pixelsToTileUnits(posA.size[0] * properties.get<LinePattern>().fromScale, state.getIntegerZoom()),
- posA.size[1]
+ tile.id.pixelsToTileUnits(posA.displaySize()[0] * properties.get<LinePattern>().fromScale, state.getIntegerZoom()),
+ posA.displaySize()[1]
}};
std::array<float, 2> sizeB {{
- tile.id.pixelsToTileUnits(posB.size[0] * properties.get<LinePattern>().toScale, state.getIntegerZoom()),
- posB.size[1]
+ tile.id.pixelsToTileUnits(posB.displaySize()[0] * properties.get<LinePattern>().toScale, state.getIntegerZoom()),
+ posB.displaySize()[1]
}};
return makeValues<LinePatternProgram::UniformValues>(
@@ -105,12 +104,13 @@ LinePatternProgram::uniformValues(const LinePaintProperties::Evaluated& properti
tile,
state,
pixelsToGLUnits,
- uniforms::u_pattern_tl_a::Value{ posA.tl },
- uniforms::u_pattern_br_a::Value{ posA.br },
- uniforms::u_pattern_tl_b::Value{ posB.tl },
- uniforms::u_pattern_br_b::Value{ posB.br },
+ uniforms::u_pattern_tl_a::Value{ posA.tl() },
+ uniforms::u_pattern_br_a::Value{ posA.br() },
+ uniforms::u_pattern_tl_b::Value{ posB.tl() },
+ uniforms::u_pattern_br_b::Value{ posB.br() },
uniforms::u_pattern_size_a::Value{ sizeA },
uniforms::u_pattern_size_b::Value{ sizeB },
+ uniforms::u_texsize::Value{ atlasSize },
uniforms::u_fade::Value{ properties.get<LinePattern>().t },
uniforms::u_image::Value{ 0 }
);
diff --git a/src/mbgl/programs/line_program.hpp b/src/mbgl/programs/line_program.hpp
index b2e55a4f3b..ed4a09bf10 100644
--- a/src/mbgl/programs/line_program.hpp
+++ b/src/mbgl/programs/line_program.hpp
@@ -7,7 +7,7 @@
#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 <mbgl/renderer/layers/render_line_layer.hpp>
#include <cmath>
@@ -16,11 +16,10 @@ namespace mbgl {
class RenderTile;
class TransformState;
class LinePatternPos;
-class SpriteAtlasElement;
+class ImagePosition;
namespace uniforms {
MBGL_DEFINE_UNIFORM_SCALAR(float, u_ratio);
-MBGL_DEFINE_UNIFORM_SCALAR(float, u_width);
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);
@@ -41,10 +40,9 @@ class LineProgram : public Program<
LineLayoutAttributes,
gl::Uniforms<
uniforms::u_matrix,
- uniforms::u_width,
uniforms::u_ratio,
uniforms::u_gl_units_to_pixels>,
- style::LinePaintProperties>
+ RenderLinePaintProperties>
{
public:
using Program::Program;
@@ -91,7 +89,7 @@ public:
*/
static const int8_t extrudeScale = 63;
- static UniformValues uniformValues(const style::LinePaintProperties::Evaluated&,
+ static UniformValues uniformValues(const RenderLinePaintProperties::PossiblyEvaluated&,
const RenderTile&,
const TransformState&,
const std::array<float, 2>& pixelsToGLUnits);
@@ -103,7 +101,6 @@ class LinePatternProgram : public Program<
LineLayoutAttributes,
gl::Uniforms<
uniforms::u_matrix,
- uniforms::u_width,
uniforms::u_ratio,
uniforms::u_gl_units_to_pixels,
uniforms::u_pattern_tl_a,
@@ -112,19 +109,21 @@ class LinePatternProgram : public Program<
uniforms::u_pattern_br_b,
uniforms::u_pattern_size_a,
uniforms::u_pattern_size_b,
+ uniforms::u_texsize,
uniforms::u_fade,
uniforms::u_image>,
- style::LinePaintProperties>
+ RenderLinePaintProperties>
{
public:
using Program::Program;
- static UniformValues uniformValues(const style::LinePaintProperties::Evaluated&,
+ static UniformValues uniformValues(const RenderLinePaintProperties::PossiblyEvaluated&,
const RenderTile&,
const TransformState&,
const std::array<float, 2>& pixelsToGLUnits,
- const SpriteAtlasElement& posA,
- const SpriteAtlasElement& posB);
+ Size atlasSize,
+ const ImagePosition& posA,
+ const ImagePosition& posB);
};
class LineSDFProgram : public Program<
@@ -133,7 +132,6 @@ class LineSDFProgram : public Program<
LineLayoutAttributes,
gl::Uniforms<
uniforms::u_matrix,
- uniforms::u_width,
uniforms::u_ratio,
uniforms::u_gl_units_to_pixels,
uniforms::u_patternscale_a,
@@ -143,19 +141,18 @@ class LineSDFProgram : public Program<
uniforms::u_mix,
uniforms::u_sdfgamma,
uniforms::u_image>,
- style::LinePaintProperties>
+ RenderLinePaintProperties>
{
public:
using Program::Program;
- static UniformValues uniformValues(const style::LinePaintProperties::Evaluated&,
+ static UniformValues uniformValues(const RenderLinePaintProperties::PossiblyEvaluated&,
float pixelRatio,
const RenderTile&,
const TransformState&,
const std::array<float, 2>& pixelsToGLUnits,
const LinePatternPos& posA,
const LinePatternPos& posB,
- float dashLineWidth,
float atlasWidth);
};
diff --git a/src/mbgl/programs/program.hpp b/src/mbgl/programs/program.hpp
index bbe4885745..3a38f30a86 100644
--- a/src/mbgl/programs/program.hpp
+++ b/src/mbgl/programs/program.hpp
@@ -56,7 +56,7 @@ public:
const gl::IndexBuffer<DrawMode>& indexBuffer,
const gl::SegmentVector<Attributes>& segments,
const PaintPropertyBinders& paintPropertyBinders,
- const typename PaintProperties::Evaluated& currentProperties,
+ const typename PaintProperties::PossiblyEvaluated& currentProperties,
float currentZoom) {
program.draw(
context,
@@ -66,7 +66,7 @@ public:
std::move(colorMode),
uniformValues
.concat(paintPropertyBinders.uniformValues(currentZoom, currentProperties)),
- LayoutAttributes::allVariableBindings(layoutVertexBuffer)
+ LayoutAttributes::bindings(layoutVertexBuffer)
.concat(paintPropertyBinders.attributeBindings(currentProperties)),
indexBuffer,
segments
@@ -86,7 +86,7 @@ public:
parameters(std::move(parameters_)) {
}
- Program& get(const typename PaintProperties::Evaluated& currentProperties) {
+ Program& get(const typename PaintProperties::PossiblyEvaluated& currentProperties) {
Bitset bits = PaintPropertyBinders::constants(currentProperties);
auto it = programs.find(bits);
if (it != programs.end()) {
diff --git a/src/mbgl/programs/symbol_program.cpp b/src/mbgl/programs/symbol_program.cpp
index 86f61c4ad2..cdbd6b9713 100644
--- a/src/mbgl/programs/symbol_program.cpp
+++ b/src/mbgl/programs/symbol_program.cpp
@@ -51,7 +51,7 @@ Values makeValues(const bool isText,
values.translateAnchor,
state) },
uniforms::u_extrude_scale::Value{ extrudeScale },
- uniforms::u_texsize::Value{ std::array<float, 2> {{ float(texsize.width) / 4, float(texsize.height) / 4 }} },
+ uniforms::u_texsize::Value{ texsize },
uniforms::u_zoom::Value{ float(state.getZoom()) },
uniforms::u_rotate_with_map::Value{ values.rotationAlignment == AlignmentType::Map },
uniforms::u_texture::Value{ 0 },
diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp
index 01e95f456d..e7c428034b 100644
--- a/src/mbgl/programs/symbol_program.hpp
+++ b/src/mbgl/programs/symbol_program.hpp
@@ -13,7 +13,7 @@
#include <mbgl/util/size.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
-#include <mbgl/renderer/render_symbol_layer.hpp>
+#include <mbgl/renderer/layers/render_symbol_layer.hpp>
#include <cmath>
@@ -29,7 +29,6 @@ class RenderTile;
class TransformState;
namespace uniforms {
-MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_texsize);
MBGL_DEFINE_UNIFORM_SCALAR(bool, u_rotate_with_map);
MBGL_DEFINE_UNIFORM_SCALAR(bool, u_pitch_with_map);
MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_texture);
@@ -67,8 +66,8 @@ struct SymbolLayoutAttributes : gl::Attributes<
static_cast<int16_t>(::round(o.y * 64))
}},
{{
- static_cast<uint16_t>(tx / 4),
- static_cast<uint16_t>(ty / 4),
+ tx,
+ ty,
mbgl::attributes::packUint8Pair(
static_cast<uint8_t>(labelminzoom * 10), // 1/10 zoom levels: z16 == 160
static_cast<uint8_t>(labelangle)
@@ -107,7 +106,7 @@ public:
const style::DataDrivenPropertyValue<float>& sizeProperty,
const float defaultValue);
- virtual SymbolSizeAttributes::Bindings attributeBindings(const PossiblyEvaluatedPropertyValue<float> currentValue) const = 0;
+ virtual SymbolSizeAttributes::Bindings attributeBindings() const = 0;
virtual void populateVertexVector(const GeometryTileFeature& feature) = 0;
virtual UniformValues uniformValues(float currentZoom) const = 0;
virtual void upload(gl::Context&) = 0;
@@ -122,7 +121,7 @@ Range<float> getCoveringStops(Stops s, float lowerZoom, float upperZoom) {
// lower_bound yields first element >= lowerZoom, but we want the *last*
// element <= lowerZoom, so if we found a stop > lowerZoom, back up by one.
- if (minIt != s.stops.begin() && minIt->first > lowerZoom) {
+ if (minIt != s.stops.begin() && minIt != s.stops.end() && minIt->first > lowerZoom) {
minIt--;
}
return Range<float> {
@@ -133,8 +132,6 @@ Range<float> getCoveringStops(Stops s, float lowerZoom, float upperZoom) {
class ConstantSymbolSizeBinder final : public SymbolSizeBinder {
public:
- using PropertyValue = variant<float, style::CameraFunction<float>>;
-
ConstantSymbolSizeBinder(const float /*tileZoom*/, const float& size, const float /*defaultValue*/)
: layoutSize(size) {}
@@ -145,9 +142,10 @@ public:
: layoutSize(function_.evaluate(tileZoom + 1)) {
function_.stops.match(
[&] (const style::ExponentialStops<float>& stops) {
+ const auto& zoomLevels = getCoveringStops(stops, tileZoom, tileZoom + 1);
coveringRanges = std::make_tuple(
- getCoveringStops(stops, tileZoom, tileZoom + 1),
- Range<float> { function_.evaluate(tileZoom), function_.evaluate(tileZoom + 1) }
+ zoomLevels,
+ Range<float> { function_.evaluate(zoomLevels.min), function_.evaluate(zoomLevels.max) }
);
functionInterpolationBase = stops.base;
},
@@ -157,9 +155,10 @@ public:
);
}
- SymbolSizeAttributes::Bindings attributeBindings(const PossiblyEvaluatedPropertyValue<float>) const override {
- return SymbolSizeAttributes::Bindings { SymbolSizeAttributes::Attribute::ConstantBinding {{{0, 0, 0}}} };
+ SymbolSizeAttributes::Bindings attributeBindings() const override {
+ return SymbolSizeAttributes::Bindings { gl::DisabledAttribute() };
}
+
void upload(gl::Context&) override {}
void populateVertexVector(const GeometryTileFeature&) override {};
@@ -211,14 +210,10 @@ public:
defaultValue(defaultValue_) {
}
- SymbolSizeAttributes::Bindings attributeBindings(const PossiblyEvaluatedPropertyValue<float> currentValue) const override {
- if (currentValue.isConstant()) {
- return SymbolSizeAttributes::Bindings { SymbolSizeAttributes::Attribute::ConstantBinding {{{0, 0, 0}}} };
- }
-
- return SymbolSizeAttributes::Bindings { SymbolSizeAttributes::Attribute::variableBinding(*buffer, 0, 1) };
+ SymbolSizeAttributes::Bindings attributeBindings() const override {
+ return SymbolSizeAttributes::Bindings { SymbolSizeAttributes::Attribute::binding(*buffer, 0, 1) };
}
-
+
void populateVertexVector(const GeometryTileFeature& feature) override {
const auto sizeVertex = Vertex {
{{
@@ -268,12 +263,8 @@ public:
return getCoveringStops(stops, tileZoom, tileZoom + 1); }))
{}
- SymbolSizeAttributes::Bindings attributeBindings(const PossiblyEvaluatedPropertyValue<float> currentValue) const override {
- if (currentValue.isConstant()) {
- return SymbolSizeAttributes::Bindings { SymbolSizeAttributes::Attribute::ConstantBinding {{{0, 0, 0}}} };
- }
-
- return SymbolSizeAttributes::Bindings { SymbolSizeAttributes::Attribute::variableBinding(*buffer, 0) };
+ SymbolSizeAttributes::Bindings attributeBindings() const override {
+ return SymbolSizeAttributes::Bindings { SymbolSizeAttributes::Attribute::binding(*buffer, 0) };
}
void populateVertexVector(const GeometryTileFeature& feature) override {
@@ -364,11 +355,10 @@ public:
UniformValues&& uniformValues,
const gl::VertexBuffer<LayoutVertex>& layoutVertexBuffer,
const SymbolSizeBinder& symbolSizeBinder,
- const PossiblyEvaluatedPropertyValue<float>& currentSizeValue,
const gl::IndexBuffer<DrawMode>& indexBuffer,
const gl::SegmentVector<Attributes>& segments,
const PaintPropertyBinders& paintPropertyBinders,
- const typename PaintProperties::Evaluated& currentProperties,
+ const typename PaintProperties::PossiblyEvaluated& currentProperties,
float currentZoom) {
program.draw(
context,
@@ -379,8 +369,8 @@ public:
uniformValues
.concat(symbolSizeBinder.uniformValues(currentZoom))
.concat(paintPropertyBinders.uniformValues(currentZoom, currentProperties)),
- LayoutAttributes::allVariableBindings(layoutVertexBuffer)
- .concat(symbolSizeBinder.attributeBindings(currentSizeValue))
+ LayoutAttributes::bindings(layoutVertexBuffer)
+ .concat(symbolSizeBinder.attributeBindings())
.concat(paintPropertyBinders.attributeBindings(currentProperties)),
indexBuffer,
segments
diff --git a/src/mbgl/programs/uniforms.hpp b/src/mbgl/programs/uniforms.hpp
index 60a50a7cb2..f1b2c2fb54 100644
--- a/src/mbgl/programs/uniforms.hpp
+++ b/src/mbgl/programs/uniforms.hpp
@@ -27,16 +27,19 @@ MBGL_DEFINE_UNIFORM_SCALAR(float, u_halo_blur);
MBGL_DEFINE_UNIFORM_SCALAR(Color, u_outline_color);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_height);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_base);
-MBGL_DEFINE_UNIFORM_SCALAR(float, u_gap_width);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_width);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_floorwidth);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_gapwidth);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_offset);
MBGL_DEFINE_UNIFORM_SCALAR(Size, u_world);
+MBGL_DEFINE_UNIFORM_SCALAR(Size, u_texsize);
MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_extrude_scale);
-MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_tl_a);
-MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_br_a);
-MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_tl_b);
-MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_br_b);
+MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 2, u_pattern_tl_a);
+MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 2, u_pattern_br_a);
+MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 2, u_pattern_tl_b);
+MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 2, u_pattern_br_b);
MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_size_a);
MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_size_b);
MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pixel_coord_upper);
diff --git a/src/mbgl/renderer/bucket_parameters.hpp b/src/mbgl/renderer/bucket_parameters.hpp
index 1774ba2bbe..50ec4cf521 100644
--- a/src/mbgl/renderer/bucket_parameters.hpp
+++ b/src/mbgl/renderer/bucket_parameters.hpp
@@ -9,6 +9,7 @@ class BucketParameters {
public:
const OverscaledTileID tileID;
const MapMode mode;
+ const float pixelRatio;
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/circle_bucket.cpp b/src/mbgl/renderer/buckets/circle_bucket.cpp
index 1e08eca478..8b5743d500 100644
--- a/src/mbgl/renderer/circle_bucket.cpp
+++ b/src/mbgl/renderer/buckets/circle_bucket.cpp
@@ -1,9 +1,9 @@
-#include <mbgl/renderer/circle_bucket.hpp>
+#include <mbgl/renderer/buckets/circle_bucket.hpp>
#include <mbgl/renderer/bucket_parameters.hpp>
#include <mbgl/renderer/painter.hpp>
#include <mbgl/programs/circle_program.hpp>
#include <mbgl/style/layers/circle_layer_impl.hpp>
-#include <mbgl/renderer/render_circle_layer.hpp>
+#include <mbgl/renderer/layers/render_circle_layer.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/math.hpp>
diff --git a/src/mbgl/renderer/circle_bucket.hpp b/src/mbgl/renderer/buckets/circle_bucket.hpp
index b048fd7675..b048fd7675 100644
--- a/src/mbgl/renderer/circle_bucket.hpp
+++ b/src/mbgl/renderer/buckets/circle_bucket.hpp
diff --git a/src/mbgl/renderer/debug_bucket.cpp b/src/mbgl/renderer/buckets/debug_bucket.cpp
index 2a514989cf..acfe15d2fb 100644
--- a/src/mbgl/renderer/debug_bucket.cpp
+++ b/src/mbgl/renderer/buckets/debug_bucket.cpp
@@ -1,4 +1,4 @@
-#include <mbgl/renderer/debug_bucket.hpp>
+#include <mbgl/renderer/buckets/debug_bucket.hpp>
#include <mbgl/renderer/painter.hpp>
#include <mbgl/programs/fill_program.hpp>
#include <mbgl/geometry/debug_font_data.hpp>
diff --git a/src/mbgl/renderer/debug_bucket.hpp b/src/mbgl/renderer/buckets/debug_bucket.hpp
index 756e58a6de..756e58a6de 100644
--- a/src/mbgl/renderer/debug_bucket.hpp
+++ b/src/mbgl/renderer/buckets/debug_bucket.hpp
diff --git a/src/mbgl/renderer/fill_bucket.cpp b/src/mbgl/renderer/buckets/fill_bucket.cpp
index 2409fd365b..042d7b7506 100644
--- a/src/mbgl/renderer/fill_bucket.cpp
+++ b/src/mbgl/renderer/buckets/fill_bucket.cpp
@@ -1,9 +1,9 @@
-#include <mbgl/renderer/fill_bucket.hpp>
+#include <mbgl/renderer/buckets/fill_bucket.hpp>
#include <mbgl/renderer/painter.hpp>
#include <mbgl/programs/fill_program.hpp>
#include <mbgl/renderer/bucket_parameters.hpp>
#include <mbgl/style/layers/fill_layer_impl.hpp>
-#include <mbgl/renderer/render_fill_layer.hpp>
+#include <mbgl/renderer/layers/render_fill_layer.hpp>
#include <mbgl/util/math.hpp>
#include <mapbox/earcut.hpp>
diff --git a/src/mbgl/renderer/fill_bucket.hpp b/src/mbgl/renderer/buckets/fill_bucket.hpp
index 421d8b332b..421d8b332b 100644
--- a/src/mbgl/renderer/fill_bucket.hpp
+++ b/src/mbgl/renderer/buckets/fill_bucket.hpp
diff --git a/src/mbgl/renderer/fill_extrusion_bucket.cpp b/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp
index 2b352ab66a..f61f1d1549 100644
--- a/src/mbgl/renderer/fill_extrusion_bucket.cpp
+++ b/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp
@@ -1,9 +1,9 @@
-#include <mbgl/renderer/fill_extrusion_bucket.hpp>
+#include <mbgl/renderer/buckets/fill_extrusion_bucket.hpp>
#include <mbgl/renderer/painter.hpp>
#include <mbgl/programs/fill_extrusion_program.hpp>
#include <mbgl/renderer/bucket_parameters.hpp>
#include <mbgl/style/layers/fill_extrusion_layer_impl.hpp>
-#include <mbgl/renderer/render_fill_extrusion_layer.hpp>
+#include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp>
#include <mbgl/util/math.hpp>
#include <mbgl/util/constants.hpp>
diff --git a/src/mbgl/renderer/fill_extrusion_bucket.hpp b/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp
index c54805d743..c54805d743 100644
--- a/src/mbgl/renderer/fill_extrusion_bucket.hpp
+++ b/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp
diff --git a/src/mbgl/renderer/line_bucket.cpp b/src/mbgl/renderer/buckets/line_bucket.cpp
index 7bb4e2f202..3af3cd63d3 100644
--- a/src/mbgl/renderer/line_bucket.cpp
+++ b/src/mbgl/renderer/buckets/line_bucket.cpp
@@ -1,6 +1,6 @@
-#include <mbgl/renderer/line_bucket.hpp>
+#include <mbgl/renderer/buckets/line_bucket.hpp>
#include <mbgl/renderer/painter.hpp>
-#include <mbgl/renderer/render_line_layer.hpp>
+#include <mbgl/renderer/layers/render_line_layer.hpp>
#include <mbgl/renderer/bucket_parameters.hpp>
#include <mbgl/style/layers/line_layer_impl.hpp>
#include <mbgl/util/math.hpp>
@@ -14,7 +14,7 @@ using namespace style;
LineBucket::LineBucket(const BucketParameters& parameters,
const std::vector<const RenderLayer*>& layers,
- const style::LineLayoutProperties& layout_)
+ const style::LineLayoutProperties::Unevaluated& layout_)
: layout(layout_.evaluate(PropertyEvaluationParameters(parameters.tileID.overscaledZ))),
overscaling(parameters.tileID.overscaleFactor()) {
for (const auto& layer : layers) {
@@ -183,7 +183,7 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates, FeatureType
const bool isSharpCorner = cosHalfAngle < COS_HALF_SHARP_CORNER && prevCoordinate && nextCoordinate;
if (isSharpCorner && i > first) {
- const double prevSegmentLength = util::dist<double>(*currentCoordinate, *prevCoordinate);
+ const auto prevSegmentLength = util::dist<double>(*currentCoordinate, *prevCoordinate);
if (prevSegmentLength > 2.0 * sharpCornerOffset) {
GeometryCoordinate newPrevVertex = *currentCoordinate - convertPoint<int16_t>(util::round(convertPoint<double>(*currentCoordinate - *prevCoordinate) * (sharpCornerOffset / prevSegmentLength)));
distance += util::dist<double>(newPrevVertex, *prevCoordinate);
@@ -356,7 +356,7 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates, FeatureType
}
if (isSharpCorner && i < len - 1) {
- const double nextSegmentLength = util::dist<double>(*currentCoordinate, *nextCoordinate);
+ const auto nextSegmentLength = util::dist<double>(*currentCoordinate, *nextCoordinate);
if (nextSegmentLength > 2 * sharpCornerOffset) {
GeometryCoordinate newCurrentVertex = *currentCoordinate + convertPoint<int16_t>(util::round(convertPoint<double>(*nextCoordinate - *currentCoordinate) * (sharpCornerOffset / nextSegmentLength)));
distance += util::dist<double>(newCurrentVertex, *currentCoordinate);
@@ -480,7 +480,7 @@ static float get(const RenderLineLayer& layer, const std::map<std::string, LineP
}
float LineBucket::getLineWidth(const RenderLineLayer& layer) const {
- float lineWidth = layer.evaluated.get<LineWidth>();
+ float lineWidth = get<LineWidth>(layer, paintPropertyBinders);
float gapWidth = get<LineGapWidth>(layer, paintPropertyBinders);
if (gapWidth) {
diff --git a/src/mbgl/renderer/line_bucket.hpp b/src/mbgl/renderer/buckets/line_bucket.hpp
index c319548714..34d8935953 100644
--- a/src/mbgl/renderer/line_bucket.hpp
+++ b/src/mbgl/renderer/buckets/line_bucket.hpp
@@ -19,7 +19,7 @@ class LineBucket : public Bucket {
public:
LineBucket(const BucketParameters&,
const std::vector<const RenderLayer*>&,
- const style::LineLayoutProperties&);
+ const style::LineLayoutProperties::Unevaluated&);
void addFeature(const GeometryTileFeature&,
const GeometryCollection&) override;
diff --git a/src/mbgl/renderer/buckets/raster_bucket.cpp b/src/mbgl/renderer/buckets/raster_bucket.cpp
new file mode 100644
index 0000000000..49ec0065c3
--- /dev/null
+++ b/src/mbgl/renderer/buckets/raster_bucket.cpp
@@ -0,0 +1,53 @@
+#include <mbgl/renderer/buckets/raster_bucket.hpp>
+#include <mbgl/renderer/layers/render_raster_layer.hpp>
+#include <mbgl/programs/raster_program.hpp>
+#include <mbgl/renderer/painter.hpp>
+#include <mbgl/gl/context.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+RasterBucket::RasterBucket(UnassociatedImage&& image_) : image(std::move(image_)) {
+}
+
+void RasterBucket::upload(gl::Context& context) {
+ if (!texture) {
+ texture = context.createTexture(image);
+ }
+ if (!vertices.empty()) {
+ vertexBuffer = context.createVertexBuffer(std::move(vertices));
+ indexBuffer = context.createIndexBuffer(std::move(indices));
+ }
+ uploaded = true;
+}
+
+void RasterBucket::clear() {
+ vertexBuffer = {};
+ indexBuffer = {};
+ segments.clear();
+ vertices.clear();
+ indices.clear();
+
+ uploaded = false;
+}
+void RasterBucket::render(Painter& painter,
+ PaintParameters& parameters,
+ const RenderLayer& layer,
+ const RenderTile& tile) {
+ painter.renderRaster(parameters, *this, *layer.as<RenderRasterLayer>(), tile.matrix, false);
+}
+
+void RasterBucket::render(Painter& painter,
+ PaintParameters& parameters,
+ const RenderLayer& layer,
+ const mat4& matrix) {
+ painter.renderRaster(parameters, *this, *layer.as<RenderRasterLayer>(), matrix, true);
+}
+
+bool RasterBucket::hasData() const {
+ return true;
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/buckets/raster_bucket.hpp b/src/mbgl/renderer/buckets/raster_bucket.hpp
new file mode 100644
index 0000000000..b5cf7997d5
--- /dev/null
+++ b/src/mbgl/renderer/buckets/raster_bucket.hpp
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <mbgl/gl/index_buffer.hpp>
+#include <mbgl/gl/texture.hpp>
+#include <mbgl/gl/vertex_buffer.hpp>
+#include <mbgl/programs/raster_program.hpp>
+#include <mbgl/renderer/bucket.hpp>
+#include <mbgl/util/image.hpp>
+#include <mbgl/util/mat4.hpp>
+#include <mbgl/util/optional.hpp>
+
+namespace mbgl {
+
+class RasterBucket : public Bucket {
+public:
+ RasterBucket(UnassociatedImage&&);
+
+ void upload(gl::Context&) override;
+ void render(Painter&, PaintParameters&, const RenderLayer&, const RenderTile&) override;
+ void render(Painter& painter,
+ PaintParameters& parameters,
+ const RenderLayer& layer,
+ const mat4& matrix);
+ bool hasData() const override;
+
+ void clear();
+ UnassociatedImage image;
+ optional<gl::Texture> texture;
+
+ // Bucket specific vertices are used for Image Sources only
+ // Raster Tile Sources use the default buffers from Painter
+ gl::VertexVector<RasterLayoutVertex> vertices;
+ gl::IndexVector<gl::Triangles> indices;
+ gl::SegmentVector<RasterAttributes> segments;
+
+ optional<gl::VertexBuffer<RasterLayoutVertex>> vertexBuffer;
+ optional<gl::IndexBuffer<gl::Triangles>> indexBuffer;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp
index 9b016c16f9..cbddade899 100644
--- a/src/mbgl/renderer/symbol_bucket.cpp
+++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp
@@ -1,8 +1,9 @@
-#include <mbgl/renderer/symbol_bucket.hpp>
+#include <mbgl/renderer/buckets/symbol_bucket.hpp>
#include <mbgl/renderer/painter.hpp>
-#include <mbgl/renderer/render_symbol_layer.hpp>
+#include <mbgl/renderer/layers/render_symbol_layer.hpp>
#include <mbgl/renderer/bucket_parameters.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
+#include <mbgl/text/glyph_atlas.hpp>
namespace mbgl {
@@ -10,7 +11,8 @@ using namespace style;
SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated layout_,
const std::map<std::string, std::pair<
- style::IconPaintProperties::Evaluated, style::TextPaintProperties::Evaluated>>& layerPaintProperties,
+ style::IconPaintProperties::PossiblyEvaluated,
+ style::TextPaintProperties::PossiblyEvaluated>>& layerPaintProperties,
const style::DataDrivenPropertyValue<float>& textSize,
const style::DataDrivenPropertyValue<float>& iconSize,
float zoom,
diff --git a/src/mbgl/renderer/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp
index f7e4bcfa20..002b6e28b3 100644
--- a/src/mbgl/renderer/symbol_bucket.hpp
+++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp
@@ -18,7 +18,7 @@ namespace mbgl {
class SymbolBucket : public Bucket {
public:
SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated,
- const std::map<std::string, std::pair<style::IconPaintProperties::Evaluated, style::TextPaintProperties::Evaluated>>&,
+ const std::map<std::string, std::pair<style::IconPaintProperties::PossiblyEvaluated, style::TextPaintProperties::PossiblyEvaluated>>&,
const style::DataDrivenPropertyValue<float>& textSize,
const style::DataDrivenPropertyValue<float>& iconSize,
float zoom,
@@ -57,6 +57,7 @@ public:
gl::VertexVector<SymbolLayoutVertex> vertices;
gl::IndexVector<gl::Triangles> triangles;
gl::SegmentVector<SymbolIconAttributes> segments;
+ PremultipliedImage atlasImage;
optional<gl::VertexBuffer<SymbolLayoutVertex>> vertexBuffer;
optional<gl::IndexBuffer<gl::Triangles>> indexBuffer;
@@ -70,8 +71,6 @@ public:
optional<gl::VertexBuffer<CollisionBoxVertex>> vertexBuffer;
optional<gl::IndexBuffer<gl::Lines>> indexBuffer;
} collisionBox;
-
- SpriteAtlas* spriteAtlas = nullptr;
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/data_driven_property_evaluator.hpp b/src/mbgl/renderer/data_driven_property_evaluator.hpp
index 6406b3478b..79ecd0d495 100644
--- a/src/mbgl/renderer/data_driven_property_evaluator.hpp
+++ b/src/mbgl/renderer/data_driven_property_evaluator.hpp
@@ -24,12 +24,18 @@ public:
}
ResultType operator()(const style::CameraFunction<T>& function) const {
- return ResultType(function.evaluate(parameters.z));
+ if (!parameters.useIntegerZoom) {
+ return ResultType(function.evaluate(parameters.z));
+ } else {
+ return ResultType(function.evaluate(floor(parameters.z)));
+ }
}
template <class Function>
ResultType operator()(const Function& function) const {
- return ResultType(function);
+ auto returnFunction = function;
+ returnFunction.useIntegerZoom = parameters.useIntegerZoom;
+ return ResultType(returnFunction);
}
private:
diff --git a/src/mbgl/renderer/frame_history.cpp b/src/mbgl/renderer/frame_history.cpp
index 35e246f488..869222b4eb 100644
--- a/src/mbgl/renderer/frame_history.cpp
+++ b/src/mbgl/renderer/frame_history.cpp
@@ -37,9 +37,9 @@ void FrameHistory::record(const TimePoint& now, float zoom, const Duration& dura
}
for (int16_t z = 0; z <= 255; z++) {
- std::chrono::duration<float> timeDiff = now - changeTimes[z];
- int32_t opacityChange = (duration == Milliseconds(0) ? 1 : (timeDiff / duration)) * 255;
- uint8_t opacity = z <= zoomIndex
+ const std::chrono::duration<float> timeDiff = now - changeTimes[z];
+ const int32_t opacityChange = (duration == Milliseconds(0) ? 1 : (timeDiff / duration)) * 255;
+ const uint8_t opacity = z <= zoomIndex
? util::min(255, changeOpacities[z] + opacityChange)
: util::max(0, changeOpacities[z] - opacityChange);
if (opacities.data[z] != opacity) {
diff --git a/src/mbgl/renderer/group_by_layout.cpp b/src/mbgl/renderer/group_by_layout.cpp
index df1eb7c7dd..3b02727ff8 100644
--- a/src/mbgl/renderer/group_by_layout.cpp
+++ b/src/mbgl/renderer/group_by_layout.cpp
@@ -19,13 +19,13 @@ std::string layoutKey(const RenderLayer& layer) {
writer.StartArray();
writer.Uint(static_cast<uint32_t>(layer.type));
- writer.String(layer.baseImpl.source);
- writer.String(layer.baseImpl.sourceLayer);
- writer.Double(layer.baseImpl.minZoom);
- writer.Double(layer.baseImpl.maxZoom);
- writer.Uint(static_cast<uint32_t>(layer.baseImpl.visibility));
- stringify(writer, layer.baseImpl.filter);
- layer.baseImpl.stringifyLayout(writer);
+ writer.String(layer.baseImpl->source);
+ writer.String(layer.baseImpl->sourceLayer);
+ writer.Double(layer.baseImpl->minZoom);
+ writer.Double(layer.baseImpl->maxZoom);
+ writer.Uint(static_cast<uint32_t>(layer.baseImpl->visibility));
+ stringify(writer, layer.baseImpl->filter);
+ layer.baseImpl->stringifyLayout(writer);
writer.EndArray();
return s.GetString();
diff --git a/src/mbgl/renderer/image_atlas.cpp b/src/mbgl/renderer/image_atlas.cpp
new file mode 100644
index 0000000000..8eee7c2095
--- /dev/null
+++ b/src/mbgl/renderer/image_atlas.cpp
@@ -0,0 +1,60 @@
+#include <mbgl/renderer/image_atlas.hpp>
+
+#include <mapbox/shelf-pack.hpp>
+
+namespace mbgl {
+
+static constexpr uint32_t padding = 1;
+
+ImagePosition::ImagePosition(const mapbox::Bin& bin, const style::Image::Impl& image)
+ : pixelRatio(image.pixelRatio),
+ textureRect(
+ bin.x + padding,
+ bin.y + padding,
+ bin.w - padding * 2,
+ bin.h - padding * 2
+ ) {
+}
+
+ImageAtlas makeImageAtlas(const ImageMap& images) {
+ ImageAtlas result;
+
+ mapbox::ShelfPack::ShelfPackOptions options;
+ options.autoResize = true;
+ mapbox::ShelfPack pack(0, 0, options);
+
+ for (const auto& entry : images) {
+ const style::Image::Impl& image = *entry.second;
+
+ const mapbox::Bin& bin = *pack.packOne(-1,
+ image.image.size.width + 2 * padding,
+ image.image.size.height + 2 * padding);
+
+ result.image.resize({
+ static_cast<uint32_t>(pack.width()),
+ static_cast<uint32_t>(pack.height())
+ });
+
+ PremultipliedImage::copy(image.image,
+ result.image,
+ { 0, 0 },
+ {
+ bin.x + padding,
+ bin.y + padding
+ },
+ image.image.size);
+
+ result.positions.emplace(image.id,
+ ImagePosition { bin, image });
+ }
+
+ pack.shrink();
+ result.image.resize({
+ static_cast<uint32_t>(pack.width()),
+ static_cast<uint32_t>(pack.height())
+ });
+
+ return result;
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/image_atlas.hpp b/src/mbgl/renderer/image_atlas.hpp
new file mode 100644
index 0000000000..b3cc166eff
--- /dev/null
+++ b/src/mbgl/renderer/image_atlas.hpp
@@ -0,0 +1,51 @@
+#pragma once
+
+#include <mbgl/style/image_impl.hpp>
+#include <mbgl/util/rect.hpp>
+
+#include <mapbox/shelf-pack.hpp>
+
+#include <array>
+
+namespace mbgl {
+
+class ImagePosition {
+public:
+ ImagePosition(const mapbox::Bin&, const style::Image::Impl&);
+
+ float pixelRatio;
+ Rect<uint16_t> textureRect;
+
+ std::array<uint16_t, 2> tl() const {
+ return {{
+ textureRect.x,
+ textureRect.y
+ }};
+ }
+
+ std::array<uint16_t, 2> br() const {
+ return {{
+ static_cast<uint16_t>(textureRect.x + textureRect.w),
+ static_cast<uint16_t>(textureRect.y + textureRect.h)
+ }};
+ }
+
+ std::array<float, 2> displaySize() const {
+ return {{
+ textureRect.w / pixelRatio,
+ textureRect.h / pixelRatio,
+ }};
+ }
+};
+
+using ImagePositions = std::map<std::string, ImagePosition>;
+
+class ImageAtlas {
+public:
+ PremultipliedImage image;
+ ImagePositions positions;
+};
+
+ImageAtlas makeImageAtlas(const ImageMap&);
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/image_manager.cpp b/src/mbgl/renderer/image_manager.cpp
new file mode 100644
index 0000000000..d0a106ede6
--- /dev/null
+++ b/src/mbgl/renderer/image_manager.cpp
@@ -0,0 +1,166 @@
+#include <mbgl/renderer/image_manager.hpp>
+#include <mbgl/util/logging.hpp>
+#include <mbgl/gl/context.hpp>
+
+namespace mbgl {
+
+void ImageManager::onSpriteLoaded() {
+ loaded = true;
+ for (const auto& entry : requestors) {
+ notify(*entry.first, entry.second);
+ }
+ requestors.clear();
+}
+
+void ImageManager::addImage(Immutable<style::Image::Impl> image_) {
+ assert(images.find(image_->id) == images.end());
+ images.emplace(image_->id, std::move(image_));
+}
+
+void ImageManager::updateImage(Immutable<style::Image::Impl> image_) {
+ removeImage(image_->id);
+ addImage(std::move(image_));
+}
+
+void ImageManager::removeImage(const std::string& id) {
+ assert(images.find(id) != images.end());
+ images.erase(id);
+
+ auto it = patterns.find(id);
+ if (it != patterns.end()) {
+ shelfPack.unref(*it->second.bin);
+ patterns.erase(it);
+ }
+}
+
+const style::Image::Impl* ImageManager::getImage(const std::string& id) const {
+ const auto it = images.find(id);
+ if (it != images.end()) {
+ return it->second.get();
+ }
+ return nullptr;
+}
+
+void ImageManager::getImages(ImageRequestor& requestor, ImageDependencies dependencies) {
+ // If the sprite has been loaded, or if all the icon dependencies are already present
+ // (i.e. if they've been addeded via runtime styling), then notify the requestor immediately.
+ // Otherwise, delay notification until the sprite is loaded. At that point, if any of the
+ // dependencies are still unavailable, we'll just assume they are permanently missing.
+ bool hasAllDependencies = true;
+ if (!isLoaded()) {
+ for (const auto& dependency : dependencies) {
+ if (images.find(dependency) == images.end()) {
+ hasAllDependencies = false;
+ }
+ }
+ }
+ if (isLoaded() || hasAllDependencies) {
+ notify(requestor, dependencies);
+ } else {
+ requestors.emplace(&requestor, std::move(dependencies));
+ }
+}
+
+void ImageManager::removeRequestor(ImageRequestor& requestor) {
+ requestors.erase(&requestor);
+}
+
+void ImageManager::notify(ImageRequestor& requestor, const ImageDependencies& dependencies) const {
+ ImageMap response;
+
+ for (const auto& dependency : dependencies) {
+ auto it = images.find(dependency);
+ if (it != images.end()) {
+ response.emplace(*it);
+ }
+ }
+
+ requestor.onImagesAvailable(response);
+}
+
+void ImageManager::dumpDebugLogs() const {
+ Log::Info(Event::General, "ImageManager::loaded: %d", loaded);
+}
+
+// When copied into the atlas texture, image data is padded by one pixel on each side. Icon
+// images are padded with fully transparent pixels, while pattern images are padded with a
+// copy of the image data wrapped from the opposite side. In both cases, this ensures the
+// correct behavior of GL_LINEAR texture sampling mode.
+static constexpr uint16_t padding = 1;
+
+static mapbox::ShelfPack::ShelfPackOptions shelfPackOptions() {
+ mapbox::ShelfPack::ShelfPackOptions options;
+ options.autoResize = true;
+ return options;
+}
+
+ImageManager::ImageManager()
+ : shelfPack(64, 64, shelfPackOptions()) {
+}
+
+ImageManager::~ImageManager() = default;
+
+optional<ImagePosition> ImageManager::getPattern(const std::string& id) {
+ auto it = patterns.find(id);
+ if (it != patterns.end()) {
+ return it->second.position;
+ }
+
+ const style::Image::Impl* image = getImage(id);
+ if (!image) {
+ return {};
+ }
+
+ const uint16_t width = image->image.size.width + padding * 2;
+ const uint16_t height = image->image.size.height + padding * 2;
+
+ mapbox::Bin* bin = shelfPack.packOne(-1, width, height);
+ if (!bin) {
+ return {};
+ }
+
+ atlasImage.resize(getPixelSize());
+
+ const PremultipliedImage& src = image->image;
+
+ const uint32_t x = bin->x + padding;
+ const uint32_t y = bin->y + padding;
+ const uint32_t w = src.size.width;
+ const uint32_t h = src.size.height;
+
+ PremultipliedImage::copy(src, atlasImage, { 0, 0 }, { x, y }, { w, h });
+
+ // Add 1 pixel wrapped padding on each side of the image.
+ PremultipliedImage::copy(src, atlasImage, { 0, h - 1 }, { x, y - 1 }, { w, 1 }); // T
+ PremultipliedImage::copy(src, atlasImage, { 0, 0 }, { x, y + h }, { w, 1 }); // B
+ PremultipliedImage::copy(src, atlasImage, { w - 1, 0 }, { x - 1, y }, { 1, h }); // L
+ PremultipliedImage::copy(src, atlasImage, { 0, 0 }, { x + w, y }, { 1, h }); // R
+
+ dirty = true;
+
+ return patterns.emplace(id, Pattern { bin, { *bin, *image } }).first->second.position;
+}
+
+Size ImageManager::getPixelSize() const {
+ return Size {
+ static_cast<uint32_t>(shelfPack.width()),
+ static_cast<uint32_t>(shelfPack.height())
+ };
+}
+
+void ImageManager::upload(gl::Context& context, gl::TextureUnit unit) {
+ if (!atlasTexture) {
+ atlasTexture = context.createTexture(atlasImage, unit);
+ } else if (dirty) {
+ context.updateTexture(*atlasTexture, atlasImage, unit);
+ }
+
+ dirty = false;
+}
+
+void ImageManager::bind(gl::Context& context, gl::TextureUnit unit) {
+ upload(context, unit);
+ context.bindTexture(*atlasTexture, unit, gl::TextureFilter::Linear);
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/image_manager.hpp b/src/mbgl/renderer/image_manager.hpp
new file mode 100644
index 0000000000..9a9a4ce997
--- /dev/null
+++ b/src/mbgl/renderer/image_manager.hpp
@@ -0,0 +1,94 @@
+#pragma once
+
+#include <mbgl/style/image_impl.hpp>
+#include <mbgl/renderer/image_atlas.hpp>
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/immutable.hpp>
+#include <mbgl/util/optional.hpp>
+#include <mbgl/gl/texture.hpp>
+
+#include <mapbox/shelf-pack.hpp>
+
+#include <set>
+#include <string>
+
+namespace mbgl {
+
+namespace gl {
+class Context;
+} // namespace gl
+
+class ImageRequestor {
+public:
+ virtual ~ImageRequestor() = default;
+ virtual void onImagesAvailable(ImageMap) = 0;
+};
+
+/*
+ ImageManager does two things:
+
+ 1. Tracks requests for icon images from tile workers and sends responses when the requests are fulfilled.
+ 2. Builds a texture atlas for pattern images.
+
+ These are disparate responsibilities and should eventually be handled by different classes. When we implement
+ data-driven support for `*-pattern`, we'll likely use per-bucket pattern atlases, and that would be a good time
+ to refactor this.
+*/
+class ImageManager : public util::noncopyable {
+public:
+ ImageManager();
+ ~ImageManager();
+
+ void onSpriteLoaded();
+
+ bool isLoaded() const {
+ return loaded;
+ }
+
+ void dumpDebugLogs() const;
+
+ const style::Image::Impl* getImage(const std::string&) const;
+
+ void addImage(Immutable<style::Image::Impl>);
+ void updateImage(Immutable<style::Image::Impl>);
+ void removeImage(const std::string&);
+
+ void getImages(ImageRequestor&, ImageDependencies);
+ void removeRequestor(ImageRequestor&);
+
+private:
+ void notify(ImageRequestor&, const ImageDependencies&) const;
+
+ bool loaded = false;
+
+ std::unordered_map<ImageRequestor*, ImageDependencies> requestors;
+ ImageMap images;
+
+// Pattern stuff
+public:
+ optional<ImagePosition> getPattern(const std::string& name);
+
+ void bind(gl::Context&, gl::TextureUnit unit);
+ void upload(gl::Context&, gl::TextureUnit unit);
+
+ Size getPixelSize() const;
+
+ // Only for use in tests.
+ const PremultipliedImage& getAtlasImage() const {
+ return atlasImage;
+ }
+
+private:
+ struct Pattern {
+ mapbox::Bin* bin;
+ ImagePosition position;
+ };
+
+ mapbox::ShelfPack shelfPack;
+ std::unordered_map<std::string, Pattern> patterns;
+ PremultipliedImage atlasImage;
+ mbgl::optional<gl::Texture> atlasTexture;
+ bool dirty = true;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_background_layer.cpp b/src/mbgl/renderer/layers/render_background_layer.cpp
index 485d4b16c6..702977cd23 100644
--- a/src/mbgl/renderer/render_background_layer.cpp
+++ b/src/mbgl/renderer/layers/render_background_layer.cpp
@@ -1,16 +1,16 @@
-#include <mbgl/renderer/render_background_layer.hpp>
+#include <mbgl/renderer/layers/render_background_layer.hpp>
#include <mbgl/style/layers/background_layer_impl.hpp>
#include <mbgl/renderer/bucket.hpp>
namespace mbgl {
-RenderBackgroundLayer::RenderBackgroundLayer(const style::BackgroundLayer::Impl& _impl)
- : RenderLayer(style::LayerType::Background, _impl),
- impl(&_impl) {
+RenderBackgroundLayer::RenderBackgroundLayer(Immutable<style::BackgroundLayer::Impl> _impl)
+ : RenderLayer(style::LayerType::Background, _impl),
+ unevaluated(impl().paint.untransitioned()) {
}
-std::unique_ptr<RenderLayer> RenderBackgroundLayer::clone() const {
- return std::make_unique<RenderBackgroundLayer>(*this);
+const style::BackgroundLayer::Impl& RenderBackgroundLayer::impl() const {
+ return static_cast<const style::BackgroundLayer::Impl&>(*baseImpl);
}
std::unique_ptr<Bucket> RenderBackgroundLayer::createBucket(const BucketParameters &,
@@ -19,8 +19,8 @@ std::unique_ptr<Bucket> RenderBackgroundLayer::createBucket(const BucketParamete
return nullptr;
}
-void RenderBackgroundLayer::cascade(const CascadeParameters &parameters) {
- unevaluated = impl->cascading.cascade(parameters, std::move(unevaluated));
+void RenderBackgroundLayer::transition(const TransitionParameters &parameters) {
+ unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated));
}
void RenderBackgroundLayer::evaluate(const PropertyEvaluationParameters &parameters) {
@@ -34,4 +34,4 @@ bool RenderBackgroundLayer::hasTransition() const {
return unevaluated.hasTransition();
}
-}
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_background_layer.hpp b/src/mbgl/renderer/layers/render_background_layer.hpp
index b1f709953f..0fba3d2bb1 100644
--- a/src/mbgl/renderer/render_background_layer.hpp
+++ b/src/mbgl/renderer/layers/render_background_layer.hpp
@@ -1,20 +1,17 @@
#pragma once
#include <mbgl/renderer/render_layer.hpp>
-#include <mbgl/style/layers/background_layer.hpp>
+#include <mbgl/style/layers/background_layer_impl.hpp>
#include <mbgl/style/layers/background_layer_properties.hpp>
namespace mbgl {
class RenderBackgroundLayer: public RenderLayer {
public:
-
- RenderBackgroundLayer(const style::BackgroundLayer::Impl&);
+ RenderBackgroundLayer(Immutable<style::BackgroundLayer::Impl>);
~RenderBackgroundLayer() final = default;
- std::unique_ptr<RenderLayer> clone() const override;
-
- void cascade(const CascadeParameters&) override;
+ void transition(const TransitionParameters&) override;
void evaluate(const PropertyEvaluationParameters&) override;
bool hasTransition() const override;
@@ -22,9 +19,9 @@ public:
// Paint properties
style::BackgroundPaintProperties::Unevaluated unevaluated;
- style::BackgroundPaintProperties::Evaluated evaluated;
+ style::BackgroundPaintProperties::PossiblyEvaluated evaluated;
- const style::BackgroundLayer::Impl* const impl;
+ const style::BackgroundLayer::Impl& impl() const;
};
template <>
@@ -32,4 +29,4 @@ inline bool RenderLayer::is<RenderBackgroundLayer>() const {
return type == style::LayerType::Background;
}
-}
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_circle_layer.cpp b/src/mbgl/renderer/layers/render_circle_layer.cpp
index f59c174dd3..51a5ecd7d6 100644
--- a/src/mbgl/renderer/render_circle_layer.cpp
+++ b/src/mbgl/renderer/layers/render_circle_layer.cpp
@@ -1,5 +1,5 @@
-#include <mbgl/renderer/render_circle_layer.hpp>
-#include <mbgl/renderer/circle_bucket.hpp>
+#include <mbgl/renderer/layers/render_circle_layer.hpp>
+#include <mbgl/renderer/buckets/circle_bucket.hpp>
#include <mbgl/style/layers/circle_layer_impl.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/util/math.hpp>
@@ -7,21 +7,21 @@
namespace mbgl {
-RenderCircleLayer::RenderCircleLayer(const style::CircleLayer::Impl& _impl)
- : RenderLayer(style::LayerType::Circle, _impl),
- impl(&_impl) {
+RenderCircleLayer::RenderCircleLayer(Immutable<style::CircleLayer::Impl> _impl)
+ : RenderLayer(style::LayerType::Circle, _impl),
+ unevaluated(impl().paint.untransitioned()) {
}
-std::unique_ptr<RenderLayer> RenderCircleLayer::clone() const {
- return std::make_unique<RenderCircleLayer>(*this);
+const style::CircleLayer::Impl& RenderCircleLayer::impl() const {
+ return static_cast<const style::CircleLayer::Impl&>(*baseImpl);
}
std::unique_ptr<Bucket> RenderCircleLayer::createBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) const {
return std::make_unique<CircleBucket>(parameters, layers);
}
-void RenderCircleLayer::cascade(const CascadeParameters& parameters) {
- unevaluated = impl->cascading.cascade(parameters, std::move(unevaluated));
+void RenderCircleLayer::transition(const TransitionParameters& parameters) {
+ unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated));
}
void RenderCircleLayer::evaluate(const PropertyEvaluationParameters& parameters) {
@@ -64,4 +64,4 @@ bool RenderCircleLayer::queryIntersectsFeature(
return util::polygonIntersectsBufferedMultiPoint(translatedQueryGeometry.value_or(queryGeometry), feature.getGeometries(), circleRadius);
}
-}
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_circle_layer.hpp b/src/mbgl/renderer/layers/render_circle_layer.hpp
index 3b82b5c988..4ae7399ad1 100644
--- a/src/mbgl/renderer/render_circle_layer.hpp
+++ b/src/mbgl/renderer/layers/render_circle_layer.hpp
@@ -1,20 +1,17 @@
#pragma once
#include <mbgl/renderer/render_layer.hpp>
-#include <mbgl/style/layers/circle_layer.hpp>
+#include <mbgl/style/layers/circle_layer_impl.hpp>
#include <mbgl/style/layers/circle_layer_properties.hpp>
namespace mbgl {
class RenderCircleLayer: public RenderLayer {
public:
-
- RenderCircleLayer(const style::CircleLayer::Impl&);
+ RenderCircleLayer(Immutable<style::CircleLayer::Impl>);
~RenderCircleLayer() final = default;
- std::unique_ptr<RenderLayer> clone() const override;
-
- void cascade(const CascadeParameters&) override;
+ void transition(const TransitionParameters&) override;
void evaluate(const PropertyEvaluationParameters&) override;
bool hasTransition() const override;
@@ -29,9 +26,9 @@ public:
// Paint properties
style::CirclePaintProperties::Unevaluated unevaluated;
- style::CirclePaintProperties::Evaluated evaluated;
+ style::CirclePaintProperties::PossiblyEvaluated evaluated;
- const style::CircleLayer::Impl* const impl;
+ const style::CircleLayer::Impl& impl() const;
};
template <>
@@ -39,4 +36,4 @@ inline bool RenderLayer::is<RenderCircleLayer>() const {
return type == style::LayerType::Circle;
}
-}
+} // namespace mbgl
diff --git a/src/mbgl/renderer/layers/render_custom_layer.cpp b/src/mbgl/renderer/layers/render_custom_layer.cpp
new file mode 100644
index 0000000000..4d6084075d
--- /dev/null
+++ b/src/mbgl/renderer/layers/render_custom_layer.cpp
@@ -0,0 +1,76 @@
+#include <mbgl/renderer/layers/render_custom_layer.hpp>
+#include <mbgl/renderer/painter.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/style/layers/custom_layer_impl.hpp>
+#include <mbgl/map/transform_state.hpp>
+#include <mbgl/map/backend_scope.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+RenderCustomLayer::RenderCustomLayer(Immutable<style::CustomLayer::Impl> _impl)
+ : RenderLayer(LayerType::Custom, _impl) {
+}
+
+RenderCustomLayer::~RenderCustomLayer() {
+ assert(BackendScope::exists());
+ if (initialized && impl().deinitializeFn) {
+ impl().deinitializeFn(impl().context);
+ }
+}
+
+const CustomLayer::Impl& RenderCustomLayer::impl() const {
+ return static_cast<const CustomLayer::Impl&>(*baseImpl);
+}
+
+void RenderCustomLayer::evaluate(const PropertyEvaluationParameters&) {
+ passes = RenderPass::Translucent;
+}
+
+bool RenderCustomLayer::hasTransition() const {
+ return false;
+}
+
+std::unique_ptr<Bucket> RenderCustomLayer::createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const {
+ assert(false);
+ return nullptr;
+}
+
+void RenderCustomLayer::render(Painter& painter, PaintParameters& paintParameters, RenderSource*) {
+ if (!initialized) {
+ assert(impl().initializeFn);
+ impl().initializeFn(impl().context);
+ initialized = true;
+ }
+
+ gl::Context& context = painter.context;
+ const TransformState& state = painter.state;
+
+ // Reset GL state to a known state so the CustomLayer always has a clean slate.
+ context.vertexArrayObject = 0;
+ context.setDepthMode(painter.depthModeForSublayer(0, gl::DepthMode::ReadOnly));
+ context.setStencilMode(gl::StencilMode::disabled());
+ context.setColorMode(painter.colorModeForRenderPass());
+
+ CustomLayerRenderParameters parameters;
+
+ parameters.width = state.getSize().width;
+ parameters.height = state.getSize().height;
+ parameters.latitude = state.getLatLng().latitude();
+ parameters.longitude = state.getLatLng().longitude();
+ parameters.zoom = state.getZoom();
+ parameters.bearing = -state.getAngle() * util::RAD2DEG;
+ parameters.pitch = state.getPitch();
+ parameters.fieldOfView = state.getFieldOfView();
+
+ assert(impl().renderFn);
+ impl().renderFn(impl().context, parameters);
+
+ // Reset the view back to our original one, just in case the CustomLayer changed
+ // the viewport or Framebuffer.
+ paintParameters.view.bind();
+ context.setDirtyState();
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_custom_layer.hpp b/src/mbgl/renderer/layers/render_custom_layer.hpp
index c3af6c77b2..dd52d315cf 100644
--- a/src/mbgl/renderer/render_custom_layer.hpp
+++ b/src/mbgl/renderer/layers/render_custom_layer.hpp
@@ -1,25 +1,26 @@
#pragma once
#include <mbgl/renderer/render_layer.hpp>
-#include <mbgl/style/layers/custom_layer.hpp>
+#include <mbgl/style/layers/custom_layer_impl.hpp>
namespace mbgl {
class RenderCustomLayer: public RenderLayer {
public:
+ RenderCustomLayer(Immutable<style::CustomLayer::Impl>);
+ ~RenderCustomLayer() final;
- RenderCustomLayer(const style::CustomLayer::Impl&);
- ~RenderCustomLayer() final = default;
-
- std::unique_ptr<RenderLayer> clone() const override;
-
- void cascade(const CascadeParameters&) final {}
+ void transition(const TransitionParameters&) final {}
void evaluate(const PropertyEvaluationParameters&) override;
bool hasTransition() const override;
std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const final;
+ void render(Painter&, PaintParameters&, RenderSource*) final;
- const style::CustomLayer::Impl* const impl;
+ const style::CustomLayer::Impl& impl() const;
+
+private:
+ bool initialized = false;
};
template <>
@@ -27,4 +28,4 @@ inline bool RenderLayer::is<RenderCustomLayer>() const {
return type == style::LayerType::Custom;
}
-}
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_fill_extrusion_layer.cpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp
index f6ba164d8c..cd69316670 100644
--- a/src/mbgl/renderer/render_fill_extrusion_layer.cpp
+++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp
@@ -1,5 +1,5 @@
-#include <mbgl/renderer/render_fill_extrusion_layer.hpp>
-#include <mbgl/renderer/fill_extrusion_bucket.hpp>
+#include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp>
+#include <mbgl/renderer/buckets/fill_extrusion_bucket.hpp>
#include <mbgl/style/layers/fill_extrusion_layer_impl.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/util/math.hpp>
@@ -7,21 +7,21 @@
namespace mbgl {
-RenderFillExtrusionLayer::RenderFillExtrusionLayer(const style::FillExtrusionLayer::Impl& _impl)
- : RenderLayer(style::LayerType::FillExtrusion, _impl),
- impl(&_impl) {
+RenderFillExtrusionLayer::RenderFillExtrusionLayer(Immutable<style::FillExtrusionLayer::Impl> _impl)
+ : RenderLayer(style::LayerType::FillExtrusion, _impl),
+ unevaluated(impl().paint.untransitioned()) {
}
-std::unique_ptr<RenderLayer> RenderFillExtrusionLayer::clone() const {
- return std::make_unique<RenderFillExtrusionLayer>(*this);
+const style::FillExtrusionLayer::Impl& RenderFillExtrusionLayer::impl() const {
+ return static_cast<const style::FillExtrusionLayer::Impl&>(*baseImpl);
}
std::unique_ptr<Bucket> RenderFillExtrusionLayer::createBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) const {
return std::make_unique<FillExtrusionBucket>(parameters, layers);
}
-void RenderFillExtrusionLayer::cascade(const CascadeParameters& parameters) {
- unevaluated = impl->cascading.cascade(parameters, std::move(unevaluated));
+void RenderFillExtrusionLayer::transition(const TransitionParameters& parameters) {
+ unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated));
}
void RenderFillExtrusionLayer::evaluate(const PropertyEvaluationParameters& parameters) {
diff --git a/src/mbgl/renderer/render_fill_extrusion_layer.hpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp
index bd66d8e3b1..1a55b56836 100644
--- a/src/mbgl/renderer/render_fill_extrusion_layer.hpp
+++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp
@@ -1,20 +1,17 @@
#pragma once
#include <mbgl/renderer/render_layer.hpp>
-#include <mbgl/style/layers/fill_extrusion_layer.hpp>
+#include <mbgl/style/layers/fill_extrusion_layer_impl.hpp>
#include <mbgl/style/layers/fill_extrusion_layer_properties.hpp>
namespace mbgl {
class RenderFillExtrusionLayer: public RenderLayer {
public:
-
- RenderFillExtrusionLayer(const style::FillExtrusionLayer::Impl&);
+ RenderFillExtrusionLayer(Immutable<style::FillExtrusionLayer::Impl>);
~RenderFillExtrusionLayer() final = default;
- std::unique_ptr<RenderLayer> clone() const override;
-
- void cascade(const CascadeParameters&) override;
+ void transition(const TransitionParameters&) override;
void evaluate(const PropertyEvaluationParameters&) override;
bool hasTransition() const override;
@@ -29,9 +26,9 @@ public:
// Paint properties
style::FillExtrusionPaintProperties::Unevaluated unevaluated;
- style::FillExtrusionPaintProperties::Evaluated evaluated;
+ style::FillExtrusionPaintProperties::PossiblyEvaluated evaluated;
- const style::FillExtrusionLayer::Impl* const impl;
+ const style::FillExtrusionLayer::Impl& impl() const;
};
template <>
diff --git a/src/mbgl/renderer/render_fill_layer.cpp b/src/mbgl/renderer/layers/render_fill_layer.cpp
index 1af139cded..f1c7e97067 100644
--- a/src/mbgl/renderer/render_fill_layer.cpp
+++ b/src/mbgl/renderer/layers/render_fill_layer.cpp
@@ -1,5 +1,5 @@
-#include <mbgl/renderer/render_fill_layer.hpp>
-#include <mbgl/renderer/fill_bucket.hpp>
+#include <mbgl/renderer/layers/render_fill_layer.hpp>
+#include <mbgl/renderer/buckets/fill_bucket.hpp>
#include <mbgl/style/layers/fill_layer_impl.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/util/math.hpp>
@@ -7,21 +7,21 @@
namespace mbgl {
-RenderFillLayer::RenderFillLayer(const style::FillLayer::Impl& _impl)
- : RenderLayer(style::LayerType::Fill, _impl),
- impl(&_impl) {
+RenderFillLayer::RenderFillLayer(Immutable<style::FillLayer::Impl> _impl)
+ : RenderLayer(style::LayerType::Fill, _impl),
+ unevaluated(impl().paint.untransitioned()) {
}
-std::unique_ptr<RenderLayer> RenderFillLayer::clone() const {
- return std::make_unique<RenderFillLayer>(*this);
+const style::FillLayer::Impl& RenderFillLayer::impl() const {
+ return static_cast<const style::FillLayer::Impl&>(*baseImpl);
}
std::unique_ptr<Bucket> RenderFillLayer::createBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) const {
return std::make_unique<FillBucket>(parameters, layers);
}
-void RenderFillLayer::cascade(const CascadeParameters& parameters) {
- unevaluated = impl->cascading.cascade(parameters, std::move(unevaluated));
+void RenderFillLayer::transition(const TransitionParameters& parameters) {
+ unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated));
}
void RenderFillLayer::evaluate(const PropertyEvaluationParameters& parameters) {
@@ -68,4 +68,4 @@ bool RenderFillLayer::queryIntersectsFeature(
}
-}
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_fill_layer.hpp b/src/mbgl/renderer/layers/render_fill_layer.hpp
index 8080cf289b..1960fb653f 100644
--- a/src/mbgl/renderer/render_fill_layer.hpp
+++ b/src/mbgl/renderer/layers/render_fill_layer.hpp
@@ -1,20 +1,17 @@
#pragma once
#include <mbgl/renderer/render_layer.hpp>
-#include <mbgl/style/layers/fill_layer.hpp>
+#include <mbgl/style/layers/fill_layer_impl.hpp>
#include <mbgl/style/layers/fill_layer_properties.hpp>
namespace mbgl {
class RenderFillLayer: public RenderLayer {
public:
-
- RenderFillLayer(const style::FillLayer::Impl&);
+ RenderFillLayer(Immutable<style::FillLayer::Impl>);
~RenderFillLayer() final = default;
- std::unique_ptr<RenderLayer> clone() const override;
-
- void cascade(const CascadeParameters&) override;
+ void transition(const TransitionParameters&) override;
void evaluate(const PropertyEvaluationParameters&) override;
bool hasTransition() const override;
@@ -29,9 +26,9 @@ public:
// Paint properties
style::FillPaintProperties::Unevaluated unevaluated;
- style::FillPaintProperties::Evaluated evaluated;
+ style::FillPaintProperties::PossiblyEvaluated evaluated;
- const style::FillLayer::Impl* const impl;
+ const style::FillLayer::Impl& impl() const;
};
template <>
diff --git a/src/mbgl/renderer/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp
index 06c2564516..c27e5ea990 100644
--- a/src/mbgl/renderer/render_line_layer.cpp
+++ b/src/mbgl/renderer/layers/render_line_layer.cpp
@@ -1,5 +1,5 @@
-#include <mbgl/renderer/render_line_layer.hpp>
-#include <mbgl/renderer/line_bucket.hpp>
+#include <mbgl/renderer/layers/render_line_layer.hpp>
+#include <mbgl/renderer/buckets/line_bucket.hpp>
#include <mbgl/style/layers/line_layer_impl.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/util/math.hpp>
@@ -7,34 +7,35 @@
namespace mbgl {
-RenderLineLayer::RenderLineLayer(const style::LineLayer::Impl& _impl)
- : RenderLayer(style::LayerType::Line, _impl),
- impl(&_impl) {
+RenderLineLayer::RenderLineLayer(Immutable<style::LineLayer::Impl> _impl)
+ : RenderLayer(style::LayerType::Line, _impl),
+ unevaluated(impl().paint.untransitioned()) {
}
-std::unique_ptr<RenderLayer> RenderLineLayer::clone() const {
- return std::make_unique<RenderLineLayer>(*this);
+const style::LineLayer::Impl& RenderLineLayer::impl() const {
+ return static_cast<const style::LineLayer::Impl&>(*baseImpl);
}
std::unique_ptr<Bucket> RenderLineLayer::createBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) const {
- return std::make_unique<LineBucket>(parameters, layers, impl->layout);
+ return std::make_unique<LineBucket>(parameters, layers, impl().layout);
}
-void RenderLineLayer::cascade(const CascadeParameters& parameters) {
- unevaluated = impl->cascading.cascade(parameters, std::move(unevaluated));
+void RenderLineLayer::transition(const TransitionParameters& parameters) {
+ unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated));
}
void RenderLineLayer::evaluate(const PropertyEvaluationParameters& parameters) {
- // for scaling dasharrays
+ style::Properties<LineFloorwidth>::Unevaluated extra(unevaluated.get<style::LineWidth>());
+
auto dashArrayParams = parameters;
- dashArrayParams.z = std::floor(dashArrayParams.z);
- dashLineWidth = unevaluated.evaluate<style::LineWidth>(dashArrayParams);
+ dashArrayParams.useIntegerZoom = true;
- evaluated = unevaluated.evaluate(parameters);
+ evaluated = RenderLinePaintProperties::PossiblyEvaluated(
+ unevaluated.evaluate(parameters).concat(extra.evaluate(dashArrayParams)));
passes = (evaluated.get<style::LineOpacity>().constantOr(1.0) > 0
&& evaluated.get<style::LineColor>().constantOr(Color::black()).a > 0
- && evaluated.get<style::LineWidth>() > 0)
+ && evaluated.get<style::LineWidth>().constantOr(1.0) > 0)
? RenderPass::Translucent : RenderPass::None;
}
@@ -103,7 +104,8 @@ bool RenderLineLayer::queryIntersectsFeature(
}
float RenderLineLayer::getLineWidth(const GeometryTileFeature& feature, const float zoom) const {
- float lineWidth = evaluated.get<style::LineWidth>();
+ float lineWidth = evaluated.get<style::LineWidth>()
+ .evaluate(feature, zoom, style::LineWidth::defaultValue());
float gapWidth = evaluated.get<style::LineGapWidth>()
.evaluate(feature, zoom, style::LineGapWidth::defaultValue());
if (gapWidth) {
diff --git a/src/mbgl/renderer/render_line_layer.hpp b/src/mbgl/renderer/layers/render_line_layer.hpp
index 6d6fecc227..77551b6b7c 100644
--- a/src/mbgl/renderer/render_line_layer.hpp
+++ b/src/mbgl/renderer/layers/render_line_layer.hpp
@@ -1,20 +1,26 @@
#pragma once
#include <mbgl/renderer/render_layer.hpp>
-#include <mbgl/style/layers/line_layer.hpp>
+#include <mbgl/style/layers/line_layer_impl.hpp>
#include <mbgl/style/layers/line_layer_properties.hpp>
+#include <mbgl/programs/uniforms.hpp>
namespace mbgl {
+struct LineFloorwidth : style::DataDrivenPaintProperty<float, attributes::a_floorwidth, uniforms::u_floorwidth> {
+ static float defaultValue() { return 1; }
+};
+
+class RenderLinePaintProperties : public style::ConcatenateProperties<
+ style::LinePaintProperties::PropertyTypes,
+ TypeList<LineFloorwidth>>::Type {};
+
class RenderLineLayer: public RenderLayer {
public:
-
- RenderLineLayer(const style::LineLayer::Impl&);
+ RenderLineLayer(Immutable<style::LineLayer::Impl>);
~RenderLineLayer() final = default;
- std::unique_ptr<RenderLayer> clone() const override;
-
- void cascade(const CascadeParameters&) override;
+ void transition(const TransitionParameters&) override;
void evaluate(const PropertyEvaluationParameters&) override;
bool hasTransition() const override;
@@ -29,16 +35,12 @@ public:
// Paint properties
style::LinePaintProperties::Unevaluated unevaluated;
- style::LinePaintProperties::Evaluated evaluated;
-
- const style::LineLayer::Impl* const impl;
+ RenderLinePaintProperties::PossiblyEvaluated evaluated;
- // Special case
- float dashLineWidth = 1;
+ const style::LineLayer::Impl& impl() const;
private:
float getLineWidth(const GeometryTileFeature&, const float) const;
-
};
template <>
diff --git a/src/mbgl/renderer/layers/render_raster_layer.cpp b/src/mbgl/renderer/layers/render_raster_layer.cpp
new file mode 100644
index 0000000000..84e27a3895
--- /dev/null
+++ b/src/mbgl/renderer/layers/render_raster_layer.cpp
@@ -0,0 +1,50 @@
+#include <mbgl/renderer/layers/render_raster_layer.hpp>
+#include <mbgl/renderer/bucket.hpp>
+#include <mbgl/style/layers/raster_layer_impl.hpp>
+#include <mbgl/gl/context.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/tile/tile.hpp>
+#include <mbgl/renderer/sources/render_image_source.hpp>
+#include <mbgl/renderer/painter.hpp>
+
+namespace mbgl {
+
+RenderRasterLayer::RenderRasterLayer(Immutable<style::RasterLayer::Impl> _impl)
+ : RenderLayer(style::LayerType::Raster, _impl),
+ unevaluated(impl().paint.untransitioned()) {
+}
+
+const style::RasterLayer::Impl& RenderRasterLayer::impl() const {
+ return static_cast<const style::RasterLayer::Impl&>(*baseImpl);
+}
+
+std::unique_ptr<Bucket> RenderRasterLayer::createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const {
+ assert(false);
+ return nullptr;
+}
+
+void RenderRasterLayer::transition(const TransitionParameters& parameters) {
+ unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated));
+}
+
+void RenderRasterLayer::evaluate(const PropertyEvaluationParameters& parameters) {
+ evaluated = unevaluated.evaluate(parameters);
+
+ passes = evaluated.get<style::RasterOpacity>() > 0 ? RenderPass::Translucent : RenderPass::None;
+}
+
+bool RenderRasterLayer::hasTransition() const {
+ return unevaluated.hasTransition();
+}
+
+void RenderRasterLayer::render(Painter& painter, PaintParameters& parameters, RenderSource* source) {
+ RenderLayer::render(painter, parameters, source);
+ if (renderTiles.empty()) {
+ RenderImageSource* imageSource = source->as<RenderImageSource>();
+ if (imageSource) {
+ imageSource->render(painter, parameters, *this);
+ }
+ }
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_raster_layer.hpp b/src/mbgl/renderer/layers/render_raster_layer.hpp
index 3ffeb8febf..ce46152a95 100644
--- a/src/mbgl/renderer/render_raster_layer.hpp
+++ b/src/mbgl/renderer/layers/render_raster_layer.hpp
@@ -1,30 +1,29 @@
#pragma once
#include <mbgl/renderer/render_layer.hpp>
-#include <mbgl/style/layers/raster_layer.hpp>
+#include <mbgl/style/layers/raster_layer_impl.hpp>
#include <mbgl/style/layers/raster_layer_properties.hpp>
namespace mbgl {
class RenderRasterLayer: public RenderLayer {
public:
-
- RenderRasterLayer(const style::RasterLayer::Impl&);
+ RenderRasterLayer(Immutable<style::RasterLayer::Impl>);
~RenderRasterLayer() final = default;
- std::unique_ptr<RenderLayer> clone() const override;
-
- void cascade(const CascadeParameters&) override;
+ void transition(const TransitionParameters&) override;
void evaluate(const PropertyEvaluationParameters&) override;
bool hasTransition() const override;
+ void render(Painter&, PaintParameters&, RenderSource*) override;
+
std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const override;
// Paint properties
style::RasterPaintProperties::Unevaluated unevaluated;
- style::RasterPaintProperties::Evaluated evaluated;
+ style::RasterPaintProperties::PossiblyEvaluated evaluated;
- const style::RasterLayer::Impl* const impl;
+ const style::RasterLayer::Impl& impl() const;
};
template <>
diff --git a/src/mbgl/renderer/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp
index 30d769e032..6540fc9612 100644
--- a/src/mbgl/renderer/render_symbol_layer.cpp
+++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp
@@ -1,4 +1,4 @@
-#include <mbgl/renderer/render_symbol_layer.hpp>
+#include <mbgl/renderer/layers/render_symbol_layer.hpp>
#include <mbgl/layout/symbol_layout.hpp>
#include <mbgl/renderer/bucket.hpp>
#include <mbgl/renderer/bucket_parameters.hpp>
@@ -8,13 +8,13 @@
namespace mbgl {
-RenderSymbolLayer::RenderSymbolLayer(const style::SymbolLayer::Impl& _impl)
- : RenderLayer(style::LayerType::Symbol, _impl),
- impl(&_impl) {
+RenderSymbolLayer::RenderSymbolLayer(Immutable<style::SymbolLayer::Impl> _impl)
+ : RenderLayer(style::LayerType::Symbol, _impl),
+ unevaluated(impl().paint.untransitioned()) {
}
-std::unique_ptr<RenderLayer> RenderSymbolLayer::clone() const {
- return std::make_unique<RenderSymbolLayer>(*this);
+const style::SymbolLayer::Impl& RenderSymbolLayer::impl() const {
+ return static_cast<const style::SymbolLayer::Impl&>(*baseImpl);
}
std::unique_ptr<Bucket> RenderSymbolLayer::createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const {
@@ -24,18 +24,18 @@ std::unique_ptr<Bucket> RenderSymbolLayer::createBucket(const BucketParameters&,
std::unique_ptr<SymbolLayout> RenderSymbolLayer::createLayout(const BucketParameters& parameters,
const std::vector<const RenderLayer*>& group,
- const GeometryTileLayer& layer,
+ std::unique_ptr<GeometryTileLayer> layer,
GlyphDependencies& glyphDependencies,
- IconDependencies& iconDependencies) const {
+ ImageDependencies& imageDependencies) const {
return std::make_unique<SymbolLayout>(parameters,
group,
- layer,
- iconDependencies,
+ std::move(layer),
+ imageDependencies,
glyphDependencies);
}
-void RenderSymbolLayer::cascade(const CascadeParameters& parameters) {
- unevaluated = impl->cascading.cascade(parameters, std::move(unevaluated));
+void RenderSymbolLayer::transition(const TransitionParameters& parameters) {
+ unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated));
}
void RenderSymbolLayer::evaluate(const PropertyEvaluationParameters& parameters) {
@@ -55,8 +55,8 @@ bool RenderSymbolLayer::hasTransition() const {
return unevaluated.hasTransition();
}
-style::IconPaintProperties::Evaluated RenderSymbolLayer::iconPaintProperties() const {
- return style::IconPaintProperties::Evaluated {
+style::IconPaintProperties::PossiblyEvaluated RenderSymbolLayer::iconPaintProperties() const {
+ return style::IconPaintProperties::PossiblyEvaluated {
evaluated.get<style::IconOpacity>(),
evaluated.get<style::IconColor>(),
evaluated.get<style::IconHaloColor>(),
@@ -67,8 +67,8 @@ style::IconPaintProperties::Evaluated RenderSymbolLayer::iconPaintProperties() c
};
}
-style::TextPaintProperties::Evaluated RenderSymbolLayer::textPaintProperties() const {
- return style::TextPaintProperties::Evaluated {
+style::TextPaintProperties::PossiblyEvaluated RenderSymbolLayer::textPaintProperties() const {
+ return style::TextPaintProperties::PossiblyEvaluated {
evaluated.get<style::TextOpacity>(),
evaluated.get<style::TextColor>(),
evaluated.get<style::TextHaloColor>(),
@@ -84,11 +84,8 @@ style::SymbolPropertyValues RenderSymbolLayer::iconPropertyValues(const style::S
return style::SymbolPropertyValues {
layout_.get<style::IconRotationAlignment>(), // icon-pitch-alignment is not yet implemented; inherit the rotation alignment
layout_.get<style::IconRotationAlignment>(),
- layout_.get<style::IconSize>(),
evaluated.get<style::IconTranslate>(),
evaluated.get<style::IconTranslateAnchor>(),
- iconSize,
- 1.0f,
evaluated.get<style::IconHaloColor>().constantOr(Color::black()).a > 0 &&
evaluated.get<style::IconHaloWidth>().constantOr(1),
evaluated.get<style::IconColor>().constantOr(Color::black()).a > 0
@@ -99,11 +96,8 @@ style::SymbolPropertyValues RenderSymbolLayer::textPropertyValues(const style::S
return style::SymbolPropertyValues {
layout_.get<style::TextPitchAlignment>(),
layout_.get<style::TextRotationAlignment>(),
- layout_.get<style::TextSize>(),
evaluated.get<style::TextTranslate>(),
evaluated.get<style::TextTranslateAnchor>(),
- textSize,
- 24.0f,
evaluated.get<style::TextHaloColor>().constantOr(Color::black()).a > 0 &&
evaluated.get<style::TextHaloWidth>().constantOr(1),
evaluated.get<style::TextColor>().constantOr(Color::black()).a > 0
diff --git a/src/mbgl/renderer/render_symbol_layer.hpp b/src/mbgl/renderer/layers/render_symbol_layer.hpp
index 80ffd95a06..2199103de2 100644
--- a/src/mbgl/renderer/render_symbol_layer.hpp
+++ b/src/mbgl/renderer/layers/render_symbol_layer.hpp
@@ -2,8 +2,8 @@
#include <mbgl/text/glyph.hpp>
#include <mbgl/renderer/render_layer.hpp>
-#include <mbgl/sprite/sprite_atlas.hpp>
-#include <mbgl/style/layers/symbol_layer.hpp>
+#include <mbgl/style/image_impl.hpp>
+#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
namespace mbgl {
@@ -13,7 +13,7 @@ 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<
+class IconPaintProperties : public Properties<
IconOpacity,
IconColor,
IconHaloColor,
@@ -23,7 +23,7 @@ class IconPaintProperties : public PaintProperties<
IconTranslateAnchor
> {};
-class TextPaintProperties : public PaintProperties<
+class TextPaintProperties : public Properties<
TextOpacity,
TextColor,
TextHaloColor,
@@ -40,14 +40,10 @@ public:
// Layout
AlignmentType pitchAlignment;
AlignmentType rotationAlignment;
- PossiblyEvaluatedPropertyValue<float> layoutSize;
// Paint
std::array<float, 2> translate;
TranslateAnchorType translateAnchor;
- float paintSize;
-
- float sdfScale; // Constant (1.0 or 24.0)
bool hasHalo;
bool hasFill;
@@ -61,33 +57,34 @@ class GeometryTileLayer;
class RenderSymbolLayer: public RenderLayer {
public:
- RenderSymbolLayer(const style::SymbolLayer::Impl&);
+ RenderSymbolLayer(Immutable<style::SymbolLayer::Impl>);
~RenderSymbolLayer() final = default;
- std::unique_ptr<RenderLayer> clone() const override;
-
- void cascade(const CascadeParameters&) override;
+ void transition(const TransitionParameters&) override;
void evaluate(const PropertyEvaluationParameters&) override;
bool hasTransition() const override;
- style::IconPaintProperties::Evaluated iconPaintProperties() const;
- style::TextPaintProperties::Evaluated textPaintProperties() const;
+ style::IconPaintProperties::PossiblyEvaluated iconPaintProperties() const;
+ style::TextPaintProperties::PossiblyEvaluated textPaintProperties() const;
style::SymbolPropertyValues iconPropertyValues(const style::SymbolLayoutProperties::PossiblyEvaluated&) const;
style::SymbolPropertyValues textPropertyValues(const style::SymbolLayoutProperties::PossiblyEvaluated&) const;
std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const override;
- std::unique_ptr<SymbolLayout> createLayout(const BucketParameters&, const std::vector<const RenderLayer*>&,
- const GeometryTileLayer&, GlyphDependencies&, IconDependencies&) const;
+ std::unique_ptr<SymbolLayout> createLayout(const BucketParameters&,
+ const std::vector<const RenderLayer*>&,
+ std::unique_ptr<GeometryTileLayer>,
+ GlyphDependencies&,
+ ImageDependencies&) const;
// Paint properties
style::SymbolPaintProperties::Unevaluated unevaluated;
- style::SymbolPaintProperties::Evaluated evaluated;
+ style::SymbolPaintProperties::PossiblyEvaluated evaluated;
float iconSize = 1.0f;
float textSize = 16.0f;
- const style::SymbolLayer::Impl* const impl;
+ const style::SymbolLayer::Impl& impl() const;
};
template <>
diff --git a/src/mbgl/renderer/paint_property_binder.hpp b/src/mbgl/renderer/paint_property_binder.hpp
index bcbc7c287d..f78147fc87 100644
--- a/src/mbgl/renderer/paint_property_binder.hpp
+++ b/src/mbgl/renderer/paint_property_binder.hpp
@@ -4,6 +4,7 @@
#include <mbgl/gl/attribute.hpp>
#include <mbgl/gl/uniform.hpp>
#include <mbgl/util/type_list.hpp>
+#include <mbgl/renderer/possibly_evaluated_property_value.hpp>
#include <mbgl/renderer/paint_property_statistics.hpp>
#include <bitset>
@@ -102,11 +103,8 @@ public:
void populateVertexVector(const GeometryTileFeature&, std::size_t) override {}
void upload(gl::Context&) override {}
- AttributeBinding attributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const override {
- auto value = attributeValue(currentValue.constantOr(constant));
- return typename Attribute::ConstantBinding {
- zoomInterpolatedAttributeValue(value, value)
- };
+ AttributeBinding attributeBinding(const PossiblyEvaluatedPropertyValue<T>&) const override {
+ return gl::DisabledAttribute();
}
float interpolationFactor(float) const override {
@@ -151,12 +149,9 @@ public:
AttributeBinding attributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const override {
if (currentValue.isConstant()) {
- BaseAttributeValue value = attributeValue(*currentValue.constant());
- return typename Attribute::ConstantBinding {
- zoomInterpolatedAttributeValue(value, value)
- };
+ return gl::DisabledAttribute();
} else {
- return Attribute::variableBinding(*vertexBuffer, 0, BaseAttribute::Dimensions);
+ return Attribute::binding(*vertexBuffer, 0, BaseAttribute::Dimensions);
}
}
@@ -215,17 +210,18 @@ public:
AttributeBinding attributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const override {
if (currentValue.isConstant()) {
- BaseAttributeValue value = attributeValue(*currentValue.constant());
- return typename Attribute::ConstantBinding {
- zoomInterpolatedAttributeValue(value, value)
- };
+ return gl::DisabledAttribute();
} else {
- return Attribute::variableBinding(*vertexBuffer, 0);
+ return Attribute::binding(*vertexBuffer, 0);
}
}
float interpolationFactor(float currentZoom) const override {
- return util::interpolationFactor(1.0f, { rangeOfCoveringRanges.min.zoom, rangeOfCoveringRanges.max.zoom }, currentZoom);
+ if (function.useIntegerZoom) {
+ return util::interpolationFactor(1.0f, { rangeOfCoveringRanges.min.zoom, rangeOfCoveringRanges.max.zoom }, std::floor(currentZoom));
+ } else {
+ return util::interpolationFactor(1.0f, { rangeOfCoveringRanges.min.zoom, rangeOfCoveringRanges.max.zoom }, currentZoom);
+ }
}
T uniformValue(const PossiblyEvaluatedPropertyValue<T>& currentValue) const override {
diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp
index da4903864b..47db8254e2 100644
--- a/src/mbgl/renderer/painter.cpp
+++ b/src/mbgl/renderer/painter.cpp
@@ -2,6 +2,7 @@
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/renderer/render_source.hpp>
+#include <mbgl/renderer/render_style.hpp>
#include <mbgl/style/source.hpp>
#include <mbgl/style/source_impl.hpp>
@@ -11,25 +12,21 @@
#include <mbgl/util/logging.hpp>
#include <mbgl/gl/debugging.hpp>
-#include <mbgl/style/style.hpp>
#include <mbgl/style/layer_impl.hpp>
+#include <mbgl/style/layers/custom_layer_impl.hpp>
#include <mbgl/tile/tile.hpp>
-#include <mbgl/renderer/render_background_layer.hpp>
-#include <mbgl/renderer/render_custom_layer.hpp>
+#include <mbgl/renderer/layers/render_background_layer.hpp>
+#include <mbgl/renderer/layers/render_custom_layer.hpp>
#include <mbgl/style/layers/custom_layer_impl.hpp>
-#include <mbgl/renderer/render_fill_extrusion_layer.hpp>
+#include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp>
-#include <mbgl/sprite/sprite_atlas.hpp>
+#include <mbgl/renderer/image_manager.hpp>
#include <mbgl/geometry/line_atlas.hpp>
-#include <mbgl/text/glyph_atlas.hpp>
#include <mbgl/programs/program_parameters.hpp>
#include <mbgl/programs/programs.hpp>
-#include <mbgl/algorithm/generate_clip_ids.hpp>
-#include <mbgl/algorithm/generate_clip_ids_impl.hpp>
-
#include <mbgl/util/constants.hpp>
#include <mbgl/util/mat3.hpp>
#include <mbgl/util/string.hpp>
@@ -118,14 +115,14 @@ Painter::Painter(gl::Context& context_,
Painter::~Painter() = default;
bool Painter::needsAnimation() const {
- return frameHistory.needsAnimation(util::DEFAULT_FADE_DURATION);
+ return frameHistory.needsAnimation(util::DEFAULT_TRANSITION_DURATION);
}
void Painter::cleanup() {
context.performCleanup();
}
-void Painter::render(const Style& style, const FrameData& frame_, View& view, SpriteAtlas& annotationSpriteAtlas) {
+void Painter::render(RenderStyle& style, const FrameData& frame_, View& view) {
frame = frame_;
if (frame.contextMode == GLContextMode::Shared) {
context.setDirtyState();
@@ -140,11 +137,10 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp
view
};
- glyphAtlas = style.glyphAtlas.get();
- spriteAtlas = style.spriteAtlas.get();
+ imageManager = style.imageManager.get();
lineAtlas = style.lineAtlas.get();
- evaluatedLight = style.getRenderLight()->getEvaluated();
+ evaluatedLight = style.getRenderLight().getEvaluated();
RenderData renderData = style.getRenderData(frame.debugOptions, state.getAngle());
const std::vector<RenderItem>& order = renderData.order;
@@ -163,7 +159,7 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp
}
frameHistory.record(frame.timePoint, state.getZoom(),
- frame.mapMode == MapMode::Continuous ? util::DEFAULT_FADE_DURATION : Milliseconds(0));
+ frame.mapMode == MapMode::Continuous ? util::DEFAULT_TRANSITION_DURATION : Milliseconds(0));
// - UPLOAD PASS -------------------------------------------------------------------------------
@@ -171,21 +167,9 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp
{
MBGL_DEBUG_GROUP(context, "upload");
- spriteAtlas->upload(context, 0);
-
+ imageManager->upload(context, 0);
lineAtlas->upload(context, 0);
- glyphAtlas->upload(context, 0);
frameHistory.upload(context, 0);
- annotationSpriteAtlas.upload(context, 0);
-
- for (const auto& item : order) {
- for (const auto& tileRef : item.tiles) {
- const auto& bucket = tileRef.get().tile.getBucket(item.layer);
- if (bucket && bucket->needsUpload()) {
- bucket->upload(context);
- }
- }
- }
}
// - CLEAR -------------------------------------------------------------------------------------
@@ -207,14 +191,14 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp
MBGL_DEBUG_GROUP(context, "clip");
// Update all clipping IDs.
- algorithm::ClipIDGenerator generator;
+ clipIDGenerator = algorithm::ClipIDGenerator();
for (const auto& source : sources) {
- source->startRender(generator, projMatrix, nearClippedProjMatrix, state);
+ source->startRender(*this);
}
MBGL_DEBUG_GROUP(context, "clipping masks");
- for (const auto& stencil : generator.getStencils()) {
+ for (const auto& stencil : clipIDGenerator.getStencils()) {
MBGL_DEBUG_GROUP(context, std::string{ "mask: " } + util::toString(stencil.first));
renderClippingMask(stencil.first, stencil.second);
}
@@ -308,21 +292,6 @@ void Painter::renderPass(PaintParameters& parameters,
if (layer.is<RenderBackgroundLayer>()) {
MBGL_DEBUG_GROUP(context, "background");
renderBackground(parameters, *layer.as<RenderBackgroundLayer>());
- } else if (layer.is<RenderCustomLayer>()) {
- MBGL_DEBUG_GROUP(context, layer.baseImpl.id + " - custom");
-
- // Reset GL state to a known state so the CustomLayer always has a clean slate.
- context.vertexArrayObject = 0;
- context.setDepthMode(depthModeForSublayer(0, gl::DepthMode::ReadOnly));
- context.setStencilMode(gl::StencilMode::disabled());
- context.setColorMode(colorModeForRenderPass());
-
- layer.as<RenderCustomLayer>()->impl->render(state);
-
- // Reset the view back to our original one, just in case the CustomLayer changed
- // the viewport or Framebuffer.
- parameters.view.bind();
- context.setDirtyState();
} else if (layer.is<RenderFillExtrusionLayer>()) {
const auto size = context.viewport.getCurrentValue().size;
@@ -336,13 +305,7 @@ void Painter::renderPass(PaintParameters& parameters,
context.setDepthMode(depthModeForSublayer(0, gl::DepthMode::ReadWrite));
context.clear(Color{ 0.0f, 0.0f, 0.0f, 0.0f }, 1.0f, {});
- for (auto& tileRef : item.tiles) {
- auto& tile = tileRef.get();
-
- MBGL_DEBUG_GROUP(context, layer.baseImpl.id + " - " + util::toString(tile.id));
- auto bucket = tile.tile.getBucket(layer);
- bucket->render(*this, parameters, layer, tile);
- }
+ renderItem(parameters, item);
parameters.view.bind();
context.bindTexture(extrusionTexture->getTexture());
@@ -350,7 +313,7 @@ void Painter::renderPass(PaintParameters& parameters,
mat4 viewportMat;
matrix::ortho(viewportMat, 0, size.width, size.height, 0, 0, 1);
- const PaintProperties<>::Evaluated properties{};
+ const Properties<>::PossiblyEvaluated properties;
parameters.programs.extrusionTexture.draw(
context, gl::Triangles(), gl::DepthMode::disabled(), gl::StencilMode::disabled(),
@@ -364,12 +327,7 @@ void Painter::renderPass(PaintParameters& parameters,
ExtrusionTextureProgram::PaintPropertyBinders{ properties, 0 }, properties,
state.getZoom());
} else {
- for (auto& tileRef : item.tiles) {
- auto& tile = tileRef.get();
- MBGL_DEBUG_GROUP(context, layer.baseImpl.id + " - " + util::toString(tile.id));
- auto bucket = tile.tile.getBucket(layer);
- bucket->render(*this, parameters, layer, tile);
- }
+ renderItem(parameters, item);
}
}
@@ -378,6 +336,12 @@ void Painter::renderPass(PaintParameters& parameters,
}
}
+void Painter::renderItem(PaintParameters& parameters, const RenderItem& item) {
+ RenderLayer& layer = item.layer;
+ MBGL_DEBUG_GROUP(context, layer.getID());
+ layer.render(*this, parameters, item.source);
+}
+
mat4 Painter::matrixForTile(const UnwrappedTileID& tileID) {
mat4 matrix;
state.matrixFor(matrix, tileID);
diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp
index 4658f0c206..7e966adefa 100644
--- a/src/mbgl/renderer/painter.hpp
+++ b/src/mbgl/renderer/painter.hpp
@@ -7,6 +7,7 @@
#include <mbgl/renderer/frame_history.hpp>
#include <mbgl/renderer/render_item.hpp>
#include <mbgl/renderer/bucket.hpp>
+#include <mbgl/renderer/render_light.hpp>
#include <mbgl/gl/context.hpp>
#include <mbgl/programs/debug_program.hpp>
@@ -15,13 +16,13 @@
#include <mbgl/programs/extrusion_texture_program.hpp>
#include <mbgl/programs/raster_program.hpp>
-#include <mbgl/style/style.hpp>
-
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/offscreen_texture.hpp>
+#include <mbgl/algorithm/generate_clip_ids.hpp>
+
#include <array>
#include <vector>
#include <set>
@@ -29,10 +30,10 @@
namespace mbgl {
+class RenderStyle;
class RenderTile;
-class SpriteAtlas;
+class ImageManager;
class View;
-class GlyphAtlas;
class LineAtlas;
struct FrameData;
class Tile;
@@ -59,11 +60,6 @@ class TilePyramid;
struct ClipID;
-namespace style {
-class Style;
-class Source;
-} // namespace style
-
struct FrameData {
TimePoint timePoint;
float pixelRatio;
@@ -77,23 +73,25 @@ public:
Painter(gl::Context&, const TransformState&, float pixelRatio, const optional<std::string>& programCacheDir);
~Painter();
- void render(const style::Style&,
+ void render(RenderStyle&,
const FrameData&,
- View&,
- SpriteAtlas& annotationSpriteAtlas);
+ View&);
void cleanup();
void renderClippingMask(const UnwrappedTileID&, const ClipID&);
void renderTileDebug(const RenderTile&);
+ void renderTileDebug(const mat4& matrix);
void renderFill(PaintParameters&, FillBucket&, const RenderFillLayer&, const RenderTile&);
void renderFillExtrusion(PaintParameters&, FillExtrusionBucket&, const RenderFillExtrusionLayer&, const RenderTile&);
void renderLine(PaintParameters&, LineBucket&, const RenderLineLayer&, const RenderTile&);
void renderCircle(PaintParameters&, CircleBucket&, const RenderCircleLayer&, const RenderTile&);
void renderSymbol(PaintParameters&, SymbolBucket&, const RenderSymbolLayer&, const RenderTile&);
- void renderRaster(PaintParameters&, RasterBucket&, const RenderRasterLayer&, const RenderTile&);
+ void renderRaster(PaintParameters&, RasterBucket&, const RenderRasterLayer&, const mat4&, bool useBucketBuffers /* = false */);
void renderBackground(PaintParameters&, const RenderBackgroundLayer&);
+ void renderItem(PaintParameters&, const RenderItem&);
+
#ifndef NDEBUG
// Renders tile clip boundaries, using stencil buffer to calculate fill color.
void renderClipMasks(PaintParameters&);
@@ -103,9 +101,6 @@ public:
bool needsAnimation() const;
-private:
- std::vector<RenderItem> determineRenderOrder(const style::Style&);
-
template <class Iterator>
void renderPass(PaintParameters&,
RenderPass,
@@ -128,9 +123,10 @@ private:
}
#endif
-private:
gl::Context& context;
+ algorithm::ClipIDGenerator clipIDGenerator;
+
mat4 projMatrix;
mat4 nearClippedProjMatrix;
@@ -155,8 +151,7 @@ private:
float depthRangeSize;
const float depthEpsilon = 1.0f / (1 << 16);
- SpriteAtlas* spriteAtlas = nullptr;
- GlyphAtlas* glyphAtlas = nullptr;
+ ImageManager* imageManager = nullptr;
LineAtlas* lineAtlas = nullptr;
optional<OffscreenTexture> extrusionTexture;
diff --git a/src/mbgl/renderer/painter_background.cpp b/src/mbgl/renderer/painters/painter_background.cpp
index d01696ee3e..577d7d6cda 100644
--- a/src/mbgl/renderer/painter_background.cpp
+++ b/src/mbgl/renderer/painters/painter_background.cpp
@@ -1,10 +1,10 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
-#include <mbgl/renderer/render_background_layer.hpp>
+#include <mbgl/renderer/layers/render_background_layer.hpp>
+#include <mbgl/renderer/image_manager.hpp>
#include <mbgl/style/layers/background_layer_impl.hpp>
#include <mbgl/programs/programs.hpp>
#include <mbgl/programs/fill_program.hpp>
-#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/util/tile_cover.hpp>
namespace mbgl {
@@ -14,9 +14,9 @@ using namespace style;
void Painter::renderBackground(PaintParameters& parameters, const RenderBackgroundLayer& layer) {
// Note that for bottommost layers without a pattern, the background color is drawn with
// glClear rather than this method.
- const BackgroundPaintProperties::Evaluated& background = layer.evaluated;
+ const BackgroundPaintProperties::PossiblyEvaluated& background = layer.evaluated;
- style::FillPaintProperties::Evaluated properties;
+ style::FillPaintProperties::PossiblyEvaluated properties;
properties.get<FillPattern>() = background.get<BackgroundPattern>();
properties.get<FillOpacity>() = { background.get<BackgroundOpacity>() };
properties.get<FillColor>() = { background.get<BackgroundColor>() };
@@ -24,13 +24,13 @@ void Painter::renderBackground(PaintParameters& parameters, const RenderBackgrou
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);
+ optional<ImagePosition> imagePosA = imageManager->getPattern(background.get<BackgroundPattern>().from);
+ optional<ImagePosition> imagePosB = imageManager->getPattern(background.get<BackgroundPattern>().to);
if (!imagePosA || !imagePosB)
return;
- spriteAtlas->bind(true, context, 0);
+ imageManager->bind(context, 0);
for (const auto& tileID : util::tileCover(state, state.getIntegerZoom())) {
parameters.programs.fillPattern.get(properties).draw(
@@ -42,6 +42,7 @@ void Painter::renderBackground(PaintParameters& parameters, const RenderBackgrou
FillPatternUniforms::values(
matrixForTile(tileID),
context.viewport.getCurrentValue().size,
+ imageManager->getPixelSize(),
*imagePosA,
*imagePosB,
background.get<BackgroundPattern>(),
diff --git a/src/mbgl/renderer/painter_circle.cpp b/src/mbgl/renderer/painters/painter_circle.cpp
index 13acb5f7fe..58e384979d 100644
--- a/src/mbgl/renderer/painter_circle.cpp
+++ b/src/mbgl/renderer/painters/painter_circle.cpp
@@ -1,8 +1,8 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
-#include <mbgl/renderer/circle_bucket.hpp>
+#include <mbgl/renderer/buckets/circle_bucket.hpp>
#include <mbgl/renderer/render_tile.hpp>
-#include <mbgl/renderer/render_circle_layer.hpp>
+#include <mbgl/renderer/layers/render_circle_layer.hpp>
#include <mbgl/style/layers/circle_layer_impl.hpp>
#include <mbgl/programs/programs.hpp>
#include <mbgl/programs/circle_program.hpp>
@@ -20,7 +20,7 @@ void Painter::renderCircle(PaintParameters& parameters,
return;
}
- const CirclePaintProperties::Evaluated& properties = layer.evaluated;
+ const CirclePaintProperties::PossiblyEvaluated& properties = layer.evaluated;
const bool scaleWithMap = properties.get<CirclePitchScale>() == CirclePitchScaleType::Map;
parameters.programs.circle.get(properties).draw(
diff --git a/src/mbgl/renderer/painter_clipping.cpp b/src/mbgl/renderer/painters/painter_clipping.cpp
index b3a2d77b1a..cad092594e 100644
--- a/src/mbgl/renderer/painter_clipping.cpp
+++ b/src/mbgl/renderer/painters/painter_clipping.cpp
@@ -6,7 +6,7 @@
namespace mbgl {
void Painter::renderClippingMask(const UnwrappedTileID& tileID, const ClipID& clip) {
- static const style::FillPaintProperties::Evaluated properties {};
+ static const style::FillPaintProperties::PossiblyEvaluated properties {};
static const FillProgram::PaintPropertyBinders paintAttibuteData(properties, 0);
programs->fill.get(properties).draw(
context,
diff --git a/src/mbgl/renderer/painter_debug.cpp b/src/mbgl/renderer/painters/painter_debug.cpp
index 37fa3bcb12..ee76aee54c 100644
--- a/src/mbgl/renderer/painter_debug.cpp
+++ b/src/mbgl/renderer/painters/painter_debug.cpp
@@ -1,5 +1,5 @@
#include <mbgl/renderer/painter.hpp>
-#include <mbgl/renderer/debug_bucket.hpp>
+#include <mbgl/renderer/buckets/debug_bucket.hpp>
#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/map/view.hpp>
@@ -20,7 +20,7 @@ void Painter::renderTileDebug(const RenderTile& renderTile) {
MBGL_DEBUG_GROUP(context, std::string { "debug " } + util::toString(renderTile.id));
- static const style::PaintProperties<>::Evaluated properties {};
+ static const style::Properties<>::PossiblyEvaluated properties {};
static const DebugProgram::PaintPropertyBinders paintAttibuteData(properties, 0);
auto draw = [&] (Color color, const auto& vertexBuffer, const auto& indexBuffer, const auto& segments, auto drawMode) {
@@ -77,6 +77,34 @@ void Painter::renderTileDebug(const RenderTile& renderTile) {
}
}
+void Painter::renderTileDebug(const mat4& matrix) {
+ if (frame.debugOptions == MapDebugOptions::NoDebug)
+ return;
+
+ static const style::Properties<>::PossiblyEvaluated properties {};
+ static const DebugProgram::PaintPropertyBinders paintAttibuteData(properties, 0);
+
+ if (frame.debugOptions & MapDebugOptions::TileBorders) {
+ programs->debug.draw(
+ context,
+ gl::LineStrip { 4.0f * frame.pixelRatio },
+ gl::DepthMode::disabled(),
+ gl::StencilMode::disabled(),
+ gl::ColorMode::unblended(),
+ DebugProgram::UniformValues {
+ uniforms::u_matrix::Value{ matrix },
+ uniforms::u_color::Value{ Color::red() }
+ },
+ tileVertexBuffer,
+ tileBorderIndexBuffer,
+ tileBorderSegments,
+ paintAttibuteData,
+ properties,
+ state.getZoom()
+ );
+ }
+}
+
#ifndef NDEBUG
void Painter::renderClipMasks(PaintParameters&) {
context.setStencilMode(gl::StencilMode::disabled());
diff --git a/src/mbgl/renderer/painter_fill.cpp b/src/mbgl/renderer/painters/painter_fill.cpp
index e1b59d8839..3a0bfed454 100644
--- a/src/mbgl/renderer/painter_fill.cpp
+++ b/src/mbgl/renderer/painters/painter_fill.cpp
@@ -1,10 +1,10 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
-#include <mbgl/renderer/fill_bucket.hpp>
+#include <mbgl/renderer/buckets/fill_bucket.hpp>
#include <mbgl/renderer/render_tile.hpp>
-#include <mbgl/renderer/render_fill_layer.hpp>
+#include <mbgl/renderer/layers/render_fill_layer.hpp>
+#include <mbgl/renderer/image_manager.hpp>
#include <mbgl/style/layers/fill_layer_impl.hpp>
-#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/programs/programs.hpp>
#include <mbgl/programs/fill_program.hpp>
#include <mbgl/util/convert.hpp>
@@ -17,21 +17,21 @@ void Painter::renderFill(PaintParameters& parameters,
FillBucket& bucket,
const RenderFillLayer& layer,
const RenderTile& tile) {
- const FillPaintProperties::Evaluated& properties = layer.evaluated;
+ const FillPaintProperties::PossiblyEvaluated& properties = layer.evaluated;
if (!properties.get<FillPattern>().from.empty()) {
if (pass != RenderPass::Translucent) {
return;
}
- optional<SpriteAtlasElement> imagePosA = spriteAtlas->getPattern(properties.get<FillPattern>().from);
- optional<SpriteAtlasElement> imagePosB = spriteAtlas->getPattern(properties.get<FillPattern>().to);
+ optional<ImagePosition> imagePosA = imageManager->getPattern(properties.get<FillPattern>().from);
+ optional<ImagePosition> imagePosB = imageManager->getPattern(properties.get<FillPattern>().to);
if (!imagePosA || !imagePosB) {
return;
}
- spriteAtlas->bind(true, context, 0);
+ imageManager->bind(context, 0);
auto draw = [&] (uint8_t sublayer,
auto& program,
@@ -49,6 +49,7 @@ void Painter::renderFill(PaintParameters& parameters,
properties.get<FillTranslateAnchor>(),
state),
context.viewport.getCurrentValue().size,
+ imageManager->getPixelSize(),
*imagePosA,
*imagePosB,
properties.get<FillPattern>(),
diff --git a/src/mbgl/renderer/painter_fill_extrusion.cpp b/src/mbgl/renderer/painters/painter_fill_extrusion.cpp
index 95617525c7..165476944b 100644
--- a/src/mbgl/renderer/painter_fill_extrusion.cpp
+++ b/src/mbgl/renderer/painters/painter_fill_extrusion.cpp
@@ -1,10 +1,10 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
-#include <mbgl/renderer/fill_extrusion_bucket.hpp>
+#include <mbgl/renderer/buckets/fill_extrusion_bucket.hpp>
#include <mbgl/renderer/render_tile.hpp>
-#include <mbgl/renderer/render_fill_extrusion_layer.hpp>
+#include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp>
+#include <mbgl/renderer/image_manager.hpp>
#include <mbgl/style/layers/fill_extrusion_layer_impl.hpp>
-#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/programs/programs.hpp>
#include <mbgl/programs/fill_extrusion_program.hpp>
#include <mbgl/util/constants.hpp>
@@ -18,23 +18,21 @@ void Painter::renderFillExtrusion(PaintParameters& parameters,
FillExtrusionBucket& bucket,
const RenderFillExtrusionLayer& layer,
const RenderTile& tile) {
- const FillExtrusionPaintProperties::Evaluated& properties = layer.evaluated;
+ const FillExtrusionPaintProperties::PossiblyEvaluated& properties = layer.evaluated;
if (pass == RenderPass::Opaque) {
return;
}
if (!properties.get<FillExtrusionPattern>().from.empty()) {
- optional<SpriteAtlasElement> imagePosA =
- spriteAtlas->getPattern(properties.get<FillExtrusionPattern>().from);
- optional<SpriteAtlasElement> imagePosB =
- spriteAtlas->getPattern(properties.get<FillExtrusionPattern>().to);
+ optional<ImagePosition> imagePosA = imageManager->getPattern(properties.get<FillExtrusionPattern>().from);
+ optional<ImagePosition> imagePosB = imageManager->getPattern(properties.get<FillExtrusionPattern>().to);
if (!imagePosA || !imagePosB) {
return;
}
- spriteAtlas->bind(true, context, 0);
+ imageManager->bind(context, 0);
parameters.programs.fillExtrusionPattern.get(properties).draw(
context,
@@ -46,6 +44,7 @@ void Painter::renderFillExtrusion(PaintParameters& parameters,
tile.translatedClipMatrix(properties.get<FillExtrusionTranslate>(),
properties.get<FillExtrusionTranslateAnchor>(),
state),
+ imageManager->getPixelSize(),
*imagePosA,
*imagePosB,
properties.get<FillExtrusionPattern>(),
diff --git a/src/mbgl/renderer/painter_line.cpp b/src/mbgl/renderer/painters/painter_line.cpp
index 9152ac8512..58f4131d96 100644
--- a/src/mbgl/renderer/painter_line.cpp
+++ b/src/mbgl/renderer/painters/painter_line.cpp
@@ -1,12 +1,12 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
-#include <mbgl/renderer/line_bucket.hpp>
+#include <mbgl/renderer/buckets/line_bucket.hpp>
#include <mbgl/renderer/render_tile.hpp>
-#include <mbgl/renderer/render_line_layer.hpp>
+#include <mbgl/renderer/layers/render_line_layer.hpp>
+#include <mbgl/renderer/image_manager.hpp>
#include <mbgl/style/layers/line_layer_impl.hpp>
#include <mbgl/programs/programs.hpp>
#include <mbgl/programs/line_program.hpp>
-#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/geometry/line_atlas.hpp>
namespace mbgl {
@@ -21,7 +21,7 @@ void Painter::renderLine(PaintParameters& parameters,
return;
}
- const LinePaintProperties::Evaluated& properties = layer.evaluated;
+ const RenderLinePaintProperties::PossiblyEvaluated& properties = layer.evaluated;
auto draw = [&] (auto& program, auto&& uniformValues) {
program.get(properties).draw(
@@ -57,17 +57,16 @@ void Painter::renderLine(PaintParameters& parameters,
pixelsToGLUnits,
posA,
posB,
- layer.dashLineWidth,
lineAtlas->getSize().width));
} else if (!properties.get<LinePattern>().from.empty()) {
- optional<SpriteAtlasElement> posA = spriteAtlas->getPattern(properties.get<LinePattern>().from);
- optional<SpriteAtlasElement> posB = spriteAtlas->getPattern(properties.get<LinePattern>().to);
+ optional<ImagePosition> posA = imageManager->getPattern(properties.get<LinePattern>().from);
+ optional<ImagePosition> posB = imageManager->getPattern(properties.get<LinePattern>().to);
if (!posA || !posB)
return;
- spriteAtlas->bind(true, context, 0);
+ imageManager->bind(context, 0);
draw(parameters.programs.linePattern,
LinePatternProgram::uniformValues(
@@ -75,6 +74,7 @@ void Painter::renderLine(PaintParameters& parameters,
tile,
state,
pixelsToGLUnits,
+ imageManager->getPixelSize(),
*posA,
*posB));
diff --git a/src/mbgl/renderer/painter_raster.cpp b/src/mbgl/renderer/painters/painter_raster.cpp
index fbe025b5b0..56e38ae8f4 100644
--- a/src/mbgl/renderer/painter_raster.cpp
+++ b/src/mbgl/renderer/painters/painter_raster.cpp
@@ -1,8 +1,8 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/render_tile.hpp>
-#include <mbgl/renderer/raster_bucket.hpp>
-#include <mbgl/renderer/render_raster_layer.hpp>
+#include <mbgl/renderer/buckets/raster_bucket.hpp>
+#include <mbgl/renderer/layers/render_raster_layer.hpp>
#include <mbgl/style/layers/raster_layer_impl.hpp>
#include <mbgl/programs/programs.hpp>
#include <mbgl/programs/raster_program.hpp>
@@ -42,13 +42,14 @@ static std::array<float, 3> spinWeights(float spin) {
void Painter::renderRaster(PaintParameters& parameters,
RasterBucket& bucket,
const RenderRasterLayer& layer,
- const RenderTile& tile) {
+ const mat4& matrix,
+ bool useBucketBuffers = false) {
if (pass != RenderPass::Translucent)
return;
if (!bucket.hasData())
return;
- const RasterPaintProperties::Evaluated& properties = layer.evaluated;
+ const RasterPaintProperties::PossiblyEvaluated& properties = layer.evaluated;
const RasterProgram::PaintPropertyBinders paintAttributeData(properties, 0);
assert(bucket.texture);
@@ -62,7 +63,7 @@ void Painter::renderRaster(PaintParameters& parameters,
gl::StencilMode::disabled(),
colorModeForRenderPass(),
RasterProgram::UniformValues {
- uniforms::u_matrix::Value{ tile.matrix },
+ uniforms::u_matrix::Value{ matrix },
uniforms::u_image0::Value{ 0 },
uniforms::u_image1::Value{ 1 },
uniforms::u_opacity::Value{ properties.get<RasterOpacity>() },
@@ -76,9 +77,9 @@ void Painter::renderRaster(PaintParameters& parameters,
uniforms::u_scale_parent::Value{ 1.0f },
uniforms::u_tl_parent::Value{ std::array<float, 2> {{ 0.0f, 0.0f }} },
},
- rasterVertexBuffer,
- quadTriangleIndexBuffer,
- rasterSegments,
+ useBucketBuffers ? *bucket.vertexBuffer : rasterVertexBuffer,
+ useBucketBuffers ? *bucket.indexBuffer : quadTriangleIndexBuffer,
+ useBucketBuffers ? bucket.segments : rasterSegments,
paintAttributeData,
properties,
state.getZoom()
diff --git a/src/mbgl/renderer/painter_symbol.cpp b/src/mbgl/renderer/painters/painter_symbol.cpp
index 86b2146b9f..d3a505aa3f 100644
--- a/src/mbgl/renderer/painter_symbol.cpp
+++ b/src/mbgl/renderer/painters/painter_symbol.cpp
@@ -1,16 +1,15 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
-#include <mbgl/renderer/symbol_bucket.hpp>
+#include <mbgl/renderer/buckets/symbol_bucket.hpp>
#include <mbgl/renderer/render_tile.hpp>
-#include <mbgl/renderer/render_symbol_layer.hpp>
+#include <mbgl/renderer/layers/render_symbol_layer.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <mbgl/text/glyph_atlas.hpp>
-#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/programs/programs.hpp>
#include <mbgl/programs/symbol_program.hpp>
#include <mbgl/programs/collision_box_program.hpp>
#include <mbgl/util/math.hpp>
-#include <mbgl/tile/tile.hpp>
+#include <mbgl/tile/geometry_tile.hpp>
#include <cmath>
@@ -54,7 +53,6 @@ void Painter::renderSymbol(PaintParameters& parameters,
std::move(uniformValues),
*buffers.vertexBuffer,
*symbolSizeBinder,
- values_.layoutSize,
*buffers.indexBuffer,
buffers.segments,
binders,
@@ -63,18 +61,21 @@ void Painter::renderSymbol(PaintParameters& parameters,
);
};
+ assert(dynamic_cast<GeometryTile*>(&tile.tile));
+ GeometryTile& geometryTile = static_cast<GeometryTile&>(tile.tile);
+
if (bucket.hasIconData()) {
auto values = layer.iconPropertyValues(layout);
auto paintPropertyValues = layer.iconPaintProperties();
- SpriteAtlas& atlas = *bucket.spriteAtlas;
- const bool iconScaled = layout.get<IconSize>().constantOr(1.0) != 1.0 ||
- frame.pixelRatio != atlas.getPixelRatio() ||
- bucket.iconsNeedLinear;
+ const bool iconScaled = layout.get<IconSize>().constantOr(1.0) != 1.0 || bucket.iconsNeedLinear;
const bool iconTransformed = values.rotationAlignment == AlignmentType::Map || state.getPitch() != 0;
- atlas.bind(bucket.sdfIcons || state.isChanging() || iconScaled || iconTransformed, context, 0);
- const Size texsize = atlas.getSize();
+ context.bindTexture(*geometryTile.iconAtlasTexture, 0,
+ bucket.sdfIcons || state.isChanging() || iconScaled || iconTransformed
+ ? gl::TextureFilter::Linear : gl::TextureFilter::Nearest);
+
+ const Size texsize = geometryTile.iconAtlasTexture->size;
if (bucket.sdfIcons) {
if (values.hasHalo) {
@@ -108,12 +109,12 @@ void Painter::renderSymbol(PaintParameters& parameters,
}
if (bucket.hasTextData()) {
- glyphAtlas->bind(context, 0);
+ context.bindTexture(*geometryTile.glyphAtlasTexture, 0, gl::TextureFilter::Linear);
auto values = layer.textPropertyValues(layout);
auto paintPropertyValues = layer.textPaintProperties();
- const Size texsize = glyphAtlas->getSize();
+ const Size texsize = geometryTile.glyphAtlasTexture->size;
if (values.hasHalo) {
draw(parameters.programs.symbolGlyph,
@@ -137,7 +138,7 @@ void Painter::renderSymbol(PaintParameters& parameters,
}
if (bucket.hasCollisionBoxData()) {
- static const style::PaintProperties<>::Evaluated properties {};
+ static const style::Properties<>::PossiblyEvaluated properties {};
static const CollisionBoxProgram::PaintPropertyBinders paintAttributeData(properties, 0);
programs->collisionBox.draw(
diff --git a/src/mbgl/renderer/possibly_evaluated_property_value.hpp b/src/mbgl/renderer/possibly_evaluated_property_value.hpp
index a0bcec2bf1..8a5dfbe4ea 100644
--- a/src/mbgl/renderer/possibly_evaluated_property_value.hpp
+++ b/src/mbgl/renderer/possibly_evaluated_property_value.hpp
@@ -19,7 +19,9 @@ private:
public:
PossiblyEvaluatedPropertyValue() = default;
- PossiblyEvaluatedPropertyValue(Value v) : value(std::move(v)) {}
+ PossiblyEvaluatedPropertyValue(Value v, bool useIntegerZoom_ = false)
+ : value(std::move(v)),
+ useIntegerZoom(useIntegerZoom_) {}
bool isConstant() const {
return value.template is<T>();
@@ -48,10 +50,16 @@ public:
return function.evaluate(feature, defaultValue);
},
[&] (const style::CompositeFunction<T>& function) {
- return function.evaluate(zoom, feature, defaultValue);
+ if (useIntegerZoom) {
+ return function.evaluate(floor(zoom), feature, defaultValue);
+ } else {
+ return function.evaluate(zoom, feature, defaultValue);
+ }
}
);
}
+
+ bool useIntegerZoom;
};
namespace util {
diff --git a/src/mbgl/renderer/property_evaluation_parameters.hpp b/src/mbgl/renderer/property_evaluation_parameters.hpp
index 39b663bdb9..da6a4a0892 100644
--- a/src/mbgl/renderer/property_evaluation_parameters.hpp
+++ b/src/mbgl/renderer/property_evaluation_parameters.hpp
@@ -11,20 +11,24 @@ public:
: z(z_),
now(Clock::time_point::max()),
zoomHistory(),
- defaultFadeDuration(0) {}
+ defaultFadeDuration(0),
+ useIntegerZoom(false) {}
PropertyEvaluationParameters(ZoomHistory zoomHistory_,
TimePoint now_,
- Duration defaultFadeDuration_)
+ Duration defaultFadeDuration_,
+ bool useIntegerZoom_ = false)
: z(zoomHistory_.lastZoom),
now(std::move(now_)),
zoomHistory(std::move(zoomHistory_)),
- defaultFadeDuration(std::move(defaultFadeDuration_)) {}
+ defaultFadeDuration(std::move(defaultFadeDuration_)),
+ useIntegerZoom(useIntegerZoom_) {}
float z;
TimePoint now;
ZoomHistory zoomHistory;
Duration defaultFadeDuration;
+ bool useIntegerZoom;
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/raster_bucket.cpp b/src/mbgl/renderer/raster_bucket.cpp
deleted file mode 100644
index ee8ef24071..0000000000
--- a/src/mbgl/renderer/raster_bucket.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-#include <mbgl/renderer/raster_bucket.hpp>
-#include <mbgl/renderer/render_raster_layer.hpp>
-#include <mbgl/programs/raster_program.hpp>
-#include <mbgl/renderer/painter.hpp>
-#include <mbgl/gl/context.hpp>
-
-namespace mbgl {
-
-using namespace style;
-
-RasterBucket::RasterBucket(UnassociatedImage&& image_) : image(std::move(image_)) {
-}
-
-void RasterBucket::upload(gl::Context& context) {
- texture = context.createTexture(std::move(image));
- uploaded = true;
-}
-
-void RasterBucket::render(Painter& painter,
- PaintParameters& parameters,
- const RenderLayer& layer,
- const RenderTile& tile) {
- painter.renderRaster(parameters, *this, *layer.as<RenderRasterLayer>(), tile);
-}
-
-bool RasterBucket::hasData() const {
- return true;
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/renderer/raster_bucket.hpp b/src/mbgl/renderer/raster_bucket.hpp
deleted file mode 100644
index 334954e3f4..0000000000
--- a/src/mbgl/renderer/raster_bucket.hpp
+++ /dev/null
@@ -1,22 +0,0 @@
-#pragma once
-
-#include <mbgl/renderer/bucket.hpp>
-#include <mbgl/util/image.hpp>
-#include <mbgl/util/optional.hpp>
-#include <mbgl/gl/texture.hpp>
-
-namespace mbgl {
-
-class RasterBucket : public Bucket {
-public:
- RasterBucket(UnassociatedImage&&);
-
- void upload(gl::Context&) override;
- void render(Painter&, PaintParameters&, const RenderLayer&, const RenderTile&) override;
- bool hasData() const override;
-
- UnassociatedImage image;
- optional<gl::Texture> texture;
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/renderer/render_custom_layer.cpp b/src/mbgl/renderer/render_custom_layer.cpp
deleted file mode 100644
index 66dd57b3d3..0000000000
--- a/src/mbgl/renderer/render_custom_layer.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-#include <mbgl/renderer/render_custom_layer.hpp>
-#include <mbgl/style/layers/custom_layer_impl.hpp>
-#include <mbgl/renderer/bucket.hpp>
-
-namespace mbgl {
-
-RenderCustomLayer::RenderCustomLayer(const style::CustomLayer::Impl& _impl)
- : RenderLayer(style::LayerType::Custom, _impl),
- impl(&_impl) {
-}
-
-std::unique_ptr<RenderLayer> RenderCustomLayer::clone() const {
- return std::make_unique<RenderCustomLayer>(*this);
-}
-
-void RenderCustomLayer::evaluate(const PropertyEvaluationParameters&) {
- passes = RenderPass::Translucent;
-}
-
-bool RenderCustomLayer::hasTransition() const {
- return false;
-}
-
-std::unique_ptr<Bucket> RenderCustomLayer::createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const {
- assert(false);
- return nullptr;
-}
-
-}
diff --git a/src/mbgl/renderer/render_item.hpp b/src/mbgl/renderer/render_item.hpp
index 787211c30a..4bf5629263 100644
--- a/src/mbgl/renderer/render_item.hpp
+++ b/src/mbgl/renderer/render_item.hpp
@@ -17,13 +17,13 @@ namespace style {
class RenderItem {
public:
- RenderItem(const RenderLayer& layer_,
- std::vector<std::reference_wrapper<RenderTile>> tiles_ = {})
- : layer(layer_), tiles(std::move(tiles_)) {
+ RenderItem(RenderLayer& layer_,
+ RenderSource* renderSource_)
+ : layer(layer_), source(renderSource_) {
}
- const RenderLayer& layer;
- std::vector<std::reference_wrapper<RenderTile>> tiles;
+ RenderLayer& layer;
+ RenderSource* source;
};
class RenderData {
diff --git a/src/mbgl/renderer/render_layer.cpp b/src/mbgl/renderer/render_layer.cpp
index 6699f39144..3f9d68003e 100644
--- a/src/mbgl/renderer/render_layer.cpp
+++ b/src/mbgl/renderer/render_layer.cpp
@@ -1,14 +1,56 @@
#include <mbgl/renderer/render_layer.hpp>
+#include <mbgl/renderer/layers/render_background_layer.hpp>
+#include <mbgl/renderer/layers/render_circle_layer.hpp>
+#include <mbgl/renderer/layers/render_custom_layer.hpp>
+#include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp>
+#include <mbgl/renderer/layers/render_fill_layer.hpp>
+#include <mbgl/renderer/layers/render_line_layer.hpp>
+#include <mbgl/renderer/layers/render_raster_layer.hpp>
+#include <mbgl/renderer/layers/render_symbol_layer.hpp>
#include <mbgl/style/types.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/tile/tile.hpp>
namespace mbgl {
-RenderLayer::RenderLayer(style::LayerType type_, const style::Layer::Impl& baseImpl_)
- : type(type_), baseImpl(baseImpl_) {
+using namespace style;
+
+std::unique_ptr<RenderLayer> RenderLayer::create(Immutable<Layer::Impl> impl) {
+ switch (impl->type) {
+ case LayerType::Fill:
+ return std::make_unique<RenderFillLayer>(staticImmutableCast<FillLayer::Impl>(impl));
+ case LayerType::Line:
+ return std::make_unique<RenderLineLayer>(staticImmutableCast<LineLayer::Impl>(impl));
+ case LayerType::Circle:
+ return std::make_unique<RenderCircleLayer>(staticImmutableCast<CircleLayer::Impl>(impl));
+ case LayerType::Symbol:
+ return std::make_unique<RenderSymbolLayer>(staticImmutableCast<SymbolLayer::Impl>(impl));
+ case LayerType::Raster:
+ return std::make_unique<RenderRasterLayer>(staticImmutableCast<RasterLayer::Impl>(impl));
+ case LayerType::Background:
+ return std::make_unique<RenderBackgroundLayer>(staticImmutableCast<BackgroundLayer::Impl>(impl));
+ case LayerType::Custom:
+ return std::make_unique<RenderCustomLayer>(staticImmutableCast<CustomLayer::Impl>(impl));
+ case LayerType::FillExtrusion:
+ return std::make_unique<RenderFillExtrusionLayer>(staticImmutableCast<FillExtrusionLayer::Impl>(impl));
+ }
+
+ // Not reachable, but placate GCC.
+ assert(false);
+ return nullptr;
+}
+
+RenderLayer::RenderLayer(style::LayerType type_, Immutable<style::Layer::Impl> baseImpl_)
+ : type(type_),
+ baseImpl(baseImpl_) {
+}
+
+void RenderLayer::setImpl(Immutable<style::Layer::Impl> impl) {
+ baseImpl = impl;
}
const std::string& RenderLayer::getID() const {
- return baseImpl.id;
+ return baseImpl->id;
}
bool RenderLayer::hasRenderPass(RenderPass pass) const {
@@ -17,9 +59,23 @@ bool RenderLayer::hasRenderPass(RenderPass pass) const {
bool RenderLayer::needsRendering(float zoom) const {
return passes != RenderPass::None
- && baseImpl.visibility != style::VisibilityType::None
- && baseImpl.minZoom <= zoom
- && baseImpl.maxZoom >= zoom;
+ && baseImpl->visibility != style::VisibilityType::None
+ && baseImpl->minZoom <= zoom
+ && baseImpl->maxZoom >= zoom;
}
-} \ No newline at end of file
+void RenderLayer::setRenderTiles(std::vector<std::reference_wrapper<RenderTile>> tiles) {
+ renderTiles = std::move(tiles);
+}
+
+void RenderLayer::render(Painter& painter, PaintParameters& parameters, RenderSource*) {
+ for (auto& tileRef : renderTiles) {
+ auto& tile = tileRef.get();
+ auto bucket = tile.tile.getBucket(*baseImpl);
+ bucket->render(painter, parameters, *this, tile);
+ }
+}
+
+
+} //namespace mbgl
+
diff --git a/src/mbgl/renderer/render_layer.hpp b/src/mbgl/renderer/render_layer.hpp
index eea2ec1f61..e06f479281 100644
--- a/src/mbgl/renderer/render_layer.hpp
+++ b/src/mbgl/renderer/render_layer.hpp
@@ -12,27 +12,28 @@ namespace mbgl {
class Bucket;
class BucketParameters;
-class CascadeParameters;
+class TransitionParameters;
class PropertyEvaluationParameters;
+class Painter;
+class PaintParameters;
+class RenderSource;
+class RenderTile;
class RenderLayer {
-
protected:
- RenderLayer(style::LayerType, const style::Layer::Impl&);
+ RenderLayer(style::LayerType, Immutable<style::Layer::Impl>);
const style::LayerType type;
public:
+ static std::unique_ptr<RenderLayer> create(Immutable<style::Layer::Impl>);
virtual ~RenderLayer() = default;
- // Create an identical copy of this layer.
- virtual std::unique_ptr<RenderLayer> clone() const = 0;
-
- // Partially evaluate paint properties based on a set of classes.
- virtual void cascade(const CascadeParameters&) = 0;
+ // Begin transitions for any properties that have changed since the last frame.
+ virtual void transition(const TransitionParameters&) = 0;
- // Fully evaluate cascaded paint properties based on a zoom level.
+ // Fully evaluate possibly-transitioning paint properties based on a zoom level.
virtual void evaluate(const PropertyEvaluationParameters&) = 0;
// Returns true if any paint properties have active transitions.
@@ -61,6 +62,8 @@ public:
// Checks whether this layer can be rendered.
bool needsRendering(float zoom) const;
+ virtual void render(Painter&, PaintParameters&, RenderSource*);
+
// Check wether the given geometry intersects
// with the feature
virtual bool queryIntersectsFeature(
@@ -72,15 +75,21 @@ public:
virtual std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const = 0;
+ void setRenderTiles(std::vector<std::reference_wrapper<RenderTile>>);
// Private implementation
- const style::Layer::Impl& baseImpl;
+ Immutable<style::Layer::Impl> baseImpl;
+ void setImpl(Immutable<style::Layer::Impl>);
friend std::string layoutKey(const RenderLayer&);
-protected:
+protected:
// Stores what render passes this layer is currently enabled for. This depends on the
// evaluated StyleProperties object and is updated accordingly.
RenderPass passes = RenderPass::None;
+
+ //Stores current set of tiles to be rendered for this layer.
+ std::vector<std::reference_wrapper<RenderTile>> renderTiles;
+
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/render_light.cpp b/src/mbgl/renderer/render_light.cpp
index 134e1829e0..85768cff47 100644
--- a/src/mbgl/renderer/render_light.cpp
+++ b/src/mbgl/renderer/render_light.cpp
@@ -2,25 +2,17 @@
namespace mbgl {
-RenderLight::RenderLight(std::shared_ptr<const style::Light::Impl> impl_)
- : impl(std::move(impl_)) {
+RenderLight::RenderLight(Immutable<style::Light::Impl> impl_)
+ : impl(std::move(impl_)),
+ transitioning(impl->properties.untransitioned()) {
}
-RenderLight::RenderLight(std::shared_ptr<const style::Light::Impl> impl_, const TransitioningLight transitioning_)
- : impl(std::move(impl_))
- , transitioning(transitioning_) {
-}
-
-std::unique_ptr<RenderLight> RenderLight::copy(std::shared_ptr<const style::Light::Impl> impl_) const {
- return std::make_unique<RenderLight>(std::move(impl_), transitioning);
-}
-
-void RenderLight::transition(const CascadeParameters& parameters) {
- transitioning = TransitioningLight(impl->properties, std::move(transitioning), parameters);
+void RenderLight::transition(const TransitionParameters& parameters) {
+ transitioning = impl->properties.transitioned(parameters, std::move(transitioning));
}
void RenderLight::evaluate(const PropertyEvaluationParameters& parameters) {
- evaluated = EvaluatedLight(transitioning, parameters);
+ evaluated = transitioning.evaluate(parameters);
}
bool RenderLight::hasTransition() const {
diff --git a/src/mbgl/renderer/render_light.hpp b/src/mbgl/renderer/render_light.hpp
index 275f3ae8ba..f13f925318 100644
--- a/src/mbgl/renderer/render_light.hpp
+++ b/src/mbgl/renderer/render_light.hpp
@@ -1,98 +1,29 @@
#pragma once
#include <mbgl/style/light_impl.hpp>
-#include <mbgl/style/light_properties.hpp>
-#include <mbgl/renderer/transitioning_property.hpp>
-#include <mbgl/renderer/cascade_parameters.hpp>
-#include <mbgl/renderer/property_evaluator.hpp>
-#include <mbgl/renderer/property_evaluation_parameters.hpp>
-#include <mbgl/util/ignore.hpp>
-
-#include <memory>
+#include <mbgl/util/immutable.hpp>
namespace mbgl {
-template <class TypeList>
-class Transitioning;
-
-template <class... Ps>
-class Transitioning<TypeList<Ps...>> : public IndexedTuple<
- TypeList<Ps...>,
- TypeList<TransitioningProperty<typename Ps::ValueType>...>>
-{
-private:
- using Properties = TypeList<Ps...>;
- using Raw = IndexedTuple<Properties, Properties>;
- using Super = IndexedTuple<
- TypeList<Ps...>,
- TypeList<TransitioningProperty<typename Ps::ValueType>...>>;
-
-public:
- Transitioning() = default;
- Transitioning(const Raw& raw, Transitioning&& prior, const CascadeParameters& params)
- : Super {
- TransitioningProperty<typename Ps::ValueType>(
- raw.template get<Ps>().value,
- std::move(prior.template get<Ps>()),
- raw.template get<Ps>().transition.reverseMerge(params.transition),
- params.now)...
- } {}
-
- bool hasTransition() const {
- bool result = false;
- util::ignore({ result |= this->template get<Ps>().hasTransition()... });
- return result;
- }
-};
-
-template <class TypeList>
-class Evaluated;
+class TransitionParameters;
+class PropertyEvaluationParameters;
-template <class... Ps>
-class Evaluated<TypeList<Ps...>> : public IndexedTuple<
- TypeList<Ps...>,
- TypeList<typename Ps::Type...>>
-{
-private:
- using Properties = TypeList<Ps...>;
- using TransitioningPs = Transitioning<Properties>;
- using Super = IndexedTuple<
- TypeList<Ps...>,
- TypeList<typename Ps::Type...>>;
-
-public:
- Evaluated() = default;
- Evaluated(TransitioningPs& transitioning, const PropertyEvaluationParameters& params)
- : Super {
- transitioning.template get<Ps>()
- .evaluate(PropertyEvaluator<typename Ps::Type>(params, Ps::defaultValue()), params.now)...
- } {}
-};
-
-using TransitioningLight = Transitioning<style::LightProperties>;
-using EvaluatedLight = Evaluated<style::LightProperties>;
+using TransitioningLight = style::LightProperties::Unevaluated;
+using EvaluatedLight = style::LightProperties::PossiblyEvaluated;
class RenderLight {
public:
- RenderLight(std::shared_ptr<const style::Light::Impl>);
-
- // Creates a copy intitalized with previous transitioning light
- RenderLight(std::shared_ptr<const style::Light::Impl>, const TransitioningLight);
+ RenderLight(Immutable<style::Light::Impl>);
- // creates a copy initialized with previous transitioning
- // values
- std::unique_ptr<RenderLight> copy(std::shared_ptr<const style::Light::Impl>) const;
-
- void transition(const CascadeParameters&);
+ void transition(const TransitionParameters&);
void evaluate(const PropertyEvaluationParameters&);
bool hasTransition() const;
const EvaluatedLight& getEvaluated() const;
- const std::shared_ptr<const style::Light::Impl> impl;
+ Immutable<style::Light::Impl> impl;
private:
-
TransitioningLight transitioning;
EvaluatedLight evaluated;
};
diff --git a/src/mbgl/renderer/render_raster_layer.cpp b/src/mbgl/renderer/render_raster_layer.cpp
deleted file mode 100644
index 5e664e6f58..0000000000
--- a/src/mbgl/renderer/render_raster_layer.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#include <mbgl/renderer/render_raster_layer.hpp>
-#include <mbgl/renderer/bucket.hpp>
-#include <mbgl/style/layers/raster_layer_impl.hpp>
-
-namespace mbgl {
-
-RenderRasterLayer::RenderRasterLayer(const style::RasterLayer::Impl& _impl)
- : RenderLayer(style::LayerType::Raster, _impl),
- impl(&_impl) {
-}
-
-std::unique_ptr<RenderLayer> RenderRasterLayer::clone() const {
- return std::make_unique<RenderRasterLayer>(*this);
-}
-
-std::unique_ptr<Bucket> RenderRasterLayer::createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const {
- assert(false);
- return nullptr;
-}
-
-void RenderRasterLayer::cascade(const CascadeParameters& parameters) {
- unevaluated = impl->cascading.cascade(parameters, std::move(unevaluated));
-}
-
-void RenderRasterLayer::evaluate(const PropertyEvaluationParameters& parameters) {
- evaluated = unevaluated.evaluate(parameters);
-
- passes = evaluated.get<style::RasterOpacity>() > 0 ? RenderPass::Translucent : RenderPass::None;
-}
-
-bool RenderRasterLayer::hasTransition() const {
- return unevaluated.hasTransition();
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/renderer/render_source.cpp b/src/mbgl/renderer/render_source.cpp
index 643d92fe81..7723a1c7ca 100644
--- a/src/mbgl/renderer/render_source.cpp
+++ b/src/mbgl/renderer/render_source.cpp
@@ -1,12 +1,42 @@
#include <mbgl/renderer/render_source.hpp>
#include <mbgl/renderer/render_source_observer.hpp>
+#include <mbgl/renderer/sources/render_geojson_source.hpp>
+#include <mbgl/renderer/sources/render_raster_source.hpp>
+#include <mbgl/renderer/sources/render_vector_source.hpp>
+#include <mbgl/renderer/tile_parameters.hpp>
+#include <mbgl/annotation/render_annotation_source.hpp>
+#include <mbgl/renderer/sources/render_image_source.hpp>
#include <mbgl/tile/tile.hpp>
namespace mbgl {
+using namespace style;
+
+std::unique_ptr<RenderSource> RenderSource::create(Immutable<Source::Impl> impl) {
+ switch (impl->type) {
+ case SourceType::Vector:
+ return std::make_unique<RenderVectorSource>(staticImmutableCast<VectorSource::Impl>(impl));
+ case SourceType::Raster:
+ return std::make_unique<RenderRasterSource>(staticImmutableCast<RasterSource::Impl>(impl));
+ case SourceType::GeoJSON:
+ return std::make_unique<RenderGeoJSONSource>(staticImmutableCast<GeoJSONSource::Impl>(impl));
+ case SourceType::Video:
+ assert(false);
+ return nullptr;
+ case SourceType::Annotations:
+ return std::make_unique<RenderAnnotationSource>(staticImmutableCast<AnnotationSource::Impl>(impl));
+ case SourceType::Image:
+ return std::make_unique<RenderImageSource>(staticImmutableCast<ImageSource::Impl>(impl));
+ }
+
+ // Not reachable, but placate GCC.
+ assert(false);
+ return nullptr;
+}
+
static RenderSourceObserver nullObserver;
-RenderSource::RenderSource(const style::Source::Impl& impl)
+RenderSource::RenderSource(Immutable<style::Source::Impl> impl)
: baseImpl(impl),
observer(&nullObserver) {
}
@@ -23,4 +53,8 @@ void RenderSource::onTileError(Tile& tile, std::exception_ptr error) {
observer->onTileError(*this, tile.id, error);
}
+bool RenderSource::isEnabled() const {
+ return enabled;
}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_source.hpp b/src/mbgl/renderer/render_source.hpp
index d31347579e..b82547b375 100644
--- a/src/mbgl/renderer/render_source.hpp
+++ b/src/mbgl/renderer/render_source.hpp
@@ -6,6 +6,7 @@
#include <mbgl/util/geo.hpp>
#include <mbgl/util/feature.hpp>
#include <mbgl/style/source_impl.hpp>
+#include <mbgl/style/layer_impl.hpp>
#include <unordered_map>
#include <vector>
@@ -17,41 +18,43 @@ namespace mbgl {
class Painter;
class TransformState;
class RenderTile;
+class RenderStyle;
+class RenderLayer;
class RenderedQueryOptions;
class SourceQueryOptions;
class Tile;
class RenderSourceObserver;
class TileParameters;
-namespace algorithm {
-class ClipIDGenerator;
-} // namespace algorithm
-
class RenderSource : protected TileObserver {
public:
- RenderSource(const style::Source::Impl&);
- virtual ~RenderSource() = default;
+ static std::unique_ptr<RenderSource> create(Immutable<style::Source::Impl>);
- virtual bool isLoaded() const = 0;
+ // Check whether this source is of the given subtype.
+ template <class T>
+ bool is() const;
- // Called when the camera has changed. May load new tiles, unload obsolete tiles, or
- // trigger re-placement of existing complete tiles.
- virtual void updateTiles(const TileParameters&) = 0;
+ // Dynamically cast this source to the given subtype.
+ template <class T>
+ T* as() {
+ return is<T>() ? reinterpret_cast<T*>(this) : nullptr;
+ }
- // Removes all tiles (by putting them into the cache).
- virtual void removeTiles() = 0;
+ template <class T>
+ const T* as() const {
+ return is<T>() ? reinterpret_cast<const T*>(this) : nullptr;
+ }
- // Remove all tiles and clear the cache.
- virtual void invalidateTiles() = 0;
+ bool isEnabled() const;
+ virtual bool isLoaded() const = 0;
- // Request that all loaded tiles re-run the layout operation on the existing source
- // data with fresh style information.
- virtual void reloadTiles() = 0;
+ virtual void update(Immutable<style::Source::Impl>,
+ const std::vector<Immutable<style::Layer::Impl>>&,
+ bool needsRendering,
+ bool needsRelayout,
+ const TileParameters&) = 0;
- virtual void startRender(algorithm::ClipIDGenerator&,
- const mat4& projMatrix,
- const mat4& clipMatrix,
- const TransformState&) = 0;
+ virtual void startRender(Painter&) = 0;
virtual void finishRender(Painter&) = 0;
virtual std::map<UnwrappedTileID, RenderTile>& getRenderTiles() = 0;
@@ -59,24 +62,26 @@ public:
virtual std::unordered_map<std::string, std::vector<Feature>>
queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
+ const RenderStyle& style,
const RenderedQueryOptions& options) const = 0;
virtual std::vector<Feature>
querySourceFeatures(const SourceQueryOptions&) const = 0;
- virtual void setCacheSize(size_t) = 0;
virtual void onLowMemory() = 0;
virtual void dumpDebugLogs() const = 0;
void setObserver(RenderSourceObserver*);
- const style::Source::Impl& baseImpl;
- bool enabled = false;
+ Immutable<style::Source::Impl> baseImpl;
protected:
+ RenderSource(Immutable<style::Source::Impl>);
RenderSourceObserver* observer;
+ bool enabled = false;
+
void onTileChanged(Tile&) final;
void onTileError(Tile&, std::exception_ptr) final;
};
diff --git a/src/mbgl/renderer/render_style.cpp b/src/mbgl/renderer/render_style.cpp
new file mode 100644
index 0000000000..91efb6c737
--- /dev/null
+++ b/src/mbgl/renderer/render_style.cpp
@@ -0,0 +1,450 @@
+#include <mbgl/renderer/render_style.hpp>
+#include <mbgl/renderer/render_style_observer.hpp>
+#include <mbgl/renderer/update_parameters.hpp>
+#include <mbgl/renderer/transition_parameters.hpp>
+#include <mbgl/renderer/property_evaluation_parameters.hpp>
+#include <mbgl/renderer/tile_parameters.hpp>
+#include <mbgl/renderer/render_source.hpp>
+#include <mbgl/renderer/render_item.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/layers/render_background_layer.hpp>
+#include <mbgl/renderer/layers/render_circle_layer.hpp>
+#include <mbgl/renderer/layers/render_custom_layer.hpp>
+#include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp>
+#include <mbgl/renderer/layers/render_fill_layer.hpp>
+#include <mbgl/renderer/layers/render_line_layer.hpp>
+#include <mbgl/renderer/layers/render_raster_layer.hpp>
+#include <mbgl/renderer/layers/render_symbol_layer.hpp>
+#include <mbgl/renderer/style_diff.hpp>
+#include <mbgl/renderer/image_manager.hpp>
+#include <mbgl/style/style.hpp>
+#include <mbgl/style/source_impl.hpp>
+#include <mbgl/style/transition_options.hpp>
+#include <mbgl/sprite/sprite_loader.hpp>
+#include <mbgl/text/glyph_manager.hpp>
+#include <mbgl/geometry/line_atlas.hpp>
+#include <mbgl/map/backend_scope.hpp>
+#include <mbgl/map/query.hpp>
+#include <mbgl/tile/tile.hpp>
+#include <mbgl/util/math.hpp>
+#include <mbgl/util/string.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+RenderStyleObserver nullObserver;
+
+RenderStyle::RenderStyle(Scheduler& scheduler_, FileSource& fileSource_)
+ : scheduler(scheduler_),
+ fileSource(fileSource_),
+ glyphManager(std::make_unique<GlyphManager>(fileSource)),
+ imageManager(std::make_unique<ImageManager>()),
+ lineAtlas(std::make_unique<LineAtlas>(Size{ 256, 512 })),
+ imageImpls(makeMutable<std::vector<Immutable<style::Image::Impl>>>()),
+ sourceImpls(makeMutable<std::vector<Immutable<style::Source::Impl>>>()),
+ layerImpls(makeMutable<std::vector<Immutable<style::Layer::Impl>>>()),
+ renderLight(makeMutable<Light::Impl>()),
+ observer(&nullObserver) {
+ glyphManager->setObserver(this);
+}
+
+RenderStyle::~RenderStyle() {
+ assert(BackendScope::exists()); // Required for custom layers.
+}
+
+void RenderStyle::setObserver(RenderStyleObserver* observer_) {
+ observer = observer_;
+}
+
+std::vector<const RenderLayer*> RenderStyle::getRenderLayers() const {
+ std::vector<const RenderLayer*> result;
+ result.reserve(renderLayers.size());
+ for (const auto& layer : *layerImpls) {
+ result.push_back(getRenderLayer(layer->id));
+ }
+ return result;
+}
+
+RenderLayer* RenderStyle::getRenderLayer(const std::string& id) {
+ auto it = renderLayers.find(id);
+ return it != renderLayers.end() ? it->second.get() : nullptr;
+}
+
+const RenderLayer* RenderStyle::getRenderLayer(const std::string& id) const {
+ auto it = renderLayers.find(id);
+ return it != renderLayers.end() ? it->second.get() : nullptr;
+}
+
+const RenderLight& RenderStyle::getRenderLight() const {
+ return renderLight;
+}
+
+void RenderStyle::update(const UpdateParameters& parameters) {
+ assert(BackendScope::exists()); // Required for custom layers.
+
+ const bool zoomChanged = zoomHistory.update(parameters.transformState.getZoom(), parameters.timePoint);
+
+ const TransitionParameters transitionParameters {
+ parameters.timePoint,
+ parameters.mode == MapMode::Continuous ? parameters.transitionOptions : TransitionOptions()
+ };
+
+ const PropertyEvaluationParameters evaluationParameters {
+ zoomHistory,
+ parameters.timePoint,
+ parameters.mode == MapMode::Continuous ? util::DEFAULT_TRANSITION_DURATION : Duration::zero()
+ };
+
+ const TileParameters tileParameters {
+ parameters.pixelRatio,
+ parameters.debugOptions,
+ parameters.transformState,
+ parameters.scheduler,
+ parameters.fileSource,
+ parameters.mode,
+ parameters.annotationManager,
+ *imageManager,
+ *glyphManager
+ };
+
+ glyphManager->setURL(parameters.glyphURL);
+
+ // Update light.
+ const bool lightChanged = renderLight.impl != parameters.light;
+
+ if (lightChanged) {
+ renderLight.impl = parameters.light;
+ renderLight.transition(transitionParameters);
+ }
+
+ if (lightChanged || zoomChanged || renderLight.hasTransition()) {
+ renderLight.evaluate(evaluationParameters);
+ }
+
+
+ const ImageDifference imageDiff = diffImages(imageImpls, parameters.images);
+ imageImpls = parameters.images;
+
+ // Remove removed images from sprite atlas.
+ for (const auto& entry : imageDiff.removed) {
+ imageManager->removeImage(entry.first);
+ }
+
+ // Add added images to sprite atlas.
+ for (const auto& entry : imageDiff.added) {
+ imageManager->addImage(entry.second);
+ }
+
+ // Update changed images.
+ for (const auto& entry : imageDiff.changed) {
+ imageManager->updateImage(entry.second.after);
+ }
+
+ if (parameters.spriteLoaded && !imageManager->isLoaded()) {
+ imageManager->onSpriteLoaded();
+ }
+
+
+ const LayerDifference layerDiff = diffLayers(layerImpls, parameters.layers);
+ layerImpls = parameters.layers;
+
+ // Remove render layers for removed layers.
+ for (const auto& entry : layerDiff.removed) {
+ renderLayers.erase(entry.first);
+ }
+
+ // Create render layers for newly added layers.
+ for (const auto& entry : layerDiff.added) {
+ renderLayers.emplace(entry.first, RenderLayer::create(entry.second));
+ }
+
+ // Update render layers for changed layers.
+ for (const auto& entry : layerDiff.changed) {
+ renderLayers.at(entry.first)->setImpl(entry.second.after);
+ }
+
+ // Update layers for class and zoom changes.
+ for (const auto& entry : renderLayers) {
+ RenderLayer& layer = *entry.second;
+ const bool layerAdded = layerDiff.added.count(entry.first);
+ const bool layerChanged = layerDiff.changed.count(entry.first);
+
+ if (layerAdded || layerChanged) {
+ layer.transition(transitionParameters);
+ }
+
+ if (layerAdded || layerChanged || zoomChanged || layer.hasTransition()) {
+ layer.evaluate(evaluationParameters);
+ }
+ }
+
+
+ const SourceDifference sourceDiff = diffSources(sourceImpls, parameters.sources);
+ sourceImpls = parameters.sources;
+
+ // Remove render layers for removed sources.
+ for (const auto& entry : sourceDiff.removed) {
+ renderSources.erase(entry.first);
+ }
+
+ // Create render sources for newly added sources.
+ for (const auto& entry : sourceDiff.added) {
+ std::unique_ptr<RenderSource> renderSource = RenderSource::create(entry.second);
+ renderSource->setObserver(this);
+ renderSources.emplace(entry.first, std::move(renderSource));
+ }
+
+ // Update all sources.
+ for (const auto& source : *sourceImpls) {
+ std::vector<Immutable<Layer::Impl>> filteredLayers;
+ bool needsRendering = false;
+ bool needsRelayout = false;
+
+ for (const auto& layer : *layerImpls) {
+ if (layer->type == LayerType::Background ||
+ layer->type == LayerType::Custom ||
+ layer->source != source->id) {
+ continue;
+ }
+
+ if (!needsRendering && getRenderLayer(layer->id)->needsRendering(zoomHistory.lastZoom)) {
+ needsRendering = true;
+ }
+
+ if (!needsRelayout && (
+ hasLayoutDifference(layerDiff, layer->id) ||
+ !imageDiff.added.empty() ||
+ !imageDiff.removed.empty() ||
+ !imageDiff.changed.empty())) {
+ needsRelayout = true;
+ }
+
+ filteredLayers.push_back(layer);
+ }
+
+ renderSources.at(source->id)->update(source,
+ filteredLayers,
+ needsRendering,
+ needsRelayout,
+ tileParameters);
+ }
+}
+
+RenderSource* RenderStyle::getRenderSource(const std::string& id) const {
+ auto it = renderSources.find(id);
+ return it != renderSources.end() ? it->second.get() : nullptr;
+}
+
+bool RenderStyle::hasTransitions() const {
+ if (renderLight.hasTransition()) {
+ return true;
+ }
+
+ for (const auto& entry : renderLayers) {
+ if (entry.second->hasTransition()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool RenderStyle::isLoaded() const {
+ for (const auto& entry: renderSources) {
+ if (!entry.second->isLoaded()) {
+ return false;
+ }
+ }
+
+ if (!imageManager->isLoaded()) {
+ return false;
+ }
+
+ return true;
+}
+
+RenderData RenderStyle::getRenderData(MapDebugOptions debugOptions, float angle) {
+ RenderData result;
+
+ for (const auto& entry : renderSources) {
+ if (entry.second->isEnabled()) {
+ result.sources.insert(entry.second.get());
+ }
+ }
+
+ for (auto& layerImpl : *layerImpls) {
+ RenderLayer* layer = getRenderLayer(layerImpl->id);
+ assert(layer);
+
+ if (!layer->needsRendering(zoomHistory.lastZoom)) {
+ continue;
+ }
+
+ if (const RenderBackgroundLayer* background = layer->as<RenderBackgroundLayer>()) {
+ if (debugOptions & MapDebugOptions::Overdraw) {
+ // We want to skip glClear optimization in overdraw mode.
+ result.order.emplace_back(*layer, nullptr);
+ continue;
+ }
+ const BackgroundPaintProperties::PossiblyEvaluated& paint = background->evaluated;
+ if (layerImpl.get() == layerImpls->at(0).get() && paint.get<BackgroundPattern>().from.empty()) {
+ // This is a solid background. We can use glClear().
+ result.backgroundColor = paint.get<BackgroundColor>() * paint.get<BackgroundOpacity>();
+ } else {
+ // This is a textured background, or not the bottommost layer. We need to render it with a quad.
+ result.order.emplace_back(*layer, nullptr);
+ }
+ continue;
+ }
+
+ if (layer->is<RenderCustomLayer>()) {
+ result.order.emplace_back(*layer, nullptr);
+ continue;
+ }
+
+ RenderSource* source = getRenderSource(layer->baseImpl->source);
+ if (!source) {
+ Log::Warning(Event::Render, "can't find source for layer '%s'", layer->getID().c_str());
+ continue;
+ }
+
+ auto& renderTiles = source->getRenderTiles();
+ const bool symbolLayer = layer->is<RenderSymbolLayer>();
+
+ // Sort symbol tiles in opposite y position, so tiles with overlapping
+ // symbols are drawn on top of each other, with lower symbols being
+ // drawn on top of higher symbols.
+ std::vector<std::reference_wrapper<RenderTile>> sortedTiles;
+ std::transform(renderTiles.begin(), renderTiles.end(), std::back_inserter(sortedTiles),
+ [](auto& pair) { return std::ref(pair.second); });
+ if (symbolLayer) {
+ std::sort(sortedTiles.begin(), sortedTiles.end(),
+ [angle](const RenderTile& a, const RenderTile& b) {
+ Point<float> pa(a.id.canonical.x, a.id.canonical.y);
+ Point<float> pb(b.id.canonical.x, b.id.canonical.y);
+
+ auto par = util::rotate(pa, angle);
+ auto pbr = util::rotate(pb, angle);
+
+ return std::tie(par.y, par.x) < std::tie(pbr.y, pbr.x);
+ });
+ }
+
+ std::vector<std::reference_wrapper<RenderTile>> sortedTilesForInsertion;
+ for (auto& sortedTile : sortedTiles) {
+ auto& tile = sortedTile.get();
+ if (!tile.tile.isRenderable()) {
+ continue;
+ }
+
+ // We're not clipping symbol layers, so when we have both parents and children of symbol
+ // layers, we drop all children in favor of their parent to avoid duplicate labels.
+ // See https://github.com/mapbox/mapbox-gl-native/issues/2482
+ if (symbolLayer) {
+ bool skip = false;
+ // Look back through the buckets we decided to render to find out whether there is
+ // already a bucket from this layer that is a parent of this tile. Tiles are ordered
+ // by zoom level when we obtain them from getTiles().
+ for (auto it = sortedTilesForInsertion.rbegin();
+ it != sortedTilesForInsertion.rend(); ++it) {
+ if (tile.tile.id.isChildOf(it->get().tile.id)) {
+ skip = true;
+ break;
+ }
+ }
+ if (skip) {
+ continue;
+ }
+ }
+
+ auto bucket = tile.tile.getBucket(*layer->baseImpl);
+ if (bucket) {
+ sortedTilesForInsertion.emplace_back(tile);
+ tile.used = true;
+ }
+ }
+ layer->setRenderTiles(std::move(sortedTilesForInsertion));
+ result.order.emplace_back(*layer, source);
+ }
+
+ return result;
+}
+
+std::vector<Feature> RenderStyle::queryRenderedFeatures(const ScreenLineString& geometry,
+ const TransformState& transformState,
+ const RenderedQueryOptions& options) const {
+ std::unordered_map<std::string, std::vector<Feature>> resultsByLayer;
+
+ if (options.layerIDs) {
+ std::unordered_set<std::string> sourceIDs;
+ for (const auto& layerID : *options.layerIDs) {
+ if (const RenderLayer* layer = getRenderLayer(layerID)) {
+ sourceIDs.emplace(layer->baseImpl->source);
+ }
+ }
+ for (const auto& sourceID : sourceIDs) {
+ if (RenderSource* renderSource = getRenderSource(sourceID)) {
+ auto sourceResults = renderSource->queryRenderedFeatures(geometry, transformState, *this, options);
+ std::move(sourceResults.begin(), sourceResults.end(), std::inserter(resultsByLayer, resultsByLayer.begin()));
+ }
+ }
+ } else {
+ for (const auto& entry : renderSources) {
+ auto sourceResults = entry.second->queryRenderedFeatures(geometry, transformState, *this, options);
+ std::move(sourceResults.begin(), sourceResults.end(), std::inserter(resultsByLayer, resultsByLayer.begin()));
+ }
+ }
+
+ std::vector<Feature> result;
+
+ if (resultsByLayer.empty()) {
+ return result;
+ }
+
+ // Combine all results based on the style layer order.
+ for (const auto& layerImpl : *layerImpls) {
+ const RenderLayer* layer = getRenderLayer(layerImpl->id);
+ if (!layer->needsRendering(zoomHistory.lastZoom)) {
+ continue;
+ }
+ auto it = resultsByLayer.find(layer->baseImpl->id);
+ if (it != resultsByLayer.end()) {
+ std::move(it->second.begin(), it->second.end(), std::back_inserter(result));
+ }
+ }
+
+ return result;
+}
+
+void RenderStyle::onLowMemory() {
+ for (const auto& entry : renderSources) {
+ entry.second->onLowMemory();
+ }
+}
+
+void RenderStyle::onGlyphsError(const FontStack& fontStack, const GlyphRange& glyphRange, std::exception_ptr error) {
+ Log::Error(Event::Style, "Failed to load glyph range %d-%d for font stack %s: %s",
+ glyphRange.first, glyphRange.second, fontStackToString(fontStack).c_str(), util::toString(error).c_str());
+ observer->onResourceError(error);
+}
+
+void RenderStyle::onTileError(RenderSource& source, const OverscaledTileID& tileID, std::exception_ptr error) {
+ Log::Error(Event::Style, "Failed to load tile %s for source %s: %s",
+ util::toString(tileID).c_str(), source.baseImpl->id.c_str(), util::toString(error).c_str());
+ observer->onResourceError(error);
+}
+
+void RenderStyle::onTileChanged(RenderSource&, const OverscaledTileID&) {
+ observer->onInvalidate();
+}
+
+void RenderStyle::dumpDebugLogs() const {
+ for (const auto& entry : renderSources) {
+ entry.second->dumpDebugLogs();
+ }
+
+ imageManager->dumpDebugLogs();
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_style.hpp b/src/mbgl/renderer/render_style.hpp
new file mode 100644
index 0000000000..23a640c482
--- /dev/null
+++ b/src/mbgl/renderer/render_style.hpp
@@ -0,0 +1,92 @@
+#pragma once
+
+#include <mbgl/style/image.hpp>
+#include <mbgl/renderer/render_source.hpp>
+#include <mbgl/renderer/render_source_observer.hpp>
+#include <mbgl/renderer/render_layer.hpp>
+#include <mbgl/renderer/render_light.hpp>
+#include <mbgl/text/glyph_manager_observer.hpp>
+#include <mbgl/map/zoom_history.hpp>
+#include <mbgl/map/mode.hpp>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace mbgl {
+
+class FileSource;
+class GlyphManager;
+class ImageManager;
+class LineAtlas;
+class RenderData;
+class TransformState;
+class RenderedQueryOptions;
+class Scheduler;
+class UpdateParameters;
+class RenderStyleObserver;
+
+namespace style {
+class Image;
+class Source;
+class Layer;
+} // namespace style
+
+class RenderStyle : public GlyphManagerObserver,
+ public RenderSourceObserver {
+public:
+ RenderStyle(Scheduler&, FileSource&);
+ ~RenderStyle() final;
+
+ void setObserver(RenderStyleObserver*);
+ void update(const UpdateParameters&);
+
+ bool isLoaded() const;
+ bool hasTransitions() const;
+
+ RenderSource* getRenderSource(const std::string& id) const;
+
+ std::vector<const RenderLayer*> getRenderLayers() const;
+
+ RenderLayer* getRenderLayer(const std::string& id);
+ const RenderLayer* getRenderLayer(const std::string& id) const;
+
+ const RenderLight& getRenderLight() const;
+
+ RenderData getRenderData(MapDebugOptions, float angle);
+
+ std::vector<Feature> queryRenderedFeatures(const ScreenLineString& geometry,
+ const TransformState& transformState,
+ const RenderedQueryOptions& options) const;
+
+ void onLowMemory();
+
+ void dumpDebugLogs() const;
+
+ Scheduler& scheduler;
+ FileSource& fileSource;
+ std::unique_ptr<GlyphManager> glyphManager;
+ std::unique_ptr<ImageManager> imageManager;
+ std::unique_ptr<LineAtlas> lineAtlas;
+
+private:
+ Immutable<std::vector<Immutable<style::Image::Impl>>> imageImpls;
+ Immutable<std::vector<Immutable<style::Source::Impl>>> sourceImpls;
+ Immutable<std::vector<Immutable<style::Layer::Impl>>> layerImpls;
+
+ std::unordered_map<std::string, std::unique_ptr<RenderSource>> renderSources;
+ std::unordered_map<std::string, std::unique_ptr<RenderLayer>> renderLayers;
+ RenderLight renderLight;
+
+ // GlyphManagerObserver implementation.
+ void onGlyphsError(const FontStack&, const GlyphRange&, std::exception_ptr) override;
+
+ // RenderSourceObserver implementation.
+ void onTileChanged(RenderSource&, const OverscaledTileID&) override;
+ void onTileError(RenderSource&, const OverscaledTileID&, std::exception_ptr) override;
+
+ RenderStyleObserver* observer;
+ ZoomHistory zoomHistory;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_style_observer.hpp b/src/mbgl/renderer/render_style_observer.hpp
new file mode 100644
index 0000000000..5852dd68b8
--- /dev/null
+++ b/src/mbgl/renderer/render_style_observer.hpp
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <exception>
+
+namespace mbgl {
+
+class RenderStyleObserver {
+public:
+ virtual ~RenderStyleObserver() = default;
+ virtual void onInvalidate() {}
+ virtual void onResourceError(std::exception_ptr) {}
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_tile.cpp b/src/mbgl/renderer/render_tile.cpp
index ce59186e61..59c3ea076b 100644
--- a/src/mbgl/renderer/render_tile.cpp
+++ b/src/mbgl/renderer/render_tile.cpp
@@ -1,5 +1,7 @@
#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/painter.hpp>
#include <mbgl/map/transform_state.hpp>
+#include <mbgl/tile/tile.hpp>
namespace mbgl {
@@ -44,15 +46,15 @@ mat4 RenderTile::translatedClipMatrix(const std::array<float, 2>& translation,
return translateVtxMatrix(nearClippedMatrix, translation, anchor, state);
}
-void RenderTile::calculateMatrices(const mat4& projMatrix,
- const mat4& projClipMatrix,
- const TransformState& transform) {
+void RenderTile::startRender(Painter& painter) {
+ tile.upload(painter.context);
+
// Calculate two matrices for this tile: matrix is the standard tile matrix; nearClippedMatrix
// clips the near plane to 100 to save depth buffer precision
- transform.matrixFor(matrix, id);
- transform.matrixFor(nearClippedMatrix, id);
- matrix::multiply(matrix, projMatrix, matrix);
- matrix::multiply(nearClippedMatrix, projClipMatrix, nearClippedMatrix);
+ painter.state.matrixFor(matrix, id);
+ painter.state.matrixFor(nearClippedMatrix, id);
+ matrix::multiply(matrix, painter.projMatrix, matrix);
+ matrix::multiply(nearClippedMatrix, painter.nearClippedProjMatrix, nearClippedMatrix);
}
} // namespace mbgl
diff --git a/src/mbgl/renderer/render_tile.hpp b/src/mbgl/renderer/render_tile.hpp
index 02e8667eec..6677278873 100644
--- a/src/mbgl/renderer/render_tile.hpp
+++ b/src/mbgl/renderer/render_tile.hpp
@@ -11,6 +11,7 @@ namespace mbgl {
class Tile;
class TransformState;
+class Painter;
class RenderTile {
public:
@@ -35,9 +36,8 @@ public:
style::TranslateAnchorType anchor,
const TransformState&) const;
- void calculateMatrices(const mat4& projMatrix,
- const mat4& projClipMatrix,
- const TransformState&);
+ void startRender(Painter&);
+
private:
mat4 translateVtxMatrix(const mat4& tileMatrix,
const std::array<float, 2>& translation,
diff --git a/src/mbgl/renderer/sources/render_geojson_source.cpp b/src/mbgl/renderer/sources/render_geojson_source.cpp
index 2b1eeea73b..2c6935b273 100644
--- a/src/mbgl/renderer/sources/render_geojson_source.cpp
+++ b/src/mbgl/renderer/sources/render_geojson_source.cpp
@@ -1,5 +1,6 @@
#include <mbgl/renderer/sources/render_geojson_source.hpp>
#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/painter.hpp>
#include <mbgl/tile/geojson_tile.hpp>
#include <mbgl/algorithm/generate_clip_ids.hpp>
@@ -9,35 +10,29 @@ namespace mbgl {
using namespace style;
-RenderGeoJSONSource::RenderGeoJSONSource(const style::GeoJSONSource::Impl& impl_)
- : RenderSource(impl_),
- impl(impl_) {
+RenderGeoJSONSource::RenderGeoJSONSource(Immutable<style::GeoJSONSource::Impl> impl_)
+ : RenderSource(impl_) {
tilePyramid.setObserver(this);
}
-bool RenderGeoJSONSource::isLoaded() const {
- return tilePyramid.isLoaded();
+const style::GeoJSONSource::Impl& RenderGeoJSONSource::impl() const {
+ return static_cast<const style::GeoJSONSource::Impl&>(*baseImpl);
}
-void RenderGeoJSONSource::invalidateTiles() {
- tilePyramid.invalidateTiles();
-}
-
-void RenderGeoJSONSource::startRender(algorithm::ClipIDGenerator& generator, const mat4& projMatrix, const mat4& clipMatrix, const TransformState& transform) {
- generator.update(tilePyramid.getRenderTiles());
- tilePyramid.startRender(projMatrix, clipMatrix, transform);
+bool RenderGeoJSONSource::isLoaded() const {
+ return tilePyramid.isLoaded();
}
-void RenderGeoJSONSource::finishRender(Painter& painter) {
- tilePyramid.finishRender(painter);
-}
+void RenderGeoJSONSource::update(Immutable<style::Source::Impl> baseImpl_,
+ const std::vector<Immutable<Layer::Impl>>& layers,
+ const bool needsRendering,
+ const bool needsRelayout,
+ const TileParameters& parameters) {
+ std::swap(baseImpl, baseImpl_);
-std::map<UnwrappedTileID, RenderTile>& RenderGeoJSONSource::getRenderTiles() {
- return tilePyramid.getRenderTiles();
-}
+ enabled = needsRendering;
-void RenderGeoJSONSource::updateTiles(const TileParameters& parameters) {
- GeoJSONData* data_ = impl.getData();
+ GeoJSONData* data_ = impl().getData();
if (!data_) {
return;
@@ -52,38 +47,43 @@ void RenderGeoJSONSource::updateTiles(const TileParameters& parameters) {
}
}
- tilePyramid.updateTiles(parameters,
- SourceType::GeoJSON,
- util::tileSize,
- impl.getZoomRange(),
- [&] (const OverscaledTileID& tileID) {
- return std::make_unique<GeoJSONTile>(tileID, impl.id, parameters, data->getTile(tileID.canonical));
- });
+ tilePyramid.update(layers,
+ needsRendering,
+ needsRelayout,
+ parameters,
+ SourceType::GeoJSON,
+ util::tileSize,
+ impl().getZoomRange(),
+ [&] (const OverscaledTileID& tileID) {
+ return std::make_unique<GeoJSONTile>(tileID, impl().id, parameters, data->getTile(tileID.canonical));
+ });
}
-void RenderGeoJSONSource::removeTiles() {
- tilePyramid.removeTiles();
+void RenderGeoJSONSource::startRender(Painter& painter) {
+ painter.clipIDGenerator.update(tilePyramid.getRenderTiles());
+ tilePyramid.startRender(painter);
+}
+
+void RenderGeoJSONSource::finishRender(Painter& painter) {
+ tilePyramid.finishRender(painter);
}
-void RenderGeoJSONSource::reloadTiles() {
- tilePyramid.reloadTiles();
+std::map<UnwrappedTileID, RenderTile>& RenderGeoJSONSource::getRenderTiles() {
+ return tilePyramid.getRenderTiles();
}
std::unordered_map<std::string, std::vector<Feature>>
RenderGeoJSONSource::queryRenderedFeatures(const ScreenLineString& geometry,
- const TransformState& transformState,
- const RenderedQueryOptions& options) const {
- return tilePyramid.queryRenderedFeatures(geometry, transformState, options);
+ const TransformState& transformState,
+ const RenderStyle& style,
+ const RenderedQueryOptions& options) const {
+ return tilePyramid.queryRenderedFeatures(geometry, transformState, style, options);
}
std::vector<Feature> RenderGeoJSONSource::querySourceFeatures(const SourceQueryOptions& options) const {
return tilePyramid.querySourceFeatures(options);
}
-void RenderGeoJSONSource::setCacheSize(size_t size) {
- tilePyramid.setCacheSize(size);
-}
-
void RenderGeoJSONSource::onLowMemory() {
tilePyramid.onLowMemory();
}
diff --git a/src/mbgl/renderer/sources/render_geojson_source.hpp b/src/mbgl/renderer/sources/render_geojson_source.hpp
index 262ab29276..b7c5a3fa7f 100644
--- a/src/mbgl/renderer/sources/render_geojson_source.hpp
+++ b/src/mbgl/renderer/sources/render_geojson_source.hpp
@@ -12,28 +12,17 @@ class GeoJSONData;
class RenderGeoJSONSource : public RenderSource {
public:
- RenderGeoJSONSource(const style::GeoJSONSource::Impl&);
+ RenderGeoJSONSource(Immutable<style::GeoJSONSource::Impl>);
bool isLoaded() const final;
- // Called when the camera has changed. May load new tiles, unload obsolete tiles, or
- // trigger re-placement of existing complete tiles.
- void updateTiles(const TileParameters&) final;
+ void update(Immutable<style::Source::Impl>,
+ const std::vector<Immutable<style::Layer::Impl>>&,
+ bool needsRendering,
+ bool needsRelayout,
+ const TileParameters&) final;
- // Removes all tiles (by putting them into the cache).
- void removeTiles() final;
-
- // Remove all tiles and clear the cache.
- void invalidateTiles() final;
-
- // Request that all loaded tiles re-run the layout operation on the existing source
- // data with fresh style information.
- void reloadTiles() final;
-
- void startRender(algorithm::ClipIDGenerator&,
- const mat4& projMatrix,
- const mat4& clipMatrix,
- const TransformState&) final;
+ void startRender(Painter&) final;
void finishRender(Painter&) final;
std::map<UnwrappedTileID, RenderTile>& getRenderTiles() final;
@@ -41,19 +30,25 @@ public:
std::unordered_map<std::string, std::vector<Feature>>
queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
+ const RenderStyle& style,
const RenderedQueryOptions& options) const final;
std::vector<Feature>
querySourceFeatures(const SourceQueryOptions&) const final;
- void setCacheSize(size_t) final;
void onLowMemory() final;
void dumpDebugLogs() const final;
private:
- const style::GeoJSONSource::Impl& impl;
+ const style::GeoJSONSource::Impl& impl() const;
+
TilePyramid tilePyramid;
style::GeoJSONData* data;
};
+template <>
+inline bool RenderSource::is<RenderGeoJSONSource>() const {
+ return baseImpl->type == SourceType::GeoJSON;
+}
+
} // namespace mbgl
diff --git a/src/mbgl/renderer/sources/render_image_source.cpp b/src/mbgl/renderer/sources/render_image_source.cpp
new file mode 100644
index 0000000000..f5068b9d7f
--- /dev/null
+++ b/src/mbgl/renderer/sources/render_image_source.cpp
@@ -0,0 +1,180 @@
+#include <mbgl/map/transform_state.hpp>
+#include <mbgl/math/log2.hpp>
+#include <mbgl/renderer/buckets/raster_bucket.hpp>
+#include <mbgl/renderer/painter.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/sources/render_image_source.hpp>
+#include <mbgl/renderer/tile_parameters.hpp>
+#include <mbgl/util/tile_coordinate.hpp>
+#include <mbgl/util/tile_cover.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+RenderImageSource::RenderImageSource(Immutable<style::ImageSource::Impl> impl_)
+ : RenderSource(impl_), shouldRender(false) {
+}
+
+RenderImageSource::~RenderImageSource() = default;
+
+const style::ImageSource::Impl& RenderImageSource::impl() const {
+ return static_cast<const style::ImageSource::Impl&>(*baseImpl);
+}
+
+bool RenderImageSource::isLoaded() const {
+ return !!bucket;
+}
+
+void RenderImageSource::startRender(Painter& painter) {
+ if (!isLoaded()) {
+ return;
+ }
+
+ matrices.clear();
+
+ for (size_t i = 0; i < tileIds.size(); i++) {
+ mat4 matrix;
+ matrix::identity(matrix);
+ painter.state.matrixFor(matrix, tileIds[i]);
+ matrix::multiply(matrix, painter.projMatrix, matrix);
+ matrices.push_back(matrix);
+ }
+
+ if (bucket->needsUpload() && shouldRender) {
+ bucket->upload(painter.context);
+ }
+}
+
+void RenderImageSource::finishRender(Painter& painter) {
+ if (!isLoaded() || !shouldRender) {
+ return;
+ }
+ for (auto matrix : matrices) {
+ painter.renderTileDebug(matrix);
+ }
+}
+
+std::unordered_map<std::string, std::vector<Feature>>
+RenderImageSource::queryRenderedFeatures(const ScreenLineString&,
+ const TransformState&,
+ const RenderStyle&,
+ const RenderedQueryOptions&) const {
+ return {};
+}
+
+std::vector<Feature> RenderImageSource::querySourceFeatures(const SourceQueryOptions&) const {
+ return {};
+}
+
+void RenderImageSource::update(Immutable<style::Source::Impl> baseImpl_,
+ const std::vector<Immutable<Layer::Impl>>&,
+ const bool needsRendering,
+ const bool,
+ const TileParameters& parameters) {
+ std::swap(baseImpl, baseImpl_);
+
+ enabled = needsRendering;
+
+ auto transformState = parameters.transformState;
+ auto size = transformState.getSize();
+ double viewportHeight = size.height;
+
+ auto coords = impl().getCoordinates();
+
+ // Compute the screen coordinates at wrap=0 for the given LatLng
+ ScreenCoordinate nePixel = { -INFINITY, -INFINITY };
+ ScreenCoordinate swPixel = { INFINITY, INFINITY };
+
+ for (LatLng latLng : coords) {
+ ScreenCoordinate pixel = transformState.latLngToScreenCoordinate(latLng);
+ swPixel.x = std::min(swPixel.x, pixel.x);
+ nePixel.x = std::max(nePixel.x, pixel.x);
+ swPixel.y = std::min(swPixel.y, viewportHeight - pixel.y);
+ nePixel.y = std::max(nePixel.y, viewportHeight - pixel.y);
+ }
+ double width = nePixel.x - swPixel.x;
+ double height = nePixel.y - swPixel.y;
+
+ // Don't bother drawing the ImageSource unless it occupies >4 screen pixels
+ shouldRender = (width * height > 4);
+ if (!shouldRender) {
+ return;
+ }
+
+ // Calculate the optimum zoom level to determine the tile ids to use for transforms
+ double minScale = INFINITY;
+ if (width > 0 || height > 0) {
+ double scaleX = double(size.width) / width;
+ double scaleY = double(size.height) / height;
+ minScale = util::min(scaleX, scaleY);
+ }
+ double zoom = transformState.getZoom() + util::log2(minScale);
+ zoom = util::clamp(zoom, transformState.getMinZoom(), transformState.getMaxZoom());
+
+ auto imageBounds = LatLngBounds::hull(coords[0], coords[1]);
+ imageBounds.extend(coords[2]);
+ imageBounds.extend(coords[3]);
+ auto tileCover = util::tileCover(imageBounds, ::floor(zoom));
+ tileIds.clear();
+ tileIds.push_back(tileCover[0]);
+
+ // Add additional wrapped tile ids if neccessary
+ auto idealTiles = util::tileCover(transformState, transformState.getZoom());
+ for (auto tile : idealTiles) {
+ if (tile.wrap != 0 && tileCover[0].canonical.isChildOf(tile.canonical)) {
+ tileIds.push_back({ tile.wrap, tileCover[0].canonical });
+ }
+ }
+
+ // Calculate Geometry Coordinates based on tile cover at ideal zoom
+ GeometryCoordinates geomCoords;
+ for (auto latLng : coords) {
+ auto tc = TileCoordinate::fromLatLng(0, latLng);
+ auto gc = TileCoordinate::toGeometryCoordinate(tileIds[0], tc.p);
+ geomCoords.push_back(gc);
+ }
+
+ const UnassociatedImage& image = impl().getImage();
+ if (!image.valid()) {
+ return;
+ }
+
+ if (!bucket || image != bucket->image) {
+ bucket = std::make_unique<RasterBucket>(image.clone());
+ } else {
+ bucket->clear();
+ }
+
+ // Set Bucket Vertices, Indices, and segments
+ bucket->vertices.emplace_back(
+ RasterProgram::layoutVertex({ geomCoords[0].x, geomCoords[0].y }, { 0, 0 }));
+ bucket->vertices.emplace_back(
+ RasterProgram::layoutVertex({ geomCoords[1].x, geomCoords[1].y }, { 32767, 0 }));
+ bucket->vertices.emplace_back(
+ RasterProgram::layoutVertex({ geomCoords[3].x, geomCoords[3].y }, { 0, 32767 }));
+ bucket->vertices.emplace_back(
+ RasterProgram::layoutVertex({ geomCoords[2].x, geomCoords[2].y }, { 32767, 32767 }));
+
+ bucket->indices.emplace_back(0, 1, 2);
+ bucket->indices.emplace_back(1, 2, 3);
+
+ bucket->segments.emplace_back(0, 0, 4, 6);
+}
+
+void RenderImageSource::render(Painter& painter,
+ PaintParameters& parameters,
+ const RenderLayer& layer) {
+ if (isLoaded() && !bucket->needsUpload() && shouldRender) {
+ for (auto matrix : matrices) {
+ bucket->render(painter, parameters, layer, matrix);
+ }
+ }
+}
+
+void RenderImageSource::dumpDebugLogs() const {
+ Log::Info(Event::General, "RenderImageSource::id: %s", impl().id.c_str());
+ Log::Info(Event::General, "RenderImageSource::loaded: %s", isLoaded() ? "yes" : "no");
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/sources/render_image_source.hpp b/src/mbgl/renderer/sources/render_image_source.hpp
new file mode 100644
index 0000000000..88f1c56567
--- /dev/null
+++ b/src/mbgl/renderer/sources/render_image_source.hpp
@@ -0,0 +1,64 @@
+#pragma once
+
+#include <mbgl/renderer/render_source.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/style/sources/image_source_impl.hpp>
+
+namespace mbgl {
+class RenderLayer;
+class PaintParameters;
+class RasterBucket;
+
+namespace gl {
+class Context;
+} // namespace gl
+
+class RenderImageSource : public RenderSource {
+public:
+ RenderImageSource(Immutable<style::ImageSource::Impl>);
+ ~RenderImageSource() override;
+
+ bool isLoaded() const final;
+
+ void startRender(Painter&) final;
+ void render(Painter&, PaintParameters&, const RenderLayer&);
+ void finishRender(Painter&) final;
+
+ void update(Immutable<style::Source::Impl>,
+ const std::vector<Immutable<style::Layer::Impl>>&,
+ bool needsRendering,
+ bool needsRelayout,
+ const TileParameters&) final;
+
+ std::map<UnwrappedTileID, RenderTile>& getRenderTiles() final {
+ return tiles;
+ }
+
+ std::unordered_map<std::string, std::vector<Feature>>
+ queryRenderedFeatures(const ScreenLineString& geometry,
+ const TransformState& transformState,
+ const RenderStyle& style,
+ const RenderedQueryOptions& options) const final;
+
+ std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const final;
+
+ void onLowMemory() final {
+ }
+ void dumpDebugLogs() const final;
+
+private:
+ const style::ImageSource::Impl& impl() const;
+ std::map<UnwrappedTileID, RenderTile> tiles;
+
+ std::vector<UnwrappedTileID> tileIds;
+ std::unique_ptr<RasterBucket> bucket;
+ std::vector<mat4> matrices;
+ bool shouldRender;
+};
+
+template <>
+inline bool RenderSource::is<RenderImageSource>() const {
+ return baseImpl->type == SourceType::Image;
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/sources/render_raster_source.cpp b/src/mbgl/renderer/sources/render_raster_source.cpp
index c5a29eebf5..20c148870e 100644
--- a/src/mbgl/renderer/sources/render_raster_source.cpp
+++ b/src/mbgl/renderer/sources/render_raster_source.cpp
@@ -6,34 +6,29 @@ namespace mbgl {
using namespace style;
-RenderRasterSource::RenderRasterSource(const style::RasterSource::Impl& impl_)
- : RenderSource(impl_),
- impl(impl_) {
+RenderRasterSource::RenderRasterSource(Immutable<style::RasterSource::Impl> impl_)
+ : RenderSource(impl_) {
tilePyramid.setObserver(this);
}
+const style::RasterSource::Impl& RenderRasterSource::impl() const {
+ return static_cast<const style::RasterSource::Impl&>(*baseImpl);
+}
+
bool RenderRasterSource::isLoaded() const {
return tilePyramid.isLoaded();
}
-void RenderRasterSource::invalidateTiles() {
- tilePyramid.invalidateTiles();
-}
+void RenderRasterSource::update(Immutable<style::Source::Impl> baseImpl_,
+ const std::vector<Immutable<Layer::Impl>>& layers,
+ const bool needsRendering,
+ const bool needsRelayout,
+ const TileParameters& parameters) {
+ std::swap(baseImpl, baseImpl_);
-void RenderRasterSource::startRender(algorithm::ClipIDGenerator&, const mat4& projMatrix, const mat4& clipMatrix, const TransformState& transform) {
- tilePyramid.startRender(projMatrix, clipMatrix, transform);
-}
+ enabled = needsRendering;
-void RenderRasterSource::finishRender(Painter& painter) {
- tilePyramid.finishRender(painter);
-}
-
-std::map<UnwrappedTileID, RenderTile>& RenderRasterSource::getRenderTiles() {
- return tilePyramid.getRenderTiles();
-}
-
-void RenderRasterSource::updateTiles(const TileParameters& parameters) {
- optional<Tileset> tileset = impl.getTileset();
+ optional<Tileset> tileset = impl().getTileset();
if (!tileset) {
return;
@@ -41,29 +36,42 @@ void RenderRasterSource::updateTiles(const TileParameters& parameters) {
if (tileURLTemplates != tileset->tiles) {
tileURLTemplates = tileset->tiles;
- tilePyramid.invalidateTiles();
+
+ // TODO: this removes existing buckets, and will cause flickering.
+ // Should instead refresh tile data in place.
+ tilePyramid.tiles.clear();
+ tilePyramid.renderTiles.clear();
+ tilePyramid.cache.clear();
}
- tilePyramid.updateTiles(parameters,
- SourceType::Raster,
- impl.getTileSize(),
- tileset->zoomRange,
- [&] (const OverscaledTileID& tileID) {
- return std::make_unique<RasterTile>(tileID, parameters, *tileset);
- });
+ tilePyramid.update(layers,
+ needsRendering,
+ needsRelayout,
+ parameters,
+ SourceType::Raster,
+ impl().getTileSize(),
+ tileset->zoomRange,
+ [&] (const OverscaledTileID& tileID) {
+ return std::make_unique<RasterTile>(tileID, parameters, *tileset);
+ });
}
-void RenderRasterSource::removeTiles() {
- tilePyramid.removeTiles();
+void RenderRasterSource::startRender(Painter& painter) {
+ tilePyramid.startRender(painter);
+}
+
+void RenderRasterSource::finishRender(Painter& painter) {
+ tilePyramid.finishRender(painter);
}
-void RenderRasterSource::reloadTiles() {
- tilePyramid.reloadTiles();
+std::map<UnwrappedTileID, RenderTile>& RenderRasterSource::getRenderTiles() {
+ return tilePyramid.getRenderTiles();
}
std::unordered_map<std::string, std::vector<Feature>>
RenderRasterSource::queryRenderedFeatures(const ScreenLineString&,
const TransformState&,
+ const RenderStyle&,
const RenderedQueryOptions&) const {
return {};
}
@@ -72,10 +80,6 @@ std::vector<Feature> RenderRasterSource::querySourceFeatures(const SourceQueryOp
return {};
}
-void RenderRasterSource::setCacheSize(size_t size) {
- tilePyramid.setCacheSize(size);
-}
-
void RenderRasterSource::onLowMemory() {
tilePyramid.onLowMemory();
}
diff --git a/src/mbgl/renderer/sources/render_raster_source.hpp b/src/mbgl/renderer/sources/render_raster_source.hpp
index 5690ba80ea..7d0c245e45 100644
--- a/src/mbgl/renderer/sources/render_raster_source.hpp
+++ b/src/mbgl/renderer/sources/render_raster_source.hpp
@@ -8,28 +8,17 @@ namespace mbgl {
class RenderRasterSource : public RenderSource {
public:
- RenderRasterSource(const style::RasterSource::Impl&);
+ RenderRasterSource(Immutable<style::RasterSource::Impl>);
bool isLoaded() const final;
- // Called when the camera has changed. May load new tiles, unload obsolete tiles, or
- // trigger re-placement of existing complete tiles.
- void updateTiles(const TileParameters&) final;
+ void update(Immutable<style::Source::Impl>,
+ const std::vector<Immutable<style::Layer::Impl>>&,
+ bool needsRendering,
+ bool needsRelayout,
+ const TileParameters&) final;
- // Removes all tiles (by putting them into the cache).
- void removeTiles() final;
-
- // Remove all tiles and clear the cache.
- void invalidateTiles() final;
-
- // Request that all loaded tiles re-run the layout operation on the existing source
- // data with fresh style information.
- void reloadTiles() final;
-
- void startRender(algorithm::ClipIDGenerator&,
- const mat4& projMatrix,
- const mat4& clipMatrix,
- const TransformState&) final;
+ void startRender(Painter&) final;
void finishRender(Painter&) final;
std::map<UnwrappedTileID, RenderTile>& getRenderTiles() final;
@@ -37,19 +26,25 @@ public:
std::unordered_map<std::string, std::vector<Feature>>
queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
+ const RenderStyle& style,
const RenderedQueryOptions& options) const final;
std::vector<Feature>
querySourceFeatures(const SourceQueryOptions&) const final;
- void setCacheSize(size_t) final;
void onLowMemory() final;
void dumpDebugLogs() const final;
private:
- const style::RasterSource::Impl& impl;
+ const style::RasterSource::Impl& impl() const;
+
TilePyramid tilePyramid;
optional<std::vector<std::string>> tileURLTemplates;
};
+template <>
+inline bool RenderSource::is<RenderRasterSource>() const {
+ return baseImpl->type == SourceType::Raster;
+}
+
} // namespace mbgl
diff --git a/src/mbgl/renderer/sources/render_vector_source.cpp b/src/mbgl/renderer/sources/render_vector_source.cpp
index 0db4698a81..4302fb21ee 100644
--- a/src/mbgl/renderer/sources/render_vector_source.cpp
+++ b/src/mbgl/renderer/sources/render_vector_source.cpp
@@ -1,5 +1,6 @@
#include <mbgl/renderer/sources/render_vector_source.hpp>
#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/painter.hpp>
#include <mbgl/tile/vector_tile.hpp>
#include <mbgl/algorithm/generate_clip_ids.hpp>
@@ -9,35 +10,29 @@ namespace mbgl {
using namespace style;
-RenderVectorSource::RenderVectorSource(const style::VectorSource::Impl& impl_)
- : RenderSource(impl_),
- impl(impl_) {
+RenderVectorSource::RenderVectorSource(Immutable<style::VectorSource::Impl> impl_)
+ : RenderSource(impl_) {
tilePyramid.setObserver(this);
}
+const style::VectorSource::Impl& RenderVectorSource::impl() const {
+ return static_cast<const style::VectorSource::Impl&>(*baseImpl);
+}
+
bool RenderVectorSource::isLoaded() const {
return tilePyramid.isLoaded();
}
-void RenderVectorSource::invalidateTiles() {
- tilePyramid.invalidateTiles();
-}
+void RenderVectorSource::update(Immutable<style::Source::Impl> baseImpl_,
+ const std::vector<Immutable<Layer::Impl>>& layers,
+ const bool needsRendering,
+ const bool needsRelayout,
+ const TileParameters& parameters) {
+ std::swap(baseImpl, baseImpl_);
-void RenderVectorSource::startRender(algorithm::ClipIDGenerator& generator, const mat4& projMatrix, const mat4& clipMatrix, const TransformState& transform) {
- generator.update(tilePyramid.getRenderTiles());
- tilePyramid.startRender(projMatrix, clipMatrix, transform);
-}
+ enabled = needsRendering;
-void RenderVectorSource::finishRender(Painter& painter) {
- tilePyramid.finishRender(painter);
-}
-
-std::map<UnwrappedTileID, RenderTile>& RenderVectorSource::getRenderTiles() {
- return tilePyramid.getRenderTiles();
-}
-
-void RenderVectorSource::updateTiles(const TileParameters& parameters) {
- optional<Tileset> tileset = impl.getTileset();
+ optional<Tileset> tileset = impl().getTileset();
if (!tileset) {
return;
@@ -45,41 +40,51 @@ void RenderVectorSource::updateTiles(const TileParameters& parameters) {
if (tileURLTemplates != tileset->tiles) {
tileURLTemplates = tileset->tiles;
- tilePyramid.invalidateTiles();
+
+ // TODO: this removes existing buckets, and will cause flickering.
+ // Should instead refresh tile data in place.
+ tilePyramid.tiles.clear();
+ tilePyramid.renderTiles.clear();
+ tilePyramid.cache.clear();
}
- tilePyramid.updateTiles(parameters,
- SourceType::Vector,
- util::tileSize,
- tileset->zoomRange,
- [&] (const OverscaledTileID& tileID) {
- return std::make_unique<VectorTile>(tileID, impl.id, parameters, *tileset);
- });
+ tilePyramid.update(layers,
+ needsRendering,
+ needsRelayout,
+ parameters,
+ SourceType::Vector,
+ util::tileSize,
+ tileset->zoomRange,
+ [&] (const OverscaledTileID& tileID) {
+ return std::make_unique<VectorTile>(tileID, impl().id, parameters, *tileset);
+ });
}
-void RenderVectorSource::removeTiles() {
- tilePyramid.removeTiles();
+void RenderVectorSource::startRender(Painter& painter) {
+ painter.clipIDGenerator.update(tilePyramid.getRenderTiles());
+ tilePyramid.startRender(painter);
+}
+
+void RenderVectorSource::finishRender(Painter& painter) {
+ tilePyramid.finishRender(painter);
}
-void RenderVectorSource::reloadTiles() {
- tilePyramid.reloadTiles();
+std::map<UnwrappedTileID, RenderTile>& RenderVectorSource::getRenderTiles() {
+ return tilePyramid.getRenderTiles();
}
std::unordered_map<std::string, std::vector<Feature>>
RenderVectorSource::queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
+ const RenderStyle& style,
const RenderedQueryOptions& options) const {
- return tilePyramid.queryRenderedFeatures(geometry, transformState, options);
+ return tilePyramid.queryRenderedFeatures(geometry, transformState, style, options);
}
std::vector<Feature> RenderVectorSource::querySourceFeatures(const SourceQueryOptions& options) const {
return tilePyramid.querySourceFeatures(options);
}
-void RenderVectorSource::setCacheSize(size_t size) {
- tilePyramid.setCacheSize(size);
-}
-
void RenderVectorSource::onLowMemory() {
tilePyramid.onLowMemory();
}
diff --git a/src/mbgl/renderer/sources/render_vector_source.hpp b/src/mbgl/renderer/sources/render_vector_source.hpp
index 36d75e0982..5e15fee533 100644
--- a/src/mbgl/renderer/sources/render_vector_source.hpp
+++ b/src/mbgl/renderer/sources/render_vector_source.hpp
@@ -8,28 +8,17 @@ namespace mbgl {
class RenderVectorSource : public RenderSource {
public:
- RenderVectorSource(const style::VectorSource::Impl&);
+ RenderVectorSource(Immutable<style::VectorSource::Impl>);
bool isLoaded() const final;
- // Called when the camera has changed. May load new tiles, unload obsolete tiles, or
- // trigger re-placement of existing complete tiles.
- void updateTiles(const TileParameters&) final;
+ void update(Immutable<style::Source::Impl>,
+ const std::vector<Immutable<style::Layer::Impl>>&,
+ bool needsRendering,
+ bool needsRelayout,
+ const TileParameters&) final;
- // Removes all tiles (by putting them into the cache).
- void removeTiles() final;
-
- // Remove all tiles and clear the cache.
- void invalidateTiles() final;
-
- // Request that all loaded tiles re-run the layout operation on the existing source
- // data with fresh style information.
- void reloadTiles() final;
-
- void startRender(algorithm::ClipIDGenerator&,
- const mat4& projMatrix,
- const mat4& clipMatrix,
- const TransformState&) final;
+ void startRender(Painter&) final;
void finishRender(Painter&) final;
std::map<UnwrappedTileID, RenderTile>& getRenderTiles() final;
@@ -37,19 +26,25 @@ public:
std::unordered_map<std::string, std::vector<Feature>>
queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
+ const RenderStyle& style,
const RenderedQueryOptions& options) const final;
std::vector<Feature>
querySourceFeatures(const SourceQueryOptions&) const final;
- void setCacheSize(size_t) final;
void onLowMemory() final;
void dumpDebugLogs() const final;
private:
- const style::VectorSource::Impl& impl;
+ const style::VectorSource::Impl& impl() const;
+
TilePyramid tilePyramid;
optional<std::vector<std::string>> tileURLTemplates;
};
+template <>
+inline bool RenderSource::is<RenderVectorSource>() const {
+ return baseImpl->type == SourceType::Vector;
+}
+
} // namespace mbgl
diff --git a/src/mbgl/renderer/style_diff.cpp b/src/mbgl/renderer/style_diff.cpp
new file mode 100644
index 0000000000..0017280310
--- /dev/null
+++ b/src/mbgl/renderer/style_diff.cpp
@@ -0,0 +1,79 @@
+#include <mbgl/renderer/style_diff.hpp>
+#include <mbgl/style/layer_impl.hpp>
+#include <mbgl/util/immutable.hpp>
+#include <mbgl/util/variant.hpp>
+#include <mbgl/util/longest_common_subsequence.hpp>
+
+namespace mbgl {
+
+template <class T, class Eq>
+StyleDifference<T> diff(const Immutable<std::vector<T>>& a,
+ const Immutable<std::vector<T>>& b,
+ const Eq& eq) {
+ StyleDifference<T> result;
+
+ if (a == b) {
+ return result;
+ }
+
+ std::vector<T> lcs;
+
+ longest_common_subsequence(a->begin(), a->end(), b->begin(), b->end(), std::back_inserter(lcs), eq);
+
+ auto aIt = a->begin();
+ auto bIt = b->begin();
+ auto lIt = lcs.begin();
+
+ while (aIt != a->end() || bIt != b->end()) {
+ if (aIt != a->end() && (lIt == lcs.end() || !eq(*lIt, *aIt))) {
+ result.removed.emplace((*aIt)->id, *aIt);
+ aIt++;
+ } else if (bIt != b->end() && (lIt == lcs.end() || !eq(*lIt, *bIt))) {
+ result.added.emplace((*bIt)->id, *bIt);
+ bIt++;
+ } else {
+ if (aIt->get() != bIt->get()) {
+ result.changed.emplace((*bIt)->id, StyleChange<T> { *aIt, *bIt });
+ }
+ aIt++;
+ bIt++;
+ lIt++;
+ }
+ }
+
+ return result;
+}
+
+ImageDifference diffImages(const Immutable<std::vector<ImmutableImage>>& a,
+ const Immutable<std::vector<ImmutableImage>>& b) {
+ return diff(a, b, [] (const ImmutableImage& lhs, const ImmutableImage& rhs) {
+ return lhs->id == rhs->id;
+ });
+}
+
+SourceDifference diffSources(const Immutable<std::vector<ImmutableSource>>& a,
+ const Immutable<std::vector<ImmutableSource>>& b) {
+ return diff(a, b, [] (const ImmutableSource& lhs, const ImmutableSource& rhs) {
+ return std::tie(lhs->id, lhs->type)
+ == std::tie(rhs->id, rhs->type);
+ });
+}
+
+LayerDifference diffLayers(const Immutable<std::vector<ImmutableLayer>>& a,
+ const Immutable<std::vector<ImmutableLayer>>& b) {
+ return diff(a, b, [] (const ImmutableLayer& lhs, const ImmutableLayer& rhs) {
+ return std::tie(lhs->id, lhs->type)
+ == std::tie(rhs->id, rhs->type);
+ });
+}
+
+bool hasLayoutDifference(const LayerDifference& layerDiff, const std::string& layerID) {
+ if (layerDiff.added.count(layerID))
+ return true;
+ const auto it = layerDiff.changed.find(layerID);
+ if (it == layerDiff.changed.end())
+ return false;
+ return it->second.before->hasLayoutDifference(*it->second.after);
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/style_diff.hpp b/src/mbgl/renderer/style_diff.hpp
new file mode 100644
index 0000000000..a5b42fc662
--- /dev/null
+++ b/src/mbgl/renderer/style_diff.hpp
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <mbgl/style/image_impl.hpp>
+#include <mbgl/style/source_impl.hpp>
+#include <mbgl/style/layer_impl.hpp>
+#include <mbgl/util/immutable.hpp>
+#include <mbgl/util/variant.hpp>
+
+#include <unordered_map>
+
+namespace mbgl {
+
+template <class T>
+class StyleChange {
+public:
+ T before;
+ T after;
+};
+
+template <class T>
+class StyleDifference {
+public:
+ std::unordered_map<std::string, T> added;
+ std::unordered_map<std::string, T> removed;
+ std::unordered_map<std::string, StyleChange<T>> changed;
+};
+
+using ImmutableImage = Immutable<style::Image::Impl>;
+using ImageDifference = StyleDifference<ImmutableImage>;
+
+ImageDifference diffImages(const Immutable<std::vector<ImmutableImage>>&,
+ const Immutable<std::vector<ImmutableImage>>&);
+
+using ImmutableSource = Immutable<style::Source::Impl>;
+using SourceDifference = StyleDifference<ImmutableSource>;
+
+SourceDifference diffSources(const Immutable<std::vector<ImmutableSource>>&,
+ const Immutable<std::vector<ImmutableSource>>&);
+
+using ImmutableLayer = Immutable<style::Layer::Impl>;
+using LayerDifference = StyleDifference<ImmutableLayer>;
+
+LayerDifference diffLayers(const Immutable<std::vector<ImmutableLayer>>&,
+ const Immutable<std::vector<ImmutableLayer>>&);
+
+bool hasLayoutDifference(const LayerDifference&, const std::string& layerID);
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/tile_parameters.hpp b/src/mbgl/renderer/tile_parameters.hpp
index 8f04baaec5..cf7a5b100a 100644
--- a/src/mbgl/renderer/tile_parameters.hpp
+++ b/src/mbgl/renderer/tile_parameters.hpp
@@ -8,30 +8,11 @@ class TransformState;
class Scheduler;
class FileSource;
class AnnotationManager;
-
-namespace style {
-class Style;
-} // namespace style
+class ImageManager;
+class GlyphManager;
class TileParameters {
public:
- TileParameters(float pixelRatio_,
- MapDebugOptions debugOptions_,
- const TransformState& transformState_,
- Scheduler& workerScheduler_,
- FileSource& fileSource_,
- const MapMode mode_,
- AnnotationManager& annotationManager_,
- style::Style& style_)
- : pixelRatio(pixelRatio_),
- debugOptions(debugOptions_),
- transformState(transformState_),
- workerScheduler(workerScheduler_),
- fileSource(fileSource_),
- mode(mode_),
- annotationManager(annotationManager_),
- style(style_) {}
-
float pixelRatio;
MapDebugOptions debugOptions;
const TransformState& transformState;
@@ -39,9 +20,8 @@ public:
FileSource& fileSource;
const MapMode mode;
AnnotationManager& annotationManager;
-
- // TODO: remove
- style::Style& style;
+ ImageManager& imageManager;
+ GlyphManager& glyphManager;
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp
index 144afcb4f6..c2806299e3 100644
--- a/src/mbgl/renderer/tile_pyramid.cpp
+++ b/src/mbgl/renderer/tile_pyramid.cpp
@@ -39,18 +39,9 @@ bool TilePyramid::isLoaded() const {
return true;
}
-void TilePyramid::invalidateTiles() {
- tiles.clear();
- renderTiles.clear();
- cache.clear();
-}
-
-void TilePyramid::startRender(const mat4& projMatrix,
- const mat4& clipMatrix,
- const TransformState& transform) {
+void TilePyramid::startRender(Painter& painter) {
for (auto& pair : renderTiles) {
- auto& tile = pair.second;
- tile.calculateMatrices(projMatrix, clipMatrix, transform);
+ pair.second.startRender(painter);
}
}
@@ -67,11 +58,34 @@ std::map<UnwrappedTileID, RenderTile>& TilePyramid::getRenderTiles() {
return renderTiles;
}
-void TilePyramid::updateTiles(const TileParameters& parameters,
- const SourceType type,
- const uint16_t tileSize,
- const Range<uint8_t> zoomRange,
- std::function<std::unique_ptr<Tile> (const OverscaledTileID&)> createTile) {
+void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layers,
+ const bool needsRendering,
+ const bool needsRelayout,
+ const TileParameters& parameters,
+ const SourceType type,
+ const uint16_t tileSize,
+ const Range<uint8_t> zoomRange,
+ std::function<std::unique_ptr<Tile> (const OverscaledTileID&)> createTile) {
+ // If we need a relayout, abandon any cached tiles; they're now stale.
+ if (needsRelayout) {
+ cache.clear();
+ }
+
+ // If we're not going to render anything, move our existing tiles into
+ // the cache (if they're not stale) or abandon them, and return.
+ if (!needsRendering) {
+ if (!needsRelayout) {
+ for (auto& entry : tiles) {
+ cache.add(entry.first, std::move(entry.second));
+ }
+ }
+
+ tiles.clear();
+ renderTiles.clear();
+
+ return;
+ }
+
// Determine the overzooming/underzooming amounts and required tiles.
int32_t overscaledZoom = util::coveringZoomLevel(parameters.transformState.getZoom(), type, tileSize);
int32_t tileZoom = overscaledZoom;
@@ -97,6 +111,9 @@ void TilePyramid::updateTiles(const TileParameters& parameters,
auto retainTileFn = [&](Tile& tile, Resource::Necessity necessity) -> void {
retain.emplace(tile.id);
tile.setNecessity(necessity);
+ if (needsRelayout) {
+ tile.setLayers(layers);
+ }
};
auto getTileFn = [&](const OverscaledTileID& tileID) -> Tile* {
auto it = tiles.find(tileID);
@@ -108,6 +125,7 @@ void TilePyramid::updateTiles(const TileParameters& parameters,
tile = createTile(tileID);
if (tile) {
tile->setObserver(observer);
+ tile->setLayers(layers);
}
}
if (!tile) {
@@ -163,23 +181,9 @@ void TilePyramid::removeStaleTiles(const std::set<OverscaledTileID>& retain) {
}
}
-void TilePyramid::removeTiles() {
- renderTiles.clear();
- if (!tiles.empty()) {
- removeStaleTiles({});
- }
-}
-
-void TilePyramid::reloadTiles() {
- cache.clear();
-
- for (auto& pair : tiles) {
- pair.second->redoLayout();
- }
-}
-
std::unordered_map<std::string, std::vector<Feature>> TilePyramid::queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
+ const RenderStyle& style,
const RenderedQueryOptions& options) const {
std::unordered_map<std::string, std::vector<Feature>> result;
if (renderTiles.empty() || geometry.empty()) {
@@ -226,6 +230,7 @@ std::unordered_map<std::string, std::vector<Feature>> TilePyramid::queryRendered
renderTile.tile.queryRenderedFeatures(result,
tileSpaceQueryGeometry,
transformState,
+ style,
options);
}
diff --git a/src/mbgl/renderer/tile_pyramid.hpp b/src/mbgl/renderer/tile_pyramid.hpp
index b51c5342de..5846560808 100644
--- a/src/mbgl/renderer/tile_pyramid.hpp
+++ b/src/mbgl/renderer/tile_pyramid.hpp
@@ -5,6 +5,7 @@
#include <mbgl/tile/tile.hpp>
#include <mbgl/tile/tile_cache.hpp>
#include <mbgl/style/types.hpp>
+#include <mbgl/style/layer_impl.hpp>
#include <mbgl/util/mat4.hpp>
#include <mbgl/util/feature.hpp>
@@ -20,6 +21,7 @@ namespace mbgl {
class Painter;
class TransformState;
class RenderTile;
+class RenderStyle;
class RenderedQueryOptions;
class SourceQueryOptions;
class TileParameters;
@@ -31,27 +33,16 @@ public:
bool isLoaded() const;
- // Called when the camera has changed. May load new tiles, unload obsolete tiles, or
- // trigger re-placement of existing complete tiles.
- void updateTiles(const TileParameters&,
- SourceType type,
- uint16_t tileSize,
- Range<uint8_t> zoomRange,
- std::function<std::unique_ptr<Tile> (const OverscaledTileID&)> createTile);
+ void update(const std::vector<Immutable<style::Layer::Impl>>&,
+ bool needsRendering,
+ bool needsRelayout,
+ const TileParameters&,
+ SourceType type,
+ uint16_t tileSize,
+ Range<uint8_t> zoomRange,
+ std::function<std::unique_ptr<Tile> (const OverscaledTileID&)> createTile);
- // Removes all tiles (by putting them into the cache).
- void removeTiles();
-
- // Remove all tiles and clear the cache.
- void invalidateTiles();
-
- // Request that all loaded tiles re-run the layout operation on the existing source
- // data with fresh style information.
- void reloadTiles();
-
- void startRender(const mat4& projMatrix,
- const mat4& clipMatrix,
- const TransformState&);
+ void startRender(Painter&);
void finishRender(Painter&);
std::map<UnwrappedTileID, RenderTile>& getRenderTiles();
@@ -59,6 +50,7 @@ public:
std::unordered_map<std::string, std::vector<Feature>>
queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
+ const RenderStyle& style,
const RenderedQueryOptions& options) const;
std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const;
diff --git a/src/mbgl/renderer/cascade_parameters.hpp b/src/mbgl/renderer/transition_parameters.hpp
index 4096cc5a6b..c47aa2e35f 100644
--- a/src/mbgl/renderer/cascade_parameters.hpp
+++ b/src/mbgl/renderer/transition_parameters.hpp
@@ -1,16 +1,14 @@
#pragma once
#include <mbgl/util/chrono.hpp>
-#include <mbgl/style/class_dictionary.hpp>
#include <mbgl/style/transition_options.hpp>
#include <vector>
namespace mbgl {
-class CascadeParameters {
+class TransitionParameters {
public:
- std::vector<style::ClassID> classes;
TimePoint now;
style::TransitionOptions transition;
};
diff --git a/src/mbgl/renderer/transitioning_property.hpp b/src/mbgl/renderer/transitioning_property.hpp
deleted file mode 100644
index c211ccf116..0000000000
--- a/src/mbgl/renderer/transitioning_property.hpp
+++ /dev/null
@@ -1,75 +0,0 @@
-#pragma once
-
-#include <mbgl/style/property_value.hpp>
-#include <mbgl/style/data_driven_property_value.hpp>
-#include <mbgl/style/transition_options.hpp>
-#include <mbgl/util/interpolate.hpp>
-
-#include <utility>
-
-namespace mbgl {
-
-template <class Value>
-class TransitioningProperty {
-public:
- TransitioningProperty() = default;
-
- TransitioningProperty(Value value_,
- TransitioningProperty<Value> prior_,
- style::TransitionOptions transition,
- TimePoint now)
- : begin(now + transition.delay.value_or(Duration::zero())),
- end(begin + transition.duration.value_or(Duration::zero())),
- value(std::move(value_)) {
- if (transition.isDefined()) {
- prior = { std::move(prior_) };
- }
- }
-
- template <class Evaluator>
- auto evaluate(const Evaluator& evaluator, TimePoint now) {
- auto finalValue = value.evaluate(evaluator);
- if (!prior) {
- // No prior value.
- return finalValue;
- } else if (now >= end) {
- // Transition from prior value is now complete.
- prior = {};
- return finalValue;
- } else if (value.isDataDriven()) {
- // Transitions to data-driven properties are not supported.
- // We snap immediately to the data-driven value so that, when we perform layout,
- // we see the data-driven function and can use it to populate vertex buffers.
- prior = {};
- return finalValue;
- } else if (now < begin) {
- // Transition hasn't started yet.
- return prior->get().evaluate(evaluator, now);
- } else {
- // Interpolate between recursively-calculated prior value and final.
- 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));
- }
- }
-
- bool hasTransition() const {
- return bool(prior);
- }
-
- bool isUndefined() const {
- return value.isUndefined();
- }
-
- const Value& getValue() const {
- return value;
- }
-
-private:
- optional<mapbox::util::recursive_wrapper<TransitioningProperty<Value>>> prior;
- TimePoint begin;
- TimePoint end;
- Value value;
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/renderer/update_parameters.hpp b/src/mbgl/renderer/update_parameters.hpp
index ae54ac09e7..ce79a4f31b 100644
--- a/src/mbgl/renderer/update_parameters.hpp
+++ b/src/mbgl/renderer/update_parameters.hpp
@@ -1,11 +1,15 @@
#pragma once
#include <mbgl/map/mode.hpp>
-#include <mbgl/map/update.hpp>
+#include <mbgl/map/transform_state.hpp>
+#include <mbgl/util/chrono.hpp>
+#include <mbgl/style/light.hpp>
+#include <mbgl/style/image.hpp>
+#include <mbgl/style/source.hpp>
+#include <mbgl/style/layer.hpp>
namespace mbgl {
-class TransformState;
class Scheduler;
class FileSource;
class AnnotationManager;
@@ -13,11 +17,19 @@ class AnnotationManager;
class UpdateParameters {
public:
const MapMode mode;
- const Update updateFlags;
const float pixelRatio;
const MapDebugOptions debugOptions;
const TimePoint timePoint;
- const TransformState& transformState;
+ const TransformState transformState;
+
+ const std::string glyphURL;
+ const bool spriteLoaded;
+ const style::TransitionOptions transitionOptions;
+ const Immutable<style::Light::Impl> light;
+ const Immutable<std::vector<Immutable<style::Image::Impl>>> images;
+ const Immutable<std::vector<Immutable<style::Source::Impl>>> sources;
+ const Immutable<std::vector<Immutable<style::Layer::Impl>>> layers;
+
Scheduler& scheduler;
FileSource& fileSource;
AnnotationManager& annotationManager;
diff --git a/src/mbgl/shaders/fill_extrusion_pattern.cpp b/src/mbgl/shaders/fill_extrusion_pattern.cpp
index 66c24b1bb0..2681973af6 100644
--- a/src/mbgl/shaders/fill_extrusion_pattern.cpp
+++ b/src/mbgl/shaders/fill_extrusion_pattern.cpp
@@ -93,6 +93,7 @@ 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 vec2 u_texsize;
uniform float u_mix;
uniform sampler2D u_image;
@@ -125,11 +126,11 @@ void main() {
#endif
vec2 imagecoord = mod(v_pos_a, 1.0);
- vec2 pos = mix(u_pattern_tl_a, u_pattern_br_a, imagecoord);
+ vec2 pos = mix(u_pattern_tl_a / u_texsize, u_pattern_br_a / u_texsize, 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);
+ vec2 pos2 = mix(u_pattern_tl_b / u_texsize, u_pattern_br_b / u_texsize, imagecoord_b);
vec4 color2 = texture2D(u_image, pos2);
vec4 mixedColor = mix(color1, color2, u_mix);
diff --git a/src/mbgl/shaders/fill_outline.cpp b/src/mbgl/shaders/fill_outline.cpp
index 45bc716be3..18a4d8c0a8 100644
--- a/src/mbgl/shaders/fill_outline.cpp
+++ b/src/mbgl/shaders/fill_outline.cpp
@@ -77,7 +77,7 @@ void main() {
#endif
float dist = length(v_pos - gl_FragCoord.xy);
- float alpha = smoothstep(1.0, 0.0, dist);
+ float alpha = 1.0 - smoothstep(0.0, 1.0, dist);
gl_FragColor = outline_color * (alpha * opacity);
#ifdef OVERDRAW_INSPECTOR
diff --git a/src/mbgl/shaders/fill_outline_pattern.cpp b/src/mbgl/shaders/fill_outline_pattern.cpp
index 5315709e3a..68e69c2135 100644
--- a/src/mbgl/shaders/fill_outline_pattern.cpp
+++ b/src/mbgl/shaders/fill_outline_pattern.cpp
@@ -54,6 +54,7 @@ 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 vec2 u_texsize;
uniform float u_mix;
uniform sampler2D u_image;
@@ -76,17 +77,17 @@ void main() {
#endif
vec2 imagecoord = mod(v_pos_a, 1.0);
- vec2 pos = mix(u_pattern_tl_a, u_pattern_br_a, imagecoord);
+ vec2 pos = mix(u_pattern_tl_a / u_texsize, u_pattern_br_a / u_texsize, 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);
+ vec2 pos2 = mix(u_pattern_tl_b / u_texsize, u_pattern_br_b / u_texsize, 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);
+ float alpha = 1.0 - smoothstep(0.0, 1.0, dist);
gl_FragColor = mix(color1, color2, u_mix) * alpha * opacity;
diff --git a/src/mbgl/shaders/fill_pattern.cpp b/src/mbgl/shaders/fill_pattern.cpp
index dd99e4efff..f6f9e2fbff 100644
--- a/src/mbgl/shaders/fill_pattern.cpp
+++ b/src/mbgl/shaders/fill_pattern.cpp
@@ -50,6 +50,7 @@ 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 vec2 u_texsize;
uniform float u_mix;
uniform sampler2D u_image;
@@ -71,11 +72,11 @@ void main() {
#endif
vec2 imagecoord = mod(v_pos_a, 1.0);
- vec2 pos = mix(u_pattern_tl_a, u_pattern_br_a, imagecoord);
+ vec2 pos = mix(u_pattern_tl_a / u_texsize, u_pattern_br_a / u_texsize, 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);
+ vec2 pos2 = mix(u_pattern_tl_b / u_texsize, u_pattern_br_b / u_texsize, imagecoord_b);
vec4 color2 = texture2D(u_image, pos2);
gl_FragColor = mix(color1, color2, u_mix) * opacity;
diff --git a/src/mbgl/shaders/line.cpp b/src/mbgl/shaders/line.cpp
index dce6046257..1eb92c4b71 100644
--- a/src/mbgl/shaders/line.cpp
+++ b/src/mbgl/shaders/line.cpp
@@ -26,7 +26,6 @@ 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;
@@ -72,6 +71,13 @@ attribute lowp vec2 a_offset;
uniform lowp float u_offset;
#endif
+#ifndef HAS_UNIFORM_u_width
+uniform lowp float a_width_t;
+attribute mediump vec2 a_width;
+#else
+uniform mediump float u_width;
+#endif
+
void main() {
#ifndef HAS_UNIFORM_u_color
@@ -104,6 +110,12 @@ void main() {
lowp float offset = u_offset;
#endif
+#ifndef HAS_UNIFORM_u_width
+ mediump float width = unpack_mix_vec2(a_width, a_width_t);
+#else
+ mediump float width = u_width;
+#endif
+
vec2 a_extrude = a_data.xy - 128.0;
float a_direction = mod(a_data.z, 4.0) - 1.0;
@@ -119,11 +131,11 @@ void main() {
// 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;
+ float halfwidth = 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;
+ float outset = gapwidth + halfwidth * (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.
diff --git a/src/mbgl/shaders/line_pattern.cpp b/src/mbgl/shaders/line_pattern.cpp
index 1c07b4f515..222042a13c 100644
--- a/src/mbgl/shaders/line_pattern.cpp
+++ b/src/mbgl/shaders/line_pattern.cpp
@@ -28,7 +28,6 @@ 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;
@@ -67,6 +66,13 @@ attribute mediump vec2 a_gapwidth;
uniform mediump float u_gapwidth;
#endif
+#ifndef HAS_UNIFORM_u_width
+uniform lowp float a_width_t;
+attribute mediump vec2 a_width;
+#else
+uniform mediump float u_width;
+#endif
+
void main() {
#ifndef HAS_UNIFORM_u_blur
@@ -93,6 +99,12 @@ void main() {
mediump float gapwidth = u_gapwidth;
#endif
+#ifndef HAS_UNIFORM_u_width
+ mediump float width = unpack_mix_vec2(a_width, a_width_t);
+#else
+ mediump float width = u_width;
+#endif
+
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;
@@ -108,11 +120,11 @@ void main() {
// 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;
+ float halfwidth = 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;
+ float outset = gapwidth + halfwidth * (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.
@@ -149,6 +161,7 @@ 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 vec2 u_texsize;
uniform float u_fade;
uniform sampler2D u_image;
@@ -194,8 +207,8 @@ void main() {
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));
+ vec2 pos_a = mix(u_pattern_tl_a / u_texsize, u_pattern_br_a / u_texsize, vec2(x_a, y_a));
+ vec2 pos_b = mix(u_pattern_tl_b / u_texsize, u_pattern_br_b / u_texsize, vec2(x_b, y_b));
vec4 color = mix(texture2D(u_image, pos_a), texture2D(u_image, pos_b), u_fade);
diff --git a/src/mbgl/shaders/line_sdf.cpp b/src/mbgl/shaders/line_sdf.cpp
index b37bf688d4..168f4ca98d 100644
--- a/src/mbgl/shaders/line_sdf.cpp
+++ b/src/mbgl/shaders/line_sdf.cpp
@@ -33,7 +33,6 @@ 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;
@@ -80,6 +79,22 @@ attribute lowp vec2 a_offset;
uniform lowp float u_offset;
#endif
+#ifndef HAS_UNIFORM_u_width
+uniform lowp float a_width_t;
+attribute mediump vec2 a_width;
+varying mediump float width;
+#else
+uniform mediump float u_width;
+#endif
+
+#ifndef HAS_UNIFORM_u_floorwidth
+uniform lowp float a_floorwidth_t;
+attribute lowp vec2 a_floorwidth;
+varying lowp float floorwidth;
+#else
+uniform lowp float u_floorwidth;
+#endif
+
void main() {
#ifndef HAS_UNIFORM_u_color
@@ -112,6 +127,18 @@ void main() {
lowp float offset = u_offset;
#endif
+#ifndef HAS_UNIFORM_u_width
+ width = unpack_mix_vec2(a_width, a_width_t);
+#else
+ mediump float width = u_width;
+#endif
+
+#ifndef HAS_UNIFORM_u_floorwidth
+ floorwidth = unpack_mix_vec2(a_floorwidth, a_floorwidth_t);
+#else
+ lowp float floorwidth = u_floorwidth;
+#endif
+
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;
@@ -127,11 +154,11 @@ void main() {
// 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;
+ float halfwidth = 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;
+ float outset = gapwidth + halfwidth * (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.
@@ -156,8 +183,8 @@ void main() {
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_tex_a = vec2(a_linesofar * u_patternscale_a.x / floorwidth, normal.y * u_patternscale_a.y + u_tex_y_a);
+ v_tex_b = vec2(a_linesofar * u_patternscale_b.x / floorwidth, normal.y * u_patternscale_b.y + u_tex_y_b);
v_width2 = vec2(outset, inset);
}
@@ -194,6 +221,18 @@ varying lowp float opacity;
uniform lowp float u_opacity;
#endif
+#ifndef HAS_UNIFORM_u_width
+varying mediump float width;
+#else
+uniform mediump float u_width;
+#endif
+
+#ifndef HAS_UNIFORM_u_floorwidth
+varying lowp float floorwidth;
+#else
+uniform lowp float u_floorwidth;
+#endif
+
void main() {
#ifdef HAS_UNIFORM_u_color
@@ -208,6 +247,14 @@ void main() {
lowp float opacity = u_opacity;
#endif
+#ifdef HAS_UNIFORM_u_width
+ mediump float width = u_width;
+#endif
+
+#ifdef HAS_UNIFORM_u_floorwidth
+ lowp float floorwidth = u_floorwidth;
+#endif
+
// Calculate the distance of the pixel from the line in pixels.
float dist = length(v_normal) * v_width2.s;
@@ -220,7 +267,7 @@ void main() {
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);
+ alpha *= smoothstep(0.5 - u_sdfgamma / floorwidth, 0.5 + u_sdfgamma / floorwidth, sdfdist);
gl_FragColor = color * (alpha * opacity);
diff --git a/src/mbgl/sprite/sprite_atlas.cpp b/src/mbgl/sprite/sprite_atlas.cpp
deleted file mode 100644
index fed8451aed..0000000000
--- a/src/mbgl/sprite/sprite_atlas.cpp
+++ /dev/null
@@ -1,340 +0,0 @@
-#include <mbgl/sprite/sprite_atlas.hpp>
-#include <mbgl/sprite/sprite_atlas_worker.hpp>
-#include <mbgl/sprite/sprite_atlas_observer.hpp>
-#include <mbgl/sprite/sprite_parser.hpp>
-#include <mbgl/gl/context.hpp>
-#include <mbgl/util/logging.hpp>
-#include <mbgl/util/platform.hpp>
-#include <mbgl/util/math.hpp>
-#include <mbgl/util/std.hpp>
-#include <mbgl/util/constants.hpp>
-#include <mbgl/util/exception.hpp>
-#include <mbgl/storage/file_source.hpp>
-#include <mbgl/storage/resource.hpp>
-#include <mbgl/storage/response.hpp>
-#include <mbgl/util/run_loop.hpp>
-#include <mbgl/actor/actor.hpp>
-
-#include <cassert>
-#include <cmath>
-#include <algorithm>
-
-namespace mbgl {
-
-static SpriteAtlasObserver nullObserver;
-
-struct SpriteAtlas::Loader {
- Loader(Scheduler& scheduler, SpriteAtlas& spriteAtlas)
- : mailbox(std::make_shared<Mailbox>(*util::RunLoop::Get())),
- worker(scheduler, ActorRef<SpriteAtlas>(spriteAtlas, mailbox)) {
- }
-
- std::shared_ptr<const std::string> image;
- std::shared_ptr<const std::string> json;
- std::unique_ptr<AsyncRequest> jsonRequest;
- std::unique_ptr<AsyncRequest> spriteRequest;
- std::shared_ptr<Mailbox> mailbox;
- Actor<SpriteAtlasWorker> worker;
-};
-
-SpriteAtlasElement::SpriteAtlasElement(Rect<uint16_t> rect_,
- const style::Image& image,
- Size size_, float pixelRatio)
- : pos(std::move(rect_)),
- sdf(image.sdf),
- relativePixelRatio(image.pixelRatio / pixelRatio),
- width(image.getWidth()),
- height(image.getHeight()) {
-
- const float padding = 1;
-
- const float w = image.getWidth() * relativePixelRatio;
- const float h = image.getHeight() * relativePixelRatio;
-
- size = {{ float(image.getWidth()), image.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_),
- observer(&nullObserver),
- bin(size.width, size.height),
- dirty(true) {
-}
-
-SpriteAtlas::~SpriteAtlas() = default;
-
-void SpriteAtlas::load(const std::string& url, Scheduler& scheduler, FileSource& fileSource) {
- if (url.empty()) {
- // Treat a non-existent sprite as a successfully loaded empty sprite.
- markAsLoaded();
- return;
- }
-
- loader = std::make_unique<Loader>(scheduler, *this);
-
- loader->jsonRequest = fileSource.request(Resource::spriteJSON(url, pixelRatio), [this](Response res) {
- if (res.error) {
- observer->onSpriteError(std::make_exception_ptr(std::runtime_error(res.error->message)));
- } else if (res.notModified) {
- return;
- } else if (res.noContent) {
- loader->json = std::make_shared<const std::string>();
- emitSpriteLoadedIfComplete();
- } else {
- // Only trigger a sprite loaded event we got new data.
- loader->json = res.data;
- emitSpriteLoadedIfComplete();
- }
- });
-
- loader->spriteRequest = fileSource.request(Resource::spriteImage(url, pixelRatio), [this](Response res) {
- if (res.error) {
- observer->onSpriteError(std::make_exception_ptr(std::runtime_error(res.error->message)));
- } else if (res.notModified) {
- return;
- } else if (res.noContent) {
- loader->image = std::make_shared<const std::string>();
- emitSpriteLoadedIfComplete();
- } else {
- loader->image = res.data;
- emitSpriteLoadedIfComplete();
- }
- });
-}
-
-void SpriteAtlas::emitSpriteLoadedIfComplete() {
- assert(loader);
-
- if (!loader->image || !loader->json) {
- return;
- }
-
- loader->worker.invoke(&SpriteAtlasWorker::parse, loader->image, loader->json);
- // TODO: delete the loader?
-}
-
-void SpriteAtlas::onParsed(Images&& result) {
- markAsLoaded();
- for (auto& pair : result) {
- addImage(pair.first, std::move(pair.second));
- }
- observer->onSpriteLoaded();
- for (auto requestor : requestors) {
- requestor->onIconsAvailable(buildIconMap());
- }
- requestors.clear();
-}
-
-void SpriteAtlas::onError(std::exception_ptr err) {
- observer->onSpriteError(err);
-}
-
-void SpriteAtlas::setObserver(SpriteAtlasObserver* observer_) {
- observer = observer_;
-}
-
-void SpriteAtlas::dumpDebugLogs() const {
- Log::Info(Event::General, "SpriteAtlas::loaded: %d", loaded);
-}
-
-void SpriteAtlas::addImage(const std::string& id, std::unique_ptr<style::Image> image_) {
- icons.clear();
-
- auto it = entries.find(id);
- if (it == entries.end()) {
- entries.emplace(id, Entry { std::move(image_), {}, {} });
- return;
- }
-
- Entry& entry = it->second;
-
- // There is already a sprite with that name in our store.
- if (entry.image->image.size != image_->image.size) {
- Log::Warning(Event::Sprite, "Can't change sprite dimensions for '%s'", id.c_str());
- return;
- }
-
- entry.image = std::move(image_);
-
- if (entry.iconRect) {
- copy(entry, &Entry::iconRect);
- }
-
- if (entry.patternRect) {
- copy(entry, &Entry::patternRect);
- }
-}
-
-void SpriteAtlas::removeImage(const std::string& id) {
- icons.clear();
-
- auto it = entries.find(id);
- 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);
-}
-
-const style::Image* SpriteAtlas::getImage(const std::string& id) const {
- const auto it = entries.find(id);
- if (it != entries.end()) {
- return it->second.image.get();
- }
- if (!entries.empty()) {
- Log::Info(Event::Sprite, "Can't find sprite named '%s'", id.c_str());
- }
- return nullptr;
-}
-
-void SpriteAtlas::getIcons(IconRequestor& requestor) {
- if (isLoaded()) {
- requestor.onIconsAvailable(buildIconMap());
- } else {
- requestors.insert(&requestor);
- }
-}
-
-void SpriteAtlas::removeRequestor(IconRequestor& requestor) {
- requestors.erase(&requestor);
-}
-
-optional<SpriteAtlasElement> SpriteAtlas::getIcon(const std::string& id) {
- return getImage(id, &Entry::iconRect);
-}
-
-optional<SpriteAtlasElement> SpriteAtlas::getPattern(const std::string& id) {
- return getImage(id, &Entry::patternRect);
-}
-
-optional<SpriteAtlasElement> SpriteAtlas::getImage(const std::string& id,
- optional<Rect<uint16_t>> Entry::*entryRect) {
-
- auto it = entries.find(id);
- if (it == entries.end()) {
- if (!entries.empty()) {
- Log::Info(Event::Sprite, "Can't find sprite named '%s'", id.c_str());
- }
- return {};
- }
-
- Entry& entry = it->second;
-
- if (entry.*entryRect) {
- assert(entry.image.get());
- return SpriteAtlasElement {
- *(entry.*entryRect),
- *entry.image,
- size,
- pixelRatio
- };
- }
-
- const uint16_t pixelWidth = std::ceil(entry.image->image.size.width / pixelRatio);
- const uint16_t pixelHeight = std::ceil(entry.image->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");
- }
- return {};
- }
-
- entry.*entryRect = rect;
- copy(entry, entryRect);
-
- return SpriteAtlasElement {
- rect,
- *entry.image,
- size,
- pixelRatio
- };
-}
-
-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)) });
- image.fill(0);
- }
-
- const PremultipliedImage& src = entry.image->image;
- const Rect<uint16_t>& rect = *(entry.*entryRect);
-
- 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;
-
- PremultipliedImage::copy(src, image, { 0, 0 }, { x, y }, { w, h });
-
- 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
- }
-
- dirty = true;
-}
-
-IconMap SpriteAtlas::buildIconMap() {
- if (icons.empty()) {
- for (const auto& entry : entries) {
- icons.emplace(std::piecewise_construct,
- std::forward_as_tuple(entry.first),
- std::forward_as_tuple(*getIcon(entry.first)));
-
- }
- }
- return icons;
-}
-
-void SpriteAtlas::upload(gl::Context& context, gl::TextureUnit unit) {
- if (!texture) {
- texture = context.createTexture(image, unit);
- } else if (dirty) {
- context.updateTexture(*texture, image, unit);
- }
-
-#if not MBGL_USE_GLES2
-// if (dirty) {
-// platform::showColorDebugImage("Sprite Atlas",
-// reinterpret_cast<const char*>(image.data.get()), size.width,
-// size.height, image.size.width, image.size.height);
-// }
-#endif // MBGL_USE_GLES2
-
- dirty = false;
-}
-
-void SpriteAtlas::bind(bool linear, gl::Context& context, gl::TextureUnit unit) {
- upload(context, unit);
- context.bindTexture(*texture, unit,
- linear ? gl::TextureFilter::Linear : gl::TextureFilter::Nearest);
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/sprite/sprite_atlas.hpp b/src/mbgl/sprite/sprite_atlas.hpp
deleted file mode 100644
index c3efeff44b..0000000000
--- a/src/mbgl/sprite/sprite_atlas.hpp
+++ /dev/null
@@ -1,140 +0,0 @@
-#pragma once
-
-#include <mbgl/geometry/binpack.hpp>
-#include <mbgl/gl/texture.hpp>
-#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/util/optional.hpp>
-#include <mbgl/style/image.hpp>
-
-#include <string>
-#include <map>
-#include <set>
-#include <unordered_map>
-#include <array>
-#include <memory>
-
-namespace mbgl {
-
-class Scheduler;
-class FileSource;
-class SpriteAtlasObserver;
-
-namespace gl {
-class Context;
-} // namespace gl
-
-class SpriteAtlasElement {
-public:
- SpriteAtlasElement(Rect<uint16_t>, const style::Image&, Size size, float pixelRatio);
-
- Rect<uint16_t> pos;
- bool sdf;
-
- float relativePixelRatio;
- std::array<float, 2> size;
- std::array<float, 2> tl;
- std::array<float, 2> br;
- float width;
- float height;
-};
-
-typedef std::map<std::string, SpriteAtlasElement> IconMap;
-typedef std::set<std::string> IconDependencies;
-
-class IconRequestor {
-public:
- virtual ~IconRequestor() = default;
- virtual void onIconsAvailable(IconMap) = 0;
-};
-
-class SpriteAtlas : public util::noncopyable {
-public:
- using Images = std::map<std::string, std::unique_ptr<style::Image>>;
-
- SpriteAtlas(Size, float pixelRatio);
- ~SpriteAtlas();
-
- void load(const std::string& url, Scheduler&, FileSource&);
-
- void markAsLoaded() {
- loaded = true;
- }
-
- bool isLoaded() const {
- return loaded;
- }
-
- void dumpDebugLogs() const;
-
- void setObserver(SpriteAtlasObserver*);
-
- const style::Image* getImage(const std::string&) const;
- void addImage(const std::string&, std::unique_ptr<style::Image>);
- void removeImage(const std::string&);
-
- void getIcons(IconRequestor& requestor);
- void removeRequestor(IconRequestor& requestor);
-
- 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);
-
- // 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);
-
- Size getSize() const { return size; }
- float getPixelRatio() const { return pixelRatio; }
-
- // Only for use in tests.
- const PremultipliedImage& getAtlasImage() const {
- return image;
- }
-
-private:
- void emitSpriteLoadedIfComplete();
-
- // Invoked by SpriteAtlasWorker
- friend class SpriteAtlasWorker;
- void onParsed(Images&& result);
- void onError(std::exception_ptr);
-
- const Size size;
- const float pixelRatio;
-
- struct Loader;
- std::unique_ptr<Loader> loader;
-
- bool loaded = false;
-
- SpriteAtlasObserver* observer = nullptr;
-
- struct Entry {
- std::unique_ptr<style::Image> image;
-
- // 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;
- };
-
- optional<SpriteAtlasElement> getImage(const std::string& name, optional<Rect<uint16_t>> Entry::*rect);
- void copy(const Entry&, optional<Rect<uint16_t>> Entry::*rect);
-
- IconMap buildIconMap();
-
- std::unordered_map<std::string, Entry> entries;
- BinPack<uint16_t> bin;
- PremultipliedImage image;
- mbgl::optional<gl::Texture> texture;
- bool dirty;
-
- std::set<IconRequestor*> requestors;
- IconMap icons;
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/sprite/sprite_atlas_observer.hpp b/src/mbgl/sprite/sprite_atlas_observer.hpp
deleted file mode 100644
index 263c95b0e8..0000000000
--- a/src/mbgl/sprite/sprite_atlas_observer.hpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#pragma once
-
-#include <exception>
-
-namespace mbgl {
-
-class SpriteAtlasObserver {
-public:
- virtual ~SpriteAtlasObserver() = default;
-
- virtual void onSpriteLoaded() {}
- virtual void onSpriteError(std::exception_ptr) {}
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/sprite/sprite_loader.cpp b/src/mbgl/sprite/sprite_loader.cpp
new file mode 100644
index 0000000000..60ece5ed73
--- /dev/null
+++ b/src/mbgl/sprite/sprite_loader.cpp
@@ -0,0 +1,104 @@
+#include <mbgl/sprite/sprite_loader.hpp>
+#include <mbgl/sprite/sprite_loader_worker.hpp>
+#include <mbgl/sprite/sprite_loader_observer.hpp>
+#include <mbgl/sprite/sprite_parser.hpp>
+#include <mbgl/util/logging.hpp>
+#include <mbgl/util/platform.hpp>
+#include <mbgl/util/std.hpp>
+#include <mbgl/util/constants.hpp>
+#include <mbgl/util/exception.hpp>
+#include <mbgl/storage/file_source.hpp>
+#include <mbgl/storage/resource.hpp>
+#include <mbgl/storage/response.hpp>
+#include <mbgl/util/run_loop.hpp>
+#include <mbgl/actor/actor.hpp>
+
+#include <cassert>
+
+namespace mbgl {
+
+static SpriteLoaderObserver nullObserver;
+
+struct SpriteLoader::Loader {
+ Loader(Scheduler& scheduler, SpriteLoader& imageManager)
+ : mailbox(std::make_shared<Mailbox>(*util::RunLoop::Get())),
+ worker(scheduler, ActorRef<SpriteLoader>(imageManager, mailbox)) {
+ }
+
+ std::shared_ptr<const std::string> image;
+ std::shared_ptr<const std::string> json;
+ std::unique_ptr<AsyncRequest> jsonRequest;
+ std::unique_ptr<AsyncRequest> spriteRequest;
+ std::shared_ptr<Mailbox> mailbox;
+ Actor<SpriteLoaderWorker> worker;
+};
+
+SpriteLoader::SpriteLoader(float pixelRatio_)
+ : pixelRatio(pixelRatio_)
+ , observer(&nullObserver) {
+}
+
+SpriteLoader::~SpriteLoader() = default;
+
+void SpriteLoader::load(const std::string& url, Scheduler& scheduler, FileSource& fileSource) {
+ if (url.empty()) {
+ // Treat a non-existent sprite as a successfully loaded empty sprite.
+ observer->onSpriteLoaded({});
+ return;
+ }
+
+ loader = std::make_unique<Loader>(scheduler, *this);
+
+ loader->jsonRequest = fileSource.request(Resource::spriteJSON(url, pixelRatio), [this](Response res) {
+ if (res.error) {
+ observer->onSpriteError(std::make_exception_ptr(std::runtime_error(res.error->message)));
+ } else if (res.notModified) {
+ return;
+ } else if (res.noContent) {
+ loader->json = std::make_shared<const std::string>();
+ emitSpriteLoadedIfComplete();
+ } else {
+ // Only trigger a sprite loaded event we got new data.
+ loader->json = res.data;
+ emitSpriteLoadedIfComplete();
+ }
+ });
+
+ loader->spriteRequest = fileSource.request(Resource::spriteImage(url, pixelRatio), [this](Response res) {
+ if (res.error) {
+ observer->onSpriteError(std::make_exception_ptr(std::runtime_error(res.error->message)));
+ } else if (res.notModified) {
+ return;
+ } else if (res.noContent) {
+ loader->image = std::make_shared<const std::string>();
+ emitSpriteLoadedIfComplete();
+ } else {
+ loader->image = res.data;
+ emitSpriteLoadedIfComplete();
+ }
+ });
+}
+
+void SpriteLoader::emitSpriteLoadedIfComplete() {
+ assert(loader);
+
+ if (!loader->image || !loader->json) {
+ return;
+ }
+
+ loader->worker.invoke(&SpriteLoaderWorker::parse, loader->image, loader->json);
+}
+
+void SpriteLoader::onParsed(std::vector<std::unique_ptr<style::Image>>&& result) {
+ observer->onSpriteLoaded(std::move(result));
+}
+
+void SpriteLoader::onError(std::exception_ptr err) {
+ observer->onSpriteError(err);
+}
+
+void SpriteLoader::setObserver(SpriteLoaderObserver* observer_) {
+ observer = observer_;
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/sprite/sprite_loader.hpp b/src/mbgl/sprite/sprite_loader.hpp
new file mode 100644
index 0000000000..0daf46be9c
--- /dev/null
+++ b/src/mbgl/sprite/sprite_loader.hpp
@@ -0,0 +1,44 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/style/image.hpp>
+
+#include <string>
+#include <map>
+#include <set>
+#include <vector>
+#include <array>
+#include <memory>
+
+namespace mbgl {
+
+class Scheduler;
+class FileSource;
+class SpriteLoaderObserver;
+
+class SpriteLoader : public util::noncopyable {
+public:
+ SpriteLoader(float pixelRatio);
+ ~SpriteLoader();
+
+ void load(const std::string& url, Scheduler&, FileSource&);
+
+ void setObserver(SpriteLoaderObserver*);
+
+private:
+ void emitSpriteLoadedIfComplete();
+
+ // Invoked by SpriteAtlasWorker
+ friend class SpriteLoaderWorker;
+ void onParsed(std::vector<std::unique_ptr<style::Image>>&&);
+ void onError(std::exception_ptr);
+
+ const float pixelRatio;
+
+ struct Loader;
+ std::unique_ptr<Loader> loader;
+
+ SpriteLoaderObserver* observer = nullptr;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/sprite/sprite_loader_observer.hpp b/src/mbgl/sprite/sprite_loader_observer.hpp
new file mode 100644
index 0000000000..c730549c2c
--- /dev/null
+++ b/src/mbgl/sprite/sprite_loader_observer.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <exception>
+#include <memory>
+#include <vector>
+
+namespace mbgl {
+
+namespace style {
+class Image;
+} // namespace style
+
+class SpriteLoaderObserver {
+public:
+ virtual ~SpriteLoaderObserver() = default;
+
+ virtual void onSpriteLoaded(std::vector<std::unique_ptr<style::Image>>&&) {}
+ virtual void onSpriteError(std::exception_ptr) {}
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/sprite/sprite_atlas_worker.cpp b/src/mbgl/sprite/sprite_loader_worker.cpp
index da507aabab..4bded33d53 100644
--- a/src/mbgl/sprite/sprite_atlas_worker.cpp
+++ b/src/mbgl/sprite/sprite_loader_worker.cpp
@@ -1,14 +1,14 @@
-#include <mbgl/sprite/sprite_atlas_worker.hpp>
-#include <mbgl/sprite/sprite_atlas.hpp>
+#include <mbgl/sprite/sprite_loader_worker.hpp>
+#include <mbgl/sprite/sprite_loader.hpp>
#include <mbgl/sprite/sprite_parser.hpp>
namespace mbgl {
-SpriteAtlasWorker::SpriteAtlasWorker(ActorRef<SpriteAtlasWorker>, ActorRef<SpriteAtlas> parent_)
+SpriteLoaderWorker::SpriteLoaderWorker(ActorRef<SpriteLoaderWorker>, ActorRef<SpriteLoader> parent_)
: parent(std::move(parent_)) {
}
-void SpriteAtlasWorker::parse(std::shared_ptr<const std::string> image,
+void SpriteLoaderWorker::parse(std::shared_ptr<const std::string> image,
std::shared_ptr<const std::string> json) {
try {
if (!image) {
@@ -20,9 +20,9 @@ void SpriteAtlasWorker::parse(std::shared_ptr<const std::string> image,
throw std::runtime_error("missing sprite metadata");
}
- parent.invoke(&SpriteAtlas::onParsed, parseSprite(*image, *json));
+ parent.invoke(&SpriteLoader::onParsed, parseSprite(*image, *json));
} catch (...) {
- parent.invoke(&SpriteAtlas::onError, std::current_exception());
+ parent.invoke(&SpriteLoader::onError, std::current_exception());
}
}
diff --git a/src/mbgl/sprite/sprite_atlas_worker.hpp b/src/mbgl/sprite/sprite_loader_worker.hpp
index 70ca0d52e5..d61e07d14f 100644
--- a/src/mbgl/sprite/sprite_atlas_worker.hpp
+++ b/src/mbgl/sprite/sprite_loader_worker.hpp
@@ -8,16 +8,16 @@
namespace mbgl {
-class SpriteAtlas;
+class SpriteLoader;
-class SpriteAtlasWorker {
+class SpriteLoaderWorker {
public:
- SpriteAtlasWorker(ActorRef<SpriteAtlasWorker>, ActorRef<SpriteAtlas>);
+ SpriteLoaderWorker(ActorRef<SpriteLoaderWorker>, ActorRef<SpriteLoader>);
void parse(std::shared_ptr<const std::string> image, std::shared_ptr<const std::string> json);
private:
- ActorRef<SpriteAtlas> parent;
+ ActorRef<SpriteLoader> parent;
};
} // namespace mbgl
diff --git a/src/mbgl/sprite/sprite_parser.cpp b/src/mbgl/sprite/sprite_parser.cpp
index c3ed20d03f..1a36e3e990 100644
--- a/src/mbgl/sprite/sprite_parser.cpp
+++ b/src/mbgl/sprite/sprite_parser.cpp
@@ -13,13 +13,14 @@
namespace mbgl {
-std::unique_ptr<style::Image> createStyleImage(const PremultipliedImage& image,
- const uint32_t srcX,
- const uint32_t srcY,
- const uint32_t width,
- const uint32_t height,
- const double ratio,
- const bool sdf) {
+std::unique_ptr<style::Image> createStyleImage(const std::string& id,
+ const PremultipliedImage& image,
+ const uint32_t srcX,
+ const uint32_t srcY,
+ const uint32_t width,
+ const uint32_t height,
+ const double ratio,
+ const bool sdf) {
// Disallow invalid parameter configurations.
if (width <= 0 || height <= 0 || width > 1024 || height > 1024 ||
ratio <= 0 || ratio > 10 ||
@@ -37,7 +38,7 @@ std::unique_ptr<style::Image> createStyleImage(const PremultipliedImage& image,
// Copy from the source image into our individual sprite image
PremultipliedImage::copy(image, dstImage, { srcX, srcY }, { 0, 0 }, { width, height });
- return std::make_unique<style::Image>(std::move(dstImage), ratio, sdf);
+ return std::make_unique<style::Image>(id, std::move(dstImage), ratio, sdf);
}
namespace {
@@ -84,7 +85,7 @@ bool getBoolean(const JSValue& value, const char* name, const bool def = false)
} // namespace
-Images parseSprite(const std::string& encodedImage, const std::string& json) {
+std::vector<std::unique_ptr<style::Image>> parseSprite(const std::string& encodedImage, const std::string& json) {
const PremultipliedImage raster = decodeImage(encodedImage);
JSDocument doc;
@@ -96,7 +97,7 @@ Images parseSprite(const std::string& encodedImage, const std::string& json) {
} else if (!doc.IsObject()) {
throw std::runtime_error("Sprite JSON root must be an object");
} else {
- Images images;
+ std::vector<std::unique_ptr<style::Image>> images;
for (const auto& property : doc.GetObject()) {
const std::string name = { property.name.GetString(), property.name.GetStringLength() };
const JSValue& value = property.value;
@@ -109,9 +110,9 @@ Images parseSprite(const std::string& encodedImage, const std::string& json) {
const double pixelRatio = getDouble(value, "pixelRatio", 1);
const bool sdf = getBoolean(value, "sdf", false);
- auto image = createStyleImage(raster, x, y, width, height, pixelRatio, sdf);
+ auto image = createStyleImage(name, raster, x, y, width, height, pixelRatio, sdf);
if (image) {
- images.emplace(name, std::move(image));
+ images.push_back(std::move(image));
}
}
}
diff --git a/src/mbgl/sprite/sprite_parser.hpp b/src/mbgl/sprite/sprite_parser.hpp
index 5be8435ebb..f602818d3b 100644
--- a/src/mbgl/sprite/sprite_parser.hpp
+++ b/src/mbgl/sprite/sprite_parser.hpp
@@ -1,13 +1,10 @@
#pragma once
#include <mbgl/util/image.hpp>
-#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/util/variant.hpp>
-#include <mbgl/util/geo.hpp>
#include <string>
#include <memory>
-#include <map>
+#include <vector>
namespace mbgl {
@@ -16,17 +13,16 @@ class Image;
} // namespace style
// Extracts an individual image from a spritesheet from the given location.
-std::unique_ptr<style::Image> createStyleImage(const PremultipliedImage&,
- uint32_t srcX,
- uint32_t srcY,
- uint32_t srcWidth,
- uint32_t srcHeight,
- double ratio,
- bool sdf);
-
-using Images = std::map<std::string, std::unique_ptr<style::Image>>;
+std::unique_ptr<style::Image> createStyleImage(const std::string& id,
+ const PremultipliedImage&,
+ uint32_t srcX,
+ uint32_t srcY,
+ uint32_t srcWidth,
+ uint32_t srcHeight,
+ double ratio,
+ bool sdf);
// Parses an image and an associated JSON file and returns the sprite objects.
-Images parseSprite(const std::string& image, const std::string& json);
+std::vector<std::unique_ptr<style::Image>> parseSprite(const std::string& image, const std::string& json);
} // namespace mbgl
diff --git a/src/mbgl/storage/asset_file_source.hpp b/src/mbgl/storage/asset_file_source.hpp
index 71e5bbdab3..6ed7af8aaf 100644
--- a/src/mbgl/storage/asset_file_source.hpp
+++ b/src/mbgl/storage/asset_file_source.hpp
@@ -17,7 +17,8 @@ public:
private:
class Impl;
- std::unique_ptr<util::Thread<Impl>> thread;
+
+ std::unique_ptr<util::Thread<Impl>> impl;
};
} // namespace mbgl
diff --git a/src/mbgl/storage/file_source_request.cpp b/src/mbgl/storage/file_source_request.cpp
new file mode 100644
index 0000000000..8a6fb21181
--- /dev/null
+++ b/src/mbgl/storage/file_source_request.cpp
@@ -0,0 +1,37 @@
+#include <mbgl/storage/file_source_request.hpp>
+
+#include <mbgl/actor/mailbox.hpp>
+#include <mbgl/util/run_loop.hpp>
+
+namespace mbgl {
+
+FileSourceRequest::FileSourceRequest(FileSource::Callback&& callback)
+ : responseCallback(callback)
+ , mailbox(std::make_shared<Mailbox>(*util::RunLoop::Get())) {
+}
+
+FileSourceRequest::~FileSourceRequest() {
+ if (cancelCallback) {
+ cancelCallback();
+ }
+
+ mailbox->close();
+}
+
+void FileSourceRequest::onCancel(std::function<void()>&& callback) {
+ cancelCallback = std::move(callback);
+}
+
+void FileSourceRequest::setResponse(const Response& response) {
+ // Copy, because calling the callback will sometimes self
+ // destroy this object. We cannot move because this method
+ // can be called more than one.
+ auto callback = responseCallback;
+ callback(response);
+}
+
+ActorRef<FileSourceRequest> FileSourceRequest::actor() {
+ return ActorRef<FileSourceRequest>(*this, mailbox);
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/storage/file_source_request.hpp b/src/mbgl/storage/file_source_request.hpp
new file mode 100644
index 0000000000..6bd0d44df6
--- /dev/null
+++ b/src/mbgl/storage/file_source_request.hpp
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <mbgl/actor/actor_ref.hpp>
+#include <mbgl/storage/file_source.hpp>
+#include <mbgl/util/async_request.hpp>
+
+#include <memory>
+#include <functional>
+
+namespace mbgl {
+
+class Mailbox;
+
+class FileSourceRequest : public AsyncRequest {
+public:
+ FileSourceRequest(FileSource::Callback&& callback);
+ ~FileSourceRequest() final;
+
+ void onCancel(std::function<void()>&& callback);
+ void setResponse(const Response& res);
+
+ ActorRef<FileSourceRequest> actor();
+
+private:
+ FileSource::Callback responseCallback = nullptr;
+ std::function<void()> cancelCallback = nullptr;
+
+ std::shared_ptr<Mailbox> mailbox;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/storage/local_file_source.hpp b/src/mbgl/storage/local_file_source.hpp
index 43319bc06e..0f065e0b5f 100644
--- a/src/mbgl/storage/local_file_source.hpp
+++ b/src/mbgl/storage/local_file_source.hpp
@@ -19,7 +19,8 @@ public:
private:
class Impl;
- std::unique_ptr<util::Thread<Impl>> thread;
+
+ std::unique_ptr<util::Thread<Impl>> impl;
};
} // namespace mbgl
diff --git a/src/mbgl/storage/resource.cpp b/src/mbgl/storage/resource.cpp
index 20dde1db56..94bba7f8bf 100644
--- a/src/mbgl/storage/resource.cpp
+++ b/src/mbgl/storage/resource.cpp
@@ -53,6 +53,13 @@ Resource Resource::source(const std::string& url) {
};
}
+Resource Resource::image(const std::string& url) {
+ return Resource {
+ Resource::Kind::Image,
+ url
+ };
+}
+
Resource Resource::spriteImage(const std::string& base, float pixelRatio) {
return Resource {
Resource::Kind::SpriteImage,
diff --git a/src/mbgl/storage/resource_transform.cpp b/src/mbgl/storage/resource_transform.cpp
new file mode 100644
index 0000000000..a5e62b2c1a
--- /dev/null
+++ b/src/mbgl/storage/resource_transform.cpp
@@ -0,0 +1,13 @@
+#include <mbgl/storage/resource_transform.hpp>
+
+namespace mbgl {
+
+ResourceTransform::ResourceTransform(ActorRef<ResourceTransform>, TransformCallback&& callback)
+ : transformCallback(std::move(callback)) {
+}
+
+void ResourceTransform::transform(Resource::Kind kind, const std::string&& url, FinishedCallback&& finished) {
+ finished(transformCallback(kind, std::move(url)));
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/style/class_dictionary.cpp b/src/mbgl/style/class_dictionary.cpp
deleted file mode 100644
index ec06ee7d9d..0000000000
--- a/src/mbgl/style/class_dictionary.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-#include <mbgl/style/class_dictionary.hpp>
-
-#include <pthread.h>
-
-namespace mbgl {
-namespace style {
-
-ClassDictionary::ClassDictionary() {}
-
-ClassDictionary &ClassDictionary::Get() {
- static pthread_once_t store_once = PTHREAD_ONCE_INIT;
- static pthread_key_t store_key;
-
- // Create the key.
- pthread_once(&store_once, []() {
- pthread_key_create(&store_key, [](void *ptr) {
- delete reinterpret_cast<ClassDictionary *>(ptr);
- });
- });
-
- ClassDictionary *ptr = reinterpret_cast<ClassDictionary *>(pthread_getspecific(store_key));
- if (ptr == nullptr) {
- ptr = new ClassDictionary();
- pthread_setspecific(store_key, ptr);
- }
-
- return *ptr;
-}
-
-ClassID ClassDictionary::lookup(const std::string &class_name) {
- auto it = store.find(class_name);
- if (it == store.end()) {
- // Insert the class name into the store.
- ClassID id = ClassID(uint32_t(ClassID::Named) + offset++);
- store.emplace(class_name, id);
- return id;
- } else {
- return it->second;
- }
-}
-
-ClassID ClassDictionary::normalize(ClassID id) {
- if (id >= ClassID::Named) {
- return ClassID::Named;
- } else {
- return id;
- }
-}
-
-} // namespace style
-} // namespace mbgl
diff --git a/src/mbgl/style/class_dictionary.hpp b/src/mbgl/style/class_dictionary.hpp
deleted file mode 100644
index 37eb488240..0000000000
--- a/src/mbgl/style/class_dictionary.hpp
+++ /dev/null
@@ -1,52 +0,0 @@
-#pragma once
-
-#include <cstdint>
-#include <string>
-#include <unordered_map>
-#include <functional>
-
-namespace mbgl {
-namespace style {
-
-enum class ClassID : uint32_t {
- Default = 1, // These values are from the default style for a layer
- Named = 2 // These values (and all subsequent IDs) are from a named style from the layer
-};
-
-class ClassDictionary {
-private:
- ClassDictionary();
-
-public:
- static ClassDictionary &Get();
-
- // Returns an ID for a class name. If the class name does not yet have an ID, one is
- // auto-generated and stored for future reference.
- ClassID lookup(const std::string &class_name);
-
- // Returns either Fallback, Default or Named, depending on the type of the class id.
- ClassID normalize(ClassID id);
-
-private:
- std::unordered_map<std::string, ClassID> store = { { "", ClassID::Default } };
- uint32_t offset = 0;
-};
-
-} // namespace style
-} // namespace mbgl
-
-namespace std {
-
-// Explicitly define std::hash<style::ClassID> because GCC doesn't automatically use std::hash<> of
-// the underlying enum type.
-
-template <>
-struct hash<mbgl::style::ClassID> {
-public:
- size_t operator()(const mbgl::style::ClassID id) const {
- using T = std::underlying_type_t<mbgl::style::ClassID>;
- return std::hash<T>()(static_cast<T>(id));
- }
-};
-
-} // namespace std
diff --git a/src/mbgl/style/collection.hpp b/src/mbgl/style/collection.hpp
new file mode 100644
index 0000000000..0deb1411b6
--- /dev/null
+++ b/src/mbgl/style/collection.hpp
@@ -0,0 +1,141 @@
+#pragma once
+
+#include <mbgl/util/immutable.hpp>
+#include <mbgl/util/optional.hpp>
+
+#include <memory>
+#include <string>
+
+namespace mbgl {
+namespace style {
+
+/*
+ Manages an ordered collection of elements and their `Immutable<Impl>`s. The latter is
+ itself stored in an Immutable container. Using immutability at the collection level
+ allows us to short-circuit significant portions of the RenderStyle update logic via
+ a simple pointer equality check, greatly improving performance.
+
+ Element types are required to have:
+
+ * An `Impl` inner class type
+ * An `Immutable<Impl> baseImpl` member
+ * A `std::string getID() const` method
+*/
+template <class T>
+class Collection {
+public:
+ using Impl = typename T::Impl;
+ using WrapperVector = std::vector<std::unique_ptr<T>>;
+ using ImmutableVector = Immutable<std::vector<Immutable<Impl>>>;
+
+ Collection();
+
+ std::size_t size() const;
+ T* get(const std::string&) const;
+
+ std::vector<T*> getWrappers() const;
+ ImmutableVector getImpls() const { return impls; }
+
+ auto begin() const { return wrappers.begin(); }
+ auto end() const { return wrappers.end(); }
+
+ void clear();
+
+ T* add(std::unique_ptr<T>, const optional<std::string>& = {});
+ std::unique_ptr<T> remove(const std::string&);
+
+ // Must be called whenever an element of the collection is internally mutated.
+ // Typically, each element permits registration of an observer, and the observer
+ // should call this method.
+ void update(const T&);
+
+private:
+ std::size_t index(const std::string&) const;
+
+ WrapperVector wrappers;
+ ImmutableVector impls;
+};
+
+template <class T>
+Collection<T>::Collection()
+ : impls(makeMutable<std::vector<Immutable<Impl>>>()) {
+}
+
+template <class T>
+std::size_t Collection<T>::size() const {
+ return wrappers.size();
+}
+
+template <class T>
+std::size_t Collection<T>::index(const std::string& id) const {
+ return std::find_if(wrappers.begin(), wrappers.end(), [&](const auto& e) {
+ return e->getID() == id;
+ }) - wrappers.begin();
+}
+
+template <class T>
+T* Collection<T>::get(const std::string& id) const {
+ std::size_t i = index(id);
+ return i < size() ? wrappers[i].get() : nullptr;
+}
+
+template <class T>
+std::vector<T*> Collection<T>::getWrappers() const {
+ std::vector<T*> result;
+ result.reserve(wrappers.size());
+
+ for (auto& wrapper : wrappers) {
+ result.push_back(wrapper.get());
+ }
+
+ return result;
+}
+
+template <class T>
+void Collection<T>::clear() {
+ mutate(impls, [&] (auto& impls_) {
+ impls_.clear();
+ });
+
+ wrappers.clear();
+}
+
+template <class T>
+T* Collection<T>::add(std::unique_ptr<T> wrapper, const optional<std::string>& before) {
+ std::size_t i = before ? index(*before) : size();
+
+ mutate(impls, [&] (auto& impls_) {
+ impls_.emplace(impls_.begin() + i, wrapper->baseImpl);
+ });
+
+ return wrappers.emplace(wrappers.begin() + i, std::move(wrapper))->get();
+}
+
+template <class T>
+std::unique_ptr<T> Collection<T>::remove(const std::string& id) {
+ std::size_t i = index(id);
+
+ if (i >= size()) {
+ return nullptr;
+ }
+
+ auto source = std::move(wrappers[i]);
+
+ mutate(impls, [&] (auto& impls_) {
+ impls_.erase(impls_.begin() + i);
+ });
+
+ wrappers.erase(wrappers.begin() + i);
+
+ return source;
+}
+
+template <class T>
+void Collection<T>::update(const T& wrapper) {
+ mutate(impls, [&] (auto& impls_) {
+ impls_.at(this->index(wrapper.getID())) = wrapper.baseImpl;
+ });
+}
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/conversion/stringify.hpp b/src/mbgl/style/conversion/stringify.hpp
index 4afbf198e5..6ae6fede42 100644
--- a/src/mbgl/style/conversion/stringify.hpp
+++ b/src/mbgl/style/conversion/stringify.hpp
@@ -2,7 +2,7 @@
#include <mbgl/style/filter.hpp>
#include <mbgl/style/property_value.hpp>
-#include <mbgl/style/layout_property.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
#include <mbgl/util/enum.hpp>
#include <mbgl/util/color.hpp>
#include <mbgl/util/feature.hpp>
@@ -446,13 +446,6 @@ void stringify(Writer& writer, const DataDrivenPropertyValue<T>& value) {
}
}
-template <class Writer, class... Ps>
-void stringify(Writer& writer, const LayoutProperties<Ps...>& ps) {
- writer.StartObject();
- util::ignore({ (stringify<Ps>(writer, ps.unevaluated.template get<Ps>()), 0)... });
- writer.EndObject();
-}
-
} // namespace conversion
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/function/identity_stops.cpp b/src/mbgl/style/function/identity_stops.cpp
index dfb34e9dd4..0c6891eac5 100644
--- a/src/mbgl/style/function/identity_stops.cpp
+++ b/src/mbgl/style/function/identity_stops.cpp
@@ -46,15 +46,16 @@ optional<std::array<float, 2>> IdentityStops<std::array<float, 2>>::evaluate(con
return {};
}
- const std::vector<Value>& vector = value.get<std::vector<Value>>();
+ const auto& vector = value.get<std::vector<Value>>();
if (vector.size() != 2 || !numericValue<float>(vector[0]) || !numericValue<float>(vector[1])) {
return {};
}
- return {{{
+ std::array<float, 2> array {{
*numericValue<float>(vector[0]),
*numericValue<float>(vector[1])
- }}};
+ }};
+ return array;
}
} // namespace style
diff --git a/src/mbgl/style/image.cpp b/src/mbgl/style/image.cpp
index 4c0c6a859b..1747de5fcc 100644
--- a/src/mbgl/style/image.cpp
+++ b/src/mbgl/style/image.cpp
@@ -1,21 +1,33 @@
#include <mbgl/style/image.hpp>
+#include <mbgl/style/image_impl.hpp>
#include <mbgl/util/exception.hpp>
namespace mbgl {
namespace style {
-Image::Image(PremultipliedImage&& image_,
- const float pixelRatio_,
- bool sdf_)
- : image(std::move(image_)),
- pixelRatio(pixelRatio_),
- sdf(sdf_) {
-
- if (!image.valid()) {
- throw util::SpriteImageException("Sprite image dimensions may not be zero");
- } else if (pixelRatio <= 0) {
- throw util::SpriteImageException("Sprite pixelRatio may not be <= 0");
- }
+Image::Image(std::string id,
+ PremultipliedImage &&image,
+ const float pixelRatio,
+ bool sdf)
+ : baseImpl(makeMutable<Impl>(std::move(id), std::move(image), pixelRatio, sdf)) {
+}
+
+std::string Image::getID() const {
+ return baseImpl->id;
+}
+
+Image::Image(const Image&) = default;
+
+const PremultipliedImage& Image::getImage() const {
+ return baseImpl->image;
+}
+
+bool Image::isSdf() const {
+ return baseImpl->sdf;
+}
+
+float Image::getPixelRatio() const {
+ return baseImpl->pixelRatio;
}
} // namespace style
diff --git a/src/mbgl/style/image_impl.cpp b/src/mbgl/style/image_impl.cpp
new file mode 100644
index 0000000000..ce327262e8
--- /dev/null
+++ b/src/mbgl/style/image_impl.cpp
@@ -0,0 +1,24 @@
+#include <mbgl/style/image_impl.hpp>
+#include <mbgl/util/exception.hpp>
+
+namespace mbgl {
+namespace style {
+
+Image::Impl::Impl(std::string id_,
+ PremultipliedImage&& image_,
+ const float pixelRatio_,
+ bool sdf_)
+ : id(std::move(id_)),
+ image(std::move(image_)),
+ pixelRatio(pixelRatio_),
+ sdf(sdf_) {
+
+ if (!image.valid()) {
+ throw util::SpriteImageException("Sprite image dimensions may not be zero");
+ } else if (pixelRatio <= 0) {
+ throw util::SpriteImageException("Sprite pixelRatio may not be <= 0");
+ }
+}
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/image_impl.hpp b/src/mbgl/style/image_impl.hpp
new file mode 100644
index 0000000000..75dc83206c
--- /dev/null
+++ b/src/mbgl/style/image_impl.hpp
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <mbgl/style/image.hpp>
+
+#include <string>
+#include <unordered_map>
+#include <set>
+
+namespace mbgl {
+namespace style {
+
+class Image::Impl {
+public:
+ Impl(std::string id, PremultipliedImage&&, float pixelRatio, bool sdf = false);
+
+ const std::string id;
+
+ PremultipliedImage image;
+
+ // Pixel ratio of the sprite image.
+ const float pixelRatio;
+
+ // Whether this image should be interpreted as a signed distance field icon.
+ const bool sdf;
+};
+
+} // namespace style
+
+using ImageMap = std::unordered_map<std::string, Immutable<style::Image::Impl>>;
+using ImageDependencies = std::set<std::string>;
+
+} // namespace mbgl
diff --git a/src/mbgl/style/layer.cpp b/src/mbgl/style/layer.cpp
index e2eba0e2e0..142fe313cf 100644
--- a/src/mbgl/style/layer.cpp
+++ b/src/mbgl/style/layer.cpp
@@ -1,17 +1,24 @@
#include <mbgl/style/layer.hpp>
#include <mbgl/style/layer_impl.hpp>
-#include <mbgl/style/layer_type.hpp>
+#include <mbgl/style/layer_observer.hpp>
namespace mbgl {
namespace style {
-Layer::Layer(LayerType type_, std::unique_ptr<Impl> baseImpl_)
- : type(type_), baseImpl(std::move(baseImpl_)) {
+static LayerObserver nullObserver;
+
+Layer::Layer(Immutable<Impl> impl)
+ : baseImpl(std::move(impl)),
+ observer(&nullObserver) {
}
Layer::~Layer() = default;
-const std::string& Layer::getID() const {
+LayerType Layer::getType() const {
+ return baseImpl->type;
+}
+
+std::string Layer::getID() const {
return baseImpl->id;
}
@@ -19,27 +26,16 @@ VisibilityType Layer::getVisibility() const {
return baseImpl->visibility;
}
-void Layer::setVisibility(VisibilityType value) {
- if (value == getVisibility())
- return;
- baseImpl->visibility = value;
- baseImpl->observer->onLayerVisibilityChanged(*this);
-}
-
float Layer::getMinZoom() const {
return baseImpl->minZoom;
}
-void Layer::setMinZoom(float minZoom) const {
- baseImpl->minZoom = minZoom;
-}
-
float Layer::getMaxZoom() const {
return baseImpl->maxZoom;
}
-void Layer::setMaxZoom(float maxZoom) const {
- baseImpl->maxZoom = maxZoom;
+void Layer::setObserver(LayerObserver* observer_) {
+ observer = observer_ ? observer_ : &nullObserver;
}
} // namespace style
diff --git a/src/mbgl/style/layer_impl.cpp b/src/mbgl/style/layer_impl.cpp
index b8eb01fe77..a9a3941f3e 100644
--- a/src/mbgl/style/layer_impl.cpp
+++ b/src/mbgl/style/layer_impl.cpp
@@ -3,16 +3,10 @@
namespace mbgl {
namespace style {
-std::unique_ptr<Layer> Layer::Impl::copy(const std::string& id_,
- const std::string& source_) const {
- std::unique_ptr<Layer> result = clone();
- result->baseImpl->id = id_;
- result->baseImpl->source = source_;
- return result;
-}
-
-void Layer::Impl::setObserver(LayerObserver* observer_) {
- observer = observer_ ? observer_ : &nullObserver;
+Layer::Impl::Impl(LayerType type_, std::string layerID, std::string sourceID)
+ : type(type_),
+ id(std::move(layerID)),
+ source(std::move(sourceID)) {
}
} // namespace style
diff --git a/src/mbgl/style/layer_impl.hpp b/src/mbgl/style/layer_impl.hpp
index 6aa8fccaf0..f350044925 100644
--- a/src/mbgl/style/layer_impl.hpp
+++ b/src/mbgl/style/layer_impl.hpp
@@ -3,13 +3,10 @@
#include <mbgl/style/layer.hpp>
#include <mbgl/style/types.hpp>
#include <mbgl/style/filter.hpp>
-#include <mbgl/style/layer_observer.hpp>
-#include <mbgl/util/noncopyable.hpp>
#include <rapidjson/writer.h>
#include <rapidjson/stringbuffer.h>
-#include <memory>
#include <string>
#include <limits>
@@ -32,27 +29,19 @@ namespace style {
*/
class Layer::Impl {
public:
+ Impl(LayerType, std::string layerID, std::string sourceID);
virtual ~Impl() = default;
- // Create a new layer with the specified `id` and `sourceID`. All other properties
- // are copied from this layer.
- std::unique_ptr<Layer> copy(const std::string& id,
- const std::string& sourceID) const;
-
- // Create an identical copy of this layer.
- virtual std::unique_ptr<Layer> clone() const = 0;
+ Impl& operator=(const Impl&) = delete;
- // Create a layer, copying all properties except id and paint properties from this layer.
- virtual std::unique_ptr<Layer> cloneRef(const std::string& id) const = 0;
+ // Returns true buckets if properties affecting layout have changed: i.e. filter,
+ // visibility, layout properties, or data-driven paint properties.
+ virtual bool hasLayoutDifference(const Layer::Impl&) const = 0;
// Utility function for automatic layer grouping.
virtual void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const = 0;
- virtual std::unique_ptr<RenderLayer> createRenderLayer() const = 0;
-
- void setObserver(LayerObserver*);
-
-public:
+ const LayerType type;
std::string id;
std::string source;
std::string sourceLayer;
@@ -61,13 +50,8 @@ public:
float maxZoom = std::numeric_limits<float>::infinity();
VisibilityType visibility = VisibilityType::Visible;
- LayerObserver nullObserver;
- LayerObserver* observer = &nullObserver;
-
protected:
- Impl() = default;
Impl(const Impl&) = default;
- Impl& operator=(const Impl&) = delete;
};
} // namespace style
diff --git a/src/mbgl/style/layer_observer.hpp b/src/mbgl/style/layer_observer.hpp
index 2fa1c39660..28074a65e7 100644
--- a/src/mbgl/style/layer_observer.hpp
+++ b/src/mbgl/style/layer_observer.hpp
@@ -9,11 +9,7 @@ class LayerObserver {
public:
virtual ~LayerObserver() = default;
- virtual void onLayerFilterChanged(Layer&) {}
- virtual void onLayerVisibilityChanged(Layer&) {}
- virtual void onLayerPaintPropertyChanged(Layer&) {}
- virtual void onLayerDataDrivenPaintPropertyChanged(Layer&) {}
- virtual void onLayerLayoutPropertyChanged(Layer&, const char *) {}
+ virtual void onLayerChanged(Layer&) {}
};
} // namespace style
diff --git a/src/mbgl/style/layers/background_layer.cpp b/src/mbgl/style/layers/background_layer.cpp
index b4ffea138b..d4ead18816 100644
--- a/src/mbgl/style/layers/background_layer.cpp
+++ b/src/mbgl/style/layers/background_layer.cpp
@@ -2,39 +2,65 @@
#include <mbgl/style/layers/background_layer.hpp>
#include <mbgl/style/layers/background_layer_impl.hpp>
-#include <mbgl/style/conversion/stringify.hpp>
+#include <mbgl/style/layer_observer.hpp>
namespace mbgl {
namespace style {
BackgroundLayer::BackgroundLayer(const std::string& layerID)
- : Layer(LayerType::Background, std::make_unique<Impl>())
- , impl(static_cast<Impl*>(baseImpl.get())) {
- impl->id = layerID;
+ : Layer(makeMutable<Impl>(LayerType::Background, layerID, std::string())) {
}
-BackgroundLayer::BackgroundLayer(const Impl& other)
- : Layer(LayerType::Background, std::make_unique<Impl>(other))
- , impl(static_cast<Impl*>(baseImpl.get())) {
+BackgroundLayer::BackgroundLayer(Immutable<Impl> impl_)
+ : Layer(std::move(impl_)) {
}
BackgroundLayer::~BackgroundLayer() = default;
-std::unique_ptr<Layer> BackgroundLayer::Impl::clone() const {
- return std::make_unique<BackgroundLayer>(*this);
+const BackgroundLayer::Impl& BackgroundLayer::impl() const {
+ return static_cast<const Impl&>(*baseImpl);
}
-std::unique_ptr<Layer> BackgroundLayer::Impl::cloneRef(const std::string& id_) const {
- auto result = std::make_unique<BackgroundLayer>(*this);
- result->impl->id = id_;
- result->impl->cascading = BackgroundPaintProperties::Cascading();
- return std::move(result);
+Mutable<BackgroundLayer::Impl> BackgroundLayer::mutableImpl() const {
+ return makeMutable<Impl>(impl());
+}
+
+std::unique_ptr<Layer> BackgroundLayer::cloneRef(const std::string& id_) const {
+ auto impl_ = mutableImpl();
+ impl_->id = id_;
+ impl_->paint = BackgroundPaintProperties::Transitionable();
+ return std::make_unique<BackgroundLayer>(std::move(impl_));
}
void BackgroundLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const {
}
+// Visibility
+
+void BackgroundLayer::setVisibility(VisibilityType value) {
+ if (value == getVisibility())
+ return;
+ auto impl_ = mutableImpl();
+ impl_->visibility = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
+}
+
+// Zoom range
+
+void BackgroundLayer::setMinZoom(float minZoom) {
+ auto impl_ = mutableImpl();
+ impl_->minZoom = minZoom;
+ baseImpl = std::move(impl_);
+}
+
+void BackgroundLayer::setMaxZoom(float maxZoom) {
+ auto impl_ = mutableImpl();
+ impl_->maxZoom = maxZoom;
+ baseImpl = std::move(impl_);
+}
+
// Layout properties
@@ -44,69 +70,81 @@ PropertyValue<Color> BackgroundLayer::getDefaultBackgroundColor() {
return { Color::black() };
}
-PropertyValue<Color> BackgroundLayer::getBackgroundColor(const optional<std::string>& klass) const {
- return impl->cascading.template get<BackgroundColor>().get(klass);
+PropertyValue<Color> BackgroundLayer::getBackgroundColor() const {
+ return impl().paint.template get<BackgroundColor>().value;
}
-void BackgroundLayer::setBackgroundColor(PropertyValue<Color> value, const optional<std::string>& klass) {
- if (value == getBackgroundColor(klass))
+void BackgroundLayer::setBackgroundColor(PropertyValue<Color> value) {
+ if (value == getBackgroundColor())
return;
- impl->cascading.template get<BackgroundColor>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<BackgroundColor>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void BackgroundLayer::setBackgroundColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<BackgroundColor>().setTransition(value, klass);
+void BackgroundLayer::setBackgroundColorTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<BackgroundColor>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions BackgroundLayer::getBackgroundColorTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<BackgroundColor>().getTransition(klass);
+TransitionOptions BackgroundLayer::getBackgroundColorTransition() const {
+ return impl().paint.template get<BackgroundColor>().options;
}
PropertyValue<std::string> BackgroundLayer::getDefaultBackgroundPattern() {
return { "" };
}
-PropertyValue<std::string> BackgroundLayer::getBackgroundPattern(const optional<std::string>& klass) const {
- return impl->cascading.template get<BackgroundPattern>().get(klass);
+PropertyValue<std::string> BackgroundLayer::getBackgroundPattern() const {
+ return impl().paint.template get<BackgroundPattern>().value;
}
-void BackgroundLayer::setBackgroundPattern(PropertyValue<std::string> value, const optional<std::string>& klass) {
- if (value == getBackgroundPattern(klass))
+void BackgroundLayer::setBackgroundPattern(PropertyValue<std::string> value) {
+ if (value == getBackgroundPattern())
return;
- impl->cascading.template get<BackgroundPattern>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<BackgroundPattern>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void BackgroundLayer::setBackgroundPatternTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<BackgroundPattern>().setTransition(value, klass);
+void BackgroundLayer::setBackgroundPatternTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<BackgroundPattern>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions BackgroundLayer::getBackgroundPatternTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<BackgroundPattern>().getTransition(klass);
+TransitionOptions BackgroundLayer::getBackgroundPatternTransition() const {
+ return impl().paint.template get<BackgroundPattern>().options;
}
PropertyValue<float> BackgroundLayer::getDefaultBackgroundOpacity() {
return { 1 };
}
-PropertyValue<float> BackgroundLayer::getBackgroundOpacity(const optional<std::string>& klass) const {
- return impl->cascading.template get<BackgroundOpacity>().get(klass);
+PropertyValue<float> BackgroundLayer::getBackgroundOpacity() const {
+ return impl().paint.template get<BackgroundOpacity>().value;
}
-void BackgroundLayer::setBackgroundOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getBackgroundOpacity(klass))
+void BackgroundLayer::setBackgroundOpacity(PropertyValue<float> value) {
+ if (value == getBackgroundOpacity())
return;
- impl->cascading.template get<BackgroundOpacity>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<BackgroundOpacity>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void BackgroundLayer::setBackgroundOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<BackgroundOpacity>().setTransition(value, klass);
+void BackgroundLayer::setBackgroundOpacityTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<BackgroundOpacity>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions BackgroundLayer::getBackgroundOpacityTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<BackgroundOpacity>().getTransition(klass);
+TransitionOptions BackgroundLayer::getBackgroundOpacityTransition() const {
+ return impl().paint.template get<BackgroundOpacity>().options;
}
} // namespace style
diff --git a/src/mbgl/style/layers/background_layer_impl.cpp b/src/mbgl/style/layers/background_layer_impl.cpp
index 6c4a4c26d9..a59a84fbe9 100644
--- a/src/mbgl/style/layers/background_layer_impl.cpp
+++ b/src/mbgl/style/layers/background_layer_impl.cpp
@@ -1,11 +1,10 @@
#include <mbgl/style/layers/background_layer_impl.hpp>
-#include <mbgl/renderer/render_background_layer.hpp>
namespace mbgl {
namespace style {
-std::unique_ptr<RenderLayer> BackgroundLayer::Impl::createRenderLayer() const {
- return std::make_unique<RenderBackgroundLayer>(*this);
+bool BackgroundLayer::Impl::hasLayoutDifference(const Layer::Impl&) const {
+ return false;
}
} // namespace style
diff --git a/src/mbgl/style/layers/background_layer_impl.hpp b/src/mbgl/style/layers/background_layer_impl.hpp
index 85152da4ec..248a751027 100644
--- a/src/mbgl/style/layers/background_layer_impl.hpp
+++ b/src/mbgl/style/layers/background_layer_impl.hpp
@@ -9,13 +9,12 @@ namespace style {
class BackgroundLayer::Impl : public Layer::Impl {
public:
- std::unique_ptr<Layer> clone() const override;
- std::unique_ptr<Layer> cloneRef(const std::string& id) const override;
- void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override;
+ using Layer::Impl::Impl;
- std::unique_ptr<RenderLayer> createRenderLayer() const override;
+ bool hasLayoutDifference(const Layer::Impl&) const override;
+ void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override;
- BackgroundPaintProperties::Cascading cascading;
+ BackgroundPaintProperties::Transitionable paint;
};
} // namespace style
diff --git a/src/mbgl/style/layers/background_layer_properties.hpp b/src/mbgl/style/layers/background_layer_properties.hpp
index fae6c26a4b..3a61392fb4 100644
--- a/src/mbgl/style/layers/background_layer_properties.hpp
+++ b/src/mbgl/style/layers/background_layer_properties.hpp
@@ -5,7 +5,9 @@
#include <mbgl/style/types.hpp>
#include <mbgl/style/layout_property.hpp>
#include <mbgl/style/paint_property.hpp>
+#include <mbgl/style/properties.hpp>
#include <mbgl/programs/attributes.hpp>
+#include <mbgl/programs/uniforms.hpp>
namespace mbgl {
namespace style {
@@ -22,7 +24,7 @@ struct BackgroundOpacity : PaintProperty<float> {
static float defaultValue() { return 1; }
};
-class BackgroundPaintProperties : public PaintProperties<
+class BackgroundPaintProperties : public Properties<
BackgroundColor,
BackgroundPattern,
BackgroundOpacity
diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp
index 8b3431a9a1..3bba135c84 100644
--- a/src/mbgl/style/layers/circle_layer.cpp
+++ b/src/mbgl/style/layers/circle_layer.cpp
@@ -2,34 +2,34 @@
#include <mbgl/style/layers/circle_layer.hpp>
#include <mbgl/style/layers/circle_layer_impl.hpp>
-#include <mbgl/style/conversion/stringify.hpp>
+#include <mbgl/style/layer_observer.hpp>
namespace mbgl {
namespace style {
CircleLayer::CircleLayer(const std::string& layerID, const std::string& sourceID)
- : Layer(LayerType::Circle, std::make_unique<Impl>())
- , impl(static_cast<Impl*>(baseImpl.get())) {
- impl->id = layerID;
- impl->source = sourceID;
+ : Layer(makeMutable<Impl>(LayerType::Circle, layerID, sourceID)) {
}
-CircleLayer::CircleLayer(const Impl& other)
- : Layer(LayerType::Circle, std::make_unique<Impl>(other))
- , impl(static_cast<Impl*>(baseImpl.get())) {
+CircleLayer::CircleLayer(Immutable<Impl> impl_)
+ : Layer(std::move(impl_)) {
}
CircleLayer::~CircleLayer() = default;
-std::unique_ptr<Layer> CircleLayer::Impl::clone() const {
- return std::make_unique<CircleLayer>(*this);
+const CircleLayer::Impl& CircleLayer::impl() const {
+ return static_cast<const Impl&>(*baseImpl);
}
-std::unique_ptr<Layer> CircleLayer::Impl::cloneRef(const std::string& id_) const {
- auto result = std::make_unique<CircleLayer>(*this);
- result->impl->id = id_;
- result->impl->cascading = CirclePaintProperties::Cascading();
- return std::move(result);
+Mutable<CircleLayer::Impl> CircleLayer::mutableImpl() const {
+ return makeMutable<Impl>(impl());
+}
+
+std::unique_ptr<Layer> CircleLayer::cloneRef(const std::string& id_) const {
+ auto impl_ = mutableImpl();
+ impl_->id = id_;
+ impl_->paint = CirclePaintProperties::Transitionable();
+ return std::make_unique<CircleLayer>(std::move(impl_));
}
void CircleLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const {
@@ -38,26 +38,55 @@ void CircleLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffe
// Source
const std::string& CircleLayer::getSourceID() const {
- return impl->source;
+ return impl().source;
}
void CircleLayer::setSourceLayer(const std::string& sourceLayer) {
- impl->sourceLayer = sourceLayer;
+ auto impl_ = mutableImpl();
+ impl_->sourceLayer = sourceLayer;
+ baseImpl = std::move(impl_);
}
const std::string& CircleLayer::getSourceLayer() const {
- return impl->sourceLayer;
+ return impl().sourceLayer;
}
// Filter
void CircleLayer::setFilter(const Filter& filter) {
- impl->filter = filter;
- impl->observer->onLayerFilterChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->filter = filter;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
const Filter& CircleLayer::getFilter() const {
- return impl->filter;
+ return impl().filter;
+}
+
+// Visibility
+
+void CircleLayer::setVisibility(VisibilityType value) {
+ if (value == getVisibility())
+ return;
+ auto impl_ = mutableImpl();
+ impl_->visibility = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
+}
+
+// Zoom range
+
+void CircleLayer::setMinZoom(float minZoom) {
+ auto impl_ = mutableImpl();
+ impl_->minZoom = minZoom;
+ baseImpl = std::move(impl_);
+}
+
+void CircleLayer::setMaxZoom(float maxZoom) {
+ auto impl_ = mutableImpl();
+ impl_->maxZoom = maxZoom;
+ baseImpl = std::move(impl_);
}
// Layout properties
@@ -69,258 +98,270 @@ DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleRadius() {
return { 5 };
}
-DataDrivenPropertyValue<float> CircleLayer::getCircleRadius(const optional<std::string>& klass) const {
- return impl->cascading.template get<CircleRadius>().get(klass);
+DataDrivenPropertyValue<float> CircleLayer::getCircleRadius() const {
+ return impl().paint.template get<CircleRadius>().value;
}
-void CircleLayer::setCircleRadius(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getCircleRadius(klass))
+void CircleLayer::setCircleRadius(DataDrivenPropertyValue<float> value) {
+ if (value == getCircleRadius())
return;
- impl->cascading.template get<CircleRadius>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<CircleRadius>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void CircleLayer::setCircleRadiusTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<CircleRadius>().setTransition(value, klass);
+void CircleLayer::setCircleRadiusTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<CircleRadius>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions CircleLayer::getCircleRadiusTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<CircleRadius>().getTransition(klass);
+TransitionOptions CircleLayer::getCircleRadiusTransition() const {
+ return impl().paint.template get<CircleRadius>().options;
}
DataDrivenPropertyValue<Color> CircleLayer::getDefaultCircleColor() {
return { Color::black() };
}
-DataDrivenPropertyValue<Color> CircleLayer::getCircleColor(const optional<std::string>& klass) const {
- return impl->cascading.template get<CircleColor>().get(klass);
+DataDrivenPropertyValue<Color> CircleLayer::getCircleColor() const {
+ return impl().paint.template get<CircleColor>().value;
}
-void CircleLayer::setCircleColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
- if (value == getCircleColor(klass))
+void CircleLayer::setCircleColor(DataDrivenPropertyValue<Color> value) {
+ if (value == getCircleColor())
return;
- impl->cascading.template get<CircleColor>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<CircleColor>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void CircleLayer::setCircleColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<CircleColor>().setTransition(value, klass);
+void CircleLayer::setCircleColorTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<CircleColor>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions CircleLayer::getCircleColorTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<CircleColor>().getTransition(klass);
+TransitionOptions CircleLayer::getCircleColorTransition() const {
+ return impl().paint.template get<CircleColor>().options;
}
DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleBlur() {
return { 0 };
}
-DataDrivenPropertyValue<float> CircleLayer::getCircleBlur(const optional<std::string>& klass) const {
- return impl->cascading.template get<CircleBlur>().get(klass);
+DataDrivenPropertyValue<float> CircleLayer::getCircleBlur() const {
+ return impl().paint.template get<CircleBlur>().value;
}
-void CircleLayer::setCircleBlur(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getCircleBlur(klass))
+void CircleLayer::setCircleBlur(DataDrivenPropertyValue<float> value) {
+ if (value == getCircleBlur())
return;
- impl->cascading.template get<CircleBlur>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<CircleBlur>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void CircleLayer::setCircleBlurTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<CircleBlur>().setTransition(value, klass);
+void CircleLayer::setCircleBlurTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<CircleBlur>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions CircleLayer::getCircleBlurTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<CircleBlur>().getTransition(klass);
+TransitionOptions CircleLayer::getCircleBlurTransition() const {
+ return impl().paint.template get<CircleBlur>().options;
}
DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleOpacity() {
return { 1 };
}
-DataDrivenPropertyValue<float> CircleLayer::getCircleOpacity(const optional<std::string>& klass) const {
- return impl->cascading.template get<CircleOpacity>().get(klass);
+DataDrivenPropertyValue<float> CircleLayer::getCircleOpacity() const {
+ return impl().paint.template get<CircleOpacity>().value;
}
-void CircleLayer::setCircleOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getCircleOpacity(klass))
+void CircleLayer::setCircleOpacity(DataDrivenPropertyValue<float> value) {
+ if (value == getCircleOpacity())
return;
- impl->cascading.template get<CircleOpacity>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<CircleOpacity>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void CircleLayer::setCircleOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<CircleOpacity>().setTransition(value, klass);
+void CircleLayer::setCircleOpacityTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<CircleOpacity>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions CircleLayer::getCircleOpacityTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<CircleOpacity>().getTransition(klass);
+TransitionOptions CircleLayer::getCircleOpacityTransition() const {
+ return impl().paint.template get<CircleOpacity>().options;
}
PropertyValue<std::array<float, 2>> CircleLayer::getDefaultCircleTranslate() {
return { {{ 0, 0 }} };
}
-PropertyValue<std::array<float, 2>> CircleLayer::getCircleTranslate(const optional<std::string>& klass) const {
- return impl->cascading.template get<CircleTranslate>().get(klass);
+PropertyValue<std::array<float, 2>> CircleLayer::getCircleTranslate() const {
+ return impl().paint.template get<CircleTranslate>().value;
}
-void CircleLayer::setCircleTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) {
- if (value == getCircleTranslate(klass))
+void CircleLayer::setCircleTranslate(PropertyValue<std::array<float, 2>> value) {
+ if (value == getCircleTranslate())
return;
- impl->cascading.template get<CircleTranslate>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<CircleTranslate>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void CircleLayer::setCircleTranslateTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<CircleTranslate>().setTransition(value, klass);
+void CircleLayer::setCircleTranslateTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<CircleTranslate>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions CircleLayer::getCircleTranslateTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<CircleTranslate>().getTransition(klass);
+TransitionOptions CircleLayer::getCircleTranslateTransition() const {
+ return impl().paint.template get<CircleTranslate>().options;
}
PropertyValue<TranslateAnchorType> CircleLayer::getDefaultCircleTranslateAnchor() {
return { TranslateAnchorType::Map };
}
-PropertyValue<TranslateAnchorType> CircleLayer::getCircleTranslateAnchor(const optional<std::string>& klass) const {
- return impl->cascading.template get<CircleTranslateAnchor>().get(klass);
+PropertyValue<TranslateAnchorType> CircleLayer::getCircleTranslateAnchor() const {
+ return impl().paint.template get<CircleTranslateAnchor>().value;
}
-void CircleLayer::setCircleTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) {
- if (value == getCircleTranslateAnchor(klass))
+void CircleLayer::setCircleTranslateAnchor(PropertyValue<TranslateAnchorType> value) {
+ if (value == getCircleTranslateAnchor())
return;
- impl->cascading.template get<CircleTranslateAnchor>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<CircleTranslateAnchor>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void CircleLayer::setCircleTranslateAnchorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<CircleTranslateAnchor>().setTransition(value, klass);
+void CircleLayer::setCircleTranslateAnchorTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<CircleTranslateAnchor>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions CircleLayer::getCircleTranslateAnchorTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<CircleTranslateAnchor>().getTransition(klass);
+TransitionOptions CircleLayer::getCircleTranslateAnchorTransition() const {
+ return impl().paint.template get<CircleTranslateAnchor>().options;
}
PropertyValue<CirclePitchScaleType> CircleLayer::getDefaultCirclePitchScale() {
return { CirclePitchScaleType::Map };
}
-PropertyValue<CirclePitchScaleType> CircleLayer::getCirclePitchScale(const optional<std::string>& klass) const {
- return impl->cascading.template get<CirclePitchScale>().get(klass);
+PropertyValue<CirclePitchScaleType> CircleLayer::getCirclePitchScale() const {
+ return impl().paint.template get<CirclePitchScale>().value;
}
-void CircleLayer::setCirclePitchScale(PropertyValue<CirclePitchScaleType> value, const optional<std::string>& klass) {
- if (value == getCirclePitchScale(klass))
+void CircleLayer::setCirclePitchScale(PropertyValue<CirclePitchScaleType> value) {
+ if (value == getCirclePitchScale())
return;
- impl->cascading.template get<CirclePitchScale>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<CirclePitchScale>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void CircleLayer::setCirclePitchScaleTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<CirclePitchScale>().setTransition(value, klass);
+void CircleLayer::setCirclePitchScaleTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<CirclePitchScale>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions CircleLayer::getCirclePitchScaleTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<CirclePitchScale>().getTransition(klass);
+TransitionOptions CircleLayer::getCirclePitchScaleTransition() const {
+ return impl().paint.template get<CirclePitchScale>().options;
}
DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleStrokeWidth() {
return { 0 };
}
-DataDrivenPropertyValue<float> CircleLayer::getCircleStrokeWidth(const optional<std::string>& klass) const {
- return impl->cascading.template get<CircleStrokeWidth>().get(klass);
+DataDrivenPropertyValue<float> CircleLayer::getCircleStrokeWidth() const {
+ return impl().paint.template get<CircleStrokeWidth>().value;
}
-void CircleLayer::setCircleStrokeWidth(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getCircleStrokeWidth(klass))
+void CircleLayer::setCircleStrokeWidth(DataDrivenPropertyValue<float> value) {
+ if (value == getCircleStrokeWidth())
return;
- impl->cascading.template get<CircleStrokeWidth>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<CircleStrokeWidth>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void CircleLayer::setCircleStrokeWidthTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<CircleStrokeWidth>().setTransition(value, klass);
+void CircleLayer::setCircleStrokeWidthTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<CircleStrokeWidth>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions CircleLayer::getCircleStrokeWidthTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<CircleStrokeWidth>().getTransition(klass);
+TransitionOptions CircleLayer::getCircleStrokeWidthTransition() const {
+ return impl().paint.template get<CircleStrokeWidth>().options;
}
DataDrivenPropertyValue<Color> CircleLayer::getDefaultCircleStrokeColor() {
return { Color::black() };
}
-DataDrivenPropertyValue<Color> CircleLayer::getCircleStrokeColor(const optional<std::string>& klass) const {
- return impl->cascading.template get<CircleStrokeColor>().get(klass);
+DataDrivenPropertyValue<Color> CircleLayer::getCircleStrokeColor() const {
+ return impl().paint.template get<CircleStrokeColor>().value;
}
-void CircleLayer::setCircleStrokeColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
- if (value == getCircleStrokeColor(klass))
+void CircleLayer::setCircleStrokeColor(DataDrivenPropertyValue<Color> value) {
+ if (value == getCircleStrokeColor())
return;
- impl->cascading.template get<CircleStrokeColor>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<CircleStrokeColor>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void CircleLayer::setCircleStrokeColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<CircleStrokeColor>().setTransition(value, klass);
+void CircleLayer::setCircleStrokeColorTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<CircleStrokeColor>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions CircleLayer::getCircleStrokeColorTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<CircleStrokeColor>().getTransition(klass);
+TransitionOptions CircleLayer::getCircleStrokeColorTransition() const {
+ return impl().paint.template get<CircleStrokeColor>().options;
}
DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleStrokeOpacity() {
return { 1 };
}
-DataDrivenPropertyValue<float> CircleLayer::getCircleStrokeOpacity(const optional<std::string>& klass) const {
- return impl->cascading.template get<CircleStrokeOpacity>().get(klass);
+DataDrivenPropertyValue<float> CircleLayer::getCircleStrokeOpacity() const {
+ return impl().paint.template get<CircleStrokeOpacity>().value;
}
-void CircleLayer::setCircleStrokeOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getCircleStrokeOpacity(klass))
+void CircleLayer::setCircleStrokeOpacity(DataDrivenPropertyValue<float> value) {
+ if (value == getCircleStrokeOpacity())
return;
- impl->cascading.template get<CircleStrokeOpacity>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<CircleStrokeOpacity>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void CircleLayer::setCircleStrokeOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<CircleStrokeOpacity>().setTransition(value, klass);
+void CircleLayer::setCircleStrokeOpacityTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<CircleStrokeOpacity>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions CircleLayer::getCircleStrokeOpacityTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<CircleStrokeOpacity>().getTransition(klass);
+TransitionOptions CircleLayer::getCircleStrokeOpacityTransition() const {
+ return impl().paint.template get<CircleStrokeOpacity>().options;
}
} // namespace style
diff --git a/src/mbgl/style/layers/circle_layer_impl.cpp b/src/mbgl/style/layers/circle_layer_impl.cpp
index 31b286f273..69f574cd6b 100644
--- a/src/mbgl/style/layers/circle_layer_impl.cpp
+++ b/src/mbgl/style/layers/circle_layer_impl.cpp
@@ -1,11 +1,14 @@
#include <mbgl/style/layers/circle_layer_impl.hpp>
-#include <mbgl/renderer/render_circle_layer.hpp>
namespace mbgl {
namespace style {
-std::unique_ptr<RenderLayer> CircleLayer::Impl::createRenderLayer() const {
- return std::make_unique<RenderCircleLayer>(*this);
+bool CircleLayer::Impl::hasLayoutDifference(const Layer::Impl& other) const {
+ assert(dynamic_cast<const CircleLayer::Impl*>(&other));
+ const auto& impl = static_cast<const style::CircleLayer::Impl&>(other);
+ return filter != impl.filter ||
+ visibility != impl.visibility ||
+ paint.hasDataDrivenPropertyDifference(impl.paint);
}
} // namespace style
diff --git a/src/mbgl/style/layers/circle_layer_impl.hpp b/src/mbgl/style/layers/circle_layer_impl.hpp
index 886815f0d1..4b148cdc42 100644
--- a/src/mbgl/style/layers/circle_layer_impl.hpp
+++ b/src/mbgl/style/layers/circle_layer_impl.hpp
@@ -9,13 +9,12 @@ namespace style {
class CircleLayer::Impl : public Layer::Impl {
public:
- std::unique_ptr<Layer> clone() const override;
- std::unique_ptr<Layer> cloneRef(const std::string& id) const override;
- void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override;
+ using Layer::Impl::Impl;
- std::unique_ptr<RenderLayer> createRenderLayer() const override;
+ bool hasLayoutDifference(const Layer::Impl&) const override;
+ void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override;
- CirclePaintProperties::Cascading cascading;
+ CirclePaintProperties::Transitionable paint;
};
} // namespace style
diff --git a/src/mbgl/style/layers/circle_layer_properties.hpp b/src/mbgl/style/layers/circle_layer_properties.hpp
index 58206c61da..73b7028465 100644
--- a/src/mbgl/style/layers/circle_layer_properties.hpp
+++ b/src/mbgl/style/layers/circle_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/style/properties.hpp>
#include <mbgl/programs/attributes.hpp>
#include <mbgl/programs/uniforms.hpp>
@@ -51,7 +52,7 @@ struct CircleStrokeOpacity : DataDrivenPaintProperty<float, attributes::a_stroke
static float defaultValue() { return 1; }
};
-class CirclePaintProperties : public PaintProperties<
+class CirclePaintProperties : public Properties<
CircleRadius,
CircleColor,
CircleBlur,
diff --git a/src/mbgl/style/layers/custom_layer.cpp b/src/mbgl/style/layers/custom_layer.cpp
index cda8a157f0..e37382d5ef 100644
--- a/src/mbgl/style/layers/custom_layer.cpp
+++ b/src/mbgl/style/layers/custom_layer.cpp
@@ -1,6 +1,6 @@
#include <mbgl/style/layers/custom_layer.hpp>
#include <mbgl/style/layers/custom_layer_impl.hpp>
-#include <mbgl/util/logging.hpp>
+#include <mbgl/style/layer_observer.hpp>
namespace mbgl {
namespace style {
@@ -10,21 +10,52 @@ CustomLayer::CustomLayer(const std::string& layerID,
CustomLayerRenderFunction render,
CustomLayerDeinitializeFunction deinit,
void* context)
- : Layer(LayerType::Custom, std::make_unique<Impl>(layerID, init, render, deinit, context))
- , impl(static_cast<Impl*>(baseImpl.get())) {
- Log::Info(Event::General, "New custom layer: %s", layerID.c_str());
+ : Layer(makeMutable<Impl>(layerID, init, render, deinit, context)) {
}
-CustomLayer::CustomLayer(const Impl& other)
- : Layer(LayerType::Custom, std::make_unique<Impl>(other))
- , impl(static_cast<Impl*>(baseImpl.get())) {
+CustomLayer::~CustomLayer() = default;
+
+const CustomLayer::Impl& CustomLayer::impl() const {
+ return static_cast<const Impl&>(*baseImpl);
}
-CustomLayer::~CustomLayer() = default;
+Mutable<CustomLayer::Impl> CustomLayer::mutableImpl() const {
+ return makeMutable<Impl>(impl());
+}
+
+std::unique_ptr<Layer> CustomLayer::cloneRef(const std::string&) const {
+ assert(false);
+ return nullptr;
+}
+
+// Visibility
+
+void CustomLayer::setVisibility(VisibilityType value) {
+ if (value == getVisibility())
+ return;
+ auto impl_ = mutableImpl();
+ impl_->visibility = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
+}
+
+// Zoom range
+
+void CustomLayer::setMinZoom(float minZoom) {
+ auto impl_ = mutableImpl();
+ impl_->minZoom = minZoom;
+ baseImpl = std::move(impl_);
+}
+
+void CustomLayer::setMaxZoom(float maxZoom) {
+ auto impl_ = mutableImpl();
+ impl_->maxZoom = maxZoom;
+ baseImpl = std::move(impl_);
+}
template <>
bool Layer::is<CustomLayer>() const {
- return type == LayerType::Custom;
+ return getType() == LayerType::Custom;
}
} // namespace style
diff --git a/src/mbgl/style/layers/custom_layer_impl.cpp b/src/mbgl/style/layers/custom_layer_impl.cpp
index 1d3e9af8d6..42e60c582c 100644
--- a/src/mbgl/style/layers/custom_layer_impl.cpp
+++ b/src/mbgl/style/layers/custom_layer_impl.cpp
@@ -1,74 +1,26 @@
#include <mbgl/style/layers/custom_layer_impl.hpp>
-#include <mbgl/renderer/render_custom_layer.hpp>
-#include <mbgl/map/transform_state.hpp>
-#include <mbgl/util/logging.hpp>
+
namespace mbgl {
namespace style {
-std::unique_ptr<RenderLayer> CustomLayer::Impl::createRenderLayer() const {
- return std::make_unique<RenderCustomLayer>(*this);
-}
-
CustomLayer::Impl::Impl(const std::string& id_,
CustomLayerInitializeFunction initializeFn_,
CustomLayerRenderFunction renderFn_,
CustomLayerDeinitializeFunction deinitializeFn_,
- void* context_) {
- Log::Info(Event::General, "New custom layer Impl: %s", id_.c_str());
- id = id_;
+ void* context_)
+ : Layer::Impl(LayerType::Custom, id_, std::string()) {
initializeFn = initializeFn_;
renderFn = renderFn_;
deinitializeFn = deinitializeFn_;
context = context_;
}
-CustomLayer::Impl::Impl(const CustomLayer::Impl &other)
- : Layer::Impl(other) {
- id = other.id;
- // Don't copy anything else.
-}
-
-CustomLayer::Impl::~Impl() = default;
-
-std::unique_ptr<Layer> CustomLayer::Impl::clone() const {
- return std::make_unique<CustomLayer>(*this);
-}
-
-std::unique_ptr<Layer> CustomLayer::Impl::cloneRef(const std::string&) const {
- assert(false);
- return std::make_unique<CustomLayer>(*this);
+bool CustomLayer::Impl::hasLayoutDifference(const Layer::Impl&) const {
+ return false;
}
void CustomLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const {
}
-void CustomLayer::Impl::initialize() {
- assert(initializeFn);
- initializeFn(context);
-}
-
-void CustomLayer::Impl::deinitialize() {
- if (deinitializeFn) {
- deinitializeFn(context);
- }
-}
-
-void CustomLayer::Impl::render(const TransformState& state) const {
- assert(renderFn);
-
- CustomLayerRenderParameters parameters;
-
- parameters.width = state.getSize().width;
- parameters.height = state.getSize().height;
- parameters.latitude = state.getLatLng().latitude();
- parameters.longitude = state.getLatLng().longitude();
- parameters.zoom = state.getZoom();
- parameters.bearing = -state.getAngle() * util::RAD2DEG;
- parameters.pitch = state.getPitch();
- parameters.fieldOfView = state.getFieldOfView();
-
- renderFn(context, parameters);
-}
-
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layers/custom_layer_impl.hpp b/src/mbgl/style/layers/custom_layer_impl.hpp
index e612d17f14..defbbe6894 100644
--- a/src/mbgl/style/layers/custom_layer_impl.hpp
+++ b/src/mbgl/style/layers/custom_layer_impl.hpp
@@ -17,20 +17,9 @@ public:
CustomLayerDeinitializeFunction,
void* context);
- Impl(const Impl&);
- ~Impl() final;
-
- void initialize();
- void deinitialize();
- void render(const TransformState&) const;
-
-private:
- std::unique_ptr<Layer> clone() const override;
- std::unique_ptr<Layer> cloneRef(const std::string& id) const override;
+ bool hasLayoutDifference(const Layer::Impl&) const override;
void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override;
- std::unique_ptr<RenderLayer> createRenderLayer() const final;
-
CustomLayerInitializeFunction initializeFn = nullptr;
CustomLayerRenderFunction renderFn = nullptr;
CustomLayerDeinitializeFunction deinitializeFn = nullptr;
diff --git a/src/mbgl/style/layers/fill_extrusion_layer.cpp b/src/mbgl/style/layers/fill_extrusion_layer.cpp
index 6f11d6052c..62f92cef75 100644
--- a/src/mbgl/style/layers/fill_extrusion_layer.cpp
+++ b/src/mbgl/style/layers/fill_extrusion_layer.cpp
@@ -2,34 +2,34 @@
#include <mbgl/style/layers/fill_extrusion_layer.hpp>
#include <mbgl/style/layers/fill_extrusion_layer_impl.hpp>
-#include <mbgl/style/conversion/stringify.hpp>
+#include <mbgl/style/layer_observer.hpp>
namespace mbgl {
namespace style {
FillExtrusionLayer::FillExtrusionLayer(const std::string& layerID, const std::string& sourceID)
- : Layer(LayerType::FillExtrusion, std::make_unique<Impl>())
- , impl(static_cast<Impl*>(baseImpl.get())) {
- impl->id = layerID;
- impl->source = sourceID;
+ : Layer(makeMutable<Impl>(LayerType::FillExtrusion, layerID, sourceID)) {
}
-FillExtrusionLayer::FillExtrusionLayer(const Impl& other)
- : Layer(LayerType::FillExtrusion, std::make_unique<Impl>(other))
- , impl(static_cast<Impl*>(baseImpl.get())) {
+FillExtrusionLayer::FillExtrusionLayer(Immutable<Impl> impl_)
+ : Layer(std::move(impl_)) {
}
FillExtrusionLayer::~FillExtrusionLayer() = default;
-std::unique_ptr<Layer> FillExtrusionLayer::Impl::clone() const {
- return std::make_unique<FillExtrusionLayer>(*this);
+const FillExtrusionLayer::Impl& FillExtrusionLayer::impl() const {
+ return static_cast<const Impl&>(*baseImpl);
}
-std::unique_ptr<Layer> FillExtrusionLayer::Impl::cloneRef(const std::string& id_) const {
- auto result = std::make_unique<FillExtrusionLayer>(*this);
- result->impl->id = id_;
- result->impl->cascading = FillExtrusionPaintProperties::Cascading();
- return std::move(result);
+Mutable<FillExtrusionLayer::Impl> FillExtrusionLayer::mutableImpl() const {
+ return makeMutable<Impl>(impl());
+}
+
+std::unique_ptr<Layer> FillExtrusionLayer::cloneRef(const std::string& id_) const {
+ auto impl_ = mutableImpl();
+ impl_->id = id_;
+ impl_->paint = FillExtrusionPaintProperties::Transitionable();
+ return std::make_unique<FillExtrusionLayer>(std::move(impl_));
}
void FillExtrusionLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const {
@@ -38,26 +38,55 @@ void FillExtrusionLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::Stri
// Source
const std::string& FillExtrusionLayer::getSourceID() const {
- return impl->source;
+ return impl().source;
}
void FillExtrusionLayer::setSourceLayer(const std::string& sourceLayer) {
- impl->sourceLayer = sourceLayer;
+ auto impl_ = mutableImpl();
+ impl_->sourceLayer = sourceLayer;
+ baseImpl = std::move(impl_);
}
const std::string& FillExtrusionLayer::getSourceLayer() const {
- return impl->sourceLayer;
+ return impl().sourceLayer;
}
// Filter
void FillExtrusionLayer::setFilter(const Filter& filter) {
- impl->filter = filter;
- impl->observer->onLayerFilterChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->filter = filter;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
const Filter& FillExtrusionLayer::getFilter() const {
- return impl->filter;
+ return impl().filter;
+}
+
+// Visibility
+
+void FillExtrusionLayer::setVisibility(VisibilityType value) {
+ if (value == getVisibility())
+ return;
+ auto impl_ = mutableImpl();
+ impl_->visibility = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
+}
+
+// Zoom range
+
+void FillExtrusionLayer::setMinZoom(float minZoom) {
+ auto impl_ = mutableImpl();
+ impl_->minZoom = minZoom;
+ baseImpl = std::move(impl_);
+}
+
+void FillExtrusionLayer::setMaxZoom(float maxZoom) {
+ auto impl_ = mutableImpl();
+ impl_->maxZoom = maxZoom;
+ baseImpl = std::move(impl_);
}
// Layout properties
@@ -69,173 +98,189 @@ PropertyValue<float> FillExtrusionLayer::getDefaultFillExtrusionOpacity() {
return { 1 };
}
-PropertyValue<float> FillExtrusionLayer::getFillExtrusionOpacity(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillExtrusionOpacity>().get(klass);
+PropertyValue<float> FillExtrusionLayer::getFillExtrusionOpacity() const {
+ return impl().paint.template get<FillExtrusionOpacity>().value;
}
-void FillExtrusionLayer::setFillExtrusionOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getFillExtrusionOpacity(klass))
+void FillExtrusionLayer::setFillExtrusionOpacity(PropertyValue<float> value) {
+ if (value == getFillExtrusionOpacity())
return;
- impl->cascading.template get<FillExtrusionOpacity>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillExtrusionOpacity>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void FillExtrusionLayer::setFillExtrusionOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<FillExtrusionOpacity>().setTransition(value, klass);
+void FillExtrusionLayer::setFillExtrusionOpacityTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillExtrusionOpacity>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions FillExtrusionLayer::getFillExtrusionOpacityTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillExtrusionOpacity>().getTransition(klass);
+TransitionOptions FillExtrusionLayer::getFillExtrusionOpacityTransition() const {
+ return impl().paint.template get<FillExtrusionOpacity>().options;
}
DataDrivenPropertyValue<Color> FillExtrusionLayer::getDefaultFillExtrusionColor() {
return { Color::black() };
}
-DataDrivenPropertyValue<Color> FillExtrusionLayer::getFillExtrusionColor(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillExtrusionColor>().get(klass);
+DataDrivenPropertyValue<Color> FillExtrusionLayer::getFillExtrusionColor() const {
+ return impl().paint.template get<FillExtrusionColor>().value;
}
-void FillExtrusionLayer::setFillExtrusionColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
- if (value == getFillExtrusionColor(klass))
+void FillExtrusionLayer::setFillExtrusionColor(DataDrivenPropertyValue<Color> value) {
+ if (value == getFillExtrusionColor())
return;
- impl->cascading.template get<FillExtrusionColor>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillExtrusionColor>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void FillExtrusionLayer::setFillExtrusionColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<FillExtrusionColor>().setTransition(value, klass);
+void FillExtrusionLayer::setFillExtrusionColorTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillExtrusionColor>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions FillExtrusionLayer::getFillExtrusionColorTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillExtrusionColor>().getTransition(klass);
+TransitionOptions FillExtrusionLayer::getFillExtrusionColorTransition() const {
+ return impl().paint.template get<FillExtrusionColor>().options;
}
PropertyValue<std::array<float, 2>> FillExtrusionLayer::getDefaultFillExtrusionTranslate() {
return { {{ 0, 0 }} };
}
-PropertyValue<std::array<float, 2>> FillExtrusionLayer::getFillExtrusionTranslate(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillExtrusionTranslate>().get(klass);
+PropertyValue<std::array<float, 2>> FillExtrusionLayer::getFillExtrusionTranslate() const {
+ return impl().paint.template get<FillExtrusionTranslate>().value;
}
-void FillExtrusionLayer::setFillExtrusionTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) {
- if (value == getFillExtrusionTranslate(klass))
+void FillExtrusionLayer::setFillExtrusionTranslate(PropertyValue<std::array<float, 2>> value) {
+ if (value == getFillExtrusionTranslate())
return;
- impl->cascading.template get<FillExtrusionTranslate>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillExtrusionTranslate>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void FillExtrusionLayer::setFillExtrusionTranslateTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<FillExtrusionTranslate>().setTransition(value, klass);
+void FillExtrusionLayer::setFillExtrusionTranslateTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillExtrusionTranslate>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions FillExtrusionLayer::getFillExtrusionTranslateTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillExtrusionTranslate>().getTransition(klass);
+TransitionOptions FillExtrusionLayer::getFillExtrusionTranslateTransition() const {
+ return impl().paint.template get<FillExtrusionTranslate>().options;
}
PropertyValue<TranslateAnchorType> FillExtrusionLayer::getDefaultFillExtrusionTranslateAnchor() {
return { TranslateAnchorType::Map };
}
-PropertyValue<TranslateAnchorType> FillExtrusionLayer::getFillExtrusionTranslateAnchor(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillExtrusionTranslateAnchor>().get(klass);
+PropertyValue<TranslateAnchorType> FillExtrusionLayer::getFillExtrusionTranslateAnchor() const {
+ return impl().paint.template get<FillExtrusionTranslateAnchor>().value;
}
-void FillExtrusionLayer::setFillExtrusionTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) {
- if (value == getFillExtrusionTranslateAnchor(klass))
+void FillExtrusionLayer::setFillExtrusionTranslateAnchor(PropertyValue<TranslateAnchorType> value) {
+ if (value == getFillExtrusionTranslateAnchor())
return;
- impl->cascading.template get<FillExtrusionTranslateAnchor>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillExtrusionTranslateAnchor>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void FillExtrusionLayer::setFillExtrusionTranslateAnchorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<FillExtrusionTranslateAnchor>().setTransition(value, klass);
+void FillExtrusionLayer::setFillExtrusionTranslateAnchorTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillExtrusionTranslateAnchor>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions FillExtrusionLayer::getFillExtrusionTranslateAnchorTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillExtrusionTranslateAnchor>().getTransition(klass);
+TransitionOptions FillExtrusionLayer::getFillExtrusionTranslateAnchorTransition() const {
+ return impl().paint.template get<FillExtrusionTranslateAnchor>().options;
}
PropertyValue<std::string> FillExtrusionLayer::getDefaultFillExtrusionPattern() {
return { "" };
}
-PropertyValue<std::string> FillExtrusionLayer::getFillExtrusionPattern(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillExtrusionPattern>().get(klass);
+PropertyValue<std::string> FillExtrusionLayer::getFillExtrusionPattern() const {
+ return impl().paint.template get<FillExtrusionPattern>().value;
}
-void FillExtrusionLayer::setFillExtrusionPattern(PropertyValue<std::string> value, const optional<std::string>& klass) {
- if (value == getFillExtrusionPattern(klass))
+void FillExtrusionLayer::setFillExtrusionPattern(PropertyValue<std::string> value) {
+ if (value == getFillExtrusionPattern())
return;
- impl->cascading.template get<FillExtrusionPattern>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillExtrusionPattern>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void FillExtrusionLayer::setFillExtrusionPatternTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<FillExtrusionPattern>().setTransition(value, klass);
+void FillExtrusionLayer::setFillExtrusionPatternTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillExtrusionPattern>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions FillExtrusionLayer::getFillExtrusionPatternTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillExtrusionPattern>().getTransition(klass);
+TransitionOptions FillExtrusionLayer::getFillExtrusionPatternTransition() const {
+ return impl().paint.template get<FillExtrusionPattern>().options;
}
DataDrivenPropertyValue<float> FillExtrusionLayer::getDefaultFillExtrusionHeight() {
return { 0 };
}
-DataDrivenPropertyValue<float> FillExtrusionLayer::getFillExtrusionHeight(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillExtrusionHeight>().get(klass);
+DataDrivenPropertyValue<float> FillExtrusionLayer::getFillExtrusionHeight() const {
+ return impl().paint.template get<FillExtrusionHeight>().value;
}
-void FillExtrusionLayer::setFillExtrusionHeight(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getFillExtrusionHeight(klass))
+void FillExtrusionLayer::setFillExtrusionHeight(DataDrivenPropertyValue<float> value) {
+ if (value == getFillExtrusionHeight())
return;
- impl->cascading.template get<FillExtrusionHeight>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillExtrusionHeight>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void FillExtrusionLayer::setFillExtrusionHeightTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<FillExtrusionHeight>().setTransition(value, klass);
+void FillExtrusionLayer::setFillExtrusionHeightTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillExtrusionHeight>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions FillExtrusionLayer::getFillExtrusionHeightTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillExtrusionHeight>().getTransition(klass);
+TransitionOptions FillExtrusionLayer::getFillExtrusionHeightTransition() const {
+ return impl().paint.template get<FillExtrusionHeight>().options;
}
DataDrivenPropertyValue<float> FillExtrusionLayer::getDefaultFillExtrusionBase() {
return { 0 };
}
-DataDrivenPropertyValue<float> FillExtrusionLayer::getFillExtrusionBase(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillExtrusionBase>().get(klass);
+DataDrivenPropertyValue<float> FillExtrusionLayer::getFillExtrusionBase() const {
+ return impl().paint.template get<FillExtrusionBase>().value;
}
-void FillExtrusionLayer::setFillExtrusionBase(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getFillExtrusionBase(klass))
+void FillExtrusionLayer::setFillExtrusionBase(DataDrivenPropertyValue<float> value) {
+ if (value == getFillExtrusionBase())
return;
- impl->cascading.template get<FillExtrusionBase>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillExtrusionBase>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void FillExtrusionLayer::setFillExtrusionBaseTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<FillExtrusionBase>().setTransition(value, klass);
+void FillExtrusionLayer::setFillExtrusionBaseTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillExtrusionBase>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions FillExtrusionLayer::getFillExtrusionBaseTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillExtrusionBase>().getTransition(klass);
+TransitionOptions FillExtrusionLayer::getFillExtrusionBaseTransition() const {
+ return impl().paint.template get<FillExtrusionBase>().options;
}
} // 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 5340541221..d37c2ad29b 100644
--- a/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp
+++ b/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp
@@ -1,11 +1,14 @@
#include <mbgl/style/layers/fill_extrusion_layer_impl.hpp>
-#include <mbgl/renderer/render_fill_extrusion_layer.hpp>
namespace mbgl {
namespace style {
-std::unique_ptr<RenderLayer> FillExtrusionLayer::Impl::createRenderLayer() const {
- return std::make_unique<RenderFillExtrusionLayer>(*this);
+bool FillExtrusionLayer::Impl::hasLayoutDifference(const Layer::Impl& other) const {
+ assert(dynamic_cast<const FillExtrusionLayer::Impl*>(&other));
+ const auto& impl = static_cast<const style::FillExtrusionLayer::Impl&>(other);
+ return filter != impl.filter ||
+ visibility != impl.visibility ||
+ paint.hasDataDrivenPropertyDifference(impl.paint);
}
} // namespace style
diff --git a/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp b/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp
index 2353bd99fe..9abc6fc4b3 100644
--- a/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp
+++ b/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp
@@ -9,13 +9,12 @@ namespace style {
class FillExtrusionLayer::Impl : public Layer::Impl {
public:
- std::unique_ptr<Layer> clone() const override;
- std::unique_ptr<Layer> cloneRef(const std::string& id) const override;
- void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override;
+ using Layer::Impl::Impl;
- std::unique_ptr<RenderLayer> createRenderLayer() const override;
+ bool hasLayoutDifference(const Layer::Impl&) const override;
+ void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override;
- FillExtrusionPaintProperties::Cascading cascading;
+ FillExtrusionPaintProperties::Transitionable paint;
};
} // namespace style
diff --git a/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp b/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp
index f41ce68b94..19be59a2fe 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/style/properties.hpp>
#include <mbgl/programs/attributes.hpp>
#include <mbgl/programs/uniforms.hpp>
@@ -39,7 +40,7 @@ struct FillExtrusionBase : DataDrivenPaintProperty<float, attributes::a_base, un
static float defaultValue() { return 0; }
};
-class FillExtrusionPaintProperties : public PaintProperties<
+class FillExtrusionPaintProperties : public Properties<
FillExtrusionOpacity,
FillExtrusionColor,
FillExtrusionTranslate,
diff --git a/src/mbgl/style/layers/fill_layer.cpp b/src/mbgl/style/layers/fill_layer.cpp
index 9fd9d33af3..65975752db 100644
--- a/src/mbgl/style/layers/fill_layer.cpp
+++ b/src/mbgl/style/layers/fill_layer.cpp
@@ -2,34 +2,34 @@
#include <mbgl/style/layers/fill_layer.hpp>
#include <mbgl/style/layers/fill_layer_impl.hpp>
-#include <mbgl/style/conversion/stringify.hpp>
+#include <mbgl/style/layer_observer.hpp>
namespace mbgl {
namespace style {
FillLayer::FillLayer(const std::string& layerID, const std::string& sourceID)
- : Layer(LayerType::Fill, std::make_unique<Impl>())
- , impl(static_cast<Impl*>(baseImpl.get())) {
- impl->id = layerID;
- impl->source = sourceID;
+ : Layer(makeMutable<Impl>(LayerType::Fill, layerID, sourceID)) {
}
-FillLayer::FillLayer(const Impl& other)
- : Layer(LayerType::Fill, std::make_unique<Impl>(other))
- , impl(static_cast<Impl*>(baseImpl.get())) {
+FillLayer::FillLayer(Immutable<Impl> impl_)
+ : Layer(std::move(impl_)) {
}
FillLayer::~FillLayer() = default;
-std::unique_ptr<Layer> FillLayer::Impl::clone() const {
- return std::make_unique<FillLayer>(*this);
+const FillLayer::Impl& FillLayer::impl() const {
+ return static_cast<const Impl&>(*baseImpl);
}
-std::unique_ptr<Layer> FillLayer::Impl::cloneRef(const std::string& id_) const {
- auto result = std::make_unique<FillLayer>(*this);
- result->impl->id = id_;
- result->impl->cascading = FillPaintProperties::Cascading();
- return std::move(result);
+Mutable<FillLayer::Impl> FillLayer::mutableImpl() const {
+ return makeMutable<Impl>(impl());
+}
+
+std::unique_ptr<Layer> FillLayer::cloneRef(const std::string& id_) const {
+ auto impl_ = mutableImpl();
+ impl_->id = id_;
+ impl_->paint = FillPaintProperties::Transitionable();
+ return std::make_unique<FillLayer>(std::move(impl_));
}
void FillLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const {
@@ -38,26 +38,55 @@ void FillLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>
// Source
const std::string& FillLayer::getSourceID() const {
- return impl->source;
+ return impl().source;
}
void FillLayer::setSourceLayer(const std::string& sourceLayer) {
- impl->sourceLayer = sourceLayer;
+ auto impl_ = mutableImpl();
+ impl_->sourceLayer = sourceLayer;
+ baseImpl = std::move(impl_);
}
const std::string& FillLayer::getSourceLayer() const {
- return impl->sourceLayer;
+ return impl().sourceLayer;
}
// Filter
void FillLayer::setFilter(const Filter& filter) {
- impl->filter = filter;
- impl->observer->onLayerFilterChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->filter = filter;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
const Filter& FillLayer::getFilter() const {
- return impl->filter;
+ return impl().filter;
+}
+
+// Visibility
+
+void FillLayer::setVisibility(VisibilityType value) {
+ if (value == getVisibility())
+ return;
+ auto impl_ = mutableImpl();
+ impl_->visibility = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
+}
+
+// Zoom range
+
+void FillLayer::setMinZoom(float minZoom) {
+ auto impl_ = mutableImpl();
+ impl_->minZoom = minZoom;
+ baseImpl = std::move(impl_);
+}
+
+void FillLayer::setMaxZoom(float maxZoom) {
+ auto impl_ = mutableImpl();
+ impl_->maxZoom = maxZoom;
+ baseImpl = std::move(impl_);
}
// Layout properties
@@ -69,173 +98,189 @@ PropertyValue<bool> FillLayer::getDefaultFillAntialias() {
return { true };
}
-PropertyValue<bool> FillLayer::getFillAntialias(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillAntialias>().get(klass);
+PropertyValue<bool> FillLayer::getFillAntialias() const {
+ return impl().paint.template get<FillAntialias>().value;
}
-void FillLayer::setFillAntialias(PropertyValue<bool> value, const optional<std::string>& klass) {
- if (value == getFillAntialias(klass))
+void FillLayer::setFillAntialias(PropertyValue<bool> value) {
+ if (value == getFillAntialias())
return;
- impl->cascading.template get<FillAntialias>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillAntialias>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void FillLayer::setFillAntialiasTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<FillAntialias>().setTransition(value, klass);
+void FillLayer::setFillAntialiasTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillAntialias>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions FillLayer::getFillAntialiasTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillAntialias>().getTransition(klass);
+TransitionOptions FillLayer::getFillAntialiasTransition() const {
+ return impl().paint.template get<FillAntialias>().options;
}
DataDrivenPropertyValue<float> FillLayer::getDefaultFillOpacity() {
return { 1 };
}
-DataDrivenPropertyValue<float> FillLayer::getFillOpacity(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillOpacity>().get(klass);
+DataDrivenPropertyValue<float> FillLayer::getFillOpacity() const {
+ return impl().paint.template get<FillOpacity>().value;
}
-void FillLayer::setFillOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getFillOpacity(klass))
+void FillLayer::setFillOpacity(DataDrivenPropertyValue<float> value) {
+ if (value == getFillOpacity())
return;
- impl->cascading.template get<FillOpacity>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillOpacity>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void FillLayer::setFillOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<FillOpacity>().setTransition(value, klass);
+void FillLayer::setFillOpacityTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillOpacity>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions FillLayer::getFillOpacityTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillOpacity>().getTransition(klass);
+TransitionOptions FillLayer::getFillOpacityTransition() const {
+ return impl().paint.template get<FillOpacity>().options;
}
DataDrivenPropertyValue<Color> FillLayer::getDefaultFillColor() {
return { Color::black() };
}
-DataDrivenPropertyValue<Color> FillLayer::getFillColor(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillColor>().get(klass);
+DataDrivenPropertyValue<Color> FillLayer::getFillColor() const {
+ return impl().paint.template get<FillColor>().value;
}
-void FillLayer::setFillColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
- if (value == getFillColor(klass))
+void FillLayer::setFillColor(DataDrivenPropertyValue<Color> value) {
+ if (value == getFillColor())
return;
- impl->cascading.template get<FillColor>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillColor>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void FillLayer::setFillColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<FillColor>().setTransition(value, klass);
+void FillLayer::setFillColorTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillColor>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions FillLayer::getFillColorTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillColor>().getTransition(klass);
+TransitionOptions FillLayer::getFillColorTransition() const {
+ return impl().paint.template get<FillColor>().options;
}
DataDrivenPropertyValue<Color> FillLayer::getDefaultFillOutlineColor() {
return { {} };
}
-DataDrivenPropertyValue<Color> FillLayer::getFillOutlineColor(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillOutlineColor>().get(klass);
+DataDrivenPropertyValue<Color> FillLayer::getFillOutlineColor() const {
+ return impl().paint.template get<FillOutlineColor>().value;
}
-void FillLayer::setFillOutlineColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
- if (value == getFillOutlineColor(klass))
+void FillLayer::setFillOutlineColor(DataDrivenPropertyValue<Color> value) {
+ if (value == getFillOutlineColor())
return;
- impl->cascading.template get<FillOutlineColor>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillOutlineColor>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void FillLayer::setFillOutlineColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<FillOutlineColor>().setTransition(value, klass);
+void FillLayer::setFillOutlineColorTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillOutlineColor>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions FillLayer::getFillOutlineColorTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillOutlineColor>().getTransition(klass);
+TransitionOptions FillLayer::getFillOutlineColorTransition() const {
+ return impl().paint.template get<FillOutlineColor>().options;
}
PropertyValue<std::array<float, 2>> FillLayer::getDefaultFillTranslate() {
return { {{ 0, 0 }} };
}
-PropertyValue<std::array<float, 2>> FillLayer::getFillTranslate(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillTranslate>().get(klass);
+PropertyValue<std::array<float, 2>> FillLayer::getFillTranslate() const {
+ return impl().paint.template get<FillTranslate>().value;
}
-void FillLayer::setFillTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) {
- if (value == getFillTranslate(klass))
+void FillLayer::setFillTranslate(PropertyValue<std::array<float, 2>> value) {
+ if (value == getFillTranslate())
return;
- impl->cascading.template get<FillTranslate>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillTranslate>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void FillLayer::setFillTranslateTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<FillTranslate>().setTransition(value, klass);
+void FillLayer::setFillTranslateTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillTranslate>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions FillLayer::getFillTranslateTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillTranslate>().getTransition(klass);
+TransitionOptions FillLayer::getFillTranslateTransition() const {
+ return impl().paint.template get<FillTranslate>().options;
}
PropertyValue<TranslateAnchorType> FillLayer::getDefaultFillTranslateAnchor() {
return { TranslateAnchorType::Map };
}
-PropertyValue<TranslateAnchorType> FillLayer::getFillTranslateAnchor(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillTranslateAnchor>().get(klass);
+PropertyValue<TranslateAnchorType> FillLayer::getFillTranslateAnchor() const {
+ return impl().paint.template get<FillTranslateAnchor>().value;
}
-void FillLayer::setFillTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) {
- if (value == getFillTranslateAnchor(klass))
+void FillLayer::setFillTranslateAnchor(PropertyValue<TranslateAnchorType> value) {
+ if (value == getFillTranslateAnchor())
return;
- impl->cascading.template get<FillTranslateAnchor>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillTranslateAnchor>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void FillLayer::setFillTranslateAnchorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<FillTranslateAnchor>().setTransition(value, klass);
+void FillLayer::setFillTranslateAnchorTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillTranslateAnchor>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions FillLayer::getFillTranslateAnchorTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillTranslateAnchor>().getTransition(klass);
+TransitionOptions FillLayer::getFillTranslateAnchorTransition() const {
+ return impl().paint.template get<FillTranslateAnchor>().options;
}
PropertyValue<std::string> FillLayer::getDefaultFillPattern() {
return { "" };
}
-PropertyValue<std::string> FillLayer::getFillPattern(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillPattern>().get(klass);
+PropertyValue<std::string> FillLayer::getFillPattern() const {
+ return impl().paint.template get<FillPattern>().value;
}
-void FillLayer::setFillPattern(PropertyValue<std::string> value, const optional<std::string>& klass) {
- if (value == getFillPattern(klass))
+void FillLayer::setFillPattern(PropertyValue<std::string> value) {
+ if (value == getFillPattern())
return;
- impl->cascading.template get<FillPattern>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillPattern>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void FillLayer::setFillPatternTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<FillPattern>().setTransition(value, klass);
+void FillLayer::setFillPatternTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<FillPattern>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions FillLayer::getFillPatternTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<FillPattern>().getTransition(klass);
+TransitionOptions FillLayer::getFillPatternTransition() const {
+ return impl().paint.template get<FillPattern>().options;
}
} // namespace style
diff --git a/src/mbgl/style/layers/fill_layer_impl.cpp b/src/mbgl/style/layers/fill_layer_impl.cpp
index 6ec55a58e3..0dc7ed14d5 100644
--- a/src/mbgl/style/layers/fill_layer_impl.cpp
+++ b/src/mbgl/style/layers/fill_layer_impl.cpp
@@ -1,11 +1,14 @@
#include <mbgl/style/layers/fill_layer_impl.hpp>
-#include <mbgl/renderer/render_fill_layer.hpp>
namespace mbgl {
namespace style {
-std::unique_ptr<RenderLayer> FillLayer::Impl::createRenderLayer() const {
- return std::make_unique<RenderFillLayer>(*this);
+bool FillLayer::Impl::hasLayoutDifference(const Layer::Impl& other) const {
+ assert(dynamic_cast<const FillLayer::Impl*>(&other));
+ const auto& impl = static_cast<const style::FillLayer::Impl&>(other);
+ return filter != impl.filter ||
+ visibility != impl.visibility ||
+ paint.hasDataDrivenPropertyDifference(impl.paint);
}
} // namespace style
diff --git a/src/mbgl/style/layers/fill_layer_impl.hpp b/src/mbgl/style/layers/fill_layer_impl.hpp
index 215558962e..2673cd7443 100644
--- a/src/mbgl/style/layers/fill_layer_impl.hpp
+++ b/src/mbgl/style/layers/fill_layer_impl.hpp
@@ -9,13 +9,12 @@ namespace style {
class FillLayer::Impl : public Layer::Impl {
public:
- std::unique_ptr<Layer> clone() const override;
- std::unique_ptr<Layer> cloneRef(const std::string& id) const override;
- void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override;
+ using Layer::Impl::Impl;
- std::unique_ptr<RenderLayer> createRenderLayer() const override;
+ bool hasLayoutDifference(const Layer::Impl&) const override;
+ void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override;
- FillPaintProperties::Cascading cascading;
+ FillPaintProperties::Transitionable paint;
};
} // namespace style
diff --git a/src/mbgl/style/layers/fill_layer_properties.hpp b/src/mbgl/style/layers/fill_layer_properties.hpp
index ee1e5158ce..cb01194515 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/style/properties.hpp>
#include <mbgl/programs/attributes.hpp>
#include <mbgl/programs/uniforms.hpp>
@@ -39,7 +40,7 @@ struct FillPattern : CrossFadedPaintProperty<std::string> {
static std::string defaultValue() { return ""; }
};
-class FillPaintProperties : public PaintProperties<
+class FillPaintProperties : public Properties<
FillAntialias,
FillOpacity,
FillColor,
diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs
index 2f690c3158..573aabda8b 100644
--- a/src/mbgl/style/layers/layer.cpp.ejs
+++ b/src/mbgl/style/layers/layer.cpp.ejs
@@ -7,47 +7,45 @@
#include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer.hpp>
#include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer_impl.hpp>
-#include <mbgl/style/conversion/stringify.hpp>
+#include <mbgl/style/layer_observer.hpp>
namespace mbgl {
namespace style {
<% if (type === 'background') { -%>
<%- camelize(type) %>Layer::<%- camelize(type) %>Layer(const std::string& layerID)
- : Layer(LayerType::<%- camelize(type) %>, std::make_unique<Impl>())
- , impl(static_cast<Impl*>(baseImpl.get())) {
- impl->id = layerID;
+ : Layer(makeMutable<Impl>(LayerType::<%- camelize(type) %>, layerID, std::string())) {
}
<% } else { -%>
<%- camelize(type) %>Layer::<%- camelize(type) %>Layer(const std::string& layerID, const std::string& sourceID)
- : Layer(LayerType::<%- camelize(type) %>, std::make_unique<Impl>())
- , impl(static_cast<Impl*>(baseImpl.get())) {
- impl->id = layerID;
- impl->source = sourceID;
+ : Layer(makeMutable<Impl>(LayerType::<%- camelize(type) %>, layerID, sourceID)) {
}
<% } -%>
-<%- camelize(type) %>Layer::<%- camelize(type) %>Layer(const Impl& other)
- : Layer(LayerType::<%- camelize(type) %>, std::make_unique<Impl>(other))
- , impl(static_cast<Impl*>(baseImpl.get())) {
+<%- camelize(type) %>Layer::<%- camelize(type) %>Layer(Immutable<Impl> impl_)
+ : Layer(std::move(impl_)) {
}
<%- camelize(type) %>Layer::~<%- camelize(type) %>Layer() = default;
-std::unique_ptr<Layer> <%- camelize(type) %>Layer::Impl::clone() const {
- return std::make_unique<<%- camelize(type) %>Layer>(*this);
+const <%- camelize(type) %>Layer::Impl& <%- camelize(type) %>Layer::impl() const {
+ return static_cast<const Impl&>(*baseImpl);
}
-std::unique_ptr<Layer> <%- camelize(type) %>Layer::Impl::cloneRef(const std::string& id_) const {
- auto result = std::make_unique<<%- camelize(type) %>Layer>(*this);
- result->impl->id = id_;
- result->impl->cascading = <%- camelize(type) %>PaintProperties::Cascading();
- return std::move(result);
+Mutable<<%- camelize(type) %>Layer::Impl> <%- camelize(type) %>Layer::mutableImpl() const {
+ return makeMutable<Impl>(impl());
+}
+
+std::unique_ptr<Layer> <%- camelize(type) %>Layer::cloneRef(const std::string& id_) const {
+ auto impl_ = mutableImpl();
+ impl_->id = id_;
+ impl_->paint = <%- camelize(type) %>PaintProperties::Transitionable();
+ return std::make_unique<<%- camelize(type) %>Layer>(std::move(impl_));
}
<% if (layoutProperties.length) { -%>
void <%- camelize(type) %>Layer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>& writer) const {
- conversion::stringify(writer, layout);
+ layout.stringify(writer);
}
<% } else { -%>
void <%- camelize(type) %>Layer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const {
@@ -58,31 +56,60 @@ void <%- camelize(type) %>Layer::Impl::stringifyLayout(rapidjson::Writer<rapidjs
// Source
const std::string& <%- camelize(type) %>Layer::getSourceID() const {
- return impl->source;
+ return impl().source;
}
<% if (type !== 'raster') { -%>
void <%- camelize(type) %>Layer::setSourceLayer(const std::string& sourceLayer) {
- impl->sourceLayer = sourceLayer;
+ auto impl_ = mutableImpl();
+ impl_->sourceLayer = sourceLayer;
+ baseImpl = std::move(impl_);
}
const std::string& <%- camelize(type) %>Layer::getSourceLayer() const {
- return impl->sourceLayer;
+ return impl().sourceLayer;
}
// Filter
void <%- camelize(type) %>Layer::setFilter(const Filter& filter) {
- impl->filter = filter;
- impl->observer->onLayerFilterChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->filter = filter;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
const Filter& <%- camelize(type) %>Layer::getFilter() const {
- return impl->filter;
+ return impl().filter;
}
<% } -%>
<% } -%>
+// Visibility
+
+void <%- camelize(type) %>Layer::setVisibility(VisibilityType value) {
+ if (value == getVisibility())
+ return;
+ auto impl_ = mutableImpl();
+ impl_->visibility = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
+}
+
+// Zoom range
+
+void <%- camelize(type) %>Layer::setMinZoom(float minZoom) {
+ auto impl_ = mutableImpl();
+ impl_->minZoom = minZoom;
+ baseImpl = std::move(impl_);
+}
+
+void <%- camelize(type) %>Layer::setMaxZoom(float maxZoom) {
+ auto impl_ = mutableImpl();
+ impl_->maxZoom = maxZoom;
+ baseImpl = std::move(impl_);
+}
+
// Layout properties
<% for (const property of layoutProperties) { -%>
@@ -91,14 +118,16 @@ const Filter& <%- camelize(type) %>Layer::getFilter() const {
}
<%- propertyValueType(property) %> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>() const {
- return impl->layout.unevaluated.get<<%- camelize(property.name) %>>();
+ return impl().layout.get<<%- camelize(property.name) %>>();
}
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;
- impl->observer->onLayerLayoutPropertyChanged(*this, "<%- property.name %>");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<<%- camelize(property.name) %>>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
<% } -%>
@@ -108,31 +137,27 @@ void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(<%- propertyV
return { <%- defaultValue(property) %> };
}
-<%- propertyValueType(property) %> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>(const optional<std::string>& klass) const {
- return impl->cascading.template get<<%- camelize(property.name) %>>().get(klass);
+<%- propertyValueType(property) %> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>() const {
+ return impl().paint.template get<<%- camelize(property.name) %>>().value;
}
-void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(<%- propertyValueType(property) %> value, const optional<std::string>& klass) {
- if (value == get<%- camelize(property.name) %>(klass))
+void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(<%- propertyValueType(property) %> value) {
+ if (value == get<%- camelize(property.name) %>())
return;
- impl->cascading.template get<<%- camelize(property.name) %>>().set(value, klass);
-<% if (isDataDriven(property)) { -%>
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
-<% } else { -%>
- impl->observer->onLayerPaintPropertyChanged(*this);
-<% } -%>
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<<%- camelize(property.name) %>>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>Transition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<<%- camelize(property.name) %>>().setTransition(value, klass);
+void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>Transition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<<%- camelize(property.name) %>>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions <%- camelize(type) %>Layer::get<%- camelize(property.name) %>Transition(const optional<std::string>& klass) const {
- return impl->cascading.template get<<%- camelize(property.name) %>>().getTransition(klass);
+TransitionOptions <%- camelize(type) %>Layer::get<%- camelize(property.name) %>Transition() const {
+ return impl().paint.template get<<%- camelize(property.name) %>>().options;
}
<% } -%>
diff --git a/src/mbgl/style/layers/layer_properties.hpp.ejs b/src/mbgl/style/layers/layer_properties.hpp.ejs
index 2a736ca388..cde1b80b7b 100644
--- a/src/mbgl/style/layers/layer_properties.hpp.ejs
+++ b/src/mbgl/style/layers/layer_properties.hpp.ejs
@@ -10,7 +10,9 @@
#include <mbgl/style/types.hpp>
#include <mbgl/style/layout_property.hpp>
#include <mbgl/style/paint_property.hpp>
+#include <mbgl/style/properties.hpp>
#include <mbgl/programs/attributes.hpp>
+#include <mbgl/programs/uniforms.hpp>
namespace mbgl {
namespace style {
@@ -29,7 +31,7 @@ struct <%- camelize(property.name) %> : <%- paintPropertyType(property, type) %>
<% } -%>
<% if (layoutProperties.length) { -%>
-class <%- camelize(type) %>LayoutProperties : public LayoutProperties<
+class <%- camelize(type) %>LayoutProperties : public Properties<
<% for (const property of layoutProperties.slice(0, -1)) { -%>
<%- camelize(property.name) %>,
<% } -%>
@@ -37,7 +39,7 @@ class <%- camelize(type) %>LayoutProperties : public LayoutProperties<
> {};
<% } -%>
-class <%- camelize(type) %>PaintProperties : public PaintProperties<
+class <%- camelize(type) %>PaintProperties : public Properties<
<% for (const property of paintProperties.slice(0, -1)) { -%>
<%- camelize(property.name) %>,
<% } -%>
diff --git a/src/mbgl/style/layers/line_layer.cpp b/src/mbgl/style/layers/line_layer.cpp
index 7f1575aad5..6fbdf19568 100644
--- a/src/mbgl/style/layers/line_layer.cpp
+++ b/src/mbgl/style/layers/line_layer.cpp
@@ -2,63 +2,92 @@
#include <mbgl/style/layers/line_layer.hpp>
#include <mbgl/style/layers/line_layer_impl.hpp>
-#include <mbgl/style/conversion/stringify.hpp>
+#include <mbgl/style/layer_observer.hpp>
namespace mbgl {
namespace style {
LineLayer::LineLayer(const std::string& layerID, const std::string& sourceID)
- : Layer(LayerType::Line, std::make_unique<Impl>())
- , impl(static_cast<Impl*>(baseImpl.get())) {
- impl->id = layerID;
- impl->source = sourceID;
+ : Layer(makeMutable<Impl>(LayerType::Line, layerID, sourceID)) {
}
-LineLayer::LineLayer(const Impl& other)
- : Layer(LayerType::Line, std::make_unique<Impl>(other))
- , impl(static_cast<Impl*>(baseImpl.get())) {
+LineLayer::LineLayer(Immutable<Impl> impl_)
+ : Layer(std::move(impl_)) {
}
LineLayer::~LineLayer() = default;
-std::unique_ptr<Layer> LineLayer::Impl::clone() const {
- return std::make_unique<LineLayer>(*this);
+const LineLayer::Impl& LineLayer::impl() const {
+ return static_cast<const Impl&>(*baseImpl);
}
-std::unique_ptr<Layer> LineLayer::Impl::cloneRef(const std::string& id_) const {
- auto result = std::make_unique<LineLayer>(*this);
- result->impl->id = id_;
- result->impl->cascading = LinePaintProperties::Cascading();
- return std::move(result);
+Mutable<LineLayer::Impl> LineLayer::mutableImpl() const {
+ return makeMutable<Impl>(impl());
+}
+
+std::unique_ptr<Layer> LineLayer::cloneRef(const std::string& id_) const {
+ auto impl_ = mutableImpl();
+ impl_->id = id_;
+ impl_->paint = LinePaintProperties::Transitionable();
+ return std::make_unique<LineLayer>(std::move(impl_));
}
void LineLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>& writer) const {
- conversion::stringify(writer, layout);
+ layout.stringify(writer);
}
// Source
const std::string& LineLayer::getSourceID() const {
- return impl->source;
+ return impl().source;
}
void LineLayer::setSourceLayer(const std::string& sourceLayer) {
- impl->sourceLayer = sourceLayer;
+ auto impl_ = mutableImpl();
+ impl_->sourceLayer = sourceLayer;
+ baseImpl = std::move(impl_);
}
const std::string& LineLayer::getSourceLayer() const {
- return impl->sourceLayer;
+ return impl().sourceLayer;
}
// Filter
void LineLayer::setFilter(const Filter& filter) {
- impl->filter = filter;
- impl->observer->onLayerFilterChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->filter = filter;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
const Filter& LineLayer::getFilter() const {
- return impl->filter;
+ return impl().filter;
+}
+
+// Visibility
+
+void LineLayer::setVisibility(VisibilityType value) {
+ if (value == getVisibility())
+ return;
+ auto impl_ = mutableImpl();
+ impl_->visibility = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
+}
+
+// Zoom range
+
+void LineLayer::setMinZoom(float minZoom) {
+ auto impl_ = mutableImpl();
+ impl_->minZoom = minZoom;
+ baseImpl = std::move(impl_);
+}
+
+void LineLayer::setMaxZoom(float maxZoom) {
+ auto impl_ = mutableImpl();
+ impl_->maxZoom = maxZoom;
+ baseImpl = std::move(impl_);
}
// Layout properties
@@ -68,56 +97,64 @@ PropertyValue<LineCapType> LineLayer::getDefaultLineCap() {
}
PropertyValue<LineCapType> LineLayer::getLineCap() const {
- return impl->layout.unevaluated.get<LineCap>();
+ return impl().layout.get<LineCap>();
}
void LineLayer::setLineCap(PropertyValue<LineCapType> value) {
if (value == getLineCap())
return;
- impl->layout.unevaluated.get<LineCap>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "line-cap");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<LineCap>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<LineJoinType> LineLayer::getDefaultLineJoin() {
return LineJoin::defaultValue();
}
PropertyValue<LineJoinType> LineLayer::getLineJoin() const {
- return impl->layout.unevaluated.get<LineJoin>();
+ return impl().layout.get<LineJoin>();
}
void LineLayer::setLineJoin(PropertyValue<LineJoinType> value) {
if (value == getLineJoin())
return;
- impl->layout.unevaluated.get<LineJoin>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "line-join");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<LineJoin>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<float> LineLayer::getDefaultLineMiterLimit() {
return LineMiterLimit::defaultValue();
}
PropertyValue<float> LineLayer::getLineMiterLimit() const {
- return impl->layout.unevaluated.get<LineMiterLimit>();
+ return impl().layout.get<LineMiterLimit>();
}
void LineLayer::setLineMiterLimit(PropertyValue<float> value) {
if (value == getLineMiterLimit())
return;
- impl->layout.unevaluated.get<LineMiterLimit>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "line-miter-limit");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<LineMiterLimit>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<float> LineLayer::getDefaultLineRoundLimit() {
return LineRoundLimit::defaultValue();
}
PropertyValue<float> LineLayer::getLineRoundLimit() const {
- return impl->layout.unevaluated.get<LineRoundLimit>();
+ return impl().layout.get<LineRoundLimit>();
}
void LineLayer::setLineRoundLimit(PropertyValue<float> value) {
if (value == getLineRoundLimit())
return;
- impl->layout.unevaluated.get<LineRoundLimit>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "line-round-limit");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<LineRoundLimit>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
// Paint properties
@@ -126,250 +163,270 @@ DataDrivenPropertyValue<float> LineLayer::getDefaultLineOpacity() {
return { 1 };
}
-DataDrivenPropertyValue<float> LineLayer::getLineOpacity(const optional<std::string>& klass) const {
- return impl->cascading.template get<LineOpacity>().get(klass);
+DataDrivenPropertyValue<float> LineLayer::getLineOpacity() const {
+ return impl().paint.template get<LineOpacity>().value;
}
-void LineLayer::setLineOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getLineOpacity(klass))
+void LineLayer::setLineOpacity(DataDrivenPropertyValue<float> value) {
+ if (value == getLineOpacity())
return;
- impl->cascading.template get<LineOpacity>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<LineOpacity>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void LineLayer::setLineOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<LineOpacity>().setTransition(value, klass);
+void LineLayer::setLineOpacityTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<LineOpacity>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions LineLayer::getLineOpacityTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<LineOpacity>().getTransition(klass);
+TransitionOptions LineLayer::getLineOpacityTransition() const {
+ return impl().paint.template get<LineOpacity>().options;
}
DataDrivenPropertyValue<Color> LineLayer::getDefaultLineColor() {
return { Color::black() };
}
-DataDrivenPropertyValue<Color> LineLayer::getLineColor(const optional<std::string>& klass) const {
- return impl->cascading.template get<LineColor>().get(klass);
+DataDrivenPropertyValue<Color> LineLayer::getLineColor() const {
+ return impl().paint.template get<LineColor>().value;
}
-void LineLayer::setLineColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
- if (value == getLineColor(klass))
+void LineLayer::setLineColor(DataDrivenPropertyValue<Color> value) {
+ if (value == getLineColor())
return;
- impl->cascading.template get<LineColor>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<LineColor>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void LineLayer::setLineColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<LineColor>().setTransition(value, klass);
+void LineLayer::setLineColorTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<LineColor>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions LineLayer::getLineColorTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<LineColor>().getTransition(klass);
+TransitionOptions LineLayer::getLineColorTransition() const {
+ return impl().paint.template get<LineColor>().options;
}
PropertyValue<std::array<float, 2>> LineLayer::getDefaultLineTranslate() {
return { {{ 0, 0 }} };
}
-PropertyValue<std::array<float, 2>> LineLayer::getLineTranslate(const optional<std::string>& klass) const {
- return impl->cascading.template get<LineTranslate>().get(klass);
+PropertyValue<std::array<float, 2>> LineLayer::getLineTranslate() const {
+ return impl().paint.template get<LineTranslate>().value;
}
-void LineLayer::setLineTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) {
- if (value == getLineTranslate(klass))
+void LineLayer::setLineTranslate(PropertyValue<std::array<float, 2>> value) {
+ if (value == getLineTranslate())
return;
- impl->cascading.template get<LineTranslate>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<LineTranslate>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void LineLayer::setLineTranslateTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<LineTranslate>().setTransition(value, klass);
+void LineLayer::setLineTranslateTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<LineTranslate>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions LineLayer::getLineTranslateTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<LineTranslate>().getTransition(klass);
+TransitionOptions LineLayer::getLineTranslateTransition() const {
+ return impl().paint.template get<LineTranslate>().options;
}
PropertyValue<TranslateAnchorType> LineLayer::getDefaultLineTranslateAnchor() {
return { TranslateAnchorType::Map };
}
-PropertyValue<TranslateAnchorType> LineLayer::getLineTranslateAnchor(const optional<std::string>& klass) const {
- return impl->cascading.template get<LineTranslateAnchor>().get(klass);
+PropertyValue<TranslateAnchorType> LineLayer::getLineTranslateAnchor() const {
+ return impl().paint.template get<LineTranslateAnchor>().value;
}
-void LineLayer::setLineTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) {
- if (value == getLineTranslateAnchor(klass))
+void LineLayer::setLineTranslateAnchor(PropertyValue<TranslateAnchorType> value) {
+ if (value == getLineTranslateAnchor())
return;
- impl->cascading.template get<LineTranslateAnchor>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<LineTranslateAnchor>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void LineLayer::setLineTranslateAnchorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<LineTranslateAnchor>().setTransition(value, klass);
+void LineLayer::setLineTranslateAnchorTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<LineTranslateAnchor>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions LineLayer::getLineTranslateAnchorTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<LineTranslateAnchor>().getTransition(klass);
+TransitionOptions LineLayer::getLineTranslateAnchorTransition() const {
+ return impl().paint.template get<LineTranslateAnchor>().options;
}
-PropertyValue<float> LineLayer::getDefaultLineWidth() {
+DataDrivenPropertyValue<float> LineLayer::getDefaultLineWidth() {
return { 1 };
}
-PropertyValue<float> LineLayer::getLineWidth(const optional<std::string>& klass) const {
- return impl->cascading.template get<LineWidth>().get(klass);
+DataDrivenPropertyValue<float> LineLayer::getLineWidth() const {
+ return impl().paint.template get<LineWidth>().value;
}
-void LineLayer::setLineWidth(PropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getLineWidth(klass))
+void LineLayer::setLineWidth(DataDrivenPropertyValue<float> value) {
+ if (value == getLineWidth())
return;
- impl->cascading.template get<LineWidth>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<LineWidth>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void LineLayer::setLineWidthTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<LineWidth>().setTransition(value, klass);
+void LineLayer::setLineWidthTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<LineWidth>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions LineLayer::getLineWidthTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<LineWidth>().getTransition(klass);
+TransitionOptions LineLayer::getLineWidthTransition() const {
+ return impl().paint.template get<LineWidth>().options;
}
DataDrivenPropertyValue<float> LineLayer::getDefaultLineGapWidth() {
return { 0 };
}
-DataDrivenPropertyValue<float> LineLayer::getLineGapWidth(const optional<std::string>& klass) const {
- return impl->cascading.template get<LineGapWidth>().get(klass);
+DataDrivenPropertyValue<float> LineLayer::getLineGapWidth() const {
+ return impl().paint.template get<LineGapWidth>().value;
}
-void LineLayer::setLineGapWidth(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getLineGapWidth(klass))
+void LineLayer::setLineGapWidth(DataDrivenPropertyValue<float> value) {
+ if (value == getLineGapWidth())
return;
- impl->cascading.template get<LineGapWidth>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<LineGapWidth>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void LineLayer::setLineGapWidthTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<LineGapWidth>().setTransition(value, klass);
+void LineLayer::setLineGapWidthTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<LineGapWidth>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions LineLayer::getLineGapWidthTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<LineGapWidth>().getTransition(klass);
+TransitionOptions LineLayer::getLineGapWidthTransition() const {
+ return impl().paint.template get<LineGapWidth>().options;
}
DataDrivenPropertyValue<float> LineLayer::getDefaultLineOffset() {
return { 0 };
}
-DataDrivenPropertyValue<float> LineLayer::getLineOffset(const optional<std::string>& klass) const {
- return impl->cascading.template get<LineOffset>().get(klass);
+DataDrivenPropertyValue<float> LineLayer::getLineOffset() const {
+ return impl().paint.template get<LineOffset>().value;
}
-void LineLayer::setLineOffset(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getLineOffset(klass))
+void LineLayer::setLineOffset(DataDrivenPropertyValue<float> value) {
+ if (value == getLineOffset())
return;
- impl->cascading.template get<LineOffset>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<LineOffset>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void LineLayer::setLineOffsetTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<LineOffset>().setTransition(value, klass);
+void LineLayer::setLineOffsetTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<LineOffset>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions LineLayer::getLineOffsetTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<LineOffset>().getTransition(klass);
+TransitionOptions LineLayer::getLineOffsetTransition() const {
+ return impl().paint.template get<LineOffset>().options;
}
DataDrivenPropertyValue<float> LineLayer::getDefaultLineBlur() {
return { 0 };
}
-DataDrivenPropertyValue<float> LineLayer::getLineBlur(const optional<std::string>& klass) const {
- return impl->cascading.template get<LineBlur>().get(klass);
+DataDrivenPropertyValue<float> LineLayer::getLineBlur() const {
+ return impl().paint.template get<LineBlur>().value;
}
-void LineLayer::setLineBlur(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getLineBlur(klass))
+void LineLayer::setLineBlur(DataDrivenPropertyValue<float> value) {
+ if (value == getLineBlur())
return;
- impl->cascading.template get<LineBlur>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<LineBlur>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void LineLayer::setLineBlurTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<LineBlur>().setTransition(value, klass);
+void LineLayer::setLineBlurTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<LineBlur>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions LineLayer::getLineBlurTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<LineBlur>().getTransition(klass);
+TransitionOptions LineLayer::getLineBlurTransition() const {
+ return impl().paint.template get<LineBlur>().options;
}
PropertyValue<std::vector<float>> LineLayer::getDefaultLineDasharray() {
return { { } };
}
-PropertyValue<std::vector<float>> LineLayer::getLineDasharray(const optional<std::string>& klass) const {
- return impl->cascading.template get<LineDasharray>().get(klass);
+PropertyValue<std::vector<float>> LineLayer::getLineDasharray() const {
+ return impl().paint.template get<LineDasharray>().value;
}
-void LineLayer::setLineDasharray(PropertyValue<std::vector<float>> value, const optional<std::string>& klass) {
- if (value == getLineDasharray(klass))
+void LineLayer::setLineDasharray(PropertyValue<std::vector<float>> value) {
+ if (value == getLineDasharray())
return;
- impl->cascading.template get<LineDasharray>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<LineDasharray>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void LineLayer::setLineDasharrayTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<LineDasharray>().setTransition(value, klass);
+void LineLayer::setLineDasharrayTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<LineDasharray>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions LineLayer::getLineDasharrayTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<LineDasharray>().getTransition(klass);
+TransitionOptions LineLayer::getLineDasharrayTransition() const {
+ return impl().paint.template get<LineDasharray>().options;
}
PropertyValue<std::string> LineLayer::getDefaultLinePattern() {
return { "" };
}
-PropertyValue<std::string> LineLayer::getLinePattern(const optional<std::string>& klass) const {
- return impl->cascading.template get<LinePattern>().get(klass);
+PropertyValue<std::string> LineLayer::getLinePattern() const {
+ return impl().paint.template get<LinePattern>().value;
}
-void LineLayer::setLinePattern(PropertyValue<std::string> value, const optional<std::string>& klass) {
- if (value == getLinePattern(klass))
+void LineLayer::setLinePattern(PropertyValue<std::string> value) {
+ if (value == getLinePattern())
return;
- impl->cascading.template get<LinePattern>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<LinePattern>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void LineLayer::setLinePatternTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<LinePattern>().setTransition(value, klass);
+void LineLayer::setLinePatternTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<LinePattern>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions LineLayer::getLinePatternTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<LinePattern>().getTransition(klass);
+TransitionOptions LineLayer::getLinePatternTransition() const {
+ return impl().paint.template get<LinePattern>().options;
}
} // namespace style
diff --git a/src/mbgl/style/layers/line_layer_impl.cpp b/src/mbgl/style/layers/line_layer_impl.cpp
index 973a77abf4..bee88d6a47 100644
--- a/src/mbgl/style/layers/line_layer_impl.cpp
+++ b/src/mbgl/style/layers/line_layer_impl.cpp
@@ -1,11 +1,15 @@
#include <mbgl/style/layers/line_layer_impl.hpp>
-#include <mbgl/renderer/render_line_layer.hpp>
namespace mbgl {
namespace style {
-std::unique_ptr<RenderLayer> LineLayer::Impl::createRenderLayer() const {
- return std::make_unique<RenderLineLayer>(*this);
+bool LineLayer::Impl::hasLayoutDifference(const Layer::Impl& other) const {
+ assert(dynamic_cast<const LineLayer::Impl*>(&other));
+ const auto& impl = static_cast<const style::LineLayer::Impl&>(other);
+ return filter != impl.filter ||
+ visibility != impl.visibility ||
+ layout != impl.layout ||
+ paint.hasDataDrivenPropertyDifference(impl.paint);
}
} // namespace style
diff --git a/src/mbgl/style/layers/line_layer_impl.hpp b/src/mbgl/style/layers/line_layer_impl.hpp
index 02c9c85f00..04adc0e85c 100644
--- a/src/mbgl/style/layers/line_layer_impl.hpp
+++ b/src/mbgl/style/layers/line_layer_impl.hpp
@@ -9,14 +9,13 @@ namespace style {
class LineLayer::Impl : public Layer::Impl {
public:
- std::unique_ptr<Layer> clone() const override;
- std::unique_ptr<Layer> cloneRef(const std::string& id) const override;
- void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override;
+ using Layer::Impl::Impl;
- std::unique_ptr<RenderLayer> createRenderLayer() const override;
+ bool hasLayoutDifference(const Layer::Impl&) const override;
+ void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override;
- LineLayoutProperties layout;
- LinePaintProperties::Cascading cascading;
+ LineLayoutProperties::Unevaluated layout;
+ LinePaintProperties::Transitionable paint;
};
} // namespace style
diff --git a/src/mbgl/style/layers/line_layer_properties.hpp b/src/mbgl/style/layers/line_layer_properties.hpp
index 0b234921ad..b2c7f3199c 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/style/properties.hpp>
#include <mbgl/programs/attributes.hpp>
#include <mbgl/programs/uniforms.hpp>
@@ -47,11 +48,11 @@ struct LineTranslateAnchor : PaintProperty<TranslateAnchorType> {
static TranslateAnchorType defaultValue() { return TranslateAnchorType::Map; }
};
-struct LineWidth : PaintProperty<float> {
+struct LineWidth : DataDrivenPaintProperty<float, attributes::a_width, uniforms::u_width> {
static float defaultValue() { return 1; }
};
-struct LineGapWidth : DataDrivenPaintProperty<float, attributes::a_gap_width, uniforms::u_gap_width> {
+struct LineGapWidth : DataDrivenPaintProperty<float, attributes::a_gapwidth, uniforms::u_gapwidth> {
static float defaultValue() { return 0; }
};
@@ -71,14 +72,14 @@ struct LinePattern : CrossFadedPaintProperty<std::string> {
static std::string defaultValue() { return ""; }
};
-class LineLayoutProperties : public LayoutProperties<
+class LineLayoutProperties : public Properties<
LineCap,
LineJoin,
LineMiterLimit,
LineRoundLimit
> {};
-class LinePaintProperties : public PaintProperties<
+class LinePaintProperties : public Properties<
LineOpacity,
LineColor,
LineTranslate,
diff --git a/src/mbgl/style/layers/raster_layer.cpp b/src/mbgl/style/layers/raster_layer.cpp
index b525f9eaa4..a9a8d273fa 100644
--- a/src/mbgl/style/layers/raster_layer.cpp
+++ b/src/mbgl/style/layers/raster_layer.cpp
@@ -2,34 +2,34 @@
#include <mbgl/style/layers/raster_layer.hpp>
#include <mbgl/style/layers/raster_layer_impl.hpp>
-#include <mbgl/style/conversion/stringify.hpp>
+#include <mbgl/style/layer_observer.hpp>
namespace mbgl {
namespace style {
RasterLayer::RasterLayer(const std::string& layerID, const std::string& sourceID)
- : Layer(LayerType::Raster, std::make_unique<Impl>())
- , impl(static_cast<Impl*>(baseImpl.get())) {
- impl->id = layerID;
- impl->source = sourceID;
+ : Layer(makeMutable<Impl>(LayerType::Raster, layerID, sourceID)) {
}
-RasterLayer::RasterLayer(const Impl& other)
- : Layer(LayerType::Raster, std::make_unique<Impl>(other))
- , impl(static_cast<Impl*>(baseImpl.get())) {
+RasterLayer::RasterLayer(Immutable<Impl> impl_)
+ : Layer(std::move(impl_)) {
}
RasterLayer::~RasterLayer() = default;
-std::unique_ptr<Layer> RasterLayer::Impl::clone() const {
- return std::make_unique<RasterLayer>(*this);
+const RasterLayer::Impl& RasterLayer::impl() const {
+ return static_cast<const Impl&>(*baseImpl);
}
-std::unique_ptr<Layer> RasterLayer::Impl::cloneRef(const std::string& id_) const {
- auto result = std::make_unique<RasterLayer>(*this);
- result->impl->id = id_;
- result->impl->cascading = RasterPaintProperties::Cascading();
- return std::move(result);
+Mutable<RasterLayer::Impl> RasterLayer::mutableImpl() const {
+ return makeMutable<Impl>(impl());
+}
+
+std::unique_ptr<Layer> RasterLayer::cloneRef(const std::string& id_) const {
+ auto impl_ = mutableImpl();
+ impl_->id = id_;
+ impl_->paint = RasterPaintProperties::Transitionable();
+ return std::make_unique<RasterLayer>(std::move(impl_));
}
void RasterLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const {
@@ -38,10 +38,35 @@ void RasterLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffe
// Source
const std::string& RasterLayer::getSourceID() const {
- return impl->source;
+ return impl().source;
}
+// Visibility
+
+void RasterLayer::setVisibility(VisibilityType value) {
+ if (value == getVisibility())
+ return;
+ auto impl_ = mutableImpl();
+ impl_->visibility = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
+}
+
+// Zoom range
+
+void RasterLayer::setMinZoom(float minZoom) {
+ auto impl_ = mutableImpl();
+ impl_->minZoom = minZoom;
+ baseImpl = std::move(impl_);
+}
+
+void RasterLayer::setMaxZoom(float maxZoom) {
+ auto impl_ = mutableImpl();
+ impl_->maxZoom = maxZoom;
+ baseImpl = std::move(impl_);
+}
+
// Layout properties
@@ -51,161 +76,189 @@ PropertyValue<float> RasterLayer::getDefaultRasterOpacity() {
return { 1 };
}
-PropertyValue<float> RasterLayer::getRasterOpacity(const optional<std::string>& klass) const {
- return impl->cascading.template get<RasterOpacity>().get(klass);
+PropertyValue<float> RasterLayer::getRasterOpacity() const {
+ return impl().paint.template get<RasterOpacity>().value;
}
-void RasterLayer::setRasterOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getRasterOpacity(klass))
+void RasterLayer::setRasterOpacity(PropertyValue<float> value) {
+ if (value == getRasterOpacity())
return;
- impl->cascading.template get<RasterOpacity>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<RasterOpacity>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void RasterLayer::setRasterOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<RasterOpacity>().setTransition(value, klass);
+void RasterLayer::setRasterOpacityTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<RasterOpacity>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions RasterLayer::getRasterOpacityTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<RasterOpacity>().getTransition(klass);
+TransitionOptions RasterLayer::getRasterOpacityTransition() const {
+ return impl().paint.template get<RasterOpacity>().options;
}
PropertyValue<float> RasterLayer::getDefaultRasterHueRotate() {
return { 0 };
}
-PropertyValue<float> RasterLayer::getRasterHueRotate(const optional<std::string>& klass) const {
- return impl->cascading.template get<RasterHueRotate>().get(klass);
+PropertyValue<float> RasterLayer::getRasterHueRotate() const {
+ return impl().paint.template get<RasterHueRotate>().value;
}
-void RasterLayer::setRasterHueRotate(PropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getRasterHueRotate(klass))
+void RasterLayer::setRasterHueRotate(PropertyValue<float> value) {
+ if (value == getRasterHueRotate())
return;
- impl->cascading.template get<RasterHueRotate>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<RasterHueRotate>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void RasterLayer::setRasterHueRotateTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<RasterHueRotate>().setTransition(value, klass);
+void RasterLayer::setRasterHueRotateTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<RasterHueRotate>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions RasterLayer::getRasterHueRotateTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<RasterHueRotate>().getTransition(klass);
+TransitionOptions RasterLayer::getRasterHueRotateTransition() const {
+ return impl().paint.template get<RasterHueRotate>().options;
}
PropertyValue<float> RasterLayer::getDefaultRasterBrightnessMin() {
return { 0 };
}
-PropertyValue<float> RasterLayer::getRasterBrightnessMin(const optional<std::string>& klass) const {
- return impl->cascading.template get<RasterBrightnessMin>().get(klass);
+PropertyValue<float> RasterLayer::getRasterBrightnessMin() const {
+ return impl().paint.template get<RasterBrightnessMin>().value;
}
-void RasterLayer::setRasterBrightnessMin(PropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getRasterBrightnessMin(klass))
+void RasterLayer::setRasterBrightnessMin(PropertyValue<float> value) {
+ if (value == getRasterBrightnessMin())
return;
- impl->cascading.template get<RasterBrightnessMin>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<RasterBrightnessMin>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void RasterLayer::setRasterBrightnessMinTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<RasterBrightnessMin>().setTransition(value, klass);
+void RasterLayer::setRasterBrightnessMinTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<RasterBrightnessMin>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions RasterLayer::getRasterBrightnessMinTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<RasterBrightnessMin>().getTransition(klass);
+TransitionOptions RasterLayer::getRasterBrightnessMinTransition() const {
+ return impl().paint.template get<RasterBrightnessMin>().options;
}
PropertyValue<float> RasterLayer::getDefaultRasterBrightnessMax() {
return { 1 };
}
-PropertyValue<float> RasterLayer::getRasterBrightnessMax(const optional<std::string>& klass) const {
- return impl->cascading.template get<RasterBrightnessMax>().get(klass);
+PropertyValue<float> RasterLayer::getRasterBrightnessMax() const {
+ return impl().paint.template get<RasterBrightnessMax>().value;
}
-void RasterLayer::setRasterBrightnessMax(PropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getRasterBrightnessMax(klass))
+void RasterLayer::setRasterBrightnessMax(PropertyValue<float> value) {
+ if (value == getRasterBrightnessMax())
return;
- impl->cascading.template get<RasterBrightnessMax>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<RasterBrightnessMax>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void RasterLayer::setRasterBrightnessMaxTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<RasterBrightnessMax>().setTransition(value, klass);
+void RasterLayer::setRasterBrightnessMaxTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<RasterBrightnessMax>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions RasterLayer::getRasterBrightnessMaxTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<RasterBrightnessMax>().getTransition(klass);
+TransitionOptions RasterLayer::getRasterBrightnessMaxTransition() const {
+ return impl().paint.template get<RasterBrightnessMax>().options;
}
PropertyValue<float> RasterLayer::getDefaultRasterSaturation() {
return { 0 };
}
-PropertyValue<float> RasterLayer::getRasterSaturation(const optional<std::string>& klass) const {
- return impl->cascading.template get<RasterSaturation>().get(klass);
+PropertyValue<float> RasterLayer::getRasterSaturation() const {
+ return impl().paint.template get<RasterSaturation>().value;
}
-void RasterLayer::setRasterSaturation(PropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getRasterSaturation(klass))
+void RasterLayer::setRasterSaturation(PropertyValue<float> value) {
+ if (value == getRasterSaturation())
return;
- impl->cascading.template get<RasterSaturation>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<RasterSaturation>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void RasterLayer::setRasterSaturationTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<RasterSaturation>().setTransition(value, klass);
+void RasterLayer::setRasterSaturationTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<RasterSaturation>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions RasterLayer::getRasterSaturationTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<RasterSaturation>().getTransition(klass);
+TransitionOptions RasterLayer::getRasterSaturationTransition() const {
+ return impl().paint.template get<RasterSaturation>().options;
}
PropertyValue<float> RasterLayer::getDefaultRasterContrast() {
return { 0 };
}
-PropertyValue<float> RasterLayer::getRasterContrast(const optional<std::string>& klass) const {
- return impl->cascading.template get<RasterContrast>().get(klass);
+PropertyValue<float> RasterLayer::getRasterContrast() const {
+ return impl().paint.template get<RasterContrast>().value;
}
-void RasterLayer::setRasterContrast(PropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getRasterContrast(klass))
+void RasterLayer::setRasterContrast(PropertyValue<float> value) {
+ if (value == getRasterContrast())
return;
- impl->cascading.template get<RasterContrast>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<RasterContrast>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void RasterLayer::setRasterContrastTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<RasterContrast>().setTransition(value, klass);
+void RasterLayer::setRasterContrastTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<RasterContrast>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions RasterLayer::getRasterContrastTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<RasterContrast>().getTransition(klass);
+TransitionOptions RasterLayer::getRasterContrastTransition() const {
+ return impl().paint.template get<RasterContrast>().options;
}
PropertyValue<float> RasterLayer::getDefaultRasterFadeDuration() {
return { 300 };
}
-PropertyValue<float> RasterLayer::getRasterFadeDuration(const optional<std::string>& klass) const {
- return impl->cascading.template get<RasterFadeDuration>().get(klass);
+PropertyValue<float> RasterLayer::getRasterFadeDuration() const {
+ return impl().paint.template get<RasterFadeDuration>().value;
}
-void RasterLayer::setRasterFadeDuration(PropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getRasterFadeDuration(klass))
+void RasterLayer::setRasterFadeDuration(PropertyValue<float> value) {
+ if (value == getRasterFadeDuration())
return;
- impl->cascading.template get<RasterFadeDuration>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<RasterFadeDuration>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void RasterLayer::setRasterFadeDurationTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<RasterFadeDuration>().setTransition(value, klass);
+void RasterLayer::setRasterFadeDurationTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<RasterFadeDuration>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions RasterLayer::getRasterFadeDurationTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<RasterFadeDuration>().getTransition(klass);
+TransitionOptions RasterLayer::getRasterFadeDurationTransition() const {
+ return impl().paint.template get<RasterFadeDuration>().options;
}
} // namespace style
diff --git a/src/mbgl/style/layers/raster_layer_impl.cpp b/src/mbgl/style/layers/raster_layer_impl.cpp
index fa9f80dac6..a995f50dd3 100644
--- a/src/mbgl/style/layers/raster_layer_impl.cpp
+++ b/src/mbgl/style/layers/raster_layer_impl.cpp
@@ -1,11 +1,10 @@
#include <mbgl/style/layers/raster_layer_impl.hpp>
-#include <mbgl/renderer/render_raster_layer.hpp>
namespace mbgl {
namespace style {
-std::unique_ptr<RenderLayer> RasterLayer::Impl::createRenderLayer() const {
- return std::make_unique<RenderRasterLayer>(*this);
+bool RasterLayer::Impl::hasLayoutDifference(const Layer::Impl&) const {
+ return false;
}
} // namespace style
diff --git a/src/mbgl/style/layers/raster_layer_impl.hpp b/src/mbgl/style/layers/raster_layer_impl.hpp
index edf5f9111b..adbe703e92 100644
--- a/src/mbgl/style/layers/raster_layer_impl.hpp
+++ b/src/mbgl/style/layers/raster_layer_impl.hpp
@@ -9,13 +9,12 @@ namespace style {
class RasterLayer::Impl : public Layer::Impl {
public:
- std::unique_ptr<Layer> clone() const override;
- std::unique_ptr<Layer> cloneRef(const std::string& id) const override;
- void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override;
+ using Layer::Impl::Impl;
- std::unique_ptr<RenderLayer> createRenderLayer() const override;
+ bool hasLayoutDifference(const Layer::Impl&) const override;
+ void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override;
- RasterPaintProperties::Cascading cascading;
+ RasterPaintProperties::Transitionable paint;
};
} // namespace style
diff --git a/src/mbgl/style/layers/raster_layer_properties.hpp b/src/mbgl/style/layers/raster_layer_properties.hpp
index 219fe34d8c..12df09f32c 100644
--- a/src/mbgl/style/layers/raster_layer_properties.hpp
+++ b/src/mbgl/style/layers/raster_layer_properties.hpp
@@ -5,7 +5,9 @@
#include <mbgl/style/types.hpp>
#include <mbgl/style/layout_property.hpp>
#include <mbgl/style/paint_property.hpp>
+#include <mbgl/style/properties.hpp>
#include <mbgl/programs/attributes.hpp>
+#include <mbgl/programs/uniforms.hpp>
namespace mbgl {
namespace style {
@@ -38,7 +40,7 @@ struct RasterFadeDuration : PaintProperty<float> {
static float defaultValue() { return 300; }
};
-class RasterPaintProperties : public PaintProperties<
+class RasterPaintProperties : public Properties<
RasterOpacity,
RasterHueRotate,
RasterBrightnessMin,
diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp
index 273a9fd24e..182b4b0a48 100644
--- a/src/mbgl/style/layers/symbol_layer.cpp
+++ b/src/mbgl/style/layers/symbol_layer.cpp
@@ -2,63 +2,92 @@
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
-#include <mbgl/style/conversion/stringify.hpp>
+#include <mbgl/style/layer_observer.hpp>
namespace mbgl {
namespace style {
SymbolLayer::SymbolLayer(const std::string& layerID, const std::string& sourceID)
- : Layer(LayerType::Symbol, std::make_unique<Impl>())
- , impl(static_cast<Impl*>(baseImpl.get())) {
- impl->id = layerID;
- impl->source = sourceID;
+ : Layer(makeMutable<Impl>(LayerType::Symbol, layerID, sourceID)) {
}
-SymbolLayer::SymbolLayer(const Impl& other)
- : Layer(LayerType::Symbol, std::make_unique<Impl>(other))
- , impl(static_cast<Impl*>(baseImpl.get())) {
+SymbolLayer::SymbolLayer(Immutable<Impl> impl_)
+ : Layer(std::move(impl_)) {
}
SymbolLayer::~SymbolLayer() = default;
-std::unique_ptr<Layer> SymbolLayer::Impl::clone() const {
- return std::make_unique<SymbolLayer>(*this);
+const SymbolLayer::Impl& SymbolLayer::impl() const {
+ return static_cast<const Impl&>(*baseImpl);
}
-std::unique_ptr<Layer> SymbolLayer::Impl::cloneRef(const std::string& id_) const {
- auto result = std::make_unique<SymbolLayer>(*this);
- result->impl->id = id_;
- result->impl->cascading = SymbolPaintProperties::Cascading();
- return std::move(result);
+Mutable<SymbolLayer::Impl> SymbolLayer::mutableImpl() const {
+ return makeMutable<Impl>(impl());
+}
+
+std::unique_ptr<Layer> SymbolLayer::cloneRef(const std::string& id_) const {
+ auto impl_ = mutableImpl();
+ impl_->id = id_;
+ impl_->paint = SymbolPaintProperties::Transitionable();
+ return std::make_unique<SymbolLayer>(std::move(impl_));
}
void SymbolLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>& writer) const {
- conversion::stringify(writer, layout);
+ layout.stringify(writer);
}
// Source
const std::string& SymbolLayer::getSourceID() const {
- return impl->source;
+ return impl().source;
}
void SymbolLayer::setSourceLayer(const std::string& sourceLayer) {
- impl->sourceLayer = sourceLayer;
+ auto impl_ = mutableImpl();
+ impl_->sourceLayer = sourceLayer;
+ baseImpl = std::move(impl_);
}
const std::string& SymbolLayer::getSourceLayer() const {
- return impl->sourceLayer;
+ return impl().sourceLayer;
}
// Filter
void SymbolLayer::setFilter(const Filter& filter) {
- impl->filter = filter;
- impl->observer->onLayerFilterChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->filter = filter;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
const Filter& SymbolLayer::getFilter() const {
- return impl->filter;
+ return impl().filter;
+}
+
+// Visibility
+
+void SymbolLayer::setVisibility(VisibilityType value) {
+ if (value == getVisibility())
+ return;
+ auto impl_ = mutableImpl();
+ impl_->visibility = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
+}
+
+// Zoom range
+
+void SymbolLayer::setMinZoom(float minZoom) {
+ auto impl_ = mutableImpl();
+ impl_->minZoom = minZoom;
+ baseImpl = std::move(impl_);
+}
+
+void SymbolLayer::setMaxZoom(float maxZoom) {
+ auto impl_ = mutableImpl();
+ impl_->maxZoom = maxZoom;
+ baseImpl = std::move(impl_);
}
// Layout properties
@@ -68,476 +97,544 @@ PropertyValue<SymbolPlacementType> SymbolLayer::getDefaultSymbolPlacement() {
}
PropertyValue<SymbolPlacementType> SymbolLayer::getSymbolPlacement() const {
- return impl->layout.unevaluated.get<SymbolPlacement>();
+ return impl().layout.get<SymbolPlacement>();
}
void SymbolLayer::setSymbolPlacement(PropertyValue<SymbolPlacementType> value) {
if (value == getSymbolPlacement())
return;
- impl->layout.unevaluated.get<SymbolPlacement>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "symbol-placement");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<SymbolPlacement>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<float> SymbolLayer::getDefaultSymbolSpacing() {
return SymbolSpacing::defaultValue();
}
PropertyValue<float> SymbolLayer::getSymbolSpacing() const {
- return impl->layout.unevaluated.get<SymbolSpacing>();
+ return impl().layout.get<SymbolSpacing>();
}
void SymbolLayer::setSymbolSpacing(PropertyValue<float> value) {
if (value == getSymbolSpacing())
return;
- impl->layout.unevaluated.get<SymbolSpacing>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "symbol-spacing");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<SymbolSpacing>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<bool> SymbolLayer::getDefaultSymbolAvoidEdges() {
return SymbolAvoidEdges::defaultValue();
}
PropertyValue<bool> SymbolLayer::getSymbolAvoidEdges() const {
- return impl->layout.unevaluated.get<SymbolAvoidEdges>();
+ return impl().layout.get<SymbolAvoidEdges>();
}
void SymbolLayer::setSymbolAvoidEdges(PropertyValue<bool> value) {
if (value == getSymbolAvoidEdges())
return;
- impl->layout.unevaluated.get<SymbolAvoidEdges>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "symbol-avoid-edges");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<SymbolAvoidEdges>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<bool> SymbolLayer::getDefaultIconAllowOverlap() {
return IconAllowOverlap::defaultValue();
}
PropertyValue<bool> SymbolLayer::getIconAllowOverlap() const {
- return impl->layout.unevaluated.get<IconAllowOverlap>();
+ return impl().layout.get<IconAllowOverlap>();
}
void SymbolLayer::setIconAllowOverlap(PropertyValue<bool> value) {
if (value == getIconAllowOverlap())
return;
- impl->layout.unevaluated.get<IconAllowOverlap>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "icon-allow-overlap");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<IconAllowOverlap>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<bool> SymbolLayer::getDefaultIconIgnorePlacement() {
return IconIgnorePlacement::defaultValue();
}
PropertyValue<bool> SymbolLayer::getIconIgnorePlacement() const {
- return impl->layout.unevaluated.get<IconIgnorePlacement>();
+ return impl().layout.get<IconIgnorePlacement>();
}
void SymbolLayer::setIconIgnorePlacement(PropertyValue<bool> value) {
if (value == getIconIgnorePlacement())
return;
- impl->layout.unevaluated.get<IconIgnorePlacement>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "icon-ignore-placement");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<IconIgnorePlacement>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<bool> SymbolLayer::getDefaultIconOptional() {
return IconOptional::defaultValue();
}
PropertyValue<bool> SymbolLayer::getIconOptional() const {
- return impl->layout.unevaluated.get<IconOptional>();
+ return impl().layout.get<IconOptional>();
}
void SymbolLayer::setIconOptional(PropertyValue<bool> value) {
if (value == getIconOptional())
return;
- impl->layout.unevaluated.get<IconOptional>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "icon-optional");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<IconOptional>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<AlignmentType> SymbolLayer::getDefaultIconRotationAlignment() {
return IconRotationAlignment::defaultValue();
}
PropertyValue<AlignmentType> SymbolLayer::getIconRotationAlignment() const {
- return impl->layout.unevaluated.get<IconRotationAlignment>();
+ return impl().layout.get<IconRotationAlignment>();
}
void SymbolLayer::setIconRotationAlignment(PropertyValue<AlignmentType> value) {
if (value == getIconRotationAlignment())
return;
- impl->layout.unevaluated.get<IconRotationAlignment>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "icon-rotation-alignment");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<IconRotationAlignment>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
DataDrivenPropertyValue<float> SymbolLayer::getDefaultIconSize() {
return IconSize::defaultValue();
}
DataDrivenPropertyValue<float> SymbolLayer::getIconSize() const {
- return impl->layout.unevaluated.get<IconSize>();
+ return impl().layout.get<IconSize>();
}
void SymbolLayer::setIconSize(DataDrivenPropertyValue<float> value) {
if (value == getIconSize())
return;
- impl->layout.unevaluated.get<IconSize>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "icon-size");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<IconSize>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<IconTextFitType> SymbolLayer::getDefaultIconTextFit() {
return IconTextFit::defaultValue();
}
PropertyValue<IconTextFitType> SymbolLayer::getIconTextFit() const {
- return impl->layout.unevaluated.get<IconTextFit>();
+ return impl().layout.get<IconTextFit>();
}
void SymbolLayer::setIconTextFit(PropertyValue<IconTextFitType> value) {
if (value == getIconTextFit())
return;
- impl->layout.unevaluated.get<IconTextFit>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "icon-text-fit");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<IconTextFit>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<std::array<float, 4>> SymbolLayer::getDefaultIconTextFitPadding() {
return IconTextFitPadding::defaultValue();
}
PropertyValue<std::array<float, 4>> SymbolLayer::getIconTextFitPadding() const {
- return impl->layout.unevaluated.get<IconTextFitPadding>();
+ return impl().layout.get<IconTextFitPadding>();
}
void SymbolLayer::setIconTextFitPadding(PropertyValue<std::array<float, 4>> value) {
if (value == getIconTextFitPadding())
return;
- impl->layout.unevaluated.get<IconTextFitPadding>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "icon-text-fit-padding");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<IconTextFitPadding>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
DataDrivenPropertyValue<std::string> SymbolLayer::getDefaultIconImage() {
return IconImage::defaultValue();
}
DataDrivenPropertyValue<std::string> SymbolLayer::getIconImage() const {
- return impl->layout.unevaluated.get<IconImage>();
+ return impl().layout.get<IconImage>();
}
void SymbolLayer::setIconImage(DataDrivenPropertyValue<std::string> value) {
if (value == getIconImage())
return;
- impl->layout.unevaluated.get<IconImage>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "icon-image");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<IconImage>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
DataDrivenPropertyValue<float> SymbolLayer::getDefaultIconRotate() {
return IconRotate::defaultValue();
}
DataDrivenPropertyValue<float> SymbolLayer::getIconRotate() const {
- return impl->layout.unevaluated.get<IconRotate>();
+ return impl().layout.get<IconRotate>();
}
void SymbolLayer::setIconRotate(DataDrivenPropertyValue<float> value) {
if (value == getIconRotate())
return;
- impl->layout.unevaluated.get<IconRotate>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "icon-rotate");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<IconRotate>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<float> SymbolLayer::getDefaultIconPadding() {
return IconPadding::defaultValue();
}
PropertyValue<float> SymbolLayer::getIconPadding() const {
- return impl->layout.unevaluated.get<IconPadding>();
+ return impl().layout.get<IconPadding>();
}
void SymbolLayer::setIconPadding(PropertyValue<float> value) {
if (value == getIconPadding())
return;
- impl->layout.unevaluated.get<IconPadding>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "icon-padding");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<IconPadding>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<bool> SymbolLayer::getDefaultIconKeepUpright() {
return IconKeepUpright::defaultValue();
}
PropertyValue<bool> SymbolLayer::getIconKeepUpright() const {
- return impl->layout.unevaluated.get<IconKeepUpright>();
+ return impl().layout.get<IconKeepUpright>();
}
void SymbolLayer::setIconKeepUpright(PropertyValue<bool> value) {
if (value == getIconKeepUpright())
return;
- impl->layout.unevaluated.get<IconKeepUpright>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "icon-keep-upright");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<IconKeepUpright>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
DataDrivenPropertyValue<std::array<float, 2>> SymbolLayer::getDefaultIconOffset() {
return IconOffset::defaultValue();
}
DataDrivenPropertyValue<std::array<float, 2>> SymbolLayer::getIconOffset() const {
- return impl->layout.unevaluated.get<IconOffset>();
+ return impl().layout.get<IconOffset>();
}
void SymbolLayer::setIconOffset(DataDrivenPropertyValue<std::array<float, 2>> value) {
if (value == getIconOffset())
return;
- impl->layout.unevaluated.get<IconOffset>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "icon-offset");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<IconOffset>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<AlignmentType> SymbolLayer::getDefaultTextPitchAlignment() {
return TextPitchAlignment::defaultValue();
}
PropertyValue<AlignmentType> SymbolLayer::getTextPitchAlignment() const {
- return impl->layout.unevaluated.get<TextPitchAlignment>();
+ return impl().layout.get<TextPitchAlignment>();
}
void SymbolLayer::setTextPitchAlignment(PropertyValue<AlignmentType> value) {
if (value == getTextPitchAlignment())
return;
- impl->layout.unevaluated.get<TextPitchAlignment>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "text-pitch-alignment");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<TextPitchAlignment>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<AlignmentType> SymbolLayer::getDefaultTextRotationAlignment() {
return TextRotationAlignment::defaultValue();
}
PropertyValue<AlignmentType> SymbolLayer::getTextRotationAlignment() const {
- return impl->layout.unevaluated.get<TextRotationAlignment>();
+ return impl().layout.get<TextRotationAlignment>();
}
void SymbolLayer::setTextRotationAlignment(PropertyValue<AlignmentType> value) {
if (value == getTextRotationAlignment())
return;
- impl->layout.unevaluated.get<TextRotationAlignment>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "text-rotation-alignment");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<TextRotationAlignment>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
DataDrivenPropertyValue<std::string> SymbolLayer::getDefaultTextField() {
return TextField::defaultValue();
}
DataDrivenPropertyValue<std::string> SymbolLayer::getTextField() const {
- return impl->layout.unevaluated.get<TextField>();
+ return impl().layout.get<TextField>();
}
void SymbolLayer::setTextField(DataDrivenPropertyValue<std::string> value) {
if (value == getTextField())
return;
- impl->layout.unevaluated.get<TextField>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "text-field");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<TextField>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<std::vector<std::string>> SymbolLayer::getDefaultTextFont() {
return TextFont::defaultValue();
}
PropertyValue<std::vector<std::string>> SymbolLayer::getTextFont() const {
- return impl->layout.unevaluated.get<TextFont>();
+ return impl().layout.get<TextFont>();
}
void SymbolLayer::setTextFont(PropertyValue<std::vector<std::string>> value) {
if (value == getTextFont())
return;
- impl->layout.unevaluated.get<TextFont>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "text-font");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<TextFont>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
DataDrivenPropertyValue<float> SymbolLayer::getDefaultTextSize() {
return TextSize::defaultValue();
}
DataDrivenPropertyValue<float> SymbolLayer::getTextSize() const {
- return impl->layout.unevaluated.get<TextSize>();
+ return impl().layout.get<TextSize>();
}
void SymbolLayer::setTextSize(DataDrivenPropertyValue<float> value) {
if (value == getTextSize())
return;
- impl->layout.unevaluated.get<TextSize>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "text-size");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<TextSize>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<float> SymbolLayer::getDefaultTextMaxWidth() {
return TextMaxWidth::defaultValue();
}
PropertyValue<float> SymbolLayer::getTextMaxWidth() const {
- return impl->layout.unevaluated.get<TextMaxWidth>();
+ return impl().layout.get<TextMaxWidth>();
}
void SymbolLayer::setTextMaxWidth(PropertyValue<float> value) {
if (value == getTextMaxWidth())
return;
- impl->layout.unevaluated.get<TextMaxWidth>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "text-max-width");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<TextMaxWidth>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<float> SymbolLayer::getDefaultTextLineHeight() {
return TextLineHeight::defaultValue();
}
PropertyValue<float> SymbolLayer::getTextLineHeight() const {
- return impl->layout.unevaluated.get<TextLineHeight>();
+ return impl().layout.get<TextLineHeight>();
}
void SymbolLayer::setTextLineHeight(PropertyValue<float> value) {
if (value == getTextLineHeight())
return;
- impl->layout.unevaluated.get<TextLineHeight>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "text-line-height");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<TextLineHeight>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<float> SymbolLayer::getDefaultTextLetterSpacing() {
return TextLetterSpacing::defaultValue();
}
PropertyValue<float> SymbolLayer::getTextLetterSpacing() const {
- return impl->layout.unevaluated.get<TextLetterSpacing>();
+ return impl().layout.get<TextLetterSpacing>();
}
void SymbolLayer::setTextLetterSpacing(PropertyValue<float> value) {
if (value == getTextLetterSpacing())
return;
- impl->layout.unevaluated.get<TextLetterSpacing>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "text-letter-spacing");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<TextLetterSpacing>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<TextJustifyType> SymbolLayer::getDefaultTextJustify() {
return TextJustify::defaultValue();
}
PropertyValue<TextJustifyType> SymbolLayer::getTextJustify() const {
- return impl->layout.unevaluated.get<TextJustify>();
+ return impl().layout.get<TextJustify>();
}
void SymbolLayer::setTextJustify(PropertyValue<TextJustifyType> value) {
if (value == getTextJustify())
return;
- impl->layout.unevaluated.get<TextJustify>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "text-justify");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<TextJustify>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<TextAnchorType> SymbolLayer::getDefaultTextAnchor() {
return TextAnchor::defaultValue();
}
PropertyValue<TextAnchorType> SymbolLayer::getTextAnchor() const {
- return impl->layout.unevaluated.get<TextAnchor>();
+ return impl().layout.get<TextAnchor>();
}
void SymbolLayer::setTextAnchor(PropertyValue<TextAnchorType> value) {
if (value == getTextAnchor())
return;
- impl->layout.unevaluated.get<TextAnchor>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "text-anchor");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<TextAnchor>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<float> SymbolLayer::getDefaultTextMaxAngle() {
return TextMaxAngle::defaultValue();
}
PropertyValue<float> SymbolLayer::getTextMaxAngle() const {
- return impl->layout.unevaluated.get<TextMaxAngle>();
+ return impl().layout.get<TextMaxAngle>();
}
void SymbolLayer::setTextMaxAngle(PropertyValue<float> value) {
if (value == getTextMaxAngle())
return;
- impl->layout.unevaluated.get<TextMaxAngle>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "text-max-angle");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<TextMaxAngle>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
DataDrivenPropertyValue<float> SymbolLayer::getDefaultTextRotate() {
return TextRotate::defaultValue();
}
DataDrivenPropertyValue<float> SymbolLayer::getTextRotate() const {
- return impl->layout.unevaluated.get<TextRotate>();
+ return impl().layout.get<TextRotate>();
}
void SymbolLayer::setTextRotate(DataDrivenPropertyValue<float> value) {
if (value == getTextRotate())
return;
- impl->layout.unevaluated.get<TextRotate>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "text-rotate");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<TextRotate>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<float> SymbolLayer::getDefaultTextPadding() {
return TextPadding::defaultValue();
}
PropertyValue<float> SymbolLayer::getTextPadding() const {
- return impl->layout.unevaluated.get<TextPadding>();
+ return impl().layout.get<TextPadding>();
}
void SymbolLayer::setTextPadding(PropertyValue<float> value) {
if (value == getTextPadding())
return;
- impl->layout.unevaluated.get<TextPadding>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "text-padding");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<TextPadding>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<bool> SymbolLayer::getDefaultTextKeepUpright() {
return TextKeepUpright::defaultValue();
}
PropertyValue<bool> SymbolLayer::getTextKeepUpright() const {
- return impl->layout.unevaluated.get<TextKeepUpright>();
+ return impl().layout.get<TextKeepUpright>();
}
void SymbolLayer::setTextKeepUpright(PropertyValue<bool> value) {
if (value == getTextKeepUpright())
return;
- impl->layout.unevaluated.get<TextKeepUpright>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "text-keep-upright");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<TextKeepUpright>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
DataDrivenPropertyValue<TextTransformType> SymbolLayer::getDefaultTextTransform() {
return TextTransform::defaultValue();
}
DataDrivenPropertyValue<TextTransformType> SymbolLayer::getTextTransform() const {
- return impl->layout.unevaluated.get<TextTransform>();
+ return impl().layout.get<TextTransform>();
}
void SymbolLayer::setTextTransform(DataDrivenPropertyValue<TextTransformType> value) {
if (value == getTextTransform())
return;
- impl->layout.unevaluated.get<TextTransform>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "text-transform");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<TextTransform>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
DataDrivenPropertyValue<std::array<float, 2>> SymbolLayer::getDefaultTextOffset() {
return TextOffset::defaultValue();
}
DataDrivenPropertyValue<std::array<float, 2>> SymbolLayer::getTextOffset() const {
- return impl->layout.unevaluated.get<TextOffset>();
+ return impl().layout.get<TextOffset>();
}
void SymbolLayer::setTextOffset(DataDrivenPropertyValue<std::array<float, 2>> value) {
if (value == getTextOffset())
return;
- impl->layout.unevaluated.get<TextOffset>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "text-offset");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<TextOffset>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<bool> SymbolLayer::getDefaultTextAllowOverlap() {
return TextAllowOverlap::defaultValue();
}
PropertyValue<bool> SymbolLayer::getTextAllowOverlap() const {
- return impl->layout.unevaluated.get<TextAllowOverlap>();
+ return impl().layout.get<TextAllowOverlap>();
}
void SymbolLayer::setTextAllowOverlap(PropertyValue<bool> value) {
if (value == getTextAllowOverlap())
return;
- impl->layout.unevaluated.get<TextAllowOverlap>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "text-allow-overlap");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<TextAllowOverlap>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<bool> SymbolLayer::getDefaultTextIgnorePlacement() {
return TextIgnorePlacement::defaultValue();
}
PropertyValue<bool> SymbolLayer::getTextIgnorePlacement() const {
- return impl->layout.unevaluated.get<TextIgnorePlacement>();
+ return impl().layout.get<TextIgnorePlacement>();
}
void SymbolLayer::setTextIgnorePlacement(PropertyValue<bool> value) {
if (value == getTextIgnorePlacement())
return;
- impl->layout.unevaluated.get<TextIgnorePlacement>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "text-ignore-placement");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<TextIgnorePlacement>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
PropertyValue<bool> SymbolLayer::getDefaultTextOptional() {
return TextOptional::defaultValue();
}
PropertyValue<bool> SymbolLayer::getTextOptional() const {
- return impl->layout.unevaluated.get<TextOptional>();
+ return impl().layout.get<TextOptional>();
}
void SymbolLayer::setTextOptional(PropertyValue<bool> value) {
if (value == getTextOptional())
return;
- impl->layout.unevaluated.get<TextOptional>() = value;
- impl->observer->onLayerLayoutPropertyChanged(*this, "text-optional");
+ auto impl_ = mutableImpl();
+ impl_->layout.get<TextOptional>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
// Paint properties
@@ -546,362 +643,378 @@ DataDrivenPropertyValue<float> SymbolLayer::getDefaultIconOpacity() {
return { 1 };
}
-DataDrivenPropertyValue<float> SymbolLayer::getIconOpacity(const optional<std::string>& klass) const {
- return impl->cascading.template get<IconOpacity>().get(klass);
+DataDrivenPropertyValue<float> SymbolLayer::getIconOpacity() const {
+ return impl().paint.template get<IconOpacity>().value;
}
-void SymbolLayer::setIconOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getIconOpacity(klass))
+void SymbolLayer::setIconOpacity(DataDrivenPropertyValue<float> value) {
+ if (value == getIconOpacity())
return;
- impl->cascading.template get<IconOpacity>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<IconOpacity>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void SymbolLayer::setIconOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<IconOpacity>().setTransition(value, klass);
+void SymbolLayer::setIconOpacityTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<IconOpacity>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions SymbolLayer::getIconOpacityTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<IconOpacity>().getTransition(klass);
+TransitionOptions SymbolLayer::getIconOpacityTransition() const {
+ return impl().paint.template get<IconOpacity>().options;
}
DataDrivenPropertyValue<Color> SymbolLayer::getDefaultIconColor() {
return { Color::black() };
}
-DataDrivenPropertyValue<Color> SymbolLayer::getIconColor(const optional<std::string>& klass) const {
- return impl->cascading.template get<IconColor>().get(klass);
+DataDrivenPropertyValue<Color> SymbolLayer::getIconColor() const {
+ return impl().paint.template get<IconColor>().value;
}
-void SymbolLayer::setIconColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
- if (value == getIconColor(klass))
+void SymbolLayer::setIconColor(DataDrivenPropertyValue<Color> value) {
+ if (value == getIconColor())
return;
- impl->cascading.template get<IconColor>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<IconColor>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void SymbolLayer::setIconColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<IconColor>().setTransition(value, klass);
+void SymbolLayer::setIconColorTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<IconColor>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions SymbolLayer::getIconColorTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<IconColor>().getTransition(klass);
+TransitionOptions SymbolLayer::getIconColorTransition() const {
+ return impl().paint.template get<IconColor>().options;
}
DataDrivenPropertyValue<Color> SymbolLayer::getDefaultIconHaloColor() {
return { {} };
}
-DataDrivenPropertyValue<Color> SymbolLayer::getIconHaloColor(const optional<std::string>& klass) const {
- return impl->cascading.template get<IconHaloColor>().get(klass);
+DataDrivenPropertyValue<Color> SymbolLayer::getIconHaloColor() const {
+ return impl().paint.template get<IconHaloColor>().value;
}
-void SymbolLayer::setIconHaloColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
- if (value == getIconHaloColor(klass))
+void SymbolLayer::setIconHaloColor(DataDrivenPropertyValue<Color> value) {
+ if (value == getIconHaloColor())
return;
- impl->cascading.template get<IconHaloColor>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<IconHaloColor>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void SymbolLayer::setIconHaloColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<IconHaloColor>().setTransition(value, klass);
+void SymbolLayer::setIconHaloColorTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<IconHaloColor>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions SymbolLayer::getIconHaloColorTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<IconHaloColor>().getTransition(klass);
+TransitionOptions SymbolLayer::getIconHaloColorTransition() const {
+ return impl().paint.template get<IconHaloColor>().options;
}
DataDrivenPropertyValue<float> SymbolLayer::getDefaultIconHaloWidth() {
return { 0 };
}
-DataDrivenPropertyValue<float> SymbolLayer::getIconHaloWidth(const optional<std::string>& klass) const {
- return impl->cascading.template get<IconHaloWidth>().get(klass);
+DataDrivenPropertyValue<float> SymbolLayer::getIconHaloWidth() const {
+ return impl().paint.template get<IconHaloWidth>().value;
}
-void SymbolLayer::setIconHaloWidth(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getIconHaloWidth(klass))
+void SymbolLayer::setIconHaloWidth(DataDrivenPropertyValue<float> value) {
+ if (value == getIconHaloWidth())
return;
- impl->cascading.template get<IconHaloWidth>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<IconHaloWidth>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void SymbolLayer::setIconHaloWidthTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<IconHaloWidth>().setTransition(value, klass);
+void SymbolLayer::setIconHaloWidthTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<IconHaloWidth>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions SymbolLayer::getIconHaloWidthTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<IconHaloWidth>().getTransition(klass);
+TransitionOptions SymbolLayer::getIconHaloWidthTransition() const {
+ return impl().paint.template get<IconHaloWidth>().options;
}
DataDrivenPropertyValue<float> SymbolLayer::getDefaultIconHaloBlur() {
return { 0 };
}
-DataDrivenPropertyValue<float> SymbolLayer::getIconHaloBlur(const optional<std::string>& klass) const {
- return impl->cascading.template get<IconHaloBlur>().get(klass);
+DataDrivenPropertyValue<float> SymbolLayer::getIconHaloBlur() const {
+ return impl().paint.template get<IconHaloBlur>().value;
}
-void SymbolLayer::setIconHaloBlur(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getIconHaloBlur(klass))
+void SymbolLayer::setIconHaloBlur(DataDrivenPropertyValue<float> value) {
+ if (value == getIconHaloBlur())
return;
- impl->cascading.template get<IconHaloBlur>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<IconHaloBlur>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void SymbolLayer::setIconHaloBlurTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<IconHaloBlur>().setTransition(value, klass);
+void SymbolLayer::setIconHaloBlurTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<IconHaloBlur>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions SymbolLayer::getIconHaloBlurTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<IconHaloBlur>().getTransition(klass);
+TransitionOptions SymbolLayer::getIconHaloBlurTransition() const {
+ return impl().paint.template get<IconHaloBlur>().options;
}
PropertyValue<std::array<float, 2>> SymbolLayer::getDefaultIconTranslate() {
return { {{ 0, 0 }} };
}
-PropertyValue<std::array<float, 2>> SymbolLayer::getIconTranslate(const optional<std::string>& klass) const {
- return impl->cascading.template get<IconTranslate>().get(klass);
+PropertyValue<std::array<float, 2>> SymbolLayer::getIconTranslate() const {
+ return impl().paint.template get<IconTranslate>().value;
}
-void SymbolLayer::setIconTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) {
- if (value == getIconTranslate(klass))
+void SymbolLayer::setIconTranslate(PropertyValue<std::array<float, 2>> value) {
+ if (value == getIconTranslate())
return;
- impl->cascading.template get<IconTranslate>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<IconTranslate>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void SymbolLayer::setIconTranslateTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<IconTranslate>().setTransition(value, klass);
+void SymbolLayer::setIconTranslateTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<IconTranslate>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions SymbolLayer::getIconTranslateTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<IconTranslate>().getTransition(klass);
+TransitionOptions SymbolLayer::getIconTranslateTransition() const {
+ return impl().paint.template get<IconTranslate>().options;
}
PropertyValue<TranslateAnchorType> SymbolLayer::getDefaultIconTranslateAnchor() {
return { TranslateAnchorType::Map };
}
-PropertyValue<TranslateAnchorType> SymbolLayer::getIconTranslateAnchor(const optional<std::string>& klass) const {
- return impl->cascading.template get<IconTranslateAnchor>().get(klass);
+PropertyValue<TranslateAnchorType> SymbolLayer::getIconTranslateAnchor() const {
+ return impl().paint.template get<IconTranslateAnchor>().value;
}
-void SymbolLayer::setIconTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) {
- if (value == getIconTranslateAnchor(klass))
+void SymbolLayer::setIconTranslateAnchor(PropertyValue<TranslateAnchorType> value) {
+ if (value == getIconTranslateAnchor())
return;
- impl->cascading.template get<IconTranslateAnchor>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<IconTranslateAnchor>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void SymbolLayer::setIconTranslateAnchorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<IconTranslateAnchor>().setTransition(value, klass);
+void SymbolLayer::setIconTranslateAnchorTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<IconTranslateAnchor>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions SymbolLayer::getIconTranslateAnchorTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<IconTranslateAnchor>().getTransition(klass);
+TransitionOptions SymbolLayer::getIconTranslateAnchorTransition() const {
+ return impl().paint.template get<IconTranslateAnchor>().options;
}
DataDrivenPropertyValue<float> SymbolLayer::getDefaultTextOpacity() {
return { 1 };
}
-DataDrivenPropertyValue<float> SymbolLayer::getTextOpacity(const optional<std::string>& klass) const {
- return impl->cascading.template get<TextOpacity>().get(klass);
+DataDrivenPropertyValue<float> SymbolLayer::getTextOpacity() const {
+ return impl().paint.template get<TextOpacity>().value;
}
-void SymbolLayer::setTextOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getTextOpacity(klass))
+void SymbolLayer::setTextOpacity(DataDrivenPropertyValue<float> value) {
+ if (value == getTextOpacity())
return;
- impl->cascading.template get<TextOpacity>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<TextOpacity>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void SymbolLayer::setTextOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<TextOpacity>().setTransition(value, klass);
+void SymbolLayer::setTextOpacityTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<TextOpacity>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions SymbolLayer::getTextOpacityTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<TextOpacity>().getTransition(klass);
+TransitionOptions SymbolLayer::getTextOpacityTransition() const {
+ return impl().paint.template get<TextOpacity>().options;
}
DataDrivenPropertyValue<Color> SymbolLayer::getDefaultTextColor() {
return { Color::black() };
}
-DataDrivenPropertyValue<Color> SymbolLayer::getTextColor(const optional<std::string>& klass) const {
- return impl->cascading.template get<TextColor>().get(klass);
+DataDrivenPropertyValue<Color> SymbolLayer::getTextColor() const {
+ return impl().paint.template get<TextColor>().value;
}
-void SymbolLayer::setTextColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
- if (value == getTextColor(klass))
+void SymbolLayer::setTextColor(DataDrivenPropertyValue<Color> value) {
+ if (value == getTextColor())
return;
- impl->cascading.template get<TextColor>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<TextColor>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void SymbolLayer::setTextColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<TextColor>().setTransition(value, klass);
+void SymbolLayer::setTextColorTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<TextColor>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions SymbolLayer::getTextColorTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<TextColor>().getTransition(klass);
+TransitionOptions SymbolLayer::getTextColorTransition() const {
+ return impl().paint.template get<TextColor>().options;
}
DataDrivenPropertyValue<Color> SymbolLayer::getDefaultTextHaloColor() {
return { {} };
}
-DataDrivenPropertyValue<Color> SymbolLayer::getTextHaloColor(const optional<std::string>& klass) const {
- return impl->cascading.template get<TextHaloColor>().get(klass);
+DataDrivenPropertyValue<Color> SymbolLayer::getTextHaloColor() const {
+ return impl().paint.template get<TextHaloColor>().value;
}
-void SymbolLayer::setTextHaloColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
- if (value == getTextHaloColor(klass))
+void SymbolLayer::setTextHaloColor(DataDrivenPropertyValue<Color> value) {
+ if (value == getTextHaloColor())
return;
- impl->cascading.template get<TextHaloColor>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<TextHaloColor>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void SymbolLayer::setTextHaloColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<TextHaloColor>().setTransition(value, klass);
+void SymbolLayer::setTextHaloColorTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<TextHaloColor>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions SymbolLayer::getTextHaloColorTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<TextHaloColor>().getTransition(klass);
+TransitionOptions SymbolLayer::getTextHaloColorTransition() const {
+ return impl().paint.template get<TextHaloColor>().options;
}
DataDrivenPropertyValue<float> SymbolLayer::getDefaultTextHaloWidth() {
return { 0 };
}
-DataDrivenPropertyValue<float> SymbolLayer::getTextHaloWidth(const optional<std::string>& klass) const {
- return impl->cascading.template get<TextHaloWidth>().get(klass);
+DataDrivenPropertyValue<float> SymbolLayer::getTextHaloWidth() const {
+ return impl().paint.template get<TextHaloWidth>().value;
}
-void SymbolLayer::setTextHaloWidth(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getTextHaloWidth(klass))
+void SymbolLayer::setTextHaloWidth(DataDrivenPropertyValue<float> value) {
+ if (value == getTextHaloWidth())
return;
- impl->cascading.template get<TextHaloWidth>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<TextHaloWidth>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void SymbolLayer::setTextHaloWidthTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<TextHaloWidth>().setTransition(value, klass);
+void SymbolLayer::setTextHaloWidthTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<TextHaloWidth>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions SymbolLayer::getTextHaloWidthTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<TextHaloWidth>().getTransition(klass);
+TransitionOptions SymbolLayer::getTextHaloWidthTransition() const {
+ return impl().paint.template get<TextHaloWidth>().options;
}
DataDrivenPropertyValue<float> SymbolLayer::getDefaultTextHaloBlur() {
return { 0 };
}
-DataDrivenPropertyValue<float> SymbolLayer::getTextHaloBlur(const optional<std::string>& klass) const {
- return impl->cascading.template get<TextHaloBlur>().get(klass);
+DataDrivenPropertyValue<float> SymbolLayer::getTextHaloBlur() const {
+ return impl().paint.template get<TextHaloBlur>().value;
}
-void SymbolLayer::setTextHaloBlur(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
- if (value == getTextHaloBlur(klass))
+void SymbolLayer::setTextHaloBlur(DataDrivenPropertyValue<float> value) {
+ if (value == getTextHaloBlur())
return;
- impl->cascading.template get<TextHaloBlur>().set(value, klass);
- if (value.isDataDriven()) {
- impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
- } else {
- impl->observer->onLayerPaintPropertyChanged(*this);
- }
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<TextHaloBlur>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void SymbolLayer::setTextHaloBlurTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<TextHaloBlur>().setTransition(value, klass);
+void SymbolLayer::setTextHaloBlurTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<TextHaloBlur>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions SymbolLayer::getTextHaloBlurTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<TextHaloBlur>().getTransition(klass);
+TransitionOptions SymbolLayer::getTextHaloBlurTransition() const {
+ return impl().paint.template get<TextHaloBlur>().options;
}
PropertyValue<std::array<float, 2>> SymbolLayer::getDefaultTextTranslate() {
return { {{ 0, 0 }} };
}
-PropertyValue<std::array<float, 2>> SymbolLayer::getTextTranslate(const optional<std::string>& klass) const {
- return impl->cascading.template get<TextTranslate>().get(klass);
+PropertyValue<std::array<float, 2>> SymbolLayer::getTextTranslate() const {
+ return impl().paint.template get<TextTranslate>().value;
}
-void SymbolLayer::setTextTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) {
- if (value == getTextTranslate(klass))
+void SymbolLayer::setTextTranslate(PropertyValue<std::array<float, 2>> value) {
+ if (value == getTextTranslate())
return;
- impl->cascading.template get<TextTranslate>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<TextTranslate>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void SymbolLayer::setTextTranslateTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<TextTranslate>().setTransition(value, klass);
+void SymbolLayer::setTextTranslateTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<TextTranslate>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions SymbolLayer::getTextTranslateTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<TextTranslate>().getTransition(klass);
+TransitionOptions SymbolLayer::getTextTranslateTransition() const {
+ return impl().paint.template get<TextTranslate>().options;
}
PropertyValue<TranslateAnchorType> SymbolLayer::getDefaultTextTranslateAnchor() {
return { TranslateAnchorType::Map };
}
-PropertyValue<TranslateAnchorType> SymbolLayer::getTextTranslateAnchor(const optional<std::string>& klass) const {
- return impl->cascading.template get<TextTranslateAnchor>().get(klass);
+PropertyValue<TranslateAnchorType> SymbolLayer::getTextTranslateAnchor() const {
+ return impl().paint.template get<TextTranslateAnchor>().value;
}
-void SymbolLayer::setTextTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) {
- if (value == getTextTranslateAnchor(klass))
+void SymbolLayer::setTextTranslateAnchor(PropertyValue<TranslateAnchorType> value) {
+ if (value == getTextTranslateAnchor())
return;
- impl->cascading.template get<TextTranslateAnchor>().set(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<TextTranslateAnchor>().value = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
}
-void SymbolLayer::setTextTranslateAnchorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
- impl->cascading.template get<TextTranslateAnchor>().setTransition(value, klass);
+void SymbolLayer::setTextTranslateAnchorTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->paint.template get<TextTranslateAnchor>().options = options;
+ baseImpl = std::move(impl_);
}
-TransitionOptions SymbolLayer::getTextTranslateAnchorTransition(const optional<std::string>& klass) const {
- return impl->cascading.template get<TextTranslateAnchor>().getTransition(klass);
+TransitionOptions SymbolLayer::getTextTranslateAnchorTransition() const {
+ return impl().paint.template get<TextTranslateAnchor>().options;
}
} // namespace style
diff --git a/src/mbgl/style/layers/symbol_layer_impl.cpp b/src/mbgl/style/layers/symbol_layer_impl.cpp
index c99dd8ad70..b59768725d 100644
--- a/src/mbgl/style/layers/symbol_layer_impl.cpp
+++ b/src/mbgl/style/layers/symbol_layer_impl.cpp
@@ -1,11 +1,15 @@
#include <mbgl/style/layers/symbol_layer_impl.hpp>
-#include <mbgl/renderer/render_symbol_layer.hpp>
namespace mbgl {
namespace style {
-std::unique_ptr<RenderLayer> SymbolLayer::Impl::createRenderLayer() const {
- return std::make_unique<RenderSymbolLayer>(*this);
+bool SymbolLayer::Impl::hasLayoutDifference(const Layer::Impl& other) const {
+ assert(dynamic_cast<const SymbolLayer::Impl*>(&other));
+ const auto& impl = static_cast<const style::SymbolLayer::Impl&>(other);
+ return filter != impl.filter ||
+ visibility != impl.visibility ||
+ layout != impl.layout ||
+ paint.hasDataDrivenPropertyDifference(impl.paint);
}
} // namespace style
diff --git a/src/mbgl/style/layers/symbol_layer_impl.hpp b/src/mbgl/style/layers/symbol_layer_impl.hpp
index df145647a0..f8ef87dcdf 100644
--- a/src/mbgl/style/layers/symbol_layer_impl.hpp
+++ b/src/mbgl/style/layers/symbol_layer_impl.hpp
@@ -1,24 +1,21 @@
#pragma once
-#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/style/layer_impl.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
namespace mbgl {
-
namespace style {
class SymbolLayer::Impl : public Layer::Impl {
public:
- std::unique_ptr<Layer> clone() const override;
- std::unique_ptr<Layer> cloneRef(const std::string& id) const override;
- void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override;
+ using Layer::Impl::Impl;
- std::unique_ptr<RenderLayer> createRenderLayer() const override;
+ bool hasLayoutDifference(const Layer::Impl&) const override;
+ void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override;
- SymbolLayoutProperties layout;
- SymbolPaintProperties::Cascading cascading;
+ SymbolLayoutProperties::Unevaluated layout;
+ SymbolPaintProperties::Transitionable paint;
};
} // namespace style
diff --git a/src/mbgl/style/layers/symbol_layer_properties.hpp b/src/mbgl/style/layers/symbol_layer_properties.hpp
index 5b57175785..f7ceaecdaa 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/style/properties.hpp>
#include <mbgl/programs/attributes.hpp>
#include <mbgl/programs/uniforms.hpp>
@@ -237,7 +238,7 @@ struct TextTranslateAnchor : PaintProperty<TranslateAnchorType> {
static TranslateAnchorType defaultValue() { return TranslateAnchorType::Map; }
};
-class SymbolLayoutProperties : public LayoutProperties<
+class SymbolLayoutProperties : public Properties<
SymbolPlacement,
SymbolSpacing,
SymbolAvoidEdges,
@@ -274,7 +275,7 @@ class SymbolLayoutProperties : public LayoutProperties<
TextOptional
> {};
-class SymbolPaintProperties : public PaintProperties<
+class SymbolPaintProperties : public Properties<
IconOpacity,
IconColor,
IconHaloColor,
diff --git a/src/mbgl/style/layout_property.hpp b/src/mbgl/style/layout_property.hpp
index 3b9d6114c0..8c59295ad2 100644
--- a/src/mbgl/style/layout_property.hpp
+++ b/src/mbgl/style/layout_property.hpp
@@ -4,117 +4,30 @@
#include <mbgl/style/data_driven_property_value.hpp>
#include <mbgl/renderer/property_evaluator.hpp>
#include <mbgl/renderer/data_driven_property_evaluator.hpp>
-#include <mbgl/util/indexed_tuple.hpp>
namespace mbgl {
-
-class PropertyEvaluationParameters;
-
namespace style {
template <class T>
class LayoutProperty {
public:
+ using TransitionableType = std::nullptr_t;
using UnevaluatedType = PropertyValue<T>;
using EvaluatorType = PropertyEvaluator<T>;
using PossiblyEvaluatedType = T;
using Type = T;
+ static constexpr bool IsDataDriven = false;
};
template <class T>
class DataDrivenLayoutProperty {
public:
+ using TransitionableType = std::nullptr_t;
using UnevaluatedType = DataDrivenPropertyValue<T>;
using EvaluatorType = DataDrivenPropertyEvaluator<T>;
using PossiblyEvaluatedType = PossiblyEvaluatedPropertyValue<T>;
using Type = T;
-};
-
-template <class... Ps>
-class LayoutProperties {
-public:
- using Properties = TypeList<Ps...>;
-
- template <class TypeList>
- using Tuple = IndexedTuple<Properties, TypeList>;
-
- /*
- For layout properties we implement a two step evaluation process: if you have a zoom level,
- you can evaluate a set of unevaluated property values, producing a set of possibly evaluated
- values, where undefined, constant, or camera function values have been fully evaluated, and
- source or composite function values have not.
-
- Once you also have a particular feature, you can evaluate that set of possibly evaluated values
- fully, producing a set of fully evaluated values.
-
- This is in theory maximally efficient in terms of avoiding repeated evaluation of camera
- functions, though it's more of a historical accident than a purposeful optimization.
- */
-
- using UnevaluatedTypes = TypeList<typename Ps::UnevaluatedType...>;
- using PossiblyEvaluatedTypes = TypeList<typename Ps::PossiblyEvaluatedType...>;
- using EvaluatedTypes = TypeList<typename Ps::Type...>;
-
- class Evaluated : public Tuple<EvaluatedTypes> {
- public:
- using Tuple<EvaluatedTypes>::Tuple;
- };
-
- class PossiblyEvaluated : public Tuple<PossiblyEvaluatedTypes> {
- public:
- using Tuple<PossiblyEvaluatedTypes>::Tuple;
-
- template <class T>
- static T evaluate(float, const GeometryTileFeature&, const T& t, const T&) {
- return t;
- }
-
- template <class T>
- static T evaluate(float z, const GeometryTileFeature& feature,
- const PossiblyEvaluatedPropertyValue<T>& v, const T& defaultValue) {
- return v.match(
- [&] (const T& t) {
- return t;
- },
- [&] (const SourceFunction<T>& t) {
- return t.evaluate(feature, defaultValue);
- },
- [&] (const CompositeFunction<T>& t) {
- return t.evaluate(z, feature, defaultValue);
- });
- }
-
- template <class P>
- auto evaluate(float z, const GeometryTileFeature& feature) const {
- return evaluate(z, feature, this->template get<P>(), P::defaultValue());
- }
-
- Evaluated evaluate(float z, const GeometryTileFeature& feature) const {
- return Evaluated {
- evaluate<Ps>(z, feature)...
- };
- }
- };
-
- class Unevaluated : public Tuple<UnevaluatedTypes> {
- public:
- using Tuple<UnevaluatedTypes>::Tuple;
- };
-
- template <class P>
- auto evaluate(const PropertyEvaluationParameters& parameters) const {
- using Evaluator = typename P::EvaluatorType;
- return unevaluated.template get<P>()
- .evaluate(Evaluator(parameters, P::defaultValue()));
- }
-
- PossiblyEvaluated evaluate(const PropertyEvaluationParameters& parameters) const {
- return PossiblyEvaluated {
- evaluate<Ps>(parameters)...
- };
- }
-
- Unevaluated unevaluated;
+ static constexpr bool IsDataDriven = true;
};
} // namespace style
diff --git a/src/mbgl/style/light.cpp b/src/mbgl/style/light.cpp
index b54920713c..352dc4d942 100644
--- a/src/mbgl/style/light.cpp
+++ b/src/mbgl/style/light.cpp
@@ -2,17 +2,28 @@
#include <mbgl/style/light.hpp>
#include <mbgl/style/light_impl.hpp>
-#include <mbgl/style/light_properties.hpp>
+#include <mbgl/style/light_observer.hpp>
namespace mbgl {
namespace style {
+static LightObserver nullObserver;
+
Light::Light()
- : impl(std::make_unique<Impl>()) {
+ : impl(makeMutable<Impl>()),
+ observer(&nullObserver) {
}
Light::~Light() = default;
+void Light::setObserver(LightObserver* observer_) {
+ observer = observer_ ? observer_ : &nullObserver;
+}
+
+Mutable<Light::Impl> Light::mutableImpl() const {
+ return makeMutable<Impl>(*impl);
+}
+
LightAnchorType Light::getDefaultAnchor() {
return LightAnchor::defaultValue();
}
@@ -22,17 +33,21 @@ PropertyValue<LightAnchorType> Light::getAnchor() const {
}
void Light::setAnchor(PropertyValue<LightAnchorType> property) {
- impl->properties.template get<LightAnchor>().value = property;
- impl->observer->onLightChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->properties.template get<LightAnchor>().value = property;
+ impl = std::move(impl_);
+ observer->onLightChanged(*this);
}
-void Light::setAnchorTransition(const TransitionOptions& transition) {
- impl->properties.template get<LightAnchor>().transition = transition;
- impl->observer->onLightChanged(*this);
+void Light::setAnchorTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->properties.template get<LightAnchor>().options = options;
+ impl = std::move(impl_);
+ observer->onLightChanged(*this);
}
TransitionOptions Light::getAnchorTransition() const {
- return impl->properties.template get<LightAnchor>().transition;
+ return impl->properties.template get<LightAnchor>().options;
}
Position Light::getDefaultPosition() {
@@ -44,17 +59,21 @@ PropertyValue<Position> Light::getPosition() const {
}
void Light::setPosition(PropertyValue<Position> property) {
- impl->properties.template get<LightPosition>().value = property;
- impl->observer->onLightChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->properties.template get<LightPosition>().value = property;
+ impl = std::move(impl_);
+ observer->onLightChanged(*this);
}
-void Light::setPositionTransition(const TransitionOptions& transition) {
- impl->properties.template get<LightPosition>().transition = transition;
- impl->observer->onLightChanged(*this);
+void Light::setPositionTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->properties.template get<LightPosition>().options = options;
+ impl = std::move(impl_);
+ observer->onLightChanged(*this);
}
TransitionOptions Light::getPositionTransition() const {
- return impl->properties.template get<LightPosition>().transition;
+ return impl->properties.template get<LightPosition>().options;
}
Color Light::getDefaultColor() {
@@ -66,17 +85,21 @@ PropertyValue<Color> Light::getColor() const {
}
void Light::setColor(PropertyValue<Color> property) {
- impl->properties.template get<LightColor>().value = property;
- impl->observer->onLightChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->properties.template get<LightColor>().value = property;
+ impl = std::move(impl_);
+ observer->onLightChanged(*this);
}
-void Light::setColorTransition(const TransitionOptions& transition) {
- impl->properties.template get<LightColor>().transition = transition;
- impl->observer->onLightChanged(*this);
+void Light::setColorTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->properties.template get<LightColor>().options = options;
+ impl = std::move(impl_);
+ observer->onLightChanged(*this);
}
TransitionOptions Light::getColorTransition() const {
- return impl->properties.template get<LightColor>().transition;
+ return impl->properties.template get<LightColor>().options;
}
float Light::getDefaultIntensity() {
@@ -88,17 +111,21 @@ PropertyValue<float> Light::getIntensity() const {
}
void Light::setIntensity(PropertyValue<float> property) {
- impl->properties.template get<LightIntensity>().value = property;
- impl->observer->onLightChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->properties.template get<LightIntensity>().value = property;
+ impl = std::move(impl_);
+ observer->onLightChanged(*this);
}
-void Light::setIntensityTransition(const TransitionOptions& transition) {
- impl->properties.template get<LightIntensity>().transition = transition;
- impl->observer->onLightChanged(*this);
+void Light::setIntensityTransition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->properties.template get<LightIntensity>().options = options;
+ impl = std::move(impl_);
+ observer->onLightChanged(*this);
}
TransitionOptions Light::getIntensityTransition() const {
- return impl->properties.template get<LightIntensity>().transition;
+ return impl->properties.template get<LightIntensity>().options;
}
diff --git a/src/mbgl/style/light.cpp.ejs b/src/mbgl/style/light.cpp.ejs
index c82c65c10c..45241c60fd 100644
--- a/src/mbgl/style/light.cpp.ejs
+++ b/src/mbgl/style/light.cpp.ejs
@@ -5,17 +5,28 @@
#include <mbgl/style/light.hpp>
#include <mbgl/style/light_impl.hpp>
-#include <mbgl/style/light_properties.hpp>
+#include <mbgl/style/light_observer.hpp>
namespace mbgl {
namespace style {
+static LightObserver nullObserver;
+
Light::Light()
- : impl(std::make_unique<Impl>()) {
+ : impl(makeMutable<Impl>()),
+ observer(&nullObserver) {
}
Light::~Light() = default;
+void Light::setObserver(LightObserver* observer_) {
+ observer = observer_ ? observer_ : &nullObserver;
+}
+
+Mutable<Light::Impl> Light::mutableImpl() const {
+ return makeMutable<Impl>(*impl);
+}
+
<% for (const property of properties) { -%>
<%- evaluatedType(property) %> Light::getDefault<%- camelize(property.name) %>() {
return Light<%- camelize(property.name) %>::defaultValue();
@@ -26,17 +37,21 @@ Light::~Light() = default;
}
void Light::set<%- camelize(property.name) %>(<%- propertyValueType(property) %> property) {
- impl->properties.template get<Light<%- camelize(property.name) %>>().value = property;
- impl->observer->onLightChanged(*this);
+ auto impl_ = mutableImpl();
+ impl_->properties.template get<Light<%- camelize(property.name) %>>().value = property;
+ impl = std::move(impl_);
+ observer->onLightChanged(*this);
}
-void Light::set<%- camelize(property.name) %>Transition(const TransitionOptions& transition) {
- impl->properties.template get<Light<%- camelize(property.name) %>>().transition = transition;
- impl->observer->onLightChanged(*this);
+void Light::set<%- camelize(property.name) %>Transition(const TransitionOptions& options) {
+ auto impl_ = mutableImpl();
+ impl_->properties.template get<Light<%- camelize(property.name) %>>().options = options;
+ impl = std::move(impl_);
+ observer->onLightChanged(*this);
}
TransitionOptions Light::get<%- camelize(property.name) %>Transition() const {
- return impl->properties.template get<Light<%- camelize(property.name) %>>().transition;
+ return impl->properties.template get<Light<%- camelize(property.name) %>>().options;
}
<% } -%>
diff --git a/src/mbgl/style/light_impl.cpp b/src/mbgl/style/light_impl.cpp
index e0ab1176ed..619d115f02 100644
--- a/src/mbgl/style/light_impl.cpp
+++ b/src/mbgl/style/light_impl.cpp
@@ -3,9 +3,5 @@
namespace mbgl {
namespace style {
-void Light::Impl::setObserver(LightObserver* observer_) {
- observer = observer_;
-}
-
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/light_impl.hpp b/src/mbgl/style/light_impl.hpp
index b4fd886742..f094c9d462 100644
--- a/src/mbgl/style/light_impl.hpp
+++ b/src/mbgl/style/light_impl.hpp
@@ -1,19 +1,58 @@
#pragma once
-#include <mbgl/style/light_properties.hpp>
-#include <mbgl/style/light_observer.hpp>
+#include <mbgl/style/light.hpp>
+#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/types.hpp>
+#include <mbgl/style/position.hpp>
+#include <mbgl/style/properties.hpp>
+#include <mbgl/renderer/property_evaluator.hpp>
+#include <mbgl/util/color.hpp>
+#include <mbgl/util/indexed_tuple.hpp>
namespace mbgl {
namespace style {
-class Light::Impl {
+template <class T>
+class LightProperty {
public:
+ using TransitionableType = Transitionable<PropertyValue<T>>;
+ using UnevaluatedType = Transitioning<PropertyValue<T>>;
+ using EvaluatorType = PropertyEvaluator<T>;
+ using PossiblyEvaluatedType = T;
+ using Type = T;
+ static constexpr bool IsDataDriven = false;
+};
+
+struct LightAnchor : LightProperty<LightAnchorType> {
+ static LightAnchorType defaultValue() {
+ return LightAnchorType::Viewport;
+ }
+};
+
+struct LightPosition : LightProperty<Position> {
+ static Position defaultValue() {
+ std::array<float, 3> default_ = { { 1.15, 210, 30 } };
+ return Position{ { default_ } };
+ }
+};
- LightObserver nullObserver;
- LightObserver* observer = &nullObserver;
- void setObserver(LightObserver*);
+struct LightColor : LightProperty<Color> {
+ static Color defaultValue() {
+ return Color::white();
+ }
+};
+
+struct LightIntensity : LightProperty<float> {
+ static float defaultValue() {
+ return 0.5;
+ }
+};
- IndexedTuple<LightProperties, LightProperties> properties;
+using LightProperties = Properties<LightAnchor, LightPosition, LightColor, LightIntensity>;
+
+class Light::Impl {
+public:
+ LightProperties::Transitionable properties;
};
} // namespace style
diff --git a/src/mbgl/style/light_observer.hpp b/src/mbgl/style/light_observer.hpp
index 751a84850d..45beb64928 100644
--- a/src/mbgl/style/light_observer.hpp
+++ b/src/mbgl/style/light_observer.hpp
@@ -1,10 +1,10 @@
#pragma once
-#include <mbgl/style/light.hpp>
-
namespace mbgl {
namespace style {
+class Light;
+
class LightObserver {
public:
virtual ~LightObserver() = default;
diff --git a/src/mbgl/style/light_properties.hpp b/src/mbgl/style/light_properties.hpp
deleted file mode 100644
index 9f6088a633..0000000000
--- a/src/mbgl/style/light_properties.hpp
+++ /dev/null
@@ -1,51 +0,0 @@
-#pragma once
-
-#include <mbgl/style/property_value.hpp>
-#include <mbgl/style/transition_options.hpp>
-#include <mbgl/style/types.hpp>
-#include <mbgl/style/position.hpp>
-#include <mbgl/util/color.hpp>
-#include <mbgl/util/indexed_tuple.hpp>
-
-namespace mbgl {
-namespace style {
-
-template <class T>
-class LightProperty {
-public:
- using Type = T;
- using ValueType = PropertyValue<T>;
-
- PropertyValue<T> value;
- TransitionOptions transition;
-};
-
-struct LightAnchor : LightProperty<LightAnchorType> {
- static LightAnchorType defaultValue() {
- return LightAnchorType::Viewport;
- }
-};
-
-struct LightPosition : LightProperty<Position> {
- static Position defaultValue() {
- std::array<float, 3> default_ = { { 1.15, 210, 30 } };
- return Position{ { default_ } };
- }
-};
-
-struct LightColor : LightProperty<Color> {
- static Color defaultValue() {
- return Color::white();
- }
-};
-
-struct LightIntensity : LightProperty<float> {
- static float defaultValue() {
- return 0.5;
- }
-};
-
-using LightProperties = TypeList<LightAnchor, LightPosition, LightColor, LightIntensity>;
-
-} // namespace style
-} // namespace mbgl
diff --git a/src/mbgl/style/observer.hpp b/src/mbgl/style/observer.hpp
index 60432334e2..ea19c599e9 100644
--- a/src/mbgl/style/observer.hpp
+++ b/src/mbgl/style/observer.hpp
@@ -1,7 +1,5 @@
#pragma once
-#include <mbgl/text/glyph_atlas_observer.hpp>
-#include <mbgl/sprite/sprite_atlas_observer.hpp>
#include <mbgl/style/source_observer.hpp>
#include <mbgl/map/update.hpp>
@@ -10,13 +8,12 @@
namespace mbgl {
namespace style {
-class Observer : public GlyphAtlasObserver,
- public SpriteAtlasObserver,
- public SourceObserver {
+class Observer : public SourceObserver {
public:
+ virtual void onStyleLoading() {}
+ virtual void onStyleLoaded() {}
virtual void onUpdate(Update) {}
virtual void onStyleError(std::exception_ptr) {}
- virtual void onStyleLoaded() {}
virtual void onResourceError(std::exception_ptr) {}
};
diff --git a/src/mbgl/style/paint_property.hpp b/src/mbgl/style/paint_property.hpp
index c203083c49..c4c996b3bd 100644
--- a/src/mbgl/style/paint_property.hpp
+++ b/src/mbgl/style/paint_property.hpp
@@ -1,108 +1,38 @@
#pragma once
-#include <mbgl/style/class_dictionary.hpp>
+#include <mbgl/style/properties.hpp>
#include <mbgl/style/property_value.hpp>
#include <mbgl/style/data_driven_property_value.hpp>
-#include <mbgl/style/transition_options.hpp>
#include <mbgl/renderer/property_evaluator.hpp>
#include <mbgl/renderer/cross_faded_property_evaluator.hpp>
#include <mbgl/renderer/data_driven_property_evaluator.hpp>
-#include <mbgl/renderer/property_evaluation_parameters.hpp>
-#include <mbgl/renderer/cascade_parameters.hpp>
-#include <mbgl/renderer/transitioning_property.hpp>
-#include <mbgl/renderer/paint_property_binder.hpp>
-#include <mbgl/util/constants.hpp>
-#include <mbgl/util/interpolate.hpp>
-#include <mbgl/util/indexed_tuple.hpp>
-#include <mbgl/util/ignore.hpp>
#include <utility>
namespace mbgl {
-
-class GeometryTileFeature;
-
namespace style {
-template <class Value>
-class CascadingPaintProperty {
-public:
- bool isUndefined() const {
- return values.find(ClassID::Default) == values.end();
- }
-
- 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 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;
- }
-
- template <class TransitioningProperty>
- TransitioningProperty cascade(const CascadeParameters& params, TransitioningProperty prior) const {
- TransitionOptions transition;
- Value value;
-
- for (const auto classID : params.classes) {
- if (values.find(classID) != values.end()) {
- value = values.at(classID);
- break;
- }
- }
-
- for (const auto classID : params.classes) {
- if (transitions.find(classID) != transitions.end()) {
- transition = transitions.at(classID).reverseMerge(transition);
- break;
- }
- }
-
- return TransitioningProperty(std::move(value),
- std::move(prior),
- transition.reverseMerge(params.transition),
- params.now);
- }
-
-private:
- std::map<ClassID, Value> values;
- std::map<ClassID, TransitionOptions> transitions;
-};
-
template <class T>
class PaintProperty {
public:
- using ValueType = PropertyValue<T>;
- using CascadingType = CascadingPaintProperty<ValueType>;
- using UnevaluatedType = TransitioningProperty<ValueType>;
+ using TransitionableType = Transitionable<PropertyValue<T>>;
+ using UnevaluatedType = Transitioning<PropertyValue<T>>;
using EvaluatorType = PropertyEvaluator<T>;
- using EvaluatedType = T;
+ using PossiblyEvaluatedType = T;
+ using Type = T;
static constexpr bool IsDataDriven = false;
};
template <class T, class A, class U>
class DataDrivenPaintProperty {
public:
- using ValueType = DataDrivenPropertyValue<T>;
- using CascadingType = CascadingPaintProperty<ValueType>;
- using UnevaluatedType = TransitioningProperty<ValueType>;
+ using TransitionableType = Transitionable<DataDrivenPropertyValue<T>>;
+ using UnevaluatedType = Transitioning<DataDrivenPropertyValue<T>>;
using EvaluatorType = DataDrivenPropertyEvaluator<T>;
- using EvaluatedType = PossiblyEvaluatedPropertyValue<T>;
+ using PossiblyEvaluatedType = PossiblyEvaluatedPropertyValue<T>;
+ using Type = T;
static constexpr bool IsDataDriven = true;
- using Type = T;
using Attribute = A;
using Uniform = U;
};
@@ -110,78 +40,13 @@ public:
template <class T>
class CrossFadedPaintProperty {
public:
- using ValueType = PropertyValue<T>;
- using CascadingType = CascadingPaintProperty<ValueType>;
- using UnevaluatedType = TransitioningProperty<ValueType>;
+ using TransitionableType = Transitionable<PropertyValue<T>>;
+ using UnevaluatedType = Transitioning<PropertyValue<T>>;
using EvaluatorType = CrossFadedPropertyEvaluator<T>;
- using EvaluatedType = Faded<T>;
+ using PossiblyEvaluatedType = Faded<T>;
+ using Type = 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...>;
-
- template <class TypeList>
- using Tuple = IndexedTuple<Properties, TypeList>;
-
- class Evaluated : public Tuple<EvaluatedTypes> {
- public:
- using Tuple<EvaluatedTypes>::Tuple;
- };
-
- class Unevaluated : public Tuple<UnevaluatedTypes> {
- public:
- using Tuple<UnevaluatedTypes>::Tuple;
-
- bool hasTransition() const {
- bool result = false;
- util::ignore({ result |= this->template get<Ps>().hasTransition()... });
- return result;
- }
-
- template <class P>
- auto evaluate(const PropertyEvaluationParameters& parameters) {
- using Evaluator = typename P::EvaluatorType;
-
- return this->template get<P>().evaluate(
- Evaluator(parameters, P::defaultValue()),
- parameters.now
- );
- }
-
- Evaluated evaluate(const PropertyEvaluationParameters& parameters) {
- return Evaluated {
- evaluate<Ps>(parameters)...
- };
- }
-
- };
-
- class Cascading : public Tuple<CascadingTypes> {
- public:
- using Tuple<CascadingTypes>::Tuple;
-
- Unevaluated cascade(const CascadeParameters& parameters, Unevaluated&& prior) const {
- return Unevaluated {
- this->template get<Ps>().cascade(
- parameters,
- std::move(prior.template get<Ps>())
- )...
- };
- }
- };
-};
-
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/parser.cpp b/src/mbgl/style/parser.cpp
index fc3ccf410b..467b44632c 100644
--- a/src/mbgl/style/parser.cpp
+++ b/src/mbgl/style/parser.cpp
@@ -2,6 +2,7 @@
#include <mbgl/style/layer_impl.hpp>
#include <mbgl/style/rapidjson_conversion.hpp>
#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/conversion/coordinate.hpp>
#include <mbgl/style/conversion/source.hpp>
#include <mbgl/style/conversion/layer.hpp>
#include <mbgl/style/conversion/light.hpp>
@@ -55,10 +56,12 @@ StyleParseResult Parser::parse(const std::string& json) {
if (document.HasMember("center")) {
const JSValue& value = document["center"];
- if (value.IsArray() && value.Size() >= 2) {
- // Style spec uses lon/lat order
- latLng = LatLng(value[1].IsNumber() ? value[1].GetDouble() : 0,
- value[0].IsNumber() ? value[0].GetDouble() : 0);
+ conversion::Error error;
+ auto convertedLatLng = conversion::convert<LatLng>(value, error);
+ if (convertedLatLng) {
+ latLng = *convertedLatLng;
+ } else {
+ Log::Warning(Event::ParseStyle, "center coordinate must be a longitude, latitude pair");
}
}
@@ -83,6 +86,10 @@ StyleParseResult Parser::parse(const std::string& json) {
}
}
+ if (document.HasMember("transition")) {
+ parseTransition(document["transition"]);
+ }
+
if (document.HasMember("light")) {
parseLight(document["light"]);
}
@@ -112,6 +119,17 @@ StyleParseResult Parser::parse(const std::string& json) {
return nullptr;
}
+void Parser::parseTransition(const JSValue& value) {
+ conversion::Error error;
+ optional<TransitionOptions> converted = conversion::convert<TransitionOptions>(value, error);
+ if (!converted) {
+ Log::Warning(Event::ParseStyle, error.message);
+ return;
+ }
+
+ transition = std::move(*converted);
+}
+
void Parser::parseLight(const JSValue& value) {
conversion::Error error;
optional<Light> converted = conversion::convert<Light>(value, error);
@@ -236,7 +254,7 @@ void Parser::parseLayer(const std::string& id, const JSValue& value, std::unique
return;
}
- layer = reference->baseImpl->cloneRef(id);
+ layer = reference->cloneRef(id);
conversion::setPaintProperties(*layer, value);
} else {
conversion::Error error;
diff --git a/src/mbgl/style/parser.hpp b/src/mbgl/style/parser.hpp
index 32b8a7a8bc..401b5ff513 100644
--- a/src/mbgl/style/parser.hpp
+++ b/src/mbgl/style/parser.hpp
@@ -32,6 +32,7 @@ public:
std::vector<std::unique_ptr<Source>> sources;
std::vector<std::unique_ptr<Layer>> layers;
+ TransitionOptions transition;
Light light;
std::string name;
@@ -44,6 +45,7 @@ public:
std::vector<FontStack> fontStacks() const;
private:
+ void parseTransition(const JSValue&);
void parseLight(const JSValue&);
void parseSources(const JSValue&);
void parseLayers(const JSValue&);
diff --git a/src/mbgl/style/properties.hpp b/src/mbgl/style/properties.hpp
new file mode 100644
index 0000000000..dfcf7993a7
--- /dev/null
+++ b/src/mbgl/style/properties.hpp
@@ -0,0 +1,248 @@
+#pragma once
+
+#include <mbgl/style/transition_options.hpp>
+#include <mbgl/style/conversion/stringify.hpp>
+#include <mbgl/renderer/transition_parameters.hpp>
+#include <mbgl/renderer/paint_property_binder.hpp>
+#include <mbgl/renderer/property_evaluation_parameters.hpp>
+#include <mbgl/renderer/transition_parameters.hpp>
+#include <mbgl/util/indexed_tuple.hpp>
+#include <mbgl/util/ignore.hpp>
+
+namespace mbgl {
+
+class GeometryTileFeature;
+
+namespace style {
+
+template <class Value>
+class Transitioning {
+public:
+ Transitioning() = default;
+
+ explicit Transitioning(Value value_)
+ : value(std::move(value_)) {
+ }
+
+ Transitioning(Value value_,
+ Transitioning<Value> prior_,
+ TransitionOptions transition,
+ TimePoint now)
+ : begin(now + transition.delay.value_or(Duration::zero())),
+ end(begin + transition.duration.value_or(Duration::zero())),
+ value(std::move(value_)) {
+ if (transition.isDefined()) {
+ prior = { std::move(prior_) };
+ }
+ }
+
+ template <class Evaluator>
+ auto evaluate(const Evaluator& evaluator, TimePoint now) const {
+ auto finalValue = value.evaluate(evaluator);
+ if (!prior) {
+ // No prior value.
+ return finalValue;
+ } else if (now >= end) {
+ // Transition from prior value is now complete.
+ prior = {};
+ return finalValue;
+ } else if (value.isDataDriven()) {
+ // Transitions to data-driven properties are not supported.
+ // We snap immediately to the data-driven value so that, when we perform layout,
+ // we see the data-driven function and can use it to populate vertex buffers.
+ prior = {};
+ return finalValue;
+ } else if (now < begin) {
+ // Transition hasn't started yet.
+ return prior->get().evaluate(evaluator, now);
+ } else {
+ // Interpolate between recursively-calculated prior value and final.
+ 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));
+ }
+ }
+
+ bool hasTransition() const {
+ return bool(prior);
+ }
+
+ bool isUndefined() const {
+ return value.isUndefined();
+ }
+
+ const Value& getValue() const {
+ return value;
+ }
+
+private:
+ mutable optional<mapbox::util::recursive_wrapper<Transitioning<Value>>> prior;
+ TimePoint begin;
+ TimePoint end;
+ Value value;
+};
+
+template <class Value>
+class Transitionable {
+public:
+ Value value;
+ TransitionOptions options;
+
+ Transitioning<Value> transition(const TransitionParameters& params, Transitioning<Value> prior) const {
+ return Transitioning<Value>(value,
+ std::move(prior),
+ options.reverseMerge(params.transition),
+ params.now);
+ }
+};
+
+template <class P>
+struct IsDataDriven : std::integral_constant<bool, P::IsDataDriven> {};
+
+template <class... Ps>
+class Properties {
+public:
+ /*
+ For style properties we implement a two step evaluation process: if you have a zoom level,
+ you can evaluate a set of unevaluated property values, producing a set of possibly evaluated
+ values, where undefined, constant, or camera function values have been fully evaluated, and
+ source or composite function values have not.
+
+ Once you also have a particular feature, you can evaluate that set of possibly evaluated values
+ fully, producing a set of fully evaluated values.
+
+ This is in theory maximally efficient in terms of avoiding repeated evaluation of camera
+ functions, though it's more of a historical accident than a purposeful optimization.
+ */
+
+ using PropertyTypes = TypeList<Ps...>;
+ using TransitionableTypes = TypeList<typename Ps::TransitionableType...>;
+ using UnevaluatedTypes = TypeList<typename Ps::UnevaluatedType...>;
+ using PossiblyEvaluatedTypes = TypeList<typename Ps::PossiblyEvaluatedType...>;
+ using EvaluatedTypes = TypeList<typename Ps::Type...>;
+
+ using DataDrivenProperties = FilteredTypeList<PropertyTypes, IsDataDriven>;
+ using Binders = PaintPropertyBinders<DataDrivenProperties>;
+
+ template <class TypeList>
+ using Tuple = IndexedTuple<PropertyTypes, TypeList>;
+
+ class Evaluated : public Tuple<EvaluatedTypes> {
+ public:
+ template <class... Us>
+ Evaluated(Us&&... us)
+ : Tuple<EvaluatedTypes>(std::forward<Us>(us)...) {
+ }
+ };
+
+ class PossiblyEvaluated : public Tuple<PossiblyEvaluatedTypes> {
+ public:
+ template <class... Us>
+ PossiblyEvaluated(Us&&... us)
+ : Tuple<PossiblyEvaluatedTypes>(std::forward<Us>(us)...) {
+ }
+
+ template <class T>
+ static T evaluate(float, const GeometryTileFeature&, const T& t, const T&) {
+ return t;
+ }
+
+ template <class T>
+ static T evaluate(float z, const GeometryTileFeature& feature,
+ const PossiblyEvaluatedPropertyValue<T>& v, const T& defaultValue) {
+ return v.match(
+ [&] (const T& t) {
+ return t;
+ },
+ [&] (const SourceFunction<T>& t) {
+ return t.evaluate(feature, defaultValue);
+ },
+ [&] (const CompositeFunction<T>& t) {
+ return t.evaluate(z, feature, defaultValue);
+ });
+ }
+
+ template <class P>
+ auto evaluate(float z, const GeometryTileFeature& feature) const {
+ return evaluate(z, feature, this->template get<P>(), P::defaultValue());
+ }
+
+ Evaluated evaluate(float z, const GeometryTileFeature& feature) const {
+ return Evaluated {
+ evaluate<Ps>(z, feature)...
+ };
+ }
+ };
+
+ class Unevaluated : public Tuple<UnevaluatedTypes> {
+ public:
+ template <class... Us>
+ Unevaluated(Us&&... us)
+ : Tuple<UnevaluatedTypes>(std::forward<Us>(us)...) {
+ }
+
+ bool hasTransition() const {
+ bool result = false;
+ util::ignore({ result |= this->template get<Ps>().hasTransition()... });
+ return result;
+ }
+
+ template <class P>
+ auto evaluate(const PropertyEvaluationParameters& parameters) const {
+ using Evaluator = typename P::EvaluatorType;
+ return this->template get<P>()
+ .evaluate(Evaluator(parameters, P::defaultValue()), parameters.now);
+ }
+
+ PossiblyEvaluated evaluate(const PropertyEvaluationParameters& parameters) const {
+ return PossiblyEvaluated {
+ evaluate<Ps>(parameters)...
+ };
+ }
+
+ template <class Writer>
+ void stringify(Writer& writer) const {
+ writer.StartObject();
+ util::ignore({ (conversion::stringify<Ps>(writer, this->template get<Ps>()), 0)... });
+ writer.EndObject();
+ }
+ };
+
+ class Transitionable : public Tuple<TransitionableTypes> {
+ public:
+ template <class... Us>
+ Transitionable(Us&&... us)
+ : Tuple<TransitionableTypes>(std::forward<Us>(us)...) {
+ }
+
+ Unevaluated transitioned(const TransitionParameters& parameters, Unevaluated&& prior) const {
+ return Unevaluated {
+ this->template get<Ps>()
+ .transition(parameters, std::move(prior.template get<Ps>()))...
+ };
+ }
+
+ Unevaluated untransitioned() const {
+ return Unevaluated {
+ typename Ps::UnevaluatedType(this->template get<Ps>().value)...
+ };
+ }
+
+ bool hasDataDrivenPropertyDifference(const Transitionable& other) const {
+ bool result = false;
+ util::ignore({ (result |= this->template get<Ps>().value.hasDataDrivenPropertyDifference(other.template get<Ps>().value))... });
+ return result;
+ }
+ };
+};
+
+template <class...>
+struct ConcatenateProperties;
+
+template <class... As, class... Bs>
+struct ConcatenateProperties<TypeList<As...>, TypeList<Bs...>> {
+ using Type = Properties<As..., Bs...>;
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/rapidjson_conversion.hpp b/src/mbgl/style/rapidjson_conversion.hpp
index 101fe67ec0..48a764ccb4 100644
--- a/src/mbgl/style/rapidjson_conversion.hpp
+++ b/src/mbgl/style/rapidjson_conversion.hpp
@@ -62,6 +62,13 @@ inline optional<float> toNumber(const JSValue& value) {
return value.GetDouble();
}
+inline optional<double> toDouble(const JSValue& value) {
+ if (!value.IsNumber()) {
+ return {};
+ }
+ return value.GetDouble();
+}
+
inline optional<std::string> toString(const JSValue& value) {
if (!value.IsString()) {
return {};
diff --git a/src/mbgl/style/source.cpp b/src/mbgl/style/source.cpp
index cfb268006b..e7701b8bec 100644
--- a/src/mbgl/style/source.cpp
+++ b/src/mbgl/style/source.cpp
@@ -1,16 +1,25 @@
#include <mbgl/style/source.hpp>
#include <mbgl/style/source_impl.hpp>
+#include <mbgl/style/source_observer.hpp>
+#include <mbgl/util/logging.hpp>
namespace mbgl {
namespace style {
-Source::Source(SourceType type_, std::unique_ptr<Impl> baseImpl_)
- : baseImpl(std::move(baseImpl_)), type(type_) {
+static SourceObserver nullObserver;
+
+Source::Source(Immutable<Impl> impl)
+ : baseImpl(std::move(impl)),
+ observer(&nullObserver) {
}
Source::~Source() = default;
-const std::string& Source::getID() const {
+SourceType Source::getType() const {
+ return baseImpl->type;
+}
+
+std::string Source::getID() const {
return baseImpl->id;
}
@@ -18,5 +27,14 @@ optional<std::string> Source::getAttribution() const {
return baseImpl->getAttribution();
}
+void Source::setObserver(SourceObserver* observer_) {
+ observer = observer_ ? observer_ : &nullObserver;
+}
+
+void Source::dumpDebugLogs() const {
+ Log::Info(Event::General, "Source::id: %s", getID().c_str());
+ Log::Info(Event::General, "Source::loaded: %d", loaded);
+}
+
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/source_impl.cpp b/src/mbgl/style/source_impl.cpp
index 1e9405abbb..0683f847cb 100644
--- a/src/mbgl/style/source_impl.cpp
+++ b/src/mbgl/style/source_impl.cpp
@@ -1,26 +1,11 @@
#include <mbgl/style/source_impl.hpp>
-#include <mbgl/style/source_observer.hpp>
-#include <mbgl/util/logging.hpp>
namespace mbgl {
namespace style {
-static SourceObserver nullObserver;
-
-Source::Impl::Impl(SourceType type_, std::string id_, Source& base_)
+Source::Impl::Impl(SourceType type_, std::string id_)
: type(type_),
- id(std::move(id_)),
- base(base_),
- observer(&nullObserver) {
-}
-
-void Source::Impl::dumpDebugLogs() const {
- Log::Info(Event::General, "Source::id: %s", base.getID().c_str());
- Log::Info(Event::General, "Source::loaded: %d", loaded);
-}
-
-void Source::Impl::setObserver(SourceObserver* observer_) {
- observer = observer_ ? observer_ : &nullObserver;
+ id(std::move(id_)) {
}
} // namespace style
diff --git a/src/mbgl/style/source_impl.hpp b/src/mbgl/style/source_impl.hpp
index 2514ec5120..42da97345a 100644
--- a/src/mbgl/style/source_impl.hpp
+++ b/src/mbgl/style/source_impl.hpp
@@ -3,35 +3,30 @@
#include <mbgl/style/source.hpp>
#include <mbgl/util/noncopyable.hpp>
+#include <string>
+
namespace mbgl {
-class FileSource;
class RenderSource;
namespace style {
class SourceObserver;
-class Source::Impl : private util::noncopyable {
+class Source::Impl {
public:
- Impl(SourceType, std::string id, Source&);
virtual ~Impl() = default;
- virtual void loadDescription(FileSource&) = 0;
- virtual std::unique_ptr<RenderSource> createRenderSource() const = 0;
+ Impl& operator=(const Impl&) = delete;
- virtual optional<std::string> getAttribution() const { return {}; };
+ virtual optional<std::string> getAttribution() const = 0;
const SourceType type;
const std::string id;
- bool loaded = false;
- Source& base;
-
- void setObserver(SourceObserver*);
- SourceObserver* observer = nullptr;
-
- void dumpDebugLogs() const;
+protected:
+ Impl(SourceType, std::string);
+ Impl(const Impl&) = default;
};
} // namespace style
diff --git a/src/mbgl/style/sources/geojson_source.cpp b/src/mbgl/style/sources/geojson_source.cpp
index 992f82b1e7..4e3478322d 100644
--- a/src/mbgl/style/sources/geojson_source.cpp
+++ b/src/mbgl/style/sources/geojson_source.cpp
@@ -1,27 +1,81 @@
#include <mbgl/style/sources/geojson_source.hpp>
#include <mbgl/style/sources/geojson_source_impl.hpp>
#include <mbgl/style/source_observer.hpp>
+#include <mbgl/style/conversion/json.hpp>
+#include <mbgl/style/conversion/geojson.hpp>
+#include <mbgl/storage/file_source.hpp>
+#include <mbgl/util/logging.hpp>
namespace mbgl {
namespace style {
GeoJSONSource::GeoJSONSource(const std::string& id, const GeoJSONOptions& options)
- : Source(SourceType::GeoJSON,
- std::make_unique<GeoJSONSource::Impl>(std::move(id), *this, options)),
- impl(static_cast<Impl*>(baseImpl.get())) {
+ : Source(makeMutable<Impl>(std::move(id), options)) {
}
-void GeoJSONSource::setURL(const std::string& url) {
- impl->setURL(url);
+GeoJSONSource::~GeoJSONSource() = default;
+
+const GeoJSONSource::Impl& GeoJSONSource::impl() const {
+ return static_cast<const Impl&>(*baseImpl);
+}
+
+void GeoJSONSource::setURL(const std::string& url_) {
+ url = std::move(url_);
+
+ // Signal that the source description needs a reload
+ if (loaded || req) {
+ loaded = false;
+ req.reset();
+ observer->onSourceDescriptionChanged(*this);
+ }
}
void GeoJSONSource::setGeoJSON(const mapbox::geojson::geojson& geoJSON) {
- impl->setGeoJSON(geoJSON);
- impl->observer->onSourceChanged(*this);
+ req.reset();
+ baseImpl = makeMutable<Impl>(impl(), geoJSON);
+ observer->onSourceChanged(*this);
}
optional<std::string> GeoJSONSource::getURL() const {
- return impl->getURL();
+ return url;
+}
+
+void GeoJSONSource::loadDescription(FileSource& fileSource) {
+ if (!url) {
+ loaded = true;
+ return;
+ }
+
+ if (req) {
+ return;
+ }
+
+ req = fileSource.request(Resource::source(*url), [this](Response res) {
+ if (res.error) {
+ observer->onSourceError(
+ *this, std::make_exception_ptr(std::runtime_error(res.error->message)));
+ } else if (res.notModified) {
+ return;
+ } else if (res.noContent) {
+ observer->onSourceError(
+ *this, std::make_exception_ptr(std::runtime_error("unexpectedly empty GeoJSON")));
+ } else {
+ conversion::Error error;
+ optional<GeoJSON> geoJSON = conversion::convertJSON<GeoJSON>(*res.data, error);
+ if (!geoJSON) {
+ Log::Error(Event::ParseStyle, "Failed to parse GeoJSON data: %s",
+ error.message.c_str());
+ // Create an empty GeoJSON VT object to make sure we're not infinitely waiting for
+ // tiles to load.
+ baseImpl = makeMutable<Impl>(impl(), GeoJSON{ FeatureCollection{} });
+ } else {
+ baseImpl = makeMutable<Impl>(impl(), *geoJSON);
+ }
+
+ loaded = true;
+ observer->onSourceLoaded(*this);
+ }
+ });
}
} // namespace style
diff --git a/src/mbgl/style/sources/geojson_source_impl.cpp b/src/mbgl/style/sources/geojson_source_impl.cpp
index 1a686ff9bc..be347af2ab 100644
--- a/src/mbgl/style/sources/geojson_source_impl.cpp
+++ b/src/mbgl/style/sources/geojson_source_impl.cpp
@@ -1,12 +1,6 @@
#include <mbgl/style/sources/geojson_source_impl.hpp>
-#include <mbgl/style/conversion/json.hpp>
-#include <mbgl/style/conversion/geojson.hpp>
-#include <mbgl/style/source_observer.hpp>
+#include <mbgl/util/constants.hpp>
#include <mbgl/tile/tile_id.hpp>
-#include <mbgl/storage/file_source.hpp>
-#include <mbgl/renderer/sources/render_geojson_source.hpp>
-#include <mbgl/util/constants.cpp>
-#include <mbgl/util/logging.hpp>
#include <mapbox/geojsonvt.hpp>
#include <supercluster.hpp>
@@ -42,33 +36,14 @@ private:
mapbox::supercluster::Supercluster impl;
};
-GeoJSONSource::Impl::Impl(std::string id_, Source& base_, const GeoJSONOptions options_)
- : Source::Impl(SourceType::GeoJSON, std::move(id_), base_), options(options_) {
+GeoJSONSource::Impl::Impl(std::string id_, GeoJSONOptions options_)
+ : Source::Impl(SourceType::GeoJSON, std::move(id_)),
+ options(std::move(options_)) {
}
-GeoJSONSource::Impl::~Impl() = default;
-
-void GeoJSONSource::Impl::setURL(std::string url_) {
- url = std::move(url_);
-
- // Signal that the source description needs a reload
- if (loaded || req) {
- loaded = false;
- req.reset();
- observer->onSourceDescriptionChanged(base);
- }
-}
-
-optional<std::string> GeoJSONSource::Impl::getURL() const {
- return url;
-}
-
-void GeoJSONSource::Impl::setGeoJSON(const GeoJSON& geoJSON) {
- req.reset();
- _setGeoJSON(geoJSON);
-}
-
-void GeoJSONSource::Impl::_setGeoJSON(const GeoJSON& geoJSON) {
+GeoJSONSource::Impl::Impl(const Impl& other, const GeoJSON& geoJSON)
+ : Source::Impl(other),
+ options(other.options) {
double scale = util::EXTENT / util::tileSize;
if (options.cluster
@@ -90,47 +65,7 @@ void GeoJSONSource::Impl::_setGeoJSON(const GeoJSON& geoJSON) {
}
}
-void GeoJSONSource::Impl::loadDescription(FileSource& fileSource) {
- if (!url) {
- loaded = true;
- return;
- }
-
- if (req) {
- return;
- }
-
- req = fileSource.request(Resource::source(*url), [this](Response res) {
- if (res.error) {
- observer->onSourceError(
- base, std::make_exception_ptr(std::runtime_error(res.error->message)));
- } else if (res.notModified) {
- return;
- } else if (res.noContent) {
- observer->onSourceError(
- base, std::make_exception_ptr(std::runtime_error("unexpectedly empty GeoJSON")));
- } else {
- conversion::Error error;
- optional<GeoJSON> geoJSON = conversion::convertJSON<GeoJSON>(*res.data, error);
- if (!geoJSON) {
- Log::Error(Event::ParseStyle, "Failed to parse GeoJSON data: %s",
- error.message.c_str());
- // Create an empty GeoJSON VT object to make sure we're not infinitely waiting for
- // tiles to load.
- _setGeoJSON(GeoJSON{ FeatureCollection{} });
- } else {
- _setGeoJSON(*geoJSON);
- }
-
- loaded = true;
- observer->onSourceLoaded(base);
- }
- });
-}
-
-std::unique_ptr<RenderSource> GeoJSONSource::Impl::createRenderSource() const {
- return std::make_unique<RenderGeoJSONSource>(*this);
-}
+GeoJSONSource::Impl::~Impl() = default;
Range<uint8_t> GeoJSONSource::Impl::getZoomRange() const {
return { 0, options.maxzoom };
@@ -140,5 +75,9 @@ GeoJSONData* GeoJSONSource::Impl::getData() const {
return data.get();
}
+optional<std::string> GeoJSONSource::Impl::getAttribution() const {
+ return {};
+}
+
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/sources/geojson_source_impl.hpp b/src/mbgl/style/sources/geojson_source_impl.hpp
index dece1269f8..a524bab9f2 100644
--- a/src/mbgl/style/sources/geojson_source_impl.hpp
+++ b/src/mbgl/style/sources/geojson_source_impl.hpp
@@ -2,7 +2,7 @@
#include <mbgl/style/source_impl.hpp>
#include <mbgl/style/sources/geojson_source.hpp>
-#include <mbgl/util/variant.hpp>
+#include <mbgl/util/range.hpp>
namespace mbgl {
@@ -19,25 +19,17 @@ public:
class GeoJSONSource::Impl : public Source::Impl {
public:
- Impl(std::string id, Source&, const GeoJSONOptions);
+ Impl(std::string id, GeoJSONOptions);
+ Impl(const GeoJSONSource::Impl&, const GeoJSON&);
~Impl() final;
- void setURL(std::string);
- optional<std::string> getURL() const;
Range<uint8_t> getZoomRange() const;
-
- void setGeoJSON(const GeoJSON&);
GeoJSONData* getData() const;
- void loadDescription(FileSource&) final;
- std::unique_ptr<RenderSource> createRenderSource() const final;
+ optional<std::string> getAttribution() const final;
private:
- void _setGeoJSON(const GeoJSON&);
-
GeoJSONOptions options;
- optional<std::string> url;
- std::unique_ptr<AsyncRequest> req;
std::unique_ptr<GeoJSONData> data;
};
diff --git a/src/mbgl/style/sources/image_source.cpp b/src/mbgl/style/sources/image_source.cpp
new file mode 100644
index 0000000000..9313d8da4a
--- /dev/null
+++ b/src/mbgl/style/sources/image_source.cpp
@@ -0,0 +1,85 @@
+#include <mbgl/style/sources/image_source.hpp>
+#include <mbgl/style/sources/image_source_impl.hpp>
+#include <mbgl/util/geo.hpp>
+#include <mbgl/style/source_observer.hpp>
+#include <mbgl/util/premultiply.hpp>
+#include <mbgl/storage/file_source.hpp>
+
+namespace mbgl {
+namespace style {
+
+ImageSource::ImageSource(std::string id, const std::array<LatLng, 4> coords_)
+ : Source(makeMutable<Impl>(std::move(id), coords_)) {
+}
+
+ImageSource::~ImageSource() = default;
+
+const ImageSource::Impl& ImageSource::impl() const {
+ return static_cast<const Impl&>(*baseImpl);
+}
+
+void ImageSource::setCoordinates(const std::array<LatLng, 4>& coords_) {
+ baseImpl = makeMutable<Impl>(impl(), coords_);
+ observer->onSourceChanged(*this);
+}
+
+std::array<LatLng, 4> ImageSource::getCoordinates() const {
+ return impl().getCoordinates();
+}
+
+void ImageSource::setURL(const std::string& url_) {
+ url = std::move(url_);
+ // Signal that the source description needs a reload
+ if (loaded || req) {
+ loaded = false;
+ req.reset();
+ observer->onSourceDescriptionChanged(*this);
+ }
+}
+
+void ImageSource::setImage(UnassociatedImage&& image_) {
+ url = {};
+ if (req) {
+ req.reset();
+ }
+ loaded = true;
+ baseImpl = makeMutable<Impl>(impl(), std::move(image_));
+ observer->onSourceChanged(*this);
+}
+
+optional<std::string> ImageSource::getURL() const {
+ return url;
+}
+
+void ImageSource::loadDescription(FileSource& fileSource) {
+ if (!url) {
+ loaded = true;
+ }
+
+ if (req || loaded) {
+ return;
+ }
+ const Resource imageResource { Resource::Image, *url, {}, Resource::Necessity::Required };
+
+ req = fileSource.request(imageResource, [this](Response res) {
+ if (res.error) {
+ observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(res.error->message)));
+ } else if (res.notModified) {
+ return;
+ } else if (res.noContent) {
+ observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error("unexpectedly empty image url")));
+ } else {
+ try {
+ UnassociatedImage image = util::unpremultiply(decodeImage(*res.data));
+ baseImpl = makeMutable<Impl>(impl(), std::move(image));
+ } catch (...) {
+ observer->onSourceError(*this, std::current_exception());
+ }
+ loaded = true;
+ observer->onSourceLoaded(*this);
+ }
+ });
+}
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/sources/image_source_impl.cpp b/src/mbgl/style/sources/image_source_impl.cpp
new file mode 100644
index 0000000000..98f3cc9db9
--- /dev/null
+++ b/src/mbgl/style/sources/image_source_impl.cpp
@@ -0,0 +1,38 @@
+#include <mbgl/style/sources/image_source_impl.hpp>
+#include <mbgl/util/geo.hpp>
+
+namespace mbgl {
+namespace style {
+
+ImageSource::Impl::Impl(std::string id_, std::array<LatLng, 4> coords_)
+ : Source::Impl(SourceType::Image, std::move(id_)),
+ coords(std::move(coords_)) {
+}
+
+ImageSource::Impl::Impl(const Impl& other, std::array<LatLng, 4> coords_)
+ : Source::Impl(other),
+ coords(std::move(coords_)),
+ image(other.image.clone()) {
+}
+
+ImageSource::Impl::Impl(const Impl& rhs, UnassociatedImage image_)
+ : Source::Impl(rhs),
+ coords(rhs.coords),
+ image(std::move(image_)) {
+}
+ImageSource::Impl::~Impl() = default;
+
+const UnassociatedImage& ImageSource::Impl::getImage() const {
+ return image;
+}
+
+std::array<LatLng, 4> ImageSource::Impl::getCoordinates() const {
+ return coords;
+}
+
+optional<std::string> ImageSource::Impl::getAttribution() const {
+ return {};
+}
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/sources/image_source_impl.hpp b/src/mbgl/style/sources/image_source_impl.hpp
new file mode 100644
index 0000000000..5fd41ac6e6
--- /dev/null
+++ b/src/mbgl/style/sources/image_source_impl.hpp
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <mbgl/style/source_impl.hpp>
+#include <mbgl/style/sources/image_source.hpp>
+#include <mbgl/util/image.hpp>
+#include <mbgl/util/geo.hpp>
+
+namespace mbgl {
+
+namespace style {
+
+class ImageSource::Impl : public Source::Impl {
+public:
+ Impl(std::string id, std::array<LatLng, 4> coords);
+ Impl(const Impl& rhs, std::array<LatLng, 4> coords);
+ Impl(const Impl& rhs, UnassociatedImage image);
+
+ ~Impl() final;
+
+ const UnassociatedImage& getImage() const;
+ std::array<LatLng, 4> getCoordinates() const;
+
+ optional<std::string> getAttribution() const final;
+private:
+ std::array<LatLng, 4> coords;
+ UnassociatedImage image;
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/sources/raster_source.cpp b/src/mbgl/style/sources/raster_source.cpp
index 94fdbcef12..0a0412a4ed 100644
--- a/src/mbgl/style/sources/raster_source.cpp
+++ b/src/mbgl/style/sources/raster_source.cpp
@@ -1,21 +1,81 @@
#include <mbgl/style/sources/raster_source.hpp>
#include <mbgl/style/sources/raster_source_impl.hpp>
+#include <mbgl/style/source_observer.hpp>
+#include <mbgl/style/conversion/json.hpp>
+#include <mbgl/style/conversion/tileset.hpp>
+#include <mbgl/storage/file_source.hpp>
+#include <mbgl/util/mapbox.hpp>
namespace mbgl {
namespace style {
-RasterSource::RasterSource(std::string id, variant<std::string, Tileset> urlOrTileset, uint16_t tileSize)
- : Source(SourceType::Raster, std::make_unique<RasterSource::Impl>(std::move(id), *this, std::move(urlOrTileset), tileSize)),
- impl(static_cast<Impl*>(baseImpl.get())) {
+RasterSource::RasterSource(std::string id, variant<std::string, Tileset> urlOrTileset_, uint16_t tileSize)
+ : Source(makeMutable<Impl>(std::move(id), tileSize)),
+ urlOrTileset(std::move(urlOrTileset_)) {
+}
+
+RasterSource::~RasterSource() = default;
+
+const RasterSource::Impl& RasterSource::impl() const {
+ return static_cast<const Impl&>(*baseImpl);
+}
+
+const variant<std::string, Tileset>& RasterSource::getURLOrTileset() const {
+ return urlOrTileset;
}
optional<std::string> RasterSource::getURL() const {
- auto urlOrTileset = impl->getURLOrTileset();
- if (urlOrTileset.is<std::string>()) {
- return urlOrTileset.get<std::string>();
- } else {
+ if (urlOrTileset.is<Tileset>()) {
return {};
}
+
+ return urlOrTileset.get<std::string>();
+}
+
+uint16_t RasterSource::getTileSize() const {
+ return impl().getTileSize();
+}
+
+void RasterSource::loadDescription(FileSource& fileSource) {
+ if (urlOrTileset.is<Tileset>()) {
+ baseImpl = makeMutable<Impl>(impl(), urlOrTileset.get<Tileset>());
+ loaded = true;
+ return;
+ }
+
+ if (req) {
+ return;
+ }
+
+ const std::string& url = urlOrTileset.get<std::string>();
+ req = fileSource.request(Resource::source(url), [this, url](Response res) {
+ if (res.error) {
+ observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(res.error->message)));
+ } else if (res.notModified) {
+ return;
+ } else if (res.noContent) {
+ observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error("unexpectedly empty TileJSON")));
+ } else {
+ conversion::Error error;
+ optional<Tileset> tileset = conversion::convertJSON<Tileset>(*res.data, error);
+ if (!tileset) {
+ observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(error.message)));
+ return;
+ }
+
+ util::mapbox::canonicalizeTileset(*tileset, url, getType(), getTileSize());
+ bool changed = impl().getTileset() != *tileset;
+
+ baseImpl = makeMutable<Impl>(impl(), *tileset);
+ loaded = true;
+
+ observer->onSourceLoaded(*this);
+
+ if (changed) {
+ observer->onSourceChanged(*this);
+ }
+ }
+ });
}
} // namespace style
diff --git a/src/mbgl/style/sources/raster_source_impl.cpp b/src/mbgl/style/sources/raster_source_impl.cpp
index b85d221f2e..50dae1f07e 100644
--- a/src/mbgl/style/sources/raster_source_impl.cpp
+++ b/src/mbgl/style/sources/raster_source_impl.cpp
@@ -1,17 +1,32 @@
#include <mbgl/style/sources/raster_source_impl.hpp>
-#include <mbgl/renderer/sources/render_raster_source.hpp>
namespace mbgl {
namespace style {
-RasterSource::Impl::Impl(std::string id_, Source& base_,
- variant<std::string, Tileset> urlOrTileset_,
- uint16_t tileSize_)
- : TileSourceImpl(SourceType::Raster, std::move(id_), base_, std::move(urlOrTileset_), tileSize_) {
+RasterSource::Impl::Impl(std::string id_, uint16_t tileSize_)
+ : Source::Impl(SourceType::Raster, std::move(id_)),
+ tileSize(tileSize_) {
}
-std::unique_ptr<RenderSource> RasterSource::Impl::createRenderSource() const {
- return std::make_unique<RenderRasterSource>(*this);
+RasterSource::Impl::Impl(const Impl& other, Tileset tileset_)
+ : Source::Impl(other),
+ tileSize(other.tileSize),
+ tileset(std::move(tileset_)) {
+}
+
+uint16_t RasterSource::Impl::getTileSize() const {
+ return tileSize;
+}
+
+optional<Tileset> RasterSource::Impl::getTileset() const {
+ return tileset;
+}
+
+optional<std::string> RasterSource::Impl::getAttribution() const {
+ if (!tileset) {
+ return {};
+ }
+ return tileset->attribution;
}
} // namespace style
diff --git a/src/mbgl/style/sources/raster_source_impl.hpp b/src/mbgl/style/sources/raster_source_impl.hpp
index 4bc76560f8..c41d5485b2 100644
--- a/src/mbgl/style/sources/raster_source_impl.hpp
+++ b/src/mbgl/style/sources/raster_source_impl.hpp
@@ -1,16 +1,24 @@
#pragma once
#include <mbgl/style/sources/raster_source.hpp>
-#include <mbgl/style/tile_source_impl.hpp>
+#include <mbgl/style/source_impl.hpp>
namespace mbgl {
namespace style {
-class RasterSource::Impl : public TileSourceImpl {
+class RasterSource::Impl : public Source::Impl {
public:
- Impl(std::string id, Source&, variant<std::string, Tileset>, uint16_t tileSize);
+ Impl(std::string id, uint16_t tileSize);
+ Impl(const Impl&, Tileset);
- std::unique_ptr<RenderSource> createRenderSource() const final;
+ optional<Tileset> getTileset() const;
+ uint16_t getTileSize() const;
+
+ optional<std::string> getAttribution() const final;
+
+private:
+ uint16_t tileSize;
+ optional<Tileset> tileset;
};
} // namespace style
diff --git a/src/mbgl/style/sources/vector_source.cpp b/src/mbgl/style/sources/vector_source.cpp
index 4bcd3b8985..ccdd453c75 100644
--- a/src/mbgl/style/sources/vector_source.cpp
+++ b/src/mbgl/style/sources/vector_source.cpp
@@ -1,21 +1,78 @@
#include <mbgl/style/sources/vector_source.hpp>
#include <mbgl/style/sources/vector_source_impl.hpp>
+#include <mbgl/style/source_observer.hpp>
+#include <mbgl/style/conversion/json.hpp>
+#include <mbgl/style/conversion/tileset.hpp>
+#include <mbgl/storage/file_source.hpp>
+#include <mbgl/util/mapbox.hpp>
+#include <mbgl/util/constants.hpp>
namespace mbgl {
namespace style {
-VectorSource::VectorSource(std::string id, variant<std::string, Tileset> urlOrTileset)
- : Source(SourceType::Vector, std::make_unique<VectorSource::Impl>(std::move(id), *this, std::move(urlOrTileset))),
- impl(static_cast<Impl*>(baseImpl.get())) {
+VectorSource::VectorSource(std::string id, variant<std::string, Tileset> urlOrTileset_)
+ : Source(makeMutable<Impl>(std::move(id))),
+ urlOrTileset(std::move(urlOrTileset_)) {
+}
+
+VectorSource::~VectorSource() = default;
+
+const VectorSource::Impl& VectorSource::impl() const {
+ return static_cast<const Impl&>(*baseImpl);
+}
+
+const variant<std::string, Tileset>& VectorSource::getURLOrTileset() const {
+ return urlOrTileset;
}
optional<std::string> VectorSource::getURL() const {
- auto urlOrTileset = impl->getURLOrTileset();
- if (urlOrTileset.is<std::string>()) {
- return urlOrTileset.get<std::string>();
- } else {
+ if (urlOrTileset.is<Tileset>()) {
return {};
}
+
+ return urlOrTileset.get<std::string>();
+}
+
+void VectorSource::loadDescription(FileSource& fileSource) {
+ if (urlOrTileset.is<Tileset>()) {
+ baseImpl = makeMutable<Impl>(impl(), urlOrTileset.get<Tileset>());
+ loaded = true;
+ return;
+ }
+
+ if (req) {
+ return;
+ }
+
+ const std::string& url = urlOrTileset.get<std::string>();
+ req = fileSource.request(Resource::source(url), [this, url](Response res) {
+ if (res.error) {
+ observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(res.error->message)));
+ } else if (res.notModified) {
+ return;
+ } else if (res.noContent) {
+ observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error("unexpectedly empty TileJSON")));
+ } else {
+ conversion::Error error;
+ optional<Tileset> tileset = conversion::convertJSON<Tileset>(*res.data, error);
+ if (!tileset) {
+ observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(error.message)));
+ return;
+ }
+
+ util::mapbox::canonicalizeTileset(*tileset, url, getType(), util::tileSize);
+ bool changed = impl().getTileset() != *tileset;
+
+ baseImpl = makeMutable<Impl>(impl(), *tileset);
+ loaded = true;
+
+ observer->onSourceLoaded(*this);
+
+ if (changed) {
+ observer->onSourceChanged(*this);
+ }
+ }
+ });
}
} // namespace style
diff --git a/src/mbgl/style/sources/vector_source_impl.cpp b/src/mbgl/style/sources/vector_source_impl.cpp
index 158abf8575..b06f0557bf 100644
--- a/src/mbgl/style/sources/vector_source_impl.cpp
+++ b/src/mbgl/style/sources/vector_source_impl.cpp
@@ -1,16 +1,26 @@
#include <mbgl/style/sources/vector_source_impl.hpp>
-#include <mbgl/renderer/sources/render_vector_source.hpp>
-#include <mbgl/util/constants.hpp>
namespace mbgl {
namespace style {
-VectorSource::Impl::Impl(std::string id_, Source& base_, variant<std::string, Tileset> urlOrTileset_)
- : TileSourceImpl(SourceType::Vector, std::move(id_), base_, std::move(urlOrTileset_), util::tileSize) {
+VectorSource::Impl::Impl(std::string id_)
+ : Source::Impl(SourceType::Vector, std::move(id_)) {
}
-std::unique_ptr<RenderSource> VectorSource::Impl::createRenderSource() const {
- return std::make_unique<RenderVectorSource>(*this);
+VectorSource::Impl::Impl(const Impl& other, Tileset tileset_)
+ : Source::Impl(other),
+ tileset(std::move(tileset_)) {
+}
+
+optional<Tileset> VectorSource::Impl::getTileset() const {
+ return tileset;
+}
+
+optional<std::string> VectorSource::Impl::getAttribution() const {
+ if (!tileset) {
+ return {};
+ }
+ return tileset->attribution;
}
} // namespace style
diff --git a/src/mbgl/style/sources/vector_source_impl.hpp b/src/mbgl/style/sources/vector_source_impl.hpp
index 844739948c..5e559b9266 100644
--- a/src/mbgl/style/sources/vector_source_impl.hpp
+++ b/src/mbgl/style/sources/vector_source_impl.hpp
@@ -1,16 +1,22 @@
#pragma once
#include <mbgl/style/sources/vector_source.hpp>
-#include <mbgl/style/tile_source_impl.hpp>
+#include <mbgl/style/source_impl.hpp>
namespace mbgl {
namespace style {
-class VectorSource::Impl : public TileSourceImpl {
+class VectorSource::Impl : public Source::Impl {
public:
- Impl(std::string id, Source&, variant<std::string, Tileset>);
+ Impl(std::string id);
+ Impl(const Impl&, Tileset);
- std::unique_ptr<RenderSource> createRenderSource() const final;
+ optional<Tileset> getTileset() const;
+
+ optional<std::string> getAttribution() const final;
+
+private:
+ optional<Tileset> tileset;
};
} // namespace style
diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp
index f1ac22082b..5fe1ab4a06 100644
--- a/src/mbgl/style/style.cpp
+++ b/src/mbgl/style/style.cpp
@@ -1,813 +1,145 @@
#include <mbgl/style/style.hpp>
-#include <mbgl/style/observer.hpp>
-#include <mbgl/style/source_impl.hpp>
-#include <mbgl/style/layers/symbol_layer.hpp>
-#include <mbgl/style/layers/symbol_layer_impl.hpp>
-#include <mbgl/style/layers/custom_layer.hpp>
-#include <mbgl/style/layers/custom_layer_impl.hpp>
-#include <mbgl/style/layers/background_layer.hpp>
-#include <mbgl/style/layers/background_layer_impl.hpp>
-#include <mbgl/style/layers/fill_layer.hpp>
-#include <mbgl/style/layers/fill_extrusion_layer.hpp>
-#include <mbgl/style/layers/line_layer.hpp>
-#include <mbgl/style/layers/circle_layer.hpp>
-#include <mbgl/style/layers/raster_layer.hpp>
-#include <mbgl/style/layer_impl.hpp>
-#include <mbgl/style/parser.hpp>
-#include <mbgl/style/transition_options.hpp>
-#include <mbgl/style/class_dictionary.hpp>
-#include <mbgl/sprite/sprite_atlas.hpp>
-#include <mbgl/text/glyph_atlas.hpp>
-#include <mbgl/geometry/line_atlas.hpp>
-#include <mbgl/renderer/update_parameters.hpp>
-#include <mbgl/renderer/cascade_parameters.hpp>
-#include <mbgl/renderer/property_evaluation_parameters.hpp>
-#include <mbgl/renderer/tile_parameters.hpp>
-#include <mbgl/renderer/render_source.hpp>
-#include <mbgl/renderer/render_item.hpp>
-#include <mbgl/renderer/render_tile.hpp>
-#include <mbgl/renderer/render_background_layer.hpp>
-#include <mbgl/renderer/render_circle_layer.hpp>
-#include <mbgl/renderer/render_custom_layer.hpp>
-#include <mbgl/renderer/render_fill_extrusion_layer.hpp>
-#include <mbgl/renderer/render_fill_layer.hpp>
-#include <mbgl/renderer/render_line_layer.hpp>
-#include <mbgl/renderer/render_raster_layer.hpp>
-#include <mbgl/renderer/render_symbol_layer.hpp>
-#include <mbgl/tile/tile.hpp>
-#include <mbgl/util/constants.hpp>
-#include <mbgl/util/exception.hpp>
-#include <mbgl/util/geometry.hpp>
-#include <mbgl/util/string.hpp>
-#include <mbgl/util/logging.hpp>
-#include <mbgl/util/math.hpp>
-#include <mbgl/util/std.hpp>
-#include <mbgl/math/minmax.hpp>
-#include <mbgl/map/query.hpp>
-
-#include <algorithm>
+#include <mbgl/style/style_impl.hpp>
+#include <mbgl/style/light.hpp>
+#include <mbgl/style/image.hpp>
+#include <mbgl/style/source.hpp>
+#include <mbgl/style/layer.hpp>
namespace mbgl {
namespace style {
-static Observer nullObserver;
-
-struct QueueSourceReloadVisitor {
- UpdateBatch& updateBatch;
-
- // No need to reload sources for these types; their visibility can change but
- // they don't participate in layout.
- void operator()(CustomLayer&) {}
- void operator()(RasterLayer&) {}
- void operator()(BackgroundLayer&) {}
-
- template <class VectorLayer>
- void operator()(VectorLayer& layer) {
- updateBatch.sourceIDs.insert(layer.getSourceID());
- }
-};
-
-Style::Style(Scheduler& scheduler_, FileSource& fileSource_, float pixelRatio)
- : scheduler(scheduler_),
- fileSource(fileSource_),
- glyphAtlas(std::make_unique<GlyphAtlas>(Size{ 2048, 2048 }, fileSource)),
- spriteAtlas(std::make_unique<SpriteAtlas>(Size{ 1024, 1024 }, pixelRatio)),
- lineAtlas(std::make_unique<LineAtlas>(Size{ 256, 512 })),
- light(std::make_unique<Light>()),
- renderLight(std::make_unique<RenderLight>(light->impl)),
- observer(&nullObserver) {
- glyphAtlas->setObserver(this);
- spriteAtlas->setObserver(this);
- light->impl->setObserver(this);
+Style::Style(Scheduler& scheduler, FileSource& fileSource, float pixelRatio)
+ : impl(std::make_unique<Impl>(scheduler, fileSource, pixelRatio)) {
}
-Style::~Style() {
- for (const auto& source : sources) {
- source->baseImpl->setObserver(nullptr);
- }
+Style::~Style() = default;
- for (const auto& layer : layers) {
- if (CustomLayer* customLayer = layer->as<CustomLayer>()) {
- customLayer->impl->deinitialize();
- }
- }
-
- glyphAtlas->setObserver(nullptr);
- spriteAtlas->setObserver(nullptr);
- light->impl->setObserver(nullptr);
-}
-
-bool Style::addClass(const std::string& className) {
- if (hasClass(className)) return false;
- classes.push_back(className);
- return true;
-}
-
-bool Style::hasClass(const std::string& className) const {
- return std::find(classes.begin(), classes.end(), className) != classes.end();
-}
-
-bool Style::removeClass(const std::string& className) {
- const auto it = std::find(classes.begin(), classes.end(), className);
- if (it != classes.end()) {
- classes.erase(it);
- return true;
- }
- return false;
+void Style::loadJSON(const std::string& json) {
+ impl->loadJSON(json);
}
-void Style::setClasses(const std::vector<std::string>& classNames) {
- classes = classNames;
-}
-
-std::vector<std::string> Style::getClasses() const {
- return classes;
-}
-
-void Style::setTransitionOptions(const TransitionOptions& options) {
- transitionOptions = options;
-}
-
-TransitionOptions Style::getTransitionOptions() const {
- return transitionOptions;
+void Style::loadURL(const std::string& url) {
+ impl->loadURL(url);
}
-void Style::setJSON(const std::string& json) {
- sources.clear();
- renderSources.clear();
- layers.clear();
- renderLayers.clear();
- classes.clear();
- transitionOptions = {};
- updateBatch = {};
-
- Parser parser;
- auto error = parser.parse(json);
-
- if (error) {
- std::string message = "Failed to parse style: " + util::toString(error);
- Log::Error(Event::ParseStyle, message.c_str());
- observer->onStyleError(std::make_exception_ptr(util::StyleParseException(message)));
- observer->onResourceError(error);
- return;
- }
-
- for (auto& source : parser.sources) {
- addSource(std::move(source));
- }
-
- for (auto& layer : parser.layers) {
- addLayer(std::move(layer));
- }
-
- name = parser.name;
- defaultLatLng = parser.latLng;
- defaultZoom = parser.zoom;
- defaultBearing = parser.bearing;
- defaultPitch = parser.pitch;
- setLight(std::make_unique<Light>(parser.light));
-
- glyphAtlas->setURL(parser.glyphURL);
- spriteAtlas->load(parser.spriteURL, scheduler, fileSource);
-
- loaded = true;
-
- observer->onStyleLoaded();
-}
-
-void Style::addSource(std::unique_ptr<Source> source) {
- // Guard against duplicate source ids
- auto it = std::find_if(sources.begin(), sources.end(), [&](const auto& existing) {
- return existing->getID() == source->getID();
- });
-
- if (it != sources.end()) {
- std::string msg = "Source " + source->getID() + " already exists";
- throw std::runtime_error(msg.c_str());
- }
-
- source->baseImpl->setObserver(this);
- source->baseImpl->loadDescription(fileSource);
-
- std::unique_ptr<RenderSource> renderSource = source->baseImpl->createRenderSource();
- renderSource->setObserver(this);
- renderSources.emplace_back(std::move(renderSource));
-
- sources.emplace_back(std::move(source));
-}
-
-struct SourceIdUsageEvaluator {
- const std::string& sourceId;
-
- bool operator()(BackgroundLayer&) { return false; }
- bool operator()(CustomLayer&) { return false; }
-
- template <class LayerType>
- bool operator()(LayerType& layer) {
- return layer.getSourceID() == sourceId;
- }
-};
-
-std::unique_ptr<Source> Style::removeSource(const std::string& id) {
- // Check if source is in use
- SourceIdUsageEvaluator sourceIdEvaluator {id};
- auto layerIt = std::find_if(layers.begin(), layers.end(), [&](const auto& layer) {
- return layer->accept(sourceIdEvaluator);
- });
-
- if (layerIt != layers.end()) {
- Log::Warning(Event::General, "Source '%s' is in use, cannot remove", id.c_str());
- return nullptr;
- }
-
- auto it = std::find_if(sources.begin(), sources.end(), [&](const auto& source) {
- return source->getID() == id;
- });
-
- if (it == sources.end()) {
- return nullptr;
- }
-
- util::erase_if(renderSources, [&](const auto& source) {
- return source->baseImpl.id == id;
- });
-
- auto source = std::move(*it);
- source->baseImpl->setObserver(nullptr);
- sources.erase(it);
- updateBatch.sourceIDs.erase(id);
-
- return source;
-}
-
-std::vector<const Layer*> Style::getLayers() const {
- std::vector<const Layer*> result;
- result.reserve(layers.size());
- for (const auto& layer : layers) {
- result.push_back(layer.get());
- }
- return result;
-}
-
-std::vector<Layer*> Style::getLayers() {
- std::vector<Layer*> result;
- result.reserve(layers.size());
- for (auto& layer : layers) {
- result.push_back(layer.get());
- }
- return result;
-}
-
-std::vector<std::unique_ptr<Layer>>::const_iterator Style::findLayer(const std::string& id) const {
- return std::find_if(layers.begin(), layers.end(), [&](const auto& layer) {
- return layer->baseImpl->id == id;
- });
-}
-
-Layer* Style::getLayer(const std::string& id) const {
- auto it = findLayer(id);
- return it != layers.end() ? it->get() : nullptr;
-}
-
-Layer* Style::addLayer(std::unique_ptr<Layer> layer, optional<std::string> before) {
- // TODO: verify source
-
- // Guard against duplicate layer ids
- auto it = std::find_if(layers.begin(), layers.end(), [&](const auto& existing) {
- return existing->getID() == layer->getID();
- });
-
- if (it != layers.end()) {
- throw std::runtime_error(std::string{"Layer "} + layer->getID() + " already exists");
- }
-
- if (CustomLayer* customLayer = layer->as<CustomLayer>()) {
- customLayer->impl->initialize();
- }
-
- layer->baseImpl->setObserver(this);
- layer->accept(QueueSourceReloadVisitor { updateBatch });
-
- auto added = layers.emplace(before ? findLayer(*before) : layers.end(), std::move(layer))->get();
- renderLayers.emplace(before ? findRenderLayer(*before) : renderLayers.end(), added->baseImpl->createRenderLayer());
- return std::move(added);
-}
-
-std::unique_ptr<Layer> Style::removeLayer(const std::string& id) {
- auto it = std::find_if(layers.begin(), layers.end(), [&](const auto& layer) {
- return layer->baseImpl->id == id;
- });
-
- if (it == layers.end())
- return nullptr;
-
- auto layer = std::move(*it);
-
- if (CustomLayer* customLayer = layer->as<CustomLayer>()) {
- customLayer->impl->deinitialize();
- }
-
- layer->baseImpl->setObserver(nullptr);
- layers.erase(it);
- removeRenderLayer(id);
- return layer;
+std::string Style::getJSON() const {
+ return impl->getJSON();
}
-std::vector<const RenderLayer*> Style::getRenderLayers() const {
- std::vector<const RenderLayer*> result;
- result.reserve(renderLayers.size());
- for (const auto& layer : renderLayers) {
- result.push_back(layer.get());
- }
- return result;
-}
-
-std::vector<RenderLayer*> Style::getRenderLayers() {
- std::vector<RenderLayer*> result;
- result.reserve(renderLayers.size());
- for (auto& layer : renderLayers) {
- result.push_back(layer.get());
- }
- return result;
-}
-
-std::vector<std::unique_ptr<RenderLayer>>::const_iterator Style::findRenderLayer(const std::string& id) const {
- return std::find_if(renderLayers.begin(), renderLayers.end(), [&](const auto& layer) {
- return layer->baseImpl.id == id;
- });
-}
-
-RenderLayer* Style::getRenderLayer(const std::string& id) const {
- auto it = findRenderLayer(id);
- return it != renderLayers.end() ? it->get() : nullptr;
-}
-
-void Style::removeRenderLayer(const std::string& id) {
- auto it = std::find_if(renderLayers.begin(), renderLayers.end(), [&](const auto& layer) {
- return layer->baseImpl.id == id;
- });
-
- if (it != renderLayers.end()) {
- renderLayers.erase(it);
- }
-}
-
-void Style::setLight(std::unique_ptr<Light> light_) {
- light = std::move(light_);
- light->impl->setObserver(this);
-
- // Copy renderlight to preserve the initialised
- // transitioning light properties
- renderLight = renderLight->copy(light->impl);
-
- onLightChanged(*light);
-}
-
-Light* Style::getLight() const {
- return light.get();
-}
-
-RenderLight* Style::getRenderLight() const {
- return renderLight.get();
+std::string Style::getURL() const {
+ return impl->getURL();
}
std::string Style::getName() const {
- return name;
+ return impl->getName();
}
LatLng Style::getDefaultLatLng() const {
- return defaultLatLng;
+ return impl->getDefaultLatLng();
}
double Style::getDefaultZoom() const {
- return defaultZoom;
+ return impl->getDefaultZoom();
}
double Style::getDefaultBearing() const {
- return defaultBearing;
+ return impl->getDefaultBearing();
}
double Style::getDefaultPitch() const {
- return defaultPitch;
-}
-
-void Style::update(const UpdateParameters& parameters) {
- bool zoomChanged = zoomHistory.update(parameters.transformState.getZoom(), parameters.timePoint);
-
- std::vector<ClassID> classIDs;
- for (const auto& className : classes) {
- classIDs.push_back(ClassDictionary::Get().lookup(className));
- }
- classIDs.push_back(ClassID::Default);
-
- const CascadeParameters cascadeParameters {
- classIDs,
- parameters.timePoint,
- parameters.mode == MapMode::Continuous ? transitionOptions : TransitionOptions()
- };
-
- const PropertyEvaluationParameters evaluationParameters {
- zoomHistory,
- parameters.timePoint,
- parameters.mode == MapMode::Continuous ? util::DEFAULT_FADE_DURATION : Duration::zero()
- };
-
- const TileParameters tileParameters(parameters.pixelRatio,
- parameters.debugOptions,
- parameters.transformState,
- parameters.scheduler,
- parameters.fileSource,
- parameters.mode,
- parameters.annotationManager,
- *this);
-
- const bool cascade = parameters.updateFlags & Update::Classes;
- const bool evaluate = cascade || zoomChanged || parameters.updateFlags & Update::RecalculateStyle;
-
- if (cascade) {
- renderLight->transition(cascadeParameters);
- }
-
- if (evaluate || renderLight->hasTransition()) {
- renderLight->evaluate(evaluationParameters);
- }
-
- for (const auto& renderSource : renderSources) {
- renderSource->enabled = false;
- }
-
- for (const auto& layer : renderLayers) {
- if (cascade) {
- layer->cascade(cascadeParameters);
- }
-
- if (evaluate || layer->hasTransition()) {
- layer->evaluate(evaluationParameters);
- }
-
- if (layer->needsRendering(zoomHistory.lastZoom)) {
- if (RenderSource* renderSource = getRenderSource(layer->baseImpl.source)) {
- renderSource->enabled = true;
- }
- }
- }
-
- for (const auto& renderSource : renderSources) {
- bool updated = updateBatch.sourceIDs.count(renderSource->baseImpl.id);
- if (renderSource->enabled) {
- if (updated) {
- renderSource->reloadTiles();
- }
- renderSource->updateTiles(tileParameters);
- } else if (updated) {
- renderSource->invalidateTiles();
- } else {
- renderSource->removeTiles();
- }
- }
-
- updateBatch.sourceIDs.clear();
-}
-
-std::vector<const Source*> Style::getSources() const {
- std::vector<const Source*> result;
- result.reserve(sources.size());
- for (const auto& source : sources) {
- result.push_back(source.get());
- }
- return result;
-}
-
-std::vector<Source*> Style::getSources() {
- std::vector<Source*> result;
- result.reserve(sources.size());
- for (auto& source : sources) {
- result.push_back(source.get());
- }
- return result;
-}
-
-Source* Style::getSource(const std::string& id) const {
- const auto it = std::find_if(sources.begin(), sources.end(), [&](const auto& source) {
- return source->getID() == id;
- });
-
- return it != sources.end() ? it->get() : nullptr;
+ return impl->getDefaultPitch();
}
-RenderSource* Style::getRenderSource(const std::string& id) const {
- const auto it = std::find_if(renderSources.begin(), renderSources.end(), [&](const auto& source) {
- return source->baseImpl.id == id;
- });
-
- return it != renderSources.end() ? it->get() : nullptr;
-}
-
-bool Style::hasTransitions() const {
- if (renderLight->hasTransition()) {
- return true;
- }
-
- for (const auto& layer : renderLayers) {
- if (layer->hasTransition()) {
- return true;
- }
- }
-
- return false;
-}
-
-bool Style::isLoaded() const {
- if (!loaded) {
- return false;
- }
-
- for (const auto& source: sources) {
- if (!source->baseImpl->loaded) {
- return false;
- }
- }
-
- for (const auto& renderSource: renderSources) {
- if (!renderSource->isLoaded()) {
- return false;
- }
- }
-
- if (!spriteAtlas->isLoaded()) {
- return false;
- }
-
- return true;
-}
-
-RenderData Style::getRenderData(MapDebugOptions debugOptions, float angle) const {
- RenderData result;
-
- for (const auto& renderSource: renderSources) {
- if (renderSource->enabled) {
- result.sources.insert(renderSource.get());
- }
- }
-
- for (const auto& layer : renderLayers) {
- if (!layer->needsRendering(zoomHistory.lastZoom)) {
- continue;
- }
-
- if (const RenderBackgroundLayer* background = layer->as<RenderBackgroundLayer>()) {
- if (debugOptions & MapDebugOptions::Overdraw) {
- // We want to skip glClear optimization in overdraw mode.
- result.order.emplace_back(*layer);
- continue;
- }
- const BackgroundPaintProperties::Evaluated& paint = background->evaluated;
- if (layer.get() == renderLayers[0].get() && paint.get<BackgroundPattern>().from.empty()) {
- // This is a solid background. We can use glClear().
- result.backgroundColor = paint.get<BackgroundColor>() * paint.get<BackgroundOpacity>();
- } else {
- // This is a textured background, or not the bottommost layer. We need to render it with a quad.
- result.order.emplace_back(*layer);
- }
- continue;
- }
-
- if (layer->is<RenderCustomLayer>()) {
- result.order.emplace_back(*layer);
- continue;
- }
-
- RenderSource* source = getRenderSource(layer->baseImpl.source);
- if (!source) {
- Log::Warning(Event::Render, "can't find source for layer '%s'", layer->baseImpl.id.c_str());
- continue;
- }
-
- auto& renderTiles = source->getRenderTiles();
- const bool symbolLayer = layer->is<RenderSymbolLayer>();
-
- // Sort symbol tiles in opposite y position, so tiles with overlapping
- // symbols are drawn on top of each other, with lower symbols being
- // drawn on top of higher symbols.
- std::vector<std::reference_wrapper<RenderTile>> sortedTiles;
- std::transform(renderTiles.begin(), renderTiles.end(), std::back_inserter(sortedTiles),
- [](auto& pair) { return std::ref(pair.second); });
- if (symbolLayer) {
- std::sort(sortedTiles.begin(), sortedTiles.end(),
- [angle](const RenderTile& a, const RenderTile& b) {
- Point<float> pa(a.id.canonical.x, a.id.canonical.y);
- Point<float> pb(b.id.canonical.x, b.id.canonical.y);
-
- auto par = util::rotate(pa, angle);
- auto pbr = util::rotate(pb, angle);
-
- return std::tie(par.y, par.x) < std::tie(pbr.y, pbr.x);
- });
- }
-
- std::vector<std::reference_wrapper<RenderTile>> sortedTilesForInsertion;
- for (auto tileIt = sortedTiles.begin(); tileIt != sortedTiles.end(); ++tileIt) {
- auto& tile = tileIt->get();
- if (!tile.tile.isRenderable()) {
- continue;
- }
-
- // We're not clipping symbol layers, so when we have both parents and children of symbol
- // layers, we drop all children in favor of their parent to avoid duplicate labels.
- // See https://github.com/mapbox/mapbox-gl-native/issues/2482
- if (symbolLayer) {
- bool skip = false;
- // Look back through the buckets we decided to render to find out whether there is
- // already a bucket from this layer that is a parent of this tile. Tiles are ordered
- // by zoom level when we obtain them from getTiles().
- for (auto it = sortedTilesForInsertion.rbegin();
- it != sortedTilesForInsertion.rend(); ++it) {
- if (tile.tile.id.isChildOf(it->get().tile.id)) {
- skip = true;
- break;
- }
- }
- if (skip) {
- continue;
- }
- }
-
- auto bucket = tile.tile.getBucket(*layer);
- if (bucket) {
- sortedTilesForInsertion.emplace_back(tile);
- tile.used = true;
- }
- }
-
- result.order.emplace_back(*layer, std::move(sortedTilesForInsertion));
- }
-
- return result;
-}
-
-std::vector<Feature> Style::queryRenderedFeatures(const ScreenLineString& geometry,
- const TransformState& transformState,
- const RenderedQueryOptions& options) const {
- std::unordered_map<std::string, std::vector<Feature>> resultsByLayer;
-
- if (options.layerIDs) {
- std::unordered_set<std::string> sourceIDs;
- for (const auto& layerID : *options.layerIDs) {
- if (Layer* layer = getLayer(layerID)) {
- sourceIDs.emplace(layer->baseImpl->source);
- }
- }
- for (const auto& sourceID : sourceIDs) {
- if (RenderSource* renderSource = getRenderSource(sourceID)) {
- auto sourceResults = renderSource->queryRenderedFeatures(geometry, transformState, options);
- std::move(sourceResults.begin(), sourceResults.end(), std::inserter(resultsByLayer, resultsByLayer.begin()));
- }
- }
- } else {
- for (const auto& renderSource : renderSources) {
- auto sourceResults = renderSource->queryRenderedFeatures(geometry, transformState, options);
- std::move(sourceResults.begin(), sourceResults.end(), std::inserter(resultsByLayer, resultsByLayer.begin()));
- }
- }
-
- std::vector<Feature> result;
-
- if (resultsByLayer.empty()) {
- return result;
- }
-
- // Combine all results based on the style layer order.
- for (const auto& layer : renderLayers) {
- if (!layer->needsRendering(zoomHistory.lastZoom)) {
- continue;
- }
- auto it = resultsByLayer.find(layer->baseImpl.id);
- if (it != resultsByLayer.end()) {
- std::move(it->second.begin(), it->second.end(), std::back_inserter(result));
- }
- }
-
- return result;
-}
-
-void Style::setSourceTileCacheSize(size_t size) {
- for (const auto& renderSource : renderSources) {
- renderSource->setCacheSize(size);
- }
+TransitionOptions Style::getTransitionOptions() const {
+ return impl->getTransitionOptions();
}
-void Style::onLowMemory() {
- for (const auto& renderSource : renderSources) {
- renderSource->onLowMemory();
- }
+void Style::setTransitionOptions(const TransitionOptions& options) {
+ impl->mutated = true;
+ impl->setTransitionOptions(options);
}
-void Style::setObserver(style::Observer* observer_) {
- observer = observer_;
+void Style::setLight(std::unique_ptr<Light> light) {
+ impl->setLight(std::move(light));
}
-void Style::onGlyphsLoaded(const FontStack& fontStack, const GlyphRange& glyphRange) {
- observer->onGlyphsLoaded(fontStack, glyphRange);
+Light* Style::getLight() {
+ impl->mutated = true;
+ return impl->getLight();
}
-void Style::onGlyphsError(const FontStack& fontStack, const GlyphRange& glyphRange, std::exception_ptr error) {
- lastError = error;
- Log::Error(Event::Style, "Failed to load glyph range %d-%d for font stack %s: %s",
- glyphRange.first, glyphRange.second, fontStackToString(fontStack).c_str(), util::toString(error).c_str());
- observer->onGlyphsError(fontStack, glyphRange, error);
- observer->onResourceError(error);
+const Light* Style::getLight() const {
+ return impl->getLight();
}
-void Style::onSourceLoaded(Source& source) {
- observer->onSourceLoaded(source);
- observer->onUpdate(Update::Repaint);
+const Image* Style::getImage(const std::string& name) const {
+ return impl->getImage(name);
}
-void Style::onSourceChanged(Source& source) {
- observer->onSourceChanged(source);
- observer->onUpdate(Update::Repaint);
+void Style::addImage(std::unique_ptr<Image> image) {
+ impl->mutated = true;
+ impl->addImage(std::move(image));
}
-void Style::onSourceError(Source& source, std::exception_ptr error) {
- lastError = error;
- Log::Error(Event::Style, "Failed to load source %s: %s",
- source.getID().c_str(), util::toString(error).c_str());
- observer->onSourceError(source, error);
- observer->onResourceError(error);
+void Style::removeImage(const std::string& name) {
+ impl->mutated = true;
+ impl->removeImage(name);
}
-void Style::onSourceDescriptionChanged(Source& source) {
- observer->onSourceDescriptionChanged(source);
- if (!source.baseImpl->loaded) {
- source.baseImpl->loadDescription(fileSource);
- }
+std::vector<Source*> Style::getSources() {
+ impl->mutated = true;
+ return impl->getSources();
}
-void Style::onTileChanged(RenderSource&, const OverscaledTileID&) {
- observer->onUpdate(Update::Repaint);
+std::vector<const Source*> Style::getSources() const {
+ return const_cast<const Impl&>(*impl).getSources();
}
-void Style::onTileError(RenderSource& source, const OverscaledTileID& tileID, std::exception_ptr error) {
- lastError = error;
- Log::Error(Event::Style, "Failed to load tile %s for source %s: %s",
- util::toString(tileID).c_str(), source.baseImpl.id.c_str(), util::toString(error).c_str());
- observer->onResourceError(error);
+Source* Style::getSource(const std::string& id) {
+ impl->mutated = true;
+ return impl->getSource(id);
}
-void Style::onSpriteLoaded() {
- observer->onSpriteLoaded();
- observer->onUpdate(Update::Repaint); // For *-pattern properties.
+const Source* Style::getSource(const std::string& id) const {
+ return impl->getSource(id);
}
-void Style::onSpriteError(std::exception_ptr error) {
- lastError = error;
- Log::Error(Event::Style, "Failed to load sprite: %s", util::toString(error).c_str());
- observer->onSpriteError(error);
- observer->onResourceError(error);
+void Style::addSource(std::unique_ptr<Source> source) {
+ impl->mutated = true;
+ impl->addSource(std::move(source));
}
-void Style::onLayerFilterChanged(Layer& layer) {
- layer.accept(QueueSourceReloadVisitor { updateBatch });
- observer->onUpdate(Update::Repaint);
+std::unique_ptr<Source> Style::removeSource(const std::string& sourceID) {
+ impl->mutated = true;
+ return impl->removeSource(sourceID);
}
-void Style::onLayerVisibilityChanged(Layer& layer) {
- layer.accept(QueueSourceReloadVisitor { updateBatch });
- observer->onUpdate(Update::RecalculateStyle);
+std::vector<Layer*> Style::getLayers() {
+ impl->mutated = true;
+ return impl->getLayers();
}
-void Style::onLayerPaintPropertyChanged(Layer&) {
- observer->onUpdate(Update::RecalculateStyle | Update::Classes);
+std::vector<const Layer*> Style::getLayers() const {
+ return const_cast<const Impl&>(*impl).getLayers();
}
-void Style::onLayerDataDrivenPaintPropertyChanged(Layer& layer) {
- layer.accept(QueueSourceReloadVisitor { updateBatch });
- observer->onUpdate(Update::RecalculateStyle | Update::Classes);
+Layer* Style::getLayer(const std::string& layerID) {
+ impl->mutated = true;
+ return impl->getLayer(layerID);
}
-void Style::onLayerLayoutPropertyChanged(Layer& layer, const char * property) {
- layer.accept(QueueSourceReloadVisitor { updateBatch });
-
- // Recalculate the style for certain properties
- observer->onUpdate((strcmp(property, "icon-size") == 0 || strcmp(property, "text-size") == 0)
- ? Update::RecalculateStyle
- : Update::Repaint);
+const Layer* Style::getLayer(const std::string& layerID) const {
+ return impl->getLayer(layerID);
}
-void Style::onLightChanged(const Light&) {
- observer->onUpdate(Update::Classes | Update::RecalculateStyle);
+void Style::addLayer(std::unique_ptr<Layer> layer, const optional<std::string>& before) {
+ impl->mutated = true;
+ impl->addLayer(std::move(layer), before);
}
-void Style::dumpDebugLogs() const {
- for (const auto& source : sources) {
- source->baseImpl->dumpDebugLogs();
- }
-
- for (const auto& renderSource : renderSources) {
- renderSource->dumpDebugLogs();
- }
-
- spriteAtlas->dumpDebugLogs();
+std::unique_ptr<Layer> Style::removeLayer(const std::string& id) {
+ impl->mutated = true;
+ return impl->removeLayer(id);
}
} // namespace style
diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp
deleted file mode 100644
index 7d235dc665..0000000000
--- a/src/mbgl/style/style.hpp
+++ /dev/null
@@ -1,192 +0,0 @@
-#pragma once
-
-#include <mbgl/style/transition_options.hpp>
-#include <mbgl/style/observer.hpp>
-#include <mbgl/style/source_observer.hpp>
-#include <mbgl/renderer/render_source_observer.hpp>
-#include <mbgl/style/layer_observer.hpp>
-#include <mbgl/style/light_observer.hpp>
-#include <mbgl/style/update_batch.hpp>
-#include <mbgl/renderer/render_layer.hpp>
-#include <mbgl/renderer/render_light.hpp>
-#include <mbgl/text/glyph_atlas_observer.hpp>
-#include <mbgl/sprite/sprite_atlas_observer.hpp>
-#include <mbgl/map/mode.hpp>
-#include <mbgl/map/zoom_history.hpp>
-
-#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/util/chrono.hpp>
-#include <mbgl/util/optional.hpp>
-#include <mbgl/util/feature.hpp>
-#include <mbgl/util/geo.hpp>
-
-#include <cstdint>
-#include <memory>
-#include <string>
-#include <vector>
-
-namespace mbgl {
-
-class FileSource;
-class GlyphAtlas;
-class SpriteAtlas;
-class LineAtlas;
-class RenderData;
-class TransformState;
-class RenderedQueryOptions;
-class Scheduler;
-class RenderLayer;
-class RenderSource;
-class UpdateParameters;
-
-namespace style {
-
-class Layer;
-class QueryParameters;
-
-class Style : public GlyphAtlasObserver,
- public SpriteAtlasObserver,
- public SourceObserver,
- public RenderSourceObserver,
- public LayerObserver,
- public LightObserver,
- public util::noncopyable {
-public:
- Style(Scheduler&, FileSource&, float pixelRatio);
- ~Style() override;
-
- void setJSON(const std::string&);
-
- void setObserver(Observer*);
-
- bool isLoaded() const;
-
- void update(const UpdateParameters&);
-
- bool hasTransitions() const;
-
- std::exception_ptr getLastError() const {
- return lastError;
- }
-
- std::vector<const Source*> getSources() const;
- std::vector<Source*> getSources();
- Source* getSource(const std::string& id) const;
- void addSource(std::unique_ptr<Source>);
- std::unique_ptr<Source> removeSource(const std::string& sourceID);
-
- std::vector<const Layer*> getLayers() const;
- std::vector<Layer*> getLayers();
- Layer* getLayer(const std::string& id) const;
- Layer* addLayer(std::unique_ptr<Layer>,
- optional<std::string> beforeLayerID = {});
- std::unique_ptr<Layer> removeLayer(const std::string& layerID);
-
- // Should be moved to Impl eventually
- std::vector<const RenderLayer*> getRenderLayers() const;
- std::vector<RenderLayer*> getRenderLayers();
- RenderLayer* getRenderLayer(const std::string& id) const;
-
- std::string getName() const;
- LatLng getDefaultLatLng() const;
- double getDefaultZoom() const;
- double getDefaultBearing() const;
- double getDefaultPitch() const;
-
- bool addClass(const std::string&);
- bool removeClass(const std::string&);
- void setClasses(const std::vector<std::string>&);
-
- TransitionOptions getTransitionOptions() const;
- void setTransitionOptions(const TransitionOptions&);
-
- bool hasClass(const std::string&) const;
- std::vector<std::string> getClasses() const;
-
- void setLight(std::unique_ptr<Light>);
- Light* getLight() const;
- RenderLight* getRenderLight() const;
-
- RenderData getRenderData(MapDebugOptions, float angle) const;
-
- std::vector<Feature> queryRenderedFeatures(const ScreenLineString& geometry,
- const TransformState& transformState,
- const RenderedQueryOptions& options) const;
-
- void setSourceTileCacheSize(size_t);
- void onLowMemory();
-
- void dumpDebugLogs() const;
-
- Scheduler& scheduler;
- FileSource& fileSource;
- std::unique_ptr<GlyphAtlas> glyphAtlas;
- std::unique_ptr<SpriteAtlas> spriteAtlas;
- std::unique_ptr<LineAtlas> lineAtlas;
-
- RenderSource* getRenderSource(const std::string& id) const;
-
-private:
- std::vector<std::unique_ptr<Source>> sources;
- std::vector<std::unique_ptr<RenderSource>> renderSources;
-
- std::vector<std::unique_ptr<Layer>> layers;
- std::vector<std::unique_ptr<RenderLayer>> renderLayers;
- std::vector<std::string> classes;
- TransitionOptions transitionOptions;
-
- std::unique_ptr<Light> light;
- std::unique_ptr<RenderLight> renderLight;
-
- // Defaults
- std::string name;
- LatLng defaultLatLng;
- double defaultZoom = 0;
- double defaultBearing = 0;
- double defaultPitch = 0;
-
- std::vector<std::unique_ptr<Layer>>::const_iterator findLayer(const std::string& layerID) const;
- std::vector<std::unique_ptr<RenderLayer>>::const_iterator findRenderLayer(const std::string&) const;
-
- // GlyphStoreObserver implementation.
- void onGlyphsLoaded(const FontStack&, const GlyphRange&) override;
- void onGlyphsError(const FontStack&, const GlyphRange&, std::exception_ptr) override;
-
- // SpriteStoreObserver implementation.
- void onSpriteLoaded() override;
- void onSpriteError(std::exception_ptr) override;
-
- // SourceObserver implementation.
- void onSourceLoaded(Source&) override;
- void onSourceChanged(Source&) override;
- void onSourceError(Source&, std::exception_ptr) override;
- void onSourceDescriptionChanged(Source&) override;
- void onTileChanged(RenderSource&, const OverscaledTileID&) override;
- void onTileError(RenderSource&, const OverscaledTileID&, std::exception_ptr) override;
-
- // LayerObserver implementation.
- void onLayerFilterChanged(Layer&) override;
- void onLayerVisibilityChanged(Layer&) override;
- void onLayerPaintPropertyChanged(Layer&) override;
- void onLayerDataDrivenPaintPropertyChanged(Layer&) override;
- void onLayerLayoutPropertyChanged(Layer&, const char *) override;
-
- // LightObserver implementation.
- void onLightChanged(const Light&) override;
-
- Observer nullObserver;
- Observer* observer = &nullObserver;
-
- std::exception_ptr lastError;
-
- UpdateBatch updateBatch;
- ZoomHistory zoomHistory;
-
- void removeRenderLayer(const std::string& layerID);
-
-public:
- bool loaded = false;
-};
-
-} // namespace style
-} // namespace mbgl
diff --git a/src/mbgl/style/style_impl.cpp b/src/mbgl/style/style_impl.cpp
new file mode 100644
index 0000000000..2d42afd086
--- /dev/null
+++ b/src/mbgl/style/style_impl.cpp
@@ -0,0 +1,371 @@
+#include <mbgl/style/style_impl.hpp>
+#include <mbgl/style/observer.hpp>
+#include <mbgl/style/source_impl.hpp>
+#include <mbgl/style/layers/symbol_layer.hpp>
+#include <mbgl/style/layers/custom_layer.hpp>
+#include <mbgl/style/layers/background_layer.hpp>
+#include <mbgl/style/layers/fill_layer.hpp>
+#include <mbgl/style/layers/fill_extrusion_layer.hpp>
+#include <mbgl/style/layers/line_layer.hpp>
+#include <mbgl/style/layers/circle_layer.hpp>
+#include <mbgl/style/layers/raster_layer.hpp>
+#include <mbgl/style/layer_impl.hpp>
+#include <mbgl/style/parser.hpp>
+#include <mbgl/style/transition_options.hpp>
+#include <mbgl/sprite/sprite_loader.hpp>
+#include <mbgl/util/exception.hpp>
+#include <mbgl/util/string.hpp>
+#include <mbgl/util/logging.hpp>
+#include <mbgl/storage/file_source.hpp>
+#include <mbgl/storage/resource.hpp>
+#include <mbgl/storage/response.hpp>
+
+namespace mbgl {
+namespace style {
+
+static Observer nullObserver;
+
+Style::Impl::Impl(Scheduler& scheduler_, FileSource& fileSource_, float pixelRatio)
+ : scheduler(scheduler_),
+ fileSource(fileSource_),
+ spriteLoader(std::make_unique<SpriteLoader>(pixelRatio)),
+ light(std::make_unique<Light>()),
+ observer(&nullObserver) {
+ spriteLoader->setObserver(this);
+ light->setObserver(this);
+}
+
+Style::Impl::~Impl() = default;
+
+void Style::Impl::loadJSON(const std::string& json_) {
+ observer->onStyleLoading();
+
+ url.clear();
+ parse(json_);
+}
+
+void Style::Impl::loadURL(const std::string& url_) {
+ observer->onStyleLoading();
+
+ loaded = false;
+ url = url_;
+
+ styleRequest = fileSource.request(Resource::style(url), [this](Response res) {
+ // Once we get a fresh style, or the style is mutated, stop revalidating.
+ if (res.isFresh() || mutated) {
+ styleRequest.reset();
+ }
+
+ // Don't allow a loaded, mutated style to be overwritten with a new version.
+ if (mutated && loaded) {
+ return;
+ }
+
+ if (res.error) {
+ const std::string message = "loading style failed: " + res.error->message;
+ Log::Error(Event::Setup, message.c_str());
+ observer->onStyleError(std::make_exception_ptr(util::StyleLoadException(message)));
+ observer->onResourceError(std::make_exception_ptr(std::runtime_error(res.error->message)));
+ } else if (res.notModified || res.noContent) {
+ return;
+ } else {
+ parse(*res.data);
+ }
+ });
+}
+
+void Style::Impl::parse(const std::string& json_) {
+ Parser parser;
+
+ if (auto error = parser.parse(json_)) {
+ std::string message = "Failed to parse style: " + util::toString(error);
+ Log::Error(Event::ParseStyle, message.c_str());
+ observer->onStyleError(std::make_exception_ptr(util::StyleParseException(message)));
+ observer->onResourceError(error);
+ return;
+ }
+
+ mutated = false;
+ loaded = true;
+ json = json_;
+
+ sources.clear();
+ layers.clear();
+ images.clear();
+
+ transitionOptions = {};
+ transitionOptions.duration = util::DEFAULT_TRANSITION_DURATION;
+
+ for (auto& source : parser.sources) {
+ addSource(std::move(source));
+ }
+
+ for (auto& layer : parser.layers) {
+ addLayer(std::move(layer));
+ }
+
+ name = parser.name;
+ defaultLatLng = parser.latLng;
+ defaultZoom = parser.zoom;
+ defaultBearing = parser.bearing;
+ defaultPitch = parser.pitch;
+ setLight(std::make_unique<Light>(parser.light));
+
+ spriteLoader->load(parser.spriteURL, scheduler, fileSource);
+ glyphURL = parser.glyphURL;
+
+ observer->onStyleLoaded();
+}
+
+std::string Style::Impl::getJSON() const {
+ return json;
+}
+
+std::string Style::Impl::getURL() const {
+ return url;
+}
+
+void Style::Impl::setTransitionOptions(const TransitionOptions& options) {
+ transitionOptions = options;
+}
+
+TransitionOptions Style::Impl::getTransitionOptions() const {
+ return transitionOptions;
+}
+
+void Style::Impl::addSource(std::unique_ptr<Source> source) {
+ if (sources.get(source->getID())) {
+ std::string msg = "Source " + source->getID() + " already exists";
+ throw std::runtime_error(msg.c_str());
+ }
+
+ source->setObserver(this);
+ source->loadDescription(fileSource);
+
+ sources.add(std::move(source));
+}
+
+struct SourceIdUsageEvaluator {
+ const std::string& sourceId;
+
+ bool operator()(BackgroundLayer&) { return false; }
+ bool operator()(CustomLayer&) { return false; }
+
+ template <class LayerType>
+ bool operator()(LayerType& layer) {
+ return layer.getSourceID() == sourceId;
+ }
+};
+
+std::unique_ptr<Source> Style::Impl::removeSource(const std::string& id) {
+ // Check if source is in use
+ SourceIdUsageEvaluator sourceIdEvaluator {id};
+ auto layerIt = std::find_if(layers.begin(), layers.end(), [&](const auto& layer) {
+ return layer->accept(sourceIdEvaluator);
+ });
+
+ if (layerIt != layers.end()) {
+ Log::Warning(Event::General, "Source '%s' is in use, cannot remove", id.c_str());
+ return nullptr;
+ }
+
+ std::unique_ptr<Source> source = sources.remove(id);
+
+ if (source) {
+ source->setObserver(nullptr);
+ }
+
+ return source;
+}
+
+std::vector<Layer*> Style::Impl::getLayers() {
+ return layers.getWrappers();
+}
+
+std::vector<const Layer*> Style::Impl::getLayers() const {
+ auto wrappers = layers.getWrappers();
+ return std::vector<const Layer*>(wrappers.begin(), wrappers.end());
+}
+
+Layer* Style::Impl::getLayer(const std::string& id) const {
+ return layers.get(id);
+}
+
+Layer* Style::Impl::addLayer(std::unique_ptr<Layer> layer, optional<std::string> before) {
+ // TODO: verify source
+
+ if (layers.get(layer->getID())) {
+ throw std::runtime_error(std::string{"Layer "} + layer->getID() + " already exists");
+ }
+
+ layer->setObserver(this);
+ observer->onUpdate(Update::Repaint);
+
+ return layers.add(std::move(layer), before);
+}
+
+std::unique_ptr<Layer> Style::Impl::removeLayer(const std::string& id) {
+ std::unique_ptr<Layer> layer = layers.remove(id);
+
+ if (layer) {
+ layer->setObserver(nullptr);
+ observer->onUpdate(Update::Repaint);
+ }
+
+ return layer;
+}
+
+void Style::Impl::setLight(std::unique_ptr<Light> light_) {
+ light = std::move(light_);
+ light->setObserver(this);
+ onLightChanged(*light);
+}
+
+Light* Style::Impl::getLight() const {
+ return light.get();
+}
+
+std::string Style::Impl::getName() const {
+ return name;
+}
+
+LatLng Style::Impl::getDefaultLatLng() const {
+ return defaultLatLng;
+}
+
+double Style::Impl::getDefaultZoom() const {
+ return defaultZoom;
+}
+
+double Style::Impl::getDefaultBearing() const {
+ return defaultBearing;
+}
+
+double Style::Impl::getDefaultPitch() const {
+ return defaultPitch;
+}
+
+std::vector<Source*> Style::Impl::getSources() {
+ return sources.getWrappers();
+}
+
+std::vector<const Source*> Style::Impl::getSources() const {
+ auto wrappers = sources.getWrappers();
+ return std::vector<const Source*>(wrappers.begin(), wrappers.end());
+}
+
+Source* Style::Impl::getSource(const std::string& id) const {
+ return sources.get(id);
+}
+
+bool Style::Impl::isLoaded() const {
+ if (!loaded) {
+ return false;
+ }
+
+ if (!spriteLoaded) {
+ return false;
+ }
+
+ for (const auto& source: sources) {
+ if (!source->loaded) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void Style::Impl::addImage(std::unique_ptr<style::Image> image) {
+ images.remove(image->getID()); // We permit using addImage to update.
+ images.add(std::move(image));
+}
+
+void Style::Impl::removeImage(const std::string& id) {
+ images.remove(id);
+}
+
+const style::Image* Style::Impl::getImage(const std::string& id) const {
+ return images.get(id);
+}
+
+void Style::Impl::setObserver(style::Observer* observer_) {
+ observer = observer_;
+}
+
+void Style::Impl::onSourceLoaded(Source& source) {
+ sources.update(source);
+ observer->onSourceLoaded(source);
+ observer->onUpdate(Update::Repaint);
+}
+
+void Style::Impl::onSourceChanged(Source& source) {
+ sources.update(source);
+ observer->onSourceChanged(source);
+ observer->onUpdate(Update::Repaint);
+}
+
+void Style::Impl::onSourceError(Source& source, std::exception_ptr error) {
+ lastError = error;
+ Log::Error(Event::Style, "Failed to load source %s: %s",
+ source.getID().c_str(), util::toString(error).c_str());
+ observer->onSourceError(source, error);
+ observer->onResourceError(error);
+}
+
+void Style::Impl::onSourceDescriptionChanged(Source& source) {
+ sources.update(source);
+ observer->onSourceDescriptionChanged(source);
+ if (!source.loaded) {
+ source.loadDescription(fileSource);
+ }
+}
+
+void Style::Impl::onSpriteLoaded(std::vector<std::unique_ptr<Image>>&& images_) {
+ for (auto& image : images_) {
+ addImage(std::move(image));
+ }
+ spriteLoaded = true;
+ observer->onUpdate(Update::Repaint); // For *-pattern properties.
+}
+
+void Style::Impl::onSpriteError(std::exception_ptr error) {
+ lastError = error;
+ Log::Error(Event::Style, "Failed to load sprite: %s", util::toString(error).c_str());
+ observer->onResourceError(error);
+}
+
+void Style::Impl::onLayerChanged(Layer& layer) {
+ layers.update(layer);
+ observer->onUpdate(Update::Repaint);
+}
+
+void Style::Impl::onLightChanged(const Light&) {
+ observer->onUpdate(Update::Repaint);
+}
+
+void Style::Impl::dumpDebugLogs() const {
+ Log::Info(Event::General, "styleURL: %s", url.c_str());
+ for (const auto& source : sources) {
+ source->dumpDebugLogs();
+ }
+}
+
+const std::string& Style::Impl::getGlyphURL() const {
+ return glyphURL;
+}
+
+Immutable<std::vector<Immutable<Image::Impl>>> Style::Impl::getImageImpls() const {
+ return images.getImpls();
+}
+
+Immutable<std::vector<Immutable<Source::Impl>>> Style::Impl::getSourceImpls() const {
+ return sources.getImpls();
+}
+
+Immutable<std::vector<Immutable<Layer::Impl>>> Style::Impl::getLayerImpls() const {
+ return layers.getImpls();
+}
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/style_impl.hpp b/src/mbgl/style/style_impl.hpp
new file mode 100644
index 0000000000..76f244d5a4
--- /dev/null
+++ b/src/mbgl/style/style_impl.hpp
@@ -0,0 +1,148 @@
+#pragma once
+
+#include <mbgl/style/style.hpp>
+#include <mbgl/style/transition_options.hpp>
+#include <mbgl/style/observer.hpp>
+#include <mbgl/style/source_observer.hpp>
+#include <mbgl/style/layer_observer.hpp>
+#include <mbgl/style/light_observer.hpp>
+#include <mbgl/sprite/sprite_loader_observer.hpp>
+#include <mbgl/style/image.hpp>
+#include <mbgl/style/source.hpp>
+#include <mbgl/style/layer.hpp>
+#include <mbgl/style/collection.hpp>
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/optional.hpp>
+#include <mbgl/util/geo.hpp>
+
+#include <memory>
+#include <string>
+#include <vector>
+#include <unordered_map>
+
+namespace mbgl {
+
+class Scheduler;
+class FileSource;
+class AsyncRequest;
+class SpriteLoader;
+
+namespace style {
+
+class Style::Impl : public SpriteLoaderObserver,
+ public SourceObserver,
+ public LayerObserver,
+ public LightObserver,
+ public util::noncopyable {
+public:
+ Impl(Scheduler&, FileSource&, float pixelRatio);
+ ~Impl() override;
+
+ void loadJSON(const std::string&);
+ void loadURL(const std::string&);
+
+ std::string getJSON() const;
+ std::string getURL() const;
+
+ void setObserver(Observer*);
+
+ bool isLoaded() const;
+
+ std::exception_ptr getLastError() const {
+ return lastError;
+ }
+
+ std::vector< Source*> getSources();
+ std::vector<const Source*> getSources() const;
+ Source* getSource(const std::string& id) const;
+
+ void addSource(std::unique_ptr<Source>);
+ std::unique_ptr<Source> removeSource(const std::string& sourceID);
+
+ std::vector< Layer*> getLayers();
+ std::vector<const Layer*> getLayers() const;
+ Layer* getLayer(const std::string& id) const;
+
+ Layer* addLayer(std::unique_ptr<Layer>,
+ optional<std::string> beforeLayerID = {});
+ std::unique_ptr<Layer> removeLayer(const std::string& layerID);
+
+ std::string getName() const;
+ LatLng getDefaultLatLng() const;
+ double getDefaultZoom() const;
+ double getDefaultBearing() const;
+ double getDefaultPitch() const;
+
+ TransitionOptions getTransitionOptions() const;
+ void setTransitionOptions(const TransitionOptions&);
+
+ void setLight(std::unique_ptr<Light>);
+ Light* getLight() const;
+
+ const style::Image* getImage(const std::string&) const;
+ void addImage(std::unique_ptr<style::Image>);
+ void removeImage(const std::string&);
+
+ const std::string& getGlyphURL() const;
+
+ Immutable<std::vector<Immutable<Image::Impl>>> getImageImpls() const;
+ Immutable<std::vector<Immutable<Source::Impl>>> getSourceImpls() const;
+ Immutable<std::vector<Immutable<Layer::Impl>>> getLayerImpls() const;
+
+ void dumpDebugLogs() const;
+
+ bool mutated = false;
+ bool loaded = false;
+ bool spriteLoaded = false;
+
+private:
+ void parse(const std::string&);
+
+ Scheduler& scheduler;
+ FileSource& fileSource;
+
+ std::string url;
+ std::string json;
+
+ std::unique_ptr<AsyncRequest> styleRequest;
+ std::unique_ptr<SpriteLoader> spriteLoader;
+
+ std::string glyphURL;
+ Collection<style::Image> images;
+ Collection<Source> sources;
+ Collection<Layer> layers;
+ TransitionOptions transitionOptions;
+ std::unique_ptr<Light> light;
+
+ // Defaults
+ std::string name;
+ LatLng defaultLatLng;
+ double defaultZoom = 0;
+ double defaultBearing = 0;
+ double defaultPitch = 0;
+
+ // SpriteLoaderObserver implementation.
+ void onSpriteLoaded(std::vector<std::unique_ptr<Image>>&&) override;
+ void onSpriteError(std::exception_ptr) override;
+
+ // SourceObserver implementation.
+ void onSourceLoaded(Source&) override;
+ void onSourceChanged(Source&) override;
+ void onSourceError(Source&, std::exception_ptr) override;
+ void onSourceDescriptionChanged(Source&) override;
+
+ // LayerObserver implementation.
+ void onLayerChanged(Layer&) override;
+
+ // LightObserver implementation.
+ void onLightChanged(const Light&) override;
+
+ Observer nullObserver;
+ Observer* observer = &nullObserver;
+
+ std::exception_ptr lastError;
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/tile_source_impl.cpp b/src/mbgl/style/tile_source_impl.cpp
deleted file mode 100644
index d2ce3def9f..0000000000
--- a/src/mbgl/style/tile_source_impl.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-#include <mbgl/style/tile_source_impl.hpp>
-#include <mbgl/style/source_observer.hpp>
-#include <mbgl/style/conversion/json.hpp>
-#include <mbgl/style/conversion/tileset.hpp>
-#include <mbgl/util/mapbox.hpp>
-#include <mbgl/storage/file_source.hpp>
-
-namespace mbgl {
-namespace style {
-
-TileSourceImpl::TileSourceImpl(SourceType type_, std::string id_, Source& base_,
- variant<std::string, Tileset> urlOrTileset_,
- uint16_t tileSize_)
- : Impl(type_, std::move(id_), base_),
- urlOrTileset(std::move(urlOrTileset_)),
- tileSize(tileSize_) {
-}
-
-TileSourceImpl::~TileSourceImpl() = default;
-
-void TileSourceImpl::loadDescription(FileSource& fileSource) {
- if (urlOrTileset.is<Tileset>()) {
- tileset = urlOrTileset.get<Tileset>();
- loaded = true;
- return;
- }
-
- if (req) {
- return;
- }
-
- const std::string& url = urlOrTileset.get<std::string>();
- req = fileSource.request(Resource::source(url), [this, url](Response res) {
- if (res.error) {
- observer->onSourceError(base, std::make_exception_ptr(std::runtime_error(res.error->message)));
- } else if (res.notModified) {
- return;
- } else if (res.noContent) {
- observer->onSourceError(base, std::make_exception_ptr(std::runtime_error("unexpectedly empty TileJSON")));
- } else {
- conversion::Error error;
- optional<Tileset> newTileset = conversion::convertJSON<Tileset>(*res.data, error);
- if (!newTileset) {
- observer->onSourceError(base, std::make_exception_ptr(std::runtime_error(error.message)));
- return;
- }
-
- util::mapbox::canonicalizeTileset(*newTileset, url, type, tileSize);
- bool attributionChanged = tileset.attribution != (*newTileset).attribution;
-
- tileset = *newTileset;
- loaded = true;
-
- observer->onSourceLoaded(base);
- if (attributionChanged) {
- observer->onSourceChanged(base);
- }
- }
- });
-}
-
-optional<Tileset> TileSourceImpl::getTileset() const {
- if (loaded) {
- return tileset;
- }
- return {};
-}
-
-optional<std::string> TileSourceImpl::getAttribution() const {
- if (loaded && !tileset.attribution.empty()) {
- return tileset.attribution;
- } else {
- return {};
- }
-}
-
-} // namespace style
-} // namespace mbgl
diff --git a/src/mbgl/style/tile_source_impl.hpp b/src/mbgl/style/tile_source_impl.hpp
deleted file mode 100644
index 0e5a53add7..0000000000
--- a/src/mbgl/style/tile_source_impl.hpp
+++ /dev/null
@@ -1,47 +0,0 @@
-#pragma once
-
-#include <mbgl/style/source_impl.hpp>
-#include <mbgl/util/tileset.hpp>
-#include <mbgl/util/variant.hpp>
-#include <mbgl/util/optional.hpp>
-
-namespace mbgl {
-
-class AsyncRequest;
-
-namespace style {
-
-/*
- Shared implementation for VectorSource and RasterSource. Should eventually
- be refactored to use composition rather than inheritance.
-*/
-class TileSourceImpl : public Source::Impl {
-public:
- TileSourceImpl(SourceType, std::string id, Source&,
- variant<std::string, Tileset> urlOrTileset,
- uint16_t tileSize);
- ~TileSourceImpl() override;
-
- void loadDescription(FileSource&) final;
-
- uint16_t getTileSize() const {
- return tileSize;
- }
-
- const variant<std::string, Tileset>& getURLOrTileset() const {
- return urlOrTileset;
- }
-
- optional<std::string> getAttribution() const override;
- optional<Tileset> getTileset() const;
-
-protected:
- const variant<std::string, Tileset> urlOrTileset;
- const uint16_t tileSize;
-
- Tileset tileset;
- std::unique_ptr<AsyncRequest> req;
-};
-
-} // namespace style
-} // namespace mbgl
diff --git a/src/mbgl/style/types.cpp b/src/mbgl/style/types.cpp
index b37e73ffb1..4fbf767e11 100644
--- a/src/mbgl/style/types.cpp
+++ b/src/mbgl/style/types.cpp
@@ -11,6 +11,7 @@ MBGL_DEFINE_ENUM(SourceType, {
{ SourceType::GeoJSON, "geojson" },
{ SourceType::Video, "video" },
{ SourceType::Annotations, "annotations" },
+ { SourceType::Image, "image" },
});
MBGL_DEFINE_ENUM(VisibilityType, {
diff --git a/src/mbgl/style/update_batch.hpp b/src/mbgl/style/update_batch.hpp
deleted file mode 100644
index 562df52afa..0000000000
--- a/src/mbgl/style/update_batch.hpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#pragma once
-
-#include <unordered_set>
-#include <string>
-
-namespace mbgl {
-namespace style {
-
-class UpdateBatch {
-public:
- std::unordered_set<std::string> sourceIDs;
-};
-
-} // namespace style
-} // namespace mbgl
diff --git a/src/mbgl/text/collision_feature.cpp b/src/mbgl/text/collision_feature.cpp
index 885ba5c426..71d7cc74e0 100644
--- a/src/mbgl/text/collision_feature.cpp
+++ b/src/mbgl/text/collision_feature.cpp
@@ -71,7 +71,7 @@ void CollisionFeature::bboxifyLabel(const GeometryCoordinates& line, GeometryCoo
p = line[index];
} while (anchorDistance > -labelLength / 2);
- float segmentLength = util::dist<float>(line[index], line[index + 1]);
+ auto segmentLength = util::dist<float>(line[index], line[index + 1]);
for (unsigned int i = 0; i < nBoxes; i++) {
// the distance the box will be from the anchor
diff --git a/src/mbgl/text/collision_feature.hpp b/src/mbgl/text/collision_feature.hpp
index 006a47eb74..c94ec23513 100644
--- a/src/mbgl/text/collision_feature.hpp
+++ b/src/mbgl/text/collision_feature.hpp
@@ -34,7 +34,7 @@ public:
class CollisionFeature {
public:
enum class AlignmentType : bool {
- Straight = 0,
+ Straight = false,
Curved
};
diff --git a/src/mbgl/text/collision_tile.hpp b/src/mbgl/text/collision_tile.hpp
index ea4324edaf..bdacbb7437 100644
--- a/src/mbgl/text/collision_tile.hpp
+++ b/src/mbgl/text/collision_tile.hpp
@@ -17,6 +17,7 @@
#pragma GCC diagnostic ignored "-Wshorten-64-to-32"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#pragma GCC diagnostic ignored "-Wmisleading-indentation"
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/box.hpp>
@@ -28,10 +29,10 @@ namespace mbgl {
namespace bg = boost::geometry;
namespace bgm = bg::model;
namespace bgi = bg::index;
-typedef bgm::point<float, 2, bg::cs::cartesian> CollisionPoint;
-typedef bgm::box<CollisionPoint> Box;
-typedef std::tuple<Box, CollisionBox, IndexedSubfeature> CollisionTreeBox;
-typedef bgi::rtree<CollisionTreeBox, bgi::linear<16, 4>> Tree;
+using CollisionPoint = bgm::point<float, 2, bg::cs::cartesian>;
+using Box = bgm::box<CollisionPoint>;
+using CollisionTreeBox = std::tuple<Box, CollisionBox, IndexedSubfeature>;
+using Tree = bgi::rtree<CollisionTreeBox, bgi::linear<16, 4>>;
class IndexedSubfeature;
diff --git a/src/mbgl/text/get_anchors.cpp b/src/mbgl/text/get_anchors.cpp
index 82702b20f0..d41faf2a71 100644
--- a/src/mbgl/text/get_anchors.cpp
+++ b/src/mbgl/text/get_anchors.cpp
@@ -34,7 +34,7 @@ static Anchors resample(const GeometryCoordinates& line,
const GeometryCoordinate& a = *(it);
const GeometryCoordinate& b = *(it + 1);
- const float segmentDist = util::dist<float>(a, b);
+ const auto segmentDist = util::dist<float>(a, b);
const float angle = util::angle_to(b, a);
while (markedDistance + spacing < distance + segmentDist) {
diff --git a/src/mbgl/text/glyph.hpp b/src/mbgl/text/glyph.hpp
index 9cf39de840..b9eaedd302 100644
--- a/src/mbgl/text/glyph.hpp
+++ b/src/mbgl/text/glyph.hpp
@@ -5,6 +5,8 @@
#include <mbgl/util/rect.hpp>
#include <mbgl/util/traits.hpp>
#include <mbgl/util/optional.hpp>
+#include <mbgl/util/immutable.hpp>
+#include <mbgl/util/image.hpp>
#include <cstdint>
#include <vector>
@@ -13,8 +15,8 @@
namespace mbgl {
-typedef char16_t GlyphID;
-typedef std::set<GlyphID> GlyphIDs;
+using GlyphID = char16_t;
+using GlyphIDs = std::set<GlyphID>;
// Note: this only works for the BMP
GlyphRange getGlyphRange(GlyphID glyph);
@@ -35,13 +37,23 @@ inline bool operator==(const GlyphMetrics& lhs, const GlyphMetrics& rhs) {
lhs.advance == rhs.advance;
}
-struct Glyph {
- Rect<uint16_t> rect;
+class Glyph {
+public:
+ // We're using this value throughout the Mapbox GL ecosystem. If this is different, the glyphs
+ // also need to be reencoded.
+ static constexpr const uint8_t borderSize = 3;
+
+ GlyphID id = 0;
+
+ // A signed distance field of the glyph with a border (see above).
+ AlphaImage bitmap;
+
+ // Glyph metrics
GlyphMetrics metrics;
};
-typedef std::map<GlyphID, optional<Glyph>> GlyphPositions;
-typedef std::map<FontStack, GlyphPositions> GlyphPositionMap;
+using Glyphs = std::map<GlyphID, optional<Immutable<Glyph>>>;
+using GlyphMap = std::map<FontStack, Glyphs>;
class PositionedGlyph {
public:
@@ -58,14 +70,14 @@ enum class WritingModeType : uint8_t;
class Shaping {
public:
- explicit Shaping() : top(0), bottom(0), left(0), right(0) {}
+ explicit Shaping() = default;
explicit Shaping(float x, float y, WritingModeType writingMode_)
: top(y), bottom(y), left(x), right(x), writingMode(writingMode_) {}
std::vector<PositionedGlyph> positionedGlyphs;
- int32_t top;
- int32_t bottom;
- int32_t left;
- int32_t right;
+ int32_t top = 0;
+ int32_t bottom = 0;
+ int32_t left = 0;
+ int32_t right = 0;
WritingModeType writingMode;
explicit operator bool() const { return !positionedGlyphs.empty(); }
@@ -97,8 +109,7 @@ constexpr WritingModeType operator~(WritingModeType value) {
return WritingModeType(~mbgl::underlying_type(value));
}
-typedef std::map<FontStack,GlyphIDs> GlyphDependencies;
-typedef std::map<FontStack,GlyphRangeSet> GlyphRangeDependencies;
-
+using GlyphDependencies = std::map<FontStack,GlyphIDs>;
+using GlyphRangeDependencies = std::map<FontStack,GlyphRangeSet>;
} // end namespace mbgl
diff --git a/src/mbgl/text/glyph_atlas.cpp b/src/mbgl/text/glyph_atlas.cpp
index 4feaab01f9..1b98ea36bf 100644
--- a/src/mbgl/text/glyph_atlas.cpp
+++ b/src/mbgl/text/glyph_atlas.cpp
@@ -1,262 +1,65 @@
#include <mbgl/text/glyph_atlas.hpp>
-#include <mbgl/text/glyph_atlas_observer.hpp>
-#include <mbgl/text/glyph_pbf.hpp>
-#include <mbgl/gl/context.hpp>
-#include <mbgl/util/logging.hpp>
-#include <mbgl/util/platform.hpp>
-#include <mbgl/storage/file_source.hpp>
-#include <mbgl/storage/resource.hpp>
-#include <mbgl/storage/response.hpp>
-#include <cassert>
-#include <algorithm>
+#include <mapbox/shelf-pack.hpp>
namespace mbgl {
-static GlyphAtlasObserver nullObserver;
+static constexpr uint32_t padding = 1;
-GlyphAtlas::GlyphAtlas(const Size size, FileSource& fileSource_)
- : fileSource(fileSource_),
- observer(&nullObserver),
- bin(size.width, size.height),
- image(size),
- dirty(true) {
-}
-
-GlyphAtlas::~GlyphAtlas() = default;
-
-void GlyphAtlas::getGlyphs(GlyphRequestor& requestor, GlyphDependencies glyphDependencies) {
- auto dependencies = std::make_shared<GlyphDependencies>(std::move(glyphDependencies));
-
- // Figure out which glyph ranges need to be fetched. For each range that does need to
- // be fetched, record an entry mapping the requestor to a shared pointer containing the
- // dependencies. When the shared pointer becomes unique, we know that all the dependencies
- // for that requestor have been fetched, and can notify it of completion.
- for (const auto& dependency : *dependencies) {
- const FontStack& fontStack = dependency.first;
- Entry& entry = entries[fontStack];
-
- const GlyphIDs& glyphIDs = dependency.second;
- GlyphRangeSet ranges;
- for (const auto& glyphID : glyphIDs) {
- ranges.insert(getGlyphRange(glyphID));
- }
-
- for (const auto& range : ranges) {
- auto it = entry.ranges.find(range);
- if (it == entry.ranges.end() || !it->second.parsed) {
- GlyphRequest& request = requestRange(entry, fontStack, range);
- request.requestors[&requestor] = dependencies;
- }
- }
- }
-
- // If the shared dependencies pointer is already unique, then all dependent glyph ranges
- // have already been loaded. Send a notification immediately.
- if (dependencies.unique()) {
- addGlyphs(requestor, *dependencies);
- }
-}
-
-GlyphAtlas::GlyphRequest& GlyphAtlas::requestRange(Entry& entry, const FontStack& fontStack, const GlyphRange& range) {
- GlyphRequest& request = entry.ranges[range];
-
- if (request.req) {
- return request;
- }
-
- request.req = fileSource.request(Resource::glyphs(glyphURL, fontStack, range), [this, fontStack, range](Response res) {
- processResponse(res, fontStack, range);
- });
+GlyphAtlas makeGlyphAtlas(const GlyphMap& glyphs) {
+ GlyphAtlas result;
- return request;
-}
+ mapbox::ShelfPack::ShelfPackOptions options;
+ options.autoResize = true;
+ mapbox::ShelfPack pack(0, 0, options);
-void GlyphAtlas::processResponse(const Response& res, const FontStack& fontStack, const GlyphRange& range) {
- if (res.error) {
- observer->onGlyphsError(fontStack, range, std::make_exception_ptr(std::runtime_error(res.error->message)));
- return;
- }
+ for (const auto& glyphMapEntry : glyphs) {
+ const FontStack& fontStack = glyphMapEntry.first;
+ GlyphPositionMap& positions = result.positions[fontStack];
- if (res.notModified) {
- return;
- }
+ for (const auto& entry : glyphMapEntry.second) {
+ if (entry.second && (*entry.second)->bitmap.valid()) {
+ const Glyph& glyph = **entry.second;
- Entry& entry = entries[fontStack];
- GlyphRequest& request = entry.ranges[range];
+ const mapbox::Bin& bin = *pack.packOne(-1,
+ glyph.bitmap.size.width + 2 * padding,
+ glyph.bitmap.size.height + 2 * padding);
- if (!res.noContent) {
- std::vector<SDFGlyph> glyphs;
-
- try {
- glyphs = parseGlyphPBF(range, *res.data);
- } catch (...) {
- observer->onGlyphsError(fontStack, range, std::current_exception());
- return;
- }
-
- for (auto& glyph : glyphs) {
- auto it = entry.glyphs.find(glyph.id);
- if (it == entry.glyphs.end()) {
- // Glyph doesn't exist yet.
- entry.glyphs.emplace(glyph.id, GlyphValue {
- std::move(glyph.bitmap),
- std::move(glyph.metrics),
- {}, {}
+ result.image.resize({
+ static_cast<uint32_t>(pack.width()),
+ static_cast<uint32_t>(pack.height())
});
- } else if (it->second.metrics == glyph.metrics) {
- if (it->second.bitmap != glyph.bitmap) {
- // The actual bitmap was updated; this is unsupported.
- Log::Warning(Event::Glyph, "Modified glyph changed bitmap represenation");
- }
- // At least try to update it in case it's currently unused.
- // If it is already used, we won't attempt to update the glyph atlas texture.
- it->second.bitmap = std::move(glyph.bitmap);
- } else {
- // The metrics were updated; this is unsupported.
- Log::Warning(Event::Glyph, "Modified glyph has different metrics");
- return;
- }
- }
- }
-
- request.parsed = true;
-
- for (auto& pair : request.requestors) {
- GlyphRequestor& requestor = *pair.first;
- const std::shared_ptr<GlyphDependencies>& dependencies = pair.second;
- if (dependencies.unique()) {
- addGlyphs(requestor, *dependencies);
- }
- }
-
- request.requestors.clear();
-
- observer->onGlyphsLoaded(fontStack, range);
-}
-
-void GlyphAtlas::setObserver(GlyphAtlasObserver* observer_) {
- observer = observer_ ? observer_ : &nullObserver;
-}
-void GlyphAtlas::addGlyphs(GlyphRequestor& requestor, const GlyphDependencies& glyphDependencies) {
- GlyphPositionMap glyphPositions;
-
- for (const auto& dependency : glyphDependencies) {
- const FontStack& fontStack = dependency.first;
- const GlyphIDs& glyphIDs = dependency.second;
-
- GlyphPositions& positions = glyphPositions[fontStack];
- Entry& entry = entries[fontStack];
-
- for (const auto& glyphID : glyphIDs) {
- // Make a glyph position entry even if we didn't get an SDF for the glyph. During layout,
- // an empty optional is treated as "loaded but nothing to show", wheras no entry in the
- // positions map means "not loaded yet".
- optional<Glyph>& glyph = positions[glyphID];
-
- auto it = entry.glyphs.find(glyphID);
- if (it == entry.glyphs.end())
- continue;
-
- it->second.ids.insert(&requestor);
-
- glyph = Glyph {
- addGlyph(it->second),
- it->second.metrics
- };
- }
- }
-
- requestor.onGlyphsAvailable(glyphPositions);
-}
-
-Rect<uint16_t> GlyphAtlas::addGlyph(GlyphValue& value) {
- // The glyph is already in this texture.
- if (value.rect) {
- return *value.rect;
- }
-
- // We don't need to add glyphs without a bitmap (e.g. whitespace).
- if (!value.bitmap.valid()) {
- return {};
- }
-
- // Add a 1px border around every image.
- const uint32_t padding = 1;
- uint16_t width = value.bitmap.size.width + 2 * padding;
- uint16_t height = value.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.
- width += (4 - width % 4);
- height += (4 - height % 4);
-
- Rect<uint16_t> rect = bin.allocate(width, height);
- if (rect.w == 0) {
- Log::Error(Event::OpenGL, "glyph bitmap overflow");
- return {};
- }
-
- AlphaImage::copy(value.bitmap, image, { 0, 0 }, { rect.x + padding, rect.y + padding }, value.bitmap.size);
- value.rect = rect;
- dirty = true;
-
- return rect;
-}
-
-void GlyphAtlas::removeGlyphValues(GlyphRequestor& requestor, std::map<GlyphID, GlyphValue>& values) {
- for (auto it = values.begin(); it != values.end(); it++) {
- GlyphValue& value = it->second;
- if (value.ids.erase(&requestor) && value.ids.empty() && value.rect) {
- const Rect<uint16_t>& rect = *value.rect;
-
- // Clear out the bitmap.
- uint8_t *target = image.data.get();
- for (uint32_t y = 0; y < rect.h; y++) {
- uint32_t y1 = image.size.width * (rect.y + y) + rect.x;
- for (uint32_t x = 0; x < rect.w; x++) {
- target[y1 + x] = 0;
- }
+ AlphaImage::copy(glyph.bitmap,
+ result.image,
+ { 0, 0 },
+ {
+ bin.x + padding,
+ bin.y + padding
+ },
+ glyph.bitmap.size);
+
+ positions.emplace(glyph.id,
+ GlyphPosition {
+ Rect<uint16_t> {
+ static_cast<uint16_t>(bin.x),
+ static_cast<uint16_t>(bin.y),
+ static_cast<uint16_t>(bin.w),
+ static_cast<uint16_t>(bin.h)
+ },
+ glyph.metrics
+ });
}
-
- bin.release(rect);
- value.rect = {};
}
}
-}
-
-void GlyphAtlas::removePendingRanges(mbgl::GlyphRequestor& requestor, std::map<GlyphRange, GlyphRequest>& ranges) {
- for (auto it = ranges.begin(); it != ranges.end(); it++) {
- it->second.requestors.erase(&requestor);
- }
-}
-void GlyphAtlas::removeGlyphs(GlyphRequestor& requestor) {
- for (auto& entry : entries) {
- removeGlyphValues(requestor, entry.second.glyphs);
- removePendingRanges(requestor, entry.second.ranges);
- }
-}
-
-Size GlyphAtlas::getSize() const {
- return image.size;
-}
-
-void GlyphAtlas::upload(gl::Context& context, gl::TextureUnit unit) {
- if (!texture) {
- texture = context.createTexture(image, unit);
- } else if (dirty) {
- context.updateTexture(*texture, image, unit);
- }
-
- dirty = false;
-}
+ pack.shrink();
+ result.image.resize({
+ static_cast<uint32_t>(pack.width()),
+ static_cast<uint32_t>(pack.height())
+ });
-void GlyphAtlas::bind(gl::Context& context, gl::TextureUnit unit) {
- upload(context, unit);
- context.bindTexture(*texture, unit, gl::TextureFilter::Linear);
+ return result;
}
} // namespace mbgl
diff --git a/src/mbgl/text/glyph_atlas.hpp b/src/mbgl/text/glyph_atlas.hpp
index ad9cf35adc..bb9115e4b4 100644
--- a/src/mbgl/text/glyph_atlas.hpp
+++ b/src/mbgl/text/glyph_atlas.hpp
@@ -1,110 +1,25 @@
#pragma once
#include <mbgl/text/glyph.hpp>
-#include <mbgl/text/glyph_atlas_observer.hpp>
-#include <mbgl/text/glyph_range.hpp>
-#include <mbgl/geometry/binpack.hpp>
-#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/util/optional.hpp>
-#include <mbgl/util/font_stack.hpp>
-#include <mbgl/util/work_queue.hpp>
-#include <mbgl/util/image.hpp>
-#include <mbgl/gl/texture.hpp>
-#include <mbgl/gl/object.hpp>
-#include <string>
-#include <unordered_set>
-#include <unordered_map>
-
-class GlyphAtlasTest;
+#include <mapbox/shelf-pack.hpp>
namespace mbgl {
-class FileSource;
-class AsyncRequest;
-class Response;
-
-namespace gl {
-class Context;
-} // namespace gl
-
-class GlyphRequestor {
-public:
- virtual ~GlyphRequestor() = default;
- virtual void onGlyphsAvailable(GlyphPositionMap) = 0;
+struct GlyphPosition {
+ Rect<uint16_t> rect;
+ GlyphMetrics metrics;
};
-
-class GlyphAtlas : public util::noncopyable {
-public:
- GlyphAtlas(Size, FileSource&);
- ~GlyphAtlas();
-
- // Workers send a `getGlyphs` message to the main thread once they have determined
- // which glyphs they will need. Invoking this method will increment reference
- // counts for all the glyphs in `GlyphDependencies`. If all glyphs are already
- // locally available, the observer will be notified that the glyphs are available
- // immediately. Otherwise, a request on the FileSource is made, and when all glyphs
- // are parsed and added to the atlas, the observer will be notified.
- // Workers are given a copied 'GlyphPositions' map to use for placing their glyphs.
- // The positions specified in this object are guaranteed to be
- // valid for the lifetime of the tile.
- void getGlyphs(GlyphRequestor&, GlyphDependencies);
- void removeGlyphs(GlyphRequestor&);
-
- void setURL(const std::string& url) {
- glyphURL = url;
- }
-
- void setObserver(GlyphAtlasObserver*);
-
- // Binds the atlas texture to the GPU, and uploads data if it is out of date.
- void bind(gl::Context&, gl::TextureUnit unit);
-
- // 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);
-
- Size getSize() const;
-private:
- FileSource& fileSource;
- std::string glyphURL;
+using GlyphPositionMap = std::map<GlyphID, GlyphPosition>;
+using GlyphPositions = std::map<FontStack, GlyphPositionMap>;
- struct GlyphValue {
- AlphaImage bitmap;
- GlyphMetrics metrics;
- optional<Rect<uint16_t>> rect;
- std::unordered_set<GlyphRequestor*> ids;
- };
-
- struct GlyphRequest {
- bool parsed = false;
- std::unique_ptr<AsyncRequest> req;
- std::unordered_map<GlyphRequestor*, std::shared_ptr<GlyphDependencies>> requestors;
- };
-
- struct Entry {
- std::map<GlyphRange, GlyphRequest> ranges;
- std::map<GlyphID, GlyphValue> glyphs;
- };
-
- std::unordered_map<FontStack, Entry, FontStackHash> entries;
-
- GlyphRequest& requestRange(Entry&, const FontStack&, const GlyphRange&);
- void processResponse(const Response&, const FontStack&, const GlyphRange&);
-
- void addGlyphs(GlyphRequestor&, const GlyphDependencies&);
- Rect<uint16_t> addGlyph(GlyphValue&);
-
- void removeGlyphValues(GlyphRequestor&, std::map<GlyphID, GlyphValue>&);
- void removePendingRanges(GlyphRequestor&, std::map<GlyphRange, GlyphRequest>&);
-
- GlyphAtlasObserver* observer = nullptr;
-
- BinPack<uint16_t> bin;
+class GlyphAtlas {
+public:
AlphaImage image;
- bool dirty;
- mbgl::optional<gl::Texture> texture;
+ GlyphPositions positions;
};
+GlyphAtlas makeGlyphAtlas(const GlyphMap&);
+
} // namespace mbgl
diff --git a/src/mbgl/text/glyph_manager.cpp b/src/mbgl/text/glyph_manager.cpp
new file mode 100644
index 0000000000..916d39ae62
--- /dev/null
+++ b/src/mbgl/text/glyph_manager.cpp
@@ -0,0 +1,145 @@
+#include <mbgl/text/glyph_manager.hpp>
+#include <mbgl/text/glyph_manager_observer.hpp>
+#include <mbgl/text/glyph_pbf.hpp>
+#include <mbgl/storage/file_source.hpp>
+#include <mbgl/storage/resource.hpp>
+#include <mbgl/storage/response.hpp>
+
+namespace mbgl {
+
+static GlyphManagerObserver nullObserver;
+
+GlyphManager::GlyphManager(FileSource& fileSource_)
+ : fileSource(fileSource_),
+ observer(&nullObserver) {
+}
+
+GlyphManager::~GlyphManager() = default;
+
+void GlyphManager::getGlyphs(GlyphRequestor& requestor, GlyphDependencies glyphDependencies) {
+ auto dependencies = std::make_shared<GlyphDependencies>(std::move(glyphDependencies));
+
+ // Figure out which glyph ranges need to be fetched. For each range that does need to
+ // be fetched, record an entry mapping the requestor to a shared pointer containing the
+ // dependencies. When the shared pointer becomes unique, we know that all the dependencies
+ // for that requestor have been fetched, and can notify it of completion.
+ for (const auto& dependency : *dependencies) {
+ const FontStack& fontStack = dependency.first;
+ Entry& entry = entries[fontStack];
+
+ const GlyphIDs& glyphIDs = dependency.second;
+ GlyphRangeSet ranges;
+ for (const auto& glyphID : glyphIDs) {
+ ranges.insert(getGlyphRange(glyphID));
+ }
+
+ for (const auto& range : ranges) {
+ auto it = entry.ranges.find(range);
+ if (it == entry.ranges.end() || !it->second.parsed) {
+ GlyphRequest& request = requestRange(entry, fontStack, range);
+ request.requestors[&requestor] = dependencies;
+ }
+ }
+ }
+
+ // If the shared dependencies pointer is already unique, then all dependent glyph ranges
+ // have already been loaded. Send a notification immediately.
+ if (dependencies.unique()) {
+ notify(requestor, *dependencies);
+ }
+}
+
+GlyphManager::GlyphRequest& GlyphManager::requestRange(Entry& entry, const FontStack& fontStack, const GlyphRange& range) {
+ GlyphRequest& request = entry.ranges[range];
+
+ if (request.req) {
+ return request;
+ }
+
+ request.req = fileSource.request(Resource::glyphs(glyphURL, fontStack, range), [this, fontStack, range](Response res) {
+ processResponse(res, fontStack, range);
+ });
+
+ return request;
+}
+
+void GlyphManager::processResponse(const Response& res, const FontStack& fontStack, const GlyphRange& range) {
+ if (res.error) {
+ observer->onGlyphsError(fontStack, range, std::make_exception_ptr(std::runtime_error(res.error->message)));
+ return;
+ }
+
+ if (res.notModified) {
+ return;
+ }
+
+ Entry& entry = entries[fontStack];
+ GlyphRequest& request = entry.ranges[range];
+
+ if (!res.noContent) {
+ std::vector<Glyph> glyphs;
+
+ try {
+ glyphs = parseGlyphPBF(range, *res.data);
+ } catch (...) {
+ observer->onGlyphsError(fontStack, range, std::current_exception());
+ return;
+ }
+
+ for (auto& glyph : glyphs) {
+ entry.glyphs.erase(glyph.id);
+ entry.glyphs.emplace(glyph.id, makeMutable<Glyph>(std::move(glyph)));
+ }
+ }
+
+ request.parsed = true;
+
+ for (auto& pair : request.requestors) {
+ GlyphRequestor& requestor = *pair.first;
+ const std::shared_ptr<GlyphDependencies>& dependencies = pair.second;
+ if (dependencies.unique()) {
+ notify(requestor, *dependencies);
+ }
+ }
+
+ request.requestors.clear();
+
+ observer->onGlyphsLoaded(fontStack, range);
+}
+
+void GlyphManager::setObserver(GlyphManagerObserver* observer_) {
+ observer = observer_ ? observer_ : &nullObserver;
+}
+
+void GlyphManager::notify(GlyphRequestor& requestor, const GlyphDependencies& glyphDependencies) {
+ GlyphMap response;
+
+ for (const auto& dependency : glyphDependencies) {
+ const FontStack& fontStack = dependency.first;
+ const GlyphIDs& glyphIDs = dependency.second;
+
+ Glyphs& glyphs = response[fontStack];
+ Entry& entry = entries[fontStack];
+
+ for (const auto& glyphID : glyphIDs) {
+ auto it = entry.glyphs.find(glyphID);
+ if (it != entry.glyphs.end()) {
+ glyphs.emplace(*it);
+ } else {
+ glyphs.emplace(glyphID, std::experimental::nullopt);
+ }
+ }
+ }
+
+ requestor.onGlyphsAvailable(response);
+}
+
+void GlyphManager::removeRequestor(GlyphRequestor& requestor) {
+ for (auto& entry : entries) {
+ for (auto& range : entry.second.ranges) {
+ range.second.requestors.erase(&requestor);
+ }
+ }
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/text/glyph_manager.hpp b/src/mbgl/text/glyph_manager.hpp
new file mode 100644
index 0000000000..00df079462
--- /dev/null
+++ b/src/mbgl/text/glyph_manager.hpp
@@ -0,0 +1,68 @@
+#pragma once
+
+#include <mbgl/text/glyph.hpp>
+#include <mbgl/text/glyph_manager_observer.hpp>
+#include <mbgl/text/glyph_range.hpp>
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/font_stack.hpp>
+#include <mbgl/util/immutable.hpp>
+
+#include <string>
+#include <unordered_map>
+
+namespace mbgl {
+
+class FileSource;
+class AsyncRequest;
+class Response;
+
+class GlyphRequestor {
+public:
+ virtual ~GlyphRequestor() = default;
+ virtual void onGlyphsAvailable(GlyphMap) = 0;
+};
+
+class GlyphManager : public util::noncopyable {
+public:
+ GlyphManager(FileSource&);
+ ~GlyphManager();
+
+ // Workers send a `getGlyphs` message to the main thread once they have determined
+ // their `GlyphDependencies`. If all glyphs are already locally available, GlyphManager
+ // will provide them to the requestor immediately. Otherwise, it makes a request on the
+ // FileSource is made for each range neeed, and notifies the observer when all are
+ // complete.
+ void getGlyphs(GlyphRequestor&, GlyphDependencies);
+ void removeRequestor(GlyphRequestor&);
+
+ void setURL(const std::string& url) {
+ glyphURL = url;
+ }
+
+ void setObserver(GlyphManagerObserver*);
+
+private:
+ FileSource& fileSource;
+ std::string glyphURL;
+
+ struct GlyphRequest {
+ bool parsed = false;
+ std::unique_ptr<AsyncRequest> req;
+ std::unordered_map<GlyphRequestor*, std::shared_ptr<GlyphDependencies>> requestors;
+ };
+
+ struct Entry {
+ std::map<GlyphRange, GlyphRequest> ranges;
+ std::map<GlyphID, Immutable<Glyph>> glyphs;
+ };
+
+ std::unordered_map<FontStack, Entry, FontStackHash> entries;
+
+ GlyphRequest& requestRange(Entry&, const FontStack&, const GlyphRange&);
+ void processResponse(const Response&, const FontStack&, const GlyphRange&);
+ void notify(GlyphRequestor&, const GlyphDependencies&);
+
+ GlyphManagerObserver* observer = nullptr;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/text/glyph_atlas_observer.hpp b/src/mbgl/text/glyph_manager_observer.hpp
index 9841017117..b8678e060a 100644
--- a/src/mbgl/text/glyph_atlas_observer.hpp
+++ b/src/mbgl/text/glyph_manager_observer.hpp
@@ -8,9 +8,9 @@
namespace mbgl {
-class GlyphAtlasObserver {
+class GlyphManagerObserver {
public:
- virtual ~GlyphAtlasObserver() = default;
+ virtual ~GlyphManagerObserver() = default;
virtual void onGlyphsLoaded(const FontStack&, const GlyphRange&) {}
virtual void onGlyphsError(const FontStack&, const GlyphRange&, std::exception_ptr) {}
diff --git a/src/mbgl/text/glyph_pbf.cpp b/src/mbgl/text/glyph_pbf.cpp
index 033f50fe9c..cfaf803f75 100644
--- a/src/mbgl/text/glyph_pbf.cpp
+++ b/src/mbgl/text/glyph_pbf.cpp
@@ -4,8 +4,8 @@
namespace mbgl {
-std::vector<SDFGlyph> parseGlyphPBF(const GlyphRange& glyphRange, const std::string& data) {
- std::vector<SDFGlyph> result;
+std::vector<Glyph> parseGlyphPBF(const GlyphRange& glyphRange, const std::string& data) {
+ std::vector<Glyph> result;
result.reserve(256);
protozero::pbf_reader glyphs_pbf(data);
@@ -15,7 +15,7 @@ std::vector<SDFGlyph> parseGlyphPBF(const GlyphRange& glyphRange, const std::str
while (fontstack_pbf.next(3)) {
auto glyph_pbf = fontstack_pbf.get_message();
- SDFGlyph glyph;
+ Glyph glyph;
protozero::data_view glyphData;
bool hasID = false, hasWidth = false, hasHeight = false, hasLeft = false,
@@ -73,8 +73,8 @@ std::vector<SDFGlyph> parseGlyphPBF(const GlyphRange& glyphRange, const std::str
// with the implicit border size, otherwise we expect there to be no bitmap at all.
if (glyph.metrics.width && glyph.metrics.height) {
const Size size {
- glyph.metrics.width + 2 * SDFGlyph::borderSize,
- glyph.metrics.height + 2 * SDFGlyph::borderSize
+ glyph.metrics.width + 2 * Glyph::borderSize,
+ glyph.metrics.height + 2 * Glyph::borderSize
};
if (size.area() != glyphData.size()) {
diff --git a/src/mbgl/text/glyph_pbf.hpp b/src/mbgl/text/glyph_pbf.hpp
index 162aeed93a..28a28b4114 100644
--- a/src/mbgl/text/glyph_pbf.hpp
+++ b/src/mbgl/text/glyph_pbf.hpp
@@ -2,28 +2,12 @@
#include <mbgl/text/glyph.hpp>
#include <mbgl/text/glyph_range.hpp>
-#include <mbgl/util/image.hpp>
#include <string>
#include <vector>
namespace mbgl {
-class SDFGlyph {
-public:
- // We're using this value throughout the Mapbox GL ecosystem. If this is different, the glyphs
- // also need to be reencoded.
- static constexpr const uint8_t borderSize = 3;
-
- GlyphID id = 0;
-
- // A signed distance field of the glyph with a border (see above).
- AlphaImage bitmap;
-
- // Glyph metrics
- GlyphMetrics metrics;
-};
-
-std::vector<SDFGlyph> parseGlyphPBF(const GlyphRange&, const std::string& data);
+std::vector<Glyph> parseGlyphPBF(const GlyphRange&, const std::string& data);
} // namespace mbgl
diff --git a/src/mbgl/text/glyph_range.hpp b/src/mbgl/text/glyph_range.hpp
index dd39e092b7..74afb73dfc 100644
--- a/src/mbgl/text/glyph_range.hpp
+++ b/src/mbgl/text/glyph_range.hpp
@@ -7,7 +7,7 @@
namespace mbgl {
-typedef std::pair<uint16_t, uint16_t> GlyphRange;
+using GlyphRange = std::pair<uint16_t, uint16_t>;
struct GlyphRangeHash {
std::size_t operator()(const GlyphRange& glyphRange) const {
@@ -15,7 +15,7 @@ struct GlyphRangeHash {
}
};
-typedef std::unordered_set<GlyphRange, GlyphRangeHash> GlyphRangeSet;
+using GlyphRangeSet = std::unordered_set<GlyphRange, GlyphRangeHash>;
constexpr uint32_t GLYPHS_PER_GLYPH_RANGE = 256;
constexpr uint32_t GLYPH_RANGES_PER_FONT_STACK = 256;
diff --git a/src/mbgl/text/quads.cpp b/src/mbgl/text/quads.cpp
index e1a9699835..ab10c5a6b7 100644
--- a/src/mbgl/text/quads.cpp
+++ b/src/mbgl/text/quads.cpp
@@ -22,13 +22,17 @@ SymbolQuad getIconQuad(const Anchor& anchor,
const float layoutTextSize,
const style::SymbolPlacementType placement,
const Shaping& shapedText) {
- auto image = *shapedIcon.image();
+ const ImagePosition& image = shapedIcon.image();
+ // If you have a 10px icon that isn't perfectly aligned to the pixel grid it will cover 11 actual
+ // pixels. The quad needs to be padded to account for this, otherwise they'll look slightly clipped
+ // on one edge in some cases.
const float border = 1.0;
- auto left = shapedIcon.left() - border;
- auto right = left + image.pos.w / image.relativePixelRatio;
- auto top = shapedIcon.top() - border;
- auto bottom = top + image.pos.h / image.relativePixelRatio;
+
+ float top = shapedIcon.top() - border / image.pixelRatio;
+ float left = shapedIcon.left() - border / image.pixelRatio;
+ float bottom = shapedIcon.bottom() + border / image.pixelRatio;
+ float right = shapedIcon.right() + border / image.pixelRatio;
Point<float> tl;
Point<float> tr;
Point<float> br;
@@ -92,7 +96,15 @@ SymbolQuad getIconQuad(const Anchor& anchor,
br = util::matrixMultiply(matrix, br);
}
- return SymbolQuad { tl, tr, bl, br, image.pos, 0, 0, anchor.point, globalMinScale, std::numeric_limits<float>::infinity(), shapedText.writingMode };
+ // Icon quad is padded, so texture coordinates also need to be padded.
+ Rect<uint16_t> textureRect {
+ static_cast<uint16_t>(image.textureRect.x - border),
+ static_cast<uint16_t>(image.textureRect.y - border),
+ static_cast<uint16_t>(image.textureRect.w + border * 2),
+ static_cast<uint16_t>(image.textureRect.h + border * 2)
+ };
+
+ return SymbolQuad { tl, tr, bl, br, textureRect, 0, 0, anchor.point, globalMinScale, std::numeric_limits<float>::infinity(), shapedText.writingMode };
}
struct GlyphInstance {
@@ -108,7 +120,7 @@ struct GlyphInstance {
const float angle = 0.0f;
};
-typedef std::vector<GlyphInstance> GlyphInstances;
+using GlyphInstances = std::vector<GlyphInstance>;
struct VirtualSegment {
Point<float> anchor;
@@ -177,7 +189,7 @@ inline Point<float> getVirtualSegmentAnchor(const Point<float>& segmentBegin, co
inline float getMinScaleForSegment(const float glyphDistanceFromAnchor,
const Point<float>& segmentAnchor,
const Point<float>& segmentEnd) {
- const float distanceFromAnchorToEnd = util::dist<float>(segmentAnchor, segmentEnd);
+ const auto distanceFromAnchorToEnd = util::dist<float>(segmentAnchor, segmentEnd);
return glyphDistanceFromAnchor / distanceFromAnchorToEnd;
}
@@ -295,18 +307,18 @@ SymbolQuads getGlyphQuads(Anchor& anchor,
const GeometryCoordinates& line,
const SymbolLayoutProperties::Evaluated& layout,
const style::SymbolPlacementType placement,
- const GlyphPositions& face) {
+ const GlyphPositionMap& positions) {
const float textRotate = layout.get<TextRotate>() * util::DEG2RAD;
const bool keepUpright = layout.get<TextKeepUpright>();
SymbolQuads quads;
for (const PositionedGlyph &positionedGlyph: shapedText.positionedGlyphs) {
- auto face_it = face.find(positionedGlyph.glyph);
- if (face_it == face.end() || !face_it->second || !(*face_it->second).rect.hasArea())
+ auto positionsIt = positions.find(positionedGlyph.glyph);
+ if (positionsIt == positions.end())
continue;
- const Glyph& glyph = *face_it->second;
+ const GlyphPosition& glyph = positionsIt->second;
const Rect<uint16_t>& rect = glyph.rect;
const float centerX = (positionedGlyph.x + glyph.metrics.advance / 2.0f) * boxScale;
diff --git a/src/mbgl/text/quads.hpp b/src/mbgl/text/quads.hpp
index 333000627b..b29f6b0ad3 100644
--- a/src/mbgl/text/quads.hpp
+++ b/src/mbgl/text/quads.hpp
@@ -1,6 +1,6 @@
#pragma once
-#include <mbgl/text/glyph.hpp>
+#include <mbgl/text/glyph_atlas.hpp>
#include <mbgl/style/types.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
@@ -49,7 +49,7 @@ public:
WritingModeType writingMode;
};
-typedef std::vector<SymbolQuad> SymbolQuads;
+using SymbolQuads = std::vector<SymbolQuad>;
SymbolQuad getIconQuad(const Anchor& anchor,
const PositionedIcon& shapedIcon,
@@ -65,6 +65,6 @@ SymbolQuads getGlyphQuads(Anchor& anchor,
const GeometryCoordinates& line,
const style::SymbolLayoutProperties::Evaluated&,
style::SymbolPlacementType placement,
- const GlyphPositions& face);
+ const GlyphPositionMap& positions);
} // namespace mbgl
diff --git a/src/mbgl/text/shaping.cpp b/src/mbgl/text/shaping.cpp
index 78aa142c61..338abe2e43 100644
--- a/src/mbgl/text/shaping.cpp
+++ b/src/mbgl/text/shaping.cpp
@@ -10,19 +10,15 @@
namespace mbgl {
-optional<PositionedIcon> PositionedIcon::shapeIcon(const SpriteAtlasElement& image, const std::array<float, 2>& iconOffset, const float iconRotation) {
- if (!image.pos.hasArea()) {
- return {};
- }
-
+PositionedIcon PositionedIcon::shapeIcon(const ImagePosition& image, const std::array<float, 2>& iconOffset, const float iconRotation) {
float dx = iconOffset[0];
float dy = iconOffset[1];
- float x1 = dx - image.width/ 2.0f;
- float x2 = x1 + image.width;
- float y1 = dy - image.height / 2.0f;
- float y2 = y1 + image.height;
+ float x1 = dx - image.displaySize()[0] / 2.0f;
+ float x2 = x1 + image.displaySize()[0];
+ float y1 = dy - image.displaySize()[1] / 2.0f;
+ float y2 = y1 + image.displaySize()[1];
- return { PositionedIcon { image, y1, y2, x1, x2, iconRotation } };
+ return PositionedIcon { image, y1, y2, x1, x2, iconRotation };
}
void align(Shaping& shaping,
@@ -46,7 +42,7 @@ void align(Shaping& shaping,
// justify left = 0, right = 1, center = .5
void justifyLine(std::vector<PositionedGlyph>& positionedGlyphs,
- const GlyphPositions& glyphs,
+ const Glyphs& glyphs,
std::size_t start,
std::size_t end,
float justify) {
@@ -57,7 +53,7 @@ void justifyLine(std::vector<PositionedGlyph>& positionedGlyphs,
PositionedGlyph& glyph = positionedGlyphs[end];
auto it = glyphs.find(glyph.glyph);
if (it != glyphs.end() && it->second) {
- const uint32_t lastAdvance = it->second->metrics.advance;
+ const uint32_t lastAdvance = (*it->second)->metrics.advance;
const float lineIndent = float(glyph.x + lastAdvance) * justify;
for (std::size_t j = start; j <= end; j++) {
@@ -69,13 +65,13 @@ void justifyLine(std::vector<PositionedGlyph>& positionedGlyphs,
float determineAverageLineWidth(const std::u16string& logicalInput,
const float spacing,
float maxWidth,
- const GlyphPositions& glyphs) {
+ const Glyphs& glyphs) {
float totalWidth = 0;
for (char16_t chr : logicalInput) {
auto it = glyphs.find(chr);
if (it != glyphs.end() && it->second) {
- totalWidth += it->second->metrics.advance + spacing;
+ totalWidth += (*it->second)->metrics.advance + spacing;
}
}
@@ -168,7 +164,7 @@ std::set<std::size_t> determineLineBreaks(const std::u16string& logicalInput,
const float spacing,
float maxWidth,
const WritingModeType writingMode,
- const GlyphPositions& glyphs) {
+ const Glyphs& glyphs) {
if (!maxWidth || writingMode != WritingModeType::Horizontal) {
return {};
}
@@ -186,7 +182,7 @@ std::set<std::size_t> determineLineBreaks(const std::u16string& logicalInput,
const char16_t codePoint = logicalInput[i];
auto it = glyphs.find(codePoint);
if (it != glyphs.end() && it->second && !boost::algorithm::is_any_of(u" \t\n\v\f\r")(codePoint)) {
- currentX += it->second->metrics.advance + spacing;
+ currentX += (*it->second)->metrics.advance + spacing;
}
// Ideographic characters, spaces, and word-breaking punctuation that often appear without
@@ -212,7 +208,7 @@ void shapeLines(Shaping& shaping,
const Point<float>& translate,
const float verticalHeight,
const WritingModeType writingMode,
- const GlyphPositions& glyphs) {
+ const Glyphs& glyphs) {
// the y offset *should* be part of the font metadata
const int32_t yOffset = -17;
@@ -238,7 +234,7 @@ void shapeLines(Shaping& shaping,
continue;
}
- const Glyph& glyph = *it->second;
+ const Glyph& glyph = **it->second;
if (writingMode == WritingModeType::Horizontal || !util::i18n::hasUprightVerticalOrientation(chr)) {
shaping.positionedGlyphs.emplace_back(chr, x, y, 0);
@@ -284,7 +280,7 @@ const Shaping getShaping(const std::u16string& logicalInput,
const float verticalHeight,
const WritingModeType writingMode,
BiDi& bidi,
- const GlyphPositions& glyphs) {
+ const Glyphs& glyphs) {
Shaping shaping(translate.x, translate.y, writingMode);
std::vector<std::u16string> reorderedLines =
diff --git a/src/mbgl/text/shaping.hpp b/src/mbgl/text/shaping.hpp
index b7eee5a5db..ca475e2a6c 100644
--- a/src/mbgl/text/shaping.hpp
+++ b/src/mbgl/text/shaping.hpp
@@ -1,32 +1,29 @@
#pragma once
#include <mbgl/text/glyph.hpp>
-#include <mbgl/sprite/sprite_atlas.hpp>
-#include <mbgl/style/image.hpp>
-#include <mbgl/util/optional.hpp>
+#include <mbgl/renderer/image_atlas.hpp>
namespace mbgl {
-class SpriteAtlasElement;
class SymbolFeature;
class BiDi;
class PositionedIcon {
private:
- PositionedIcon(const SpriteAtlasElement& image_,
+ PositionedIcon(ImagePosition image_,
float top_,
float bottom_,
float left_,
float right_,
float angle_)
- : _image(image_),
+ : _image(std::move(image_)),
_top(top_),
_bottom(bottom_),
_left(left_),
_right(right_),
_angle(angle_) {}
- optional<SpriteAtlasElement> _image;
+ ImagePosition _image;
float _top;
float _bottom;
float _left;
@@ -34,9 +31,9 @@ private:
float _angle;
public:
- static optional<PositionedIcon> shapeIcon(const class SpriteAtlasElement&, const std::array<float, 2>& iconOffset, const float iconRotation);
+ static PositionedIcon shapeIcon(const ImagePosition&, const std::array<float, 2>& iconOffset, const float iconRotation);
- optional<class SpriteAtlasElement> image() const { return _image; }
+ const ImagePosition& image() const { return _image; }
float top() const { return _top; }
float bottom() const { return _bottom; }
float left() const { return _left; }
@@ -55,6 +52,6 @@ const Shaping getShaping(const std::u16string& string,
float verticalHeight,
const WritingModeType,
BiDi& bidi,
- const GlyphPositions& glyphs);
+ const Glyphs& glyphs);
} // namespace mbgl
diff --git a/src/mbgl/tile/geojson_tile.cpp b/src/mbgl/tile/geojson_tile.cpp
index 3c4939a0a6..e9865e8272 100644
--- a/src/mbgl/tile/geojson_tile.cpp
+++ b/src/mbgl/tile/geojson_tile.cpp
@@ -1,7 +1,6 @@
#include <mbgl/tile/geojson_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/map/query.hpp>
-#include <mbgl/style/style.hpp>
#include <mbgl/renderer/tile_parameters.hpp>
#include <mapbox/geojsonvt.hpp>
@@ -52,43 +51,57 @@ public:
}
};
-class GeoJSONTileData : public GeometryTileData,
- public GeometryTileLayer {
+class GeoJSONTileLayer : public GeometryTileLayer {
public:
- mapbox::geometry::feature_collection<int16_t> features;
-
- GeoJSONTileData(mapbox::geometry::feature_collection<int16_t> features_)
+ GeoJSONTileLayer(std::shared_ptr<const mapbox::geometry::feature_collection<int16_t>> features_)
: features(std::move(features_)) {
}
- std::unique_ptr<GeometryTileData> clone() const override {
- return std::make_unique<GeoJSONTileData>(*this);
+ std::size_t featureCount() const override {
+ return features->size();
}
- const GeometryTileLayer* getLayer(const std::string&) const override {
- return this;
+ std::unique_ptr<GeometryTileFeature> getFeature(std::size_t i) const override {
+ return std::make_unique<GeoJSONTileFeature>((*features)[i]);
}
std::string getName() const override {
return "";
}
- std::size_t featureCount() const override {
- return features.size();
+private:
+ std::shared_ptr<const mapbox::geometry::feature_collection<int16_t>> features;
+};
+
+class GeoJSONTileData : public GeometryTileData {
+public:
+ GeoJSONTileData(mapbox::geometry::feature_collection<int16_t> features_)
+ : features(std::make_shared<mapbox::geometry::feature_collection<int16_t>>(
+ std::move(features_))) {
}
- std::unique_ptr<GeometryTileFeature> getFeature(std::size_t i) const override {
- return std::make_unique<GeoJSONTileFeature>(features[i]);
+ GeoJSONTileData(std::shared_ptr<const mapbox::geometry::feature_collection<int16_t>> features_)
+ : features(std::move(features_)) {
+ }
+
+ std::unique_ptr<GeometryTileData> clone() const override {
+ return std::make_unique<GeoJSONTileData>(features);
}
+
+ std::unique_ptr<GeometryTileLayer> getLayer(const std::string&) const override {
+ return std::make_unique<GeoJSONTileLayer>(features);
+ }
+
+
+private:
+ std::shared_ptr<const mapbox::geometry::feature_collection<int16_t>> features;
};
GeoJSONTile::GeoJSONTile(const OverscaledTileID& overscaledTileID,
std::string sourceID_,
const TileParameters& parameters,
mapbox::geometry::feature_collection<int16_t> features)
- : GeometryTile(overscaledTileID, sourceID_, parameters,
- *parameters.style.glyphAtlas,
- *parameters.style.spriteAtlas) {
+ : GeometryTile(overscaledTileID, sourceID_, parameters) {
updateData(std::move(features));
}
diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp
index 29ba7d42cd..4ab11d79fe 100644
--- a/src/mbgl/tile/geometry_tile.cpp
+++ b/src/mbgl/tile/geometry_tile.cpp
@@ -6,11 +6,12 @@
#include <mbgl/style/layers/background_layer.hpp>
#include <mbgl/style/layers/custom_layer.hpp>
#include <mbgl/renderer/tile_parameters.hpp>
-#include <mbgl/renderer/render_background_layer.hpp>
-#include <mbgl/renderer/render_custom_layer.hpp>
-#include <mbgl/renderer/render_symbol_layer.hpp>
-#include <mbgl/renderer/symbol_bucket.hpp>
-#include <mbgl/style/style.hpp>
+#include <mbgl/renderer/layers/render_background_layer.hpp>
+#include <mbgl/renderer/layers/render_custom_layer.hpp>
+#include <mbgl/renderer/layers/render_symbol_layer.hpp>
+#include <mbgl/renderer/buckets/symbol_bucket.hpp>
+#include <mbgl/text/glyph_atlas.hpp>
+#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/storage/file_source.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/text/collision_tile.hpp>
@@ -29,30 +30,32 @@ using namespace style;
GeometryTile::GeometryTile(const OverscaledTileID& id_,
std::string sourceID_,
- const TileParameters& parameters,
- GlyphAtlas& glyphAtlas_,
- SpriteAtlas& spriteAtlas_)
+ const TileParameters& parameters)
: Tile(id_),
sourceID(std::move(sourceID_)),
- style(parameters.style),
mailbox(std::make_shared<Mailbox>(*util::RunLoop::Get())),
worker(parameters.workerScheduler,
ActorRef<GeometryTile>(*this, mailbox),
id_,
obsolete,
- parameters.mode),
- glyphAtlas(glyphAtlas_),
- spriteAtlas(spriteAtlas_),
+ parameters.mode,
+ parameters.pixelRatio),
+ glyphManager(parameters.glyphManager),
+ imageManager(parameters.imageManager),
placementThrottler(Milliseconds(300), [this] { invokePlacement(); }) {
}
GeometryTile::~GeometryTile() {
- glyphAtlas.removeGlyphs(*this);
- spriteAtlas.removeRequestor(*this);
- cancel();
+ glyphManager.removeRequestor(*this);
+ imageManager.removeRequestor(*this);
+ markObsolete();
}
void GeometryTile::cancel() {
+ markObsolete();
+}
+
+void GeometryTile::markObsolete() {
obsolete = true;
}
@@ -69,7 +72,6 @@ void GeometryTile::setData(std::unique_ptr<const GeometryTileData> data_) {
++correlationID;
worker.invoke(&GeometryTileWorker::setData, std::move(data_), correlationID);
- redoLayout();
}
void GeometryTile::setPlacementConfig(const PlacementConfig& desiredConfig) {
@@ -92,29 +94,29 @@ void GeometryTile::invokePlacement() {
}
}
-void GeometryTile::redoLayout() {
+void GeometryTile::setLayers(const std::vector<Immutable<Layer::Impl>>& layers) {
// Mark the tile as pending again if it was complete before to prevent signaling a complete
// state despite pending parse operations.
pending = true;
- std::vector<std::unique_ptr<Layer>> copy;
+ std::vector<Immutable<Layer::Impl>> impls;
- for (const Layer* layer : style.getLayers()) {
- // Avoid cloning and including irrelevant layers.
- if (layer->is<BackgroundLayer>() ||
- layer->is<CustomLayer>() ||
- layer->baseImpl->source != sourceID ||
- id.overscaledZ < std::floor(layer->baseImpl->minZoom) ||
- id.overscaledZ >= std::ceil(layer->baseImpl->maxZoom) ||
- layer->baseImpl->visibility == VisibilityType::None) {
+ for (const auto& layer : layers) {
+ // Skip irrelevant layers.
+ if (layer->type == LayerType::Background ||
+ layer->type == LayerType::Custom ||
+ layer->source != sourceID ||
+ id.overscaledZ < std::floor(layer->minZoom) ||
+ id.overscaledZ >= std::ceil(layer->maxZoom) ||
+ layer->visibility == VisibilityType::None) {
continue;
}
- copy.push_back(layer->baseImpl->clone());
+ impls.push_back(layer);
}
++correlationID;
- worker.invoke(&GeometryTileWorker::setLayers, std::move(copy), correlationID);
+ worker.invoke(&GeometryTileWorker::setLayers, std::move(impls), correlationID);
}
void GeometryTile::onLayout(LayoutResult result) {
@@ -134,10 +136,13 @@ void GeometryTile::onPlacement(PlacementResult result) {
pending = false;
}
symbolBuckets = std::move(result.symbolBuckets);
- for (auto& entry : symbolBuckets) {
- dynamic_cast<SymbolBucket*>(entry.second.get())->spriteAtlas = &spriteAtlas;
- }
collisionTile = std::move(result.collisionTile);
+ if (result.glyphAtlasImage) {
+ glyphAtlasImage = std::move(*result.glyphAtlasImage);
+ }
+ if (result.iconAtlasImage) {
+ iconAtlasImage = std::move(*result.iconAtlasImage);
+ }
observer->onTileChanged(*this);
}
@@ -148,25 +153,51 @@ void GeometryTile::onError(std::exception_ptr err) {
observer->onTileError(*this, err);
}
-void GeometryTile::onGlyphsAvailable(GlyphPositionMap glyphPositions) {
- worker.invoke(&GeometryTileWorker::onGlyphsAvailable, std::move(glyphPositions));
+void GeometryTile::onGlyphsAvailable(GlyphMap glyphs) {
+ worker.invoke(&GeometryTileWorker::onGlyphsAvailable, std::move(glyphs));
}
void GeometryTile::getGlyphs(GlyphDependencies glyphDependencies) {
- glyphAtlas.getGlyphs(*this, std::move(glyphDependencies));
+ glyphManager.getGlyphs(*this, std::move(glyphDependencies));
+}
+
+void GeometryTile::onImagesAvailable(ImageMap images) {
+ worker.invoke(&GeometryTileWorker::onImagesAvailable, std::move(images));
}
-void GeometryTile::onIconsAvailable(IconMap icons) {
- worker.invoke(&GeometryTileWorker::onIconsAvailable, std::move(icons));
+void GeometryTile::getImages(ImageDependencies imageDependencies) {
+ imageManager.getImages(*this, std::move(imageDependencies));
}
-void GeometryTile::getIcons(IconDependencies) {
- spriteAtlas.getIcons(*this);
+void GeometryTile::upload(gl::Context& context) {
+ auto upload = [&] (Bucket& bucket) {
+ if (bucket.needsUpload()) {
+ bucket.upload(context);
+ }
+ };
+
+ for (auto& entry : nonSymbolBuckets) {
+ upload(*entry.second);
+ }
+
+ for (auto& entry : symbolBuckets) {
+ upload(*entry.second);
+ }
+
+ if (glyphAtlasImage) {
+ glyphAtlasTexture = context.createTexture(*glyphAtlasImage, 0);
+ glyphAtlasImage = {};
+ }
+
+ if (iconAtlasImage) {
+ iconAtlasTexture = context.createTexture(*iconAtlasImage, 0);
+ iconAtlasImage = {};
+ }
}
-Bucket* GeometryTile::getBucket(const RenderLayer& layer) const {
- const auto& buckets = layer.is<RenderSymbolLayer>() ? symbolBuckets : nonSymbolBuckets;
- const auto it = buckets.find(layer.baseImpl.id);
+Bucket* GeometryTile::getBucket(const Layer::Impl& layer) const {
+ const auto& buckets = layer.type == LayerType::Symbol ? symbolBuckets : nonSymbolBuckets;
+ const auto it = buckets.find(layer.id);
if (it == buckets.end()) {
return nullptr;
}
@@ -179,6 +210,7 @@ void GeometryTile::queryRenderedFeatures(
std::unordered_map<std::string, std::vector<Feature>>& result,
const GeometryCoordinates& queryGeometry,
const TransformState& transformState,
+ const RenderStyle& style,
const RenderedQueryOptions& options) {
if (!featureIndex || !data) return;
diff --git a/src/mbgl/tile/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp
index ed5d8d87bf..77202d20b6 100644
--- a/src/mbgl/tile/geometry_tile.hpp
+++ b/src/mbgl/tile/geometry_tile.hpp
@@ -1,9 +1,9 @@
#pragma once
-#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/tile/tile.hpp>
#include <mbgl/tile/geometry_tile_worker.hpp>
-#include <mbgl/text/glyph_atlas.hpp>
+#include <mbgl/renderer/image_manager.hpp>
+#include <mbgl/text/glyph_manager.hpp>
#include <mbgl/text/placement_config.hpp>
#include <mbgl/util/feature.hpp>
#include <mbgl/util/throttler.hpp>
@@ -19,21 +19,18 @@ namespace mbgl {
class GeometryTileData;
class FeatureIndex;
class CollisionTile;
+class RenderStyle;
class RenderLayer;
class SourceQueryOptions;
class TileParameters;
+class GlyphAtlas;
+class ImageAtlas;
-namespace style {
-class Style;
-} // namespace style
-
-class GeometryTile : public Tile, public GlyphRequestor, IconRequestor {
+class GeometryTile : public Tile, public GlyphRequestor, ImageRequestor {
public:
GeometryTile(const OverscaledTileID&,
std::string sourceID,
- const TileParameters&,
- GlyphAtlas&,
- SpriteAtlas&);
+ const TileParameters&);
~GeometryTile() override;
@@ -41,20 +38,25 @@ public:
void setData(std::unique_ptr<const GeometryTileData>);
void setPlacementConfig(const PlacementConfig&) override;
- void redoLayout() override;
+ void setLayers(const std::vector<Immutable<style::Layer::Impl>>&) override;
- void onGlyphsAvailable(GlyphPositionMap) override;
- void onIconsAvailable(IconMap) override;
+ void onGlyphsAvailable(GlyphMap) override;
+ void onImagesAvailable(ImageMap) override;
void getGlyphs(GlyphDependencies);
- void getIcons(IconDependencies);
+ void getImages(ImageDependencies);
+
+ void upload(gl::Context&) override;
+ Bucket* getBucket(const style::Layer::Impl&) const override;
- Bucket* getBucket(const RenderLayer&) const override;
+ Size bindGlyphAtlas(gl::Context&);
+ Size bindIconAtlas(gl::Context&);
void queryRenderedFeatures(
std::unordered_map<std::string, std::vector<Feature>>& result,
const GeometryCoordinates& queryGeometry,
const TransformState&,
+ const RenderStyle&,
const RenderedQueryOptions& options) override;
void querySourceFeatures(
@@ -76,6 +78,8 @@ public:
public:
std::unordered_map<std::string, std::shared_ptr<Bucket>> symbolBuckets;
std::unique_ptr<CollisionTile> collisionTile;
+ optional<AlphaImage> glyphAtlasImage;
+ optional<PremultipliedImage> iconAtlasImage;
uint64_t correlationID;
};
void onPlacement(PlacementResult);
@@ -88,10 +92,10 @@ protected:
}
private:
+ void markObsolete();
void invokePlacement();
-
+
const std::string sourceID;
- style::Style& style;
// Used to signal the worker that it should abandon parsing this tile as soon as possible.
std::atomic<bool> obsolete { false };
@@ -99,8 +103,8 @@ private:
std::shared_ptr<Mailbox> mailbox;
Actor<GeometryTileWorker> worker;
- GlyphAtlas& glyphAtlas;
- SpriteAtlas& spriteAtlas;
+ GlyphManager& glyphManager;
+ ImageManager& imageManager;
uint64_t correlationID = 0;
optional<PlacementConfig> requestedConfig;
@@ -109,10 +113,17 @@ private:
std::unique_ptr<FeatureIndex> featureIndex;
std::unique_ptr<const GeometryTileData> data;
+ optional<AlphaImage> glyphAtlasImage;
+ optional<PremultipliedImage> iconAtlasImage;
+
std::unordered_map<std::string, std::shared_ptr<Bucket>> symbolBuckets;
std::unique_ptr<CollisionTile> collisionTile;
util::Throttler placementThrottler;
+
+public:
+ optional<gl::Texture> glyphAtlasTexture;
+ optional<gl::Texture> iconAtlasTexture;
};
} // namespace mbgl
diff --git a/src/mbgl/tile/geometry_tile_data.hpp b/src/mbgl/tile/geometry_tile_data.hpp
index 285f86cc7b..449d8cab28 100644
--- a/src/mbgl/tile/geometry_tile_data.hpp
+++ b/src/mbgl/tile/geometry_tile_data.hpp
@@ -51,7 +51,11 @@ class GeometryTileLayer {
public:
virtual ~GeometryTileLayer() = default;
virtual std::size_t featureCount() const = 0;
+
+ // Returns the feature object at the given position within the layer. The returned feature
+ // object may *not* outlive the layer object.
virtual std::unique_ptr<GeometryTileFeature> getFeature(std::size_t) const = 0;
+
virtual std::string getName() const = 0;
};
@@ -59,7 +63,10 @@ class GeometryTileData {
public:
virtual ~GeometryTileData() = default;
virtual std::unique_ptr<GeometryTileData> clone() const = 0;
- virtual const GeometryTileLayer* getLayer(const std::string&) const = 0;
+
+ // Returns the layer with the given name. The returned layer object *may* outlive the data
+ // object.
+ virtual std::unique_ptr<GeometryTileLayer> getLayer(const std::string&) const = 0;
};
// classifies an array of rings into polygons with outer rings and holes
diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp
index 616a0bba1f..12bb84d7e3 100644
--- a/src/mbgl/tile/geometry_tile_worker.cpp
+++ b/src/mbgl/tile/geometry_tile_worker.cpp
@@ -3,14 +3,13 @@
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/text/collision_tile.hpp>
#include <mbgl/layout/symbol_layout.hpp>
-#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/renderer/bucket_parameters.hpp>
#include <mbgl/renderer/group_by_layout.hpp>
#include <mbgl/style/filter.hpp>
#include <mbgl/style/filter_evaluator.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
-#include <mbgl/renderer/render_symbol_layer.hpp>
-#include <mbgl/renderer/symbol_bucket.hpp>
+#include <mbgl/renderer/layers/render_symbol_layer.hpp>
+#include <mbgl/renderer/buckets/symbol_bucket.hpp>
#include <mbgl/util/logging.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/string.hpp>
@@ -26,16 +25,17 @@ GeometryTileWorker::GeometryTileWorker(ActorRef<GeometryTileWorker> self_,
ActorRef<GeometryTile> parent_,
OverscaledTileID id_,
const std::atomic<bool>& obsolete_,
- const MapMode mode_)
+ const MapMode mode_,
+ const float pixelRatio_)
: self(std::move(self_)),
parent(std::move(parent_)),
id(std::move(id_)),
obsolete(obsolete_),
- mode(mode_) {
+ mode(mode_),
+ pixelRatio(pixelRatio_) {
}
-GeometryTileWorker::~GeometryTileWorker() {
-}
+GeometryTileWorker::~GeometryTileWorker() = default;
/*
GeometryTileWorker is a state machine. This is its transition diagram.
@@ -92,7 +92,7 @@ void GeometryTileWorker::setData(std::unique_ptr<const GeometryTileData> data_,
}
}
-void GeometryTileWorker::setLayers(std::vector<std::unique_ptr<Layer>> layers_, uint64_t correlationID_) {
+void GeometryTileWorker::setLayers(std::vector<Immutable<Layer::Impl>> layers_, uint64_t correlationID_) {
try {
layers = std::move(layers_);
correlationID = correlationID_;
@@ -196,37 +196,37 @@ void GeometryTileWorker::coalesce() {
self.invoke(&GeometryTileWorker::coalesced);
}
-void GeometryTileWorker::onGlyphsAvailable(GlyphPositionMap newGlyphPositions) {
- for (auto& newFontGlyphs : newGlyphPositions) {
+void GeometryTileWorker::onGlyphsAvailable(GlyphMap newGlyphMap) {
+ for (auto& newFontGlyphs : newGlyphMap) {
const FontStack& fontStack = newFontGlyphs.first;
- GlyphPositions& newPositions = newFontGlyphs.second;
+ Glyphs& newGlyphs = newFontGlyphs.second;
- GlyphPositions& positions = glyphPositions[fontStack];
+ Glyphs& glyphs = glyphMap[fontStack];
GlyphIDs& pendingGlyphIDs = pendingGlyphDependencies[fontStack];
- for (auto& newPosition : newPositions) {
- const GlyphID& glyphID = newPosition.first;
- optional<Glyph>& glyph = newPosition.second;
+ for (auto& newGlyph : newGlyphs) {
+ const GlyphID& glyphID = newGlyph.first;
+ optional<Immutable<Glyph>>& glyph = newGlyph.second;
if (pendingGlyphIDs.erase(glyphID)) {
- positions.emplace(glyphID, std::move(glyph));
+ glyphs.emplace(glyphID, std::move(glyph));
}
}
}
symbolDependenciesChanged();
}
-void GeometryTileWorker::onIconsAvailable(IconMap newIcons) {
- icons = std::move(newIcons);
- pendingIconDependencies.clear();
+void GeometryTileWorker::onImagesAvailable(ImageMap newImageMap) {
+ imageMap = std::move(newImageMap);
+ pendingImageDependencies.clear();
symbolDependenciesChanged();
}
void GeometryTileWorker::requestNewGlyphs(const GlyphDependencies& glyphDependencies) {
for (auto& fontDependencies : glyphDependencies) {
- auto fontGlyphs = glyphPositions.find(fontDependencies.first);
+ auto fontGlyphs = glyphMap.find(fontDependencies.first);
for (auto glyphID : fontDependencies.second) {
- if (fontGlyphs == glyphPositions.end() || fontGlyphs->second.find(glyphID) == fontGlyphs->second.end()) {
+ if (fontGlyphs == glyphMap.end() || fontGlyphs->second.find(glyphID) == fontGlyphs->second.end()) {
pendingGlyphDependencies[fontDependencies.first].insert(glyphID);
}
}
@@ -236,21 +236,20 @@ void GeometryTileWorker::requestNewGlyphs(const GlyphDependencies& glyphDependen
}
}
-void GeometryTileWorker::requestNewIcons(const IconDependencies& iconDependencies) {
- pendingIconDependencies = iconDependencies;
- if (!pendingIconDependencies.empty()) {
- parent.invoke(&GeometryTile::getIcons, pendingIconDependencies);
+void GeometryTileWorker::requestNewImages(const ImageDependencies& imageDependencies) {
+ pendingImageDependencies = imageDependencies;
+ if (!pendingImageDependencies.empty()) {
+ parent.invoke(&GeometryTile::getImages, pendingImageDependencies);
}
}
-static std::vector<std::unique_ptr<RenderLayer>> toRenderLayers(const std::vector<std::unique_ptr<style::Layer>>& layers, float zoom) {
+static std::vector<std::unique_ptr<RenderLayer>> toRenderLayers(const std::vector<Immutable<style::Layer::Impl>>& layers, float zoom) {
std::vector<std::unique_ptr<RenderLayer>> renderLayers;
renderLayers.reserve(layers.size());
for (auto& layer : layers) {
- renderLayers.push_back(layer->baseImpl->createRenderLayer());
+ renderLayers.push_back(RenderLayer::create(layer));
- renderLayers.back()->cascade(CascadeParameters {
- { ClassID::Default },
+ renderLayers.back()->transition(TransitionParameters {
Clock::time_point::max(),
TransitionOptions()
});
@@ -269,18 +268,18 @@ void GeometryTileWorker::redoLayout() {
std::vector<std::string> symbolOrder;
for (auto it = layers->rbegin(); it != layers->rend(); it++) {
- if ((*it)->is<SymbolLayer>()) {
- symbolOrder.push_back((*it)->getID());
+ if ((*it)->type == LayerType::Symbol) {
+ symbolOrder.push_back((*it)->id);
}
}
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, mode };
+ BucketParameters parameters { id, mode, pixelRatio };
GlyphDependencies glyphDependencies;
- IconDependencies iconDependencies;
+ ImageDependencies imageDependencies;
// Create render layers and group by layout
std::vector<std::unique_ptr<RenderLayer>> renderLayers = toRenderLayers(*layers, id.overscaledZ);
@@ -297,7 +296,7 @@ void GeometryTileWorker::redoLayout() {
const RenderLayer& leader = *group.at(0);
- auto geometryLayer = (*data)->getLayer(leader.baseImpl.sourceLayer);
+ auto geometryLayer = (*data)->getLayer(leader.baseImpl->sourceLayer);
if (!geometryLayer) {
continue;
}
@@ -310,11 +309,12 @@ void GeometryTileWorker::redoLayout() {
featureIndex->setBucketLayerIDs(leader.getID(), layerIDs);
if (leader.is<RenderSymbolLayer>()) {
- symbolLayoutMap.emplace(leader.getID(),
- leader.as<RenderSymbolLayer>()->createLayout(parameters, group, *geometryLayer, glyphDependencies, iconDependencies));
+ auto layout = leader.as<RenderSymbolLayer>()->createLayout(
+ parameters, group, std::move(geometryLayer), glyphDependencies, imageDependencies);
+ symbolLayoutMap.emplace(leader.getID(), std::move(layout));
} else {
- const Filter& filter = leader.baseImpl.filter;
- const std::string& sourceLayerID = leader.baseImpl.sourceLayer;
+ const Filter& filter = leader.baseImpl->filter;
+ const std::string& sourceLayerID = leader.baseImpl->sourceLayer;
std::shared_ptr<Bucket> bucket = leader.createBucket(parameters, group);
for (std::size_t i = 0; !obsolete && i < geometryLayer->featureCount(); i++) {
@@ -347,7 +347,7 @@ void GeometryTileWorker::redoLayout() {
}
requestNewGlyphs(glyphDependencies);
- requestNewIcons(iconDependencies);
+ requestNewImages(imageDependencies);
parent.invoke(&GeometryTile::onLayout, GeometryTile::LayoutResult {
std::move(buckets),
@@ -375,7 +375,7 @@ bool GeometryTileWorker::hasPendingSymbolDependencies() const {
return true;
}
}
- return !pendingIconDependencies.empty();
+ return !pendingImageDependencies.empty();
}
@@ -387,14 +387,24 @@ void GeometryTileWorker::attemptPlacement() {
auto collisionTile = std::make_unique<CollisionTile>(*placementConfig);
std::unordered_map<std::string, std::shared_ptr<Bucket>> buckets;
+ optional<AlphaImage> glyphAtlasImage;
+ optional<PremultipliedImage> iconAtlasImage;
+
for (auto& symbolLayout : symbolLayouts) {
if (obsolete) {
return;
}
if (symbolLayout->state == SymbolLayout::Pending) {
- symbolLayout->prepare(glyphPositions, icons);
+ GlyphAtlas glyphAtlas = makeGlyphAtlas(glyphMap);
+ ImageAtlas imageAtlas = makeImageAtlas(imageMap);
+
+ symbolLayout->prepare(glyphMap, glyphAtlas.positions,
+ imageMap, imageAtlas.positions);
symbolLayout->state = SymbolLayout::Placed;
+
+ glyphAtlasImage = std::move(glyphAtlas.image);
+ iconAtlasImage = std::move(imageAtlas.image);
}
if (!symbolLayout->hasSymbolInstances()) {
@@ -410,6 +420,8 @@ void GeometryTileWorker::attemptPlacement() {
parent.invoke(&GeometryTile::onPlacement, GeometryTile::PlacementResult {
std::move(buckets),
std::move(collisionTile),
+ std::move(glyphAtlasImage),
+ std::move(iconAtlasImage),
correlationID
});
}
diff --git a/src/mbgl/tile/geometry_tile_worker.hpp b/src/mbgl/tile/geometry_tile_worker.hpp
index 1df1ef43c4..194477e7b8 100644
--- a/src/mbgl/tile/geometry_tile_worker.hpp
+++ b/src/mbgl/tile/geometry_tile_worker.hpp
@@ -2,11 +2,13 @@
#include <mbgl/map/mode.hpp>
#include <mbgl/tile/tile_id.hpp>
-#include <mbgl/sprite/sprite_atlas.hpp>
+#include <mbgl/style/image_impl.hpp>
#include <mbgl/text/glyph.hpp>
#include <mbgl/text/placement_config.hpp>
#include <mbgl/actor/actor_ref.hpp>
#include <mbgl/util/optional.hpp>
+#include <mbgl/util/immutable.hpp>
+#include <mbgl/style/layer_impl.hpp>
#include <atomic>
#include <memory>
@@ -15,9 +17,7 @@ namespace mbgl {
class GeometryTile;
class GeometryTileData;
-class GlyphAtlas;
class SymbolLayout;
-class RenderLayer;
namespace style {
class Layer;
@@ -29,15 +29,16 @@ public:
ActorRef<GeometryTile> parent,
OverscaledTileID,
const std::atomic<bool>&,
- const MapMode);
+ const MapMode,
+ const float pixelRatio);
~GeometryTileWorker();
- void setLayers(std::vector<std::unique_ptr<style::Layer>>, uint64_t correlationID);
+ void setLayers(std::vector<Immutable<style::Layer::Impl>>, uint64_t correlationID);
void setData(std::unique_ptr<const GeometryTileData>, uint64_t correlationID);
void setPlacementConfig(PlacementConfig, uint64_t correlationID);
- void onGlyphsAvailable(GlyphPositionMap glyphs);
- void onIconsAvailable(IconMap icons);
+ void onGlyphsAvailable(GlyphMap glyphs);
+ void onImagesAvailable(ImageMap images);
private:
void coalesced();
@@ -47,7 +48,7 @@ private:
void coalesce();
void requestNewGlyphs(const GlyphDependencies&);
- void requestNewIcons(const IconDependencies&);
+ void requestNewImages(const ImageDependencies&);
void symbolDependenciesChanged();
bool hasPendingSymbolDependencies() const;
@@ -59,6 +60,7 @@ private:
const OverscaledTileID id;
const std::atomic<bool>& obsolete;
const MapMode mode;
+ const float pixelRatio;
enum State {
Idle,
@@ -71,15 +73,15 @@ private:
uint64_t correlationID = 0;
// Outer optional indicates whether we've received it or not.
- optional<std::vector<std::unique_ptr<style::Layer>>> layers;
+ optional<std::vector<Immutable<style::Layer::Impl>>> layers;
optional<std::unique_ptr<const GeometryTileData>> data;
optional<PlacementConfig> placementConfig;
std::vector<std::unique_ptr<SymbolLayout>> symbolLayouts;
GlyphDependencies pendingGlyphDependencies;
- IconDependencies pendingIconDependencies;
- GlyphPositionMap glyphPositions;
- IconMap icons;
+ ImageDependencies pendingImageDependencies;
+ GlyphMap glyphMap;
+ ImageMap imageMap;
};
} // namespace mbgl
diff --git a/src/mbgl/tile/raster_tile.cpp b/src/mbgl/tile/raster_tile.cpp
index b1a901e565..8a92c40e4a 100644
--- a/src/mbgl/tile/raster_tile.cpp
+++ b/src/mbgl/tile/raster_tile.cpp
@@ -7,7 +7,7 @@
#include <mbgl/storage/response.hpp>
#include <mbgl/storage/file_source.hpp>
#include <mbgl/renderer/tile_parameters.hpp>
-#include <mbgl/renderer/raster_bucket.hpp>
+#include <mbgl/renderer/buckets/raster_bucket.hpp>
#include <mbgl/util/run_loop.hpp>
namespace mbgl {
@@ -55,7 +55,13 @@ void RasterTile::onError(std::exception_ptr err) {
observer->onTileError(*this, err);
}
-Bucket* RasterTile::getBucket(const RenderLayer&) const {
+void RasterTile::upload(gl::Context& context) {
+ if (bucket) {
+ bucket->upload(context);
+ }
+}
+
+Bucket* RasterTile::getBucket(const style::Layer::Impl&) const {
return bucket.get();
}
diff --git a/src/mbgl/tile/raster_tile.hpp b/src/mbgl/tile/raster_tile.hpp
index e047430485..51075a2dbc 100644
--- a/src/mbgl/tile/raster_tile.hpp
+++ b/src/mbgl/tile/raster_tile.hpp
@@ -29,7 +29,9 @@ public:
optional<Timestamp> expires_);
void cancel() override;
- Bucket* getBucket(const RenderLayer&) const override;
+
+ void upload(gl::Context&) override;
+ Bucket* getBucket(const style::Layer::Impl&) const override;
void onParsed(std::unique_ptr<Bucket> result);
void onError(std::exception_ptr);
diff --git a/src/mbgl/tile/raster_tile_worker.cpp b/src/mbgl/tile/raster_tile_worker.cpp
index 8c1fc2f673..86fb5f181d 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.hpp>
+#include <mbgl/renderer/buckets/raster_bucket.hpp>
#include <mbgl/actor/actor.hpp>
#include <mbgl/util/premultiply.hpp>
diff --git a/src/mbgl/tile/tile.cpp b/src/mbgl/tile/tile.cpp
index 0adc151a64..5080d42933 100644
--- a/src/mbgl/tile/tile.cpp
+++ b/src/mbgl/tile/tile.cpp
@@ -1,6 +1,6 @@
#include <mbgl/tile/tile.hpp>
#include <mbgl/tile/tile_observer.hpp>
-#include <mbgl/renderer/debug_bucket.hpp>
+#include <mbgl/renderer/buckets/debug_bucket.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/logging.hpp>
#include <mbgl/map/query.hpp>
@@ -33,6 +33,7 @@ void Tile::queryRenderedFeatures(
std::unordered_map<std::string, std::vector<Feature>>&,
const GeometryCoordinates&,
const TransformState&,
+ const RenderStyle&,
const RenderedQueryOptions&) {}
void Tile::querySourceFeatures(
diff --git a/src/mbgl/tile/tile.hpp b/src/mbgl/tile/tile.hpp
index 795fd62140..a925d88af3 100644
--- a/src/mbgl/tile/tile.hpp
+++ b/src/mbgl/tile/tile.hpp
@@ -9,6 +9,7 @@
#include <mbgl/renderer/bucket.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/storage/resource.hpp>
+#include <mbgl/style/layer_impl.hpp>
#include <string>
#include <memory>
@@ -21,12 +22,13 @@ class DebugBucket;
class TransformState;
class TileObserver;
class PlacementConfig;
+class RenderStyle;
class RenderedQueryOptions;
class SourceQueryOptions;
-class RenderLayer;
-namespace style {
-} // namespace style
+namespace gl {
+class Context;
+} // namespace gl
class Tile : private util::noncopyable {
public:
@@ -47,15 +49,17 @@ public:
// Mark this tile as no longer needed and cancel any pending work.
virtual void cancel() = 0;
- virtual Bucket* getBucket(const RenderLayer&) const = 0;
+ virtual void upload(gl::Context&) = 0;
+ virtual Bucket* getBucket(const style::Layer::Impl&) const = 0;
virtual void setPlacementConfig(const PlacementConfig&) {}
- virtual void redoLayout() {}
+ virtual void setLayers(const std::vector<Immutable<style::Layer::Impl>>&) {}
virtual void queryRenderedFeatures(
std::unordered_map<std::string, std::vector<Feature>>& result,
const GeometryCoordinates& queryGeometry,
const TransformState&,
+ const RenderStyle&,
const RenderedQueryOptions& options);
virtual void querySourceFeatures(
diff --git a/src/mbgl/tile/vector_tile.cpp b/src/mbgl/tile/vector_tile.cpp
index 46914e5f5a..e2e700b7b7 100644
--- a/src/mbgl/tile/vector_tile.cpp
+++ b/src/mbgl/tile/vector_tile.cpp
@@ -1,94 +1,15 @@
#include <mbgl/tile/vector_tile.hpp>
+#include <mbgl/tile/vector_tile_data.hpp>
#include <mbgl/tile/tile_loader_impl.hpp>
-#include <mbgl/tile/geometry_tile_data.hpp>
-#include <mbgl/style/style.hpp>
#include <mbgl/renderer/tile_parameters.hpp>
-#include <protozero/pbf_reader.hpp>
-
-#include <unordered_map>
-#include <functional>
-#include <utility>
-
namespace mbgl {
-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, std::shared_ptr<VectorTileLayerData> layerData);
-
- FeatureType getType() const override { return type; }
- optional<Value> getValue(const std::string&) const override;
- std::unordered_map<std::string,Value> getProperties() const override;
- optional<FeatureIdentifier> getID() const override;
- GeometryCollection getGeometries() const override;
-
-private:
- 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, 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;
- std::string getName() const override;
-
-private:
- friend class VectorTileData;
- friend class VectorTileFeature;
-
- std::string name;
- std::vector<protozero::pbf_reader> features;
- std::shared_ptr<VectorTileLayerData> data;
-};
-
-class VectorTileData : public GeometryTileData {
-public:
- VectorTileData(std::shared_ptr<const std::string> data);
-
- std::unique_ptr<GeometryTileData> clone() const override {
- return std::make_unique<VectorTileData>(*this);
- }
-
- const GeometryTileLayer* getLayer(const std::string&) const override;
-
-private:
- std::shared_ptr<const std::string> data;
- mutable bool parsed = false;
- mutable std::unordered_map<std::string, VectorTileLayer> layers;
-};
-
VectorTile::VectorTile(const OverscaledTileID& id_,
std::string sourceID_,
const TileParameters& parameters,
const Tileset& tileset)
- : GeometryTile(id_, sourceID_, parameters,
- *parameters.style.glyphAtlas,
- *parameters.style.spriteAtlas),
- loader(*this, id_, parameters, tileset) {
+ : GeometryTile(id_, sourceID_, parameters), loader(*this, id_, parameters, tileset) {
}
void VectorTile::setNecessity(Necessity necessity) {
@@ -104,220 +25,4 @@ void VectorTile::setData(std::shared_ptr<const std::string> data_,
GeometryTile::setData(data_ ? std::make_unique<VectorTileData>(data_) : nullptr);
}
-Value parseValue(protozero::pbf_reader data) {
- while (data.next())
- {
- switch (data.tag()) {
- case 1: // string_value
- return data.get_string();
- case 2: // float_value
- return static_cast<double>(data.get_float());
- case 3: // double_value
- return data.get_double();
- case 4: // int_value
- return data.get_int64();
- case 5: // uint_value
- return data.get_uint64();
- case 6: // sint_value
- return data.get_sint64();
- case 7: // bool_value
- return data.get_bool();
- default:
- data.skip();
- break;
- }
- }
- return false;
-}
-
-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
- id = { feature_pbf.get_uint64() };
- break;
- case 2: // tags
- tags_iter = feature_pbf.get_packed_uint32();
- break;
- case 3: // type
- type = static_cast<FeatureType>(feature_pbf.get_enum());
- break;
- case 4: // geometry
- geometry_iter = feature_pbf.get_packed_uint32();
- break;
- default:
- feature_pbf.skip();
- break;
- }
- }
-}
-
-optional<Value> VectorTileFeature::getValue(const std::string& key) const {
- auto keyIter = layerData->keysMap.find(key);
- if (keyIter == layerData->keysMap.end()) {
- return optional<Value>();
- }
-
- auto start_itr = tags_iter.begin();
- const auto & end_itr = tags_iter.end();
- while (start_itr != end_itr) {
- uint32_t tag_key = static_cast<uint32_t>(*start_itr++);
-
- if (layerData->keysMap.size() <= tag_key) {
- throw std::runtime_error("feature referenced out of range key");
- }
-
- if (start_itr == end_itr) {
- throw std::runtime_error("uneven number of feature tag ids");
- }
-
- uint32_t tag_val = static_cast<uint32_t>(*start_itr++);;
- if (layerData->values.size() <= tag_val) {
- throw std::runtime_error("feature referenced out of range value");
- }
-
- if (tag_key == keyIter->second) {
- return layerData->values[tag_val];
- }
- }
-
- return optional<Value>();
-}
-
-std::unordered_map<std::string,Value> VectorTileFeature::getProperties() const {
- std::unordered_map<std::string,Value> properties;
- auto start_itr = tags_iter.begin();
- const auto & end_itr = tags_iter.end();
- while (start_itr != end_itr) {
- uint32_t tag_key = static_cast<uint32_t>(*start_itr++);
- if (start_itr == end_itr) {
- throw std::runtime_error("uneven number of feature tag ids");
- }
- uint32_t tag_val = static_cast<uint32_t>(*start_itr++);
- properties[layerData->keys.at(tag_key)] = layerData->values.at(tag_val);
- }
- return properties;
-}
-
-optional<FeatureIdentifier> VectorTileFeature::getID() const {
- return id;
-}
-
-GeometryCollection VectorTileFeature::getGeometries() const {
- uint8_t cmd = 1;
- uint32_t length = 0;
- int32_t x = 0;
- int32_t y = 0;
- const float scale = float(util::EXTENT) / layerData->extent;
-
- GeometryCollection lines;
-
- lines.emplace_back();
- GeometryCoordinates* line = &lines.back();
-
- auto g_itr = geometry_iter.begin();
- while (g_itr != geometry_iter.end()) {
- if (length == 0) {
- uint32_t cmd_length = static_cast<uint32_t>(*g_itr++);
- cmd = cmd_length & 0x7;
- length = cmd_length >> 3;
- }
-
- --length;
-
- if (cmd == 1 || cmd == 2) {
- x += protozero::decode_zigzag32(static_cast<uint32_t>(*g_itr++));
- y += protozero::decode_zigzag32(static_cast<uint32_t>(*g_itr++));
-
- if (cmd == 1 && !line->empty()) { // moveTo
- lines.emplace_back();
- line = &lines.back();
- }
-
- line->emplace_back(::round(x * scale), ::round(y * scale));
-
- } else if (cmd == 7) { // closePolygon
- if (!line->empty()) {
- line->push_back((*line)[0]);
- }
-
- } else {
- throw std::runtime_error("unknown command");
- }
- }
-
- if (layerData->version >= 2 || type != FeatureType::Polygon) {
- return lines;
- }
-
- return fixupPolygons(lines);
-}
-
-VectorTileData::VectorTileData(std::shared_ptr<const std::string> data_)
- : data(std::move(data_)) {
-}
-
-const GeometryTileLayer* VectorTileData::getLayer(const std::string& name) const {
- if (!parsed) {
- parsed = true;
- protozero::pbf_reader tile_pbf(*data);
- while (tile_pbf.next(3)) {
- VectorTileLayer layer(tile_pbf.get_message(), data);
- layers.emplace(layer.name, std::move(layer));
- }
- }
-
- auto it = layers.find(name);
- if (it != layers.end()) {
- return &it->second;
- }
- return nullptr;
-}
-
-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
- name = layer_pbf.get_string();
- break;
- case 2: // feature
- features.push_back(layer_pbf.get_message());
- break;
- case 3: // keys
- {
- 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
- data->values.emplace_back(parseValue(layer_pbf.get_message()));
- break;
- case 5: // extent
- data->extent = layer_pbf.get_uint32();
- break;
- case 15: // version
- data->version = layer_pbf.get_uint32();
- break;
- default:
- layer_pbf.skip();
- break;
- }
- }
-}
-
-std::unique_ptr<GeometryTileFeature> VectorTileLayer::getFeature(std::size_t i) const {
- return std::make_unique<VectorTileFeature>(features.at(i), data);
-}
-
-std::string VectorTileLayer::getName() const {
- return name;
-}
-
} // namespace mbgl
diff --git a/src/mbgl/tile/vector_tile_data.cpp b/src/mbgl/tile/vector_tile_data.cpp
new file mode 100644
index 0000000000..2d4a01bda3
--- /dev/null
+++ b/src/mbgl/tile/vector_tile_data.cpp
@@ -0,0 +1,89 @@
+#include <mbgl/tile/vector_tile_data.hpp>
+#include <mbgl/util/constants.hpp>
+
+namespace mbgl {
+
+VectorTileFeature::VectorTileFeature(const mapbox::vector_tile::layer& layer,
+ const protozero::data_view& view)
+ : feature(view, layer) {
+}
+
+FeatureType VectorTileFeature::getType() const {
+ switch (feature.getType()) {
+ case mapbox::vector_tile::GeomType::POINT:
+ return FeatureType::Point;
+ case mapbox::vector_tile::GeomType::LINESTRING:
+ return FeatureType::LineString;
+ case mapbox::vector_tile::GeomType::POLYGON:
+ return FeatureType::Polygon;
+ default:
+ return FeatureType::Unknown;
+ }
+}
+
+optional<Value> VectorTileFeature::getValue(const std::string& key) const {
+ return feature.getValue(key);
+}
+
+std::unordered_map<std::string, Value> VectorTileFeature::getProperties() const {
+ return feature.getProperties();
+}
+
+optional<FeatureIdentifier> VectorTileFeature::getID() const {
+ return feature.getID();
+}
+
+GeometryCollection VectorTileFeature::getGeometries() const {
+ const float scale = float(util::EXTENT) / feature.getExtent();
+ auto lines = feature.getGeometries<GeometryCollection>(scale);
+ if (feature.getVersion() >= 2 || feature.getType() != mapbox::vector_tile::GeomType::POLYGON) {
+ return lines;
+ } else {
+ return fixupPolygons(lines);
+ }
+}
+
+VectorTileLayer::VectorTileLayer(std::shared_ptr<const std::string> data_,
+ const protozero::data_view& view)
+ : data(std::move(data_)), layer(view) {
+}
+
+std::size_t VectorTileLayer::featureCount() const {
+ return layer.featureCount();
+}
+
+std::unique_ptr<GeometryTileFeature> VectorTileLayer::getFeature(std::size_t i) const {
+ return std::make_unique<VectorTileFeature>(layer, layer.getFeature(i));
+}
+
+std::string VectorTileLayer::getName() const {
+ return layer.getName();
+}
+
+VectorTileData::VectorTileData(std::shared_ptr<const std::string> data_) : data(std::move(data_)) {
+}
+
+std::unique_ptr<GeometryTileData> VectorTileData::clone() const {
+ return std::make_unique<VectorTileData>(data);
+}
+
+std::unique_ptr<GeometryTileLayer> VectorTileData::getLayer(const std::string& name) const {
+ if (!parsed) {
+ // We're parsing this lazily so that we can construct VectorTileData objects on the main
+ // thread without incurring the overhead of parsing immediately.
+ layers = mapbox::vector_tile::buffer(*data).getLayers();
+ parsed = true;
+ }
+
+ auto it = layers.find(name);
+ if (it != layers.end()) {
+ return std::make_unique<VectorTileLayer>(data, it->second);
+ }
+ return nullptr;
+}
+
+std::vector<std::string> VectorTileData::layerNames() const {
+ return mapbox::vector_tile::buffer(*data).layerNames();
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/tile/vector_tile_data.hpp b/src/mbgl/tile/vector_tile_data.hpp
new file mode 100644
index 0000000000..48beaf9d07
--- /dev/null
+++ b/src/mbgl/tile/vector_tile_data.hpp
@@ -0,0 +1,54 @@
+#include <mbgl/tile/geometry_tile_data.hpp>
+
+#include <mapbox/vector_tile.hpp>
+#include <protozero/pbf_reader.hpp>
+
+#include <unordered_map>
+#include <functional>
+#include <utility>
+
+namespace mbgl {
+
+class VectorTileFeature : public GeometryTileFeature {
+public:
+ VectorTileFeature(const mapbox::vector_tile::layer&, const protozero::data_view&);
+
+ FeatureType getType() const override;
+ optional<Value> getValue(const std::string& key) const override;
+ std::unordered_map<std::string, Value> getProperties() const override;
+ optional<FeatureIdentifier> getID() const override;
+ GeometryCollection getGeometries() const override;
+
+private:
+ mapbox::vector_tile::feature feature;
+};
+
+class VectorTileLayer : public GeometryTileLayer {
+public:
+ VectorTileLayer(std::shared_ptr<const std::string> data, const protozero::data_view&);
+
+ std::size_t featureCount() const override;
+ std::unique_ptr<GeometryTileFeature> getFeature(std::size_t i) const override;
+ std::string getName() const override;
+
+private:
+ std::shared_ptr<const std::string> data;
+ mapbox::vector_tile::layer layer;
+};
+
+class VectorTileData : public GeometryTileData {
+public:
+ VectorTileData(std::shared_ptr<const std::string> data);
+
+ std::unique_ptr<GeometryTileData> clone() const override;
+ std::unique_ptr<GeometryTileLayer> getLayer(const std::string& name) const override;
+
+ std::vector<std::string> layerNames() const;
+
+private:
+ std::shared_ptr<const std::string> data;
+ mutable bool parsed = false;
+ mutable std::map<std::string, const protozero::data_view> layers;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/util/i18n.cpp b/src/mbgl/util/i18n.cpp
index 6cfdc697e3..ada6f6526c 100644
--- a/src/mbgl/util/i18n.cpp
+++ b/src/mbgl/util/i18n.cpp
@@ -311,7 +311,7 @@ const std::map<char16_t, char16_t> verticalPunctuation = {
{ u'{', u'︷' }, { u'|', u'―' }, { u'}', u'︸' }, { u'⦅', u'︵' }, { u'⦆', u'︶' },
{ u'。', u'︒' }, { u'「', u'﹁' }, { u'」', u'﹂' },
};
-}
+} // namespace
namespace mbgl {
namespace util {
diff --git a/src/mbgl/util/intersection_tests.cpp b/src/mbgl/util/intersection_tests.cpp
index c580357298..e6ce245c0e 100644
--- a/src/mbgl/util/intersection_tests.cpp
+++ b/src/mbgl/util/intersection_tests.cpp
@@ -19,7 +19,7 @@ bool polygonContainsPoint(const GeometryCoordinates& ring, const GeometryCoordin
// Code from http://stackoverflow.com/a/1501725/331379.
float distToSegmentSquared(const GeometryCoordinate& p, const GeometryCoordinate& v, const GeometryCoordinate& w) {
if (v == w) return util::distSqr<float>(p, v);
- const float l2 = util::distSqr<float>(v, w);
+ const auto l2 = util::distSqr<float>(v, w);
const float t = float((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / l2;
if (t < 0) return util::distSqr<float>(p, v);
if (t > 1) return util::distSqr<float>(p, w);
diff --git a/src/mbgl/util/logging.cpp b/src/mbgl/util/logging.cpp
index 939f1def64..0552eb36cb 100644
--- a/src/mbgl/util/logging.cpp
+++ b/src/mbgl/util/logging.cpp
@@ -1,6 +1,6 @@
#include <mbgl/util/logging.hpp>
#include <mbgl/util/enum.hpp>
-#include <mbgl/util/thread.hpp>
+#include <mbgl/util/platform.hpp>
#include <cstdio>
#include <cstdarg>
diff --git a/src/mbgl/util/longest_common_subsequence.hpp b/src/mbgl/util/longest_common_subsequence.hpp
new file mode 100644
index 0000000000..522b5a86b1
--- /dev/null
+++ b/src/mbgl/util/longest_common_subsequence.hpp
@@ -0,0 +1,106 @@
+#pragma once
+
+#include <cstddef>
+#include <functional>
+#include <iterator>
+#include <vector>
+
+namespace mbgl {
+
+/*
+ Computes the longest common subsequence (LCS) of sequences A and B, represented
+ by pairs of random access iterators. The result is output to the provided output
+ iterator. Equality of elements is determined by the provided comparator, defaulting
+ to ==.
+
+ The algorithm used is the O(ND) time and space algorithm from:
+
+ Myers, Eugene W. An O(ND) Difference Algorithm and Its Variations. Algorithmica
+ (1986) 1: 251. http://xmailserver.org/diff2.pdf
+
+ For understanding this algorithm, http://simplygenius.net/Article/DiffTutorial1 is
+ also helpful.
+
+ TODO: implement the O(N) space refinement presented in the paper.
+*/
+template <class InIt, class OutIt, class Equal>
+OutIt longest_common_subsequence(InIt a, InIt endA,
+ InIt b, InIt endB,
+ OutIt outIt,
+ Equal eq) {
+ const std::ptrdiff_t N = endA - a;
+ const std::ptrdiff_t M = endB - b;
+ const std::ptrdiff_t D = N + M;
+
+ if (D == 0) {
+ return outIt;
+ }
+
+ std::vector<std::vector<std::ptrdiff_t>> vs;
+
+ // Self-executing lambda to allow `return` to break from inner loop, and avoid shadowing `v`.
+ [&] () {
+ std::vector<std::ptrdiff_t> v;
+ v.resize(2 * D + 1);
+ v[1] = 0;
+
+ // Core of the algorithm: greedily find farthest-reaching D-paths for increasing
+ // values of D. Store the farthest-reaching endpoints found in each iteration for
+ // later reconstructing the LCS.
+ for (std::ptrdiff_t d = 0; d <= D; ++d) {
+ for (std::ptrdiff_t k = -d; k <= d; k += 2) {
+ std::ptrdiff_t x = (k == -d || (k != d && v.at(k - 1 + D) < v.at(k + 1 + D)))
+ ? v.at(k + 1 + D) // moving down
+ : v.at(k - 1 + D) + 1; // moving right
+
+ std::ptrdiff_t y = x - k;
+
+ while (x < N && y < M && eq(a[x], b[y])) {
+ x++;
+ y++;
+ }
+
+ v[k + D] = x;
+
+ if (x >= N && y >= M) {
+ vs.push_back(v);
+ return;
+ }
+ }
+
+ vs.push_back(v);
+ }
+ }();
+
+ std::ptrdiff_t x = N;
+ std::ptrdiff_t y = M;
+
+ using E = typename std::iterator_traits<InIt>::value_type;
+ std::vector<E> lcsReverse;
+
+ // Reconstruct the LCS using the farthest-reaching endpoints stored above.
+ for (std::ptrdiff_t d = vs.size() - 1; x > 0 || y > 0; --d) {
+ const std::vector<std::ptrdiff_t>& v = vs.at(d);
+ const std::ptrdiff_t k = x - y;
+ const bool down = (k == -d || (k != d && v.at(k - 1 + D) < v.at(k + 1 + D)));
+ const std::ptrdiff_t kPrev = down ? k + 1 : k - 1;
+
+ x = v.at(kPrev + D);
+ y = x - kPrev;
+
+ for (std::ptrdiff_t c = v[k + D]; c != (down ? x : x + 1); --c) {
+ lcsReverse.push_back(a[c - 1]);
+ }
+ }
+
+ return std::copy(lcsReverse.rbegin(), lcsReverse.rend(), outIt);
+}
+
+template < typename InIt, typename OutIt >
+OutIt longest_common_subsequence(InIt a, InIt endA,
+ InIt b, InIt endB,
+ OutIt outIt) {
+ return longest_common_subsequence(a, endA, b, endB, outIt, std::equal_to<>());
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/util/mat2.hpp b/src/mbgl/util/mat2.hpp
index 6a25ef0f1e..c463202daa 100644
--- a/src/mbgl/util/mat2.hpp
+++ b/src/mbgl/util/mat2.hpp
@@ -26,7 +26,7 @@
namespace mbgl {
-typedef std::array<double, 4> mat2;
+using mat2 = std::array<double, 4>;
namespace matrix {
diff --git a/src/mbgl/util/offscreen_texture.cpp b/src/mbgl/util/offscreen_texture.cpp
index fe24774b7c..77a1416e48 100644
--- a/src/mbgl/util/offscreen_texture.cpp
+++ b/src/mbgl/util/offscreen_texture.cpp
@@ -33,6 +33,7 @@ public:
}
context.activeTexture = 0;
+ context.scissorTest = false;
context.viewport = { 0, 0, size };
}
diff --git a/src/mbgl/util/offscreen_texture.hpp b/src/mbgl/util/offscreen_texture.hpp
index ae96286340..c265700555 100644
--- a/src/mbgl/util/offscreen_texture.hpp
+++ b/src/mbgl/util/offscreen_texture.hpp
@@ -20,7 +20,7 @@ public:
OffscreenTexture(gl::Context&,
Size size = { 256, 256 },
OffscreenTextureAttachment type = OffscreenTextureAttachment::None);
- ~OffscreenTexture();
+ ~OffscreenTexture() override;
OffscreenTexture(OffscreenTexture&&);
OffscreenTexture& operator=(OffscreenTexture&&);
diff --git a/src/mbgl/util/premultiply.cpp b/src/mbgl/util/premultiply.cpp
index 219273d7cc..d9fb2480de 100644
--- a/src/mbgl/util/premultiply.cpp
+++ b/src/mbgl/util/premultiply.cpp
@@ -9,6 +9,7 @@ PremultipliedImage premultiply(UnassociatedImage&& src) {
PremultipliedImage dst;
dst.size = src.size;
+ src.size = { 0, 0 };
dst.data = std::move(src.data);
uint8_t* data = dst.data.get();
@@ -29,6 +30,7 @@ UnassociatedImage unpremultiply(PremultipliedImage&& src) {
UnassociatedImage dst;
dst.size = src.size;
+ src.size = { 0, 0 };
dst.data = std::move(src.data);
uint8_t* data = dst.data.get();
diff --git a/src/mbgl/util/std.hpp b/src/mbgl/util/std.hpp
index 1db20e09e5..974e21329c 100644
--- a/src/mbgl/util/std.hpp
+++ b/src/mbgl/util/std.hpp
@@ -8,10 +8,10 @@ namespace mbgl {
namespace util {
template <typename Container, typename ForwardIterator, typename Predicate>
-void erase_if(Container &container, ForwardIterator it, Predicate pred) {
- while (it != container.end()) {
+void erase_if(Container &container, ForwardIterator it, const ForwardIterator end, Predicate pred) {
+ while (it != end) {
if (pred(*it)) {
- it = container.erase(it);
+ container.erase(it++);
} else {
++it;
}
@@ -20,7 +20,7 @@ void erase_if(Container &container, ForwardIterator it, Predicate pred) {
template <typename Container, typename Predicate>
void erase_if(Container &container, Predicate pred) {
- erase_if(container, container.begin(), pred);
+ erase_if(container, container.begin(), container.end(), pred);
}
} // namespace util
diff --git a/src/mbgl/util/thread.hpp b/src/mbgl/util/thread.hpp
index 184c6a8a12..572f46080e 100644
--- a/src/mbgl/util/thread.hpp
+++ b/src/mbgl/util/thread.hpp
@@ -1,63 +1,100 @@
#pragma once
+#include <mbgl/actor/actor.hpp>
+#include <mbgl/actor/mailbox.hpp>
+#include <mbgl/actor/scheduler.hpp>
+#include <mbgl/util/platform.hpp>
+#include <mbgl/util/run_loop.hpp>
+#include <mbgl/util/util.hpp>
+
#include <cassert>
#include <future>
+#include <memory>
+#include <mutex>
+#include <queue>
+#include <string>
#include <thread>
-#include <atomic>
#include <utility>
-#include <functional>
-
-#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 {
-// Manages a thread with Object.
-
-// Upon creation of this object, it launches a thread, creates an object of type Object in that
-// thread, and then calls .start(); on that object. When the Thread<> object is destructed, the
-// Object's .stop() function is called, and the destructor waits for thread termination. The
-// Thread<> constructor blocks until the thread and the Object are fully created, so after the
-// object creation, it's safe to obtain the Object stored in this thread.
-
-template <class Object>
-class Thread {
+// Manages a thread with `Object`.
+
+// Upon creation of this object, it launches a thread and creates an object of type `Object`
+// in that thread. When the `Thread<>` object is destructed, the destructor waits
+// for thread termination. The `Thread<>` constructor blocks until the thread and
+// the `Object` are fully created, so after the object creation, it's safe to obtain the
+// `Object` stored in this thread. The thread created will always have low priority on
+// the platforms that support setting thread priority.
+//
+// The following properties make this class different from `ThreadPool`:
+//
+// - Only one thread is created.
+// - `Object` will live in a single thread, providing thread affinity.
+// - It is safe to use `ThreadLocal` in an `Object` managed by `Thread<>`
+// - A `RunLoop` is created for the `Object` thread.
+// - `Object` can use `Timer` and do asynchronous I/O, like wait for sockets events.
+//
+template<class Object>
+class Thread : public Scheduler {
public:
template <class... Args>
- Thread(const ThreadContext&, Args&&... args);
- ~Thread();
+ Thread(const std::string& name, Args&&... args) {
+ std::promise<void> running;
- // Invoke object->fn(args...) asynchronously.
- template <typename Fn, class... Args>
- void invoke(Fn fn, Args&&... args) {
- loop->invoke(bind(fn), std::forward<Args>(args)...);
- }
+ thread = std::thread([&] {
+ platform::setCurrentThreadName(name);
+ platform::makeThreadLowPriority();
+
+ util::RunLoop loop_(util::RunLoop::Type::New);
+ loop = &loop_;
- // Invoke object->fn(args...) asynchronously. The final argument to fn must be a callback.
- // The provided callback is wrapped such that it is invoked, in the current thread (which
- // must have a RunLoop), once for each time the invocation of fn invokes the wrapper, each
- // time forwarding the passed arguments, until such time as the AsyncRequest is cancelled.
- template <typename Fn, class... Args>
- std::unique_ptr<AsyncRequest>
- invokeWithCallback(Fn fn, Args&&... args) {
- return loop->invokeWithCallback(bind(fn), std::forward<Args>(args)...);
+ object = std::make_unique<Actor<Object>>(*this, std::forward<Args>(args)...);
+ running.set_value();
+
+ loop->run();
+ loop = nullptr;
+ });
+
+ running.get_future().get();
}
- // Invoke object->fn(args...) asynchronously, but wait for the result.
- template <typename Fn, class... Args>
- auto invokeSync(Fn fn, Args&&... args) {
- assert(!paused);
+ ~Thread() override {
+ MBGL_VERIFY_THREAD(tid);
+
+ if (paused) {
+ resume();
+ }
+
+ std::promise<void> joinable;
+
+ // Kill the actor, so we don't get more
+ // messages posted on this scheduler after
+ // we delete the RunLoop.
+ loop->invoke([&] {
+ object.reset();
+ joinable.set_value();
+ });
+
+ joinable.get_future().get();
- 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();
- loop->invoke(std::move(task));
- return future.get();
+ loop->stop();
+ thread.join();
}
+ // Returns a non-owning reference to `Object` that
+ // can be used to send messages to `Object`. It is safe
+ // to the non-owning reference to outlive this object
+ // and be used after the `Thread<>` gets destroyed.
+ ActorRef<std::decay_t<Object>> actor() const {
+ return object->self();
+ }
+
+ // Pauses the `Object` thread. It will prevent the object to wake
+ // up from events such as timers and file descriptor I/O. Messages
+ // sent to a paused `Object` will be queued and only processed after
+ // `resume()` is called.
void pause() {
MBGL_VERIFY_THREAD(tid);
@@ -77,6 +114,7 @@ public:
pausing.get();
}
+ // Resumes the `Object` thread previously paused by `pause()`.
void resume() {
MBGL_VERIFY_THREAD(tid);
@@ -91,83 +129,35 @@ public:
private:
MBGL_STORE_THREAD(tid);
- Thread(const Thread&) = delete;
- Thread(Thread&&) = delete;
- Thread& operator=(const Thread&) = delete;
- Thread& operator=(Thread&&) = delete;
+ void schedule(std::weak_ptr<Mailbox> mailbox) override {
+ {
+ std::lock_guard<std::mutex> lock(mutex);
+ queue.push(mailbox);
+ }
- template <typename Fn>
- auto bind(Fn fn) {
- return [fn, this] (auto &&... args) {
- return (object->*fn)(std::forward<decltype(args)>(args)...);
- };
+ loop->invoke([this] { receive(); });
}
- template <typename P, std::size_t... I>
- void run(P&& params, std::index_sequence<I...>);
+ void receive() {
+ std::unique_lock<std::mutex> lock(mutex);
- std::promise<void> running;
- std::promise<void> joinable;
+ auto mailbox = queue.front();
+ queue.pop();
+ lock.unlock();
- std::unique_ptr<std::promise<void>> paused;
- std::unique_ptr<std::promise<void>> resumed;
+ Mailbox::maybeReceive(mailbox);
+ }
+ std::mutex mutex;
+ std::queue<std::weak_ptr<Mailbox>> queue;
std::thread thread;
+ std::unique_ptr<Actor<Object>> object;
- Object* object = nullptr;
- RunLoop* loop = nullptr;
-};
-
-template <class Object>
-template <class... Args>
-Thread<Object>::Thread(const ThreadContext& context, Args&&... args) {
- // Note: We're using std::tuple<> to store the arguments because GCC 4.9 has a bug
- // when expanding parameters packs captured in lambdas.
- std::tuple<Args...> params = std::forward_as_tuple(::std::forward<Args>(args)...);
-
- thread = std::thread([&] {
- platform::setCurrentThreadName(context.name);
-
- if (context.priority == ThreadPriority::Low) {
- platform::makeThreadLowPriority();
- }
-
- run(std::move(params), std::index_sequence_for<Args...>{});
- });
-
- running.get_future().get();
-}
-
-template <class Object>
-template <typename P, std::size_t... I>
-void Thread<Object>::run(P&& params, std::index_sequence<I...>) {
- RunLoop loop_(RunLoop::Type::New);
- loop = &loop_;
-
- Object object_(std::get<I>(std::forward<P>(params))...);
- object = &object_;
-
- running.set_value();
- loop_.run();
-
- loop = nullptr;
- object = nullptr;
-
- joinable.get_future().get();
-}
-
-template <class Object>
-Thread<Object>::~Thread() {
- MBGL_VERIFY_THREAD(tid);
-
- if (paused) {
- resume();
- }
+ std::unique_ptr<std::promise<void>> paused;
+ std::unique_ptr<std::promise<void>> resumed;
- loop->stop();
- joinable.set_value();
- thread.join();
-}
+ util::RunLoop* loop = nullptr;
+};
} // namespace util
} // namespace mbgl
diff --git a/src/mbgl/util/thread_context.cpp b/src/mbgl/util/thread_context.cpp
deleted file mode 100644
index fe64c2a686..0000000000
--- a/src/mbgl/util/thread_context.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-#include <mbgl/util/thread_context.hpp>
-#include <utility>
-
-namespace mbgl {
-namespace util {
-
-ThreadContext::ThreadContext(std::string name_, ThreadPriority priority_)
- : name(std::move(name_)),
- priority(priority_) {
-}
-
-} // namespace util
-} // namespace mbgl
diff --git a/src/mbgl/util/thread_context.hpp b/src/mbgl/util/thread_context.hpp
deleted file mode 100644
index a51dede404..0000000000
--- a/src/mbgl/util/thread_context.hpp
+++ /dev/null
@@ -1,22 +0,0 @@
-#pragma once
-
-#include <string>
-
-namespace mbgl {
-namespace util {
-
-enum class ThreadPriority : bool {
- Regular,
- Low,
-};
-
-struct ThreadContext {
-public:
- ThreadContext(std::string name, ThreadPriority priority = ThreadPriority::Regular);
-
- std::string name;
- ThreadPriority priority;
-};
-
-} // namespace util
-} // namespace mbgl
diff --git a/src/mbgl/util/thread_local.hpp b/src/mbgl/util/thread_local.hpp
index 9fddbd5bbc..15d4d56524 100644
--- a/src/mbgl/util/thread_local.hpp
+++ b/src/mbgl/util/thread_local.hpp
@@ -32,7 +32,7 @@ public:
}
T* get() {
- T* ret = reinterpret_cast<T*>(pthread_getspecific(key));
+ auto* ret = reinterpret_cast<T*>(pthread_getspecific(key));
if (!ret) {
return nullptr;
}
diff --git a/src/mbgl/util/work_queue.cpp b/src/mbgl/util/work_queue.cpp
deleted file mode 100644
index d0033e3ca2..0000000000
--- a/src/mbgl/util/work_queue.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-#include <mbgl/util/work_queue.hpp>
-#include <mbgl/util/run_loop.hpp>
-
-#include <cassert>
-
-namespace mbgl {
-namespace util {
-
-WorkQueue::WorkQueue() : runLoop(RunLoop::Get()) {
-}
-
-WorkQueue::~WorkQueue() {
- assert(runLoop == RunLoop::Get());
-
- // Cancel all pending AsyncRequests.
- while (!queue.empty()) {
- queue.pop();
- }
-}
-
-void WorkQueue::push(std::function<void()>&& fn) {
- std::lock_guard<std::mutex> lock(queueMutex);
-
- auto workRequest = runLoop->invokeCancellable(std::bind(&WorkQueue::pop, this, std::move(fn)));
- queue.push(std::move(workRequest));
-}
-
-void WorkQueue::pop(const std::function<void()>& fn) {
- assert(runLoop == RunLoop::Get());
-
- fn();
-
- std::lock_guard<std::mutex> lock(queueMutex);
- queue.pop();
-}
-
-} // namespace util
-} // namespace mbgl
diff --git a/src/mbgl/util/work_queue.hpp b/src/mbgl/util/work_queue.hpp
deleted file mode 100644
index 3f6328fb57..0000000000
--- a/src/mbgl/util/work_queue.hpp
+++ /dev/null
@@ -1,40 +0,0 @@
-#pragma once
-
-#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/util/async_request.hpp>
-
-#include <functional>
-#include <memory>
-#include <mutex>
-#include <queue>
-
-namespace mbgl {
-namespace util {
-
-class RunLoop;
-
-// The WorkQueue will manage a queue of closures
-// and it will make sure they get executed on the
-// thread that created the WorkQueue. All pending
-// works are canceled when the queue gets destructed.
-class WorkQueue : private util::noncopyable {
-public:
- WorkQueue();
- ~WorkQueue();
-
- // Push a closure to the queue. It is advised to
- // only push tasks calling functions on the object
- // that owns the queue to avoid use after free errors.
- void push(std::function<void()>&&);
-
-private:
- void pop(const std::function<void()>&);
-
- std::queue<std::unique_ptr<AsyncRequest>> queue;
- std::mutex queueMutex;
-
- RunLoop* runLoop;
-};
-
-} // namespace util
-} // namespace mbgl