summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mbgl/algorithm/generate_clip_ids_impl.hpp11
-rw-r--r--src/mbgl/annotation/annotation_manager.cpp4
-rw-r--r--src/mbgl/annotation/annotation_tile.hpp2
-rw-r--r--src/mbgl/geometry/line_atlas.cpp88
-rw-r--r--src/mbgl/geometry/line_atlas.hpp18
-rw-r--r--src/mbgl/gl/attribute.cpp29
-rw-r--r--src/mbgl/gl/attribute.hpp177
-rw-r--r--src/mbgl/gl/color_mode.cpp44
-rw-r--r--src/mbgl/gl/color_mode.hpp95
-rw-r--r--src/mbgl/gl/context.cpp404
-rw-r--r--src/mbgl/gl/context.hpp153
-rw-r--r--src/mbgl/gl/debugging.cpp4
-rw-r--r--src/mbgl/gl/depth_mode.cpp18
-rw-r--r--src/mbgl/gl/depth_mode.hpp36
-rw-r--r--src/mbgl/gl/draw_mode.hpp76
-rw-r--r--src/mbgl/gl/extension.cpp21
-rw-r--r--src/mbgl/gl/framebuffer.hpp5
-rw-r--r--src/mbgl/gl/index_buffer.hpp39
-rw-r--r--src/mbgl/gl/primitives.hpp22
-rw-r--r--src/mbgl/gl/program.hpp70
-rw-r--r--src/mbgl/gl/renderbuffer.hpp5
-rw-r--r--src/mbgl/gl/segment.hpp39
-rw-r--r--src/mbgl/gl/shader.cpp113
-rw-r--r--src/mbgl/gl/shader.hpp45
-rw-r--r--src/mbgl/gl/stencil_mode.cpp27
-rw-r--r--src/mbgl/gl/stencil_mode.hpp66
-rw-r--r--src/mbgl/gl/texture.hpp7
-rw-r--r--src/mbgl/gl/types.hpp97
-rw-r--r--src/mbgl/gl/uniform.cpp54
-rw-r--r--src/mbgl/gl/uniform.hpp94
-rw-r--r--src/mbgl/gl/value.cpp99
-rw-r--r--src/mbgl/gl/value.hpp125
-rw-r--r--src/mbgl/gl/vao.cpp58
-rw-r--r--src/mbgl/gl/vao.hpp78
-rw-r--r--src/mbgl/gl/vertex_buffer.hpp31
-rw-r--r--src/mbgl/layout/merge_lines.cpp4
-rw-r--r--src/mbgl/layout/symbol_feature.hpp3
-rw-r--r--src/mbgl/layout/symbol_instance.cpp2
-rw-r--r--src/mbgl/layout/symbol_instance.hpp7
-rw-r--r--src/mbgl/layout/symbol_layout.cpp332
-rw-r--r--src/mbgl/layout/symbol_layout.hpp16
-rw-r--r--src/mbgl/map/map.cpp72
-rw-r--r--src/mbgl/map/transform.cpp37
-rw-r--r--src/mbgl/map/transform.hpp2
-rw-r--r--src/mbgl/map/transform_state.cpp50
-rw-r--r--src/mbgl/map/transform_state.hpp6
-rw-r--r--src/mbgl/math/log2.cpp (renamed from src/mbgl/util/math.cpp)12
-rw-r--r--src/mbgl/programs/attributes.hpp23
-rw-r--r--src/mbgl/programs/circle_program.cpp7
-rw-r--r--src/mbgl/programs/circle_program.hpp59
-rw-r--r--src/mbgl/programs/collision_box_program.cpp7
-rw-r--r--src/mbgl/programs/collision_box_program.hpp56
-rw-r--r--src/mbgl/programs/debug_program.hpp27
-rw-r--r--src/mbgl/programs/fill_program.cpp47
-rw-r--r--src/mbgl/programs/fill_program.hpp123
-rw-r--r--src/mbgl/programs/line_program.cpp129
-rw-r--r--src/mbgl/programs/line_program.hpp178
-rw-r--r--src/mbgl/programs/program.hpp43
-rw-r--r--src/mbgl/programs/program_parameters.hpp16
-rw-r--r--src/mbgl/programs/programs.hpp50
-rw-r--r--src/mbgl/programs/raster_program.cpp7
-rw-r--r--src/mbgl/programs/raster_program.hpp68
-rw-r--r--src/mbgl/programs/symbol_program.cpp145
-rw-r--r--src/mbgl/programs/symbol_program.hpp136
-rw-r--r--src/mbgl/programs/uniforms.hpp33
-rw-r--r--src/mbgl/renderer/bucket.hpp5
-rw-r--r--src/mbgl/renderer/circle_bucket.cpp75
-rw-r--r--src/mbgl/renderer/circle_bucket.hpp20
-rw-r--r--src/mbgl/renderer/debug_bucket.cpp65
-rw-r--r--src/mbgl/renderer/debug_bucket.hpp14
-rw-r--r--src/mbgl/renderer/element_group.hpp28
-rw-r--r--src/mbgl/renderer/fill_bucket.cpp126
-rw-r--r--src/mbgl/renderer/fill_bucket.hpp35
-rw-r--r--src/mbgl/renderer/frame_history.cpp72
-rw-r--r--src/mbgl/renderer/frame_history.hpp18
-rw-r--r--src/mbgl/renderer/line_bucket.cpp118
-rw-r--r--src/mbgl/renderer/line_bucket.hpp33
-rw-r--r--src/mbgl/renderer/paint_parameters.hpp4
-rw-r--r--src/mbgl/renderer/painter.cpp193
-rw-r--r--src/mbgl/renderer/painter.hpp80
-rw-r--r--src/mbgl/renderer/painter_background.cpp112
-rw-r--r--src/mbgl/renderer/painter_circle.cpp78
-rw-r--r--src/mbgl/renderer/painter_clipping.cpp68
-rw-r--r--src/mbgl/renderer/painter_debug.cpp198
-rw-r--r--src/mbgl/renderer/painter_fill.cpp263
-rw-r--r--src/mbgl/renderer/painter_line.cpp192
-rw-r--r--src/mbgl/renderer/painter_raster.cpp92
-rw-r--r--src/mbgl/renderer/painter_symbol.cpp305
-rw-r--r--src/mbgl/renderer/raster_bucket.cpp18
-rw-r--r--src/mbgl/renderer/raster_bucket.hpp13
-rw-r--r--src/mbgl/renderer/render_tile.hpp1
-rw-r--r--src/mbgl/renderer/symbol_bucket.cpp76
-rw-r--r--src/mbgl/renderer/symbol_bucket.hpp48
-rw-r--r--src/mbgl/shader/circle_shader.cpp15
-rw-r--r--src/mbgl/shader/circle_shader.hpp30
-rw-r--r--src/mbgl/shader/circle_vertex.cpp7
-rw-r--r--src/mbgl/shader/circle_vertex.hpp39
-rw-r--r--src/mbgl/shader/collision_box_shader.cpp15
-rw-r--r--src/mbgl/shader/collision_box_shader.hpp27
-rw-r--r--src/mbgl/shader/collision_box_vertex.cpp7
-rw-r--r--src/mbgl/shader/collision_box_vertex.hpp43
-rw-r--r--src/mbgl/shader/fill_outline_pattern_shader.cpp15
-rw-r--r--src/mbgl/shader/fill_outline_pattern_shader.hpp37
-rw-r--r--src/mbgl/shader/fill_outline_shader.cpp15
-rw-r--r--src/mbgl/shader/fill_outline_shader.hpp26
-rw-r--r--src/mbgl/shader/fill_pattern_shader.cpp15
-rw-r--r--src/mbgl/shader/fill_pattern_shader.hpp36
-rw-r--r--src/mbgl/shader/fill_shader.cpp15
-rw-r--r--src/mbgl/shader/fill_shader.hpp25
-rw-r--r--src/mbgl/shader/fill_vertex.cpp7
-rw-r--r--src/mbgl/shader/fill_vertex.hpp30
-rw-r--r--src/mbgl/shader/line_pattern_shader.cpp15
-rw-r--r--src/mbgl/shader/line_pattern_shader.hpp41
-rw-r--r--src/mbgl/shader/line_sdf_shader.cpp15
-rw-r--r--src/mbgl/shader/line_sdf_shader.hpp42
-rw-r--r--src/mbgl/shader/line_shader.cpp15
-rw-r--r--src/mbgl/shader/line_shader.hpp35
-rw-r--r--src/mbgl/shader/line_vertex.cpp7
-rw-r--r--src/mbgl/shader/line_vertex.hpp72
-rw-r--r--src/mbgl/shader/raster_shader.cpp15
-rw-r--r--src/mbgl/shader/raster_shader.hpp35
-rw-r--r--src/mbgl/shader/raster_vertex.cpp7
-rw-r--r--src/mbgl/shader/raster_vertex.hpp39
-rw-r--r--src/mbgl/shader/shaders.hpp58
-rw-r--r--src/mbgl/shader/symbol_icon_shader.cpp15
-rw-r--r--src/mbgl/shader/symbol_icon_shader.hpp32
-rw-r--r--src/mbgl/shader/symbol_sdf_shader.cpp15
-rw-r--r--src/mbgl/shader/symbol_sdf_shader.hpp40
-rw-r--r--src/mbgl/shader/symbol_vertex.cpp9
-rw-r--r--src/mbgl/shader/symbol_vertex.hpp54
-rw-r--r--src/mbgl/sprite/sprite_atlas.cpp139
-rw-r--r--src/mbgl/sprite/sprite_atlas.hpp39
-rw-r--r--src/mbgl/sprite/sprite_image.cpp2
-rw-r--r--src/mbgl/sprite/sprite_parser.cpp27
-rw-r--r--src/mbgl/sprite/sprite_parser.hpp8
-rw-r--r--src/mbgl/style/class_dictionary.hpp1
-rw-r--r--src/mbgl/style/cross_faded_property_evaluator.cpp53
-rw-r--r--src/mbgl/style/cross_faded_property_evaluator.hpp48
-rw-r--r--src/mbgl/style/function.cpp81
-rw-r--r--src/mbgl/style/layer_impl.hpp4
-rw-r--r--src/mbgl/style/layers/background_layer.cpp12
-rw-r--r--src/mbgl/style/layers/background_layer_impl.cpp8
-rw-r--r--src/mbgl/style/layers/background_layer_impl.hpp2
-rw-r--r--src/mbgl/style/layers/background_layer_properties.cpp16
-rw-r--r--src/mbgl/style/layers/background_layer_properties.hpp23
-rw-r--r--src/mbgl/style/layers/circle_layer.cpp73
-rw-r--r--src/mbgl/style/layers/circle_layer_impl.cpp16
-rw-r--r--src/mbgl/style/layers/circle_layer_impl.hpp2
-rw-r--r--src/mbgl/style/layers/circle_layer_properties.cpp24
-rw-r--r--src/mbgl/style/layers/circle_layer_properties.hpp66
-rw-r--r--src/mbgl/style/layers/custom_layer_impl.cpp6
-rw-r--r--src/mbgl/style/layers/custom_layer_impl.hpp2
-rw-r--r--src/mbgl/style/layers/fill_extrusion_layer.cpp171
-rw-r--r--src/mbgl/style/layers/fill_extrusion_layer_impl.cpp19
-rw-r--r--src/mbgl/style/layers/fill_extrusion_layer_impl.hpp24
-rw-r--r--src/mbgl/style/layers/fill_extrusion_layer_properties.cpp9
-rw-r--r--src/mbgl/style/layers/fill_extrusion_layer_properties.hpp51
-rw-r--r--src/mbgl/style/layers/fill_layer.cpp28
-rw-r--r--src/mbgl/style/layers/fill_layer_impl.cpp14
-rw-r--r--src/mbgl/style/layers/fill_layer_impl.hpp2
-rw-r--r--src/mbgl/style/layers/fill_layer_properties.cpp24
-rw-r--r--src/mbgl/style/layers/fill_layer_properties.hpp51
-rw-r--r--src/mbgl/style/layers/layer.cpp.ejs14
-rw-r--r--src/mbgl/style/layers/layer_properties.cpp.ejs26
-rw-r--r--src/mbgl/style/layers/layer_properties.hpp.ejs40
-rw-r--r--src/mbgl/style/layers/line_layer.cpp64
-rw-r--r--src/mbgl/style/layers/line_layer_impl.cpp30
-rw-r--r--src/mbgl/style/layers/line_layer_impl.hpp2
-rw-r--r--src/mbgl/style/layers/line_layer_properties.cpp37
-rw-r--r--src/mbgl/style/layers/line_layer_properties.hpp102
-rw-r--r--src/mbgl/style/layers/raster_layer.cpp28
-rw-r--r--src/mbgl/style/layers/raster_layer_impl.cpp8
-rw-r--r--src/mbgl/style/layers/raster_layer_impl.hpp2
-rw-r--r--src/mbgl/style/layers/raster_layer_properties.cpp24
-rw-r--r--src/mbgl/style/layers/raster_layer_properties.hpp51
-rw-r--r--src/mbgl/style/layers/symbol_layer.cpp260
-rw-r--r--src/mbgl/style/layers/symbol_layer_impl.cpp85
-rw-r--r--src/mbgl/style/layers/symbol_layer_impl.hpp35
-rw-r--r--src/mbgl/style/layers/symbol_layer_properties.cpp75
-rw-r--r--src/mbgl/style/layers/symbol_layer_properties.hpp306
-rw-r--r--src/mbgl/style/layout_property.hpp64
-rw-r--r--src/mbgl/style/paint_property.hpp224
-rw-r--r--src/mbgl/style/parser.cpp2
-rw-r--r--src/mbgl/style/property_evaluation_parameters.hpp (renamed from src/mbgl/style/calculation_parameters.hpp)6
-rw-r--r--src/mbgl/style/property_evaluator.cpp152
-rw-r--r--src/mbgl/style/property_evaluator.hpp46
-rw-r--r--src/mbgl/style/property_parsing.hpp2
-rw-r--r--src/mbgl/style/source_impl.cpp38
-rw-r--r--src/mbgl/style/source_impl.hpp3
-rw-r--r--src/mbgl/style/sources/geojson_source_impl.cpp2
-rw-r--r--src/mbgl/style/style.cpp73
-rw-r--r--src/mbgl/style/style.hpp8
-rw-r--r--src/mbgl/text/bidi.hpp46
-rw-r--r--src/mbgl/text/collision_tile.cpp1
-rw-r--r--src/mbgl/text/get_anchors.cpp1
-rw-r--r--src/mbgl/text/glyph.cpp2
-rw-r--r--src/mbgl/text/glyph.hpp20
-rw-r--r--src/mbgl/text/glyph_atlas.cpp92
-rw-r--r--src/mbgl/text/glyph_atlas.hpp13
-rw-r--r--src/mbgl/text/glyph_set.cpp254
-rw-r--r--src/mbgl/text/glyph_set.hpp33
-rw-r--r--src/mbgl/text/quads.cpp30
-rw-r--r--src/mbgl/text/quads.hpp9
-rw-r--r--src/mbgl/text/shaping.cpp8
-rw-r--r--src/mbgl/text/shaping.hpp11
-rw-r--r--src/mbgl/tile/geometry_tile.cpp6
-rw-r--r--src/mbgl/tile/geometry_tile_worker.cpp2
-rw-r--r--src/mbgl/tile/tile.cpp2
-rw-r--r--src/mbgl/tile/tile.hpp3
-rw-r--r--src/mbgl/util/default_styles.cpp16
-rw-r--r--src/mbgl/util/event.cpp (renamed from src/mbgl/platform/event.cpp)2
-rw-r--r--src/mbgl/util/i18n.cpp355
-rw-r--r--src/mbgl/util/i18n.hpp24
-rw-r--r--src/mbgl/util/ignore.hpp23
-rw-r--r--src/mbgl/util/indexed_tuple.hpp47
-rw-r--r--src/mbgl/util/logging.cpp (renamed from src/mbgl/platform/log.cpp)2
-rw-r--r--src/mbgl/util/mapbox.cpp23
-rw-r--r--src/mbgl/util/math.hpp6
-rw-r--r--src/mbgl/util/offscreen_texture.cpp23
-rw-r--r--src/mbgl/util/offscreen_texture.hpp6
-rw-r--r--src/mbgl/util/premultiply.cpp10
-rw-r--r--src/mbgl/util/stopwatch.cpp2
-rw-r--r--src/mbgl/util/stopwatch.hpp2
-rw-r--r--src/mbgl/util/thread.hpp2
-rw-r--r--src/mbgl/util/tile_cover.cpp4
-rw-r--r--src/mbgl/util/url.cpp35
-rw-r--r--src/mbgl/util/url.hpp1
-rw-r--r--src/mbgl/util/utf.hpp15
228 files changed, 6296 insertions, 4955 deletions
diff --git a/src/mbgl/algorithm/generate_clip_ids_impl.hpp b/src/mbgl/algorithm/generate_clip_ids_impl.hpp
index ff8f8d3fdf..59ca66bf66 100644
--- a/src/mbgl/algorithm/generate_clip_ids_impl.hpp
+++ b/src/mbgl/algorithm/generate_clip_ids_impl.hpp
@@ -1,8 +1,8 @@
#pragma once
#include <mbgl/algorithm/generate_clip_ids.hpp>
-#include <mbgl/util/math.hpp>
-#include <mbgl/platform/log.hpp>
+#include <mbgl/math/log2.hpp>
+#include <mbgl/util/logging.hpp>
namespace mbgl {
namespace algorithm {
@@ -15,6 +15,10 @@ void ClipIDGenerator::update(Renderables& renderables) {
for (auto it = renderables.begin(); it != end; it++) {
auto& tileID = it->first;
auto& renderable = it->second;
+ if (!renderable.used) {
+ continue;
+ }
+
renderable.clip = {};
Leaf leaf{ renderable.clip };
@@ -58,6 +62,9 @@ void ClipIDGenerator::update(Renderables& renderables) {
uint8_t count = 1;
for (auto& pair : renderables) {
auto& renderable = pair.second;
+ if (!renderable.used) {
+ continue;
+ }
renderable.clip.mask |= mask;
// Assign only to clip IDs that have no value yet.
diff --git a/src/mbgl/annotation/annotation_manager.cpp b/src/mbgl/annotation/annotation_manager.cpp
index dbd5f1f433..f8c1c3adf7 100644
--- a/src/mbgl/annotation/annotation_manager.cpp
+++ b/src/mbgl/annotation/annotation_manager.cpp
@@ -20,7 +20,7 @@ const std::string AnnotationManager::SourceID = "com.mapbox.annotations";
const std::string AnnotationManager::PointLayerID = "com.mapbox.annotations.points";
AnnotationManager::AnnotationManager(float pixelRatio)
- : spriteAtlas(1024, 1024, pixelRatio) {
+ : spriteAtlas({ 1024, 1024 }, pixelRatio) {
struct NullFileSource : public FileSource {
std::unique_ptr<AsyncRequest> request(const Resource&, Callback) override {
@@ -232,7 +232,7 @@ void AnnotationManager::removeIcon(const std::string& name) {
double AnnotationManager::getTopOffsetPixelsForIcon(const std::string& name) {
auto sprite = spriteAtlas.getSprite(name);
- return sprite ? -(sprite->image.height / sprite->pixelRatio) / 2 : 0;
+ return sprite ? -(sprite->image.size.height / sprite->pixelRatio) / 2 : 0;
}
} // namespace mbgl
diff --git a/src/mbgl/annotation/annotation_tile.hpp b/src/mbgl/annotation/annotation_tile.hpp
index d43ec82d38..bf73075992 100644
--- a/src/mbgl/annotation/annotation_tile.hpp
+++ b/src/mbgl/annotation/annotation_tile.hpp
@@ -31,7 +31,7 @@ public:
FeatureType getType() const override { return type; }
optional<Value> getValue(const std::string&) const override;
- optional<FeatureIdentifier> getID() const override { return { id }; }
+ optional<FeatureIdentifier> getID() const override { return { static_cast<uint64_t>(id) }; }
GeometryCollection getGeometries() const override { return geometries; }
const AnnotationID id;
diff --git a/src/mbgl/geometry/line_atlas.cpp b/src/mbgl/geometry/line_atlas.cpp
index 50e82cc015..71a855b943 100644
--- a/src/mbgl/geometry/line_atlas.cpp
+++ b/src/mbgl/geometry/line_atlas.cpp
@@ -1,8 +1,7 @@
#include <mbgl/geometry/line_atlas.hpp>
-#include <mbgl/gl/gl.hpp>
#include <mbgl/gl/context.hpp>
-#include <mbgl/platform/log.hpp>
-#include <mbgl/platform/platform.hpp>
+#include <mbgl/util/logging.hpp>
+#include <mbgl/util/platform.hpp>
#include <boost/functional/hash.hpp>
@@ -11,10 +10,8 @@
namespace mbgl {
-LineAtlas::LineAtlas(uint16_t w, uint16_t h)
- : width(w),
- height(h),
- data(std::make_unique<char[]>(w * h)),
+LineAtlas::LineAtlas(const Size size)
+ : image(size),
dirty(true) {
}
@@ -40,11 +37,11 @@ LinePatternPos LineAtlas::getDashPosition(const std::vector<float>& dasharray,
}
LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatternCap patternCap) {
- int n = patternCap == LinePatternCap::Round ? 7 : 0;
- int dashheight = 2 * n + 1;
+ const uint8_t n = patternCap == LinePatternCap::Round ? 7 : 0;
+ const uint8_t dashheight = 2 * n + 1;
const uint8_t offset = 128;
- if (nextRow + dashheight > height) {
+ if (nextRow + dashheight > image.size.height) {
Log::Warning(Event::OpenGL, "line atlas bitmap overflow");
return LinePatternPos();
}
@@ -54,7 +51,7 @@ LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatte
length += part;
}
- float stretch = width / length;
+ float stretch = image.size.width / length;
float halfWidth = stretch * 0.5;
// If dasharray has an odd length, both the first and last parts
// are dashes and should be joined seamlessly.
@@ -62,7 +59,7 @@ LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatte
for (int y = -n; y <= n; y++) {
int row = nextRow + n + y;
- int index = width * row;
+ int index = image.size.width * row;
float left = 0;
float right = dasharray[0];
@@ -72,7 +69,7 @@ LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatte
left -= dasharray.back();
}
- for (int x = 0; x < width; x++) {
+ for (uint32_t x = 0; x < image.size.width; x++) {
while (right < x / stretch) {
left = right;
@@ -104,13 +101,13 @@ LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatte
signedDistance = int((inside ? 1 : -1) * dist);
}
- data[index + x] = fmax(0, fmin(255, signedDistance + offset));
+ image.data[index + x] = fmax(0, fmin(255, signedDistance + offset));
}
}
LinePatternPos position;
- position.y = (0.5 + nextRow + n) / height;
- position.height = (2.0 * n) / height;
+ position.y = (0.5 + nextRow + n) / image.size.height;
+ position.height = (2.0 * n) / image.size.height;
position.width = length;
nextRow += dashheight;
@@ -120,59 +117,24 @@ LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatte
return position;
}
-void LineAtlas::upload(gl::Context& context, gl::TextureUnit unit) {
- if (dirty) {
- bind(context, unit);
- }
+Size LineAtlas::getSize() const {
+ return image.size;
}
-void LineAtlas::bind(gl::Context& context, gl::TextureUnit unit) {
- bool first = false;
+void LineAtlas::upload(gl::Context& context, gl::TextureUnit unit) {
if (!texture) {
- texture = context.createTexture();
- context.activeTexture = unit;
- context.texture[unit] = *texture;
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT));
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
- first = true;
- } else if (context.texture[unit] != *texture) {
- context.activeTexture = unit;
- context.texture[unit] = *texture;
+ texture = context.createTexture(image, unit);
+ } else if (dirty) {
+ context.updateTexture(*texture, image, unit);
}
- if (dirty) {
- context.activeTexture = unit;
- if (first) {
- MBGL_CHECK_ERROR(glTexImage2D(
- GL_TEXTURE_2D, // GLenum target
- 0, // GLint level
- GL_ALPHA, // GLint internalformat
- width, // GLsizei width
- height, // GLsizei height
- 0, // GLint border
- GL_ALPHA, // GLenum format
- GL_UNSIGNED_BYTE, // GLenum type
- data.get() // const GLvoid * data
- ));
- } else {
- MBGL_CHECK_ERROR(glTexSubImage2D(
- GL_TEXTURE_2D, // GLenum target
- 0, // GLint level
- 0, // GLint xoffset
- 0, // GLint yoffset
- width, // GLsizei width
- height, // GLsizei height
- GL_ALPHA, // GLenum format
- GL_UNSIGNED_BYTE, // GLenum type
- data.get() // const GLvoid *pixels
- ));
- }
-
+ dirty = false;
+}
- dirty = false;
- }
+void LineAtlas::bind(gl::Context& context, gl::TextureUnit unit) {
+ upload(context, unit);
+ context.bindTexture(*texture, unit, gl::TextureFilter::Linear, gl::TextureMipMap::No,
+ gl::TextureWrap::Repeat, gl::TextureWrap::Clamp);
}
} // namespace mbgl
diff --git a/src/mbgl/geometry/line_atlas.hpp b/src/mbgl/geometry/line_atlas.hpp
index e974b4ff02..b1e7a670c1 100644
--- a/src/mbgl/geometry/line_atlas.hpp
+++ b/src/mbgl/geometry/line_atlas.hpp
@@ -1,6 +1,8 @@
#pragma once
+#include <mbgl/gl/texture.hpp>
#include <mbgl/gl/object.hpp>
+#include <mbgl/util/image.hpp>
#include <mbgl/util/optional.hpp>
#include <vector>
@@ -13,11 +15,12 @@ namespace gl {
class Context;
} // namespace gl
-typedef struct {
+class LinePatternPos {
+public:
float width;
float height;
float y;
-} LinePatternPos;
+};
enum class LinePatternCap : bool {
Square = false,
@@ -26,7 +29,7 @@ enum class LinePatternCap : bool {
class LineAtlas {
public:
- LineAtlas(uint16_t width, uint16_t height);
+ LineAtlas(Size);
~LineAtlas();
// Binds the atlas texture to the GPU, and uploads data if it is out of date.
@@ -39,14 +42,13 @@ public:
LinePatternPos getDashPosition(const std::vector<float>&, LinePatternCap);
LinePatternPos addDash(const std::vector<float>& dasharray, LinePatternCap);
- const uint16_t width;
- const uint16_t height;
+ Size getSize() const;
private:
- const std::unique_ptr<char[]> data;
+ const AlphaImage image;
bool dirty;
- mbgl::optional<gl::UniqueTexture> texture;
- int nextRow = 0;
+ mbgl::optional<gl::Texture> texture;
+ uint32_t nextRow = 0;
std::unordered_map<size_t, LinePatternPos> positions;
};
diff --git a/src/mbgl/gl/attribute.cpp b/src/mbgl/gl/attribute.cpp
new file mode 100644
index 0000000000..7432fff590
--- /dev/null
+++ b/src/mbgl/gl/attribute.cpp
@@ -0,0 +1,29 @@
+#include <mbgl/gl/attribute.hpp>
+#include <mbgl/gl/gl.hpp>
+
+namespace mbgl {
+namespace gl {
+
+AttributeLocation bindAttributeLocation(ProgramID id, AttributeLocation location, const char* name) {
+ MBGL_CHECK_ERROR(glBindAttribLocation(id, location, name));
+ return location;
+}
+
+void bindAttribute(AttributeLocation location,
+ std::size_t count,
+ DataType type,
+ std::size_t vertexSize,
+ std::size_t vertexOffset,
+ std::size_t attributeOffset) {
+ MBGL_CHECK_ERROR(glEnableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttribPointer(
+ location,
+ static_cast<GLint>(count),
+ static_cast<GLenum>(type),
+ GL_FALSE,
+ static_cast<GLsizei>(vertexSize),
+ reinterpret_cast<GLvoid*>(attributeOffset + (vertexSize * vertexOffset))));
+}
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/attribute.hpp b/src/mbgl/gl/attribute.hpp
index 8bc474e967..e45014127b 100644
--- a/src/mbgl/gl/attribute.hpp
+++ b/src/mbgl/gl/attribute.hpp
@@ -1,50 +1,171 @@
#pragma once
#include <mbgl/gl/types.hpp>
-#include <mbgl/gl/shader.hpp>
+#include <mbgl/util/ignore.hpp>
+#include <mbgl/util/indexed_tuple.hpp>
#include <cstddef>
-#include <limits>
-#include <vector>
+#include <functional>
namespace mbgl {
namespace gl {
-template <typename T, std::size_t N>
+template <class Tag, class T, std::size_t N>
class Attribute {
public:
- Attribute(const char* name, const Shader& shader)
- : location(shader.getAttributeLocation(name)) {}
+ using Type = T[N];
- AttributeLocation location;
+ class State {
+ public:
+ explicit State(AttributeLocation location_)
+ : location(location_) {}
+
+ AttributeLocation location;
+ static constexpr std::size_t count = N;
+ static constexpr DataType type = DataTypeOf<T>::value;
+ };
};
-class AttributeBinding {
+#define MBGL_DEFINE_ATTRIBUTE(type_, n_, name_) \
+ struct name_ : ::mbgl::gl::Attribute<name_, type_, n_> { static constexpr auto name = #name_; }
+
+namespace detail {
+
+// Attribute binding requires member offsets. The only standard way to
+// obtain an offset is the offsetof macro. The offsetof macro has defined
+// behavior only for standard layout types. That rules out std::tuple and
+// any other solution that relies on chained inheritance. Manually implemented
+// variadic specialization looks like the only solution. Fortunately, we
+// only use a maximum of five attributes.
+
+template <class... As>
+class Vertex;
+
+template <class A1>
+class Vertex<A1> {
public:
- template <class Vertex, class T, std::size_t N, std::size_t O>
- AttributeBinding(const T (Vertex::*)[N], const Attribute<T, N>& attribute, std::integral_constant<std::size_t, O>)
- : location(attribute.location),
- type(DataTypeOf<T>::value),
- count(N),
- offset(O) {
- static_assert(std::is_standard_layout<Vertex>::value, "vertex type must use standard layout");
- static_assert(O % 4 == 0, "vertex attribute must be optimally aligned");
- static_assert(1 <= N && N <= 4, "count must be 1, 2, 3, or 4");
- static_assert(sizeof(Vertex) <= std::numeric_limits<int32_t>::max(), "vertex type is too big");
- }
+ typename A1::Type a1;
- AttributeLocation location;
- DataType type;
- uint8_t count;
- std::size_t offset;
+ using VertexType = Vertex<A1>;
+ static const std::size_t attributeOffsets[1];
};
-#define MBGL_MAKE_ATTRIBUTE_BINDING(Vertex, shader, name) \
- ::mbgl::gl::AttributeBinding(&Vertex::name, \
- shader.name, \
- std::integral_constant<std::size_t, offsetof(Vertex, name)>())
+template <class A1, class A2>
+class Vertex<A1, A2> {
+public:
+ typename A1::Type a1;
+ typename A2::Type a2;
+
+ using VertexType = Vertex<A1, A2>;
+ static const std::size_t attributeOffsets[2];
+};
+
+template <class A1, class A2, class A3>
+class Vertex<A1, A2, A3> {
+public:
+ typename A1::Type a1;
+ typename A2::Type a2;
+ typename A3::Type a3;
+
+ using VertexType = Vertex<A1, A2, A3>;
+ static const std::size_t attributeOffsets[3];
+};
+
+template <class A1, class A2, class A3, class A4>
+class Vertex<A1, A2, A3, A4> {
+public:
+ typename A1::Type a1;
+ typename A2::Type a2;
+ typename A3::Type a3;
+ typename A4::Type a4;
+
+ using VertexType = Vertex<A1, A2, A3, A4>;
+ static const std::size_t attributeOffsets[4];
+};
+
+template <class A1, class A2, class A3, class A4, class A5>
+class Vertex<A1, A2, A3, A4, A5> {
+public:
+ typename A1::Type a1;
+ typename A2::Type a2;
+ typename A3::Type a3;
+ typename A4::Type a4;
+ typename A5::Type a5;
+
+ using VertexType = Vertex<A1, A2, A3, A4, A5>;
+ static const std::size_t attributeOffsets[5];
+};
-template <class Shader, class Vertex> struct AttributeBindings;
+template <class A1>
+const std::size_t Vertex<A1>::attributeOffsets[1] = {
+ offsetof(VertexType, a1)
+};
+
+template <class A1, class A2>
+const std::size_t Vertex<A1, A2>::attributeOffsets[2] = {
+ offsetof(VertexType, a1),
+ offsetof(VertexType, a2)
+};
+
+template <class A1, class A2, class A3>
+const std::size_t Vertex<A1, A2, A3>::attributeOffsets[3] = {
+ offsetof(VertexType, a1),
+ offsetof(VertexType, a2),
+ offsetof(VertexType, a3)
+};
+
+template <class A1, class A2, class A3, class A4>
+const std::size_t Vertex<A1, A2, A3, A4>::attributeOffsets[4] = {
+ offsetof(VertexType, a1),
+ offsetof(VertexType, a2),
+ offsetof(VertexType, a3),
+ offsetof(VertexType, a4)
+};
+
+template <class A1, class A2, class A3, class A4, class A5>
+const std::size_t Vertex<A1, A2, A3, A4, A5>::attributeOffsets[5] = {
+ offsetof(VertexType, a1),
+ offsetof(VertexType, a2),
+ offsetof(VertexType, a3),
+ offsetof(VertexType, a4),
+ offsetof(VertexType, a5)
+};
+
+} // namespace detail
+
+AttributeLocation bindAttributeLocation(ProgramID, AttributeLocation, const char * name);
+
+void bindAttribute(AttributeLocation location,
+ std::size_t count,
+ DataType type,
+ std::size_t vertexSize,
+ std::size_t vertexOffset,
+ std::size_t attributeOffset);
+
+template <class... As>
+class Attributes {
+public:
+ using State = IndexedTuple<TypeList<As...>, TypeList<typename As::State...>>;
+ using Vertex = detail::Vertex<As...>;
+
+ template <class A>
+ static constexpr std::size_t Index = TypeIndex<A, As...>::value;
+
+ static State state(const ProgramID& id) {
+ return State { typename As::State(bindAttributeLocation(id, Index<As>, As::name))... };
+ }
+
+ static std::function<void (std::size_t)> binder(const State& state) {
+ return [&state] (std::size_t vertexOffset) {
+ util::ignore({ (bindAttribute(state.template get<As>().location,
+ state.template get<As>().count,
+ state.template get<As>().type,
+ sizeof(Vertex),
+ vertexOffset,
+ Vertex::attributeOffsets[Index<As>]), 0)... });
+ };
+ }
+};
} // namespace gl
} // namespace mbgl
diff --git a/src/mbgl/gl/color_mode.cpp b/src/mbgl/gl/color_mode.cpp
new file mode 100644
index 0000000000..e838c8e2ff
--- /dev/null
+++ b/src/mbgl/gl/color_mode.cpp
@@ -0,0 +1,44 @@
+#include <mbgl/gl/color_mode.hpp>
+#include <mbgl/gl/gl.hpp>
+#include <mbgl/util/traits.hpp>
+
+namespace mbgl {
+namespace gl {
+
+static_assert(underlying_type(ColorMode::BlendEquation::Add) == GL_FUNC_ADD, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::BlendEquation::Subtract) == GL_FUNC_SUBTRACT, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::BlendEquation::ReverseSubtract) == GL_FUNC_REVERSE_SUBTRACT, "OpenGL enum mismatch");
+
+static_assert(underlying_type(ColorMode::Zero) == GL_ZERO, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::One) == GL_ONE, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::SrcColor) == GL_SRC_COLOR, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::OneMinusSrcColor) == GL_ONE_MINUS_SRC_COLOR, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::DstColor) == GL_DST_COLOR, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::OneMinusDstColor) == GL_ONE_MINUS_DST_COLOR, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::SrcAlpha) == GL_SRC_ALPHA, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::OneMinusSrcAlpha) == GL_ONE_MINUS_SRC_ALPHA, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::DstAlpha) == GL_DST_ALPHA, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::OneMinusDstAlpha) == GL_ONE_MINUS_DST_ALPHA, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::ConstantColor) == GL_CONSTANT_COLOR, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::OneMinusConstantColor) == GL_ONE_MINUS_CONSTANT_COLOR, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::ConstantAlpha) == GL_CONSTANT_ALPHA, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::OneMinusConstantAlpha) == GL_ONE_MINUS_CONSTANT_ALPHA, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::SrcAlphaSaturate) == GL_SRC_ALPHA_SATURATE, "OpenGL enum mismatch");
+
+static_assert(underlying_type(ColorMode::Zero) == GL_ZERO, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::One) == GL_ONE, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::SrcColor) == GL_SRC_COLOR, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::OneMinusSrcColor) == GL_ONE_MINUS_SRC_COLOR, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::DstColor) == GL_DST_COLOR, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::OneMinusDstColor) == GL_ONE_MINUS_DST_COLOR, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::SrcAlpha) == GL_SRC_ALPHA, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::OneMinusSrcAlpha) == GL_ONE_MINUS_SRC_ALPHA, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::DstAlpha) == GL_DST_ALPHA, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::OneMinusDstAlpha) == GL_ONE_MINUS_DST_ALPHA, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::ConstantColor) == GL_CONSTANT_COLOR, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::OneMinusConstantColor) == GL_ONE_MINUS_CONSTANT_COLOR, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::ConstantAlpha) == GL_CONSTANT_ALPHA, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::OneMinusConstantAlpha) == GL_ONE_MINUS_CONSTANT_ALPHA, "OpenGL enum mismatch");
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/color_mode.hpp b/src/mbgl/gl/color_mode.hpp
new file mode 100644
index 0000000000..e73c8737eb
--- /dev/null
+++ b/src/mbgl/gl/color_mode.hpp
@@ -0,0 +1,95 @@
+#pragma once
+
+#include <mbgl/util/variant.hpp>
+#include <mbgl/util/color.hpp>
+
+namespace mbgl {
+namespace gl {
+
+class ColorMode {
+public:
+ enum class BlendEquation {
+ Add = 0x8006,
+ Subtract = 0x800A,
+ ReverseSubtract = 0x800B
+ };
+
+ enum BlendFactor {
+ Zero = 0x0000,
+ One = 0x0001,
+ SrcColor = 0x0300,
+ OneMinusSrcColor = 0x0301,
+ SrcAlpha = 0x0302,
+ OneMinusSrcAlpha = 0x0303,
+ DstAlpha = 0x0304,
+ OneMinusDstAlpha = 0x0305,
+ DstColor = 0x0306,
+ OneMinusDstColor = 0x0307,
+ SrcAlphaSaturate = 0x0308,
+ ConstantColor = 0x8001,
+ OneMinusConstantColor = 0x8002,
+ ConstantAlpha = 0x8003,
+ OneMinusConstantAlpha = 0x8004
+ };
+
+ template <BlendEquation E>
+ struct ConstantBlend {
+ static constexpr BlendEquation equation = E;
+ static constexpr BlendFactor srcFactor = One;
+ static constexpr BlendFactor dstFactor = One;
+ };
+
+ template <BlendEquation E>
+ struct LinearBlend {
+ static constexpr BlendEquation equation = E;
+ BlendFactor srcFactor;
+ BlendFactor dstFactor;
+ };
+
+ struct Replace {
+ static constexpr BlendEquation equation = BlendEquation::Add;
+ static constexpr BlendFactor srcFactor = One;
+ static constexpr BlendFactor dstFactor = One;
+ };
+
+ using Add = LinearBlend<BlendEquation::Add>;
+ using Subtract = LinearBlend<BlendEquation::Subtract>;
+ using ReverseSubtract = LinearBlend<BlendEquation::ReverseSubtract>;
+
+ using BlendFunction = variant<
+ Replace,
+ Add,
+ Subtract,
+ ReverseSubtract>;
+
+ BlendFunction blendFunction;
+ Color blendColor;
+
+ struct Mask {
+ bool r;
+ bool g;
+ bool b;
+ bool a;
+ };
+
+ Mask mask;
+
+ static ColorMode disabled() {
+ return ColorMode { Replace(), {}, { false, false, false, false } };
+ }
+
+ static ColorMode unblended() {
+ return ColorMode { Replace(), {}, { true, true, true, true } };
+ }
+
+ static ColorMode alphaBlended() {
+ return ColorMode { Add { One, OneMinusSrcAlpha }, {}, { true, true, true, true } };
+ }
+};
+
+constexpr bool operator!=(const ColorMode::Mask& a, const ColorMode::Mask& b) {
+ return a.r != b.r || a.g != b.g || a.b != b.b || a.a != b.a;
+}
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp
index 23b28a15df..5048ffcd66 100644
--- a/src/mbgl/gl/context.cpp
+++ b/src/mbgl/gl/context.cpp
@@ -3,10 +3,25 @@
#include <mbgl/gl/gl.hpp>
#include <mbgl/gl/vertex_array.hpp>
#include <mbgl/util/traits.hpp>
+#include <mbgl/util/std.hpp>
+#include <mbgl/util/logging.hpp>
+
+#include <cstring>
namespace mbgl {
namespace gl {
+static_assert(underlying_type(ShaderType::Vertex) == GL_VERTEX_SHADER, "OpenGL type mismatch");
+static_assert(underlying_type(ShaderType::Fragment) == GL_FRAGMENT_SHADER, "OpenGL type mismatch");
+
+static_assert(underlying_type(PrimitiveType::Points) == GL_POINTS, "OpenGL type mismatch");
+static_assert(underlying_type(PrimitiveType::Lines) == GL_LINES, "OpenGL type mismatch");
+static_assert(underlying_type(PrimitiveType::LineLoop) == GL_LINE_LOOP, "OpenGL type mismatch");
+static_assert(underlying_type(PrimitiveType::LineStrip) == GL_LINE_STRIP, "OpenGL type mismatch");
+static_assert(underlying_type(PrimitiveType::Triangles) == GL_TRIANGLES, "OpenGL type mismatch");
+static_assert(underlying_type(PrimitiveType::TriangleStrip) == GL_TRIANGLE_STRIP, "OpenGL type mismatch");
+static_assert(underlying_type(PrimitiveType::TriangleFan) == GL_TRIANGLE_FAN, "OpenGL type mismatch");
+
static_assert(std::is_same<ProgramID, GLuint>::value, "OpenGL type mismatch");
static_assert(std::is_same<ShaderID, GLuint>::value, "OpenGL type mismatch");
static_assert(std::is_same<BufferID, GLuint>::value, "OpenGL type mismatch");
@@ -15,81 +30,66 @@ static_assert(std::is_same<VertexArrayID, GLuint>::value, "OpenGL type mismatch"
static_assert(std::is_same<FramebufferID, GLuint>::value, "OpenGL type mismatch");
static_assert(std::is_same<RenderbufferID, GLuint>::value, "OpenGL type mismatch");
-static_assert(std::is_same<StencilValue, GLint>::value, "OpenGL type mismatch");
-static_assert(std::is_same<StencilMaskValue, GLuint>::value, "OpenGL type mismatch");
-
-static_assert(underlying_type(StencilTestFunction::Never) == GL_NEVER, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestFunction::Less) == GL_LESS, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestFunction::Equal) == GL_EQUAL, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestFunction::LessEqual) == GL_LEQUAL, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestFunction::Greater) == GL_GREATER, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestFunction::NotEqual) == GL_NOTEQUAL, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestFunction::GreaterEqual) == GL_GEQUAL, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestFunction::Always) == GL_ALWAYS, "OpenGL enum mismatch");
-
-static_assert(underlying_type(StencilTestOperation::Keep) == GL_KEEP, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestOperation::Zero) == GL_ZERO, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestOperation::Replace) == GL_REPLACE, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestOperation::Increment) == GL_INCR, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestOperation::IncrementWrap) == GL_INCR_WRAP, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestOperation::Decrement) == GL_DECR, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestOperation::DecrementWrap) == GL_DECR_WRAP, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestOperation::Invert) == GL_INVERT, "OpenGL enum mismatch");
-
-static_assert(underlying_type(DepthTestFunction::Never) == GL_NEVER, "OpenGL enum mismatch");
-static_assert(underlying_type(DepthTestFunction::Less) == GL_LESS, "OpenGL enum mismatch");
-static_assert(underlying_type(DepthTestFunction::Equal) == GL_EQUAL, "OpenGL enum mismatch");
-static_assert(underlying_type(DepthTestFunction::LessEqual) == GL_LEQUAL, "OpenGL enum mismatch");
-static_assert(underlying_type(DepthTestFunction::Greater) == GL_GREATER, "OpenGL enum mismatch");
-static_assert(underlying_type(DepthTestFunction::NotEqual) == GL_NOTEQUAL, "OpenGL enum mismatch");
-static_assert(underlying_type(DepthTestFunction::GreaterEqual) == GL_GEQUAL, "OpenGL enum mismatch");
-static_assert(underlying_type(DepthTestFunction::Always) == GL_ALWAYS, "OpenGL enum mismatch");
-
-static_assert(underlying_type(BlendSourceFactor::Zero) == GL_ZERO, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::One) == GL_ONE, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::SrcColor) == GL_SRC_COLOR, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::OneMinusSrcColor) == GL_ONE_MINUS_SRC_COLOR, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::DstColor) == GL_DST_COLOR, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::OneMinusDstColor) == GL_ONE_MINUS_DST_COLOR, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::SrcAlpha) == GL_SRC_ALPHA, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::OneMinusSrcAlpha) == GL_ONE_MINUS_SRC_ALPHA, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::DstAlpha) == GL_DST_ALPHA, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::OneMinusDstAlpha) == GL_ONE_MINUS_DST_ALPHA, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::ConstantColor) == GL_CONSTANT_COLOR, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::OneMinusConstantColor) == GL_ONE_MINUS_CONSTANT_COLOR, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::ConstantAlpha) == GL_CONSTANT_ALPHA, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::OneMinusConstantAlpha) == GL_ONE_MINUS_CONSTANT_ALPHA, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::SrcAlphaSaturate) == GL_SRC_ALPHA_SATURATE, "OpenGL enum mismatch");
-
-static_assert(underlying_type(BlendDestinationFactor::Zero) == GL_ZERO, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::One) == GL_ONE, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::SrcColor) == GL_SRC_COLOR, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::OneMinusSrcColor) == GL_ONE_MINUS_SRC_COLOR, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::DstColor) == GL_DST_COLOR, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::OneMinusDstColor) == GL_ONE_MINUS_DST_COLOR, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::SrcAlpha) == GL_SRC_ALPHA, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::OneMinusSrcAlpha) == GL_ONE_MINUS_SRC_ALPHA, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::DstAlpha) == GL_DST_ALPHA, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::OneMinusDstAlpha) == GL_ONE_MINUS_DST_ALPHA, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::ConstantColor) == GL_CONSTANT_COLOR, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::OneMinusConstantColor) == GL_ONE_MINUS_CONSTANT_COLOR, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::ConstantAlpha) == GL_CONSTANT_ALPHA, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::OneMinusConstantAlpha) == GL_ONE_MINUS_CONSTANT_ALPHA, "OpenGL enum mismatch");
+static_assert(std::is_same<std::underlying_type_t<TextureFormat>, GLenum>::value, "OpenGL type mismatch");
+static_assert(underlying_type(TextureFormat::RGBA) == GL_RGBA, "OpenGL type mismatch");
+static_assert(underlying_type(TextureFormat::Alpha) == GL_ALPHA, "OpenGL type mismatch");
Context::~Context() {
reset();
}
-UniqueProgram Context::createProgram() {
- return UniqueProgram{ MBGL_CHECK_ERROR(glCreateProgram()), { this } };
+UniqueShader Context::createShader(ShaderType type, const std::string& source) {
+ UniqueShader result { MBGL_CHECK_ERROR(glCreateShader(static_cast<GLenum>(type))), { this } };
+
+ const GLchar* sources = source.data();
+ const GLsizei lengths = static_cast<GLsizei>(source.length());
+ MBGL_CHECK_ERROR(glShaderSource(result, 1, &sources, &lengths));
+ MBGL_CHECK_ERROR(glCompileShader(result));
+
+ GLint status = 0;
+ MBGL_CHECK_ERROR(glGetShaderiv(result, GL_COMPILE_STATUS, &status));
+ if (status != 0) {
+ return result;
+ }
+
+ GLint logLength;
+ MBGL_CHECK_ERROR(glGetShaderiv(result, GL_INFO_LOG_LENGTH, &logLength));
+ if (logLength > 0) {
+ const auto log = std::make_unique<GLchar[]>(logLength);
+ MBGL_CHECK_ERROR(glGetShaderInfoLog(result, logLength, &logLength, log.get()));
+ Log::Error(Event::Shader, "Shader failed to compile: %s", log.get());
+ }
+
+ throw std::runtime_error("shader failed to compile");
}
-UniqueShader Context::createVertexShader() {
- return UniqueShader{ MBGL_CHECK_ERROR(glCreateShader(GL_VERTEX_SHADER)), { this } };
+UniqueProgram Context::createProgram(ShaderID vertexShader, ShaderID fragmentShader) {
+ UniqueProgram result { MBGL_CHECK_ERROR(glCreateProgram()), { this } };
+
+ MBGL_CHECK_ERROR(glAttachShader(result, vertexShader));
+ MBGL_CHECK_ERROR(glAttachShader(result, fragmentShader));
+
+ return result;
}
-UniqueShader Context::createFragmentShader() {
- return UniqueShader{ MBGL_CHECK_ERROR(glCreateShader(GL_FRAGMENT_SHADER)), { this } };
+void Context::linkProgram(ProgramID program_) {
+ MBGL_CHECK_ERROR(glLinkProgram(program_));
+
+ GLint status;
+ MBGL_CHECK_ERROR(glGetProgramiv(program_, GL_LINK_STATUS, &status));
+ if (status == GL_TRUE) {
+ return;
+ }
+
+ GLint logLength;
+ MBGL_CHECK_ERROR(glGetProgramiv(program_, GL_INFO_LOG_LENGTH, &logLength));
+ const auto log = std::make_unique<GLchar[]>(logLength);
+ if (logLength > 0) {
+ MBGL_CHECK_ERROR(glGetProgramInfoLog(program_, logLength, &logLength, log.get()));
+ Log::Error(Event::Shader, "Program failed to link: %s", log.get());
+ }
+
+ throw std::runtime_error("program failed to link");
}
UniqueBuffer Context::createVertexBuffer(const void* data, std::size_t size) {
@@ -105,21 +105,12 @@ UniqueBuffer Context::createIndexBuffer(const void* data, std::size_t size) {
BufferID id = 0;
MBGL_CHECK_ERROR(glGenBuffers(1, &id));
UniqueBuffer result { std::move(id), { this } };
+ vertexArrayObject = 0;
elementBuffer = result;
MBGL_CHECK_ERROR(glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW));
return result;
}
-void Context::bindAttribute(const AttributeBinding& binding, std::size_t stride, const int8_t* offset) {
- MBGL_CHECK_ERROR(glEnableVertexAttribArray(binding.location));
- MBGL_CHECK_ERROR(glVertexAttribPointer(binding.location,
- binding.count,
- static_cast<GLenum>(binding.type),
- false,
- static_cast<GLsizei>(stride),
- offset + binding.offset));
-}
-
UniqueTexture Context::createTexture() {
if (pooledTextures.empty()) {
pooledTextures.resize(TextureMax);
@@ -131,31 +122,60 @@ UniqueTexture Context::createTexture() {
return UniqueTexture{ std::move(id), { this } };
}
-UniqueVertexArray Context::createVertexArray() {
- VertexArrayID id = 0;
- MBGL_CHECK_ERROR(gl::GenVertexArrays(1, &id));
- return UniqueVertexArray{ std::move(id), { this } };
-}
-
UniqueFramebuffer Context::createFramebuffer() {
FramebufferID id = 0;
MBGL_CHECK_ERROR(glGenFramebuffers(1, &id));
return UniqueFramebuffer{ std::move(id), { this } };
}
-UniqueRenderbuffer Context::createRenderbuffer(const RenderbufferType type,
- const uint16_t width,
- const uint16_t height) {
+UniqueRenderbuffer Context::createRenderbuffer(const RenderbufferType type, const Size size) {
RenderbufferID id = 0;
MBGL_CHECK_ERROR(glGenRenderbuffers(1, &id));
UniqueRenderbuffer renderbuffer{ std::move(id), { this } };
bindRenderbuffer = renderbuffer;
MBGL_CHECK_ERROR(
- glRenderbufferStorage(GL_RENDERBUFFER, static_cast<GLenum>(type), width, height));
+ glRenderbufferStorage(GL_RENDERBUFFER, static_cast<GLenum>(type), size.width, size.height));
return renderbuffer;
}
+std::unique_ptr<uint8_t[]> Context::readFramebuffer(const Size size, const TextureFormat format, const bool flip) {
+ const size_t stride = size.width * (format == TextureFormat::RGBA ? 4 : 1);
+ auto data = std::make_unique<uint8_t[]>(stride * size.height);
+
+#if not MBGL_USE_GLES2
+ // When reading data from the framebuffer, make sure that we are storing the values
+ // tightly packed into the buffer to avoid buffer overruns.
+ pixelStorePack = { 1 };
+#endif // MBGL_USE_GLES2
+
+ MBGL_CHECK_ERROR(glReadPixels(0, 0, size.width, size.height, static_cast<GLenum>(format),
+ GL_UNSIGNED_BYTE, data.get()));
+
+ if (flip) {
+ auto tmp = std::make_unique<uint8_t[]>(stride);
+ uint8_t* rgba = data.get();
+ for (int i = 0, j = size.height - 1; i < j; i++, j--) {
+ std::memcpy(tmp.get(), rgba + i * stride, stride);
+ std::memcpy(rgba + i * stride, rgba + j * stride, stride);
+ std::memcpy(rgba + j * stride, tmp.get(), stride);
+ }
+ }
+
+ return data;
+}
+
+#if not MBGL_USE_GLES2
+void Context::drawPixels(const Size size, const void* data, TextureFormat format) {
+ pixelStoreUnpack = { 1 };
+ if (format != TextureFormat::RGBA) {
+ format = static_cast<TextureFormat>(GL_LUMINANCE);
+ }
+ MBGL_CHECK_ERROR(glDrawPixels(size.width, size.height, static_cast<GLenum>(GL_LUMINANCE),
+ GL_UNSIGNED_BYTE, data));
+}
+#endif // MBGL_USE_GLES2
+
namespace {
void checkFramebuffer() {
@@ -251,35 +271,62 @@ Framebuffer Context::createFramebuffer(const Texture& color) {
}
UniqueTexture
-Context::createTexture(uint16_t width, uint16_t height, const void* data, TextureUnit unit) {
+Context::createTexture(const Size size, const void* data, TextureFormat format, TextureUnit unit) {
auto obj = createTexture();
- activeTexture = unit;
- texture[unit] = obj;
+ updateTexture(obj, size, data, format, unit);
+ // We are using clamp to edge here since OpenGL ES doesn't allow GL_REPEAT on NPOT textures.
+ // We use those when the pixelRatio isn't a power of two, e.g. on iPhone 6 Plus.
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
- MBGL_CHECK_ERROR(
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data));
return obj;
}
+void Context::updateTexture(
+ TextureID id, const Size size, const void* data, TextureFormat format, TextureUnit unit) {
+ activeTexture = unit;
+ texture[unit] = id;
+ MBGL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, static_cast<GLenum>(format), size.width,
+ size.height, 0, static_cast<GLenum>(format), GL_UNSIGNED_BYTE,
+ data));
+}
+
void Context::bindTexture(Texture& obj,
TextureUnit unit,
TextureFilter filter,
- TextureMipMap mipmap) {
- if (filter != obj.filter || mipmap != obj.mipmap) {
+ TextureMipMap mipmap,
+ TextureWrap wrapX,
+ TextureWrap wrapY) {
+ if (filter != obj.filter || mipmap != obj.mipmap || wrapX != obj.wrapX || wrapY != obj.wrapY) {
activeTexture = unit;
texture[unit] = obj.texture;
- MBGL_CHECK_ERROR(glTexParameteri(
- GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
- filter == TextureFilter::Linear
- ? (mipmap == TextureMipMap::Yes ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR)
- : (mipmap == TextureMipMap::Yes ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST)));
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
- filter == TextureFilter::Linear ? GL_LINEAR : GL_NEAREST));
- obj.filter = filter;
- obj.mipmap = mipmap;
+
+ if (filter != obj.filter || mipmap != obj.mipmap) {
+ MBGL_CHECK_ERROR(glTexParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ filter == TextureFilter::Linear
+ ? (mipmap == TextureMipMap::Yes ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR)
+ : (mipmap == TextureMipMap::Yes ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST)));
+ MBGL_CHECK_ERROR(
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+ filter == TextureFilter::Linear ? GL_LINEAR : GL_NEAREST));
+ obj.filter = filter;
+ obj.mipmap = mipmap;
+ }
+ if (wrapX != obj.wrapX) {
+
+ MBGL_CHECK_ERROR(
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
+ wrapX == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT));
+ obj.wrapX = wrapX;
+ }
+ if (wrapY != obj.wrapY) {
+ MBGL_CHECK_ERROR(
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
+ wrapY == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT));
+ obj.wrapY = wrapY;
+ }
} else if (texture[unit] != obj.texture) {
// We are checking first to avoid setting the active texture without a subsequent
// texture bind.
@@ -306,6 +353,7 @@ void Context::setDirtyState() {
depthTest.setDirty();
depthFunc.setDirty();
blend.setDirty();
+ blendEquation.setDirty();
blendFunc.setDirty();
blendColor.setDirty();
colorMask.setDirty();
@@ -316,8 +364,13 @@ void Context::setDirtyState() {
lineWidth.setDirty();
activeTexture.setDirty();
#if not MBGL_USE_GLES2
+ pointSize.setDirty();
pixelZoom.setDirty();
rasterPos.setDirty();
+ pixelStorePack.setDirty();
+ pixelStoreUnpack.setDirty();
+ pixelTransferDepth.setDirty();
+ pixelTransferStencil.setDirty();
#endif // MBGL_USE_GLES2
for (auto& tex : texture) {
tex.setDirty();
@@ -327,6 +380,153 @@ void Context::setDirtyState() {
vertexArrayObject.setDirty();
}
+void Context::clear(optional<mbgl::Color> color,
+ optional<float> depth,
+ optional<int32_t> stencil) {
+ GLbitfield mask = 0;
+
+ if (color) {
+ mask |= GL_COLOR_BUFFER_BIT;
+ clearColor = *color;
+ colorMask = { true, true, true, true };
+ }
+
+ if (depth) {
+ mask |= GL_DEPTH_BUFFER_BIT;
+ clearDepth = *depth;
+ depthMask = true;
+ }
+
+ if (stencil) {
+ mask |= GL_STENCIL_BUFFER_BIT;
+ clearStencil = *stencil;
+ stencilMask = 0xFF;
+ }
+
+ MBGL_CHECK_ERROR(glClear(mask));
+}
+
+#if not MBGL_USE_GLES2
+PrimitiveType Context::operator()(const Points& points) {
+ pointSize = points.pointSize;
+ return PrimitiveType::Points;
+}
+#else
+PrimitiveType Context::operator()(const Points&) {
+ return PrimitiveType::Points;
+}
+#endif // MBGL_USE_GLES2
+
+PrimitiveType Context::operator()(const Lines& lines) {
+ lineWidth = lines.lineWidth;
+ return PrimitiveType::Lines;
+}
+
+PrimitiveType Context::operator()(const LineStrip& lineStrip) {
+ lineWidth = lineStrip.lineWidth;
+ return PrimitiveType::LineStrip;
+}
+
+PrimitiveType Context::operator()(const Triangles&) {
+ return PrimitiveType::Triangles;
+}
+
+PrimitiveType Context::operator()(const TriangleStrip&) {
+ return PrimitiveType::TriangleStrip;
+}
+
+void Context::setDepthMode(const DepthMode& depth) {
+ if (depth.func == DepthMode::Always && !depth.mask) {
+ depthTest = false;
+ } else {
+ depthTest = true;
+ depthFunc = depth.func;
+ depthMask = depth.mask;
+ depthRange = depth.range;
+ }
+}
+
+void Context::setStencilMode(const StencilMode& stencil) {
+ if (stencil.test.is<StencilMode::Always>() && !stencil.mask) {
+ stencilTest = false;
+ } else {
+ stencilTest = true;
+ stencilMask = stencil.mask;
+ stencilOp = { stencil.fail, stencil.depthFail, stencil.pass };
+ apply_visitor([&] (const auto& test) {
+ stencilFunc = { test.func, stencil.ref, test.mask };
+ }, stencil.test);
+ }
+}
+
+void Context::setColorMode(const ColorMode& color) {
+ if (color.blendFunction.is<ColorMode::Replace>()) {
+ blend = false;
+ } else {
+ blend = true;
+ blendColor = color.blendColor;
+ apply_visitor([&] (const auto& blendFunction) {
+ blendEquation = ColorMode::BlendEquation(blendFunction.equation);
+ blendFunc = { blendFunction.srcFactor, blendFunction.dstFactor };
+ }, color.blendFunction);
+ }
+
+ colorMask = color.mask;
+}
+
+void Context::draw(const Drawable& drawable) {
+ if (drawable.segments.empty()) {
+ return;
+ }
+
+ PrimitiveType primitiveType = apply_visitor([&] (auto m) { return (*this)(m); }, drawable.drawMode);
+
+ setDepthMode(drawable.depthMode);
+ setStencilMode(drawable.stencilMode);
+ setColorMode(drawable.colorMode);
+
+ program = drawable.program;
+
+ drawable.bindUniforms();
+
+ for (const auto& segment : drawable.segments) {
+ auto needAttributeBindings = [&] () {
+ if (!gl::GenVertexArrays || !gl::BindVertexArray) {
+ return true;
+ }
+
+ if (segment.vao) {
+ vertexArrayObject = *segment.vao;
+ return false;
+ }
+
+ VertexArrayID id = 0;
+ MBGL_CHECK_ERROR(gl::GenVertexArrays(1, &id));
+ vertexArrayObject = id;
+ segment.vao = UniqueVertexArray(std::move(id), { this });
+
+ // If we are initializing a new VAO, we need to force the buffers
+ // to be rebound. VAOs don't inherit the existing buffer bindings.
+ vertexBuffer.setDirty();
+ elementBuffer.setDirty();
+
+ return true;
+ };
+
+ if (needAttributeBindings()) {
+ vertexBuffer = drawable.vertexBuffer;
+ elementBuffer = drawable.indexBuffer;
+ drawable.bindAttributes(segment.vertexOffset);
+ }
+
+ MBGL_CHECK_ERROR(glDrawElements(
+ static_cast<GLenum>(primitiveType),
+ static_cast<GLsizei>(segment.indexLength),
+ GL_UNSIGNED_SHORT,
+ reinterpret_cast<GLvoid*>(sizeof(uint16_t) * segment.indexOffset)));
+ }
+}
+
void Context::performCleanup() {
for (auto id : abandonedPrograms) {
if (program == id) {
diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp
index cf8bb2658b..093afa20ed 100644
--- a/src/mbgl/gl/context.hpp
+++ b/src/mbgl/gl/context.hpp
@@ -8,12 +8,21 @@
#include <mbgl/gl/framebuffer.hpp>
#include <mbgl/gl/vertex_buffer.hpp>
#include <mbgl/gl/index_buffer.hpp>
-#include <mbgl/gl/attribute.hpp>
+#include <mbgl/gl/types.hpp>
+#include <mbgl/gl/draw_mode.hpp>
+#include <mbgl/gl/depth_mode.hpp>
+#include <mbgl/gl/stencil_mode.hpp>
+#include <mbgl/gl/color_mode.hpp>
+#include <mbgl/gl/segment.hpp>
#include <mbgl/util/noncopyable.hpp>
+
+#include <functional>
#include <memory>
#include <vector>
#include <array>
+#include <string>
+#include <unordered_map>
namespace mbgl {
@@ -27,32 +36,31 @@ class Context : private util::noncopyable {
public:
~Context();
- UniqueProgram createProgram();
- UniqueShader createVertexShader();
- UniqueShader createFragmentShader();
+ UniqueShader createShader(ShaderType type, const std::string& source);
+ UniqueProgram createProgram(ShaderID vertexShader, ShaderID fragmentShader);
+ void linkProgram(ProgramID);
UniqueTexture createTexture();
- UniqueVertexArray createVertexArray();
- template <class V>
- VertexBuffer<V> createVertexBuffer(std::vector<V>&& v) {
- return VertexBuffer<V> {
- v.size(),
- createVertexBuffer(v.data(), v.size() * sizeof(V))
+ template <class Vertex, class DrawMode>
+ VertexBuffer<Vertex, DrawMode> createVertexBuffer(VertexVector<Vertex, DrawMode>&& v) {
+ return VertexBuffer<Vertex, DrawMode> {
+ v.vertexSize(),
+ createVertexBuffer(v.data(), v.byteSize())
};
}
- template <class P>
- IndexBuffer<P> createIndexBuffer(std::vector<P>&& v) {
- return IndexBuffer<P> {
- createIndexBuffer(v.data(), v.size() * sizeof(P))
+ template <class DrawMode>
+ IndexBuffer<DrawMode> createIndexBuffer(IndexVector<DrawMode>&& v) {
+ return IndexBuffer<DrawMode> {
+ createIndexBuffer(v.data(), v.byteSize())
};
}
template <RenderbufferType type>
- Renderbuffer<type> createRenderbuffer(const std::array<uint16_t, 2>& size) {
+ Renderbuffer<type> createRenderbuffer(const Size size) {
static_assert(type == RenderbufferType::RGBA || type == RenderbufferType::DepthStencil,
"invalid renderbuffer type");
- return { size, createRenderbuffer(type, size[0], size[1]) };
+ return { size, createRenderbuffer(type, size) };
}
Framebuffer createFramebuffer(const Renderbuffer<RenderbufferType::RGBA>&,
@@ -62,30 +70,73 @@ public:
const Renderbuffer<RenderbufferType::DepthStencil>&);
Framebuffer createFramebuffer(const Texture&);
+ template <typename Image,
+ TextureFormat format = Image::channels == 4 ? TextureFormat::RGBA
+ : TextureFormat::Alpha>
+ Image readFramebuffer(const Size size, bool flip = true) {
+ static_assert(Image::channels == (format == TextureFormat::RGBA ? 4 : 1),
+ "image format mismatch");
+ return { size, readFramebuffer(size, format, flip) };
+ }
+
+#if not MBGL_USE_GLES2
+ template <typename Image>
+ void drawPixels(const Image& image) {
+ auto format = image.channels == 4 ? TextureFormat::RGBA : TextureFormat::Alpha;
+ drawPixels(image.size, image.data.get(), format);
+ }
+#endif // MBGL_USE_GLES2
+
// Create a texture from an image with data.
template <typename Image>
Texture createTexture(const Image& image, TextureUnit unit = 0) {
- return { {{ image.width, image.height }},
- createTexture(image.width, image.height, image.data.get(), unit) };
+ auto format = image.channels == 4 ? TextureFormat::RGBA : TextureFormat::Alpha;
+ return { image.size, createTexture(image.size, image.data.get(), format, unit) };
+ }
+
+ template <typename Image>
+ void updateTexture(Texture& obj, const Image& image, TextureUnit unit = 0) {
+ auto format = image.channels == 4 ? TextureFormat::RGBA : TextureFormat::Alpha;
+ updateTexture(obj.texture.get(), image.size, image.data.get(), format, unit);
+ obj.size = image.size;
}
// Creates an empty texture with the specified dimensions.
- Texture createTexture(const std::array<uint16_t, 2>& size, TextureUnit unit = 0) {
- return { size, createTexture(size[0], size[1], nullptr, unit) };
+ Texture createTexture(const Size size,
+ TextureFormat format = TextureFormat::RGBA,
+ TextureUnit unit = 0) {
+ return { size, createTexture(size, nullptr, format, unit) };
}
void bindTexture(Texture&,
TextureUnit = 0,
TextureFilter = TextureFilter::Nearest,
- TextureMipMap = TextureMipMap::No);
-
- template <class Shader, class Vertex>
- void bindAttributes(const Shader& shader, const VertexBuffer<Vertex>&, const int8_t* offset) {
- static_assert(std::is_same<typename Shader::VertexType, Vertex>::value, "vertex type mismatch");
- for (const auto& binding : AttributeBindings<Shader, Vertex>()(shader)) {
- bindAttribute(binding, sizeof(Vertex), offset);
- }
- }
+ TextureMipMap = TextureMipMap::No,
+ TextureWrap wrapX = TextureWrap::Clamp,
+ TextureWrap wrapY = TextureWrap::Clamp);
+
+ void clear(optional<mbgl::Color> color,
+ optional<float> depth,
+ optional<int32_t> stencil);
+
+ struct Drawable {
+ DrawMode drawMode;
+ DepthMode depthMode;
+ StencilMode stencilMode;
+ ColorMode colorMode;
+ gl::ProgramID program;
+ gl::BufferID vertexBuffer;
+ gl::BufferID indexBuffer;
+ const std::vector<Segment>& segments;
+ std::function<void ()> bindUniforms;
+ std::function<void (std::size_t)> bindAttributes;
+ };
+
+ void draw(const Drawable&);
+
+ void setDepthMode(const DepthMode&);
+ void setStencilMode(const StencilMode&);
+ void setColorMode(const ColorMode&);
// Actually remove the objects we marked as abandoned with the above methods.
// Only call this while the OpenGL context is exclusive to this thread.
@@ -107,6 +158,23 @@ public:
void setDirtyState();
+ State<value::ActiveTexture> activeTexture;
+ State<value::BindFramebuffer> bindFramebuffer;
+ State<value::Viewport> viewport;
+ std::array<State<value::BindTexture>, 2> texture;
+ State<value::BindVertexArray> vertexArrayObject;
+ State<value::Program> program;
+
+#if not MBGL_USE_GLES2
+ State<value::PixelZoom> pixelZoom;
+ State<value::RasterPos> rasterPos;
+ State<value::PixelStorePack> pixelStorePack;
+ State<value::PixelStoreUnpack> pixelStoreUnpack;
+ State<value::PixelTransferDepth> pixelTransferDepth;
+ State<value::PixelTransferStencil> pixelTransferStencil;
+#endif // MBGL_USE_GLES2
+
+private:
State<value::StencilFunc> stencilFunc;
State<value::StencilMask> stencilMask;
State<value::StencilTest> stencilTest;
@@ -116,34 +184,37 @@ public:
State<value::DepthTest> depthTest;
State<value::DepthFunc> depthFunc;
State<value::Blend> blend;
+ State<value::BlendEquation> blendEquation;
State<value::BlendFunc> blendFunc;
State<value::BlendColor> blendColor;
State<value::ColorMask> colorMask;
State<value::ClearDepth> clearDepth;
State<value::ClearColor> clearColor;
State<value::ClearStencil> clearStencil;
- State<value::Program> program;
State<value::LineWidth> lineWidth;
- State<value::ActiveTexture> activeTexture;
- State<value::BindFramebuffer> bindFramebuffer;
- State<value::Viewport> viewport;
State<value::BindRenderbuffer> bindRenderbuffer;
#if not MBGL_USE_GLES2
- State<value::PixelZoom> pixelZoom;
- State<value::RasterPos> rasterPos;
+ State<value::PointSize> pointSize;
#endif // MBGL_USE_GLES2
- std::array<State<value::BindTexture>, 2> texture;
State<value::BindVertexBuffer> vertexBuffer;
State<value::BindElementBuffer> elementBuffer;
- State<value::BindVertexArray> vertexArrayObject;
-private:
UniqueBuffer createVertexBuffer(const void* data, std::size_t size);
UniqueBuffer createIndexBuffer(const void* data, std::size_t size);
- UniqueTexture createTexture(uint16_t width, uint16_t height, const void* data, TextureUnit);
+ UniqueTexture createTexture(Size size, const void* data, TextureFormat, TextureUnit);
+ void updateTexture(TextureID, Size size, const void* data, TextureFormat, TextureUnit);
UniqueFramebuffer createFramebuffer();
- UniqueRenderbuffer createRenderbuffer(RenderbufferType, uint16_t width, uint16_t height);
- void bindAttribute(const AttributeBinding&, std::size_t stride, const int8_t* offset);
+ UniqueRenderbuffer createRenderbuffer(RenderbufferType, Size size);
+ std::unique_ptr<uint8_t[]> readFramebuffer(Size, TextureFormat, bool flip);
+#if not MBGL_USE_GLES2
+ void drawPixels(Size size, const void* data, TextureFormat);
+#endif // MBGL_USE_GLES2
+
+ PrimitiveType operator()(const Points&);
+ PrimitiveType operator()(const Lines&);
+ PrimitiveType operator()(const LineStrip&);
+ PrimitiveType operator()(const Triangles&);
+ PrimitiveType operator()(const TriangleStrip&);
friend detail::ProgramDeleter;
friend detail::ShaderDeleter;
diff --git a/src/mbgl/gl/debugging.cpp b/src/mbgl/gl/debugging.cpp
index 1d82b6afb0..8037fc5ef5 100644
--- a/src/mbgl/gl/debugging.cpp
+++ b/src/mbgl/gl/debugging.cpp
@@ -2,8 +2,8 @@
#include <mbgl/gl/debugging.hpp>
#include <mbgl/gl/gl.hpp>
#include <mbgl/gl/extension.hpp>
-#include <mbgl/platform/event.hpp>
-#include <mbgl/platform/log.hpp>
+#include <mbgl/util/event.hpp>
+#include <mbgl/util/logging.hpp>
#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243
diff --git a/src/mbgl/gl/depth_mode.cpp b/src/mbgl/gl/depth_mode.cpp
new file mode 100644
index 0000000000..21af75a391
--- /dev/null
+++ b/src/mbgl/gl/depth_mode.cpp
@@ -0,0 +1,18 @@
+#include <mbgl/gl/depth_mode.hpp>
+#include <mbgl/gl/gl.hpp>
+#include <mbgl/util/traits.hpp>
+
+namespace mbgl {
+namespace gl {
+
+static_assert(underlying_type(DepthMode::Never) == GL_NEVER, "OpenGL enum mismatch");
+static_assert(underlying_type(DepthMode::Less) == GL_LESS, "OpenGL enum mismatch");
+static_assert(underlying_type(DepthMode::Equal) == GL_EQUAL, "OpenGL enum mismatch");
+static_assert(underlying_type(DepthMode::LessEqual) == GL_LEQUAL, "OpenGL enum mismatch");
+static_assert(underlying_type(DepthMode::Greater) == GL_GREATER, "OpenGL enum mismatch");
+static_assert(underlying_type(DepthMode::NotEqual) == GL_NOTEQUAL, "OpenGL enum mismatch");
+static_assert(underlying_type(DepthMode::GreaterEqual) == GL_GEQUAL, "OpenGL enum mismatch");
+static_assert(underlying_type(DepthMode::Always) == GL_ALWAYS, "OpenGL enum mismatch");
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/depth_mode.hpp b/src/mbgl/gl/depth_mode.hpp
new file mode 100644
index 0000000000..37617e3c34
--- /dev/null
+++ b/src/mbgl/gl/depth_mode.hpp
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <mbgl/util/range.hpp>
+
+namespace mbgl {
+namespace gl {
+
+class DepthMode {
+public:
+ enum Function {
+ Never = 0x0200,
+ Less = 0x0201,
+ Equal = 0x0202,
+ LessEqual = 0x0203,
+ Greater = 0x0204,
+ NotEqual = 0x0205,
+ GreaterEqual = 0x0206,
+ Always = 0x0207
+ };
+
+ enum Mask : bool {
+ ReadOnly = false,
+ ReadWrite = true
+ };
+
+ Function func;
+ Mask mask;
+ Range<float> range;
+
+ static DepthMode disabled() {
+ return DepthMode { Always, ReadOnly, { 0.0, 1.0 } };
+ }
+};
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/draw_mode.hpp b/src/mbgl/gl/draw_mode.hpp
new file mode 100644
index 0000000000..ab86d5e469
--- /dev/null
+++ b/src/mbgl/gl/draw_mode.hpp
@@ -0,0 +1,76 @@
+#pragma once
+
+#include <mbgl/gl/primitives.hpp>
+#include <mbgl/util/variant.hpp>
+
+#include <cassert>
+
+namespace mbgl {
+namespace gl {
+
+class Points {
+public:
+ using Primitive = Point;
+ static constexpr std::size_t bufferGroupSize = 1;
+
+ explicit Points(float pointSize_) : pointSize(pointSize_) {}
+
+ float pointSize;
+};
+
+class Lines {
+public:
+ using Primitive = Line;
+ static constexpr std::size_t bufferGroupSize = 2;
+
+ explicit Lines(float lineWidth_) : lineWidth(lineWidth_) {
+ assert(lineWidth > 0);
+ }
+
+ float lineWidth;
+};
+
+class LineStrip {
+public:
+ // LineStrip is a form of "Line" rendering, but the element buffer
+ // cannot be grouped into logical elements beyond a single Point.
+ using Primitive = Line;
+ static constexpr std::size_t bufferGroupSize = 1;
+
+ explicit LineStrip(float lineWidth_) : lineWidth(lineWidth_) {
+ assert(lineWidth > 0);
+ }
+
+ float lineWidth;
+};
+
+class Triangles {
+public:
+ using Primitive = Triangle;
+ static constexpr std::size_t bufferGroupSize = 3;
+};
+
+class TriangleStrip {
+public:
+ // TriangleStrip is a form of "Triangle" rendering, but the element buffer
+ // cannot be grouped into logical elements beyond a single Point.
+ using Primitive = Triangle;
+ static constexpr std::size_t bufferGroupSize = 1;
+};
+
+// Special draw mode for use with VertexVector<Indexed, Vertex>, in which
+// case the true draw mode is denoted by the IndexVector type.
+class Indexed {
+public:
+ static constexpr std::size_t bufferGroupSize = 1;
+};
+
+using DrawMode = variant<
+ Points,
+ Lines,
+ LineStrip,
+ Triangles,
+ TriangleStrip>;
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/extension.cpp b/src/mbgl/gl/extension.cpp
index ee94e8ecfd..e6b4d9156e 100644
--- a/src/mbgl/gl/extension.cpp
+++ b/src/mbgl/gl/extension.cpp
@@ -4,6 +4,7 @@
#include <mutex>
#include <string>
#include <vector>
+#include <cstring>
namespace mbgl {
namespace gl {
@@ -26,18 +27,14 @@ static std::once_flag initializeExtensionsOnce;
void InitializeExtensions(glProc (*getProcAddress)(const char*)) {
std::call_once(initializeExtensionsOnce, [getProcAddress] {
- const char* extensionsPtr =
- reinterpret_cast<const char*>(MBGL_CHECK_ERROR(glGetString(GL_EXTENSIONS)));
-
- if (!extensionsPtr)
- return;
-
- const std::string extensions = extensionsPtr;
- for (auto fn : detail::extensionFunctions()) {
- for (auto probe : fn.second) {
- if (extensions.find(probe.first) != std::string::npos) {
- *fn.first = getProcAddress(probe.second);
- break;
+ if (const char* extensions =
+ reinterpret_cast<const char*>(MBGL_CHECK_ERROR(glGetString(GL_EXTENSIONS)))) {
+ for (auto fn : detail::extensionFunctions()) {
+ for (auto probe : fn.second) {
+ if (strstr(extensions, probe.first) != nullptr) {
+ *fn.first = getProcAddress(probe.second);
+ break;
+ }
}
}
}
diff --git a/src/mbgl/gl/framebuffer.hpp b/src/mbgl/gl/framebuffer.hpp
index 880fed159e..91ed467b40 100644
--- a/src/mbgl/gl/framebuffer.hpp
+++ b/src/mbgl/gl/framebuffer.hpp
@@ -1,15 +1,14 @@
#pragma once
#include <mbgl/gl/object.hpp>
-
-#include <array>
+#include <mbgl/util/size.hpp>
namespace mbgl {
namespace gl {
class Framebuffer {
public:
- std::array<uint16_t, 2> size;
+ Size size;
gl::UniqueFramebuffer framebuffer;
};
diff --git a/src/mbgl/gl/index_buffer.hpp b/src/mbgl/gl/index_buffer.hpp
index f38d7fd4f5..b3610f4154 100644
--- a/src/mbgl/gl/index_buffer.hpp
+++ b/src/mbgl/gl/index_buffer.hpp
@@ -1,39 +1,38 @@
#pragma once
#include <mbgl/gl/object.hpp>
+#include <mbgl/gl/draw_mode.hpp>
+#include <mbgl/util/ignore.hpp>
+
+#include <vector>
namespace mbgl {
namespace gl {
-class Line {
+template <class DrawMode>
+class IndexVector {
public:
- Line(uint16_t a_, uint16_t b_)
- : a(a_), b(b_) {}
-
- uint16_t a;
- uint16_t b;
+ static constexpr std::size_t groupSize = DrawMode::bufferGroupSize;
- static constexpr std::size_t IndexCount = 2;
-};
+ template <class... Args>
+ void emplace_back(Args&&... args) {
+ static_assert(sizeof...(args) == groupSize, "wrong buffer element count");
+ util::ignore({(v.emplace_back(std::forward<Args>(args)), 0)...});
+ }
-class Triangle {
-public:
- Triangle(uint16_t a_, uint16_t b_, uint16_t c_)
- : a(a_), b(b_), c(c_) {}
+ std::size_t indexSize() const { return v.size(); }
+ std::size_t byteSize() const { return v.size() * sizeof(uint16_t); }
- uint16_t a;
- uint16_t b;
- uint16_t c;
+ bool empty() const { return v.empty(); }
+ const uint16_t* data() const { return v.data(); }
- static constexpr std::size_t IndexCount = 3;
+private:
+ std::vector<uint16_t> v;
};
-template <class Primitive>
+template <class DrawMode>
class IndexBuffer {
public:
- static_assert(std::is_same<Primitive, Line>::value || std::is_same<Primitive, Triangle>::value,
- "primitive must be Line or Triangle");
- static constexpr std::size_t primitiveSize = sizeof(Primitive);
UniqueBuffer buffer;
};
diff --git a/src/mbgl/gl/primitives.hpp b/src/mbgl/gl/primitives.hpp
new file mode 100644
index 0000000000..fe6b1b2e5b
--- /dev/null
+++ b/src/mbgl/gl/primitives.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+namespace mbgl {
+namespace gl {
+
+class Point {
+public:
+ static constexpr std::size_t vertexCount = 1;
+};
+
+class Line {
+public:
+ static constexpr std::size_t vertexCount = 2;
+};
+
+class Triangle {
+public:
+ static constexpr std::size_t vertexCount = 3;
+};
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/program.hpp b/src/mbgl/gl/program.hpp
new file mode 100644
index 0000000000..33387e9d4e
--- /dev/null
+++ b/src/mbgl/gl/program.hpp
@@ -0,0 +1,70 @@
+#pragma once
+
+#include <mbgl/gl/types.hpp>
+#include <mbgl/gl/object.hpp>
+#include <mbgl/gl/context.hpp>
+#include <mbgl/gl/vertex_buffer.hpp>
+#include <mbgl/gl/index_buffer.hpp>
+#include <mbgl/gl/attribute.hpp>
+#include <mbgl/gl/uniform.hpp>
+
+#include <string>
+
+namespace mbgl {
+namespace gl {
+
+template <class P, class As, class Us>
+class Program {
+public:
+ using Primitive = P;
+ using Attributes = As;
+ using Uniforms = Us;
+
+ using Vertex = typename Attributes::Vertex;
+ using UniformValues = typename Uniforms::Values;
+
+ static_assert(std::is_standard_layout<Vertex>::value, "vertex type must use standard layout");
+
+ Program(Context& context, const std::string& vertexSource, const std::string& fragmentSource)
+ : vertexShader(context.createShader(ShaderType::Vertex, vertexSource)),
+ fragmentShader(context.createShader(ShaderType::Fragment, fragmentSource)),
+ program(context.createProgram(vertexShader, fragmentShader)),
+ attributesState(Attributes::state(program)),
+ uniformsState((context.linkProgram(program), Uniforms::state(program))) {}
+
+ template <class DrawMode>
+ void draw(Context& context,
+ DrawMode drawMode,
+ DepthMode depthMode,
+ StencilMode stencilMode,
+ ColorMode colorMode,
+ UniformValues&& uniformValues,
+ const VertexBuffer<Vertex>& vertexBuffer,
+ const IndexBuffer<DrawMode>& indexBuffer,
+ const SegmentVector<Attributes>& segments) {
+ static_assert(std::is_same<Primitive, typename DrawMode::Primitive>::value, "incompatible draw mode");
+ context.draw({
+ std::move(drawMode),
+ std::move(depthMode),
+ std::move(stencilMode),
+ std::move(colorMode),
+ program,
+ vertexBuffer.buffer,
+ indexBuffer.buffer,
+ segments,
+ Uniforms::binder(uniformsState, std::move(uniformValues)),
+ Attributes::binder(attributesState)
+ });
+ }
+
+private:
+ UniqueShader vertexShader;
+ UniqueShader fragmentShader;
+ UniqueProgram program;
+
+ typename Attributes::State attributesState;
+ typename Uniforms::State uniformsState;
+};
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/renderbuffer.hpp b/src/mbgl/gl/renderbuffer.hpp
index 9e8993bb77..cc8ff13268 100644
--- a/src/mbgl/gl/renderbuffer.hpp
+++ b/src/mbgl/gl/renderbuffer.hpp
@@ -1,8 +1,7 @@
#pragma once
#include <mbgl/gl/object.hpp>
-
-#include <array>
+#include <mbgl/util/size.hpp>
namespace mbgl {
namespace gl {
@@ -11,7 +10,7 @@ template <RenderbufferType renderbufferType>
class Renderbuffer {
public:
using type = std::integral_constant<RenderbufferType, renderbufferType>;
- std::array<uint16_t, 2> size;
+ Size size;
gl::UniqueRenderbuffer renderbuffer;
};
diff --git a/src/mbgl/gl/segment.hpp b/src/mbgl/gl/segment.hpp
new file mode 100644
index 0000000000..8f74afd237
--- /dev/null
+++ b/src/mbgl/gl/segment.hpp
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <mbgl/util/optional.hpp>
+
+#include <cstddef>
+
+namespace mbgl {
+namespace gl {
+
+class Segment {
+public:
+ Segment(std::size_t vertexOffset_,
+ std::size_t indexOffset_,
+ std::size_t vertexLength_ = 0,
+ std::size_t indexLength_ = 0)
+ : vertexOffset(vertexOffset_),
+ indexOffset(indexOffset_),
+ vertexLength(vertexLength_),
+ indexLength(indexLength_) {}
+
+ const std::size_t vertexOffset;
+ const std::size_t indexOffset;
+
+ std::size_t vertexLength;
+ std::size_t indexLength;
+
+private:
+ friend class Context;
+ mutable optional<UniqueVertexArray> vao;
+};
+
+template <class Attributes>
+class SegmentVector : public std::vector<Segment> {
+public:
+ SegmentVector() = default;
+};
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/shader.cpp b/src/mbgl/gl/shader.cpp
deleted file mode 100644
index d8ee734567..0000000000
--- a/src/mbgl/gl/shader.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-#include <mbgl/gl/shader.hpp>
-#include <mbgl/gl/gl.hpp>
-#include <mbgl/gl/context.hpp>
-#include <mbgl/util/stopwatch.hpp>
-#include <mbgl/util/exception.hpp>
-#include <mbgl/platform/log.hpp>
-#include <mbgl/platform/platform.hpp>
-
-#include <cstring>
-#include <cassert>
-#include <iostream>
-#include <string>
-#include <fstream>
-#include <cstdio>
-#include <cassert>
-
-namespace mbgl {
-namespace gl {
-
-Shader::Shader(const char* name_,
- const char* vertexSource,
- const char* fragmentSource,
- Context& context,
- Defines defines)
- : name(name_),
- program(context.createProgram()),
- vertexShader(context.createVertexShader()),
- fragmentShader(context.createFragmentShader()) {
- util::stopwatch stopwatch("shader compilation", Event::Shader);
-
- if (!compileShader(vertexShader, vertexSource)) {
- Log::Error(Event::Shader, "Vertex shader %s failed to compile: %s", name, vertexSource);
- throw util::ShaderException(std::string { "Vertex shader " } + name + " failed to compile");
- }
-
- std::string fragment(fragmentSource);
- if (defines & Defines::Overdraw) {
- assert(fragment.find("#ifdef OVERDRAW_INSPECTOR") != std::string::npos);
- fragment.replace(fragment.find_first_of('\n'), 1, "\n#define OVERDRAW_INSPECTOR\n");
- }
-
- if (!compileShader(fragmentShader, fragment.c_str())) {
- Log::Error(Event::Shader, "Fragment shader %s failed to compile: %s", name, fragmentSource);
- throw util::ShaderException(std::string { "Fragment shader " } + name + " failed to compile");
- }
-
- // Attach shaders
- MBGL_CHECK_ERROR(glAttachShader(program.get(), vertexShader.get()));
- MBGL_CHECK_ERROR(glAttachShader(program.get(), fragmentShader.get()));
-
- // Link program
- GLint status;
- MBGL_CHECK_ERROR(glLinkProgram(program.get()));
-
- MBGL_CHECK_ERROR(glGetProgramiv(program.get(), GL_LINK_STATUS, &status));
- if (status == 0) {
- GLint logLength;
- MBGL_CHECK_ERROR(glGetProgramiv(program.get(), GL_INFO_LOG_LENGTH, &logLength));
- const auto log = std::make_unique<GLchar[]>(logLength);
- if (logLength > 0) {
- MBGL_CHECK_ERROR(glGetProgramInfoLog(program.get(), logLength, &logLength, log.get()));
- Log::Error(Event::Shader, "Program failed to link: %s", log.get());
- }
- throw util::ShaderException(std::string { "Program " } + name + " failed to link: " + log.get());
- }
-}
-
-bool Shader::compileShader(UniqueShader& shader, const GLchar *source) {
- GLint status = 0;
-
- const GLsizei lengths = static_cast<GLsizei>(std::strlen(source));
- MBGL_CHECK_ERROR(glShaderSource(shader.get(), 1, &source, &lengths));
-
- MBGL_CHECK_ERROR(glCompileShader(shader.get()));
-
- MBGL_CHECK_ERROR(glGetShaderiv(shader.get(), GL_COMPILE_STATUS, &status));
- if (status == 0) {
- GLint logLength;
- MBGL_CHECK_ERROR(glGetShaderiv(shader.get(), GL_INFO_LOG_LENGTH, &logLength));
- if (logLength > 0) {
- const auto log = std::make_unique<GLchar[]>(logLength);
- MBGL_CHECK_ERROR(glGetShaderInfoLog(shader.get(), logLength, &logLength, log.get()));
- Log::Error(Event::Shader, "Shader failed to compile: %s", log.get());
- }
- return false;
- }
-
- MBGL_CHECK_ERROR(glGetShaderiv(shader.get(), GL_COMPILE_STATUS, &status));
- if (status == GL_FALSE) {
- Log::Error(Event::Shader, "Shader %s failed to compile.", name);
- return false;
- }
-
- return true;
-}
-
-Shader::~Shader() {
- if (program.get()) {
- MBGL_CHECK_ERROR(glDetachShader(program.get(), vertexShader.get()));
- MBGL_CHECK_ERROR(glDetachShader(program.get(), fragmentShader.get()));
- }
-}
-
-UniformLocation Shader::getUniformLocation(const char* uniform) const {
- return MBGL_CHECK_ERROR(glGetUniformLocation(program.get(), uniform));
-}
-
-AttributeLocation Shader::getAttributeLocation(const char* attribute) const {
- return MBGL_CHECK_ERROR(glGetAttribLocation(program.get(), attribute));
-}
-
-} // namespace gl
-} // namespace mbgl
diff --git a/src/mbgl/gl/shader.hpp b/src/mbgl/gl/shader.hpp
deleted file mode 100644
index f88bd4f867..0000000000
--- a/src/mbgl/gl/shader.hpp
+++ /dev/null
@@ -1,45 +0,0 @@
-#pragma once
-
-#include <mbgl/gl/types.hpp>
-#include <mbgl/gl/object.hpp>
-#include <mbgl/util/noncopyable.hpp>
-
-namespace mbgl {
-namespace gl {
-
-class Context;
-
-class Shader : private util::noncopyable {
-public:
- ~Shader();
- const char* name;
-
- ProgramID getID() const {
- return program.get();
- }
-
- AttributeLocation getAttributeLocation(const char* uniform) const;
- UniformLocation getUniformLocation(const char* uniform) const;
-
- enum Defines : bool {
- None = false,
- Overdraw = true,
- };
-
-protected:
- Shader(const char* name_,
- const char* vertex,
- const char* fragment,
- Context&,
- Defines defines = Defines::None);
-
-private:
- bool compileShader(UniqueShader&, const char *source);
-
- UniqueProgram program;
- UniqueShader vertexShader;
- UniqueShader fragmentShader;
-};
-
-} // namespace gl
-} // namespace mbgl
diff --git a/src/mbgl/gl/stencil_mode.cpp b/src/mbgl/gl/stencil_mode.cpp
new file mode 100644
index 0000000000..6858d6d106
--- /dev/null
+++ b/src/mbgl/gl/stencil_mode.cpp
@@ -0,0 +1,27 @@
+#include <mbgl/gl/stencil_mode.hpp>
+#include <mbgl/gl/gl.hpp>
+#include <mbgl/util/traits.hpp>
+
+namespace mbgl {
+namespace gl {
+
+static_assert(StencilMode::Never::func == GL_NEVER, "OpenGL enum mismatch");
+static_assert(StencilMode::Less::func == GL_LESS, "OpenGL enum mismatch");
+static_assert(StencilMode::Equal::func == GL_EQUAL, "OpenGL enum mismatch");
+static_assert(StencilMode::LessEqual::func == GL_LEQUAL, "OpenGL enum mismatch");
+static_assert(StencilMode::Greater::func == GL_GREATER, "OpenGL enum mismatch");
+static_assert(StencilMode::NotEqual::func == GL_NOTEQUAL, "OpenGL enum mismatch");
+static_assert(StencilMode::GreaterEqual::func == GL_GEQUAL, "OpenGL enum mismatch");
+static_assert(StencilMode::Always::func == GL_ALWAYS, "OpenGL enum mismatch");
+
+static_assert(underlying_type(StencilMode::Keep) == GL_KEEP, "OpenGL enum mismatch");
+static_assert(underlying_type(StencilMode::Zero) == GL_ZERO, "OpenGL enum mismatch");
+static_assert(underlying_type(StencilMode::Replace) == GL_REPLACE, "OpenGL enum mismatch");
+static_assert(underlying_type(StencilMode::Increment) == GL_INCR, "OpenGL enum mismatch");
+static_assert(underlying_type(StencilMode::IncrementWrap) == GL_INCR_WRAP, "OpenGL enum mismatch");
+static_assert(underlying_type(StencilMode::Decrement) == GL_DECR, "OpenGL enum mismatch");
+static_assert(underlying_type(StencilMode::DecrementWrap) == GL_DECR_WRAP, "OpenGL enum mismatch");
+static_assert(underlying_type(StencilMode::Invert) == GL_INVERT, "OpenGL enum mismatch");
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/stencil_mode.hpp b/src/mbgl/gl/stencil_mode.hpp
new file mode 100644
index 0000000000..bc959c9a73
--- /dev/null
+++ b/src/mbgl/gl/stencil_mode.hpp
@@ -0,0 +1,66 @@
+#pragma once
+
+#include <mbgl/util/variant.hpp>
+
+namespace mbgl {
+namespace gl {
+
+class StencilMode {
+public:
+ template <uint32_t F>
+ struct SimpleTest {
+ static constexpr uint32_t func = F;
+ static constexpr uint32_t mask = 0;
+ };
+
+ template <uint32_t F>
+ struct MaskedTest {
+ static constexpr uint32_t func = F;
+ uint32_t mask;
+ };
+
+ using Never = SimpleTest<0x0200>;
+ using Less = MaskedTest<0x0201>;
+ using Equal = MaskedTest<0x0202>;
+ using LessEqual = MaskedTest<0x0203>;
+ using Greater = MaskedTest<0x0204>;
+ using NotEqual = MaskedTest<0x0205>;
+ using GreaterEqual = MaskedTest<0x0206>;
+ using Always = SimpleTest<0x0207>;
+
+ using Test = variant<
+ Never,
+ Less,
+ Equal,
+ LessEqual,
+ Greater,
+ NotEqual,
+ GreaterEqual,
+ Always>;
+
+ enum Op {
+ Zero = 0x0000,
+ Keep = 0x1E00,
+ Replace = 0x1E01,
+ Increment = 0x1E02,
+ Decrement = 0x1E03,
+ Invert = 0x150A,
+ IncrementWrap = 0x8507,
+ DecrementWrap = 0x8508
+ };
+
+ Test test;
+ int32_t ref;
+ uint32_t mask;
+
+ Op fail;
+ Op depthFail;
+ Op pass;
+
+ static StencilMode disabled() {
+ return StencilMode { Always(), 0, 0, Keep, Keep, Keep };
+ }
+};
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/texture.hpp b/src/mbgl/gl/texture.hpp
index 49e1323095..5330689ac2 100644
--- a/src/mbgl/gl/texture.hpp
+++ b/src/mbgl/gl/texture.hpp
@@ -1,18 +1,19 @@
#pragma once
#include <mbgl/gl/object.hpp>
-
-#include <array>
+#include <mbgl/util/size.hpp>
namespace mbgl {
namespace gl {
class Texture {
public:
- std::array<uint16_t, 2> size;
+ Size size;
UniqueTexture texture;
TextureFilter filter = TextureFilter::Nearest;
TextureMipMap mipmap = TextureMipMap::No;
+ TextureWrap wrapX = TextureWrap::Clamp;
+ TextureWrap wrapY = TextureWrap::Clamp;
};
} // namespace gl
diff --git a/src/mbgl/gl/types.hpp b/src/mbgl/gl/types.hpp
index dccc61b03a..577629d5d3 100644
--- a/src/mbgl/gl/types.hpp
+++ b/src/mbgl/gl/types.hpp
@@ -19,9 +19,10 @@ using AttributeLocation = int32_t;
using UniformLocation = int32_t;
using TextureUnit = uint8_t;
-using DepthValue = double;
-using StencilValue = int32_t;
-using StencilMaskValue = uint32_t;
+enum class ShaderType : uint32_t {
+ Vertex = 0x8B31,
+ Fragment = 0x8B30
+};
enum class DataType : uint32_t {
Byte = 0x1400,
@@ -43,11 +44,6 @@ template <> struct DataTypeOf<int32_t> : std::integral_constant<DataType, DataT
template <> struct DataTypeOf<uint32_t> : std::integral_constant<DataType, DataType::UnsignedInteger> {};
template <> struct DataTypeOf<float> : std::integral_constant<DataType, DataType::Float> {};
-enum class BufferType : uint32_t {
- Vertex = 0x8892,
- Element = 0x8893
-};
-
enum class RenderbufferType : uint32_t {
RGBA = 0x8058,
DepthStencil = 0x88F0,
@@ -55,74 +51,37 @@ enum class RenderbufferType : uint32_t {
enum class TextureMipMap : bool { No = false, Yes = true };
enum class TextureFilter : bool { Nearest = false, Linear = true };
-
-enum class StencilTestFunction : uint32_t {
- Never = 0x0200,
- Less = 0x0201,
- Equal = 0x0202,
- LessEqual = 0x0203,
- Greater = 0x0204,
- NotEqual = 0x0205,
- GreaterEqual = 0x0206,
- Always = 0x0207,
+enum class TextureWrap : bool { Clamp, Repeat };
+enum class TextureFormat : uint32_t {
+ RGBA = 0x1908,
+ Alpha = 0x1906,
+#if not MBGL_USE_GLES2
+ Stencil = 0x1901,
+ Depth = 0x1902,
+#endif // MBGL_USE_GLES2
};
-enum class StencilTestOperation : uint32_t {
- Keep = 0x1E00,
- Zero = 0x0000,
- Replace = 0x1E01,
- Increment = 0x1E02,
- IncrementWrap = 0x8507,
- Decrement = 0x1E03,
- DecrementWrap = 0x8508,
- Invert = 0x150A,
+enum class PrimitiveType {
+ Points = 0x0000,
+ Lines = 0x0001,
+ LineLoop = 0x0002,
+ LineStrip = 0x0003,
+ Triangles = 0x0004,
+ TriangleStrip = 0x0005,
+ TriangleFan = 0x0006
};
-enum class DepthTestFunction : uint32_t {
- Never = 0x0200,
- Less = 0x0201,
- Equal = 0x0202,
- LessEqual = 0x0203,
- Greater = 0x0204,
- NotEqual = 0x0205,
- GreaterEqual = 0x0206,
- Always = 0x0207,
-};
+#if not MBGL_USE_GLES2
-enum class BlendSourceFactor : uint32_t {
- Zero = 0x0000,
- One = 0x0001,
- SrcColor = 0x0300,
- OneMinusSrcColor = 0x0301,
- DstColor = 0x0306,
- OneMinusDstColor = 0x0307,
- SrcAlpha = 0x0302,
- OneMinusSrcAlpha = 0x0303,
- DstAlpha = 0x0304,
- OneMinusDstAlpha = 0x0305,
- ConstantColor = 0x8001,
- OneMinusConstantColor = 0x8002,
- ConstantAlpha = 0x8003,
- OneMinusConstantAlpha = 0x8004,
- SrcAlphaSaturate = 0x0308,
+struct PixelStorageType {
+ int32_t alignment;
};
-enum class BlendDestinationFactor : uint32_t {
- Zero = 0x0000,
- One = 0x0001,
- SrcColor = 0x0300,
- OneMinusSrcColor = 0x0301,
- DstColor = 0x0306,
- OneMinusDstColor = 0x0307,
- SrcAlpha = 0x0302,
- OneMinusSrcAlpha = 0x0303,
- DstAlpha = 0x0304,
- OneMinusDstAlpha = 0x0305,
- ConstantColor = 0x8001,
- OneMinusConstantColor = 0x8002,
- ConstantAlpha = 0x8003,
- OneMinusConstantAlpha = 0x8004,
-};
+constexpr bool operator!=(const PixelStorageType& a, const PixelStorageType& b) {
+ return a.alignment != b.alignment;
+}
+
+#endif // MBGL_USE_GLES2
} // namespace gl
} // namespace mbgl
diff --git a/src/mbgl/gl/uniform.cpp b/src/mbgl/gl/uniform.cpp
index 07a27963d9..7b674f2cde 100644
--- a/src/mbgl/gl/uniform.cpp
+++ b/src/mbgl/gl/uniform.cpp
@@ -1,54 +1,80 @@
#include <mbgl/gl/uniform.hpp>
#include <mbgl/gl/gl.hpp>
#include <mbgl/util/color.hpp>
+#include <mbgl/util/size.hpp>
+#include <mbgl/util/convert.hpp>
namespace mbgl {
namespace gl {
+UniformLocation uniformLocation(ProgramID id, const char* name) {
+ return MBGL_CHECK_ERROR(glGetUniformLocation(id, name));
+}
+
template <>
-void Uniform<float>::bind(const float& t) {
+void bindUniform<float>(UniformLocation location, const float& t) {
MBGL_CHECK_ERROR(glUniform1f(location, t));
}
template <>
-void Uniform<int32_t>::bind(const int32_t& t) {
+void bindUniform<int32_t>(UniformLocation location, const int32_t& t) {
MBGL_CHECK_ERROR(glUniform1i(location, t));
}
template <>
-void Uniform<std::array<float, 2>>::bind(const std::array<float, 2>& t) {
+void bindUniform<std::array<float, 2>>(UniformLocation location, const std::array<float, 2>& t) {
MBGL_CHECK_ERROR(glUniform2fv(location, 1, t.data()));
}
template <>
-void Uniform<std::array<float, 3>>::bind(const std::array<float, 3>& t) {
+void bindUniform<std::array<float, 3>>(UniformLocation location, const std::array<float, 3>& t) {
MBGL_CHECK_ERROR(glUniform3fv(location, 1, t.data()));
}
template <>
-void Uniform<std::array<float, 4>>::bind(const std::array<float, 4>& t) {
+void bindUniform<std::array<float, 4>>(UniformLocation location, const std::array<float, 4>& t) {
MBGL_CHECK_ERROR(glUniform4fv(location, 1, t.data()));
}
template <>
-void Uniform<Color>::bind(const Color& t) {
- std::array<float, 4> a = {{ t.r, t.g, t.b, t.a }};
- MBGL_CHECK_ERROR(glUniform4fv(location, 1, a.data()));
+void bindUniform<std::array<double, 4>>(UniformLocation location, const std::array<double, 4>& t) {
+ MBGL_CHECK_ERROR(glUniformMatrix2fv(location, 1, GL_FALSE, util::convert<float>(t).data()));
+}
+
+template <>
+void bindUniform<std::array<double, 9>>(UniformLocation location, const std::array<double, 9>& t) {
+ MBGL_CHECK_ERROR(glUniformMatrix3fv(location, 1, GL_FALSE, util::convert<float>(t).data()));
+}
+
+template <>
+void bindUniform<std::array<double, 16>>(UniformLocation location, const std::array<double, 16>& t) {
+ MBGL_CHECK_ERROR(glUniformMatrix4fv(location, 1, GL_FALSE, util::convert<float>(t).data()));
+}
+
+
+template <>
+void bindUniform<bool>(UniformLocation location, const bool& t) {
+ return bindUniform(location, int32_t(t));
+}
+
+template <>
+void bindUniform<uint8_t>(UniformLocation location, const uint8_t& t) {
+ bindUniform(location, int32_t(t));
}
template <>
-void UniformMatrix<2>::bind(const std::array<float, 4>& t) {
- MBGL_CHECK_ERROR(glUniformMatrix2fv(location, 1, GL_FALSE, t.data()));
+void bindUniform<Color>(UniformLocation location, const Color& t) {
+ bindUniform(location, std::array<float, 4> {{ t.r, t.g, t.b, t.a }});
}
template <>
-void UniformMatrix<3>::bind(const std::array<float, 9>& t) {
- MBGL_CHECK_ERROR(glUniformMatrix3fv(location, 1, GL_FALSE, t.data()));
+void bindUniform<Size>(UniformLocation location, const Size& t) {
+ bindUniform(location, util::convert<float>(std::array<uint32_t, 2> {{ t.width, t.height }}));
}
template <>
-void UniformMatrix<4>::bind(const std::array<float, 16>& t) {
- MBGL_CHECK_ERROR(glUniformMatrix4fv(location, 1, GL_FALSE, t.data()));
+void bindUniform<std::array<uint16_t, 2>>(UniformLocation location, const std::array<uint16_t, 2>& t) {
+ bindUniform(location, util::convert<float>(t));
}
// Add more as needed.
diff --git a/src/mbgl/gl/uniform.hpp b/src/mbgl/gl/uniform.hpp
index 5af781043d..726cd4fe10 100644
--- a/src/mbgl/gl/uniform.hpp
+++ b/src/mbgl/gl/uniform.hpp
@@ -1,60 +1,80 @@
#pragma once
-#include <mbgl/gl/shader.hpp>
+#include <mbgl/gl/types.hpp>
+#include <mbgl/util/optional.hpp>
+#include <mbgl/util/ignore.hpp>
+#include <mbgl/util/indexed_tuple.hpp>
#include <array>
+#include <functional>
namespace mbgl {
namespace gl {
-template <typename T>
+template <class T>
+void bindUniform(UniformLocation, const T&);
+
+template <class Tag, class T>
+class UniformValue {
+public:
+ explicit UniformValue(T t_) : t(std::move(t_)) {}
+ T t;
+};
+
+template <class Tag, class T>
class Uniform {
public:
- Uniform(const char* name, const Shader& shader)
- : current(), location(shader.getUniformLocation(name)) {
- }
+ using Value = UniformValue<Tag, T>;
- void operator=(const T& t) {
- if (current != t) {
- current = t;
- bind(t);
+ class State {
+ public:
+ void operator=(const Value& value) {
+ if (!current || *current != value.t) {
+ current = value.t;
+ bindUniform(location, value.t);
+ }
}
- }
-
-private:
- void bind(const T&);
- T current;
- UniformLocation location;
+ UniformLocation location;
+ optional<T> current = {};
+ };
};
-template <size_t C, size_t R = C>
-class UniformMatrix {
+template <class Tag, class T>
+using UniformScalar = Uniform<Tag, T>;
+
+template <class Tag, class T, size_t N>
+using UniformVector = Uniform<Tag, std::array<T, N>>;
+
+template <class Tag, class T, size_t N>
+using UniformMatrix = Uniform<Tag, std::array<T, N*N>>;
+
+#define MBGL_DEFINE_UNIFORM_SCALAR(type_, name_) \
+ struct name_ : ::mbgl::gl::UniformScalar<name_, type_> { static constexpr auto name = #name_; }
+
+#define MBGL_DEFINE_UNIFORM_VECTOR(type_, n_, name_) \
+ struct name_ : ::mbgl::gl::UniformVector<name_, type_, n_> { static constexpr auto name = #name_; }
+
+#define MBGL_DEFINE_UNIFORM_MATRIX(type_, n_, name_) \
+ struct name_ : ::mbgl::gl::UniformMatrix<name_, type_, n_> { static constexpr auto name = #name_; }
+
+UniformLocation uniformLocation(ProgramID, const char * name);
+
+template <class... Us>
+class Uniforms {
public:
- typedef std::array<float, C*R> T;
+ using State = IndexedTuple<TypeList<Us...>, TypeList<typename Us::State...>>;
+ using Values = IndexedTuple<TypeList<Us...>, TypeList<typename Us::Value...>>;
- UniformMatrix(const char* name, const Shader& shader)
- : current(), location(shader.getUniformLocation(name)) {
+ static State state(const ProgramID& id) {
+ return State { { uniformLocation(id, Us::name) }... };
}
- void operator=(const std::array<double, C*R>& t) {
- bool dirty = false;
- for (unsigned int i = 0; i < C*R; i++) {
- if (current[i] != t[i]) {
- current[i] = t[i];
- dirty = true;
- }
- }
- if (dirty) {
- bind(current);
- }
+ static std::function<void ()> binder(State& state, Values&& values_) {
+ return [&state, values = std::move(values_)] () mutable {
+ util::ignore({ (state.template get<Us>() = values.template get<Us>(), 0)... });
+ };
}
-
-private:
- void bind(const T&);
-
- T current;
- UniformLocation location;
};
} // namespace gl
diff --git a/src/mbgl/gl/value.cpp b/src/mbgl/gl/value.cpp
index 14cd03efc4..86218f3d9a 100644
--- a/src/mbgl/gl/value.cpp
+++ b/src/mbgl/gl/value.cpp
@@ -94,7 +94,7 @@ StencilFunc::Type StencilFunc::Get() {
MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_FUNC, &func));
MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_REF, &ref));
MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_VALUE_MASK, &mask));
- return { static_cast<StencilTestFunction>(func), ref, static_cast<StencilMaskValue>(mask) };
+ return { static_cast<uint32_t>(func), ref, static_cast<uint32_t>(mask) };
}
const constexpr StencilTest::Type StencilTest::Default;
@@ -122,17 +122,17 @@ StencilOp::Type StencilOp::Get() {
MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_FAIL, &sfail));
MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &dpfail));
MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &dppass));
- return { static_cast<StencilTestOperation>(sfail), static_cast<StencilTestOperation>(dpfail),
- static_cast<StencilTestOperation>(dppass) };
+ return { static_cast<StencilMode::Op>(sfail), static_cast<StencilMode::Op>(dpfail),
+ static_cast<StencilMode::Op>(dppass) };
}
const constexpr DepthRange::Type DepthRange::Default;
void DepthRange::Set(const Type& value) {
#if MBGL_USE_GLES2
- MBGL_CHECK_ERROR(glDepthRangef(value.near, value.far));
+ MBGL_CHECK_ERROR(glDepthRangef(value.min, value.max));
#else
- MBGL_CHECK_ERROR(glDepthRange(value.near, value.far));
+ MBGL_CHECK_ERROR(glDepthRange(value.min, value.max));
#endif
}
@@ -178,6 +178,18 @@ Blend::Type Blend::Get() {
return blend;
}
+const constexpr BlendEquation::Type BlendEquation::Default;
+
+void BlendEquation::Set(const Type& value) {
+ MBGL_CHECK_ERROR(glBlendEquation(static_cast<GLenum>(value)));
+}
+
+BlendEquation::Type BlendEquation::Get() {
+ GLint blend;
+ MBGL_CHECK_ERROR(glGetIntegerv(GL_BLEND_EQUATION_RGB, &blend));
+ return static_cast<Type>(blend);
+}
+
const constexpr BlendFunc::Type BlendFunc::Default;
void BlendFunc::Set(const Type& value) {
@@ -189,8 +201,8 @@ BlendFunc::Type BlendFunc::Get() {
GLint sfactor, dfactor;
MBGL_CHECK_ERROR(glGetIntegerv(GL_BLEND_SRC_ALPHA, &sfactor));
MBGL_CHECK_ERROR(glGetIntegerv(GL_BLEND_DST_ALPHA, &dfactor));
- return { static_cast<BlendSourceFactor>(sfactor),
- static_cast<BlendDestinationFactor>(dfactor) };
+ return { static_cast<ColorMode::BlendFactor>(sfactor),
+ static_cast<ColorMode::BlendFactor>(dfactor) };
}
const constexpr BlendColor::Type BlendColor::Default;
@@ -244,14 +256,14 @@ ActiveTexture::Type ActiveTexture::Get() {
const constexpr Viewport::Type Viewport::Default;
void Viewport::Set(const Type& value) {
- MBGL_CHECK_ERROR(glViewport(value.x, value.y, value.width, value.height));
+ MBGL_CHECK_ERROR(glViewport(value.x, value.y, value.size.width, value.size.height));
}
Viewport::Type Viewport::Get() {
GLint viewport[4];
MBGL_CHECK_ERROR(glGetIntegerv(GL_VIEWPORT, viewport));
return { static_cast<int32_t>(viewport[0]), static_cast<int32_t>(viewport[1]),
- static_cast<uint16_t>(viewport[2]), static_cast<uint16_t>(viewport[3]) };
+ { static_cast<uint32_t>(viewport[2]), static_cast<uint32_t>(viewport[3]) } };
}
const constexpr BindFramebuffer::Type BindFramebuffer::Default;
@@ -340,6 +352,18 @@ BindVertexArray::Type BindVertexArray::Get() {
#if not MBGL_USE_GLES2
+const constexpr PointSize::Type PointSize::Default;
+
+void PointSize::Set(const Type& value) {
+ MBGL_CHECK_ERROR(glPointSize(value));
+}
+
+PointSize::Type PointSize::Get() {
+ GLfloat pointSize;
+ MBGL_CHECK_ERROR(glGetFloatv(GL_POINT_SIZE, &pointSize));
+ return pointSize;
+}
+
const constexpr PixelZoom::Type PixelZoom::Default;
void PixelZoom::Set(const Type& value) {
@@ -365,8 +389,63 @@ RasterPos::Type RasterPos::Get() {
return { pos[0], pos[1], pos[2], pos[3] };
}
-#endif // MBGL_USE_GLES2
+const constexpr PixelStorePack::Type PixelStorePack::Default;
+
+void PixelStorePack::Set(const Type& value) {
+ assert(value.alignment == 1 || value.alignment == 2 || value.alignment == 4 ||
+ value.alignment == 8);
+ MBGL_CHECK_ERROR(glPixelStorei(GL_PACK_ALIGNMENT, value.alignment));
+}
+
+PixelStorePack::Type PixelStorePack::Get() {
+ Type value;
+ MBGL_CHECK_ERROR(glGetIntegerv(GL_PACK_ALIGNMENT, &value.alignment));
+ return value;
+}
+
+const constexpr PixelStoreUnpack::Type PixelStoreUnpack::Default;
+void PixelStoreUnpack::Set(const Type& value) {
+ assert(value.alignment == 1 || value.alignment == 2 || value.alignment == 4 ||
+ value.alignment == 8);
+ MBGL_CHECK_ERROR(glPixelStorei(GL_UNPACK_ALIGNMENT, value.alignment));
+}
+
+PixelStoreUnpack::Type PixelStoreUnpack::Get() {
+ Type value;
+ MBGL_CHECK_ERROR(glGetIntegerv(GL_UNPACK_ALIGNMENT, &value.alignment));
+ return value;
+}
+
+const constexpr PixelTransferDepth::Type PixelTransferDepth::Default;
+
+void PixelTransferDepth::Set(const Type& value) {
+ MBGL_CHECK_ERROR(glPixelTransferf(GL_DEPTH_SCALE, value.scale));
+ MBGL_CHECK_ERROR(glPixelTransferf(GL_DEPTH_BIAS, value.bias));
+}
+
+PixelTransferDepth::Type PixelTransferDepth::Get() {
+ Type value;
+ MBGL_CHECK_ERROR(glGetFloatv(GL_DEPTH_SCALE, &value.scale));
+ MBGL_CHECK_ERROR(glGetFloatv(GL_DEPTH_BIAS, &value.bias));
+ return value;
+}
+
+const constexpr PixelTransferStencil::Type PixelTransferStencil::Default;
+
+void PixelTransferStencil::Set(const Type& value) {
+ MBGL_CHECK_ERROR(glPixelTransferf(GL_INDEX_SHIFT, value.shift));
+ MBGL_CHECK_ERROR(glPixelTransferf(GL_INDEX_OFFSET, value.offset));
+}
+
+PixelTransferStencil::Type PixelTransferStencil::Get() {
+ Type value;
+ MBGL_CHECK_ERROR(glGetIntegerv(GL_INDEX_SHIFT, &value.shift));
+ MBGL_CHECK_ERROR(glGetIntegerv(GL_INDEX_OFFSET, &value.offset));
+ return value;
+}
+
+#endif // MBGL_USE_GLES2
} // namespace value
} // namespace gl
diff --git a/src/mbgl/gl/value.hpp b/src/mbgl/gl/value.hpp
index 866ce389a4..3586c26bda 100644
--- a/src/mbgl/gl/value.hpp
+++ b/src/mbgl/gl/value.hpp
@@ -1,7 +1,12 @@
#pragma once
#include <mbgl/gl/types.hpp>
+#include <mbgl/gl/depth_mode.hpp>
+#include <mbgl/gl/stencil_mode.hpp>
+#include <mbgl/gl/color_mode.hpp>
#include <mbgl/util/color.hpp>
+#include <mbgl/util/size.hpp>
+#include <mbgl/util/range.hpp>
namespace mbgl {
namespace gl {
@@ -22,14 +27,14 @@ struct ClearColor {
};
struct ClearStencil {
- using Type = StencilValue;
+ using Type = int32_t;
static const constexpr Type Default = 0;
static void Set(const Type&);
static Type Get();
};
struct StencilMask {
- using Type = StencilMaskValue;
+ using Type = uint32_t;
static const constexpr Type Default = ~0u;
static void Set(const Type&);
static Type Get();
@@ -43,28 +48,19 @@ struct DepthMask {
};
struct ColorMask {
- struct Type {
- bool r;
- bool g;
- bool b;
- bool a;
- };
+ using Type = ColorMode::Mask;
static const constexpr Type Default = { true, true, true, true };
static void Set(const Type&);
static Type Get();
};
-constexpr bool operator!=(const ColorMask::Type& a, const ColorMask::Type& b) {
- return a.r != b.r || a.g != b.g || a.b != b.b || a.a != b.a;
-}
-
struct StencilFunc {
struct Type {
- StencilTestFunction func;
- StencilValue ref;
- StencilMaskValue mask;
+ uint32_t func;
+ int32_t ref;
+ uint32_t mask;
};
- static const constexpr Type Default = { StencilTestFunction::Always, 0, ~0u };
+ static const constexpr Type Default = { StencilMode::Always::func, 0, ~0u };
static void Set(const Type&);
static Type Get();
};
@@ -82,12 +78,11 @@ struct StencilTest {
struct StencilOp {
struct Type {
- StencilTestOperation sfail;
- StencilTestOperation dpfail;
- StencilTestOperation dppass;
+ StencilMode::Op sfail;
+ StencilMode::Op dpfail;
+ StencilMode::Op dppass;
};
- static const constexpr Type Default = { StencilTestOperation::Keep, StencilTestOperation::Keep,
- StencilTestOperation::Keep };
+ static const constexpr Type Default = { StencilMode::Keep, StencilMode::Keep, StencilMode::Keep };
static void Set(const Type&);
static Type Get();
};
@@ -97,19 +92,12 @@ constexpr bool operator!=(const StencilOp::Type& a, const StencilOp::Type& b) {
}
struct DepthRange {
- struct Type {
- float near;
- float far;
- };
+ using Type = Range<float>;
static const constexpr Type Default = { 0, 1 };
static void Set(const Type&);
static Type Get();
};
-constexpr bool operator!=(const DepthRange::Type& a, const DepthRange::Type& b) {
- return a.near != b.near || a.far != b.far;
-}
-
struct DepthTest {
using Type = bool;
static const constexpr Type Default = false;
@@ -118,8 +106,8 @@ struct DepthTest {
};
struct DepthFunc {
- using Type = DepthTestFunction;
- static const constexpr Type Default = DepthTestFunction::Less;
+ using Type = DepthMode::Function;
+ static const constexpr Type Default = DepthMode::Less;
static void Set(const Type&);
static Type Get();
};
@@ -131,12 +119,19 @@ struct Blend {
static Type Get();
};
+struct BlendEquation {
+ using Type = ColorMode::BlendEquation;
+ static const constexpr Type Default = ColorMode::BlendEquation::Add;
+ static void Set(const Type&);
+ static Type Get();
+};
+
struct BlendFunc {
struct Type {
- BlendSourceFactor sfactor;
- BlendDestinationFactor dfactor;
+ ColorMode::BlendFactor sfactor;
+ ColorMode::BlendFactor dfactor;
};
- static const constexpr Type Default = { BlendSourceFactor::One, BlendDestinationFactor::Zero };
+ static const constexpr Type Default = { ColorMode::One, ColorMode::Zero };
static void Set(const Type&);
static Type Get();
};
@@ -177,16 +172,19 @@ struct Viewport {
struct Type {
int32_t x;
int32_t y;
- uint16_t width;
- uint16_t height;
+ Size size;
};
- static const constexpr Type Default = { 0, 0, 0, 0 };
+ static const constexpr Type Default = { 0, 0, { 0, 0 } };
static void Set(const Type&);
static Type Get();
};
constexpr bool operator!=(const Viewport::Type& a, const Viewport::Type& b) {
- return a.x != b.x || a.y != b.y || a.width != b.width || a.height != b.height;
+ return a.x != b.x || a.y != b.y || a.size != b.size;
+}
+
+constexpr bool operator==(const Viewport::Type& a, const Viewport::Type& b) {
+ return !(a != b);
}
struct BindFramebuffer {
@@ -233,6 +231,13 @@ struct BindVertexArray {
#if not MBGL_USE_GLES2
+struct PointSize {
+ using Type = float;
+ static const constexpr Type Default = 1;
+ static void Set(const Type&);
+ static Type Get();
+};
+
struct PixelZoom {
struct Type {
float xfactor;
@@ -254,7 +259,7 @@ struct RasterPos {
double z;
double w;
};
- static const constexpr Type Default = { 0, 0, 0, 0 };
+ static const constexpr Type Default = { 0, 0, 0, 1 };
static void Set(const Type&);
static Type Get();
};
@@ -263,6 +268,48 @@ constexpr bool operator!=(const RasterPos::Type& a, const RasterPos::Type& b) {
return a.x != b.x || a.y != b.y || a.z != b.z || a.w != b.w;
}
+struct PixelStorePack {
+ using Type = PixelStorageType;
+ static const constexpr Type Default = { 4 };
+ static void Set(const Type&);
+ static Type Get();
+};
+
+struct PixelStoreUnpack {
+ using Type = PixelStorageType;
+ static const constexpr Type Default = { 4 };
+ static void Set(const Type&);
+ static Type Get();
+};
+
+struct PixelTransferDepth {
+ struct Type {
+ float scale;
+ float bias;
+ };
+ static const constexpr Type Default = { 1, 0 };
+ static void Set(const Type&);
+ static Type Get();
+};
+
+constexpr bool operator!=(const PixelTransferDepth::Type& a, const PixelTransferDepth::Type& b) {
+ return a.scale != b.scale || a.bias != b.bias;
+}
+
+struct PixelTransferStencil {
+ struct Type {
+ int32_t shift;
+ int32_t offset;
+ };
+ static const constexpr Type Default = { 0, 0 };
+ static void Set(const Type&);
+ static Type Get();
+};
+
+constexpr bool operator!=(const PixelTransferStencil::Type& a, const PixelTransferStencil::Type& b) {
+ return a.shift != b.shift || a.offset != b.offset;
+}
+
#endif // MBGL_USE_GLES2
} // namespace value
diff --git a/src/mbgl/gl/vao.cpp b/src/mbgl/gl/vao.cpp
deleted file mode 100644
index b235b0e63b..0000000000
--- a/src/mbgl/gl/vao.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-#include <mbgl/gl/vao.hpp>
-#include <mbgl/gl/vertex_array.hpp>
-#include <mbgl/platform/log.hpp>
-#include <mbgl/util/string.hpp>
-#include <mbgl/gl/gl.hpp>
-
-namespace mbgl {
-namespace gl {
-
-void VertexArrayObject::bindVertexArrayObject(Context& context) {
- if (!GenVertexArrays || !BindVertexArray) {
- static bool reported = false;
- if (!reported) {
- Log::Warning(Event::OpenGL, "Not using Vertex Array Objects");
- reported = true;
- }
- return;
- }
-
- if (!vertexArray) {
- vertexArray = context.createVertexArray();
- context.vertexBuffer.setDirty();
- context.elementBuffer.setDirty();
- }
-
- context.vertexArrayObject = *vertexArray;
-}
-
-void VertexArrayObject::verifyBinding(Shader& shader,
- BufferID vertexBuffer,
- BufferID elementsBuffer,
- int8_t* offset) {
- if (bound_shader != shader.getID()) {
- throw std::runtime_error(std::string("trying to rebind VAO to another shader from " +
- util::toString(bound_shader) + "(" + bound_shader_name + ") to " +
- util::toString(shader.getID()) + "(" + shader.name + ")" ));
- } else if (bound_offset != offset) {
- throw std::runtime_error("trying to bind VAO to another offset");
- } else if (bound_vertex_buffer != vertexBuffer) {
- throw std::runtime_error("trying to bind VAO to another vertex buffer");
- } else if (bound_elements_buffer != elementsBuffer) {
- throw std::runtime_error("trying to bind VAO to another elements buffer");
- }
-}
-
-void VertexArrayObject::storeBinding(Shader& shader,
- BufferID vertexBuffer,
- BufferID elementsBuffer,
- int8_t* offset) {
- bound_shader = shader.getID();
- bound_shader_name = shader.name;
- bound_offset = offset;
- bound_vertex_buffer = vertexBuffer;
- bound_elements_buffer = elementsBuffer;
-}
-
-} // namespace gl
-} // namespace mbgl
diff --git a/src/mbgl/gl/vao.hpp b/src/mbgl/gl/vao.hpp
deleted file mode 100644
index 826c028d32..0000000000
--- a/src/mbgl/gl/vao.hpp
+++ /dev/null
@@ -1,78 +0,0 @@
-#pragma once
-
-#include <mbgl/gl/shader.hpp>
-#include <mbgl/gl/context.hpp>
-#include <mbgl/gl/vertex_buffer.hpp>
-#include <mbgl/util/optional.hpp>
-
-#include <stdexcept>
-
-namespace mbgl {
-namespace gl {
-
-class VertexArrayObject {
-public:
- template <typename Shader, typename T>
- void bind(Shader& shader,
- const VertexBuffer<T>& vertexBuffer,
- int8_t* offset,
- Context& context) {
- bindVertexArrayObject(context);
- if (bound_shader == 0) {
- context.vertexBuffer = vertexBuffer.buffer;
- context.bindAttributes(shader, vertexBuffer, offset);
- if (vertexArray) {
- storeBinding(shader, vertexBuffer.buffer, 0, offset);
- }
- } else {
- verifyBinding(shader, vertexBuffer.buffer, 0, offset);
- }
- }
-
- template <typename Shader, typename T, typename P>
- void bind(Shader& shader,
- const VertexBuffer<T>& vertexBuffer,
- const IndexBuffer<P>& indexBuffer,
- int8_t* offset,
- Context& context) {
- bindVertexArrayObject(context);
- if (bound_shader == 0) {
- context.vertexBuffer = vertexBuffer.buffer;
- context.elementBuffer = indexBuffer.buffer;
- context.bindAttributes(shader, vertexBuffer, offset);
- if (vertexArray) {
- storeBinding(shader, vertexBuffer.buffer, indexBuffer.buffer, offset);
- }
- } else {
- verifyBinding(shader, vertexBuffer.buffer, indexBuffer.buffer, offset);
- }
- }
-
- VertexArrayID getID() const {
- return *vertexArray;
- }
-
-private:
- void bindVertexArrayObject(Context&);
- void storeBinding(Shader& shader,
- BufferID vertexBuffer,
- BufferID elementsBuffer,
- int8_t* offset);
- void verifyBinding(Shader& shader,
- BufferID vertexBuffer,
- BufferID elementsBuffer,
- int8_t* offset);
-
- optional<UniqueVertexArray> vertexArray;
-
- // For debug reasons, we're storing the bind information so that we can
- // detect errors and report
- ProgramID bound_shader = 0;
- const char* bound_shader_name = "";
- BufferID bound_vertex_buffer = 0;
- BufferID bound_elements_buffer = 0;
- int8_t *bound_offset = nullptr;
-};
-
-} // namespace gl
-} // namespace mbgl
diff --git a/src/mbgl/gl/vertex_buffer.hpp b/src/mbgl/gl/vertex_buffer.hpp
index c77a9a4213..c9bc01f3e8 100644
--- a/src/mbgl/gl/vertex_buffer.hpp
+++ b/src/mbgl/gl/vertex_buffer.hpp
@@ -1,14 +1,43 @@
#pragma once
#include <mbgl/gl/object.hpp>
+#include <mbgl/gl/primitives.hpp>
+#include <mbgl/gl/draw_mode.hpp>
+#include <mbgl/util/ignore.hpp>
+
+#include <vector>
namespace mbgl {
namespace gl {
-template <class Vertex>
+template <class V, class DrawMode = Indexed>
+class VertexVector {
+public:
+ using Vertex = V;
+ static constexpr std::size_t groupSize = DrawMode::bufferGroupSize;
+
+ template <class... Args>
+ void emplace_back(Args&&... args) {
+ static_assert(sizeof...(args) == groupSize, "wrong buffer element count");
+ util::ignore({(v.emplace_back(std::forward<Args>(args)), 0)...});
+ }
+
+ std::size_t vertexSize() const { return v.size(); }
+ std::size_t byteSize() const { return v.size() * sizeof(Vertex); }
+
+ bool empty() const { return v.empty(); }
+ const Vertex* data() const { return v.data(); }
+
+private:
+ std::vector<Vertex> v;
+};
+
+template <class V, class DrawMode = Indexed>
class VertexBuffer {
public:
+ using Vertex = V;
static constexpr std::size_t vertexSize = sizeof(Vertex);
+
std::size_t vertexCount;
UniqueBuffer buffer;
};
diff --git a/src/mbgl/layout/merge_lines.cpp b/src/mbgl/layout/merge_lines.cpp
index f4fdb82617..676cbc092d 100644
--- a/src/mbgl/layout/merge_lines.cpp
+++ b/src/mbgl/layout/merge_lines.cpp
@@ -47,10 +47,10 @@ enum class Side {
};
size_t
-getKey(const std::u32string& text, const GeometryCollection& geom, Side side) {
+getKey(const std::u16string& text, const GeometryCollection& geom, Side side) {
const GeometryCoordinate& coord = side == Side::Right ? geom[0].back() : geom[0].front();
- auto hash = std::hash<std::u32string>()(text);
+ auto hash = std::hash<std::u16string>()(text);
boost::hash_combine(hash, coord.x);
boost::hash_combine(hash, coord.y);
return hash;
diff --git a/src/mbgl/layout/symbol_feature.hpp b/src/mbgl/layout/symbol_feature.hpp
index 99db4f9ac5..5dd61d9156 100644
--- a/src/mbgl/layout/symbol_feature.hpp
+++ b/src/mbgl/layout/symbol_feature.hpp
@@ -9,8 +9,9 @@ namespace mbgl {
class SymbolFeature {
public:
+ FeatureType type;
GeometryCollection geometry;
- optional<std::u32string> text;
+ optional<std::u16string> text;
optional<std::string> icon;
std::size_t index;
};
diff --git a/src/mbgl/layout/symbol_instance.cpp b/src/mbgl/layout/symbol_instance.cpp
index 64b913200e..fafcc7c15d 100644
--- a/src/mbgl/layout/symbol_instance.cpp
+++ b/src/mbgl/layout/symbol_instance.cpp
@@ -7,7 +7,7 @@ using namespace style;
SymbolInstance::SymbolInstance(Anchor& anchor, const GeometryCoordinates& line,
const Shaping& shapedText, const PositionedIcon& shapedIcon,
- const SymbolLayoutProperties& layout, const bool addToBuffers, const uint32_t index_,
+ const SymbolLayoutProperties::Evaluated& layout, const bool addToBuffers, const uint32_t index_,
const float textBoxScale, const float textPadding, const SymbolPlacementType textPlacement,
const float iconBoxScale, const float iconPadding, const SymbolPlacementType iconPlacement,
const GlyphPositions& face, const IndexedSubfeature& indexedFeature) :
diff --git a/src/mbgl/layout/symbol_instance.hpp b/src/mbgl/layout/symbol_instance.hpp
index 3087bf09f9..508c11a394 100644
--- a/src/mbgl/layout/symbol_instance.hpp
+++ b/src/mbgl/layout/symbol_instance.hpp
@@ -2,21 +2,18 @@
#include <mbgl/text/quads.hpp>
#include <mbgl/text/collision_feature.hpp>
+#include <mbgl/style/layers/symbol_layer_properties.hpp>
namespace mbgl {
struct Anchor;
class IndexedSubfeature;
-namespace style {
-class SymbolLayoutProperties;
-} // namespace style
-
class SymbolInstance {
public:
explicit SymbolInstance(Anchor& anchor, const GeometryCoordinates& line,
const Shaping& shapedText, const PositionedIcon& shapedIcon,
- const style::SymbolLayoutProperties&, const bool inside, const uint32_t index,
+ const style::SymbolLayoutProperties::Evaluated&, const bool inside, const uint32_t index,
const float textBoxScale, const float textPadding, style::SymbolPlacementType textPlacement,
const float iconBoxScale, const float iconPadding, style::SymbolPlacementType iconPlacement,
const GlyphPositions& face, const IndexedSubfeature& indexedfeature);
diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp
index 07ba2bf4a3..7be2c13ada 100644
--- a/src/mbgl/layout/symbol_layout.cpp
+++ b/src/mbgl/layout/symbol_layout.cpp
@@ -11,14 +11,14 @@
#include <mbgl/util/constants.hpp>
#include <mbgl/util/utf.hpp>
#include <mbgl/util/token.hpp>
-#include <mbgl/util/math.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/math/clamp.hpp>
#include <mbgl/math/minmax.hpp>
-#include <mbgl/platform/platform.hpp>
-#include <mbgl/platform/log.hpp>
+#include <mbgl/math/log2.hpp>
+#include <mbgl/util/platform.hpp>
+#include <mbgl/util/logging.hpp>
namespace mbgl {
@@ -31,7 +31,7 @@ SymbolLayout::SymbolLayout(std::string bucketName_,
const MapMode mode_,
const GeometryTileLayer& layer,
const style::Filter& filter,
- style::SymbolLayoutProperties layout_,
+ style::SymbolLayoutProperties::Evaluated layout_,
float textMaxSize_,
SpriteAtlas& spriteAtlas_)
: bucketName(std::move(bucketName_)),
@@ -45,8 +45,8 @@ SymbolLayout::SymbolLayout(std::string bucketName_,
tileSize(util::tileSize * overscaling_),
tilePixelRatio(float(util::EXTENT) / tileSize) {
- const bool hasText = !layout.textField.value.empty() && !layout.textFont.value.empty();
- const bool hasIcon = !layout.iconImage.value.empty();
+ const bool hasText = !layout.get<TextField>().empty() && !layout.get<TextFont>().empty();
+ const bool hasIcon = !layout.get<IconImage>().empty();
if (!hasText && !hasIcon) {
return;
@@ -82,42 +82,34 @@ SymbolLayout::SymbolLayout(std::string bucketName_,
};
if (hasText) {
- std::string u8string = util::replaceTokens(layout.textField, getValue);
+ std::string u8string = util::replaceTokens(layout.get<TextField>(), getValue);
- if (layout.textTransform == TextTransformType::Uppercase) {
+ if (layout.get<TextTransform>() == TextTransformType::Uppercase) {
u8string = platform::uppercase(u8string);
- } else if (layout.textTransform == TextTransformType::Lowercase) {
+ } else if (layout.get<TextTransform>() == TextTransformType::Lowercase) {
u8string = platform::lowercase(u8string);
}
- ft.text = util::utf8_to_utf32::convert(u8string);
+ ft.text = applyArabicShaping(util::utf8_to_utf16::convert(u8string));
// Loop through all characters of this text and collect unique codepoints.
- for (char32_t chr : *ft.text) {
+ for (char16_t chr : *ft.text) {
ranges.insert(getGlyphRange(chr));
}
}
if (hasIcon) {
- ft.icon = util::replaceTokens(layout.iconImage, getValue);
+ ft.icon = util::replaceTokens(layout.get<IconImage>(), getValue);
}
if (ft.text || ft.icon) {
- auto &multiline = ft.geometry;
-
- GeometryCollection geometryCollection = feature->getGeometries();
- for (auto& line : geometryCollection) {
- multiline.emplace_back();
- for (auto& point : line) {
- multiline.back().emplace_back(point.x, point.y);
- }
- }
-
+ ft.type = feature->getType();
+ ft.geometry = feature->getGeometries();
features.push_back(std::move(ft));
}
}
- if (layout.symbolPlacement == SymbolPlacementType::Line) {
+ if (layout.get<SymbolPlacement>() == SymbolPlacementType::Line) {
util::mergeLines(features);
}
}
@@ -127,11 +119,11 @@ bool SymbolLayout::hasSymbolInstances() const {
}
bool SymbolLayout::canPrepare(GlyphAtlas& glyphAtlas) {
- if (!layout.textField.value.empty() && !layout.textFont.value.empty() && !glyphAtlas.hasGlyphRanges(layout.textFont, ranges)) {
+ if (!layout.get<TextField>().empty() && !layout.get<TextFont>().empty() && !glyphAtlas.hasGlyphRanges(layout.get<TextFont>(), ranges)) {
return false;
}
- if (!layout.iconImage.value.empty() && !spriteAtlas.isLoaded()) {
+ if (!layout.get<IconImage>().empty() && !spriteAtlas.isLoaded()) {
return false;
}
@@ -143,7 +135,7 @@ void SymbolLayout::prepare(uintptr_t tileUID,
float horizontalAlign = 0.5;
float verticalAlign = 0.5;
- switch (layout.textAnchor) {
+ switch (layout.get<TextAnchor>()) {
case TextAnchorType::Top:
case TextAnchorType::Bottom:
case TextAnchorType::Center:
@@ -160,7 +152,7 @@ void SymbolLayout::prepare(uintptr_t tileUID,
break;
}
- switch (layout.textAnchor) {
+ switch (layout.get<TextAnchor>()) {
case TextAnchorType::Left:
case TextAnchorType::Right:
case TextAnchorType::Center:
@@ -177,11 +169,11 @@ void SymbolLayout::prepare(uintptr_t tileUID,
break;
}
- const float justify = layout.textJustify == TextJustifyType::Right ? 1 :
- layout.textJustify == TextJustifyType::Left ? 0 :
+ const float justify = layout.get<TextJustify>() == TextJustifyType::Right ? 1 :
+ layout.get<TextJustify>() == TextJustifyType::Left ? 0 :
0.5;
- auto glyphSet = glyphAtlas.getGlyphSet(layout.textFont);
+ auto glyphSet = glyphAtlas.getGlyphSet(layout.get<TextFont>());
for (const auto& feature : features) {
if (feature.geometry.empty()) continue;
@@ -194,18 +186,19 @@ void SymbolLayout::prepare(uintptr_t tileUID,
if (feature.text) {
shapedText = glyphSet->getShaping(
/* string */ *feature.text,
- /* maxWidth: ems */ layout.symbolPlacement != SymbolPlacementType::Line ?
- layout.textMaxWidth * 24 : 0,
- /* lineHeight: ems */ layout.textLineHeight * 24,
+ /* maxWidth: ems */ layout.get<SymbolPlacement>() != SymbolPlacementType::Line ?
+ layout.get<TextMaxWidth>() * 24 : 0,
+ /* lineHeight: ems */ layout.get<TextLineHeight>() * 24,
/* horizontalAlign */ horizontalAlign,
/* verticalAlign */ verticalAlign,
/* justify */ justify,
- /* spacing: ems */ layout.textLetterSpacing * 24,
- /* translate */ Point<float>(layout.textOffset.value[0], layout.textOffset.value[1]));
+ /* spacing: ems */ layout.get<TextLetterSpacing>() * 24,
+ /* translate */ Point<float>(layout.get<TextOffset>()[0], layout.get<TextOffset>()[1]),
+ /* bidirectional algorithm object */ bidi);
// Add the glyphs we need for this label to the glyph atlas.
if (shapedText) {
- glyphAtlas.addGlyphs(tileUID, *feature.text, layout.textFont, **glyphSet, face);
+ glyphAtlas.addGlyphs(tileUID, *feature.text, layout.get<TextFont>(), **glyphSet, face);
}
}
@@ -220,7 +213,7 @@ void SymbolLayout::prepare(uintptr_t tileUID,
}
if ((*image).relativePixelRatio != 1.0f) {
iconsNeedLinear = true;
- } else if (layout.iconRotate != 0) {
+ } else if (layout.get<IconRotate>() != 0) {
iconsNeedLinear = true;
}
}
@@ -228,93 +221,114 @@ void SymbolLayout::prepare(uintptr_t tileUID,
// if either shapedText or icon position is present, add the feature
if (shapedText || shapedIcon) {
- addFeature(feature.geometry, shapedText, shapedIcon, face, feature.index);
+ addFeature(feature, shapedText, shapedIcon, face);
}
}
features.clear();
}
-
-void SymbolLayout::addFeature(const GeometryCollection &lines,
- const Shaping &shapedText, const PositionedIcon &shapedIcon, const GlyphPositions &face, const size_t index) {
-
+void SymbolLayout::addFeature(const SymbolFeature& feature,
+ const Shaping& shapedText,
+ const PositionedIcon& shapedIcon,
+ const GlyphPositions& face) {
const float minScale = 0.5f;
const float glyphSize = 24.0f;
- const float fontScale = layout.textSize / glyphSize;
+ const float fontScale = layout.get<TextSize>() / glyphSize;
const float textBoxScale = tilePixelRatio * fontScale;
const float textMaxBoxScale = tilePixelRatio * textMaxSize / glyphSize;
- const float iconBoxScale = tilePixelRatio * layout.iconSize;
- const float symbolSpacing = tilePixelRatio * layout.symbolSpacing;
- const bool avoidEdges = layout.symbolAvoidEdges && layout.symbolPlacement != SymbolPlacementType::Line;
- const float textPadding = layout.textPadding * tilePixelRatio;
- const float iconPadding = layout.iconPadding * tilePixelRatio;
- const float textMaxAngle = layout.textMaxAngle * util::DEG2RAD;
- const SymbolPlacementType textPlacement = layout.textRotationAlignment != AlignmentType::Map
+ const float iconBoxScale = tilePixelRatio * layout.get<IconSize>();
+ const float symbolSpacing = tilePixelRatio * layout.get<SymbolSpacing>();
+ const bool avoidEdges = layout.get<SymbolAvoidEdges>() && layout.get<SymbolPlacement>() != SymbolPlacementType::Line;
+ const float textPadding = layout.get<TextPadding>() * tilePixelRatio;
+ const float iconPadding = layout.get<IconPadding>() * tilePixelRatio;
+ const float textMaxAngle = layout.get<TextMaxAngle>() * util::DEG2RAD;
+ const SymbolPlacementType textPlacement = layout.get<TextRotationAlignment>() != AlignmentType::Map
? SymbolPlacementType::Point
- : layout.symbolPlacement;
- const SymbolPlacementType iconPlacement = layout.iconRotationAlignment != AlignmentType::Map
+ : layout.get<SymbolPlacement>();
+ const SymbolPlacementType iconPlacement = layout.get<IconRotationAlignment>() != AlignmentType::Map
? SymbolPlacementType::Point
- : layout.symbolPlacement;
- const bool mayOverlap = layout.textAllowOverlap || layout.iconAllowOverlap ||
- layout.textIgnorePlacement || layout.iconIgnorePlacement;
- const bool isLine = layout.symbolPlacement == SymbolPlacementType::Line;
+ : layout.get<SymbolPlacement>();
const float textRepeatDistance = symbolSpacing / 2;
-
- auto& clippedLines = isLine ?
- util::clipLines(lines, 0, 0, util::EXTENT, util::EXTENT) :
- lines;
-
- IndexedSubfeature indexedFeature = {index, sourceLayerName, bucketName, symbolInstances.size()};
-
- for (const auto& line : clippedLines) {
- if (line.empty()) continue;
-
- // Calculate the anchor points around which you want to place labels
- Anchors anchors = isLine ?
- getAnchors(line, symbolSpacing, textMaxAngle, shapedText.left, shapedText.right, shapedIcon.left, shapedIcon.right, glyphSize, textMaxBoxScale, overscaling) :
- Anchors({ Anchor(float(line[0].x), float(line[0].y), 0, minScale) });
-
- // For each potential label, create the placement features used to check for collisions, and the quads use for rendering.
- for (Anchor &anchor : anchors) {
- if (shapedText && isLine) {
- if (anchorIsTooClose(shapedText.text, textRepeatDistance, anchor)) {
- continue;
+ IndexedSubfeature indexedFeature = {feature.index, sourceLayerName, bucketName, symbolInstances.size()};
+
+ auto addSymbolInstance = [&] (const GeometryCoordinates& line, Anchor& anchor) {
+ // https://github.com/mapbox/vector-tile-spec/tree/master/2.1#41-layers
+ // +-------------------+ Symbols with anchors located on tile edges
+ // |(0,0) || are duplicated on neighbor tiles.
+ // | ||
+ // | || In continuous mode, to avoid overdraw we
+ // | || skip symbols located on the extent edges.
+ // | Tile || In still mode, we include the features in
+ // | || the buffers for both tiles and clip them
+ // | || at draw time.
+ // | ||
+ // +-------------------| In this scenario, the inner bounding box
+ // +-------------------+ is called 'withinPlus0', and the outer
+ // (extent,extent) is called 'inside'.
+ const bool withinPlus0 = anchor.point.x >= 0 && anchor.point.x < util::EXTENT && anchor.point.y >= 0 && anchor.point.y < util::EXTENT;
+ const bool inside = withinPlus0 || anchor.point.x == util::EXTENT || anchor.point.y == util::EXTENT;
+
+ if (avoidEdges && !inside) return;
+
+ const bool addToBuffers = mode == MapMode::Still || withinPlus0;
+
+ symbolInstances.emplace_back(anchor, line, shapedText, shapedIcon, layout, addToBuffers, symbolInstances.size(),
+ textBoxScale, textPadding, textPlacement,
+ iconBoxScale, iconPadding, iconPlacement,
+ face, indexedFeature);
+ };
+
+ if (layout.get<SymbolPlacement>() == SymbolPlacementType::Line) {
+ auto clippedLines = util::clipLines(feature.geometry, 0, 0, util::EXTENT, util::EXTENT);
+ for (const auto& line : clippedLines) {
+ Anchors anchors = getAnchors(line,
+ symbolSpacing,
+ textMaxAngle,
+ shapedText.left,
+ shapedText.right,
+ shapedIcon.left,
+ shapedIcon.right,
+ glyphSize,
+ textMaxBoxScale,
+ overscaling);
+
+ for (auto& anchor : anchors) {
+ if (!shapedText || !anchorIsTooClose(shapedText.text, textRepeatDistance, anchor)) {
+ addSymbolInstance(line, anchor);
}
}
-
- const bool inside = !(anchor.point.x < 0 || anchor.point.x > util::EXTENT || anchor.point.y < 0 || anchor.point.y > util::EXTENT);
-
- if (avoidEdges && !inside) continue;
-
- // Normally symbol layers are drawn across tile boundaries. Only symbols
- // with their anchors within the tile boundaries are added to the buffers
- // to prevent symbols from being drawn twice.
- //
- // Symbols in layers with overlap are sorted in the y direction so that
- // symbols lower on the canvas are drawn on top of symbols near the top.
- // To preserve this order across tile boundaries these symbols can't
- // be drawn across tile boundaries. Instead they need to be included in
- // the buffers for both tiles and clipped to tile boundaries at draw time.
- //
- // TODO remove the `&& false` when is #1673 implemented
- const bool addToBuffers = (mode == MapMode::Still) || inside || (mayOverlap && false);
-
- symbolInstances.emplace_back(anchor, line, shapedText, shapedIcon, layout, addToBuffers, symbolInstances.size(),
- textBoxScale, textPadding, textPlacement,
- iconBoxScale, iconPadding, iconPlacement,
- face, indexedFeature);
+ }
+ } else if (feature.type == FeatureType::Polygon) {
+ // TODO: pole of inaccessibility
+ for (const auto& ring : feature.geometry) {
+ for (const auto& point : ring) {
+ Anchor anchor(point.x, point.y, 0, minScale);
+ addSymbolInstance(ring, anchor);
+ }
+ }
+ } else if (feature.type == FeatureType::LineString) {
+ for (const auto& line : feature.geometry) {
+ Anchor anchor(line[0].x, line[0].y, 0, minScale);
+ addSymbolInstance(line, anchor);
+ }
+ } else if (feature.type == FeatureType::Point) {
+ for (const auto& points : feature.geometry) {
+ for (const auto& point : points) {
+ Anchor anchor(point.x, point.y, 0, minScale);
+ addSymbolInstance({point}, anchor);
+ }
}
}
}
-bool SymbolLayout::anchorIsTooClose(const std::u32string &text, const float repeatDistance, Anchor &anchor) {
+bool SymbolLayout::anchorIsTooClose(const std::u16string& text, const float repeatDistance, const Anchor& anchor) {
if (compareText.find(text) == compareText.end()) {
compareText.emplace(text, Anchors());
} else {
auto otherAnchors = compareText.find(text)->second;
- for (Anchor &otherAnchor : otherAnchors) {
+ for (const Anchor& otherAnchor : otherAnchors) {
if (util::dist<float>(anchor.point, otherAnchor.point) < repeatDistance) {
return true;
}
@@ -330,15 +344,15 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile)
// Calculate which labels can be shown and when they can be shown and
// create the bufers used for rendering.
- const SymbolPlacementType textPlacement = layout.textRotationAlignment != AlignmentType::Map
+ const SymbolPlacementType textPlacement = layout.get<TextRotationAlignment>() != AlignmentType::Map
? SymbolPlacementType::Point
- : layout.symbolPlacement;
- const SymbolPlacementType iconPlacement = layout.iconRotationAlignment != AlignmentType::Map
+ : layout.get<SymbolPlacement>();
+ const SymbolPlacementType iconPlacement = layout.get<IconRotationAlignment>() != AlignmentType::Map
? SymbolPlacementType::Point
- : layout.symbolPlacement;
+ : layout.get<SymbolPlacement>();
- const bool mayOverlap = layout.textAllowOverlap || layout.iconAllowOverlap ||
- layout.textIgnorePlacement || layout.iconIgnorePlacement;
+ const bool mayOverlap = layout.get<TextAllowOverlap>() || layout.get<IconAllowOverlap>() ||
+ layout.get<TextIgnorePlacement>() || layout.get<IconIgnorePlacement>();
// Sort symbols by their y position on the canvas so that they lower symbols
// are drawn on top of higher symbols.
@@ -362,18 +376,18 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile)
const bool hasText = symbolInstance.hasText;
const bool hasIcon = symbolInstance.hasIcon;
- const bool iconWithoutText = layout.textOptional || !hasText;
- const bool textWithoutIcon = layout.iconOptional || !hasIcon;
+ const bool iconWithoutText = layout.get<TextOptional>() || !hasText;
+ const bool textWithoutIcon = layout.get<IconOptional>() || !hasIcon;
// Calculate the scales at which the text and icon can be placed without collision.
float glyphScale = hasText ?
collisionTile.placeFeature(symbolInstance.textCollisionFeature,
- layout.textAllowOverlap, layout.symbolAvoidEdges) :
+ layout.get<TextAllowOverlap>(), layout.get<SymbolAvoidEdges>()) :
collisionTile.minScale;
float iconScale = hasIcon ?
collisionTile.placeFeature(symbolInstance.iconCollisionFeature,
- layout.iconAllowOverlap, layout.symbolAvoidEdges) :
+ layout.get<IconAllowOverlap>(), layout.get<SymbolAvoidEdges>()) :
collisionTile.minScale;
@@ -391,20 +405,20 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile)
// Insert final placement into collision tree and add glyphs/icons to buffers
if (hasText) {
- collisionTile.insertFeature(symbolInstance.textCollisionFeature, glyphScale, layout.textIgnorePlacement);
+ collisionTile.insertFeature(symbolInstance.textCollisionFeature, glyphScale, layout.get<TextIgnorePlacement>());
if (glyphScale < collisionTile.maxScale) {
addSymbols(
bucket->text, symbolInstance.glyphQuads, glyphScale,
- layout.textKeepUpright, textPlacement, collisionTile.config.angle);
+ layout.get<TextKeepUpright>(), textPlacement, collisionTile.config.angle);
}
}
if (hasIcon) {
- collisionTile.insertFeature(symbolInstance.iconCollisionFeature, iconScale, layout.iconIgnorePlacement);
+ collisionTile.insertFeature(symbolInstance.iconCollisionFeature, iconScale, layout.get<IconIgnorePlacement>());
if (iconScale < collisionTile.maxScale) {
addSymbols(
bucket->icon, symbolInstance.iconQuads, iconScale,
- layout.iconKeepUpright, iconPlacement, collisionTile.config.angle);
+ layout.get<IconKeepUpright>(), iconPlacement, collisionTile.config.angle);
}
}
}
@@ -418,8 +432,8 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile)
template <typename Buffer>
void SymbolLayout::addSymbols(Buffer &buffer, const SymbolQuads &symbols, float scale, const bool keepUpright, const style::SymbolPlacementType placement, const float placementAngle) {
-
- const float placementZoom = ::fmax(std::log(scale) / std::log(2) + zoom, 0);
+ constexpr const uint16_t vertexLength = 4;
+ const float placementZoom = util::max(util::log2(scale) + zoom, 0.0f);
for (const auto& symbol : symbols) {
const auto &tl = symbol.tl;
@@ -428,9 +442,8 @@ void SymbolLayout::addSymbols(Buffer &buffer, const SymbolQuads &symbols, float
const auto &br = symbol.br;
const auto &tex = symbol.tex;
- float minZoom =
- util::max(static_cast<float>(zoom + log(symbol.minScale) / log(2)), placementZoom);
- float maxZoom = util::min(static_cast<float>(zoom + log(symbol.maxScale) / log(2)), 25.0f);
+ float minZoom = util::max(zoom + util::log2(symbol.minScale), placementZoom);
+ float maxZoom = util::min(zoom + util::log2(symbol.maxScale), util::MAX_ZOOM_F);
const auto &anchorPoint = symbol.anchorPoint;
// drop upside down versions of glyphs
@@ -449,41 +462,35 @@ void SymbolLayout::addSymbols(Buffer &buffer, const SymbolQuads &symbols, float
minZoom = 0;
}
- const int glyph_vertex_length = 4;
-
- if (buffer.groups.empty() || buffer.groups.back().vertexLength + glyph_vertex_length > 65535) {
- // Move to a new group because the old one can't hold the geometry.
- buffer.groups.emplace_back();
+ if (buffer.segments.empty() || buffer.segments.back().vertexLength + vertexLength > std::numeric_limits<uint16_t>::max()) {
+ buffer.segments.emplace_back(buffer.vertices.vertexSize(), buffer.triangles.indexSize());
}
// We're generating triangle fans, so we always start with the first
// coordinate in this polygon.
- auto& group = buffer.groups.back();
- size_t index = group.vertexLength;
+ auto& segment = buffer.segments.back();
+ assert(segment.vertexLength <= std::numeric_limits<uint16_t>::max());
+ uint16_t index = segment.vertexLength;
// Encode angle of glyph
uint8_t glyphAngle = std::round((symbol.glyphAngle / (M_PI * 2)) * 256);
// coordinates (2 triangles)
- buffer.vertices.emplace_back(anchorPoint.x, anchorPoint.y, tl.x, tl.y, tex.x, tex.y, minZoom,
- maxZoom, placementZoom, glyphAngle);
- buffer.vertices.emplace_back(anchorPoint.x, anchorPoint.y, tr.x, tr.y, tex.x + tex.w, tex.y,
- minZoom, maxZoom, placementZoom, glyphAngle);
- buffer.vertices.emplace_back(anchorPoint.x, anchorPoint.y, bl.x, bl.y, tex.x, tex.y + tex.h,
- minZoom, maxZoom, placementZoom, glyphAngle);
- buffer.vertices.emplace_back(anchorPoint.x, anchorPoint.y, br.x, br.y, tex.x + tex.w, tex.y + tex.h,
- minZoom, maxZoom, placementZoom, glyphAngle);
+ buffer.vertices.emplace_back(SymbolAttributes::vertex(anchorPoint, tl, tex.x, tex.y,
+ minZoom, maxZoom, placementZoom, glyphAngle));
+ buffer.vertices.emplace_back(SymbolAttributes::vertex(anchorPoint, tr, tex.x + tex.w, tex.y,
+ minZoom, maxZoom, placementZoom, glyphAngle));
+ buffer.vertices.emplace_back(SymbolAttributes::vertex(anchorPoint, bl, tex.x, tex.y + tex.h,
+ minZoom, maxZoom, placementZoom, glyphAngle));
+ buffer.vertices.emplace_back(SymbolAttributes::vertex(anchorPoint, br, tex.x + tex.w, tex.y + tex.h,
+ minZoom, maxZoom, placementZoom, glyphAngle));
// add the two triangles, referencing the four coordinates we just inserted.
- buffer.triangles.emplace_back(static_cast<uint16_t>(index + 0),
- static_cast<uint16_t>(index + 1),
- static_cast<uint16_t>(index + 2));
- buffer.triangles.emplace_back(static_cast<uint16_t>(index + 1),
- static_cast<uint16_t>(index + 2),
- static_cast<uint16_t>(index + 3));
-
- group.vertexLength += glyph_vertex_length;
- group.indexLength += 2;
+ buffer.triangles.emplace_back(index + 0, index + 1, index + 2);
+ buffer.triangles.emplace_back(index + 1, index + 2, index + 3);
+
+ segment.vertexLength += vertexLength;
+ segment.indexLength += 6;
}
}
@@ -496,10 +503,6 @@ void SymbolLayout::addToDebugBuffers(CollisionTile& collisionTile, SymbolBucket&
const float yStretch = collisionTile.yStretch;
auto& collisionBox = bucket.collisionBox;
- if (collisionBox.groups.empty()) {
- // Move to a new group because the old one can't hold the geometry.
- collisionBox.groups.emplace_back();
- }
for (const SymbolInstance &symbolInstance : symbolInstances) {
auto populateCollisionBox = [&](const auto& feature) {
@@ -515,20 +518,31 @@ void SymbolLayout::addToDebugBuffers(CollisionTile& collisionTile, SymbolBucket&
bl = util::matrixMultiply(collisionTile.reverseRotationMatrix, bl);
br = util::matrixMultiply(collisionTile.reverseRotationMatrix, br);
- const float maxZoom = util::clamp(zoom + log(box.maxScale) / log(2), util::MIN_ZOOM, util::MAX_ZOOM);
- const float placementZoom = util::clamp(zoom + log(box.placementScale) / log(2), util::MIN_ZOOM, util::MAX_ZOOM);
+ const float maxZoom = util::clamp(zoom + util::log2(box.maxScale), util::MIN_ZOOM_F, util::MAX_ZOOM_F);
+ const float placementZoom = util::clamp(zoom + util::log2(box.placementScale), util::MIN_ZOOM_F, util::MAX_ZOOM_F);
+
+ static constexpr std::size_t vertexLength = 4;
+ static constexpr std::size_t indexLength = 8;
+
+ if (collisionBox.segments.empty() || collisionBox.segments.back().vertexLength + vertexLength > std::numeric_limits<uint16_t>::max()) {
+ collisionBox.segments.emplace_back(collisionBox.vertices.vertexSize(), collisionBox.lines.indexSize());
+ }
+
+ auto& segment = collisionBox.segments.back();
+ uint16_t index = segment.vertexLength;
+
+ collisionBox.vertices.emplace_back(CollisionBoxProgram::vertex(anchor, tl, maxZoom, placementZoom));
+ collisionBox.vertices.emplace_back(CollisionBoxProgram::vertex(anchor, tr, maxZoom, placementZoom));
+ collisionBox.vertices.emplace_back(CollisionBoxProgram::vertex(anchor, br, maxZoom, placementZoom));
+ collisionBox.vertices.emplace_back(CollisionBoxProgram::vertex(anchor, bl, maxZoom, placementZoom));
- collisionBox.vertices.emplace_back(anchor.x, anchor.y, tl.x, tl.y, maxZoom, placementZoom);
- collisionBox.vertices.emplace_back(anchor.x, anchor.y, tr.x, tr.y, maxZoom, placementZoom);
- collisionBox.vertices.emplace_back(anchor.x, anchor.y, tr.x, tr.y, maxZoom, placementZoom);
- collisionBox.vertices.emplace_back(anchor.x, anchor.y, br.x, br.y, maxZoom, placementZoom);
- collisionBox.vertices.emplace_back(anchor.x, anchor.y, br.x, br.y, maxZoom, placementZoom);
- collisionBox.vertices.emplace_back(anchor.x, anchor.y, bl.x, bl.y, maxZoom, placementZoom);
- collisionBox.vertices.emplace_back(anchor.x, anchor.y, bl.x, bl.y, maxZoom, placementZoom);
- collisionBox.vertices.emplace_back(anchor.x, anchor.y, tl.x, tl.y, maxZoom, placementZoom);
+ collisionBox.lines.emplace_back(index + 0, index + 1);
+ collisionBox.lines.emplace_back(index + 1, index + 2);
+ collisionBox.lines.emplace_back(index + 2, index + 3);
+ collisionBox.lines.emplace_back(index + 3, index + 0);
- auto& group = collisionBox.groups.back();
- group.vertexLength += 8;
+ segment.vertexLength += vertexLength;
+ segment.indexLength += indexLength;
}
};
populateCollisionBox(symbolInstance.textCollisionFeature);
diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp
index 54acf84aaf..18fb9ff4bc 100644
--- a/src/mbgl/layout/symbol_layout.hpp
+++ b/src/mbgl/layout/symbol_layout.hpp
@@ -4,6 +4,7 @@
#include <mbgl/style/layers/symbol_layer_properties.hpp>
#include <mbgl/layout/symbol_feature.hpp>
#include <mbgl/layout/symbol_instance.hpp>
+#include <mbgl/text/bidi.hpp>
#include <memory>
#include <map>
@@ -33,7 +34,7 @@ public:
const MapMode,
const GeometryTileLayer&,
const style::Filter&,
- style::SymbolLayoutProperties,
+ style::SymbolLayoutProperties::Evaluated,
float textMaxSize,
SpriteAtlas&);
@@ -58,14 +59,13 @@ public:
const std::string sourceLayerName;
private:
- void addFeature(const GeometryCollection&,
+ void addFeature(const SymbolFeature&,
const Shaping& shapedText,
const PositionedIcon& shapedIcon,
- const GlyphPositions& face,
- const size_t index);
+ const GlyphPositions& face);
- bool anchorIsTooClose(const std::u32string& text, const float repeatDistance, Anchor&);
- std::map<std::u32string, std::vector<Anchor>> compareText;
+ bool anchorIsTooClose(const std::u16string& text, const float repeatDistance, const Anchor&);
+ std::map<std::u16string, std::vector<Anchor>> compareText;
void addToDebugBuffers(CollisionTile&, SymbolBucket&);
@@ -77,7 +77,7 @@ private:
const float overscaling;
const float zoom;
const MapMode mode;
- const style::SymbolLayoutProperties layout;
+ const style::SymbolLayoutProperties::Evaluated layout;
const float textMaxSize;
SpriteAtlas& spriteAtlas;
@@ -91,6 +91,8 @@ private:
GlyphRangeSet ranges;
std::vector<SymbolInstance> symbolInstances;
std::vector<SymbolFeature> features;
+
+ BiDi bidi; // Consider moving this up to geometry tile worker to reduce reinstantiation costs; use of BiDi/ubiditransform object must be constrained to one thread
};
} // namespace mbgl
diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp
index 1efc1c063a..d76044cd47 100644
--- a/src/mbgl/map/map.cpp
+++ b/src/mbgl/map/map.cpp
@@ -23,7 +23,8 @@
#include <mbgl/util/mapbox.hpp>
#include <mbgl/util/tile_coordinate.hpp>
#include <mbgl/actor/scheduler.hpp>
-#include <mbgl/platform/log.hpp>
+#include <mbgl/util/logging.hpp>
+#include <mbgl/math/log2.hpp>
namespace mbgl {
@@ -46,7 +47,8 @@ struct StillImageRequest {
class Map::Impl : public style::Observer {
public:
- Impl(Backend&,
+ Impl(Map&,
+ Backend&,
float pixelRatio,
FileSource&,
Scheduler&,
@@ -66,6 +68,7 @@ public:
void loadStyleJSON(const std::string&);
+ Map& map;
Backend& backend;
FileSource& fileSource;
Scheduler& scheduler;
@@ -89,6 +92,7 @@ public:
std::string styleURL;
std::string styleJSON;
bool styleMutated = false;
+ bool cameraMutated = false;
std::unique_ptr<AsyncRequest> styleRequest;
@@ -99,7 +103,7 @@ public:
};
Map::Map(Backend& backend,
- const std::array<uint16_t, 2> size,
+ const Size size,
const float pixelRatio,
FileSource& fileSource,
Scheduler& scheduler,
@@ -107,7 +111,8 @@ Map::Map(Backend& backend,
GLContextMode contextMode,
ConstrainMode constrainMode,
ViewportMode viewportMode)
- : impl(std::make_unique<Impl>(backend,
+ : impl(std::make_unique<Impl>(*this,
+ backend,
pixelRatio,
fileSource,
scheduler,
@@ -118,7 +123,8 @@ Map::Map(Backend& backend,
impl->transform.resize(size);
}
-Map::Impl::Impl(Backend& backend_,
+Map::Impl::Impl(Map& map_,
+ Backend& backend_,
float pixelRatio_,
FileSource& fileSource_,
Scheduler& scheduler_,
@@ -126,7 +132,8 @@ Map::Impl::Impl(Backend& backend_,
GLContextMode contextMode_,
ConstrainMode constrainMode_,
ViewportMode viewportMode_)
- : backend(backend_),
+ : map(map_),
+ backend(backend_),
fileSource(fileSource_),
scheduler(scheduler_),
transform([this](MapChange change) { backend.notifyMapChange(change); },
@@ -282,7 +289,7 @@ void Map::Impl::update() {
void Map::Impl::render(View& view) {
if (!painter) {
- painter = std::make_unique<Painter>(backend.getContext(), transform.getState());
+ painter = std::make_unique<Painter>(backend.getContext(), transform.getState(), pixelRatio);
}
FrameData frameData { timePoint,
@@ -384,6 +391,14 @@ void Map::Impl::loadStyleJSON(const std::string& json) {
// force style cascade, causing all pending transitions to complete.
style->cascade(Clock::now(), mode);
+ if (!cameraMutated) {
+ // Zoom first because it may constrain subsequent operations.
+ map.setZoom(map.getDefaultZoom());
+ map.setLatLng(map.getDefaultLatLng());
+ map.setBearing(map.getDefaultBearing());
+ map.setPitch(map.getDefaultPitch());
+ }
+
updateFlags |= Update::Classes | Update::RecalculateStyle | Update::AnnotationStyle;
asyncUpdate.send();
}
@@ -431,16 +446,19 @@ CameraOptions Map::getCameraOptions(optional<EdgeInsets> padding) const {
}
void Map::jumpTo(const CameraOptions& camera) {
+ impl->cameraMutated = true;
impl->transform.jumpTo(camera);
impl->onUpdate(camera.zoom ? Update::RecalculateStyle : Update::Repaint);
}
void Map::easeTo(const CameraOptions& camera, const AnimationOptions& animation) {
+ impl->cameraMutated = true;
impl->transform.easeTo(camera, animation);
impl->onUpdate(camera.zoom ? Update::RecalculateStyle : Update::Repaint);
}
void Map::flyTo(const CameraOptions& camera, const AnimationOptions& animation) {
+ impl->cameraMutated = true;
impl->transform.flyTo(camera, animation);
impl->onUpdate(Update::RecalculateStyle);
}
@@ -448,20 +466,24 @@ void Map::flyTo(const CameraOptions& camera, const AnimationOptions& animation)
#pragma mark - Position
void Map::moveBy(const ScreenCoordinate& point, const Duration& duration) {
+ impl->cameraMutated = true;
impl->transform.moveBy(point, duration);
impl->onUpdate(Update::Repaint);
}
void Map::setLatLng(const LatLng& latLng, const Duration& duration) {
+ impl->cameraMutated = true;
setLatLng(latLng, optional<ScreenCoordinate> {}, duration);
}
void Map::setLatLng(const LatLng& latLng, optional<EdgeInsets> padding, const Duration& duration) {
+ impl->cameraMutated = true;
impl->transform.setLatLng(latLng, padding, duration);
impl->onUpdate(Update::Repaint);
}
void Map::setLatLng(const LatLng& latLng, optional<ScreenCoordinate> anchor, const Duration& duration) {
+ impl->cameraMutated = true;
impl->transform.setLatLng(latLng, anchor, duration);
impl->onUpdate(Update::Repaint);
}
@@ -471,6 +493,7 @@ LatLng Map::getLatLng(optional<EdgeInsets> padding) const {
}
void Map::resetPosition(optional<EdgeInsets> padding) {
+ impl->cameraMutated = true;
CameraOptions camera;
camera.angle = 0;
camera.pitch = 0;
@@ -485,11 +508,13 @@ void Map::resetPosition(optional<EdgeInsets> padding) {
#pragma mark - Scale
void Map::scaleBy(double ds, optional<ScreenCoordinate> anchor, const Duration& duration) {
+ impl->cameraMutated = true;
impl->transform.scaleBy(ds, anchor, duration);
impl->onUpdate(Update::RecalculateStyle);
}
void Map::setScale(double scale, optional<ScreenCoordinate> anchor, const Duration& duration) {
+ impl->cameraMutated = true;
impl->transform.setScale(scale, anchor, duration);
impl->onUpdate(Update::RecalculateStyle);
}
@@ -499,10 +524,12 @@ double Map::getScale() const {
}
void Map::setZoom(double zoom, const Duration& duration) {
+ impl->cameraMutated = true;
setZoom(zoom, {}, duration);
}
void Map::setZoom(double zoom, optional<EdgeInsets> padding, const Duration& duration) {
+ impl->cameraMutated = true;
impl->transform.setZoom(zoom, padding, duration);
impl->onUpdate(Update::RecalculateStyle);
}
@@ -512,10 +539,12 @@ double Map::getZoom() const {
}
void Map::setLatLngZoom(const LatLng& latLng, double zoom, const Duration& duration) {
+ impl->cameraMutated = true;
setLatLngZoom(latLng, zoom, {}, duration);
}
void Map::setLatLngZoom(const LatLng& latLng, double zoom, optional<EdgeInsets> padding, const Duration& duration) {
+ impl->cameraMutated = true;
impl->transform.setLatLngZoom(latLng, zoom, padding, duration);
impl->onUpdate(Update::RecalculateStyle);
}
@@ -538,7 +567,7 @@ CameraOptions Map::cameraForLatLngs(const std::vector<LatLng>& latLngs, optional
// Calculate the bounds of the possibly rotated shape with respect to the viewport.
ScreenCoordinate nePixel = {-INFINITY, -INFINITY};
ScreenCoordinate swPixel = {INFINITY, INFINITY};
- double viewportHeight = getHeight();
+ double viewportHeight = getSize().height;
for (LatLng latLng : latLngs) {
ScreenCoordinate pixel = pixelForLatLng(latLng);
swPixel.x = std::min(swPixel.x, pixel.x);
@@ -552,8 +581,8 @@ CameraOptions Map::cameraForLatLngs(const std::vector<LatLng>& latLngs, optional
// Calculate the zoom level.
double minScale = INFINITY;
if (width > 0 || height > 0) {
- double scaleX = getWidth() / width;
- double scaleY = getHeight() / height;
+ double scaleX = double(getSize().width) / width;
+ double scaleY = double(getSize().height) / height;
if (padding && *padding) {
scaleX -= (padding->left + padding->right) / width;
scaleY -= (padding->top + padding->bottom) / height;
@@ -587,6 +616,7 @@ CameraOptions Map::cameraForLatLngs(const std::vector<LatLng>& latLngs, optional
}
void Map::resetZoom() {
+ impl->cameraMutated = true;
setZoom(0);
}
@@ -614,36 +644,36 @@ double Map::getMaxZoom() const {
#pragma mark - Size
-void Map::setSize(const std::array<uint16_t, 2>& size) {
+void Map::setSize(const Size size) {
impl->transform.resize(size);
impl->onUpdate(Update::Repaint);
}
-uint16_t Map::getWidth() const {
- return impl->transform.getState().getWidth();
-}
-
-uint16_t Map::getHeight() const {
- return impl->transform.getState().getHeight();
+Size Map::getSize() const {
+ return impl->transform.getState().getSize();
}
#pragma mark - Rotation
void Map::rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const Duration& duration) {
+ impl->cameraMutated = true;
impl->transform.rotateBy(first, second, duration);
impl->onUpdate(Update::Repaint);
}
void Map::setBearing(double degrees, const Duration& duration) {
+ impl->cameraMutated = true;
setBearing(degrees, EdgeInsets(), duration);
}
void Map::setBearing(double degrees, optional<ScreenCoordinate> anchor, const Duration& duration) {
+ impl->cameraMutated = true;
impl->transform.setAngle(-degrees * util::DEG2RAD, anchor, duration);
impl->onUpdate(Update::Repaint);
}
void Map::setBearing(double degrees, optional<EdgeInsets> padding, const Duration& duration) {
+ impl->cameraMutated = true;
impl->transform.setAngle(-degrees * util::DEG2RAD, padding, duration);
impl->onUpdate(Update::Repaint);
}
@@ -653,6 +683,7 @@ double Map::getBearing() const {
}
void Map::resetNorth(const Duration& duration) {
+ impl->cameraMutated = true;
impl->transform.setAngle(0, duration);
impl->onUpdate(Update::Repaint);
}
@@ -660,10 +691,12 @@ void Map::resetNorth(const Duration& duration) {
#pragma mark - Pitch
void Map::setPitch(double pitch, const Duration& duration) {
+ impl->cameraMutated = true;
setPitch(pitch, {}, duration);
}
void Map::setPitch(double pitch, optional<ScreenCoordinate> anchor, const Duration& duration) {
+ impl->cameraMutated = true;
impl->transform.setPitch(pitch * util::DEG2RAD, anchor, duration);
impl->onUpdate(Update::Repaint);
}
@@ -789,7 +822,8 @@ AnnotationIDs Map::queryPointAnnotations(const ScreenBox& box) {
std::set<AnnotationID> set;
for (auto &feature : features) {
assert(feature.id);
- assert(*feature.id <= std::numeric_limits<AnnotationID>::max());
+ assert(feature.id->is<uint64_t>());
+ assert(feature.id->get<uint64_t>() <= std::numeric_limits<AnnotationID>::max());
set.insert(static_cast<AnnotationID>(feature.id->get<uint64_t>()));
}
AnnotationIDs ids;
@@ -826,7 +860,7 @@ std::unique_ptr<Source> Map::removeSource(const std::string& sourceID) {
}
return nullptr;
}
-
+
std::vector<style::Layer*> Map::getLayers() {
return impl->style ? impl->style->getLayers() : std::vector<style::Layer*>();
}
diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp
index 85805a109d..ba5e205301 100644
--- a/src/mbgl/map/transform.cpp
+++ b/src/mbgl/map/transform.cpp
@@ -9,8 +9,8 @@
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/projection.hpp>
#include <mbgl/math/clamp.hpp>
-#include <mbgl/platform/log.hpp>
-#include <mbgl/platform/platform.hpp>
+#include <mbgl/util/logging.hpp>
+#include <mbgl/util/platform.hpp>
#include <cstdio>
#include <cmath>
@@ -45,8 +45,8 @@ Transform::Transform(std::function<void(MapChange)> callback_,
#pragma mark - Map View
-bool Transform::resize(const std::array<uint16_t, 2> size) {
- if (state.width == size[0] && state.height == size[1]) {
+bool Transform::resize(const Size size) {
+ if (state.size == size) {
return false;
}
@@ -54,8 +54,7 @@ bool Transform::resize(const std::array<uint16_t, 2> size) {
callback(MapChangeRegionWillChange);
}
- state.width = size[0];
- state.height = size[1];
+ state.size = size;
state.constrain(state.scale, state.x, state.y);
if (callback) {
@@ -117,7 +116,7 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim
const Point<double> endPoint = Projection::project(latLng, state.scale);
ScreenCoordinate center = getScreenCoordinate(padding);
- center.y = state.height - center.y;
+ center.y = state.size.height - center.y;
// Constrain camera options.
zoom = util::clamp(zoom, state.getMinZoom(), state.getMaxZoom());
@@ -187,7 +186,7 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
const Point<double> endPoint = Projection::project(latLng, state.scale);
ScreenCoordinate center = getScreenCoordinate(padding);
- center.y = state.height - center.y;
+ center.y = state.size.height - center.y;
// Constrain camera options.
zoom = util::clamp(zoom, state.getMinZoom(), state.getMaxZoom());
@@ -203,9 +202,9 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
/// w₀: Initial visible span, measured in pixels at the initial scale.
/// Known henceforth as a <i>screenful</i>.
- double w0 = padding ? std::max(state.width, state.height)
- : std::max(state.width - padding.left - padding.right,
- state.height - padding.top - padding.bottom);
+ double w0 = padding ? std::max(state.size.width, state.size.height)
+ : std::max(state.size.width - padding.left - padding.right,
+ state.size.height - padding.top - padding.bottom);
/// w₁: Final visible span, measured in pixels with respect to the initial
/// scale.
double w1 = w0 / state.zoomScale(zoom - startZoom);
@@ -355,8 +354,8 @@ void Transform::setLatLng(const LatLng& latLng, optional<ScreenCoordinate> ancho
EdgeInsets padding;
padding.top = anchor->y;
padding.left = anchor->x;
- padding.bottom = state.height - anchor->y;
- padding.right = state.width - anchor->x;
+ padding.bottom = state.size.height - anchor->y;
+ padding.right = state.size.width - anchor->x;
if (padding) camera.padding = padding;
}
easeTo(camera, duration);
@@ -378,7 +377,7 @@ void Transform::setLatLngZoom(const LatLng& latLng, double zoom, optional<EdgeIn
LatLng Transform::getLatLng(optional<EdgeInsets> padding) const {
if (padding && *padding) {
- return screenCoordinateToLatLng(padding->getCenter(state.width, state.height));
+ return screenCoordinateToLatLng(padding->getCenter(state.size.width, state.size.height));
} else {
return state.getLatLng();
}
@@ -386,9 +385,9 @@ LatLng Transform::getLatLng(optional<EdgeInsets> padding) const {
ScreenCoordinate Transform::getScreenCoordinate(optional<EdgeInsets> padding) const {
if (padding && *padding) {
- return padding->getCenter(state.width, state.height);
+ return padding->getCenter(state.size.width, state.size.height);
} else {
- return { state.width / 2., state.height / 2. };
+ return { state.size.width / 2., state.size.height / 2. };
}
}
@@ -565,7 +564,7 @@ void Transform::startTransition(const CameraOptions& camera,
optional<ScreenCoordinate> anchor = camera.anchor;
LatLng anchorLatLng;
if (anchor) {
- anchor->y = state.getHeight() - anchor->y;
+ anchor->y = state.size.height - anchor->y;
anchorLatLng = state.screenCoordinateToLatLng(*anchor);
}
@@ -650,13 +649,13 @@ ScreenCoordinate Transform::latLngToScreenCoordinate(const LatLng& latLng) const
LatLng unwrappedLatLng = latLng.wrapped();
unwrappedLatLng.unwrapForShortestPath(getLatLng());
ScreenCoordinate point = state.latLngToScreenCoordinate(unwrappedLatLng);
- point.y = state.height - point.y;
+ point.y = state.size.height - point.y;
return point;
}
LatLng Transform::screenCoordinateToLatLng(const ScreenCoordinate& point) const {
ScreenCoordinate flippedPoint = point;
- flippedPoint.y = state.height - flippedPoint.y;
+ flippedPoint.y = state.size.height - flippedPoint.y;
return state.screenCoordinateToLatLng(flippedPoint).wrapped();
}
diff --git a/src/mbgl/map/transform.hpp b/src/mbgl/map/transform.hpp
index abc301b1cb..febe71035d 100644
--- a/src/mbgl/map/transform.hpp
+++ b/src/mbgl/map/transform.hpp
@@ -23,7 +23,7 @@ public:
ViewportMode = ViewportMode::Default);
// Map view
- bool resize(std::array<uint16_t, 2> size);
+ bool resize(Size size);
// Camera
/** Returns the current camera options. */
diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp
index 4f6bcecdb6..59ae129518 100644
--- a/src/mbgl/map/transform_state.cpp
+++ b/src/mbgl/map/transform_state.cpp
@@ -2,7 +2,7 @@
#include <mbgl/tile/tile_id.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/interpolate.hpp>
-#include <mbgl/util/math.hpp>
+#include <mbgl/math/log2.hpp>
#include <mbgl/math/clamp.hpp>
namespace mbgl {
@@ -33,15 +33,16 @@ void TransformState::getProjMatrix(mat4& projMatrix) const {
// Calculate z value of the farthest fragment that should be rendered.
double farZ = std::cos(M_PI / 2.0f - getPitch()) * topHalfSurfaceDistance + getAltitude();
- matrix::perspective(projMatrix, 2.0f * std::atan((getHeight() / 2.0f) / getAltitude()),
- double(getWidth()) / getHeight(), 0.1, farZ);
+ matrix::perspective(projMatrix, 2.0f * std::atan((size.height / 2.0f) / getAltitude()),
+ double(size.width) / size.height, 0.1, farZ);
matrix::translate(projMatrix, projMatrix, 0, 0, -getAltitude());
// After the rotateX, z values are in pixel units. Convert them to
// altitude unites. 1 altitude unit = the screen height.
const bool flippedY = viewportMode == ViewportMode::FlippedY;
- matrix::scale(projMatrix, projMatrix, 1, flippedY ? 1 : -1, 1.0f / (rotatedNorth() ? getWidth() : getHeight()));
+ matrix::scale(projMatrix, projMatrix, 1, flippedY ? 1 : -1,
+ 1.0f / (rotatedNorth() ? size.width : size.height));
using NO = NorthOrientation;
switch (getNorthOrientation()) {
@@ -53,18 +54,14 @@ void TransformState::getProjMatrix(mat4& projMatrix) const {
matrix::rotate_z(projMatrix, projMatrix, getAngle() + getNorthOrientationAngle());
- matrix::translate(projMatrix, projMatrix, pixel_x() - getWidth() / 2.0f,
- pixel_y() - getHeight() / 2.0f, 0);
+ matrix::translate(projMatrix, projMatrix, pixel_x() - size.width / 2.0f,
+ pixel_y() - size.height / 2.0f, 0);
}
#pragma mark - Dimensions
-uint16_t TransformState::getWidth() const {
- return width;
-}
-
-uint16_t TransformState::getHeight() const {
- return height;
+Size TransformState::getSize() const {
+ return size;
}
#pragma mark - North Orientation
@@ -108,23 +105,23 @@ LatLng TransformState::getLatLng(LatLng::WrapMode wrapMode) const {
}
double TransformState::pixel_x() const {
- const double center = (width - Projection::worldSize(scale)) / 2;
+ const double center = (size.width - Projection::worldSize(scale)) / 2;
return center + x;
}
double TransformState::pixel_y() const {
- const double center = (height - Projection::worldSize(scale)) / 2;
+ const double center = (size.height - Projection::worldSize(scale)) / 2;
return center + y;
}
#pragma mark - Zoom
double TransformState::getZoom() const {
- return std::log(scale) / M_LN2;
+ return scaleZoom(scale);
}
int32_t TransformState::getIntegerZoom() const {
- return std::floor(getZoom());
+ return getZoom();
}
double TransformState::getZoomFraction() const {
@@ -202,7 +199,7 @@ bool TransformState::isGestureInProgress() const {
#pragma mark - Projection
double TransformState::zoomScale(double zoom) const {
- return std::pow(2.0f, zoom);
+ return std::pow(2.0, zoom);
}
double TransformState::scaleZoom(double s) const {
@@ -210,7 +207,7 @@ double TransformState::scaleZoom(double s) const {
}
ScreenCoordinate TransformState::latLngToScreenCoordinate(const LatLng& latLng) const {
- if (width == 0 || height == 0) {
+ if (!size) {
return {};
}
@@ -219,11 +216,11 @@ ScreenCoordinate TransformState::latLngToScreenCoordinate(const LatLng& latLng)
Point<double> pt = Projection::project(latLng, scale) / double(util::tileSize);
vec4 c = {{ pt.x, pt.y, 0, 1 }};
matrix::transformMat4(p, c, mat);
- return { p[0] / p[3], height - p[1] / p[3] };
+ return { p[0] / p[3], size.height - p[1] / p[3] };
}
LatLng TransformState::screenCoordinateToLatLng(const ScreenCoordinate& point, LatLng::WrapMode wrapMode) const {
- if (width == 0 || height == 0) {
+ if (!size) {
return {};
}
@@ -235,7 +232,7 @@ LatLng TransformState::screenCoordinateToLatLng(const ScreenCoordinate& point, L
if (err) throw std::runtime_error("failed to invert coordinatePointMatrix");
- double flippedY = height - point.y;
+ double flippedY = size.height - point.y;
// since we don't know the correct projected z value for the point,
// unproject two points to get a line and then find the point on that
@@ -273,7 +270,8 @@ mat4 TransformState::coordinatePointMatrix(double z) const {
mat4 TransformState::getPixelMatrix() const {
mat4 m;
matrix::identity(m);
- matrix::scale(m, m, width / 2.0f, -height / 2.0f, 1);
+ matrix::scale(m, m,
+ static_cast<double>(size.width) / 2, -static_cast<double>(size.height) / 2, 1);
matrix::translate(m, m, 1, -1, 0);
return m;
}
@@ -289,17 +287,17 @@ bool TransformState::rotatedNorth() const {
void TransformState::constrain(double& scale_, double& x_, double& y_) const {
// Constrain minimum scale to avoid zooming out far enough to show off-world areas.
scale_ = util::max(scale_,
- static_cast<double>((rotatedNorth() ? height : width) / util::tileSize),
- static_cast<double>((rotatedNorth() ? width : height) / util::tileSize));
+ static_cast<double>(rotatedNorth() ? size.height : size.width) / util::tileSize,
+ static_cast<double>(rotatedNorth() ? size.width : size.height) / util::tileSize);
// Constrain min/max pan to avoid showing off-world areas.
if (constrainMode == ConstrainMode::WidthAndHeight) {
- double max_x = (scale_ * util::tileSize - (rotatedNorth() ? height : width)) / 2;
+ double max_x = (scale_ * util::tileSize - (rotatedNorth() ? size.height : size.width)) / 2;
x_ = std::max(-max_x, std::min(x_, max_x));
}
if (constrainMode != ConstrainMode::None) {
- double max_y = (scale_ * util::tileSize - (rotatedNorth() ? width : height)) / 2;
+ double max_y = (scale_ * util::tileSize - (rotatedNorth() ? size.width : size.height)) / 2;
y_ = std::max(-max_y, std::min(y_, max_y));
}
}
diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp
index 8a12b62a9e..6faaf4ac41 100644
--- a/src/mbgl/map/transform_state.hpp
+++ b/src/mbgl/map/transform_state.hpp
@@ -6,6 +6,7 @@
#include <mbgl/util/constants.hpp>
#include <mbgl/util/projection.hpp>
#include <mbgl/util/mat4.hpp>
+#include <mbgl/util/size.hpp>
#include <cstdint>
#include <array>
@@ -26,8 +27,7 @@ public:
void getProjMatrix(mat4& matrix) const;
// Dimensions
- uint16_t getWidth() const;
- uint16_t getHeight() const;
+ Size getSize() const;
// North Orientation
NorthOrientation getNorthOrientation() const;
@@ -84,7 +84,7 @@ private:
NorthOrientation orientation = NorthOrientation::Upwards;
// logical dimensions
- uint16_t width = 0, height = 0;
+ Size size;
mat4 coordinatePointMatrix(double z) const;
mat4 getPixelMatrix() const;
diff --git a/src/mbgl/util/math.cpp b/src/mbgl/math/log2.cpp
index 7b1516c041..222e67dbd7 100644
--- a/src/mbgl/util/math.cpp
+++ b/src/mbgl/math/log2.cpp
@@ -1,4 +1,4 @@
-#include <mbgl/util/math.hpp>
+#include <mbgl/math/log2.hpp>
namespace mbgl {
namespace util {
@@ -21,15 +21,5 @@ uint32_t ceil_log2(uint64_t x) {
return y;
}
-double log2(double x) {
-// log2() is producing wrong results on ARMv5 binaries
-// running on ARMv7+ CPUs.
-#if defined(__ANDROID__)
- return std::log(x) / 0.6931471805599453; // log(x) / log(2)
-#else
- return ::log2(x);
-#endif
-}
-
} // namespace util
} // namespace mbgl
diff --git a/src/mbgl/programs/attributes.hpp b/src/mbgl/programs/attributes.hpp
new file mode 100644
index 0000000000..38bbe89377
--- /dev/null
+++ b/src/mbgl/programs/attributes.hpp
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <mbgl/gl/attribute.hpp>
+
+#include <cstdint>
+
+namespace mbgl {
+namespace attributes {
+
+// Attributes common to several shaders.
+
+MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_pos);
+MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_offset);
+MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_extrude);
+MBGL_DEFINE_ATTRIBUTE(uint16_t, 2, a_texture_pos);
+
+template <std::size_t N>
+struct a_data : gl::Attribute<a_data<N>, uint8_t, N> {
+ static constexpr auto name = "a_data";
+};
+
+} // namespace attributes
+} // namespace mbgl
diff --git a/src/mbgl/programs/circle_program.cpp b/src/mbgl/programs/circle_program.cpp
new file mode 100644
index 0000000000..d6bc439feb
--- /dev/null
+++ b/src/mbgl/programs/circle_program.cpp
@@ -0,0 +1,7 @@
+#include <mbgl/programs/circle_program.hpp>
+
+namespace mbgl {
+
+static_assert(sizeof(CircleProgram::Vertex) == 4, "expected CircleVertex size");
+
+} // namespace mbgl
diff --git a/src/mbgl/programs/circle_program.hpp b/src/mbgl/programs/circle_program.hpp
new file mode 100644
index 0000000000..c9aea1d137
--- /dev/null
+++ b/src/mbgl/programs/circle_program.hpp
@@ -0,0 +1,59 @@
+#pragma once
+
+#include <mbgl/programs/program.hpp>
+#include <mbgl/programs/attributes.hpp>
+#include <mbgl/programs/uniforms.hpp>
+#include <mbgl/shader/circle.hpp>
+#include <mbgl/util/geometry.hpp>
+
+namespace mbgl {
+
+namespace uniforms {
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_radius);
+MBGL_DEFINE_UNIFORM_SCALAR(Color, u_stroke_color);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_stroke_width);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_stroke_opacity);
+MBGL_DEFINE_UNIFORM_SCALAR(bool, u_scale_with_map);
+} // namespace uniforms
+
+using CircleAttributes = gl::Attributes<
+ attributes::a_pos>;
+
+class CircleProgram : public Program<
+ shaders::circle,
+ gl::Triangle,
+ CircleAttributes,
+ gl::Uniforms<
+ uniforms::u_matrix,
+ uniforms::u_opacity,
+ uniforms::u_color,
+ uniforms::u_radius,
+ uniforms::u_blur,
+ uniforms::u_stroke_color,
+ uniforms::u_stroke_width,
+ uniforms::u_stroke_opacity,
+ uniforms::u_scale_with_map,
+ uniforms::u_extrude_scale>>
+{
+public:
+ using Program::Program;
+
+ /*
+ * @param {number} x vertex position
+ * @param {number} y vertex position
+ * @param {number} ex extrude normal
+ * @param {number} ey extrude normal
+ */
+ static Vertex vertex(Point<int16_t> p, float ex, float ey) {
+ return Vertex {
+ {
+ static_cast<int16_t>((p.x * 2) + ((ex + 1) / 2)),
+ static_cast<int16_t>((p.y * 2) + ((ey + 1) / 2))
+ }
+ };
+ }
+};
+
+using CircleVertex = CircleProgram::Vertex;
+
+} // namespace mbgl
diff --git a/src/mbgl/programs/collision_box_program.cpp b/src/mbgl/programs/collision_box_program.cpp
new file mode 100644
index 0000000000..d6a36e54a1
--- /dev/null
+++ b/src/mbgl/programs/collision_box_program.cpp
@@ -0,0 +1,7 @@
+#include <mbgl/programs/collision_box_program.hpp>
+
+namespace mbgl {
+
+static_assert(sizeof(CollisionBoxProgram::Vertex) == 10, "expected CollisionBoxVertex size");
+
+} // namespace mbgl
diff --git a/src/mbgl/programs/collision_box_program.hpp b/src/mbgl/programs/collision_box_program.hpp
new file mode 100644
index 0000000000..26e38419a4
--- /dev/null
+++ b/src/mbgl/programs/collision_box_program.hpp
@@ -0,0 +1,56 @@
+#pragma once
+
+#include <mbgl/programs/program.hpp>
+#include <mbgl/programs/attributes.hpp>
+#include <mbgl/programs/uniforms.hpp>
+#include <mbgl/shader/collision_box.hpp>
+#include <mbgl/util/geometry.hpp>
+
+#include <cmath>
+
+namespace mbgl {
+
+namespace uniforms {
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_scale);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_maxzoom);
+} // namespace uniforms
+
+using CollisionBoxAttributes = gl::Attributes<
+ attributes::a_pos,
+ attributes::a_extrude,
+ attributes::a_data<2>>;
+
+class CollisionBoxProgram : public Program<
+ shaders::collision_box,
+ gl::Line,
+ CollisionBoxAttributes,
+ gl::Uniforms<
+ uniforms::u_matrix,
+ uniforms::u_scale,
+ uniforms::u_zoom,
+ uniforms::u_maxzoom>>
+{
+public:
+ using Program::Program;
+
+ static Vertex vertex(Point<float> a, Point<float> o, float maxzoom, float placementZoom) {
+ return Vertex {
+ {
+ static_cast<int16_t>(a.x),
+ static_cast<int16_t>(a.y)
+ },
+ {
+ static_cast<int16_t>(::round(o.x)),
+ static_cast<int16_t>(::round(o.y))
+ },
+ {
+ static_cast<uint8_t>(maxzoom * 10),
+ static_cast<uint8_t>(placementZoom * 10)
+ }
+ };
+ }
+};
+
+using CollisionBoxVertex = CollisionBoxProgram::Vertex;
+
+} // namespace mbgl
diff --git a/src/mbgl/programs/debug_program.hpp b/src/mbgl/programs/debug_program.hpp
new file mode 100644
index 0000000000..cd4e08b1bc
--- /dev/null
+++ b/src/mbgl/programs/debug_program.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <mbgl/programs/program.hpp>
+#include <mbgl/programs/attributes.hpp>
+#include <mbgl/programs/uniforms.hpp>
+#include <mbgl/shader/debug.hpp>
+
+namespace mbgl {
+
+using DebugAttributes = gl::Attributes<
+ attributes::a_pos>;
+
+class DebugProgram : public Program<
+ shaders::debug,
+ gl::Line,
+ DebugAttributes,
+ gl::Uniforms<
+ uniforms::u_matrix,
+ uniforms::u_color>>
+{
+public:
+ using Program::Program;
+};
+
+using DebugVertex = DebugProgram::Vertex;
+
+} // namespace mbgl
diff --git a/src/mbgl/programs/fill_program.cpp b/src/mbgl/programs/fill_program.cpp
new file mode 100644
index 0000000000..a8154d08f9
--- /dev/null
+++ b/src/mbgl/programs/fill_program.cpp
@@ -0,0 +1,47 @@
+#include <mbgl/programs/fill_program.hpp>
+#include <mbgl/sprite/sprite_atlas.hpp>
+#include <mbgl/style/cross_faded_property_evaluator.hpp>
+#include <mbgl/tile/tile_id.hpp>
+#include <mbgl/map/transform_state.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+static_assert(sizeof(FillAttributes::Vertex) == 4, "expected FillVertex size");
+
+FillPatternUniforms::Values
+FillPatternUniforms::values(mat4 matrix,
+ float opacity,
+ Size framebufferSize,
+ const SpriteAtlasPosition& a,
+ const SpriteAtlasPosition& b,
+ const Faded<std::string>& fading,
+ const UnwrappedTileID& tileID,
+ const TransformState& state)
+{
+ int32_t tileSizeAtNearestZoom = util::tileSize * state.zoomScale(state.getIntegerZoom() - tileID.canonical.z);
+ int32_t pixelX = tileSizeAtNearestZoom * (tileID.canonical.x + tileID.wrap * state.zoomScale(tileID.canonical.z));
+ int32_t pixelY = tileSizeAtNearestZoom * tileID.canonical.y;
+
+ return FillPatternUniforms::Values {
+ uniforms::u_matrix::Value{ matrix },
+ uniforms::u_opacity::Value{ opacity },
+ uniforms::u_world::Value{ framebufferSize },
+ uniforms::u_pattern_tl_a::Value{ a.tl },
+ uniforms::u_pattern_br_a::Value{ a.br },
+ uniforms::u_pattern_tl_b::Value{ b.tl },
+ uniforms::u_pattern_br_b::Value{ b.br },
+ uniforms::u_pattern_size_a::Value{ a.size },
+ uniforms::u_pattern_size_b::Value{ b.size },
+ uniforms::u_scale_a::Value{ fading.fromScale },
+ uniforms::u_scale_b::Value{ fading.toScale },
+ uniforms::u_mix::Value{ fading.t },
+ uniforms::u_image::Value{ 0 },
+ uniforms::u_pixel_coord_upper::Value{ std::array<float, 2> {{ float(pixelX >> 16), float(pixelY >> 16) }} },
+ uniforms::u_pixel_coord_lower::Value{ std::array<float, 2> {{ float(pixelX & 0xFFFF), float(pixelY & 0xFFFF) }} },
+ uniforms::u_tile_units_to_pixels::Value{ 1.0f / tileID.pixelsToTileUnits(1.0f, state.getIntegerZoom()) },
+ };
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/programs/fill_program.hpp b/src/mbgl/programs/fill_program.hpp
new file mode 100644
index 0000000000..d885215c59
--- /dev/null
+++ b/src/mbgl/programs/fill_program.hpp
@@ -0,0 +1,123 @@
+#pragma once
+
+#include <mbgl/programs/program.hpp>
+#include <mbgl/programs/attributes.hpp>
+#include <mbgl/programs/uniforms.hpp>
+#include <mbgl/shader/fill.hpp>
+#include <mbgl/shader/fill_pattern.hpp>
+#include <mbgl/shader/fill_outline.hpp>
+#include <mbgl/shader/fill_outline_pattern.hpp>
+#include <mbgl/util/geometry.hpp>
+#include <mbgl/util/mat4.hpp>
+#include <mbgl/util/size.hpp>
+
+#include <string>
+
+namespace mbgl {
+
+class SpriteAtlasPosition;
+class UnwrappedTileID;
+class TransformState;
+
+namespace style {
+template <class> class Faded;
+} // namespace style
+
+namespace uniforms {
+MBGL_DEFINE_UNIFORM_SCALAR(Size, u_world);
+MBGL_DEFINE_UNIFORM_SCALAR(Color, u_outline_color);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_scale_a);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_scale_b);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_tile_units_to_pixels);
+MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pixel_coord_upper);
+MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pixel_coord_lower);
+} // namespace uniforms
+
+struct FillAttributes : gl::Attributes<
+ attributes::a_pos>
+{
+ static Vertex vertex(Point<int16_t> p) {
+ return Vertex {
+ {
+ p.x,
+ p.y
+ }
+ };
+ }
+};
+
+using FillVertex = FillAttributes::Vertex;
+
+struct FillUniforms : gl::Uniforms<
+ uniforms::u_matrix,
+ uniforms::u_opacity,
+ uniforms::u_color,
+ uniforms::u_outline_color,
+ uniforms::u_world>
+{};
+
+struct FillPatternUniforms : gl::Uniforms<
+ uniforms::u_matrix,
+ uniforms::u_opacity,
+ uniforms::u_world,
+ uniforms::u_pattern_tl_a,
+ uniforms::u_pattern_br_a,
+ uniforms::u_pattern_tl_b,
+ uniforms::u_pattern_br_b,
+ uniforms::u_pattern_size_a,
+ uniforms::u_pattern_size_b,
+ uniforms::u_scale_a,
+ uniforms::u_scale_b,
+ uniforms::u_mix,
+ uniforms::u_image,
+ uniforms::u_pixel_coord_upper,
+ uniforms::u_pixel_coord_lower,
+ uniforms::u_tile_units_to_pixels>
+{
+ static Values values(mat4 matrix,
+ float opacity,
+ Size framebufferSize,
+ const SpriteAtlasPosition&,
+ const SpriteAtlasPosition&,
+ const style::Faded<std::string>&,
+ const UnwrappedTileID&,
+ const TransformState&);
+};
+
+class FillProgram : public Program<
+ shaders::fill,
+ gl::Triangle,
+ FillAttributes,
+ FillUniforms>
+{
+ using Program::Program;
+};
+
+class FillPatternProgram : public Program<
+ shaders::fill_pattern,
+ gl::Triangle,
+ FillAttributes,
+ FillPatternUniforms>
+{
+ using Program::Program;
+};
+
+class FillOutlineProgram : public Program<
+ shaders::fill_outline,
+ gl::Line,
+ FillAttributes,
+ FillUniforms>
+{
+ using Program::Program;
+};
+
+class FillOutlinePatternProgram : public Program<
+ shaders::fill_outline_pattern,
+ gl::Line,
+ FillAttributes,
+ FillPatternUniforms>
+{
+ using Program::Program;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/programs/line_program.cpp b/src/mbgl/programs/line_program.cpp
new file mode 100644
index 0000000000..2cadaa6c11
--- /dev/null
+++ b/src/mbgl/programs/line_program.cpp
@@ -0,0 +1,129 @@
+#include <mbgl/programs/line_program.hpp>
+#include <mbgl/style/layers/line_layer_properties.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/map/transform_state.hpp>
+#include <mbgl/util/mat2.hpp>
+#include <mbgl/sprite/sprite_atlas.hpp>
+#include <mbgl/geometry/line_atlas.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+static_assert(sizeof(LineAttributes::Vertex) == 8, "expected LineVertex size");
+
+template <class Values, class...Args>
+Values makeValues(const LinePaintProperties::Evaluated& properties,
+ const RenderTile& tile,
+ const TransformState& state,
+ Args&&... args) {
+
+ mat2 antialiasingMatrix;
+ matrix::identity(antialiasingMatrix);
+ matrix::scale(antialiasingMatrix, antialiasingMatrix, 1.0, std::cos(state.getPitch()));
+ matrix::rotate(antialiasingMatrix, antialiasingMatrix, state.getAngle());
+
+ // calculate how much longer the real world distance is at the top of the screen
+ // than at the middle of the screen.
+ float topedgelength = std::sqrt(std::pow(state.getSize().height, 2.0f) / 4.0f * (1.0f + std::pow(state.getAltitude(), 2.0f)));
+ float x = state.getSize().height / 2.0f * std::tan(state.getPitch());
+
+ return Values {
+ uniforms::u_matrix::Value{
+ tile.translatedMatrix(properties.get<LineTranslate>(),
+ properties.get<LineTranslateAnchor>(),
+ state)
+ },
+ uniforms::u_opacity::Value{ properties.get<LineOpacity>() },
+ uniforms::u_width::Value{ properties.get<LineWidth>() },
+ uniforms::u_gapwidth::Value{ properties.get<LineGapWidth>() },
+ uniforms::u_blur::Value{ properties.get<LineBlur>() },
+ uniforms::u_offset::Value{ properties.get<LineOffset>() },
+ uniforms::u_antialiasingmatrix::Value{ antialiasingMatrix },
+ uniforms::u_ratio::Value{ 1.0f / tile.id.pixelsToTileUnits(1.0, state.getZoom()) },
+ uniforms::u_extra::Value{ (topedgelength + x) / topedgelength - 1.0f },
+ std::forward<Args>(args)...
+ };
+}
+
+LineProgram::UniformValues
+LineProgram::uniformValues(const LinePaintProperties::Evaluated& properties,
+ const RenderTile& tile,
+ const TransformState& state) {
+ return makeValues<LineProgram::UniformValues>(
+ properties,
+ tile,
+ state,
+ uniforms::u_color::Value{ properties.get<LineColor>() }
+ );
+}
+
+LineSDFProgram::UniformValues
+LineSDFProgram::uniformValues(const LinePaintProperties::Evaluated& properties,
+ float pixelRatio,
+ const RenderTile& tile,
+ const TransformState& state,
+ const LinePatternPos& posA,
+ const LinePatternPos& posB,
+ float dashLineWidth,
+ float atlasWidth) {
+ const float widthA = posA.width * properties.get<LineDasharray>().fromScale * dashLineWidth;
+ const float widthB = posB.width * properties.get<LineDasharray>().toScale * dashLineWidth;
+
+ std::array<float, 2> scaleA {{
+ 1.0f / tile.id.pixelsToTileUnits(widthA, state.getIntegerZoom()),
+ -posA.height / 2.0f
+ }};
+
+ std::array<float, 2> scaleB {{
+ 1.0f / tile.id.pixelsToTileUnits(widthB, state.getIntegerZoom()),
+ -posB.height / 2.0f
+ }};
+
+ return makeValues<LineSDFProgram::UniformValues>(
+ properties,
+ tile,
+ state,
+ uniforms::u_color::Value{ properties.get<LineColor>() },
+ uniforms::u_patternscale_a::Value{ scaleA },
+ uniforms::u_patternscale_b::Value{ scaleB },
+ uniforms::u_tex_y_a::Value{ posA.y },
+ uniforms::u_tex_y_b::Value{ posB.y },
+ uniforms::u_mix::Value{ properties.get<LineDasharray>().t },
+ uniforms::u_sdfgamma::Value{ atlasWidth / (std::min(widthA, widthB) * 256.0f * pixelRatio) / 2.0f },
+ uniforms::u_image::Value{ 0 }
+ );
+}
+
+LinePatternProgram::UniformValues
+LinePatternProgram::uniformValues(const LinePaintProperties::Evaluated& properties,
+ const RenderTile& tile,
+ const TransformState& state,
+ const SpriteAtlasPosition& posA,
+ const SpriteAtlasPosition& posB) {
+ std::array<float, 2> sizeA {{
+ tile.id.pixelsToTileUnits(posA.size[0] * properties.get<LinePattern>().fromScale, state.getIntegerZoom()),
+ posA.size[1]
+ }};
+
+ std::array<float, 2> sizeB {{
+ tile.id.pixelsToTileUnits(posB.size[0] * properties.get<LinePattern>().toScale, state.getIntegerZoom()),
+ posB.size[1]
+ }};
+
+ return makeValues<LinePatternProgram::UniformValues>(
+ properties,
+ tile,
+ state,
+ uniforms::u_pattern_tl_a::Value{ posA.tl },
+ uniforms::u_pattern_br_a::Value{ posA.br },
+ uniforms::u_pattern_tl_b::Value{ posB.tl },
+ uniforms::u_pattern_br_b::Value{ posB.br },
+ uniforms::u_pattern_size_a::Value{ sizeA },
+ uniforms::u_pattern_size_b::Value{ sizeB },
+ uniforms::u_fade::Value{ properties.get<LinePattern>().t },
+ uniforms::u_image::Value{ 0 }
+ );
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/programs/line_program.hpp b/src/mbgl/programs/line_program.hpp
new file mode 100644
index 0000000000..059806ffb2
--- /dev/null
+++ b/src/mbgl/programs/line_program.hpp
@@ -0,0 +1,178 @@
+#pragma once
+
+#include <mbgl/programs/program.hpp>
+#include <mbgl/programs/attributes.hpp>
+#include <mbgl/programs/uniforms.hpp>
+#include <mbgl/shader/line.hpp>
+#include <mbgl/shader/line_pattern.hpp>
+#include <mbgl/shader/line_sdf.hpp>
+#include <mbgl/style/layers/line_layer_properties.hpp>
+#include <mbgl/util/geometry.hpp>
+
+#include <cmath>
+
+namespace mbgl {
+
+class RenderTile;
+class TransformState;
+class LinePatternPos;
+class SpriteAtlasPosition;
+
+namespace uniforms {
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_ratio);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_width);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_gapwidth);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_extra);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_offset);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_tex_y_a);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_tex_y_b);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_sdfgamma);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_fade);
+MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_patternscale_a);
+MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_patternscale_b);
+MBGL_DEFINE_UNIFORM_MATRIX(double, 2, u_antialiasingmatrix);
+} // namespace uniforms
+
+struct LineAttributes : gl::Attributes<
+ attributes::a_pos,
+ attributes::a_data<4>>
+{
+ /*
+ * @param p vertex position
+ * @param e extrude normal
+ * @param t texture normal
+ * @param dir direction of the line cap (-1/0/1)
+ */
+ static Vertex vertex(Point<int16_t> p, Point<double> e, Point<bool> t, int8_t dir, int32_t linesofar = 0) {
+ return Vertex {
+ {
+ static_cast<int16_t>((p.x * 2) | t.x),
+ static_cast<int16_t>((p.y * 2) | t.y)
+ },
+ {
+ // add 128 to store an byte in an unsigned byte
+ static_cast<uint8_t>(::round(extrudeScale * e.x) + 128),
+ static_cast<uint8_t>(::round(extrudeScale * e.y) + 128),
+
+ // Encode the -1/0/1 direction value into the first two bits of .z of a_data.
+ // Combine it with the lower 6 bits of `linesofar` (shifted by 2 bites to make
+ // room for the direction value). The upper 8 bits of `linesofar` are placed in
+ // the `w` component. `linesofar` is scaled down by `LINE_DISTANCE_SCALE` so that
+ // we can store longer distances while sacrificing precision.
+
+ // Encode the -1/0/1 direction value into .zw coordinates of a_data, which is normally covered
+ // by linesofar, so we need to merge them.
+ // The z component's first bit, as well as the sign bit is reserved for the direction,
+ // so we need to shift the linesofar.
+ static_cast<uint8_t>(((dir == 0 ? 0 : (dir < 0 ? -1 : 1 )) + 1) | ((linesofar & 0x3F) << 2)),
+ static_cast<uint8_t>(linesofar >> 6)
+ }
+ };
+ }
+
+ /*
+ * Scale the extrusion vector so that the normal length is this value.
+ * Contains the "texture" normals (-1..1). This is distinct from the extrude
+ * normals for line joins, because the x-value remains 0 for the texture
+ * normal array, while the extrude normal actually moves the vertex to create
+ * the acute/bevelled line join.
+ */
+ static const int8_t extrudeScale = 63;
+};
+
+using LineVertex = LineAttributes::Vertex;
+
+class LineProgram : public Program<
+ shaders::line,
+ gl::Triangle,
+ LineAttributes,
+ gl::Uniforms<
+ uniforms::u_matrix,
+ uniforms::u_opacity,
+ uniforms::u_width,
+ uniforms::u_gapwidth,
+ uniforms::u_blur,
+ uniforms::u_offset,
+ uniforms::u_antialiasingmatrix,
+ uniforms::u_ratio,
+ uniforms::u_extra,
+ uniforms::u_color>>
+{
+public:
+ using Program::Program;
+
+ static UniformValues uniformValues(const style::LinePaintProperties::Evaluated&,
+ const RenderTile&,
+ const TransformState&);
+};
+
+class LinePatternProgram : public Program<
+ shaders::line_pattern,
+ gl::Triangle,
+ LineAttributes,
+ gl::Uniforms<
+ uniforms::u_matrix,
+ uniforms::u_opacity,
+ uniforms::u_width,
+ uniforms::u_gapwidth,
+ uniforms::u_blur,
+ uniforms::u_offset,
+ uniforms::u_antialiasingmatrix,
+ uniforms::u_ratio,
+ uniforms::u_extra,
+ uniforms::u_pattern_tl_a,
+ uniforms::u_pattern_br_a,
+ uniforms::u_pattern_tl_b,
+ uniforms::u_pattern_br_b,
+ uniforms::u_pattern_size_a,
+ uniforms::u_pattern_size_b,
+ uniforms::u_fade,
+ uniforms::u_image>>
+{
+public:
+ using Program::Program;
+
+ static UniformValues uniformValues(const style::LinePaintProperties::Evaluated&,
+ const RenderTile&,
+ const TransformState&,
+ const SpriteAtlasPosition& posA,
+ const SpriteAtlasPosition& posB);
+};
+
+class LineSDFProgram : public Program<
+ shaders::line_sdf,
+ gl::Triangle,
+ LineAttributes,
+ gl::Uniforms<
+ uniforms::u_matrix,
+ uniforms::u_opacity,
+ uniforms::u_width,
+ uniforms::u_gapwidth,
+ uniforms::u_blur,
+ uniforms::u_offset,
+ uniforms::u_antialiasingmatrix,
+ uniforms::u_ratio,
+ uniforms::u_extra,
+ uniforms::u_color,
+ uniforms::u_patternscale_a,
+ uniforms::u_patternscale_b,
+ uniforms::u_tex_y_a,
+ uniforms::u_tex_y_b,
+ uniforms::u_mix,
+ uniforms::u_sdfgamma,
+ uniforms::u_image>>
+{
+public:
+ using Program::Program;
+
+ static UniformValues uniformValues(const style::LinePaintProperties::Evaluated&,
+ float pixelRatio,
+ const RenderTile&,
+ const TransformState&,
+ const LinePatternPos& posA,
+ const LinePatternPos& posB,
+ float dashLineWidth,
+ float atlasWidth);
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/programs/program.hpp b/src/mbgl/programs/program.hpp
new file mode 100644
index 0000000000..e5aae24997
--- /dev/null
+++ b/src/mbgl/programs/program.hpp
@@ -0,0 +1,43 @@
+#pragma once
+
+#include <mbgl/gl/program.hpp>
+#include <mbgl/programs/program_parameters.hpp>
+
+#include <sstream>
+#include <cassert>
+
+namespace mbgl {
+
+template <class Shaders, class Primitive, class Attributes, class Uniforms>
+class Program : public gl::Program<Primitive, Attributes, Uniforms> {
+public:
+ using ParentType = gl::Program<Primitive, Attributes, Uniforms>;
+
+ Program(gl::Context& context, const ProgramParameters& programParameters)
+ : ParentType(context, vertexSource(programParameters), fragmentSource(programParameters))
+ {}
+
+ static std::string pixelRatioDefine(const ProgramParameters& parameters) {
+ std::ostringstream pixelRatioSS;
+ pixelRatioSS.imbue(std::locale("C"));
+ pixelRatioSS.setf(std::ios_base::showpoint);
+ pixelRatioSS << parameters.pixelRatio;
+ return std::string("#define DEVICE_PIXEL_RATIO ") + pixelRatioSS.str() + "\n";
+ }
+
+ static std::string fragmentSource(const ProgramParameters& parameters) {
+ std::string source = pixelRatioDefine(parameters) + Shaders::fragmentSource;
+ if (parameters.overdraw) {
+ assert(source.find("#ifdef OVERDRAW_INSPECTOR") != std::string::npos);
+ source.replace(source.find_first_of('\n'), 1, "\n#define OVERDRAW_INSPECTOR\n");
+ }
+ return source;
+ }
+
+ static std::string vertexSource(const ProgramParameters& parameters) {
+ return pixelRatioDefine(parameters) + Shaders::vertexSource;
+ }
+
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/programs/program_parameters.hpp b/src/mbgl/programs/program_parameters.hpp
new file mode 100644
index 0000000000..ad8cbf1bf8
--- /dev/null
+++ b/src/mbgl/programs/program_parameters.hpp
@@ -0,0 +1,16 @@
+#pragma once
+
+namespace mbgl {
+
+class ProgramParameters {
+public:
+ ProgramParameters(float pixelRatio_ = 1.0, bool overdraw_ = false)
+ : pixelRatio(pixelRatio_),
+ overdraw(overdraw_) {}
+
+ float pixelRatio;
+ bool overdraw;
+};
+
+} // namespace mbgl
+
diff --git a/src/mbgl/programs/programs.hpp b/src/mbgl/programs/programs.hpp
new file mode 100644
index 0000000000..dd71c2ce97
--- /dev/null
+++ b/src/mbgl/programs/programs.hpp
@@ -0,0 +1,50 @@
+#pragma once
+
+#include <mbgl/programs/circle_program.hpp>
+#include <mbgl/programs/fill_program.hpp>
+#include <mbgl/programs/line_program.hpp>
+#include <mbgl/programs/raster_program.hpp>
+#include <mbgl/programs/symbol_program.hpp>
+#include <mbgl/programs/debug_program.hpp>
+#include <mbgl/programs/collision_box_program.hpp>
+#include <mbgl/programs/program_parameters.hpp>
+
+namespace mbgl {
+
+class Programs {
+public:
+ Programs(gl::Context& context, const ProgramParameters& programParameters)
+ : circle(context, programParameters),
+ fill(context, programParameters),
+ fillPattern(context, programParameters),
+ fillOutline(context, programParameters),
+ fillOutlinePattern(context, programParameters),
+ line(context, programParameters),
+ lineSDF(context, programParameters),
+ linePattern(context, programParameters),
+ raster(context, programParameters),
+ symbolIcon(context, programParameters),
+ symbolIconSDF(context, programParameters),
+ symbolGlyph(context, programParameters),
+ debug(context, ProgramParameters(programParameters.pixelRatio, false)),
+ collisionBox(context, ProgramParameters(programParameters.pixelRatio, false)) {
+ }
+
+ CircleProgram circle;
+ FillProgram fill;
+ FillPatternProgram fillPattern;
+ FillOutlineProgram fillOutline;
+ FillOutlinePatternProgram fillOutlinePattern;
+ LineProgram line;
+ LineSDFProgram lineSDF;
+ LinePatternProgram linePattern;
+ RasterProgram raster;
+ SymbolIconProgram symbolIcon;
+ SymbolSDFProgram symbolIconSDF;
+ SymbolSDFProgram symbolGlyph;
+
+ DebugProgram debug;
+ CollisionBoxProgram collisionBox;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/programs/raster_program.cpp b/src/mbgl/programs/raster_program.cpp
new file mode 100644
index 0000000000..ebec4c68cc
--- /dev/null
+++ b/src/mbgl/programs/raster_program.cpp
@@ -0,0 +1,7 @@
+#include <mbgl/programs/raster_program.hpp>
+
+namespace mbgl {
+
+static_assert(sizeof(RasterProgram::Vertex) == 8, "expected RasterVertex size");
+
+} // namespace mbgl
diff --git a/src/mbgl/programs/raster_program.hpp b/src/mbgl/programs/raster_program.hpp
new file mode 100644
index 0000000000..d6179904d2
--- /dev/null
+++ b/src/mbgl/programs/raster_program.hpp
@@ -0,0 +1,68 @@
+#pragma once
+
+#include <mbgl/programs/program.hpp>
+#include <mbgl/programs/attributes.hpp>
+#include <mbgl/programs/uniforms.hpp>
+#include <mbgl/shader/raster.hpp>
+#include <mbgl/util/geometry.hpp>
+
+namespace mbgl {
+
+namespace uniforms {
+MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_image0);
+MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_image1);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_opacity0);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_opacity1);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_buffer_scale);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_brightness_low);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_brightness_high);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_saturation_factor);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_contrast_factor);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_scale_parent);
+MBGL_DEFINE_UNIFORM_VECTOR(float, 3, u_spin_weights);
+MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_tl_parent);
+} // namespace uniforms
+
+using RasterAttributes = gl::Attributes<
+ attributes::a_pos,
+ attributes::a_texture_pos>;
+
+class RasterProgram : public Program<
+ shaders::raster,
+ gl::Triangle,
+ RasterAttributes,
+ gl::Uniforms<
+ uniforms::u_matrix,
+ uniforms::u_image0,
+ uniforms::u_image1,
+ uniforms::u_opacity0,
+ uniforms::u_opacity1,
+ uniforms::u_brightness_low,
+ uniforms::u_brightness_high,
+ uniforms::u_saturation_factor,
+ uniforms::u_contrast_factor,
+ uniforms::u_spin_weights,
+ uniforms::u_buffer_scale,
+ uniforms::u_scale_parent,
+ uniforms::u_tl_parent>>
+{
+public:
+ using Program::Program;
+
+ static Vertex vertex(Point<int16_t> p, Point<uint16_t> t) {
+ return Vertex {
+ {
+ p.x,
+ p.y
+ },
+ {
+ t.x,
+ t.y
+ }
+ };
+ }
+};
+
+using RasterVertex = RasterProgram::Vertex;
+
+} // namespace mbgl
diff --git a/src/mbgl/programs/symbol_program.cpp b/src/mbgl/programs/symbol_program.cpp
new file mode 100644
index 0000000000..8c9c34210c
--- /dev/null
+++ b/src/mbgl/programs/symbol_program.cpp
@@ -0,0 +1,145 @@
+#include <mbgl/programs/symbol_program.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/map/transform_state.hpp>
+#include <mbgl/style/layers/symbol_layer_impl.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+static_assert(sizeof(SymbolAttributes::Vertex) == 16, "expected SymbolVertex size");
+
+template <class Values, class...Args>
+Values makeValues(const style::SymbolPropertyValues& values,
+ const Size& texsize,
+ const std::array<float, 2>& pixelsToGLUnits,
+ const RenderTile& tile,
+ const TransformState& state,
+ Args&&... args) {
+ std::array<float, 2> extrudeScale;
+
+ const float scale = values.paintSize / values.sdfScale;
+ if (values.pitchAlignment == AlignmentType::Map) {
+ extrudeScale.fill(tile.id.pixelsToTileUnits(1, state.getZoom()) * scale);
+ } else {
+ extrudeScale = {{
+ pixelsToGLUnits[0] * scale * state.getAltitude(),
+ pixelsToGLUnits[1] * scale * state.getAltitude()
+ }};
+ }
+
+ // adjust min/max zooms for variable font sies
+ float zoomAdjust = std::log(values.paintSize / values.layoutSize) / std::log(2);
+
+ return Values {
+ uniforms::u_matrix::Value{ tile.translatedMatrix(values.translate,
+ values.translateAnchor,
+ state) },
+ uniforms::u_opacity::Value{ values.opacity },
+ uniforms::u_extrude_scale::Value{ extrudeScale },
+ uniforms::u_texsize::Value{ std::array<float, 2> {{ float(texsize.width) / 4, float(texsize.height) / 4 }} },
+ uniforms::u_zoom::Value{ float((state.getZoom() - zoomAdjust) * 10) },
+ uniforms::u_rotate_with_map::Value{ values.rotationAlignment == AlignmentType::Map },
+ uniforms::u_texture::Value{ 0 },
+ uniforms::u_fadetexture::Value{ 1 },
+ std::forward<Args>(args)...
+ };
+}
+
+SymbolIconProgram::UniformValues
+SymbolIconProgram::uniformValues(const style::SymbolPropertyValues& values,
+ const Size& texsize,
+ const std::array<float, 2>& pixelsToGLUnits,
+ const RenderTile& tile,
+ const TransformState& state)
+{
+ return makeValues<SymbolIconProgram::UniformValues>(
+ values,
+ texsize,
+ pixelsToGLUnits,
+ tile,
+ state
+ );
+}
+
+static SymbolSDFProgram::UniformValues makeSDFValues(const style::SymbolPropertyValues& values,
+ const Size& texsize,
+ const std::array<float, 2>& pixelsToGLUnits,
+ const RenderTile& tile,
+ const TransformState& state,
+ float pixelRatio,
+ Color color,
+ float buffer,
+ float gammaAdjust)
+{
+ // The default gamma value has to be adjust for the current pixelratio so that we're not
+ // drawing blurry font on retina screens.
+ const float gammaBase = 0.105 * values.sdfScale / values.paintSize / pixelRatio;
+ const float gammaScale = values.pitchAlignment == AlignmentType::Map
+ ? 1.0 / std::cos(state.getPitch())
+ : 1.0;
+
+ return makeValues<SymbolSDFProgram::UniformValues>(
+ values,
+ texsize,
+ pixelsToGLUnits,
+ tile,
+ state,
+ uniforms::u_color::Value{ color },
+ uniforms::u_buffer::Value{ buffer },
+ uniforms::u_gamma::Value{ (gammaBase + gammaAdjust) * gammaScale },
+ uniforms::u_pitch::Value{ state.getPitch() },
+ uniforms::u_bearing::Value{ -1.0f * state.getAngle() },
+ uniforms::u_aspect_ratio::Value{ (state.getSize().width * 1.0f) / (state.getSize().height * 1.0f) },
+ uniforms::u_pitch_with_map::Value{ values.pitchAlignment == AlignmentType::Map }
+ );
+}
+
+SymbolSDFProgram::UniformValues
+SymbolSDFProgram::haloUniformValues(const style::SymbolPropertyValues& values,
+ const Size& texsize,
+ const std::array<float, 2>& pixelsToGLUnits,
+ const RenderTile& tile,
+ const TransformState& state,
+ float pixelRatio)
+{
+ const float scale = values.paintSize / values.sdfScale;
+ const float sdfPx = 8.0f;
+ const float blurOffset = 1.19f;
+ const float haloOffset = 6.0f;
+
+ return makeSDFValues(
+ values,
+ texsize,
+ pixelsToGLUnits,
+ tile,
+ state,
+ pixelRatio,
+ values.haloColor,
+ (haloOffset - values.haloWidth / scale) / sdfPx,
+ values.haloBlur * blurOffset / scale / sdfPx
+ );
+}
+
+SymbolSDFProgram::UniformValues
+SymbolSDFProgram::foregroundUniformValues(const style::SymbolPropertyValues& values,
+ const Size& texsize,
+ const std::array<float, 2>& pixelsToGLUnits,
+ const RenderTile& tile,
+ const TransformState& state,
+ float pixelRatio)
+{
+ return makeSDFValues(
+ values,
+ texsize,
+ pixelsToGLUnits,
+ tile,
+ state,
+ pixelRatio,
+ values.color,
+ (256.0f - 64.0f) / 256.0f,
+ 0
+ );
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp
new file mode 100644
index 0000000000..be987551c0
--- /dev/null
+++ b/src/mbgl/programs/symbol_program.hpp
@@ -0,0 +1,136 @@
+#pragma once
+
+#include <mbgl/programs/program.hpp>
+#include <mbgl/programs/attributes.hpp>
+#include <mbgl/programs/uniforms.hpp>
+#include <mbgl/shader/symbol_icon.hpp>
+#include <mbgl/shader/symbol_sdf.hpp>
+#include <mbgl/util/geometry.hpp>
+#include <mbgl/util/size.hpp>
+
+#include <cmath>
+#include <array>
+
+namespace mbgl {
+
+namespace style {
+class SymbolPropertyValues;
+} // namespace style
+
+class RenderTile;
+class TransformState;
+
+namespace uniforms {
+MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_texsize);
+MBGL_DEFINE_UNIFORM_SCALAR(bool, u_rotate_with_map);
+MBGL_DEFINE_UNIFORM_SCALAR(bool, u_pitch_with_map);
+MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_texture);
+MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_fadetexture);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_buffer);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_gamma);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_aspect_ratio);
+} // namespace uniforms
+
+struct SymbolAttributes : gl::Attributes<
+ attributes::a_pos,
+ attributes::a_offset,
+ attributes::a_texture_pos,
+ attributes::a_data<4>>
+{
+ static Vertex vertex(Point<float> a,
+ Point<float> o,
+ uint16_t tx,
+ uint16_t ty,
+ float minzoom,
+ float maxzoom,
+ float labelminzoom,
+ uint8_t labelangle) {
+ return Vertex {
+ {
+ static_cast<int16_t>(a.x),
+ static_cast<int16_t>(a.y)
+ },
+ {
+ static_cast<int16_t>(::round(o.x * 64)), // use 1/64 pixels for placement
+ static_cast<int16_t>(::round(o.y * 64))
+ },
+ {
+ static_cast<uint16_t>(tx / 4),
+ static_cast<uint16_t>(ty / 4)
+ },
+ {
+ static_cast<uint8_t>(labelminzoom * 10), // 1/10 zoom levels: z16 == 160
+ static_cast<uint8_t>(labelangle),
+ static_cast<uint8_t>(minzoom * 10),
+ static_cast<uint8_t>(::fmin(maxzoom, 25) * 10)
+ }
+ };
+ }
+};
+
+using SymbolVertex = SymbolAttributes::Vertex;
+
+class SymbolIconProgram : public Program<
+ shaders::symbol_icon,
+ gl::Triangle,
+ SymbolAttributes,
+ gl::Uniforms<
+ uniforms::u_matrix,
+ uniforms::u_opacity,
+ uniforms::u_extrude_scale,
+ uniforms::u_texsize,
+ uniforms::u_zoom,
+ uniforms::u_rotate_with_map,
+ uniforms::u_texture,
+ uniforms::u_fadetexture>>
+{
+public:
+ using Program::Program;
+
+ static UniformValues uniformValues(const style::SymbolPropertyValues&,
+ const Size& texsize,
+ const std::array<float, 2>& pixelsToGLUnits,
+ const RenderTile&,
+ const TransformState&);
+};
+
+class SymbolSDFProgram : public Program<
+ shaders::symbol_sdf,
+ gl::Triangle,
+ SymbolAttributes,
+ gl::Uniforms<
+ uniforms::u_matrix,
+ uniforms::u_opacity,
+ uniforms::u_extrude_scale,
+ uniforms::u_texsize,
+ uniforms::u_zoom,
+ uniforms::u_rotate_with_map,
+ uniforms::u_texture,
+ uniforms::u_fadetexture,
+ uniforms::u_color,
+ uniforms::u_buffer,
+ uniforms::u_gamma,
+ uniforms::u_pitch,
+ uniforms::u_bearing,
+ uniforms::u_aspect_ratio,
+ uniforms::u_pitch_with_map>>
+{
+public:
+ using Program::Program;
+
+ static UniformValues haloUniformValues(const style::SymbolPropertyValues&,
+ const Size& texsize,
+ const std::array<float, 2>& pixelsToGLUnits,
+ const RenderTile&,
+ const TransformState&,
+ float pixelRatio);
+
+ static UniformValues foregroundUniformValues(const style::SymbolPropertyValues&,
+ const Size& texsize,
+ const std::array<float, 2>& pixelsToGLUnits,
+ const RenderTile&,
+ const TransformState&,
+ float pixelRatio);
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/programs/uniforms.hpp b/src/mbgl/programs/uniforms.hpp
new file mode 100644
index 0000000000..e0c5a0d361
--- /dev/null
+++ b/src/mbgl/programs/uniforms.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <mbgl/gl/uniform.hpp>
+#include <mbgl/util/color.hpp>
+
+namespace mbgl {
+namespace uniforms {
+
+// Uniforms common to several shaders.
+
+MBGL_DEFINE_UNIFORM_MATRIX(double, 4, u_matrix);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_opacity);
+MBGL_DEFINE_UNIFORM_SCALAR(Color, u_color);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_blur);
+
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_zoom);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_pitch);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_bearing);
+
+MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_extrude_scale);
+
+MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_tl_a);
+MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_br_a);
+MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_tl_b);
+MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_br_b);
+MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_size_a);
+MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_size_b);
+
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_mix);
+MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_image);
+
+} // namespace uniforms
+} // namespace mbgl
diff --git a/src/mbgl/renderer/bucket.hpp b/src/mbgl/renderer/bucket.hpp
index 2c3c7a6e47..49619c14f7 100644
--- a/src/mbgl/renderer/bucket.hpp
+++ b/src/mbgl/renderer/bucket.hpp
@@ -5,9 +5,6 @@
#include <atomic>
-#define BUFFER_OFFSET_0 ((int8_t*)nullptr)
-#define BUFFER_OFFSET(i) ((BUFFER_OFFSET_0) + (i))
-
namespace mbgl {
class Painter;
@@ -38,8 +35,6 @@ public:
virtual bool hasData() const = 0;
- virtual bool needsClipping() const = 0;
-
bool needsUpload() const {
return !uploaded;
}
diff --git a/src/mbgl/renderer/circle_bucket.cpp b/src/mbgl/renderer/circle_bucket.cpp
index f12139d004..ba2285c4eb 100644
--- a/src/mbgl/renderer/circle_bucket.cpp
+++ b/src/mbgl/renderer/circle_bucket.cpp
@@ -1,8 +1,8 @@
#include <mbgl/renderer/circle_bucket.hpp>
#include <mbgl/renderer/painter.hpp>
-#include <mbgl/gl/gl.hpp>
+#include <mbgl/gl/context.hpp>
-#include <mbgl/shader/circle_shader.hpp>
+#include <mbgl/programs/circle_program.hpp>
#include <mbgl/style/layers/circle_layer.hpp>
#include <mbgl/util/constants.hpp>
@@ -13,10 +13,6 @@ using namespace style;
CircleBucket::CircleBucket(MapMode mode_) : mode(mode_) {
}
-CircleBucket::~CircleBucket() {
- // Do not remove. header file only contains forward definitions to unique pointers.
-}
-
void CircleBucket::upload(gl::Context& context) {
vertexBuffer = context.createVertexBuffer(std::move(vertices));
indexBuffer = context.createIndexBuffer(std::move(triangles));
@@ -31,18 +27,16 @@ void CircleBucket::render(Painter& painter,
}
bool CircleBucket::hasData() const {
- return !groups.empty();
-}
-
-bool CircleBucket::needsClipping() const {
- return true;
+ return !segments.empty();
}
void CircleBucket::addGeometry(const GeometryCollection& geometryCollection) {
+ constexpr const uint16_t vertexLength = 4;
+
for (auto& circle : geometryCollection) {
- for(auto & geometry : circle) {
- auto x = geometry.x;
- auto y = geometry.y;
+ for(auto& point : circle) {
+ auto x = point.x;
+ auto y = point.y;
// Do not include points that are outside the tile boundaries.
// Include all points in Still mode. You need to include points from
@@ -50,6 +44,11 @@ void CircleBucket::addGeometry(const GeometryCollection& geometryCollection) {
if ((mode != MapMode::Still) &&
(x < 0 || x >= util::EXTENT || y < 0 || y >= util::EXTENT)) continue;
+ if (segments.empty() || segments.back().vertexLength + vertexLength > std::numeric_limits<uint16_t>::max()) {
+ // Move to a new segments because the old one can't hold the geometry.
+ segments.emplace_back(vertices.vertexSize(), triangles.indexSize());
+ }
+
// this geometry will be of the Point type, and we'll derive
// two triangles from it.
//
@@ -59,47 +58,23 @@ void CircleBucket::addGeometry(const GeometryCollection& geometryCollection) {
// │ 1 2 │
// └─────────┘
//
- vertices.emplace_back(x, y, -1, -1); // 1
- vertices.emplace_back(x, y, 1, -1); // 2
- vertices.emplace_back(x, y, 1, 1); // 3
- vertices.emplace_back(x, y, -1, 1); // 4
-
- if (!groups.size() || groups.back().vertexLength + 4 > 65535) {
- // Move to a new group because the old one can't hold the geometry.
- groups.emplace_back();
- }
+ vertices.emplace_back(CircleProgram::vertex(point, -1, -1)); // 1
+ vertices.emplace_back(CircleProgram::vertex(point, 1, -1)); // 2
+ vertices.emplace_back(CircleProgram::vertex(point, 1, 1)); // 3
+ vertices.emplace_back(CircleProgram::vertex(point, -1, 1)); // 4
- auto& group = groups.back();
- uint16_t index = group.vertexLength;
+ auto& segment = segments.back();
+ assert(segment.vertexLength <= std::numeric_limits<uint16_t>::max());
+ uint16_t index = segment.vertexLength;
// 1, 2, 3
// 1, 4, 3
- triangles.emplace_back(index,
- static_cast<uint16_t>(index + 1),
- static_cast<uint16_t>(index + 2));
- triangles.emplace_back(index,
- static_cast<uint16_t>(index + 3),
- static_cast<uint16_t>(index + 2));
-
- group.vertexLength += 4;
- group.indexLength += 2;
- }
- }
-}
-
-void CircleBucket::drawCircles(CircleShader& shader, gl::Context& context, PaintMode paintMode) {
- GLbyte* vertexIndex = BUFFER_OFFSET(0);
- GLbyte* elementsIndex = BUFFER_OFFSET(0);
+ triangles.emplace_back(index, index + 1, index + 2);
+ triangles.emplace_back(index, index + 3, index + 2);
- for (auto& group : groups) {
- if (!group.indexLength) continue;
-
- group.getVAO(shader, paintMode).bind(shader, *vertexBuffer, *indexBuffer, vertexIndex, context);
-
- MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(group.indexLength * 3), GL_UNSIGNED_SHORT, elementsIndex));
-
- vertexIndex += group.vertexLength * vertexBuffer->vertexSize;
- elementsIndex += group.indexLength * indexBuffer->primitiveSize;
+ segment.vertexLength += vertexLength;
+ segment.indexLength += 6;
+ }
}
}
diff --git a/src/mbgl/renderer/circle_bucket.hpp b/src/mbgl/renderer/circle_bucket.hpp
index 2f3faccdec..af7041a238 100644
--- a/src/mbgl/renderer/circle_bucket.hpp
+++ b/src/mbgl/renderer/circle_bucket.hpp
@@ -1,39 +1,31 @@
#pragma once
#include <mbgl/renderer/bucket.hpp>
-#include <mbgl/renderer/element_group.hpp>
#include <mbgl/map/mode.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/gl/vertex_buffer.hpp>
#include <mbgl/gl/index_buffer.hpp>
-#include <mbgl/shader/circle_vertex.hpp>
+#include <mbgl/gl/segment.hpp>
+#include <mbgl/programs/circle_program.hpp>
namespace mbgl {
-class CircleShader;
-
class CircleBucket : public Bucket {
public:
CircleBucket(const MapMode);
- ~CircleBucket() override;
void upload(gl::Context&) override;
void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override;
bool hasData() const override;
- bool needsClipping() const override;
void addGeometry(const GeometryCollection&);
- void drawCircles(CircleShader&, gl::Context&, PaintMode);
-
-private:
- std::vector<CircleVertex> vertices;
- std::vector<gl::Triangle> triangles;
-
- std::vector<ElementGroup<CircleShader>> groups;
+ gl::VertexVector<CircleVertex> vertices;
+ gl::IndexVector<gl::Triangles> triangles;
+ gl::SegmentVector<CircleAttributes> segments;
optional<gl::VertexBuffer<CircleVertex>> vertexBuffer;
- optional<gl::IndexBuffer<gl::Triangle>> indexBuffer;
+ optional<gl::IndexBuffer<gl::Triangles>> indexBuffer;
const MapMode mode;
};
diff --git a/src/mbgl/renderer/debug_bucket.cpp b/src/mbgl/renderer/debug_bucket.cpp
index c47ae434be..167df4376f 100644
--- a/src/mbgl/renderer/debug_bucket.cpp
+++ b/src/mbgl/renderer/debug_bucket.cpp
@@ -1,25 +1,30 @@
#include <mbgl/renderer/debug_bucket.hpp>
#include <mbgl/renderer/painter.hpp>
-#include <mbgl/shader/fill_shader.hpp>
-#include <mbgl/shader/fill_vertex.hpp>
+#include <mbgl/programs/fill_program.hpp>
#include <mbgl/geometry/debug_font_data.hpp>
#include <mbgl/util/string.hpp>
-#include <mbgl/gl/gl.hpp>
-
#include <cmath>
#include <string>
#include <vector>
namespace mbgl {
-std::vector<FillVertex> buildTextVertices(const OverscaledTileID& id,
- const bool renderable,
- const bool complete,
- optional<Timestamp> modified,
- optional<Timestamp> expires,
- MapDebugOptions debugMode) {
- std::vector<FillVertex> textPoints;
+DebugBucket::DebugBucket(const OverscaledTileID& id,
+ const bool renderable_,
+ const bool complete_,
+ optional<Timestamp> modified_,
+ optional<Timestamp> expires_,
+ MapDebugOptions debugMode_,
+ gl::Context& context)
+ : renderable(renderable_),
+ complete(complete_),
+ modified(std::move(modified_)),
+ expires(std::move(expires_)),
+ debugMode(debugMode_) {
+
+ gl::VertexVector<FillVertex> vertices;
+ gl::IndexVector<gl::Lines> indices;
auto addText = [&] (const std::string& text, double left, double baseline, double scale) {
for (uint8_t c : text) {
@@ -38,9 +43,11 @@ std::vector<FillVertex> buildTextVertices(const OverscaledTileID& id,
int16_t(::round(baseline - glyph.data[j + 1] * scale))
};
+ vertices.emplace_back(FillAttributes::vertex(p));
+
if (prev) {
- textPoints.emplace_back(prev->x, prev->y);
- textPoints.emplace_back(p.x, p.y);
+ indices.emplace_back(vertices.vertexSize() - 2,
+ vertices.vertexSize() - 1);
}
prev = p;
@@ -67,36 +74,10 @@ std::vector<FillVertex> buildTextVertices(const OverscaledTileID& id,
addText(expiresText, 50, baseline + 200, 5);
}
- return textPoints;
-}
-
-DebugBucket::DebugBucket(const OverscaledTileID& id,
- const bool renderable_,
- const bool complete_,
- optional<Timestamp> modified_,
- optional<Timestamp> expires_,
- MapDebugOptions debugMode_,
- gl::Context& context)
- : renderable(renderable_),
- complete(complete_),
- modified(std::move(modified_)),
- expires(std::move(expires_)),
- debugMode(debugMode_),
- vertexBuffer(context.createVertexBuffer(buildTextVertices(id, renderable_, complete_, modified_, expires_, debugMode_))) {
-}
+ segments.emplace_back(0, 0, vertices.vertexSize(), indices.indexSize());
-void DebugBucket::drawLines(FillShader& shader, gl::Context& context) {
- if (vertexBuffer.vertexCount != 0) {
- array.bind(shader, vertexBuffer, BUFFER_OFFSET_0, context);
- MBGL_CHECK_ERROR(glDrawArrays(GL_LINES, 0, static_cast<GLsizei>(vertexBuffer.vertexCount)));
- }
-}
-
-void DebugBucket::drawPoints(FillShader& shader, gl::Context& context) {
- if (vertexBuffer.vertexCount != 0) {
- array.bind(shader, vertexBuffer, BUFFER_OFFSET_0, context);
- MBGL_CHECK_ERROR(glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(vertexBuffer.vertexCount)));
- }
+ vertexBuffer = context.createVertexBuffer(std::move(vertices));
+ indexBuffer = context.createIndexBuffer(std::move(indices));
}
} // namespace mbgl
diff --git a/src/mbgl/renderer/debug_bucket.hpp b/src/mbgl/renderer/debug_bucket.hpp
index 89087f0010..4676381789 100644
--- a/src/mbgl/renderer/debug_bucket.hpp
+++ b/src/mbgl/renderer/debug_bucket.hpp
@@ -6,13 +6,12 @@
#include <mbgl/util/optional.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/gl/vertex_buffer.hpp>
-#include <mbgl/gl/vao.hpp>
-#include <mbgl/shader/fill_vertex.hpp>
+#include <mbgl/gl/index_buffer.hpp>
+#include <mbgl/programs/debug_program.hpp>
namespace mbgl {
class OverscaledTileID;
-class FillShader;
namespace gl {
class Context;
@@ -28,18 +27,15 @@ public:
MapDebugOptions,
gl::Context&);
- void drawLines(FillShader&, gl::Context&);
- void drawPoints(FillShader&, gl::Context&);
-
const bool renderable;
const bool complete;
const optional<Timestamp> modified;
const optional<Timestamp> expires;
const MapDebugOptions debugMode;
-private:
- gl::VertexBuffer<FillVertex> vertexBuffer;
- gl::VertexArrayObject array;
+ gl::SegmentVector<DebugAttributes> segments;
+ optional<gl::VertexBuffer<DebugVertex>> vertexBuffer;
+ optional<gl::IndexBuffer<gl::Lines>> indexBuffer;
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/element_group.hpp b/src/mbgl/renderer/element_group.hpp
deleted file mode 100644
index 59b5c3068d..0000000000
--- a/src/mbgl/renderer/element_group.hpp
+++ /dev/null
@@ -1,28 +0,0 @@
-#pragma once
-
-#include <mbgl/gl/vao.hpp>
-#include <mbgl/renderer/render_pass.hpp>
-
-namespace mbgl {
-
-template <class... Shaders>
-struct ElementGroup {
- template <class Shader>
- struct VAOs {
- gl::VertexArrayObject normalVAO;
- gl::VertexArrayObject overdrawVAO;
- };
-
- std::tuple<VAOs<Shaders>...> vaos;
-
- template <class Shader>
- gl::VertexArrayObject& getVAO(const Shader&, PaintMode paintMode) {
- auto& vao = std::get<VAOs<Shader>>(vaos);
- return paintMode == PaintMode::Overdraw ? vao.overdrawVAO : vao.normalVAO;
- }
-
- std::size_t vertexLength = 0;
- std::size_t indexLength = 0;
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/renderer/fill_bucket.cpp b/src/mbgl/renderer/fill_bucket.cpp
index cd4277cabc..b89e982057 100644
--- a/src/mbgl/renderer/fill_bucket.cpp
+++ b/src/mbgl/renderer/fill_bucket.cpp
@@ -1,12 +1,8 @@
#include <mbgl/renderer/fill_bucket.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
#include <mbgl/renderer/painter.hpp>
-#include <mbgl/shader/fill_shader.hpp>
-#include <mbgl/shader/fill_pattern_shader.hpp>
-#include <mbgl/shader/fill_outline_shader.hpp>
-#include <mbgl/shader/fill_outline_pattern_shader.hpp>
-#include <mbgl/gl/gl.hpp>
-#include <mbgl/platform/log.hpp>
+#include <mbgl/programs/fill_program.hpp>
+#include <mbgl/util/logging.hpp>
#include <mapbox/earcut.hpp>
@@ -30,11 +26,6 @@ using namespace style;
struct GeometryTooLongException : std::exception {};
-FillBucket::FillBucket() {
-}
-
-FillBucket::~FillBucket() = default;
-
void FillBucket::addGeometry(const GeometryCollection& geometry) {
for (auto& polygon : classifyRings(geometry)) {
// Optimize polygons with many interior rings for earcut tesselation.
@@ -44,34 +35,36 @@ void FillBucket::addGeometry(const GeometryCollection& geometry) {
for (const auto& ring : polygon) {
totalVertices += ring.size();
- if (totalVertices > 65535)
+ if (totalVertices > std::numeric_limits<uint16_t>::max())
throw GeometryTooLongException();
}
+ std::size_t startVertices = vertices.vertexSize();
+
for (const auto& ring : polygon) {
std::size_t nVertices = ring.size();
if (nVertices == 0)
continue;
- if (lineGroups.empty() || lineGroups.back().vertexLength + nVertices > 65535)
- lineGroups.emplace_back();
+ if (lineSegments.empty() || lineSegments.back().vertexLength + nVertices > std::numeric_limits<uint16_t>::max()) {
+ lineSegments.emplace_back(vertices.vertexSize(), lines.indexSize());
+ }
- auto& lineGroup = lineGroups.back();
- uint16_t lineIndex = lineGroup.vertexLength;
+ auto& lineSegment = lineSegments.back();
+ assert(lineSegment.vertexLength <= std::numeric_limits<uint16_t>::max());
+ uint16_t lineIndex = lineSegment.vertexLength;
- vertices.emplace_back(ring[0].x, ring[0].y);
- lines.emplace_back(static_cast<uint16_t>(lineIndex + nVertices - 1),
- static_cast<uint16_t>(lineIndex));
+ vertices.emplace_back(FillAttributes::vertex(ring[0]));
+ lines.emplace_back(lineIndex + nVertices - 1, lineIndex);
for (uint32_t i = 1; i < nVertices; i++) {
- vertices.emplace_back(ring[i].x, ring[i].y);
- lines.emplace_back(static_cast<uint16_t>(lineIndex + i - 1),
- static_cast<uint16_t>(lineIndex + i));
+ vertices.emplace_back(FillAttributes::vertex(ring[i]));
+ lines.emplace_back(lineIndex + i - 1, lineIndex + i);
}
- lineGroup.vertexLength += nVertices;
- lineGroup.indexLength += nVertices;
+ lineSegment.vertexLength += nVertices;
+ lineSegment.indexLength += nVertices * 2;
}
std::vector<uint32_t> indices = mapbox::earcut(polygon);
@@ -79,21 +72,22 @@ void FillBucket::addGeometry(const GeometryCollection& geometry) {
std::size_t nIndicies = indices.size();
assert(nIndicies % 3 == 0);
- if (triangleGroups.empty() || triangleGroups.back().vertexLength + totalVertices > 65535) {
- triangleGroups.emplace_back();
+ if (triangleSegments.empty() || triangleSegments.back().vertexLength + totalVertices > std::numeric_limits<uint16_t>::max()) {
+ triangleSegments.emplace_back(startVertices, triangles.indexSize());
}
- auto& triangleGroup = triangleGroups.back();
- uint16_t triangleIndex = triangleGroup.vertexLength;
+ auto& triangleSegment = triangleSegments.back();
+ assert(triangleSegment.vertexLength <= std::numeric_limits<uint16_t>::max());
+ uint16_t triangleIndex = triangleSegment.vertexLength;
for (uint32_t i = 0; i < nIndicies; i += 3) {
- triangles.emplace_back(static_cast<uint16_t>(triangleIndex + indices[i]),
- static_cast<uint16_t>(triangleIndex + indices[i + 1]),
- static_cast<uint16_t>(triangleIndex + indices[i + 2]));
+ triangles.emplace_back(triangleIndex + indices[i],
+ triangleIndex + indices[i + 1],
+ triangleIndex + indices[i + 2]);
}
- triangleGroup.vertexLength += totalVertices;
- triangleGroup.indexLength += nIndicies / 3;
+ triangleSegment.vertexLength += totalVertices;
+ triangleSegment.indexLength += nIndicies;
}
}
@@ -114,71 +108,7 @@ void FillBucket::render(Painter& painter,
}
bool FillBucket::hasData() const {
- return !triangleGroups.empty() || !lineGroups.empty();
-}
-
-bool FillBucket::needsClipping() const {
- return true;
-}
-
-void FillBucket::drawElements(FillShader& shader,
- gl::Context& context,
- PaintMode paintMode) {
- GLbyte* vertex_index = BUFFER_OFFSET(0);
- GLbyte* elements_index = BUFFER_OFFSET(0);
- for (auto& group : triangleGroups) {
- group.getVAO(shader, paintMode).bind(
- shader, *vertexBuffer, *triangleIndexBuffer, vertex_index, context);
- MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(group.indexLength * 3), GL_UNSIGNED_SHORT,
- elements_index));
- vertex_index += group.vertexLength * vertexBuffer->vertexSize;
- elements_index += group.indexLength * triangleIndexBuffer->primitiveSize;
- }
-}
-
-void FillBucket::drawElements(FillPatternShader& shader,
- gl::Context& context,
- PaintMode paintMode) {
- GLbyte* vertex_index = BUFFER_OFFSET(0);
- GLbyte* elements_index = BUFFER_OFFSET(0);
- for (auto& group : triangleGroups) {
- group.getVAO(shader, paintMode).bind(
- shader, *vertexBuffer, *triangleIndexBuffer, vertex_index, context);
- MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(group.indexLength * 3), GL_UNSIGNED_SHORT,
- elements_index));
- vertex_index += group.vertexLength * vertexBuffer->vertexSize;
- elements_index += group.indexLength * triangleIndexBuffer->primitiveSize;
- }
-}
-
-void FillBucket::drawVertices(FillOutlineShader& shader,
- gl::Context& context,
- PaintMode paintMode) {
- GLbyte* vertex_index = BUFFER_OFFSET(0);
- GLbyte* elements_index = BUFFER_OFFSET(0);
- for (auto& group : lineGroups) {
- group.getVAO(shader, paintMode).bind(
- shader, *vertexBuffer, *lineIndexBuffer, vertex_index, context);
- MBGL_CHECK_ERROR(glDrawElements(GL_LINES, static_cast<GLsizei>(group.indexLength * 2), GL_UNSIGNED_SHORT,
- elements_index));
- vertex_index += group.vertexLength * vertexBuffer->vertexSize;
- elements_index += group.indexLength * lineIndexBuffer->primitiveSize;
- }
-}
-
-void FillBucket::drawVertices(FillOutlinePatternShader& shader,
- gl::Context& context,
- PaintMode paintMode) {
- GLbyte* vertex_index = BUFFER_OFFSET(0);
- GLbyte* elements_index = BUFFER_OFFSET(0);
- for (auto& group : lineGroups) {
- group.getVAO(shader, paintMode).bind(
- shader, *vertexBuffer, *lineIndexBuffer, vertex_index, context);
- MBGL_CHECK_ERROR(glDrawElements(GL_LINES, static_cast<GLsizei>(group.indexLength * 2), GL_UNSIGNED_SHORT,
- elements_index));
- vertex_index += group.vertexLength * vertexBuffer->vertexSize;
- elements_index += group.indexLength * lineIndexBuffer->primitiveSize;
- }
+ return !triangleSegments.empty() || !lineSegments.empty();
}
} // namespace mbgl
diff --git a/src/mbgl/renderer/fill_bucket.hpp b/src/mbgl/renderer/fill_bucket.hpp
index 34cd886687..edb1521c1d 100644
--- a/src/mbgl/renderer/fill_bucket.hpp
+++ b/src/mbgl/renderer/fill_bucket.hpp
@@ -1,50 +1,33 @@
#pragma once
#include <mbgl/renderer/bucket.hpp>
-#include <mbgl/renderer/element_group.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/gl/vertex_buffer.hpp>
#include <mbgl/gl/index_buffer.hpp>
-#include <mbgl/shader/fill_vertex.hpp>
+#include <mbgl/gl/segment.hpp>
+#include <mbgl/programs/fill_program.hpp>
#include <vector>
-#include <memory>
namespace mbgl {
-class FillShader;
-class FillPatternShader;
-class FillOutlineShader;
-class FillOutlinePatternShader;
-
class FillBucket : public Bucket {
public:
- FillBucket();
- ~FillBucket() override;
-
void upload(gl::Context&) override;
void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override;
bool hasData() const override;
- bool needsClipping() const override;
void addGeometry(const GeometryCollection&);
- void drawElements(FillShader&, gl::Context&, PaintMode);
- void drawElements(FillPatternShader&, gl::Context&, PaintMode);
- void drawVertices(FillOutlineShader&, gl::Context&, PaintMode);
- void drawVertices(FillOutlinePatternShader&, gl::Context&, PaintMode);
-
-private:
- std::vector<FillVertex> vertices;
- std::vector<gl::Line> lines;
- std::vector<gl::Triangle> triangles;
-
- std::vector<ElementGroup<FillOutlineShader, FillOutlinePatternShader>> lineGroups;
- std::vector<ElementGroup<FillShader, FillPatternShader>> triangleGroups;
+ gl::VertexVector<FillVertex> vertices;
+ gl::IndexVector<gl::Lines> lines;
+ gl::IndexVector<gl::Triangles> triangles;
+ gl::SegmentVector<FillAttributes> lineSegments;
+ gl::SegmentVector<FillAttributes> triangleSegments;
optional<gl::VertexBuffer<FillVertex>> vertexBuffer;
- optional<gl::IndexBuffer<gl::Line>> lineIndexBuffer;
- optional<gl::IndexBuffer<gl::Triangle>> triangleIndexBuffer;
+ optional<gl::IndexBuffer<gl::Lines>> lineIndexBuffer;
+ optional<gl::IndexBuffer<gl::Triangles>> triangleIndexBuffer;
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/frame_history.cpp b/src/mbgl/renderer/frame_history.cpp
index daf24c8c37..1ee53d87b2 100644
--- a/src/mbgl/renderer/frame_history.cpp
+++ b/src/mbgl/renderer/frame_history.cpp
@@ -1,13 +1,14 @@
#include <mbgl/renderer/frame_history.hpp>
#include <mbgl/math/minmax.hpp>
#include <mbgl/gl/context.hpp>
-#include <mbgl/gl/gl.hpp>
+
+#include <cassert>
namespace mbgl {
FrameHistory::FrameHistory() {
changeOpacities.fill(0);
- opacities.fill(0);
+ std::fill(opacities.data.get(), opacities.data.get() + opacities.bytes(), 0);
}
void FrameHistory::record(const TimePoint& now, float zoom, const Duration& duration) {
@@ -18,7 +19,7 @@ void FrameHistory::record(const TimePoint& now, float zoom, const Duration& dura
changeTimes.fill(now);
for (int16_t z = 0; z <= zoomIndex; z++) {
- opacities[z] = 255u;
+ opacities.data[z] = 255u;
}
firstFrame = false;
}
@@ -26,12 +27,12 @@ void FrameHistory::record(const TimePoint& now, float zoom, const Duration& dura
if (zoomIndex < previousZoomIndex) {
for (int16_t z = zoomIndex + 1; z <= previousZoomIndex; z++) {
changeTimes[z] = now;
- changeOpacities[z] = opacities[z];
+ changeOpacities[z] = opacities.data[z];
}
} else {
for (int16_t z = zoomIndex; z > previousZoomIndex; z--) {
changeTimes[z] = now;
- changeOpacities[z] = opacities[z];
+ changeOpacities[z] = opacities.data[z];
}
}
@@ -39,13 +40,13 @@ void FrameHistory::record(const TimePoint& now, float zoom, const Duration& dura
std::chrono::duration<float> timeDiff = now - changeTimes[z];
int32_t opacityChange = (duration == Milliseconds(0) ? 1 : (timeDiff / duration)) * 255;
if (z <= zoomIndex) {
- opacities[z] = util::min(255, changeOpacities[z] + opacityChange);
+ opacities.data[z] = util::min(255, changeOpacities[z] + opacityChange);
} else {
- opacities[z] = util::max(0, changeOpacities[z] - opacityChange);
+ opacities.data[z] = util::max(0, changeOpacities[z] - opacityChange);
}
}
- changed = true;
+ dirty = true;
if (zoomIndex != previousZoomIndex) {
previousZoomIndex = zoomIndex;
@@ -60,58 +61,17 @@ bool FrameHistory::needsAnimation(const Duration& duration) const {
}
void FrameHistory::upload(gl::Context& context, uint32_t unit) {
-
- if (changed) {
- const bool first = !texture;
- bind(context, unit);
-
- if (first) {
- MBGL_CHECK_ERROR(glTexImage2D(
- GL_TEXTURE_2D, // GLenum target
- 0, // GLint level
- GL_ALPHA, // GLint internalformat
- width, // GLsizei width
- height, // GLsizei height
- 0, // GLint border
- GL_ALPHA, // GLenum format
- GL_UNSIGNED_BYTE, // GLenum type
- opacities.data()
- ));
- } else {
- MBGL_CHECK_ERROR(glTexSubImage2D(
- GL_TEXTURE_2D, // GLenum target
- 0, // GLint level
- 0, // GLint xoffset
- 0, // GLint yoffset
- width, // GLsizei width
- height, // GLsizei height
- GL_ALPHA, // GLenum format
- GL_UNSIGNED_BYTE, // GLenum type
- opacities.data()
- ));
- }
-
- changed = false;
-
+ if (!texture) {
+ texture = context.createTexture(opacities, unit);
+ } else if (dirty) {
+ context.updateTexture(*texture, opacities, unit);
}
+ dirty = false;
}
void FrameHistory::bind(gl::Context& context, uint32_t unit) {
- if (!texture) {
- texture = context.createTexture();
- context.activeTexture = unit;
- context.texture[unit] = *texture;
-#if not MBGL_USE_GLES2
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
-#endif
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
- } else if (context.texture[unit] != *texture) {
- context.activeTexture = unit;
- context.texture[unit] = *texture;
- }
+ upload(context, unit);
+ context.bindTexture(*texture, unit);
}
} // namespace mbgl
diff --git a/src/mbgl/renderer/frame_history.hpp b/src/mbgl/renderer/frame_history.hpp
index 063930af26..fffbd113ed 100644
--- a/src/mbgl/renderer/frame_history.hpp
+++ b/src/mbgl/renderer/frame_history.hpp
@@ -2,9 +2,10 @@
#include <array>
-#include <mbgl/platform/platform.hpp>
-#include <mbgl/gl/object.hpp>
+#include <mbgl/util/platform.hpp>
+#include <mbgl/gl/texture.hpp>
#include <mbgl/util/chrono.hpp>
+#include <mbgl/util/image.hpp>
#include <mbgl/util/optional.hpp>
namespace mbgl {
@@ -23,20 +24,17 @@ public:
void upload(gl::Context&, uint32_t);
private:
- const int width = 256;
- const int height = 1;
-
std::array<TimePoint, 256> changeTimes;
std::array<uint8_t, 256> changeOpacities;
- std::array<uint8_t, 256> opacities;
+ const AlphaImage opacities{ { 256, 1 } };
int16_t previousZoomIndex = 0;
- TimePoint previousTime = TimePoint::min();
- TimePoint time = TimePoint::min();
+ TimePoint previousTime;
+ TimePoint time;
bool firstFrame = true;
- bool changed = true;
+ bool dirty = true;
- mbgl::optional<gl::UniqueTexture> texture;
+ mbgl::optional<gl::Texture> texture;
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/line_bucket.cpp b/src/mbgl/renderer/line_bucket.cpp
index 7a5309bafc..007060bd1b 100644
--- a/src/mbgl/renderer/line_bucket.cpp
+++ b/src/mbgl/renderer/line_bucket.cpp
@@ -1,12 +1,8 @@
#include <mbgl/renderer/line_bucket.hpp>
#include <mbgl/style/layers/line_layer.hpp>
#include <mbgl/renderer/painter.hpp>
-#include <mbgl/shader/line_shader.hpp>
-#include <mbgl/shader/line_sdf_shader.hpp>
-#include <mbgl/shader/line_pattern_shader.hpp>
#include <mbgl/util/math.hpp>
#include <mbgl/util/constants.hpp>
-#include <mbgl/gl/gl.hpp>
#include <cassert>
@@ -54,8 +50,8 @@ const float LINE_DISTANCE_SCALE = 1.0 / 2.0;
const float MAX_LINE_DISTANCE = std::pow(2, LINE_DISTANCE_BUFFER_BITS) / LINE_DISTANCE_SCALE;
void LineBucket::addGeometry(const GeometryCoordinates& coordinates) {
- const GLsizei len = [&coordinates] {
- GLsizei l = static_cast<GLsizei>(coordinates.size());
+ const std::size_t len = [&coordinates] {
+ std::size_t l = coordinates.size();
// If the line has duplicate vertices at the end, adjust length to remove them.
while (l > 2 && coordinates[l - 1] == coordinates[l - 2]) {
l--;
@@ -68,7 +64,7 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates) {
return;
}
- const float miterLimit = layout.lineJoin == LineJoinType::Bevel ? 1.05f : float(layout.lineMiterLimit);
+ const float miterLimit = layout.get<LineJoin>() == LineJoinType::Bevel ? 1.05f : float(layout.get<LineMiterLimit>());
const double sharpCornerOffset = SHARP_CORNER_OFFSET * (float(util::EXTENT) / (util::tileSize * overscaling));
@@ -81,8 +77,8 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates) {
return;
}
- const LineCapType beginCap = layout.lineCap;
- const LineCapType endCap = closed ? LineCapType::Butt : LineCapType(layout.lineCap);
+ const LineCapType beginCap = layout.get<LineCap>();
+ const LineCapType endCap = closed ? LineCapType::Butt : LineCapType(layout.get<LineCap>());
double distance = 0;
bool startOfLine = true;
@@ -100,10 +96,10 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates) {
nextNormal = util::perp(util::unit(convertPoint<double>(firstCoordinate - *currentCoordinate)));
}
- const std::size_t startVertex = vertices.size();
+ const std::size_t startVertex = vertices.vertexSize();
std::vector<TriangleElement> triangleStore;
- for (GLsizei i = 0; i < len; ++i) {
+ for (std::size_t i = 0; i < len; ++i) {
if (closed && i == len - 1) {
// if the line is closed, we treat the last vertex like the first
nextCoordinate = coordinates[1];
@@ -175,12 +171,12 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates) {
// The join if a middle vertex, otherwise the cap
const bool middleVertex = prevCoordinate && nextCoordinate;
- LineJoinType currentJoin = layout.lineJoin;
+ LineJoinType currentJoin = layout.get<LineJoin>();
const LineCapType currentCap = nextCoordinate ? beginCap : endCap;
if (middleVertex) {
if (currentJoin == LineJoinType::Round) {
- if (miterLength < layout.lineRoundLimit) {
+ if (miterLength < layout.get<LineRoundLimit>()) {
currentJoin = LineJoinType::Miter;
} else if (miterLength <= 2) {
currentJoin = LineJoinType::FakeRound;
@@ -349,25 +345,23 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates) {
startOfLine = false;
}
- const std::size_t endVertex = vertices.size();
+ const std::size_t endVertex = vertices.vertexSize();
const std::size_t vertexCount = endVertex - startVertex;
- if (groups.empty() || groups.back().vertexLength + vertexCount > 65535) {
- // Move to a new group because the old one can't hold the geometry.
- groups.emplace_back();
+ if (segments.empty() || segments.back().vertexLength + vertexCount > std::numeric_limits<uint16_t>::max()) {
+ segments.emplace_back(startVertex, triangles.indexSize());
}
- auto& group = groups.back();
- uint16_t index = group.vertexLength;
+ auto& segment = segments.back();
+ assert(segment.vertexLength <= std::numeric_limits<uint16_t>::max());
+ uint16_t index = segment.vertexLength;
for (const auto& triangle : triangleStore) {
- triangles.emplace_back(static_cast<uint16_t>(index + triangle.a),
- static_cast<uint16_t>(index + triangle.b),
- static_cast<uint16_t>(index + triangle.c));
+ triangles.emplace_back(index + triangle.a, index + triangle.b, index + triangle.c);
}
- group.vertexLength += vertexCount;
- group.indexLength += triangleStore.size();
+ segment.vertexLength += vertexCount;
+ segment.indexLength += triangleStore.size() * 3;
}
void LineBucket::addCurrentVertex(const GeometryCoordinate& currentCoordinate,
@@ -378,13 +372,11 @@ void LineBucket::addCurrentVertex(const GeometryCoordinate& currentCoordinate,
bool round,
std::size_t startVertex,
std::vector<TriangleElement>& triangleStore) {
- int8_t tx = round ? 1 : 0;
-
Point<double> extrude = normal;
if (endLeft)
extrude = extrude - (util::perp(normal) * endLeft);
- vertices.emplace_back(currentCoordinate.x, currentCoordinate.y, extrude.x, extrude.y, tx, 0, endLeft, distance * LINE_DISTANCE_SCALE);
- e3 = vertices.size() - 1 - startVertex;
+ vertices.emplace_back(LineAttributes::vertex(currentCoordinate, extrude, { round, false }, endLeft, distance * LINE_DISTANCE_SCALE));
+ e3 = vertices.vertexSize() - 1 - startVertex;
if (e1 >= 0 && e2 >= 0) {
triangleStore.emplace_back(e1, e2, e3);
}
@@ -394,8 +386,8 @@ void LineBucket::addCurrentVertex(const GeometryCoordinate& currentCoordinate,
extrude = normal * -1.0;
if (endRight)
extrude = extrude - (util::perp(normal) * endRight);
- vertices.emplace_back(currentCoordinate.x, currentCoordinate.y, extrude.x, extrude.y, tx, 1, -endRight, distance * LINE_DISTANCE_SCALE);
- e3 = vertices.size() - 1 - startVertex;
+ vertices.emplace_back(LineAttributes::vertex(currentCoordinate, extrude, { round, true }, -endRight, distance * LINE_DISTANCE_SCALE));
+ e3 = vertices.vertexSize() - 1 - startVertex;
if (e1 >= 0 && e2 >= 0) {
triangleStore.emplace_back(e1, e2, e3);
}
@@ -418,11 +410,9 @@ void LineBucket::addPieSliceVertex(const GeometryCoordinate& currentVertex,
bool lineTurnsLeft,
std::size_t startVertex,
std::vector<TriangleElement>& triangleStore) {
- int8_t ty = lineTurnsLeft;
-
Point<double> flippedExtrude = extrude * (lineTurnsLeft ? -1.0 : 1.0);
- vertices.emplace_back(currentVertex.x, currentVertex.y, flippedExtrude.x, flippedExtrude.y, 0, ty, 0, distance * LINE_DISTANCE_SCALE);
- e3 = vertices.size() - 1 - startVertex;
+ vertices.emplace_back(LineAttributes::vertex(currentVertex, flippedExtrude, { false, lineTurnsLeft }, 0, distance * LINE_DISTANCE_SCALE));
+ e3 = vertices.vertexSize() - 1 - startVertex;
if (e1 >= 0 && e2 >= 0) {
triangleStore.emplace_back(e1, e2, e3);
}
@@ -450,65 +440,7 @@ void LineBucket::render(Painter& painter,
}
bool LineBucket::hasData() const {
- return !groups.empty();
-}
-
-bool LineBucket::needsClipping() const {
- return true;
-}
-
-void LineBucket::drawLines(LineShader& shader,
- gl::Context& context,
- PaintMode paintMode) {
- GLbyte* vertex_index = BUFFER_OFFSET(0);
- GLbyte* elements_index = BUFFER_OFFSET(0);
- for (auto& group : groups) {
- if (!group.indexLength) {
- continue;
- }
- group.getVAO(shader, paintMode).bind(
- shader, *vertexBuffer, *indexBuffer, vertex_index, context);
- MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(group.indexLength * 3), GL_UNSIGNED_SHORT,
- elements_index));
- vertex_index += group.vertexLength * vertexBuffer->vertexSize;
- elements_index += group.indexLength * indexBuffer->primitiveSize;
- }
-}
-
-void LineBucket::drawLineSDF(LineSDFShader& shader,
- gl::Context& context,
- PaintMode paintMode) {
- GLbyte* vertex_index = BUFFER_OFFSET(0);
- GLbyte* elements_index = BUFFER_OFFSET(0);
- for (auto& group : groups) {
- if (!group.indexLength) {
- continue;
- }
- group.getVAO(shader, paintMode).bind(
- shader, *vertexBuffer, *indexBuffer, vertex_index, context);
- MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(group.indexLength * 3), GL_UNSIGNED_SHORT,
- elements_index));
- vertex_index += group.vertexLength * vertexBuffer->vertexSize;
- elements_index += group.indexLength * indexBuffer->primitiveSize;
- }
-}
-
-void LineBucket::drawLinePatterns(LinePatternShader& shader,
- gl::Context& context,
- PaintMode paintMode) {
- GLbyte* vertex_index = BUFFER_OFFSET(0);
- GLbyte* elements_index = BUFFER_OFFSET(0);
- for (auto& group : groups) {
- if (!group.indexLength) {
- continue;
- }
- group.getVAO(shader, paintMode).bind(
- shader, *vertexBuffer, *indexBuffer, vertex_index, context);
- MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(group.indexLength * 3), GL_UNSIGNED_SHORT,
- elements_index));
- vertex_index += group.vertexLength * vertexBuffer->vertexSize;
- elements_index += group.indexLength * indexBuffer->primitiveSize;
- }
+ return !segments.empty();
}
} // namespace mbgl
diff --git a/src/mbgl/renderer/line_bucket.hpp b/src/mbgl/renderer/line_bucket.hpp
index 14af710877..d11d78ff69 100644
--- a/src/mbgl/renderer/line_bucket.hpp
+++ b/src/mbgl/renderer/line_bucket.hpp
@@ -1,23 +1,18 @@
#pragma once
#include <mbgl/renderer/bucket.hpp>
-#include <mbgl/renderer/element_group.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/gl/vertex_buffer.hpp>
#include <mbgl/gl/index_buffer.hpp>
-#include <mbgl/shader/line_vertex.hpp>
+#include <mbgl/gl/segment.hpp>
+#include <mbgl/programs/line_program.hpp>
#include <mbgl/style/layers/line_layer_properties.hpp>
#include <vector>
namespace mbgl {
-class LineShader;
-class LineSDFShader;
-class LinePatternShader;
-
class LineBucket : public Bucket {
-
public:
LineBucket(uint32_t overscaling);
~LineBucket() override;
@@ -25,14 +20,18 @@ public:
void upload(gl::Context&) override;
void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override;
bool hasData() const override;
- bool needsClipping() const override;
void addGeometry(const GeometryCollection&);
void addGeometry(const GeometryCoordinates& line);
- void drawLines(LineShader&, gl::Context&, PaintMode);
- void drawLineSDF(LineSDFShader&, gl::Context&, PaintMode);
- void drawLinePatterns(LinePatternShader&, gl::Context&, PaintMode);
+ style::LineLayoutProperties::Evaluated layout;
+
+ gl::VertexVector<LineVertex> vertices;
+ gl::IndexVector<gl::Triangles> triangles;
+ gl::SegmentVector<LineAttributes> segments;
+
+ optional<gl::VertexBuffer<LineVertex>> vertexBuffer;
+ optional<gl::IndexBuffer<gl::Triangles>> indexBuffer;
private:
struct TriangleElement {
@@ -46,18 +45,6 @@ private:
const Point<double>& extrude, bool lineTurnsLeft, std::size_t startVertex,
std::vector<TriangleElement>& triangleStore);
-public:
- style::LineLayoutProperties layout;
-
-private:
- std::vector<LineVertex> vertices;
- std::vector<gl::Triangle> triangles;
-
- std::vector<ElementGroup<LineShader, LineSDFShader, LinePatternShader>> groups;
-
- optional<gl::VertexBuffer<LineVertex>> vertexBuffer;
- optional<gl::IndexBuffer<gl::Triangle>> indexBuffer;
-
std::ptrdiff_t e1;
std::ptrdiff_t e2;
std::ptrdiff_t e3;
diff --git a/src/mbgl/renderer/paint_parameters.hpp b/src/mbgl/renderer/paint_parameters.hpp
index bd67dc9cfd..213c01cfbd 100644
--- a/src/mbgl/renderer/paint_parameters.hpp
+++ b/src/mbgl/renderer/paint_parameters.hpp
@@ -2,12 +2,12 @@
namespace mbgl {
-class Shaders;
+class Programs;
class View;
class PaintParameters {
public:
- Shaders& shaders;
+ Programs& programs;
View& view;
};
diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp
index fc61d6e0a0..5894912ef3 100644
--- a/src/mbgl/renderer/painter.cpp
+++ b/src/mbgl/renderer/painter.cpp
@@ -7,8 +7,7 @@
#include <mbgl/map/view.hpp>
-#include <mbgl/platform/log.hpp>
-#include <mbgl/gl/gl.hpp>
+#include <mbgl/util/logging.hpp>
#include <mbgl/gl/debugging.hpp>
#include <mbgl/style/style.hpp>
@@ -22,7 +21,8 @@
#include <mbgl/geometry/line_atlas.hpp>
#include <mbgl/text/glyph_atlas.hpp>
-#include <mbgl/shader/shaders.hpp>
+#include <mbgl/programs/program_parameters.hpp>
+#include <mbgl/programs/programs.hpp>
#include <mbgl/algorithm/generate_clip_ids.hpp>
#include <mbgl/algorithm/generate_clip_ids_impl.hpp>
@@ -42,37 +42,63 @@ namespace mbgl {
using namespace style;
-Painter::Painter(gl::Context& context_, const TransformState& state_)
+static gl::VertexVector<FillVertex> tileVertices() {
+ gl::VertexVector<FillVertex> result;
+ result.emplace_back(FillAttributes::vertex({ 0, 0 }));
+ result.emplace_back(FillAttributes::vertex({ util::EXTENT, 0 }));
+ result.emplace_back(FillAttributes::vertex({ 0, util::EXTENT }));
+ result.emplace_back(FillAttributes::vertex({ util::EXTENT, util::EXTENT }));
+ return result;
+}
+
+static gl::IndexVector<gl::Triangles> tileTriangleIndices() {
+ gl::IndexVector<gl::Triangles> result;
+ result.emplace_back(0, 1, 2);
+ result.emplace_back(1, 2, 3);
+ return result;
+}
+
+static gl::IndexVector<gl::LineStrip> tileLineStripIndices() {
+ gl::IndexVector<gl::LineStrip> result;
+ result.emplace_back(0);
+ result.emplace_back(1);
+ result.emplace_back(3);
+ result.emplace_back(2);
+ result.emplace_back(0);
+ return result;
+}
+
+static gl::VertexVector<RasterVertex> rasterVertices() {
+ gl::VertexVector<RasterVertex> result;
+ result.emplace_back(RasterProgram::vertex({ 0, 0 }, { 0, 0 }));
+ result.emplace_back(RasterProgram::vertex({ util::EXTENT, 0 }, { 32767, 0 }));
+ result.emplace_back(RasterProgram::vertex({ 0, util::EXTENT }, { 0, 32767 }));
+ result.emplace_back(RasterProgram::vertex({ util::EXTENT, util::EXTENT }, { 32767, 32767 }));
+ return result;
+}
+
+Painter::Painter(gl::Context& context_, const TransformState& state_, float pixelRatio)
: context(context_),
state(state_),
- tileTriangleVertexBuffer(context.createVertexBuffer(std::vector<FillVertex> {{
- { 0, 0 },
- { util::EXTENT, 0 },
- { 0, util::EXTENT },
- { util::EXTENT, 0 },
- { 0, util::EXTENT },
- { util::EXTENT, util::EXTENT }
- }})),
- tileLineStripVertexBuffer(context.createVertexBuffer(std::vector<FillVertex> {{
- { 0, 0 },
- { util::EXTENT, 0 },
- { util::EXTENT, util::EXTENT },
- { 0, util::EXTENT },
- { 0, 0 }
- }})),
- rasterVertexBuffer(context.createVertexBuffer(std::vector<RasterVertex> {{
- { 0, 0, 0, 0 },
- { util::EXTENT, 0, 32767, 0 },
- { 0, util::EXTENT, 0, 32767 },
- { util::EXTENT, util::EXTENT, 32767, 32767 }
- }})) {
+ tileVertexBuffer(context.createVertexBuffer(tileVertices())),
+ rasterVertexBuffer(context.createVertexBuffer(rasterVertices())),
+ tileTriangleIndexBuffer(context.createIndexBuffer(tileTriangleIndices())),
+ tileBorderIndexBuffer(context.createIndexBuffer(tileLineStripIndices())) {
+
+ tileTriangleSegments.emplace_back(0, 0, 4, 6);
+ tileBorderSegments.emplace_back(0, 0, 4, 5);
+ rasterSegments.emplace_back(0, 0, 4, 6);
+
#ifndef NDEBUG
gl::debugging::enable();
#endif
- shaders = std::make_unique<Shaders>(context);
+ ProgramParameters programParameters{ pixelRatio, false };
+ programs = std::make_unique<Programs>(context, programParameters);
#ifndef NDEBUG
- overdrawShaders = std::make_unique<Shaders>(context, gl::Shader::Overdraw);
+
+ ProgramParameters programParametersOverdraw{ pixelRatio, true };
+ overdrawPrograms = std::make_unique<Programs>(context, programParametersOverdraw);
#endif
}
@@ -82,12 +108,6 @@ bool Painter::needsAnimation() const {
return frameHistory.needsAnimation(util::DEFAULT_FADE_DURATION);
}
-void Painter::setClipping(const ClipID& clip) {
- const GLint ref = (GLint)clip.reference.to_ulong();
- const GLuint mask = (GLuint)clip.mask.to_ulong();
- context.stencilFunc = { gl::StencilTestFunction::Equal, ref, mask };
-}
-
void Painter::cleanup() {
context.performCleanup();
}
@@ -100,9 +120,9 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp
PaintParameters parameters {
#ifndef NDEBUG
- paintMode() == PaintMode::Overdraw ? *overdrawShaders : *shaders,
+ paintMode() == PaintMode::Overdraw ? *overdrawPrograms : *programs,
#else
- *shaders,
+ *programs,
#endif
view
};
@@ -111,15 +131,14 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp
spriteAtlas = style.spriteAtlas.get();
lineAtlas = style.lineAtlas.get();
- RenderData renderData = style.getRenderData(frame.debugOptions);
+ RenderData renderData = style.getRenderData(frame.debugOptions, state.getAngle());
const std::vector<RenderItem>& order = renderData.order;
const std::unordered_set<Source*>& sources = renderData.sources;
- const Color& background = renderData.backgroundColor;
// Update the default matrices to the current viewport dimensions.
state.getProjMatrix(projMatrix);
- pixelsToGLUnits = {{ 2.0f / state.getWidth(), -2.0f / state.getHeight() }};
+ pixelsToGLUnits = {{ 2.0f / state.getSize().width, -2.0f / state.getSize().height }};
if (state.getViewportMode() == ViewportMode::FlippedY) {
pixelsToGLUnits[1] *= -1;
}
@@ -153,26 +172,11 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp
{
MBGL_DEBUG_GROUP("clear");
view.bind();
- context.stencilFunc = { gl::StencilTestFunction::Always, 0, ~0u };
- context.stencilTest = true;
- context.stencilMask = 0xFF;
- context.depthTest = false;
- context.depthMask = true;
- context.colorMask = { true, true, true, true };
-
- if (paintMode() == PaintMode::Overdraw) {
- context.blend = true;
- context.blendFunc = { gl::BlendSourceFactor::ConstantColor,
- gl::BlendDestinationFactor::One };
- const float overdraw = 1.0f / 8.0f;
- context.blendColor = { overdraw, overdraw, overdraw, 0.0f };
- context.clearColor = Color::black();
- } else {
- context.clearColor = background;
- }
- context.clearStencil = 0;
- context.clearDepth = 1;
- MBGL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
+ context.clear(paintMode() == PaintMode::Overdraw
+ ? Color::black()
+ : renderData.backgroundColor,
+ 1.0f,
+ 0);
}
// - CLIPPING MASKS ----------------------------------------------------------------------------
@@ -186,7 +190,12 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp
source->baseImpl->startRender(generator, projMatrix, state);
}
- drawClippingMasks(parameters, generator.getStencils());
+ MBGL_DEBUG_GROUP("clipping masks");
+
+ for (const auto& stencil : generator.getStencils()) {
+ MBGL_DEBUG_GROUP(std::string{ "mask: " } + util::toString(stencil.first));
+ renderClippingMask(stencil.first, stencil.second);
+ }
}
#if not MBGL_USE_GLES2 and not defined(NDEBUG)
@@ -214,7 +223,7 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp
renderPass(parameters,
RenderPass::Translucent,
order.begin(), order.end(),
- static_cast<GLsizei>(order.size()) - 1, -1);
+ static_cast<uint32_t>(order.size()) - 1, -1);
if (debug::renderTree) { Log::Info(Event::Render, "}"); indent--; }
@@ -275,19 +284,6 @@ void Painter::renderPass(PaintParameters& parameters,
if (!layer.baseImpl->hasRenderPass(pass))
continue;
- if (paintMode() == PaintMode::Overdraw) {
- context.blend = true;
- } else if (pass == RenderPass::Translucent) {
- context.blend = true;
- context.blendFunc = { gl::BlendSourceFactor::One,
- gl::BlendDestinationFactor::OneMinusSrcAlpha };
- } else {
- context.blend = false;
- }
-
- context.colorMask = { true, true, true, true };
- context.stencilMask = 0x0;
-
if (layer.is<BackgroundLayer>()) {
MBGL_DEBUG_GROUP("background");
renderBackground(parameters, *layer.as<BackgroundLayer>());
@@ -296,11 +292,9 @@ void Painter::renderPass(PaintParameters& parameters,
// Reset GL state to a known state so the CustomLayer always has a clean slate.
context.vertexArrayObject = 0;
- context.depthFunc = gl::DepthTestFunction::LessEqual;
- context.depthTest = true;
- context.depthMask = false;
- context.stencilTest = false;
- setDepthSublayer(0);
+ context.setDepthMode(depthModeForSublayer(0, gl::DepthMode::ReadOnly));
+ context.setStencilMode(gl::StencilMode::disabled());
+ context.setColorMode(colorModeForRenderPass());
layer.as<CustomLayer>()->impl->render(state);
@@ -310,9 +304,6 @@ void Painter::renderPass(PaintParameters& parameters,
context.setDirtyState();
} else {
MBGL_DEBUG_GROUP(layer.baseImpl->id + " - " + util::toString(item.tile->id));
- if (item.bucket->needsClipping()) {
- setClipping(item.tile->clip);
- }
item.bucket->render(*this, parameters, layer, *item.tile);
}
}
@@ -322,10 +313,46 @@ void Painter::renderPass(PaintParameters& parameters,
}
}
-void Painter::setDepthSublayer(int n) {
+mat4 Painter::matrixForTile(const UnwrappedTileID& tileID) {
+ mat4 matrix;
+ state.matrixFor(matrix, tileID);
+ matrix::multiply(matrix, projMatrix, matrix);
+ return matrix;
+}
+
+gl::DepthMode Painter::depthModeForSublayer(uint8_t n, gl::DepthMode::Mask mask) const {
float nearDepth = ((1 + currentLayer) * numSublayers + n) * depthEpsilon;
float farDepth = nearDepth + depthRangeSize;
- context.depthRange = { nearDepth, farDepth };
+ return gl::DepthMode { gl::DepthMode::LessEqual, mask, { nearDepth, farDepth } };
+}
+
+gl::StencilMode Painter::stencilModeForClipping(const ClipID& id) const {
+ return gl::StencilMode {
+ gl::StencilMode::Equal { static_cast<uint32_t>(id.mask.to_ulong()) },
+ static_cast<int32_t>(id.reference.to_ulong()),
+ 0,
+ gl::StencilMode::Keep,
+ gl::StencilMode::Keep,
+ gl::StencilMode::Replace
+ };
+}
+
+gl::ColorMode Painter::colorModeForRenderPass() const {
+ if (paintMode() == PaintMode::Overdraw) {
+ const float overdraw = 1.0f / 8.0f;
+ return gl::ColorMode {
+ gl::ColorMode::Add {
+ gl::ColorMode::ConstantColor,
+ gl::ColorMode::One
+ },
+ Color { overdraw, overdraw, overdraw, 0.0f },
+ gl::ColorMode::Mask { true, true, true, true }
+ };
+ } else if (pass == RenderPass::Translucent) {
+ return gl::ColorMode::alphaBlended();
+ } else {
+ return gl::ColorMode::unblended();
+ }
}
} // namespace mbgl
diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp
index f339ed1aed..dec7fa57fd 100644
--- a/src/mbgl/renderer/painter.hpp
+++ b/src/mbgl/renderer/painter.hpp
@@ -8,10 +8,11 @@
#include <mbgl/renderer/render_item.hpp>
#include <mbgl/renderer/bucket.hpp>
-#include <mbgl/gl/vao.hpp>
#include <mbgl/gl/context.hpp>
-#include <mbgl/shader/fill_vertex.hpp>
-#include <mbgl/shader/raster_vertex.hpp>
+#include <mbgl/programs/debug_program.hpp>
+#include <mbgl/programs/program_parameters.hpp>
+#include <mbgl/programs/fill_program.hpp>
+#include <mbgl/programs/raster_program.hpp>
#include <mbgl/style/style.hpp>
@@ -41,8 +42,7 @@ class CircleBucket;
class SymbolBucket;
class RasterBucket;
-class Shaders;
-class SymbolSDFShader;
+class Programs;
class PaintParameters;
struct ClipID;
@@ -68,7 +68,7 @@ struct FrameData {
class Painter : private util::noncopyable {
public:
- Painter(gl::Context&, const TransformState&);
+ Painter(gl::Context&, const TransformState&, float pixelRatio);
~Painter();
void render(const style::Style&,
@@ -78,20 +78,8 @@ public:
void cleanup();
- // Renders debug information for a tile.
+ void renderClippingMask(const UnwrappedTileID&, const ClipID&);
void renderTileDebug(const RenderTile&);
-
- // Renders the red debug frame around a tile, visualizing its perimeter.
- void renderDebugFrame(const mat4 &matrix);
-
-#ifndef NDEBUG
- // Renders tile clip boundaries, using stencil buffer to calculate fill color.
- void renderClipMasks(PaintParameters&);
- // Renders the depth buffer.
- void renderDepthBuffer(PaintParameters&);
-#endif
-
- void renderDebugText(Tile&, const mat4&);
void renderFill(PaintParameters&, FillBucket&, const style::FillLayer&, const RenderTile&);
void renderLine(PaintParameters&, LineBucket&, const style::LineLayer&, const RenderTile&);
void renderCircle(PaintParameters&, CircleBucket&, const style::CircleLayer&, const RenderTile&);
@@ -99,11 +87,12 @@ public:
void renderRaster(PaintParameters&, RasterBucket&, const style::RasterLayer&, const RenderTile&);
void renderBackground(PaintParameters&, const style::BackgroundLayer&);
- float saturationFactor(float saturation);
- float contrastFactor(float contrast);
- std::array<float, 3> spinWeights(float spin_value);
-
- void drawClippingMasks(PaintParameters&, const std::map<UnwrappedTileID, ClipID>&);
+#ifndef NDEBUG
+ // Renders tile clip boundaries, using stencil buffer to calculate fill color.
+ void renderClipMasks(PaintParameters&);
+ // Renders the depth buffer.
+ void renderDepthBuffer(PaintParameters&);
+#endif
bool needsAnimation() const;
@@ -116,31 +105,10 @@ private:
Iterator it, Iterator end,
uint32_t i, int8_t increment);
- void setClipping(const ClipID&);
-
- void renderSDF(SymbolBucket&,
- const RenderTile&,
- float scaleDivisor,
- std::array<float, 2> texsize,
- SymbolSDFShader& sdfShader,
- void (SymbolBucket::*drawSDF)(SymbolSDFShader&, gl::Context&, PaintMode),
-
- // Layout
- style::AlignmentType rotationAlignment,
- style::AlignmentType pitchAlignment,
- float layoutSize,
-
- // Paint
- float opacity,
- Color color,
- Color haloColor,
- float haloWidth,
- float haloBlur,
- std::array<float, 2> translate,
- style::TranslateAnchorType translateAnchor,
- float paintSize);
-
- void setDepthSublayer(int n);
+ mat4 matrixForTile(const UnwrappedTileID&);
+ gl::DepthMode depthModeForSublayer(uint8_t n, gl::DepthMode::Mask) const;
+ gl::StencilMode stencilModeForClipping(const ClipID&) const;
+ gl::ColorMode colorModeForRenderPass() const;
#ifndef NDEBUG
PaintMode paintMode() const {
@@ -185,16 +153,20 @@ private:
FrameHistory frameHistory;
- std::unique_ptr<Shaders> shaders;
+ std::unique_ptr<Programs> programs;
#ifndef NDEBUG
- std::unique_ptr<Shaders> overdrawShaders;
+ std::unique_ptr<Programs> overdrawPrograms;
#endif
- gl::VertexBuffer<FillVertex> tileTriangleVertexBuffer;
- gl::VertexBuffer<FillVertex> tileLineStripVertexBuffer;
+ gl::VertexBuffer<FillVertex> tileVertexBuffer;
gl::VertexBuffer<RasterVertex> rasterVertexBuffer;
- gl::VertexArrayObject tileBorderArray;
+ gl::IndexBuffer<gl::Triangles> tileTriangleIndexBuffer;
+ gl::IndexBuffer<gl::LineStrip> tileBorderIndexBuffer;
+
+ gl::SegmentVector<FillAttributes> tileTriangleSegments;
+ gl::SegmentVector<DebugAttributes> tileBorderSegments;
+ gl::SegmentVector<RasterAttributes> rasterSegments;
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/painter_background.cpp b/src/mbgl/renderer/painter_background.cpp
index 61ec76d1d8..4a3e41701d 100644
--- a/src/mbgl/renderer/painter_background.cpp
+++ b/src/mbgl/renderer/painter_background.cpp
@@ -1,12 +1,10 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
-#include <mbgl/gl/gl.hpp>
-
#include <mbgl/style/layers/background_layer.hpp>
#include <mbgl/style/layers/background_layer_impl.hpp>
-#include <mbgl/shader/shaders.hpp>
+#include <mbgl/programs/programs.hpp>
+#include <mbgl/programs/fill_program.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
-#include <mbgl/util/mat4.hpp>
#include <mbgl/util/tile_cover.hpp>
namespace mbgl {
@@ -16,75 +14,61 @@ using namespace style;
void Painter::renderBackground(PaintParameters& parameters, const BackgroundLayer& layer) {
// Note that for bottommost layers without a pattern, the background color is drawn with
// glClear rather than this method.
- const BackgroundPaintProperties& properties = layer.impl->paint;
-
- bool isPatterned = !properties.backgroundPattern.value.to.empty();// && false;
- optional<SpriteAtlasPosition> imagePosA;
- optional<SpriteAtlasPosition> imagePosB;
-
- auto& patternShader = parameters.shaders.fillPattern;
- auto& plainShader = parameters.shaders.fill;
- auto& arrayBackgroundPattern = parameters.shaders.backgroundPatternArray;
- auto& arrayBackground = parameters.shaders.backgroundArray;
+ const BackgroundPaintProperties::Evaluated& properties = layer.impl->paint.evaluated;
- if (isPatterned) {
- imagePosA = spriteAtlas->getPosition(properties.backgroundPattern.value.from,
- SpritePatternMode::Repeating);
- imagePosB = spriteAtlas->getPosition(properties.backgroundPattern.value.to,
- SpritePatternMode::Repeating);
+ if (!properties.get<BackgroundPattern>().to.empty()) {
+ optional<SpriteAtlasPosition> imagePosA = spriteAtlas->getPosition(
+ properties.get<BackgroundPattern>().from, SpritePatternMode::Repeating);
+ optional<SpriteAtlasPosition> imagePosB = spriteAtlas->getPosition(
+ properties.get<BackgroundPattern>().to, SpritePatternMode::Repeating);
if (!imagePosA || !imagePosB)
return;
- context.program = patternShader.getID();
- patternShader.u_matrix = identityMatrix;
- patternShader.u_pattern_tl_a = imagePosA->tl;
- patternShader.u_pattern_br_a = imagePosA->br;
- patternShader.u_pattern_tl_b = imagePosB->tl;
- patternShader.u_pattern_br_b = imagePosB->br;
- patternShader.u_mix = properties.backgroundPattern.value.t;
- patternShader.u_opacity = properties.backgroundOpacity;
-
spriteAtlas->bind(true, context, 0);
- arrayBackgroundPattern.bind(patternShader, tileTriangleVertexBuffer, BUFFER_OFFSET(0), context);
+ for (const auto& tileID : util::tileCover(state, state.getIntegerZoom())) {
+ parameters.programs.fillPattern.draw(
+ context,
+ gl::Triangles(),
+ depthModeForSublayer(0, gl::DepthMode::ReadOnly),
+ gl::StencilMode::disabled(),
+ colorModeForRenderPass(),
+ FillPatternUniforms::values(
+ matrixForTile(tileID),
+ properties.get<BackgroundOpacity>(),
+ context.viewport.getCurrentValue().size,
+ *imagePosA,
+ *imagePosB,
+ properties.get<BackgroundPattern>(),
+ tileID,
+ state
+ ),
+ tileVertexBuffer,
+ tileTriangleIndexBuffer,
+ tileTriangleSegments
+ );
+ }
} else {
- context.program = plainShader.getID();
- plainShader.u_color = properties.backgroundColor;
- plainShader.u_opacity = properties.backgroundOpacity;
-
- arrayBackground.bind(plainShader, tileTriangleVertexBuffer, BUFFER_OFFSET(0), context);
- }
-
- context.stencilTest = false;
- context.depthFunc = gl::DepthTestFunction::LessEqual;
- context.depthTest = true;
- context.depthMask = false;
- setDepthSublayer(0);
-
- for (const auto& tileID : util::tileCover(state, state.getIntegerZoom())) {
- mat4 vertexMatrix;
- state.matrixFor(vertexMatrix, tileID);
- matrix::multiply(vertexMatrix, projMatrix, vertexMatrix);
-
- if (isPatterned) {
- patternShader.u_matrix = vertexMatrix;
- patternShader.u_pattern_size_a = imagePosA->size;
- patternShader.u_pattern_size_b = imagePosB->size;
- patternShader.u_scale_a = properties.backgroundPattern.value.fromScale;
- patternShader.u_scale_b = properties.backgroundPattern.value.toScale;
- patternShader.u_tile_units_to_pixels = 1.0f / tileID.pixelsToTileUnits(1.0f, state.getIntegerZoom());
-
- GLint tileSizeAtNearestZoom = util::tileSize * state.zoomScale(state.getIntegerZoom() - tileID.canonical.z);
- GLint pixelX = tileSizeAtNearestZoom * (tileID.canonical.x + tileID.wrap * state.zoomScale(tileID.canonical.z));
- GLint pixelY = tileSizeAtNearestZoom * tileID.canonical.y;
- patternShader.u_pixel_coord_upper = {{ float(pixelX >> 16), float(pixelY >> 16) }};
- patternShader.u_pixel_coord_lower = {{ float(pixelX & 0xFFFF), float(pixelY & 0xFFFF) }};
- } else {
- plainShader.u_matrix = vertexMatrix;
+ for (const auto& tileID : util::tileCover(state, state.getIntegerZoom())) {
+ parameters.programs.fill.draw(
+ context,
+ gl::Triangles(),
+ depthModeForSublayer(0, gl::DepthMode::ReadOnly),
+ gl::StencilMode::disabled(),
+ colorModeForRenderPass(),
+ FillProgram::UniformValues {
+ uniforms::u_matrix::Value{ matrixForTile(tileID) },
+ uniforms::u_opacity::Value{ properties.get<BackgroundOpacity>() },
+ uniforms::u_color::Value{ properties.get<BackgroundColor>() },
+ uniforms::u_outline_color::Value{ properties.get<BackgroundColor>() },
+ uniforms::u_world::Value{ context.viewport.getCurrentValue().size },
+ },
+ tileVertexBuffer,
+ tileTriangleIndexBuffer,
+ tileTriangleSegments
+ );
}
-
- MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, static_cast<GLsizei>(tileTriangleVertexBuffer.vertexCount)));
}
}
diff --git a/src/mbgl/renderer/painter_circle.cpp b/src/mbgl/renderer/painter_circle.cpp
index 462ed59ebf..9385b7b1a3 100644
--- a/src/mbgl/renderer/painter_circle.cpp
+++ b/src/mbgl/renderer/painter_circle.cpp
@@ -2,11 +2,11 @@
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/circle_bucket.hpp>
#include <mbgl/renderer/render_tile.hpp>
-
#include <mbgl/style/layers/circle_layer.hpp>
#include <mbgl/style/layers/circle_layer_impl.hpp>
-
-#include <mbgl/shader/shaders.hpp>
+#include <mbgl/programs/programs.hpp>
+#include <mbgl/programs/circle_program.hpp>
+#include <mbgl/gl/context.hpp>
namespace mbgl {
@@ -16,42 +16,46 @@ void Painter::renderCircle(PaintParameters& parameters,
CircleBucket& bucket,
const CircleLayer& layer,
const RenderTile& tile) {
- // Abort early.
- if (pass == RenderPass::Opaque) return;
-
- context.stencilTest = frame.mapMode == MapMode::Still;
- context.depthFunc = gl::DepthTestFunction::LessEqual;
- context.depthTest = true;
- context.depthMask = false;
- setDepthSublayer(0);
-
- const CirclePaintProperties& properties = layer.impl->paint;
- auto& circleShader = parameters.shaders.circle;
-
- context.program = circleShader.getID();
-
- circleShader.u_matrix = tile.translatedMatrix(properties.circleTranslate,
- properties.circleTranslateAnchor,
- state);
-
- if (properties.circlePitchScale == CirclePitchScaleType::Map) {
- circleShader.u_extrude_scale = {{
- pixelsToGLUnits[0] * state.getAltitude(),
- pixelsToGLUnits[1] * state.getAltitude()
- }};
- circleShader.u_scale_with_map = true;
- } else {
- circleShader.u_extrude_scale = pixelsToGLUnits;
- circleShader.u_scale_with_map = false;
+ if (pass == RenderPass::Opaque) {
+ return;
}
- circleShader.u_devicepixelratio = frame.pixelRatio;
- circleShader.u_color = properties.circleColor;
- circleShader.u_radius = properties.circleRadius;
- circleShader.u_blur = properties.circleBlur;
- circleShader.u_opacity = properties.circleOpacity;
-
- bucket.drawCircles(circleShader, context, paintMode());
+ const CirclePaintProperties::Evaluated& properties = layer.impl->paint.evaluated;
+ const bool scaleWithMap = properties.get<CirclePitchScale>() == CirclePitchScaleType::Map;
+
+ parameters.programs.circle.draw(
+ context,
+ gl::Triangles(),
+ depthModeForSublayer(0, gl::DepthMode::ReadOnly),
+ frame.mapMode == MapMode::Still
+ ? stencilModeForClipping(tile.clip)
+ : gl::StencilMode::disabled(),
+ colorModeForRenderPass(),
+ CircleProgram::UniformValues {
+ uniforms::u_matrix::Value{
+ tile.translatedMatrix(properties.get<CircleTranslate>(),
+ properties.get<CircleTranslateAnchor>(),
+ state)
+ },
+ uniforms::u_opacity::Value{ properties.get<CircleOpacity>() },
+ uniforms::u_color::Value{ properties.get<CircleColor>() },
+ uniforms::u_radius::Value{ properties.get<CircleRadius>() },
+ uniforms::u_blur::Value{ properties.get<CircleBlur>() },
+ uniforms::u_stroke_color::Value{ properties.get<CircleStrokeColor>() },
+ uniforms::u_stroke_width::Value{ properties.get<CircleStrokeWidth>() },
+ uniforms::u_stroke_opacity::Value{ properties.get<CircleStrokeOpacity>() },
+ uniforms::u_scale_with_map::Value{ scaleWithMap },
+ uniforms::u_extrude_scale::Value{ scaleWithMap
+ ? std::array<float, 2> {{
+ pixelsToGLUnits[0] * state.getAltitude(),
+ pixelsToGLUnits[1] * state.getAltitude()
+ }}
+ : pixelsToGLUnits }
+ },
+ *bucket.vertexBuffer,
+ *bucket.indexBuffer,
+ bucket.segments
+ );
}
} // namespace mbgl
diff --git a/src/mbgl/renderer/painter_clipping.cpp b/src/mbgl/renderer/painter_clipping.cpp
index 68f580c280..a2529561fe 100644
--- a/src/mbgl/renderer/painter_clipping.cpp
+++ b/src/mbgl/renderer/painter_clipping.cpp
@@ -1,49 +1,35 @@
#include <mbgl/renderer/painter.hpp>
-#include <mbgl/renderer/paint_parameters.hpp>
-#include <mbgl/gl/gl.hpp>
-
-#include <mbgl/style/source.hpp>
-#include <mbgl/shader/shaders.hpp>
+#include <mbgl/programs/programs.hpp>
+#include <mbgl/programs/fill_program.hpp>
#include <mbgl/util/clip_id.hpp>
-#include <mbgl/util/string.hpp>
-#include <mbgl/gl/debugging.hpp>
namespace mbgl {
-
-void Painter::drawClippingMasks(PaintParameters& parameters, const std::map<UnwrappedTileID, ClipID>& stencils) {
- MBGL_DEBUG_GROUP("clipping masks");
-
- auto& plainShader = parameters.shaders.fill;
- auto& arrayCoveringPlain = parameters.shaders.coveringPlainArray;
-
- mat4 matrix;
- const GLuint mask = 0b11111111;
-
- context.program = plainShader.getID();
- context.stencilOp = { gl::StencilTestOperation::Keep, gl::StencilTestOperation::Keep,
- gl::StencilTestOperation::Replace };
- context.stencilTest = true;
- context.depthTest = false;
- context.depthMask = false;
- context.colorMask = { false, false, false, false };
- context.stencilMask = mask;
-
- arrayCoveringPlain.bind(plainShader, tileTriangleVertexBuffer, BUFFER_OFFSET_0, context);
-
- for (const auto& stencil : stencils) {
- const auto& id = stencil.first;
- const auto& clip = stencil.second;
-
- MBGL_DEBUG_GROUP(std::string{ "mask: " } + util::toString(id));
- state.matrixFor(matrix, id);
- matrix::multiply(matrix, projMatrix, matrix);
- plainShader.u_matrix = matrix;
-
- const GLint ref = (GLint)(clip.reference.to_ulong());
- context.stencilFunc = { gl::StencilTestFunction::Always, ref, mask };
- MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(tileTriangleVertexBuffer.vertexCount)));
- }
+void Painter::renderClippingMask(const UnwrappedTileID& tileID, const ClipID& clip) {
+ programs->fill.draw(
+ context,
+ gl::Triangles(),
+ gl::DepthMode::disabled(),
+ gl::StencilMode {
+ gl::StencilMode::Always(),
+ static_cast<int32_t>(clip.reference.to_ulong()),
+ 0b11111111,
+ gl::StencilMode::Keep,
+ gl::StencilMode::Keep,
+ gl::StencilMode::Replace
+ },
+ gl::ColorMode::disabled(),
+ FillProgram::UniformValues {
+ uniforms::u_matrix::Value{ matrixForTile(tileID) },
+ uniforms::u_opacity::Value{ 0.0f },
+ uniforms::u_color::Value{ Color {} },
+ uniforms::u_outline_color::Value{ Color {} },
+ uniforms::u_world::Value{ context.viewport.getCurrentValue().size },
+ },
+ tileVertexBuffer,
+ tileTriangleIndexBuffer,
+ tileTriangleSegments
+ );
}
} // namespace mbgl
diff --git a/src/mbgl/renderer/painter_debug.cpp b/src/mbgl/renderer/painter_debug.cpp
index e57bb2205e..2b838dec0e 100644
--- a/src/mbgl/renderer/painter_debug.cpp
+++ b/src/mbgl/renderer/painter_debug.cpp
@@ -4,161 +4,121 @@
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/map/view.hpp>
#include <mbgl/tile/tile.hpp>
-#include <mbgl/shader/shaders.hpp>
+#include <mbgl/programs/programs.hpp>
+#include <mbgl/programs/fill_program.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/gl/debugging.hpp>
-#include <mbgl/gl/gl.hpp>
#include <mbgl/util/color.hpp>
namespace mbgl {
-void Painter::renderTileDebug(const RenderTile& tile) {
- MBGL_DEBUG_GROUP(std::string { "debug " } + util::toString(tile.id));
- if (frame.debugOptions != MapDebugOptions::NoDebug) {
- setClipping(tile.clip);
- if (frame.debugOptions & (MapDebugOptions::Timestamps | MapDebugOptions::ParseStatus)) {
- renderDebugText(tile.tile, tile.matrix);
+void Painter::renderTileDebug(const RenderTile& renderTile) {
+ if (frame.debugOptions == MapDebugOptions::NoDebug)
+ return;
+
+ MBGL_DEBUG_GROUP(std::string { "debug " } + util::toString(renderTile.id));
+
+ auto draw = [&] (Color color, const auto& vertexBuffer, const auto& indexBuffer, const auto& segments, auto drawMode) {
+ programs->debug.draw(
+ context,
+ drawMode,
+ gl::DepthMode::disabled(),
+ stencilModeForClipping(renderTile.clip),
+ gl::ColorMode::unblended(),
+ DebugProgram::UniformValues {
+ uniforms::u_matrix::Value{ renderTile.matrix },
+ uniforms::u_color::Value{ color }
+ },
+ vertexBuffer,
+ indexBuffer,
+ segments
+ );
+ };
+
+ if (frame.debugOptions & (MapDebugOptions::Timestamps | MapDebugOptions::ParseStatus)) {
+ Tile& tile = renderTile.tile;
+ if (!tile.debugBucket || tile.debugBucket->renderable != tile.isRenderable() ||
+ tile.debugBucket->complete != tile.isComplete() ||
+ !(tile.debugBucket->modified == tile.modified) ||
+ !(tile.debugBucket->expires == tile.expires) ||
+ tile.debugBucket->debugMode != frame.debugOptions) {
+ tile.debugBucket = std::make_unique<DebugBucket>(
+ tile.id, tile.isRenderable(), tile.isComplete(), tile.modified,
+ tile.expires, frame.debugOptions, context);
}
- if (frame.debugOptions & MapDebugOptions::TileBorders) {
- renderDebugFrame(tile.matrix);
- }
- }
-}
-void Painter::renderDebugText(Tile& tile, const mat4 &matrix) {
- MBGL_DEBUG_GROUP("debug text");
-
- context.depthTest = false;
-
- if (!tile.debugBucket || tile.debugBucket->renderable != tile.isRenderable() ||
- tile.debugBucket->complete != tile.isComplete() ||
- !(tile.debugBucket->modified == tile.modified) ||
- !(tile.debugBucket->expires == tile.expires) ||
- tile.debugBucket->debugMode != frame.debugOptions) {
- tile.debugBucket = std::make_unique<DebugBucket>(
- tile.id, tile.isRenderable(), tile.isComplete(), tile.modified,
- tile.expires, frame.debugOptions, context);
+ draw(Color::white(),
+ *tile.debugBucket->vertexBuffer,
+ *tile.debugBucket->indexBuffer,
+ tile.debugBucket->segments,
+ gl::Lines { 4.0f * frame.pixelRatio });
+
+ draw(Color::black(),
+ *tile.debugBucket->vertexBuffer,
+ *tile.debugBucket->indexBuffer,
+ tile.debugBucket->segments,
+ gl::Lines { 2.0f * frame.pixelRatio });
}
- auto& plainShader = shaders->fill;
- context.program = plainShader.getID();
- plainShader.u_matrix = matrix;
- plainShader.u_opacity = 1.0f;
-
- // Draw white outline
- plainShader.u_color = Color::white();
- context.lineWidth = 4.0f * frame.pixelRatio;
- tile.debugBucket->drawLines(plainShader, context);
-
-#if not MBGL_USE_GLES2
- // Draw line "end caps"
- MBGL_CHECK_ERROR(glPointSize(2));
- tile.debugBucket->drawPoints(plainShader, context);
-#endif // MBGL_USE_GLES2
-
- // Draw black text.
- plainShader.u_color = Color::black();
- context.lineWidth = 2.0f * frame.pixelRatio;
- tile.debugBucket->drawLines(plainShader, context);
-
- context.depthFunc = gl::DepthTestFunction::LessEqual;
- context.depthTest = true;
-}
-
-void Painter::renderDebugFrame(const mat4 &matrix) {
- MBGL_DEBUG_GROUP("debug frame");
-
- // Disable depth test and don't count this towards the depth buffer,
- // but *don't* disable stencil test, as we want to clip the red tile border
- // to the tile viewport.
- context.depthTest = false;
- context.stencilOp = { gl::StencilTestOperation::Keep, gl::StencilTestOperation::Keep,
- gl::StencilTestOperation::Replace };
- context.stencilTest = true;
-
- auto& plainShader = shaders->fill;
- context.program = plainShader.getID();
- plainShader.u_matrix = matrix;
- plainShader.u_opacity = 1.0f;
-
- // draw tile outline
- tileBorderArray.bind(plainShader, tileLineStripVertexBuffer, BUFFER_OFFSET_0, context);
- plainShader.u_color = { 1.0f, 0.0f, 0.0f, 1.0f };
- context.lineWidth = 4.0f * frame.pixelRatio;
- MBGL_CHECK_ERROR(glDrawArrays(GL_LINE_STRIP, 0, static_cast<GLsizei>(tileLineStripVertexBuffer.vertexCount)));
+ if (frame.debugOptions & MapDebugOptions::TileBorders) {
+ draw(Color::red(),
+ tileVertexBuffer,
+ tileBorderIndexBuffer,
+ tileBorderSegments,
+ gl::LineStrip { 4.0f * frame.pixelRatio });
+ }
}
#ifndef NDEBUG
void Painter::renderClipMasks(PaintParameters&) {
- context.stencilTest = false;
- context.depthTest = false;
+ context.setStencilMode(gl::StencilMode::disabled());
+ context.setDepthMode(gl::DepthMode::disabled());
+ context.setColorMode(gl::ColorMode::unblended());
context.program = 0;
- context.colorMask = { true, true, true, true };
#if not MBGL_USE_GLES2
- context.pixelZoom = { 1, 1 };
- context.rasterPos = { -1, -1, 0, 0 };
+ // Reset the value in case someone else changed it, or it's dirty.
+ context.pixelTransferStencil = gl::value::PixelTransferStencil::Default;
// Read the stencil buffer
const auto viewport = context.viewport.getCurrentValue();
- auto pixels = std::make_unique<uint8_t[]>(viewport.width * viewport.height);
- MBGL_CHECK_ERROR(glReadPixels(
- viewport.x, // GLint x
- viewport.y, // GLint y
- viewport.width, // GLsizei width
- viewport.height, // GLsizei height
- GL_STENCIL_INDEX, // GLenum format
- GL_UNSIGNED_BYTE, // GLenum type
- pixels.get() // GLvoid * data
- ));
+ auto image =
+ context.readFramebuffer<AlphaImage, gl::TextureFormat::Stencil>(viewport.size, false);
// Scale the Stencil buffer to cover the entire color space.
- auto it = pixels.get();
- auto end = it + viewport.width * viewport.height;
+ auto it = image.data.get();
+ auto end = it + viewport.size.width * viewport.size.height;
const auto factor = 255.0f / *std::max_element(it, end);
for (; it != end; ++it) {
*it *= factor;
}
- MBGL_CHECK_ERROR(glWindowPos2i(viewport.x, viewport.y));
- MBGL_CHECK_ERROR(glDrawPixels(viewport.width, viewport.height, GL_LUMINANCE, GL_UNSIGNED_BYTE,
- pixels.get()));
+ context.pixelZoom = { 1, 1 };
+ context.rasterPos = { -1, -1, 0, 1 };
+ context.drawPixels(image);
#endif // MBGL_USE_GLES2
}
-#endif // NDEBUG
-#ifndef NDEBUG
void Painter::renderDepthBuffer(PaintParameters&) {
- context.stencilTest = false;
- context.depthTest = false;
+ context.setStencilMode(gl::StencilMode::disabled());
+ context.setDepthMode(gl::DepthMode::disabled());
+ context.setColorMode(gl::ColorMode::unblended());
context.program = 0;
- context.colorMask = { true, true, true, true };
#if not MBGL_USE_GLES2
- context.pixelZoom = { 1, 1 };
- context.rasterPos = { -1, -1, 0, 0 };
+ // Scales the values in the depth buffer so that they cover the entire grayscale range. This
+ // makes it easier to spot tiny differences.
+ const float base = 1.0f / (1.0f - depthRangeSize);
+ context.pixelTransferDepth = { base, 1.0f - base };
// Read the stencil buffer
- const auto viewport = context.viewport.getCurrentValue();
- auto pixels = std::make_unique<uint8_t[]>(viewport.width * viewport.height);
-
- const double base = 1.0 / (1.0 - depthRangeSize);
- glPixelTransferf(GL_DEPTH_SCALE, base);
- glPixelTransferf(GL_DEPTH_BIAS, 1.0 - base);
-
- MBGL_CHECK_ERROR(glReadPixels(
- viewport.x, // GLint x
- viewport.y, // GLint y
- viewport.width, // GLsizei width
- viewport.height, // GLsizei height
- GL_DEPTH_COMPONENT, // GLenum format
- GL_UNSIGNED_BYTE, // GLenum type
- pixels.get() // GLvoid * data
- ));
-
- MBGL_CHECK_ERROR(glWindowPos2i(viewport.x, viewport.y));
- MBGL_CHECK_ERROR(glDrawPixels(viewport.width, viewport.height, GL_LUMINANCE, GL_UNSIGNED_BYTE,
- pixels.get()));
+ auto viewport = context.viewport.getCurrentValue();
+ auto image =
+ context.readFramebuffer<AlphaImage, gl::TextureFormat::Depth>(viewport.size, false);
+
+ context.pixelZoom = { 1, 1 };
+ context.rasterPos = { -1, -1, 0, 1 };
+ context.drawPixels(image);
#endif // MBGL_USE_GLES2
}
#endif // NDEBUG
diff --git a/src/mbgl/renderer/painter_fill.cpp b/src/mbgl/renderer/painter_fill.cpp
index b6606ca40b..356ccfc0b2 100644
--- a/src/mbgl/renderer/painter_fill.cpp
+++ b/src/mbgl/renderer/painter_fill.cpp
@@ -1,14 +1,12 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
-#include <mbgl/gl/gl.hpp>
-#include <mbgl/map/view.hpp>
-
#include <mbgl/renderer/fill_bucket.hpp>
#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
#include <mbgl/style/layers/fill_layer_impl.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
-#include <mbgl/shader/shaders.hpp>
+#include <mbgl/programs/programs.hpp>
+#include <mbgl/programs/fill_program.hpp>
#include <mbgl/util/convert.hpp>
namespace mbgl {
@@ -19,160 +17,131 @@ void Painter::renderFill(PaintParameters& parameters,
FillBucket& bucket,
const FillLayer& layer,
const RenderTile& tile) {
- const FillPaintProperties& properties = layer.impl->paint;
- mat4 vertexMatrix = tile.translatedMatrix(properties.fillTranslate,
- properties.fillTranslateAnchor,
- state);
-
- Color fillColor = properties.fillColor;
- float opacity = properties.fillOpacity;
-
- const bool isOutlineColorDefined = !properties.fillOutlineColor.isUndefined();
- Color strokeColor = isOutlineColorDefined? properties.fillOutlineColor : fillColor;
-
- const auto viewport = context.viewport.getCurrentValue();
- const std::array<GLfloat, 2> worldSize{ { static_cast<GLfloat>(viewport.width),
- static_cast<GLfloat>(viewport.height) } };
-
- bool pattern = !properties.fillPattern.value.from.empty();
- bool outline = properties.fillAntialias && !pattern && isOutlineColorDefined;
- bool fringeline = properties.fillAntialias && !pattern && !isOutlineColorDefined;
-
- context.stencilOp = { gl::StencilTestOperation::Keep, gl::StencilTestOperation::Keep,
- gl::StencilTestOperation::Replace };
- context.stencilTest = true;
- context.depthFunc = gl::DepthTestFunction::LessEqual;
- context.depthTest = true;
- context.depthMask = true;
- context.lineWidth = 2.0f; // This is always fixed and does not depend on the pixelRatio!
-
- auto& outlineShader = parameters.shaders.fillOutline;
- auto& patternShader = parameters.shaders.fillPattern;
- auto& outlinePatternShader = parameters.shaders.fillOutlinePattern;
- auto& plainShader = parameters.shaders.fill;
+ const FillPaintProperties::Evaluated& properties = layer.impl->paint.evaluated;
- // Because we're drawing top-to-bottom, and we update the stencil mask
- // befrom, we have to draw the outline first (!)
- if (outline && pass == RenderPass::Translucent) {
- context.program = outlineShader.getID();
- outlineShader.u_matrix = vertexMatrix;
-
- outlineShader.u_outline_color = strokeColor;
- outlineShader.u_opacity = opacity;
-
- // Draw the entire line
- outlineShader.u_world = worldSize;
- if (isOutlineColorDefined) {
- // If we defined a different color for the fill outline, we are
- // going to ignore the bits in 0x07 and just care about the global
- // clipping mask.
- setDepthSublayer(2); // OK
- } else {
- // Otherwise, we only want to drawFill the antialiased parts that are
- // *outside* the current shape. This is important in case the fill
- // or stroke color is translucent. If we wouldn't clip to outside
- // the current shape, some pixels from the outline stroke overlapped
- // the (non-antialiased) fill.
- setDepthSublayer(0); // OK
+ if (!properties.get<FillPattern>().from.empty()) {
+ if (pass != RenderPass::Translucent) {
+ return;
}
- bucket.drawVertices(outlineShader, context, paintMode());
- }
- if (pattern) {
optional<SpriteAtlasPosition> imagePosA = spriteAtlas->getPosition(
- properties.fillPattern.value.from, SpritePatternMode::Repeating);
- optional<SpriteAtlasPosition> imagePosB =
- spriteAtlas->getPosition(properties.fillPattern.value.to, SpritePatternMode::Repeating);
-
- // Image fill.
- if (pass == RenderPass::Translucent && imagePosA && imagePosB) {
- context.program = patternShader.getID();
- patternShader.u_matrix = vertexMatrix;
- patternShader.u_pattern_tl_a = imagePosA->tl;
- patternShader.u_pattern_br_a = imagePosA->br;
- patternShader.u_pattern_tl_b = imagePosB->tl;
- patternShader.u_pattern_br_b = imagePosB->br;
- patternShader.u_opacity = properties.fillOpacity;
- patternShader.u_image = 0;
- patternShader.u_mix = properties.fillPattern.value.t;
- patternShader.u_pattern_size_a = imagePosA->size;
- patternShader.u_pattern_size_b = imagePosB->size;
- patternShader.u_scale_a = properties.fillPattern.value.fromScale;
- patternShader.u_scale_b = properties.fillPattern.value.toScale;
- patternShader.u_tile_units_to_pixels = 1.0f / tile.id.pixelsToTileUnits(1.0f, state.getIntegerZoom());
-
- GLint tileSizeAtNearestZoom = util::tileSize * state.zoomScale(state.getIntegerZoom() - tile.id.canonical.z);
- GLint pixelX = tileSizeAtNearestZoom * (tile.id.canonical.x + tile.id.wrap * state.zoomScale(tile.id.canonical.z));
- GLint pixelY = tileSizeAtNearestZoom * tile.id.canonical.y;
- patternShader.u_pixel_coord_upper = {{ float(pixelX >> 16), float(pixelY >> 16) }};
- patternShader.u_pixel_coord_lower = {{ float(pixelX & 0xFFFF), float(pixelY & 0xFFFF) }};
-
- spriteAtlas->bind(true, context, 0);
+ properties.get<FillPattern>().from, SpritePatternMode::Repeating);
+ optional<SpriteAtlasPosition> imagePosB = spriteAtlas->getPosition(
+ properties.get<FillPattern>().to, SpritePatternMode::Repeating);
- // Draw the actual triangles into the color & stencil buffer.
- setDepthSublayer(0);
- bucket.drawElements(patternShader, context, paintMode());
-
- if (properties.fillAntialias && !isOutlineColorDefined) {
- context.program = outlinePatternShader.getID();
- outlinePatternShader.u_matrix = vertexMatrix;
-
- outlinePatternShader.u_pattern_tl_a = imagePosA->tl;
- outlinePatternShader.u_pattern_br_a = imagePosA->br;
- outlinePatternShader.u_pattern_tl_b = imagePosB->tl;
- outlinePatternShader.u_pattern_br_b = imagePosB->br;
- outlinePatternShader.u_opacity = properties.fillOpacity;
- outlinePatternShader.u_image = 0;
- outlinePatternShader.u_mix = properties.fillPattern.value.t;
- outlinePatternShader.u_pattern_size_a = imagePosA->size;
- outlinePatternShader.u_pattern_size_b = imagePosB->size;
- outlinePatternShader.u_scale_a = properties.fillPattern.value.fromScale;
- outlinePatternShader.u_scale_b = properties.fillPattern.value.toScale;
- outlinePatternShader.u_tile_units_to_pixels = 1.0f / tile.id.pixelsToTileUnits(1.0f, state.getIntegerZoom());
- outlinePatternShader.u_pixel_coord_upper = {{ float(pixelX >> 16), float(pixelY >> 16) }};
- outlinePatternShader.u_pixel_coord_lower = {{ float(pixelX & 0xFFFF), float(pixelY & 0xFFFF) }};
-
- // Draw the entire line
- outlinePatternShader.u_world = worldSize;
-
- spriteAtlas->bind(true, context, 0);
-
- setDepthSublayer(2);
- bucket.drawVertices(outlinePatternShader, context, paintMode());
- }
+ if (!imagePosA || !imagePosB) {
+ return;
}
- } else {
- // No image fill.
- if ((fillColor.a >= 1.0f && opacity >= 1.0f) == (pass == RenderPass::Opaque)) {
- // Only draw the fill when it's either opaque and we're drawing opaque
- // fragments or when it's translucent and we're drawing translucent
- // fragments
- // Draw filling rectangle.
- context.program = plainShader.getID();
- plainShader.u_matrix = vertexMatrix;
- plainShader.u_color = fillColor;
- plainShader.u_opacity = opacity;
- // Draw the actual triangles into the color & stencil buffer.
- setDepthSublayer(1);
- bucket.drawElements(plainShader, context, paintMode());
+ spriteAtlas->bind(true, context, 0);
+
+ auto draw = [&] (uint8_t sublayer,
+ auto& program,
+ const auto& drawMode,
+ const auto& vertexBuffer,
+ const auto& indexBuffer,
+ const auto& segments) {
+ program.draw(
+ context,
+ drawMode,
+ depthModeForSublayer(sublayer, gl::DepthMode::ReadWrite),
+ stencilModeForClipping(tile.clip),
+ colorModeForRenderPass(),
+ FillPatternUniforms::values(
+ tile.translatedMatrix(properties.get<FillTranslate>(),
+ properties.get<FillTranslateAnchor>(),
+ state),
+ properties.get<FillOpacity>(),
+ context.viewport.getCurrentValue().size,
+ *imagePosA,
+ *imagePosB,
+ properties.get<FillPattern>(),
+ tile.id,
+ state
+ ),
+ vertexBuffer,
+ indexBuffer,
+ segments
+ );
+ };
+
+ draw(0,
+ parameters.programs.fillPattern,
+ gl::Triangles(),
+ *bucket.vertexBuffer,
+ *bucket.triangleIndexBuffer,
+ bucket.triangleSegments);
+
+ if (!properties.get<FillAntialias>() || !layer.impl->paint.unevaluated.get<FillOutlineColor>().isUndefined()) {
+ return;
}
- }
-
- // Because we're drawing top-to-bottom, and we update the stencil mask
- // below, we have to draw the outline first (!)
- if (fringeline && pass == RenderPass::Translucent) {
- context.program = outlineShader.getID();
- outlineShader.u_matrix = vertexMatrix;
- outlineShader.u_outline_color = fillColor;
- outlineShader.u_opacity = opacity;
+ draw(2,
+ parameters.programs.fillOutlinePattern,
+ gl::Lines { 2.0f },
+ *bucket.vertexBuffer,
+ *bucket.lineIndexBuffer,
+ bucket.lineSegments);
+ } else {
+ auto draw = [&] (uint8_t sublayer,
+ auto& program,
+ Color outlineColor,
+ const auto& drawMode,
+ const auto& vertexBuffer,
+ const auto& indexBuffer,
+ const auto& segments) {
+ program.draw(
+ context,
+ drawMode,
+ depthModeForSublayer(sublayer, gl::DepthMode::ReadWrite),
+ stencilModeForClipping(tile.clip),
+ colorModeForRenderPass(),
+ FillProgram::UniformValues {
+ uniforms::u_matrix::Value{ tile.translatedMatrix(properties.get<FillTranslate>(),
+ properties.get<FillTranslateAnchor>(),
+ state) },
+ uniforms::u_opacity::Value{ properties.get<FillOpacity>() },
+ uniforms::u_color::Value{ properties.get<FillColor>() },
+ uniforms::u_outline_color::Value{ outlineColor },
+ uniforms::u_world::Value{ context.viewport.getCurrentValue().size },
+ },
+ vertexBuffer,
+ indexBuffer,
+ segments
+ );
+ };
+
+ if (properties.get<FillAntialias>() && !layer.impl->paint.unevaluated.get<FillOutlineColor>().isUndefined() && pass == RenderPass::Translucent) {
+ draw(2,
+ parameters.programs.fillOutline,
+ properties.get<FillOutlineColor>(),
+ gl::Lines { 2.0f },
+ *bucket.vertexBuffer,
+ *bucket.lineIndexBuffer,
+ bucket.lineSegments);
+ }
- // Draw the entire line
- outlineShader.u_world = worldSize;
+ // Only draw the fill when it's opaque and we're drawing opaque fragments,
+ // or when it's translucent and we're drawing translucent fragments.
+ if ((properties.get<FillColor>().a >= 1.0f && properties.get<FillOpacity>() >= 1.0f) == (pass == RenderPass::Opaque)) {
+ draw(1,
+ parameters.programs.fill,
+ properties.get<FillOutlineColor>(),
+ gl::Triangles(),
+ *bucket.vertexBuffer,
+ *bucket.triangleIndexBuffer,
+ bucket.triangleSegments);
+ }
- setDepthSublayer(2);
- bucket.drawVertices(outlineShader, context, paintMode());
+ if (properties.get<FillAntialias>() && layer.impl->paint.unevaluated.get<FillOutlineColor>().isUndefined() && pass == RenderPass::Translucent) {
+ draw(2,
+ parameters.programs.fillOutline,
+ properties.get<FillColor>(),
+ gl::Lines { 2.0f },
+ *bucket.vertexBuffer,
+ *bucket.lineIndexBuffer,
+ bucket.lineSegments);
+ }
}
}
diff --git a/src/mbgl/renderer/painter_line.cpp b/src/mbgl/renderer/painter_line.cpp
index 85a5786353..a66f53a856 100644
--- a/src/mbgl/renderer/painter_line.cpp
+++ b/src/mbgl/renderer/painter_line.cpp
@@ -4,10 +4,10 @@
#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/style/layers/line_layer.hpp>
#include <mbgl/style/layers/line_layer_impl.hpp>
-#include <mbgl/shader/shaders.hpp>
+#include <mbgl/programs/programs.hpp>
+#include <mbgl/programs/line_program.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/geometry/line_atlas.hpp>
-#include <mbgl/util/mat2.hpp>
namespace mbgl {
@@ -17,150 +17,70 @@ void Painter::renderLine(PaintParameters& parameters,
LineBucket& bucket,
const LineLayer& layer,
const RenderTile& tile) {
- // Abort early.
- if (pass == RenderPass::Opaque) return;
-
- context.stencilOp = { gl::StencilTestOperation::Keep, gl::StencilTestOperation::Keep,
- gl::StencilTestOperation::Replace };
- context.stencilTest = true;
- context.depthFunc = gl::DepthTestFunction::LessEqual;
- context.depthTest = true;
- context.depthMask = false;
-
- const auto& properties = layer.impl->paint;
- const auto& layout = bucket.layout;
-
- // the distance over which the line edge fades out.
- // Retina devices need a smaller distance to avoid aliasing.
- float antialiasing = 1.0 / frame.pixelRatio;
-
- float blur = properties.lineBlur + antialiasing;
-
- const Color color = properties.lineColor;
- const float opacity = properties.lineOpacity;
- const float ratio = 1.0 / tile.id.pixelsToTileUnits(1.0, state.getZoom());
-
- mat2 antialiasingMatrix;
- matrix::identity(antialiasingMatrix);
- matrix::scale(antialiasingMatrix, antialiasingMatrix, 1.0, std::cos(state.getPitch()));
- matrix::rotate(antialiasingMatrix, antialiasingMatrix, state.getAngle());
-
- // calculate how much longer the real world distance is at the top of the screen
- // than at the middle of the screen.
- float topedgelength = std::sqrt(std::pow(state.getHeight(), 2.0f) / 4.0f * (1.0f + std::pow(state.getAltitude(), 2.0f)));
- float x = state.getHeight() / 2.0f * std::tan(state.getPitch());
- float extra = (topedgelength + x) / topedgelength - 1.0f;
-
- mat4 vtxMatrix = tile.translatedMatrix(properties.lineTranslate,
- properties.lineTranslateAnchor,
- state);
-
- setDepthSublayer(0);
-
- auto& linesdfShader = parameters.shaders.lineSDF;
- auto& linepatternShader = parameters.shaders.linePattern;
- auto& lineShader = parameters.shaders.line;
-
- if (!properties.lineDasharray.value.from.empty()) {
- context.program = linesdfShader.getID();
-
- linesdfShader.u_matrix = vtxMatrix;
- linesdfShader.u_linewidth = properties.lineWidth / 2;
- linesdfShader.u_gapwidth = properties.lineGapWidth / 2;
- linesdfShader.u_antialiasing = antialiasing / 2;
- linesdfShader.u_ratio = ratio;
- linesdfShader.u_blur = blur;
- linesdfShader.u_color = color;
- linesdfShader.u_opacity = opacity;
-
- const LinePatternCap cap =
- layout.lineCap == LineCapType::Round ? LinePatternCap::Round : LinePatternCap::Square;
- LinePatternPos posA = lineAtlas->getDashPosition(properties.lineDasharray.value.from, cap);
- LinePatternPos posB = lineAtlas->getDashPosition(properties.lineDasharray.value.to, cap);
-
- const float widthA = posA.width * properties.lineDasharray.value.fromScale * layer.impl->dashLineWidth;
- const float widthB = posB.width * properties.lineDasharray.value.toScale * layer.impl->dashLineWidth;
-
- float scaleXA = 1.0 / tile.id.pixelsToTileUnits(widthA, state.getIntegerZoom());
- float scaleYA = -posA.height / 2.0;
- float scaleXB = 1.0 / tile.id.pixelsToTileUnits(widthB, state.getIntegerZoom());
- float scaleYB = -posB.height / 2.0;
+ if (pass == RenderPass::Opaque) {
+ return;
+ }
- linesdfShader.u_patternscale_a = {{ scaleXA, scaleYA }};
- linesdfShader.u_tex_y_a = posA.y;
- linesdfShader.u_patternscale_b = {{ scaleXB, scaleYB }};
- linesdfShader.u_tex_y_b = posB.y;
- linesdfShader.u_sdfgamma = lineAtlas->width / (std::min(widthA, widthB) * 256.0 * frame.pixelRatio) / 2;
- linesdfShader.u_mix = properties.lineDasharray.value.t;
- linesdfShader.u_extra = extra;
- linesdfShader.u_offset = -properties.lineOffset;
- linesdfShader.u_antialiasingmatrix = antialiasingMatrix;
+ const LinePaintProperties::Evaluated& properties = layer.impl->paint.evaluated;
+
+ auto draw = [&] (auto& program, auto&& uniformValues) {
+ program.draw(
+ context,
+ gl::Triangles(),
+ depthModeForSublayer(0, gl::DepthMode::ReadOnly),
+ stencilModeForClipping(tile.clip),
+ colorModeForRenderPass(),
+ std::move(uniformValues),
+ *bucket.vertexBuffer,
+ *bucket.indexBuffer,
+ bucket.segments
+ );
+ };
+
+ if (!properties.get<LineDasharray>().from.empty()) {
+ const LinePatternCap cap = bucket.layout.get<LineCap>() == LineCapType::Round
+ ? LinePatternCap::Round : LinePatternCap::Square;
+ LinePatternPos posA = lineAtlas->getDashPosition(properties.get<LineDasharray>().from, cap);
+ LinePatternPos posB = lineAtlas->getDashPosition(properties.get<LineDasharray>().to, cap);
- linesdfShader.u_image = 0;
lineAtlas->bind(context, 0);
- bucket.drawLineSDF(linesdfShader, context, paintMode());
-
- } else if (!properties.linePattern.value.from.empty()) {
- optional<SpriteAtlasPosition> imagePosA = spriteAtlas->getPosition(
- properties.linePattern.value.from, SpritePatternMode::Repeating);
- optional<SpriteAtlasPosition> imagePosB =
- spriteAtlas->getPosition(properties.linePattern.value.to, SpritePatternMode::Repeating);
-
- if (!imagePosA || !imagePosB)
+ draw(parameters.programs.lineSDF,
+ LineSDFProgram::uniformValues(
+ properties,
+ frame.pixelRatio,
+ tile,
+ state,
+ posA,
+ posB,
+ layer.impl->dashLineWidth,
+ lineAtlas->getSize().width));
+
+ } else if (!properties.get<LinePattern>().from.empty()) {
+ optional<SpriteAtlasPosition> posA = spriteAtlas->getPosition(
+ properties.get<LinePattern>().from, SpritePatternMode::Repeating);
+ optional<SpriteAtlasPosition> posB = spriteAtlas->getPosition(
+ properties.get<LinePattern>().to, SpritePatternMode::Repeating);
+
+ if (!posA || !posB)
return;
- context.program = linepatternShader.getID();
-
- linepatternShader.u_matrix = vtxMatrix;
- linepatternShader.u_linewidth = properties.lineWidth / 2;
- linepatternShader.u_gapwidth = properties.lineGapWidth / 2;
- linepatternShader.u_antialiasing = antialiasing / 2;
- linepatternShader.u_ratio = ratio;
- linepatternShader.u_blur = blur;
-
- linepatternShader.u_pattern_size_a = {{
- tile.id.pixelsToTileUnits((*imagePosA).size[0] * properties.linePattern.value.fromScale, state.getIntegerZoom()),
- (*imagePosA).size[1]
- }};
- linepatternShader.u_pattern_tl_a = (*imagePosA).tl;
- linepatternShader.u_pattern_br_a = (*imagePosA).br;
-
- linepatternShader.u_pattern_size_b = {{
- tile.id.pixelsToTileUnits((*imagePosB).size[0] * properties.linePattern.value.toScale, state.getIntegerZoom()),
- (*imagePosB).size[1]
- }};
- linepatternShader.u_pattern_tl_b = (*imagePosB).tl;
- linepatternShader.u_pattern_br_b = (*imagePosB).br;
-
- linepatternShader.u_fade = properties.linePattern.value.t;
- linepatternShader.u_opacity = properties.lineOpacity;
- linepatternShader.u_extra = extra;
- linepatternShader.u_offset = -properties.lineOffset;
- linepatternShader.u_antialiasingmatrix = antialiasingMatrix;
-
- linepatternShader.u_image = 0;
spriteAtlas->bind(true, context, 0);
- bucket.drawLinePatterns(linepatternShader, context, paintMode());
+ draw(parameters.programs.linePattern,
+ LinePatternProgram::uniformValues(
+ properties,
+ tile,
+ state,
+ *posA,
+ *posB));
} else {
- context.program = lineShader.getID();
-
- lineShader.u_matrix = vtxMatrix;
- lineShader.u_linewidth = properties.lineWidth / 2;
- lineShader.u_gapwidth = properties.lineGapWidth / 2;
- lineShader.u_antialiasing = antialiasing / 2;
- lineShader.u_ratio = ratio;
- lineShader.u_blur = blur;
- lineShader.u_extra = extra;
- lineShader.u_offset = -properties.lineOffset;
- lineShader.u_antialiasingmatrix = antialiasingMatrix;
-
- lineShader.u_color = color;
- lineShader.u_opacity = opacity;
-
- bucket.drawLines(lineShader, context, paintMode());
+ draw(parameters.programs.line,
+ LineProgram::uniformValues(
+ properties,
+ tile,
+ state));
}
}
diff --git a/src/mbgl/renderer/painter_raster.cpp b/src/mbgl/renderer/painter_raster.cpp
index 8b39c8adf8..96bb6dc565 100644
--- a/src/mbgl/renderer/painter_raster.cpp
+++ b/src/mbgl/renderer/painter_raster.cpp
@@ -1,57 +1,17 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/render_tile.hpp>
-#include <mbgl/gl/gl.hpp>
#include <mbgl/renderer/raster_bucket.hpp>
#include <mbgl/style/layers/raster_layer.hpp>
#include <mbgl/style/layers/raster_layer_impl.hpp>
-#include <mbgl/shader/shaders.hpp>
+#include <mbgl/programs/programs.hpp>
+#include <mbgl/programs/raster_program.hpp>
namespace mbgl {
using namespace style;
-void Painter::renderRaster(PaintParameters& parameters,
- RasterBucket& bucket,
- const RasterLayer& layer,
- const RenderTile& tile) {
- if (pass != RenderPass::Translucent) return;
-
- const RasterPaintProperties& properties = layer.impl->paint;
-
- if (bucket.hasData()) {
- auto& rasterShader = parameters.shaders.raster;
- auto& rasterVAO = parameters.shaders.coveringRasterArray;
-
- context.program = rasterShader.getID();
- rasterShader.u_matrix = tile.matrix;
- rasterShader.u_buffer_scale = 1.0f;
- rasterShader.u_opacity0 = properties.rasterOpacity;
- rasterShader.u_opacity1 = 0;
-
- rasterShader.u_brightness_low = properties.rasterBrightnessMin;
- rasterShader.u_brightness_high = properties.rasterBrightnessMax;
- rasterShader.u_saturation_factor = saturationFactor(properties.rasterSaturation);
- rasterShader.u_contrast_factor = contrastFactor(properties.rasterContrast);
- rasterShader.u_spin_weights = spinWeights(properties.rasterHueRotate);
-
- context.stencilTest = false;
-
- rasterShader.u_image0 = 0; // GL_TEXTURE0
- rasterShader.u_image1 = 1; // GL_TEXTURE1
- rasterShader.u_tl_parent = {{ 0.0f, 0.0f }};
- rasterShader.u_scale_parent = 1.0f;
-
- context.depthFunc = gl::DepthTestFunction::LessEqual;
- context.depthTest = true;
- context.depthMask = false;
- setDepthSublayer(0);
-
- bucket.drawRaster(rasterShader, rasterVertexBuffer, rasterVAO, context);
- }
-}
-
-float Painter::saturationFactor(float saturation) {
+static float saturationFactor(float saturation) {
if (saturation > 0) {
return 1 - 1 / (1.001 - saturation);
} else {
@@ -59,7 +19,7 @@ float Painter::saturationFactor(float saturation) {
}
}
-float Painter::contrastFactor(float contrast) {
+static float contrastFactor(float contrast) {
if (contrast > 0) {
return 1 / (1 - contrast);
} else {
@@ -67,7 +27,7 @@ float Painter::contrastFactor(float contrast) {
}
}
-std::array<float, 3> Painter::spinWeights(float spin) {
+static std::array<float, 3> spinWeights(float spin) {
spin *= util::DEG2RAD;
float s = std::sin(spin);
float c = std::cos(spin);
@@ -79,4 +39,46 @@ std::array<float, 3> Painter::spinWeights(float spin) {
return spin_weights;
}
+void Painter::renderRaster(PaintParameters& parameters,
+ RasterBucket& bucket,
+ const RasterLayer& layer,
+ const RenderTile& tile) {
+ if (pass != RenderPass::Translucent)
+ return;
+ if (!bucket.hasData())
+ return;
+
+ const RasterPaintProperties::Evaluated& properties = layer.impl->paint.evaluated;
+
+ assert(bucket.texture);
+ context.bindTexture(*bucket.texture, 0, gl::TextureFilter::Linear);
+ context.bindTexture(*bucket.texture, 1, gl::TextureFilter::Linear);
+
+ parameters.programs.raster.draw(
+ context,
+ gl::Triangles(),
+ depthModeForSublayer(0, gl::DepthMode::ReadOnly),
+ gl::StencilMode::disabled(),
+ colorModeForRenderPass(),
+ RasterProgram::UniformValues {
+ uniforms::u_matrix::Value{ tile.matrix },
+ uniforms::u_image0::Value{ 0 },
+ uniforms::u_image1::Value{ 1 },
+ uniforms::u_opacity0::Value{ properties.get<RasterOpacity>() },
+ uniforms::u_opacity1::Value{ 0 },
+ uniforms::u_brightness_low::Value{ properties.get<RasterBrightnessMin>() },
+ uniforms::u_brightness_high::Value{ properties.get<RasterBrightnessMax>() },
+ uniforms::u_saturation_factor::Value{ saturationFactor(properties.get<RasterSaturation>()) },
+ uniforms::u_contrast_factor::Value{ contrastFactor(properties.get<RasterContrast>()) },
+ uniforms::u_spin_weights::Value{ spinWeights(properties.get<RasterHueRotate>()) },
+ uniforms::u_buffer_scale::Value{ 1.0f },
+ uniforms::u_scale_parent::Value{ 1.0f },
+ uniforms::u_tl_parent::Value{ std::array<float, 2> {{ 0.0f, 0.0f }} },
+ },
+ rasterVertexBuffer,
+ tileTriangleIndexBuffer,
+ rasterSegments
+ );
+}
+
} // namespace mbgl
diff --git a/src/mbgl/renderer/painter_symbol.cpp b/src/mbgl/renderer/painter_symbol.cpp
index 2ed6facad8..39075976a0 100644
--- a/src/mbgl/renderer/painter_symbol.cpp
+++ b/src/mbgl/renderer/painter_symbol.cpp
@@ -6,8 +6,11 @@
#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <mbgl/text/glyph_atlas.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
-#include <mbgl/shader/shaders.hpp>
+#include <mbgl/programs/programs.hpp>
+#include <mbgl/programs/symbol_program.hpp>
+#include <mbgl/programs/collision_box_program.hpp>
#include <mbgl/util/math.hpp>
+#include <mbgl/tile/tile.hpp>
#include <cmath>
@@ -15,254 +18,114 @@ namespace mbgl {
using namespace style;
-void Painter::renderSDF(SymbolBucket& bucket,
- const RenderTile& tile,
- float sdfFontSize,
- std::array<float, 2> texsize,
- SymbolSDFShader& sdfShader,
- void (SymbolBucket::*drawSDF)(SymbolSDFShader&, gl::Context&, PaintMode),
-
- // Layout
- AlignmentType rotationAlignment,
- AlignmentType pitchAlignment,
- float layoutSize,
-
- // Paint
- float opacity,
- Color color,
- Color haloColor,
- float haloWidth,
- float haloBlur,
- std::array<float, 2> translate,
- TranslateAnchorType translateAnchor,
- float paintSize)
-{
- mat4 vtxMatrix = tile.translatedMatrix(translate, translateAnchor, state);
-
- // If layerStyle.size > bucket.info.fontSize then labels may collide
- float fontSize = paintSize;
- float fontScale = fontSize / sdfFontSize;
-
- bool rotateWithMap = rotationAlignment == AlignmentType::Map;
- bool pitchWithMap = pitchAlignment == AlignmentType::Map;
-
- std::array<float, 2> extrudeScale;
- float gammaScale;
-
- if (pitchWithMap) {
- gammaScale = 1.0 / std::cos(state.getPitch());
- extrudeScale.fill(tile.id.pixelsToTileUnits(1, state.getZoom()) * fontScale);
- } else {
- gammaScale = 1.0;
- extrudeScale = {{
- pixelsToGLUnits[0] * fontScale * state.getAltitude(),
- pixelsToGLUnits[1] * fontScale * state.getAltitude()
- }};
- }
-
- context.program = sdfShader.getID();
- sdfShader.u_matrix = vtxMatrix;
- sdfShader.u_extrude_scale = extrudeScale;
- sdfShader.u_texsize = texsize;
- sdfShader.u_rotate_with_map = rotateWithMap;
- sdfShader.u_pitch_with_map = pitchWithMap;
- sdfShader.u_texture = 0;
- sdfShader.u_pitch = state.getPitch();
- sdfShader.u_bearing = -1.0f * state.getAngle();
- sdfShader.u_aspect_ratio = (state.getWidth() * 1.0f) / (state.getHeight() * 1.0f);
-
- // adjust min/max zooms for variable font sies
- float zoomAdjust = std::log(fontSize / layoutSize) / std::log(2);
-
- sdfShader.u_zoom = (state.getZoom() - zoomAdjust) * 10; // current zoom level
-
- frameHistory.bind(context, 1);
- sdfShader.u_fadetexture = 1;
-
- // The default gamma value has to be adjust for the current pixelratio so that we're not
- // drawing blurry font on retina screens.
- const float gamma = 0.105 * sdfFontSize / fontSize / frame.pixelRatio;
-
- const float sdfPx = 8.0f;
- const float blurOffset = 1.19f;
- const float haloOffset = 6.0f;
-
- // We're drawing in the translucent pass which is bottom-to-top, so we need
- // to draw the halo first.
- if (haloColor.a > 0.0f && haloWidth > 0.0f) {
- sdfShader.u_gamma = (haloBlur * blurOffset / fontScale / sdfPx + gamma) * gammaScale;
- sdfShader.u_color = haloColor;
- sdfShader.u_opacity = opacity;
- sdfShader.u_buffer = (haloOffset - haloWidth / fontScale) / sdfPx;
- (bucket.*drawSDF)(sdfShader, context, paintMode());
- }
-
- // Then, we draw the text/icon over the halo
- if (color.a > 0.0f) {
- sdfShader.u_gamma = gamma * gammaScale;
- sdfShader.u_color = color;
- sdfShader.u_opacity = opacity;
- sdfShader.u_buffer = (256.0f - 64.0f) / 256.0f;
- (bucket.*drawSDF)(sdfShader, context, paintMode());
- }
-}
-
void Painter::renderSymbol(PaintParameters& parameters,
SymbolBucket& bucket,
const SymbolLayer& layer,
const RenderTile& tile) {
- // Abort early.
if (pass == RenderPass::Opaque) {
return;
}
- const auto& paint = layer.impl->paint;
const auto& layout = bucket.layout;
- context.depthMask = false;
-
- // TODO remove the `true ||` when #1673 is implemented
- const bool drawAcrossEdges = (frame.mapMode == MapMode::Continuous) && (true || !(layout.textAllowOverlap || layout.iconAllowOverlap ||
- layout.textIgnorePlacement || layout.iconIgnorePlacement));
-
- // Disable the stencil test so that labels aren't clipped to tile boundaries.
- //
- // Layers with features that may be drawn overlapping aren't clipped. These
- // layers are sorted in the y direction, and to draw the correct ordering near
- // tile edges the icons are included in both tiles and clipped when drawing.
- if (drawAcrossEdges) {
- context.stencilTest = false;
- } else {
- context.stencilOp = { gl::StencilTestOperation::Keep, gl::StencilTestOperation::Keep,
- gl::StencilTestOperation::Replace };
- context.stencilTest = true;
- }
+ frameHistory.bind(context, 1);
- setDepthSublayer(0);
+ auto draw = [&] (auto& program,
+ auto&& uniformValues,
+ const auto& buffers,
+ const SymbolPropertyValues& values_)
+ {
+ // We clip symbols to their tile extent in still mode.
+ const bool needsClipping = frame.mapMode == MapMode::Still;
+
+ program.draw(
+ context,
+ gl::Triangles(),
+ values_.pitchAlignment == AlignmentType::Map
+ ? depthModeForSublayer(0, gl::DepthMode::ReadOnly)
+ : gl::DepthMode::disabled(),
+ needsClipping
+ ? stencilModeForClipping(tile.clip)
+ : gl::StencilMode::disabled(),
+ colorModeForRenderPass(),
+ std::move(uniformValues),
+ *buffers.vertexBuffer,
+ *buffers.indexBuffer,
+ buffers.segments
+ );
+ };
if (bucket.hasIconData()) {
- if (layout.iconRotationAlignment == AlignmentType::Map) {
- context.depthFunc = gl::DepthTestFunction::LessEqual;
- context.depthTest = true;
- } else {
- context.depthTest = false;
- }
+ auto values = layer.impl->iconPropertyValues(layout);
- bool sdf = bucket.sdfIcons;
+ SpriteAtlas& atlas = *layer.impl->spriteAtlas;
+ const bool iconScaled = values.paintSize != 1.0f || frame.pixelRatio != atlas.getPixelRatio() || bucket.iconsNeedLinear;
+ const bool iconTransformed = values.rotationAlignment == AlignmentType::Map || state.getPitch() != 0;
+ atlas.bind(bucket.sdfIcons || state.isChanging() || iconScaled || iconTransformed, context, 0);
- const float angleOffset =
- layout.iconRotationAlignment == AlignmentType::Map
- ? state.getAngle()
- : 0;
+ const Size texsize = atlas.getSize();
- const float fontSize = layer.impl->iconSize;
- const float fontScale = fontSize / 1.0f;
-
- SpriteAtlas* activeSpriteAtlas = layer.impl->spriteAtlas;
- const bool iconScaled = fontScale != 1 || frame.pixelRatio != activeSpriteAtlas->getPixelRatio() || bucket.iconsNeedLinear;
- const bool iconTransformed = layout.iconRotationAlignment == AlignmentType::Map || angleOffset != 0 || state.getPitch() != 0;
- activeSpriteAtlas->bind(sdf || state.isChanging() || iconScaled || iconTransformed, context, 0);
-
- if (sdf) {
- renderSDF(bucket,
- tile,
- 1.0f,
- {{ float(activeSpriteAtlas->getWidth()) / 4.0f, float(activeSpriteAtlas->getHeight()) / 4.0f }},
- parameters.shaders.symbolIconSDF,
- &SymbolBucket::drawIcons,
- layout.iconRotationAlignment,
- // icon-pitch-alignment is not yet implemented
- // and we simply inherit the rotation alignment
- layout.iconRotationAlignment,
- layout.iconSize,
- paint.iconOpacity,
- paint.iconColor,
- paint.iconHaloColor,
- paint.iconHaloWidth,
- paint.iconHaloBlur,
- paint.iconTranslate,
- paint.iconTranslateAnchor,
- layer.impl->iconSize);
- } else {
- mat4 vtxMatrix = tile.translatedMatrix(paint.iconTranslate,
- paint.iconTranslateAnchor,
- state);
-
- std::array<float, 2> extrudeScale;
-
- const bool alignedWithMap = layout.iconRotationAlignment == AlignmentType::Map;
- if (alignedWithMap) {
- extrudeScale.fill(tile.id.pixelsToTileUnits(1, state.getZoom()) * fontScale);
- } else {
- extrudeScale = {{
- pixelsToGLUnits[0] * fontScale * state.getAltitude(),
- pixelsToGLUnits[1] * fontScale * state.getAltitude()
- }};
+ if (bucket.sdfIcons) {
+ if (values.hasHalo()) {
+ draw(parameters.programs.symbolIconSDF,
+ SymbolSDFProgram::haloUniformValues(values, texsize, pixelsToGLUnits, tile, state, frame.pixelRatio),
+ bucket.icon,
+ values);
}
- auto& iconShader = parameters.shaders.symbolIcon;
+ if (values.hasForeground()) {
+ draw(parameters.programs.symbolIconSDF,
+ SymbolSDFProgram::foregroundUniformValues(values, texsize, pixelsToGLUnits, tile, state, frame.pixelRatio),
+ bucket.icon,
+ values);
+ }
+ } else {
+ draw(parameters.programs.symbolIcon,
+ SymbolIconProgram::uniformValues(values, texsize, pixelsToGLUnits, tile, state),
+ bucket.icon,
+ values);
+ }
+ }
- context.program = iconShader.getID();
- iconShader.u_matrix = vtxMatrix;
- iconShader.u_extrude_scale = extrudeScale;
- iconShader.u_texsize = {{ float(activeSpriteAtlas->getWidth()) / 4.0f, float(activeSpriteAtlas->getHeight()) / 4.0f }};
- iconShader.u_rotate_with_map = alignedWithMap;
- iconShader.u_texture = 0;
+ if (bucket.hasTextData()) {
+ glyphAtlas->bind(context, 0);
- // adjust min/max zooms for variable font sies
- float zoomAdjust = std::log(fontSize / layout.iconSize) / std::log(2);
- iconShader.u_zoom = (state.getZoom() - zoomAdjust) * 10; // current zoom level
- iconShader.u_opacity = paint.iconOpacity;
+ auto values = layer.impl->textPropertyValues(layout);
- frameHistory.bind(context, 1);
- iconShader.u_fadetexture = 1;
+ const Size texsize = glyphAtlas->getSize();
- bucket.drawIcons(iconShader, context, paintMode());
+ if (values.hasHalo()) {
+ draw(parameters.programs.symbolGlyph,
+ SymbolSDFProgram::haloUniformValues(values, texsize, pixelsToGLUnits, tile, state, frame.pixelRatio),
+ bucket.text,
+ values);
}
- }
- if (bucket.hasTextData()) {
- if (layout.textPitchAlignment == AlignmentType::Map) {
- context.depthFunc = gl::DepthTestFunction::LessEqual;
- context.depthTest = true;
- } else {
- context.depthTest = false;
+ if (values.hasForeground()) {
+ draw(parameters.programs.symbolGlyph,
+ SymbolSDFProgram::foregroundUniformValues(values, texsize, pixelsToGLUnits, tile, state, frame.pixelRatio),
+ bucket.text,
+ values);
}
-
- glyphAtlas->bind(context, 0);
-
- renderSDF(bucket,
- tile,
- 24.0f,
- {{ float(glyphAtlas->width) / 4, float(glyphAtlas->height) / 4 }},
- parameters.shaders.symbolGlyph,
- &SymbolBucket::drawGlyphs,
- layout.textRotationAlignment,
- layout.textPitchAlignment,
- layout.textSize,
- paint.textOpacity,
- paint.textColor,
- paint.textHaloColor,
- paint.textHaloWidth,
- paint.textHaloBlur,
- paint.textTranslate,
- paint.textTranslateAnchor,
- layer.impl->textSize);
}
if (bucket.hasCollisionBoxData()) {
- context.stencilTest = false;
-
- auto& collisionBoxShader = shaders->collisionBox;
- context.program = collisionBoxShader.getID();
- collisionBoxShader.u_matrix = tile.matrix;
- // TODO: This was the overscaled z instead of the canonical z.
- collisionBoxShader.u_scale = std::pow(2, state.getZoom() - tile.id.canonical.z);
- collisionBoxShader.u_zoom = state.getZoom() * 10;
- collisionBoxShader.u_maxzoom = (tile.id.canonical.z + 1) * 10;
- context.lineWidth = 1.0f;
-
- bucket.drawCollisionBoxes(collisionBoxShader, context);
+ programs->collisionBox.draw(
+ context,
+ gl::Lines { 1.0f },
+ gl::DepthMode::disabled(),
+ gl::StencilMode::disabled(),
+ colorModeForRenderPass(),
+ CollisionBoxProgram::UniformValues {
+ uniforms::u_matrix::Value{ tile.matrix },
+ uniforms::u_scale::Value{ std::pow(2.0f, float(state.getZoom() - tile.tile.id.overscaledZ)) },
+ uniforms::u_zoom::Value{ float(state.getZoom() * 10) },
+ uniforms::u_maxzoom::Value{ float((tile.id.canonical.z + 1) * 10) },
+ },
+ *bucket.collisionBox.vertexBuffer,
+ *bucket.collisionBox.indexBuffer,
+ bucket.collisionBox.segments
+ );
}
}
diff --git a/src/mbgl/renderer/raster_bucket.cpp b/src/mbgl/renderer/raster_bucket.cpp
index 80d6dfe8dd..0355911296 100644
--- a/src/mbgl/renderer/raster_bucket.cpp
+++ b/src/mbgl/renderer/raster_bucket.cpp
@@ -1,8 +1,7 @@
#include <mbgl/renderer/raster_bucket.hpp>
#include <mbgl/style/layers/raster_layer.hpp>
-#include <mbgl/shader/raster_shader.hpp>
+#include <mbgl/programs/raster_program.hpp>
#include <mbgl/renderer/painter.hpp>
-#include <mbgl/gl/gl.hpp>
#include <mbgl/gl/context.hpp>
namespace mbgl {
@@ -25,23 +24,8 @@ void RasterBucket::render(Painter& painter,
painter.renderRaster(parameters, *this, *layer.as<RasterLayer>(), tile);
}
-void RasterBucket::drawRaster(RasterShader& shader,
- gl::VertexBuffer<RasterVertex>& vertices,
- gl::VertexArrayObject& array,
- gl::Context& context) {
- assert(texture);
- context.bindTexture(*texture, 0, gl::TextureFilter::Linear);
- context.bindTexture(*texture, 1, gl::TextureFilter::Linear);
- array.bind(shader, vertices, BUFFER_OFFSET_0, context);
- MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, static_cast<GLsizei>(vertices.vertexCount)));
-}
-
bool RasterBucket::hasData() const {
return true;
}
-bool RasterBucket::needsClipping() const {
- return false;
-}
-
} // namespace mbgl
diff --git a/src/mbgl/renderer/raster_bucket.hpp b/src/mbgl/renderer/raster_bucket.hpp
index b0d3ca49c7..9648e954bd 100644
--- a/src/mbgl/renderer/raster_bucket.hpp
+++ b/src/mbgl/renderer/raster_bucket.hpp
@@ -7,15 +7,6 @@
namespace mbgl {
-class RasterShader;
-class RasterVertex;
-
-namespace gl {
-class Context;
-template <class> class VertexBuffer;
-class VertexArrayObject;
-} // namespace gl
-
class RasterBucket : public Bucket {
public:
RasterBucket(PremultipliedImage&&);
@@ -23,11 +14,7 @@ public:
void upload(gl::Context&) override;
void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override;
bool hasData() const override;
- bool needsClipping() const override;
-
- void drawRaster(RasterShader&, gl::VertexBuffer<RasterVertex>&, gl::VertexArrayObject&, gl::Context&);
-private:
PremultipliedImage image;
optional<gl::Texture> texture;
};
diff --git a/src/mbgl/renderer/render_tile.hpp b/src/mbgl/renderer/render_tile.hpp
index 74669faaf9..e2e0c3d656 100644
--- a/src/mbgl/renderer/render_tile.hpp
+++ b/src/mbgl/renderer/render_tile.hpp
@@ -24,6 +24,7 @@ public:
Tile& tile;
ClipID clip;
mat4 matrix;
+ bool used = false;
mat4 translatedMatrix(const std::array<float, 2>& translate,
style::TranslateAnchorType anchor,
diff --git a/src/mbgl/renderer/symbol_bucket.cpp b/src/mbgl/renderer/symbol_bucket.cpp
index 565c58c7ed..0f2c89339f 100644
--- a/src/mbgl/renderer/symbol_bucket.cpp
+++ b/src/mbgl/renderer/symbol_bucket.cpp
@@ -1,17 +1,13 @@
#include <mbgl/renderer/symbol_bucket.hpp>
#include <mbgl/renderer/painter.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
-#include <mbgl/shader/symbol_sdf_shader.hpp>
-#include <mbgl/shader/symbol_icon_shader.hpp>
-#include <mbgl/shader/collision_box_shader.hpp>
-#include <mbgl/gl/gl.hpp>
namespace mbgl {
using namespace style;
SymbolBucket::SymbolBucket(const MapMode mode_,
- style::SymbolLayoutProperties layout_,
+ style::SymbolLayoutProperties::Evaluated layout_,
bool sdfIcons_,
bool iconsNeedLinear_)
: mode(mode_),
@@ -31,8 +27,9 @@ void SymbolBucket::upload(gl::Context& context) {
icon.indexBuffer = context.createIndexBuffer(std::move(icon.triangles));
}
- if (hasCollisionBoxData()) {
+ if (!collisionBox.vertices.empty()) {
collisionBox.vertexBuffer = context.createVertexBuffer(std::move(collisionBox.vertices));
+ collisionBox.indexBuffer = context.createIndexBuffer(std::move(collisionBox.lines));
}
uploaded = true;
@@ -46,79 +43,20 @@ void SymbolBucket::render(Painter& painter,
}
bool SymbolBucket::hasData() const {
- assert(false); // Should be calling SymbolLayout::hasSymbolInstances() instead.
+ assert(false); // Should be calling SymbolLayout::has{Text,Icon,CollisonBox}Data() instead.
return false;
}
bool SymbolBucket::hasTextData() const {
- return !text.groups.empty();
+ return !text.segments.empty();
}
bool SymbolBucket::hasIconData() const {
- return !icon.groups.empty();
+ return !icon.segments.empty();
}
bool SymbolBucket::hasCollisionBoxData() const {
- return !collisionBox.groups.empty();
-}
-
-bool SymbolBucket::needsClipping() const {
- return mode == MapMode::Still;
-}
-
-void SymbolBucket::drawGlyphs(SymbolSDFShader& shader,
- gl::Context& context,
- PaintMode paintMode) {
- GLbyte* vertex_index = BUFFER_OFFSET_0;
- GLbyte* elements_index = BUFFER_OFFSET_0;
- for (auto& group : text.groups) {
- group.getVAO(shader, paintMode).bind(
- shader, *text.vertexBuffer, *text.indexBuffer, vertex_index, context);
- MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(group.indexLength * 3), GL_UNSIGNED_SHORT,
- elements_index));
- vertex_index += group.vertexLength * text.vertexBuffer->vertexSize;
- elements_index += group.indexLength * text.indexBuffer->primitiveSize;
- }
-}
-
-void SymbolBucket::drawIcons(SymbolSDFShader& shader,
- gl::Context& context,
- PaintMode paintMode) {
- GLbyte* vertex_index = BUFFER_OFFSET_0;
- GLbyte* elements_index = BUFFER_OFFSET_0;
- for (auto& group : icon.groups) {
- group.getVAO(shader, paintMode).bind(
- shader, *icon.vertexBuffer, *icon.indexBuffer, vertex_index, context);
- MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(group.indexLength * 3), GL_UNSIGNED_SHORT,
- elements_index));
- vertex_index += group.vertexLength * icon.vertexBuffer->vertexSize;
- elements_index += group.indexLength * icon.indexBuffer->primitiveSize;
- }
-}
-
-void SymbolBucket::drawIcons(SymbolIconShader& shader,
- gl::Context& context,
- PaintMode paintMode) {
- GLbyte* vertex_index = BUFFER_OFFSET_0;
- GLbyte* elements_index = BUFFER_OFFSET_0;
- for (auto& group : icon.groups) {
- group.getVAO(shader, paintMode).bind(
- shader, *icon.vertexBuffer, *icon.indexBuffer, vertex_index, context);
- MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(group.indexLength * 3), GL_UNSIGNED_SHORT,
- elements_index));
- vertex_index += group.vertexLength * icon.vertexBuffer->vertexSize;
- elements_index += group.indexLength * icon.indexBuffer->primitiveSize;
- }
-}
-
-void SymbolBucket::drawCollisionBoxes(CollisionBoxShader& shader,
- gl::Context& context) {
- GLbyte* vertex_index = BUFFER_OFFSET_0;
- for (auto& group : collisionBox.groups) {
- group.getVAO(shader, PaintMode::Regular).bind(
- shader, *collisionBox.vertexBuffer, vertex_index, context);
- MBGL_CHECK_ERROR(glDrawArrays(GL_LINES, 0, static_cast<GLsizei>(group.vertexLength)));
- }
+ return !collisionBox.segments.empty();
}
} // namespace mbgl
diff --git a/src/mbgl/renderer/symbol_bucket.hpp b/src/mbgl/renderer/symbol_bucket.hpp
index e5180c31e2..d62a61aab7 100644
--- a/src/mbgl/renderer/symbol_bucket.hpp
+++ b/src/mbgl/renderer/symbol_bucket.hpp
@@ -1,28 +1,23 @@
#pragma once
#include <mbgl/renderer/bucket.hpp>
-#include <mbgl/renderer/element_group.hpp>
#include <mbgl/map/mode.hpp>
#include <mbgl/gl/vertex_buffer.hpp>
#include <mbgl/gl/index_buffer.hpp>
-#include <mbgl/shader/symbol_vertex.hpp>
-#include <mbgl/shader/collision_box_vertex.hpp>
+#include <mbgl/gl/segment.hpp>
+#include <mbgl/programs/symbol_program.hpp>
+#include <mbgl/programs/collision_box_program.hpp>
#include <mbgl/text/glyph_range.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
-#include <memory>
#include <vector>
namespace mbgl {
-class SymbolSDFShader;
-class SymbolIconShader;
-class CollisionBoxShader;
-
class SymbolBucket : public Bucket {
public:
SymbolBucket(const MapMode,
- style::SymbolLayoutProperties,
+ style::SymbolLayoutProperties::Evaluated,
bool sdfIcons,
bool iconsNeedLinear);
@@ -32,46 +27,37 @@ public:
bool hasTextData() const;
bool hasIconData() const;
bool hasCollisionBoxData() const;
- bool needsClipping() const override;
-
- void drawGlyphs(SymbolSDFShader&, gl::Context&, PaintMode);
- void drawIcons(SymbolSDFShader&, gl::Context&, PaintMode);
- void drawIcons(SymbolIconShader&, gl::Context&, PaintMode);
- void drawCollisionBoxes(CollisionBoxShader&, gl::Context&);
const MapMode mode;
- const style::SymbolLayoutProperties layout;
+ const style::SymbolLayoutProperties::Evaluated layout;
const bool sdfIcons;
const bool iconsNeedLinear;
-private:
- friend class SymbolLayout;
-
struct TextBuffer {
- std::vector<SymbolVertex> vertices;
- std::vector<gl::Triangle> triangles;
- std::vector<ElementGroup<SymbolSDFShader>> groups;
+ gl::VertexVector<SymbolVertex> vertices;
+ gl::IndexVector<gl::Triangles> triangles;
+ gl::SegmentVector<SymbolAttributes> segments;
optional<gl::VertexBuffer<SymbolVertex>> vertexBuffer;
- optional<gl::IndexBuffer<gl::Triangle>> indexBuffer;
+ optional<gl::IndexBuffer<gl::Triangles>> indexBuffer;
} text;
struct IconBuffer {
- std::vector<SymbolVertex> vertices;
- std::vector<gl::Triangle> triangles;
- std::vector<ElementGroup<SymbolSDFShader, SymbolIconShader>> groups;
+ gl::VertexVector<SymbolVertex> vertices;
+ gl::IndexVector<gl::Triangles> triangles;
+ gl::SegmentVector<SymbolAttributes> segments;
optional<gl::VertexBuffer<SymbolVertex>> vertexBuffer;
- optional<gl::IndexBuffer<gl::Triangle>> indexBuffer;
+ optional<gl::IndexBuffer<gl::Triangles>> indexBuffer;
} icon;
struct CollisionBoxBuffer {
- std::vector<CollisionBoxVertex> vertices;
- std::vector<gl::Line> lines;
- std::vector<ElementGroup<CollisionBoxShader>> groups;
+ gl::VertexVector<CollisionBoxVertex> vertices;
+ gl::IndexVector<gl::Lines> lines;
+ gl::SegmentVector<CollisionBoxAttributes> segments;
optional<gl::VertexBuffer<CollisionBoxVertex>> vertexBuffer;
- optional<gl::IndexBuffer<gl::Line>> indexBuffer;
+ optional<gl::IndexBuffer<gl::Lines>> indexBuffer;
} collisionBox;
};
diff --git a/src/mbgl/shader/circle_shader.cpp b/src/mbgl/shader/circle_shader.cpp
deleted file mode 100644
index 9e294f8d76..0000000000
--- a/src/mbgl/shader/circle_shader.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#include <mbgl/shader/circle_shader.hpp>
-#include <mbgl/shader/circle.vertex.hpp>
-#include <mbgl/shader/circle.fragment.hpp>
-#include <mbgl/shader/circle_vertex.hpp>
-
-namespace mbgl {
-
-CircleShader::CircleShader(gl::Context& context, Defines defines)
- : Shader(shaders::circle::name,
- shaders::circle::vertex,
- shaders::circle::fragment,
- context, defines) {
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/circle_shader.hpp b/src/mbgl/shader/circle_shader.hpp
deleted file mode 100644
index c2c4053ba4..0000000000
--- a/src/mbgl/shader/circle_shader.hpp
+++ /dev/null
@@ -1,30 +0,0 @@
-#pragma once
-
-#include <mbgl/gl/shader.hpp>
-#include <mbgl/gl/attribute.hpp>
-#include <mbgl/gl/uniform.hpp>
-#include <mbgl/util/color.hpp>
-
-namespace mbgl {
-
-class CircleVertex;
-
-class CircleShader : public gl::Shader {
-public:
- CircleShader(gl::Context&, Defines defines = None);
-
- using VertexType = CircleVertex;
-
- gl::Attribute<int16_t, 2> a_pos = {"a_pos", *this};
-
- gl::UniformMatrix<4> u_matrix = {"u_matrix", *this};
- gl::Uniform<std::array<float, 2>> u_extrude_scale = {"u_extrude_scale", *this};
- gl::Uniform<float> u_devicepixelratio = {"u_devicepixelratio", *this};
- gl::Uniform<Color> u_color = {"u_color", *this};
- gl::Uniform<float> u_radius = {"u_radius", *this};
- gl::Uniform<float> u_blur = {"u_blur", *this};
- gl::Uniform<float> u_opacity = {"u_opacity", *this};
- gl::Uniform<int32_t> u_scale_with_map = {"u_scale_with_map", *this};
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/circle_vertex.cpp b/src/mbgl/shader/circle_vertex.cpp
deleted file mode 100644
index 8beb88e650..0000000000
--- a/src/mbgl/shader/circle_vertex.cpp
+++ /dev/null
@@ -1,7 +0,0 @@
-#include <mbgl/shader/circle_vertex.hpp>
-
-namespace mbgl {
-
-static_assert(sizeof(CircleVertex) == 4, "expected CircleVertex size");
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/circle_vertex.hpp b/src/mbgl/shader/circle_vertex.hpp
deleted file mode 100644
index 4fce49f137..0000000000
--- a/src/mbgl/shader/circle_vertex.hpp
+++ /dev/null
@@ -1,39 +0,0 @@
-#pragma once
-
-#include <mbgl/gl/attribute.hpp>
-
-#include <array>
-#include <cstdint>
-
-namespace mbgl {
-
-class CircleVertex {
-public:
- /*
- * @param {number} x vertex position
- * @param {number} y vertex position
- * @param {number} ex extrude normal
- * @param {number} ey extrude normal
- */
- CircleVertex(int16_t x, int16_t y, float ex, float ey)
- : a_pos {
- static_cast<int16_t>((x * 2) + ((ex + 1) / 2)),
- static_cast<int16_t>((y * 2) + ((ey + 1) / 2))
- } {}
-
- const int16_t a_pos[2];
-};
-
-namespace gl {
-
-template <class Shader>
-struct AttributeBindings<Shader, CircleVertex> {
- std::array<AttributeBinding, 1> operator()(const Shader& shader) {
- return {{
- MBGL_MAKE_ATTRIBUTE_BINDING(CircleVertex, shader, a_pos)
- }};
- };
-};
-
-} // namespace gl
-} // namespace mbgl
diff --git a/src/mbgl/shader/collision_box_shader.cpp b/src/mbgl/shader/collision_box_shader.cpp
deleted file mode 100644
index d61c849cd1..0000000000
--- a/src/mbgl/shader/collision_box_shader.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#include <mbgl/shader/collision_box_shader.hpp>
-#include <mbgl/shader/collision_box.vertex.hpp>
-#include <mbgl/shader/collision_box.fragment.hpp>
-#include <mbgl/shader/collision_box_vertex.hpp>
-
-namespace mbgl {
-
-CollisionBoxShader::CollisionBoxShader(gl::Context& context)
- : Shader(shaders::collision_box::name,
- shaders::collision_box::vertex,
- shaders::collision_box::fragment,
- context) {
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/collision_box_shader.hpp b/src/mbgl/shader/collision_box_shader.hpp
deleted file mode 100644
index 2f5c506168..0000000000
--- a/src/mbgl/shader/collision_box_shader.hpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#pragma once
-
-#include <mbgl/gl/shader.hpp>
-#include <mbgl/gl/attribute.hpp>
-#include <mbgl/gl/uniform.hpp>
-
-namespace mbgl {
-
-class CollisionBoxVertex;
-
-class CollisionBoxShader : public gl::Shader {
-public:
- CollisionBoxShader(gl::Context&);
-
- using VertexType = CollisionBoxVertex;
-
- gl::Attribute<int16_t, 2> a_pos = {"a_pos", *this};
- gl::Attribute<int16_t, 2> a_extrude = {"a_extrude", *this};
- gl::Attribute<uint8_t, 2> a_data = {"a_data", *this};
-
- gl::UniformMatrix<4> u_matrix = {"u_matrix", *this};
- gl::Uniform<float> u_scale = {"u_scale", *this};
- gl::Uniform<float> u_zoom = {"u_zoom", *this};
- gl::Uniform<float> u_maxzoom = {"u_maxzoom", *this};
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/collision_box_vertex.cpp b/src/mbgl/shader/collision_box_vertex.cpp
deleted file mode 100644
index 397fbfe6a3..0000000000
--- a/src/mbgl/shader/collision_box_vertex.cpp
+++ /dev/null
@@ -1,7 +0,0 @@
-#include <mbgl/shader/collision_box_vertex.hpp>
-
-namespace mbgl {
-
-static_assert(sizeof(CollisionBoxVertex) == 10, "expected CollisionBoxVertex size");
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/collision_box_vertex.hpp b/src/mbgl/shader/collision_box_vertex.hpp
deleted file mode 100644
index ba72b1c0ee..0000000000
--- a/src/mbgl/shader/collision_box_vertex.hpp
+++ /dev/null
@@ -1,43 +0,0 @@
-#pragma once
-
-#include <mbgl/gl/attribute.hpp>
-
-#include <array>
-#include <cstdint>
-#include <cmath>
-
-namespace mbgl {
-
-class CollisionBoxVertex {
-public:
- CollisionBoxVertex(int16_t x, int16_t y, float ox, float oy, float maxzoom, float placementZoom)
- : a_pos { x, y },
- a_extrude {
- static_cast<int16_t>(::round(ox)),
- static_cast<int16_t>(::round(oy))
- },
- a_data {
- static_cast<uint8_t>(maxzoom * 10),
- static_cast<uint8_t>(placementZoom * 10)
- } {}
-
- const int16_t a_pos[2];
- const int16_t a_extrude[2];
- const uint8_t a_data[2];
-};
-
-namespace gl {
-
-template <class Shader>
-struct AttributeBindings<Shader, CollisionBoxVertex> {
- std::array<AttributeBinding, 3> operator()(const Shader& shader) {
- return {{
- MBGL_MAKE_ATTRIBUTE_BINDING(CollisionBoxVertex, shader, a_pos),
- MBGL_MAKE_ATTRIBUTE_BINDING(CollisionBoxVertex, shader, a_extrude),
- MBGL_MAKE_ATTRIBUTE_BINDING(CollisionBoxVertex, shader, a_data)
- }};
- };
-};
-
-} // namespace gl
-} // namespace mbgl
diff --git a/src/mbgl/shader/fill_outline_pattern_shader.cpp b/src/mbgl/shader/fill_outline_pattern_shader.cpp
deleted file mode 100644
index b03921d384..0000000000
--- a/src/mbgl/shader/fill_outline_pattern_shader.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#include <mbgl/shader/fill_outline_pattern_shader.hpp>
-#include <mbgl/shader/fill_outline_pattern.vertex.hpp>
-#include <mbgl/shader/fill_outline_pattern.fragment.hpp>
-#include <mbgl/shader/fill_vertex.hpp>
-
-namespace mbgl {
-
-FillOutlinePatternShader::FillOutlinePatternShader(gl::Context& context, Defines defines)
- : Shader(shaders::fill_outline_pattern::name,
- shaders::fill_outline_pattern::vertex,
- shaders::fill_outline_pattern::fragment,
- context, defines) {
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/fill_outline_pattern_shader.hpp b/src/mbgl/shader/fill_outline_pattern_shader.hpp
deleted file mode 100644
index 630e6a7ce8..0000000000
--- a/src/mbgl/shader/fill_outline_pattern_shader.hpp
+++ /dev/null
@@ -1,37 +0,0 @@
-#pragma once
-
-#include <mbgl/gl/shader.hpp>
-#include <mbgl/gl/attribute.hpp>
-#include <mbgl/gl/uniform.hpp>
-
-namespace mbgl {
-
-class FillVertex;
-
-class FillOutlinePatternShader : public gl::Shader {
-public:
- FillOutlinePatternShader(gl::Context&, Defines defines = None);
-
- using VertexType = FillVertex;
-
- gl::Attribute<int16_t, 2> a_pos = {"a_pos", *this};
-
- gl::UniformMatrix<4> u_matrix = {"u_matrix", *this};
- gl::Uniform<std::array<float, 2>> u_pattern_tl_a = {"u_pattern_tl_a", *this};
- gl::Uniform<std::array<float, 2>> u_pattern_br_a = {"u_pattern_br_a", *this};
- gl::Uniform<std::array<float, 2>> u_pattern_tl_b = {"u_pattern_tl_b", *this};
- gl::Uniform<std::array<float, 2>> u_pattern_br_b = {"u_pattern_br_b", *this};
- gl::Uniform<float> u_opacity = {"u_opacity", *this};
- gl::Uniform<float> u_mix = {"u_mix", *this};
- gl::Uniform<float> u_scale_a = {"u_scale_a", *this};
- gl::Uniform<float> u_scale_b = {"u_scale_b", *this};
- gl::Uniform<float> u_tile_units_to_pixels = {"u_tile_units_to_pixels", *this};
- gl::Uniform<int32_t> u_image = {"u_image", *this};
- gl::Uniform<std::array<float, 2>> u_pattern_size_a = {"u_pattern_size_a", *this};
- gl::Uniform<std::array<float, 2>> u_pattern_size_b = {"u_pattern_size_b", *this};
- gl::Uniform<std::array<float, 2>> u_pixel_coord_upper = {"u_pixel_coord_upper", *this};
- gl::Uniform<std::array<float, 2>> u_pixel_coord_lower = {"u_pixel_coord_lower", *this};
- gl::Uniform<std::array<float, 2>> u_world = {"u_world", *this};
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/fill_outline_shader.cpp b/src/mbgl/shader/fill_outline_shader.cpp
deleted file mode 100644
index 6e6d8c2239..0000000000
--- a/src/mbgl/shader/fill_outline_shader.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#include <mbgl/shader/fill_outline_shader.hpp>
-#include <mbgl/shader/fill_outline.vertex.hpp>
-#include <mbgl/shader/fill_outline.fragment.hpp>
-#include <mbgl/shader/fill_vertex.hpp>
-
-namespace mbgl {
-
-FillOutlineShader::FillOutlineShader(gl::Context& context, Defines defines)
- : Shader(shaders::fill_outline::name,
- shaders::fill_outline::vertex,
- shaders::fill_outline::fragment,
- context, defines) {
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/fill_outline_shader.hpp b/src/mbgl/shader/fill_outline_shader.hpp
deleted file mode 100644
index c20bc187d3..0000000000
--- a/src/mbgl/shader/fill_outline_shader.hpp
+++ /dev/null
@@ -1,26 +0,0 @@
-#pragma once
-
-#include <mbgl/gl/shader.hpp>
-#include <mbgl/gl/attribute.hpp>
-#include <mbgl/gl/uniform.hpp>
-#include <mbgl/util/color.hpp>
-
-namespace mbgl {
-
-class FillVertex;
-
-class FillOutlineShader : public gl::Shader {
-public:
- FillOutlineShader(gl::Context&, Defines defines = None);
-
- using VertexType = FillVertex;
-
- gl::Attribute<int16_t, 2> a_pos = {"a_pos", *this};
-
- gl::UniformMatrix<4> u_matrix = {"u_matrix", *this};
- gl::Uniform<Color> u_outline_color = {"u_outline_color", *this};
- gl::Uniform<float> u_opacity = {"u_opacity", *this};
- gl::Uniform<std::array<float, 2>> u_world = {"u_world", *this};
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/fill_pattern_shader.cpp b/src/mbgl/shader/fill_pattern_shader.cpp
deleted file mode 100644
index 60be6d79ad..0000000000
--- a/src/mbgl/shader/fill_pattern_shader.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#include <mbgl/shader/fill_pattern_shader.hpp>
-#include <mbgl/shader/fill_pattern.vertex.hpp>
-#include <mbgl/shader/fill_pattern.fragment.hpp>
-#include <mbgl/shader/fill_vertex.hpp>
-
-namespace mbgl {
-
-FillPatternShader::FillPatternShader(gl::Context& context, Defines defines)
- : Shader(shaders::fill_pattern::name,
- shaders::fill_pattern::vertex,
- shaders::fill_pattern::fragment,
- context, defines) {
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/fill_pattern_shader.hpp b/src/mbgl/shader/fill_pattern_shader.hpp
deleted file mode 100644
index 36be538000..0000000000
--- a/src/mbgl/shader/fill_pattern_shader.hpp
+++ /dev/null
@@ -1,36 +0,0 @@
-#pragma once
-
-#include <mbgl/gl/shader.hpp>
-#include <mbgl/gl/attribute.hpp>
-#include <mbgl/gl/uniform.hpp>
-
-namespace mbgl {
-
-class FillVertex;
-
-class FillPatternShader : public gl::Shader {
-public:
- FillPatternShader(gl::Context&, Defines defines = None);
-
- using VertexType = FillVertex;
-
- gl::Attribute<int16_t, 2> a_pos = {"a_pos", *this};
-
- gl::UniformMatrix<4> u_matrix = {"u_matrix", *this};
- gl::Uniform<std::array<float, 2>> u_pattern_tl_a = {"u_pattern_tl_a", *this};
- gl::Uniform<std::array<float, 2>> u_pattern_br_a = {"u_pattern_br_a", *this};
- gl::Uniform<std::array<float, 2>> u_pattern_tl_b = {"u_pattern_tl_b", *this};
- gl::Uniform<std::array<float, 2>> u_pattern_br_b = {"u_pattern_br_b", *this};
- gl::Uniform<float> u_opacity = {"u_opacity", *this};
- gl::Uniform<float> u_mix = {"u_mix", *this};
- gl::Uniform<float> u_scale_a = {"u_scale_a", *this};
- gl::Uniform<float> u_scale_b = {"u_scale_b", *this};
- gl::Uniform<float> u_tile_units_to_pixels = {"u_tile_units_to_pixels", *this};
- gl::Uniform<int32_t> u_image = {"u_image", *this};
- gl::Uniform<std::array<float, 2>> u_pattern_size_a = {"u_pattern_size_a", *this};
- gl::Uniform<std::array<float, 2>> u_pattern_size_b = {"u_pattern_size_b", *this};
- gl::Uniform<std::array<float, 2>> u_pixel_coord_upper = {"u_pixel_coord_upper", *this};
- gl::Uniform<std::array<float, 2>> u_pixel_coord_lower = {"u_pixel_coord_lower", *this};
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/fill_shader.cpp b/src/mbgl/shader/fill_shader.cpp
deleted file mode 100644
index 7026bb2f1c..0000000000
--- a/src/mbgl/shader/fill_shader.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#include <mbgl/shader/fill_shader.hpp>
-#include <mbgl/shader/fill.vertex.hpp>
-#include <mbgl/shader/fill.fragment.hpp>
-#include <mbgl/shader/fill_vertex.hpp>
-
-namespace mbgl {
-
-FillShader::FillShader(gl::Context& context, Defines defines)
- : Shader(shaders::fill::name,
- shaders::fill::vertex,
- shaders::fill::fragment,
- context, defines) {
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/fill_shader.hpp b/src/mbgl/shader/fill_shader.hpp
deleted file mode 100644
index 1240b73aa2..0000000000
--- a/src/mbgl/shader/fill_shader.hpp
+++ /dev/null
@@ -1,25 +0,0 @@
-#pragma once
-
-#include <mbgl/gl/shader.hpp>
-#include <mbgl/gl/attribute.hpp>
-#include <mbgl/gl/uniform.hpp>
-#include <mbgl/util/color.hpp>
-
-namespace mbgl {
-
-class FillVertex;
-
-class FillShader : public gl::Shader {
-public:
- FillShader(gl::Context&, Defines defines = None);
-
- using VertexType = FillVertex;
-
- gl::Attribute<int16_t, 2> a_pos = {"a_pos", *this};
-
- gl::UniformMatrix<4> u_matrix = {"u_matrix", *this};
- gl::Uniform<Color> u_color = {"u_color", *this};
- gl::Uniform<float> u_opacity = {"u_opacity", *this};
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/fill_vertex.cpp b/src/mbgl/shader/fill_vertex.cpp
deleted file mode 100644
index c39a0b96b1..0000000000
--- a/src/mbgl/shader/fill_vertex.cpp
+++ /dev/null
@@ -1,7 +0,0 @@
-#include <mbgl/shader/fill_vertex.hpp>
-
-namespace mbgl {
-
-static_assert(sizeof(FillVertex) == 4, "expected FillVertex size");
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/fill_vertex.hpp b/src/mbgl/shader/fill_vertex.hpp
deleted file mode 100644
index 1b8130382a..0000000000
--- a/src/mbgl/shader/fill_vertex.hpp
+++ /dev/null
@@ -1,30 +0,0 @@
-#pragma once
-
-#include <mbgl/gl/attribute.hpp>
-
-#include <array>
-#include <cstdint>
-
-namespace mbgl {
-
-class FillVertex {
-public:
- FillVertex(int16_t x, int16_t y)
- : a_pos { x, y } {}
-
- const int16_t a_pos[2];
-};
-
-namespace gl {
-
-template <class Shader>
-struct AttributeBindings<Shader, FillVertex> {
- std::array<AttributeBinding, 1> operator()(const Shader& shader) {
- return {{
- MBGL_MAKE_ATTRIBUTE_BINDING(FillVertex, shader, a_pos)
- }};
- };
-};
-
-} // namespace gl
-} // namespace mbgl
diff --git a/src/mbgl/shader/line_pattern_shader.cpp b/src/mbgl/shader/line_pattern_shader.cpp
deleted file mode 100644
index e6bc32a5c9..0000000000
--- a/src/mbgl/shader/line_pattern_shader.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#include <mbgl/shader/line_pattern_shader.hpp>
-#include <mbgl/shader/line_pattern.vertex.hpp>
-#include <mbgl/shader/line_pattern.fragment.hpp>
-#include <mbgl/shader/line_vertex.hpp>
-
-namespace mbgl {
-
-LinePatternShader::LinePatternShader(gl::Context& context, Defines defines)
- : Shader(shaders::line_pattern::name,
- shaders::line_pattern::vertex,
- shaders::line_pattern::fragment,
- context, defines) {
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/line_pattern_shader.hpp b/src/mbgl/shader/line_pattern_shader.hpp
deleted file mode 100644
index 1bd6085c8b..0000000000
--- a/src/mbgl/shader/line_pattern_shader.hpp
+++ /dev/null
@@ -1,41 +0,0 @@
-#pragma once
-
-#include <mbgl/gl/shader.hpp>
-#include <mbgl/gl/uniform.hpp>
-#include <mbgl/gl/attribute.hpp>
-
-namespace mbgl {
-
-class LineVertex;
-
-class LinePatternShader : public gl::Shader {
-public:
- LinePatternShader(gl::Context&, Defines defines = None);
-
- using VertexType = LineVertex;
-
- gl::Attribute<int16_t, 2> a_pos = { "a_pos", *this };
- gl::Attribute<uint8_t, 4> a_data = { "a_data", *this };
-
- gl::UniformMatrix<4> u_matrix = {"u_matrix", *this};
- gl::Uniform<float> u_linewidth = {"u_linewidth", *this};
- gl::Uniform<float> u_gapwidth = {"u_gapwidth", *this};
- gl::Uniform<float> u_antialiasing = {"u_antialiasing", *this};
- gl::Uniform<std::array<float, 2>> u_pattern_size_a = {"u_pattern_size_a", *this};
- gl::Uniform<std::array<float, 2>> u_pattern_tl_a = {"u_pattern_tl_a", *this};
- gl::Uniform<std::array<float, 2>> u_pattern_br_a = {"u_pattern_br_a", *this};
- gl::Uniform<std::array<float, 2>> u_pattern_size_b = {"u_pattern_size_b", *this};
- gl::Uniform<std::array<float, 2>> u_pattern_tl_b = {"u_pattern_tl_b", *this};
- gl::Uniform<std::array<float, 2>> u_pattern_br_b = {"u_pattern_br_b", *this};
- gl::Uniform<float> u_ratio = {"u_ratio", *this};
- gl::Uniform<float> u_point = {"u_point", *this};
- gl::Uniform<float> u_blur = {"u_blur", *this};
- gl::Uniform<float> u_fade = {"u_fade", *this};
- gl::Uniform<float> u_opacity = {"u_opacity", *this};
- gl::Uniform<float> u_extra = {"u_extra", *this};
- gl::Uniform<float> u_offset = {"u_offset", *this};
- gl::Uniform<int32_t> u_image = {"u_image", *this};
- gl::UniformMatrix<2> u_antialiasingmatrix = {"u_antialiasingmatrix", *this};
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/line_sdf_shader.cpp b/src/mbgl/shader/line_sdf_shader.cpp
deleted file mode 100644
index dd724365ea..0000000000
--- a/src/mbgl/shader/line_sdf_shader.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#include <mbgl/shader/line_sdf_shader.hpp>
-#include <mbgl/shader/line_sdf.vertex.hpp>
-#include <mbgl/shader/line_sdf.fragment.hpp>
-#include <mbgl/shader/line_vertex.hpp>
-
-namespace mbgl {
-
-LineSDFShader::LineSDFShader(gl::Context& context, Defines defines)
- : Shader(shaders::line_sdf::name,
- shaders::line_sdf::vertex,
- shaders::line_sdf::fragment,
- context, defines) {
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/line_sdf_shader.hpp b/src/mbgl/shader/line_sdf_shader.hpp
deleted file mode 100644
index d74e42e50f..0000000000
--- a/src/mbgl/shader/line_sdf_shader.hpp
+++ /dev/null
@@ -1,42 +0,0 @@
-#pragma once
-
-#include <mbgl/gl/shader.hpp>
-#include <mbgl/gl/attribute.hpp>
-#include <mbgl/gl/uniform.hpp>
-#include <mbgl/util/color.hpp>
-
-namespace mbgl {
-
-class LineVertex;
-
-class LineSDFShader : public gl::Shader {
-public:
- LineSDFShader(gl::Context&, Defines defines = None);
-
- using VertexType = LineVertex;
-
- gl::Attribute<int16_t, 2> a_pos = { "a_pos", *this };
- gl::Attribute<uint8_t, 4> a_data = { "a_data", *this };
-
- gl::UniformMatrix<4> u_matrix = {"u_matrix", *this};
- gl::Uniform<Color> u_color = {"u_color", *this};
- gl::Uniform<float> u_opacity = {"u_opacity", *this};
- gl::Uniform<float> u_linewidth = {"u_linewidth", *this};
- gl::Uniform<float> u_gapwidth = {"u_gapwidth", *this};
- gl::Uniform<float> u_antialiasing = {"u_antialiasing", *this};
- gl::Uniform<float> u_ratio = {"u_ratio", *this};
- gl::Uniform<float> u_blur = {"u_blur", *this};
- gl::Uniform<std::array<float, 2>> u_patternscale_a = { "u_patternscale_a", *this};
- gl::Uniform<float> u_tex_y_a = {"u_tex_y_a", *this};
- gl::Uniform<std::array<float, 2>> u_patternscale_b = { "u_patternscale_b", *this};
- gl::Uniform<float> u_tex_y_b = {"u_tex_y_b", *this};
- gl::Uniform<int32_t> u_image = {"u_image", *this};
- gl::Uniform<float> u_sdfgamma = {"u_sdfgamma", *this};
- gl::Uniform<float> u_mix = {"u_mix", *this};
- gl::Uniform<float> u_extra = {"u_extra", *this};
- gl::Uniform<float> u_offset = {"u_offset", *this};
- gl::UniformMatrix<2> u_antialiasingmatrix = {"u_antialiasingmatrix", *this};
-};
-
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/line_shader.cpp b/src/mbgl/shader/line_shader.cpp
deleted file mode 100644
index 4e934cd60c..0000000000
--- a/src/mbgl/shader/line_shader.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#include <mbgl/shader/line_shader.hpp>
-#include <mbgl/shader/line.vertex.hpp>
-#include <mbgl/shader/line.fragment.hpp>
-#include <mbgl/shader/line_vertex.hpp>
-
-namespace mbgl {
-
-LineShader::LineShader(gl::Context& context, Defines defines)
- : Shader(shaders::line::name,
- shaders::line::vertex,
- shaders::line::fragment,
- context, defines) {
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/line_shader.hpp b/src/mbgl/shader/line_shader.hpp
deleted file mode 100644
index 79991e1883..0000000000
--- a/src/mbgl/shader/line_shader.hpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#pragma once
-
-#include <mbgl/gl/shader.hpp>
-#include <mbgl/gl/attribute.hpp>
-#include <mbgl/gl/uniform.hpp>
-#include <mbgl/util/color.hpp>
-
-namespace mbgl {
-
-class LineVertex;
-
-class LineShader : public gl::Shader {
-public:
- LineShader(gl::Context&, Defines defines = None);
-
- using VertexType = LineVertex;
-
- gl::Attribute<int16_t, 2> a_pos = { "a_pos", *this };
- gl::Attribute<uint8_t, 4> a_data = { "a_data", *this };
-
- gl::UniformMatrix<4> u_matrix = {"u_matrix", *this};
- gl::Uniform<Color> u_color = {"u_color", *this};
- gl::Uniform<float> u_opacity = {"u_opacity", *this};
- gl::Uniform<float> u_ratio = {"u_ratio", *this};
- gl::Uniform<float> u_linewidth = {"u_linewidth", *this};
- gl::Uniform<float> u_gapwidth = {"u_gapwidth", *this};
- gl::Uniform<float> u_antialiasing = {"u_antialiasing", *this};
- gl::Uniform<float> u_blur = {"u_blur", *this};
- gl::Uniform<float> u_extra = {"u_extra", *this};
- gl::Uniform<float> u_offset = {"u_offset", *this};
- gl::UniformMatrix<2> u_antialiasingmatrix = {"u_antialiasingmatrix", *this};
-};
-
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/line_vertex.cpp b/src/mbgl/shader/line_vertex.cpp
deleted file mode 100644
index ad466310d8..0000000000
--- a/src/mbgl/shader/line_vertex.cpp
+++ /dev/null
@@ -1,7 +0,0 @@
-#include <mbgl/shader/line_vertex.hpp>
-
-namespace mbgl {
-
-static_assert(sizeof(LineVertex) == 8, "expected LineVertex size");
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/line_vertex.hpp b/src/mbgl/shader/line_vertex.hpp
deleted file mode 100644
index 086100810e..0000000000
--- a/src/mbgl/shader/line_vertex.hpp
+++ /dev/null
@@ -1,72 +0,0 @@
-#pragma once
-
-#include <mbgl/gl/attribute.hpp>
-
-#include <array>
-#include <cstdint>
-#include <cmath>
-
-namespace mbgl {
-
-class LineVertex {
-public:
- /*
- * @param {number} x vertex position
- * @param {number} y vertex position
- * @param {number} ex extrude normal
- * @param {number} ey extrude normal
- * @param {number} tx texture normal
- * @param {number} ty texture normal
- * @param {number} dir direction of the line cap (-1/0/1)
- */
- LineVertex(int16_t x, int16_t y, float ex, float ey, bool tx, bool ty, int8_t dir, int32_t linesofar = 0)
- : a_pos {
- static_cast<int16_t>((x * 2) | tx),
- static_cast<int16_t>((y * 2) | ty)
- },
- a_data {
- // add 128 to store an byte in an unsigned byte
- static_cast<uint8_t>(::round(extrudeScale * ex) + 128),
- static_cast<uint8_t>(::round(extrudeScale * ey) + 128),
-
- // Encode the -1/0/1 direction value into the first two bits of .z of a_data.
- // Combine it with the lower 6 bits of `linesofar` (shifted by 2 bites to make
- // room for the direction value). The upper 8 bits of `linesofar` are placed in
- // the `w` component. `linesofar` is scaled down by `LINE_DISTANCE_SCALE` so that
- // we can store longer distances while sacrificing precision.
-
- // Encode the -1/0/1 direction value into .zw coordinates of a_data, which is normally covered
- // by linesofar, so we need to merge them.
- // The z component's first bit, as well as the sign bit is reserved for the direction,
- // so we need to shift the linesofar.
- static_cast<uint8_t>(((dir == 0 ? 0 : (dir < 0 ? -1 : 1 )) + 1) | ((linesofar & 0x3F) << 2)),
- static_cast<uint8_t>(linesofar >> 6)
- } {}
-
- const int16_t a_pos[2];
- const uint8_t a_data[4];
-
- /*
- * Scale the extrusion vector so that the normal length is this value.
- * Contains the "texture" normals (-1..1). This is distinct from the extrude
- * normals for line joins, because the x-value remains 0 for the texture
- * normal array, while the extrude normal actually moves the vertex to create
- * the acute/bevelled line join.
- */
- static const int8_t extrudeScale = 63;
-};
-
-namespace gl {
-
-template <class Shader>
-struct AttributeBindings<Shader, LineVertex> {
- std::array<AttributeBinding, 2> operator()(const Shader& shader) {
- return {{
- MBGL_MAKE_ATTRIBUTE_BINDING(LineVertex, shader, a_pos),
- MBGL_MAKE_ATTRIBUTE_BINDING(LineVertex, shader, a_data)
- }};
- };
-};
-
-} // namespace gl
-} // namespace mbgl
diff --git a/src/mbgl/shader/raster_shader.cpp b/src/mbgl/shader/raster_shader.cpp
deleted file mode 100644
index 34b2bdf47b..0000000000
--- a/src/mbgl/shader/raster_shader.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#include <mbgl/shader/raster_shader.hpp>
-#include <mbgl/shader/raster.vertex.hpp>
-#include <mbgl/shader/raster.fragment.hpp>
-#include <mbgl/shader/raster_vertex.hpp>
-
-namespace mbgl {
-
-RasterShader::RasterShader(gl::Context& context, Defines defines)
- : Shader(shaders::raster::name,
- shaders::raster::vertex,
- shaders::raster::fragment,
- context, defines) {
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/raster_shader.hpp b/src/mbgl/shader/raster_shader.hpp
deleted file mode 100644
index 9633fd5fa0..0000000000
--- a/src/mbgl/shader/raster_shader.hpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#pragma once
-
-#include <mbgl/gl/shader.hpp>
-#include <mbgl/gl/attribute.hpp>
-#include <mbgl/gl/uniform.hpp>
-
-namespace mbgl {
-
-class RasterVertex;
-
-class RasterShader : public gl::Shader {
-public:
- RasterShader(gl::Context&, Defines defines = None);
-
- using VertexType = RasterVertex;
-
- gl::Attribute<int16_t, 2> a_pos = { "a_pos", *this };
- gl::Attribute<uint16_t, 2> a_texture_pos = { "a_texture_pos", *this };
-
- gl::UniformMatrix<4> u_matrix = {"u_matrix", *this};
- gl::Uniform<int32_t> u_image0 = {"u_image0", *this};
- gl::Uniform<int32_t> u_image1 = {"u_image1", *this};
- gl::Uniform<float> u_opacity0 = {"u_opacity0", *this};
- gl::Uniform<float> u_opacity1 = {"u_opacity1", *this};
- gl::Uniform<float> u_buffer_scale = {"u_buffer_scale", *this};
- gl::Uniform<float> u_brightness_low = {"u_brightness_low", *this};
- gl::Uniform<float> u_brightness_high = {"u_brightness_high", *this};
- gl::Uniform<float> u_saturation_factor = {"u_saturation_factor", *this};
- gl::Uniform<float> u_contrast_factor = {"u_contrast_factor", *this};
- gl::Uniform<std::array<float, 3>> u_spin_weights = {"u_spin_weights", *this};
- gl::Uniform<std::array<float, 2>> u_tl_parent = {"u_tl_parent", *this};
- gl::Uniform<float> u_scale_parent = {"u_scale_parent", *this};
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/raster_vertex.cpp b/src/mbgl/shader/raster_vertex.cpp
deleted file mode 100644
index fc9b1f11c2..0000000000
--- a/src/mbgl/shader/raster_vertex.cpp
+++ /dev/null
@@ -1,7 +0,0 @@
-#include <mbgl/shader/raster_vertex.hpp>
-
-namespace mbgl {
-
-static_assert(sizeof(RasterVertex) == 8, "expected RasterVertex size");
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/raster_vertex.hpp b/src/mbgl/shader/raster_vertex.hpp
deleted file mode 100644
index 70e08c609d..0000000000
--- a/src/mbgl/shader/raster_vertex.hpp
+++ /dev/null
@@ -1,39 +0,0 @@
-#pragma once
-
-#include <mbgl/gl/attribute.hpp>
-
-#include <array>
-#include <cstdint>
-
-namespace mbgl {
-
-class RasterVertex {
-public:
- RasterVertex(int16_t x, int16_t y, uint16_t tx, uint16_t ty)
- : a_pos {
- x,
- y
- },
- a_texture_pos {
- tx,
- ty
- } {}
-
- const int16_t a_pos[2];
- const uint16_t a_texture_pos[2];
-};
-
-namespace gl {
-
-template <class Shader>
-struct AttributeBindings<Shader, RasterVertex> {
- std::array<AttributeBinding, 2> operator()(const Shader& shader) {
- return {{
- MBGL_MAKE_ATTRIBUTE_BINDING(RasterVertex, shader, a_pos),
- MBGL_MAKE_ATTRIBUTE_BINDING(RasterVertex, shader, a_texture_pos)
- }};
- };
-};
-
-} // namespace gl
-} // namespace mbgl
diff --git a/src/mbgl/shader/shaders.hpp b/src/mbgl/shader/shaders.hpp
deleted file mode 100644
index 937ee85f44..0000000000
--- a/src/mbgl/shader/shaders.hpp
+++ /dev/null
@@ -1,58 +0,0 @@
-#pragma once
-
-#include <mbgl/shader/circle_shader.hpp>
-#include <mbgl/shader/fill_shader.hpp>
-#include <mbgl/shader/fill_pattern_shader.hpp>
-#include <mbgl/shader/fill_outline_shader.hpp>
-#include <mbgl/shader/fill_outline_pattern_shader.hpp>
-#include <mbgl/shader/line_shader.hpp>
-#include <mbgl/shader/line_sdf_shader.hpp>
-#include <mbgl/shader/line_pattern_shader.hpp>
-#include <mbgl/shader/raster_shader.hpp>
-#include <mbgl/shader/symbol_icon_shader.hpp>
-#include <mbgl/shader/symbol_sdf_shader.hpp>
-
-#include <mbgl/shader/collision_box_shader.hpp>
-
-namespace mbgl {
-
-class Shaders {
-public:
- Shaders(gl::Context& context, gl::Shader::Defines defines = gl::Shader::None)
- : circle(context, defines),
- fill(context, defines),
- fillPattern(context, defines),
- fillOutline(context, defines),
- fillOutlinePattern(context, defines),
- line(context, defines),
- lineSDF(context, defines),
- linePattern(context, defines),
- raster(context, defines),
- symbolIcon(context, defines),
- symbolIconSDF(context, defines),
- symbolGlyph(context, defines),
- collisionBox(context) {
- }
-
- CircleShader circle;
- FillShader fill;
- FillPatternShader fillPattern;
- FillOutlineShader fillOutline;
- FillOutlinePatternShader fillOutlinePattern;
- LineShader line;
- LineSDFShader lineSDF;
- LinePatternShader linePattern;
- RasterShader raster;
- SymbolIconShader symbolIcon;
- SymbolSDFShader symbolIconSDF;
- SymbolSDFShader symbolGlyph;
-
- CollisionBoxShader collisionBox;
-
- gl::VertexArrayObject coveringPlainArray;
- gl::VertexArrayObject coveringRasterArray;
- gl::VertexArrayObject backgroundPatternArray;
- gl::VertexArrayObject backgroundArray;
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/symbol_icon_shader.cpp b/src/mbgl/shader/symbol_icon_shader.cpp
deleted file mode 100644
index 2655a1c9b5..0000000000
--- a/src/mbgl/shader/symbol_icon_shader.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#include <mbgl/shader/symbol_icon_shader.hpp>
-#include <mbgl/shader/symbol_icon.vertex.hpp>
-#include <mbgl/shader/symbol_icon.fragment.hpp>
-#include <mbgl/shader/symbol_vertex.hpp>
-
-namespace mbgl {
-
-SymbolIconShader::SymbolIconShader(gl::Context& context, Defines defines)
- : Shader(shaders::symbol_icon::name,
- shaders::symbol_icon::vertex,
- shaders::symbol_icon::fragment,
- context, defines) {
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/symbol_icon_shader.hpp b/src/mbgl/shader/symbol_icon_shader.hpp
deleted file mode 100644
index 5281beb60c..0000000000
--- a/src/mbgl/shader/symbol_icon_shader.hpp
+++ /dev/null
@@ -1,32 +0,0 @@
-#pragma once
-
-#include <mbgl/gl/shader.hpp>
-#include <mbgl/gl/attribute.hpp>
-#include <mbgl/gl/uniform.hpp>
-
-namespace mbgl {
-
-class SymbolVertex;
-
-class SymbolIconShader : public gl::Shader {
-public:
- SymbolIconShader(gl::Context&, Defines defines = None);
-
- using VertexType = SymbolVertex;
-
- gl::Attribute<int16_t, 2> a_pos = { "a_pos", *this };
- gl::Attribute<int16_t, 2> a_offset = { "a_offset", *this };
- gl::Attribute<uint16_t, 2> a_texture_pos = { "a_texture_pos", *this };
- gl::Attribute<uint8_t, 4> a_data = { "a_data", *this };
-
- gl::UniformMatrix<4> u_matrix = {"u_matrix", *this};
- gl::Uniform<std::array<float, 2>> u_extrude_scale = {"u_extrude_scale", *this};
- gl::Uniform<float> u_zoom = {"u_zoom", *this};
- gl::Uniform<float> u_opacity = {"u_opacity", *this};
- gl::Uniform<std::array<float, 2>> u_texsize = {"u_texsize", *this};
- gl::Uniform<int32_t> u_rotate_with_map = {"u_rotate_with_map", *this};
- gl::Uniform<int32_t> u_texture = {"u_texture", *this};
- gl::Uniform<int32_t> u_fadetexture = {"u_fadetexture", *this};
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/symbol_sdf_shader.cpp b/src/mbgl/shader/symbol_sdf_shader.cpp
deleted file mode 100644
index 63c3bd5a4a..0000000000
--- a/src/mbgl/shader/symbol_sdf_shader.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#include <mbgl/shader/symbol_sdf_shader.hpp>
-#include <mbgl/shader/symbol_sdf.vertex.hpp>
-#include <mbgl/shader/symbol_sdf.fragment.hpp>
-#include <mbgl/shader/symbol_vertex.hpp>
-
-namespace mbgl {
-
-SymbolSDFShader::SymbolSDFShader(gl::Context& context, Defines defines)
- : Shader(shaders::symbol_sdf::name,
- shaders::symbol_sdf::vertex,
- shaders::symbol_sdf::fragment,
- context, defines) {
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/symbol_sdf_shader.hpp b/src/mbgl/shader/symbol_sdf_shader.hpp
deleted file mode 100644
index 8d3b3df939..0000000000
--- a/src/mbgl/shader/symbol_sdf_shader.hpp
+++ /dev/null
@@ -1,40 +0,0 @@
-#pragma once
-
-#include <mbgl/gl/shader.hpp>
-#include <mbgl/gl/attribute.hpp>
-#include <mbgl/gl/uniform.hpp>
-#include <mbgl/util/color.hpp>
-
-namespace mbgl {
-
-class SymbolVertex;
-
-class SymbolSDFShader : public gl::Shader {
-public:
- SymbolSDFShader(gl::Context&, Defines defines = None);
-
- using VertexType = SymbolVertex;
-
- gl::Attribute<int16_t, 2> a_pos = { "a_pos", *this };
- gl::Attribute<int16_t, 2> a_offset = { "a_offset", *this };
- gl::Attribute<uint16_t, 2> a_texture_pos = { "a_texture_pos", *this };
- gl::Attribute<uint8_t, 4> a_data = { "a_data", *this };
-
- gl::UniformMatrix<4> u_matrix = {"u_matrix", *this};
- gl::Uniform<std::array<float, 2>> u_extrude_scale = {"u_extrude_scale", *this};
- gl::Uniform<Color> u_color = {"u_color", *this};
- gl::Uniform<float> u_opacity = {"u_opacity", *this};
- gl::Uniform<std::array<float, 2>> u_texsize = {"u_texsize", *this};
- gl::Uniform<float> u_buffer = {"u_buffer", *this};
- gl::Uniform<float> u_gamma = {"u_gamma", *this};
- gl::Uniform<float> u_zoom = {"u_zoom", *this};
- gl::Uniform<float> u_pitch = {"u_pitch", *this};
- gl::Uniform<float> u_bearing = {"u_bearing", *this};
- gl::Uniform<float> u_aspect_ratio = {"u_aspect_ratio", *this};
- gl::Uniform<int32_t> u_rotate_with_map = {"u_rotate_with_map", *this};
- gl::Uniform<int32_t> u_pitch_with_map = {"u_pitch_with_map", *this};
- gl::Uniform<int32_t> u_texture = {"u_texture", *this};
- gl::Uniform<int32_t> u_fadetexture = {"u_fadetexture", *this};
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/symbol_vertex.cpp b/src/mbgl/shader/symbol_vertex.cpp
deleted file mode 100644
index 4075d749ea..0000000000
--- a/src/mbgl/shader/symbol_vertex.cpp
+++ /dev/null
@@ -1,9 +0,0 @@
-#include <mbgl/shader/symbol_vertex.hpp>
-#include <mbgl/gl/shader.hpp>
-#include <mbgl/gl/gl.hpp>
-
-namespace mbgl {
-
-static_assert(sizeof(SymbolVertex) == 16, "expected SymbolVertex size");
-
-} // namespace mbgl
diff --git a/src/mbgl/shader/symbol_vertex.hpp b/src/mbgl/shader/symbol_vertex.hpp
deleted file mode 100644
index 4eba86f946..0000000000
--- a/src/mbgl/shader/symbol_vertex.hpp
+++ /dev/null
@@ -1,54 +0,0 @@
-#pragma once
-
-#include <mbgl/gl/attribute.hpp>
-
-#include <array>
-#include <cstdint>
-#include <cmath>
-
-namespace mbgl {
-
-class SymbolVertex {
-public:
- SymbolVertex(int16_t x, int16_t y, float ox, float oy, uint16_t tx, uint16_t ty, float minzoom, float maxzoom, float labelminzoom, uint8_t labelangle)
- : a_pos {
- x,
- y
- },
- a_offset {
- static_cast<int16_t>(::round(ox * 64)), // use 1/64 pixels for placement
- static_cast<int16_t>(::round(oy * 64))
- },
- a_texture_pos {
- static_cast<uint16_t>(tx / 4),
- static_cast<uint16_t>(ty / 4)
- },
- a_data {
- static_cast<uint8_t>(labelminzoom * 10), // 1/10 zoom levels: z16 == 160
- static_cast<uint8_t>(labelangle),
- static_cast<uint8_t>(minzoom * 10),
- static_cast<uint8_t>(::fmin(maxzoom, 25) * 10)
- } {}
-
- const int16_t a_pos[2];
- const int16_t a_offset[2];
- const uint16_t a_texture_pos[2];
- const uint8_t a_data[4];
-};
-
-namespace gl {
-
-template <class Shader>
-struct AttributeBindings<Shader, SymbolVertex> {
- std::array<AttributeBinding, 4> operator()(const Shader& shader) {
- return {{
- MBGL_MAKE_ATTRIBUTE_BINDING(SymbolVertex, shader, a_pos),
- MBGL_MAKE_ATTRIBUTE_BINDING(SymbolVertex, shader, a_offset),
- MBGL_MAKE_ATTRIBUTE_BINDING(SymbolVertex, shader, a_texture_pos),
- MBGL_MAKE_ATTRIBUTE_BINDING(SymbolVertex, shader, a_data)
- }};
- };
-};
-
-} // namespace gl
-} // namespace mbgl
diff --git a/src/mbgl/sprite/sprite_atlas.cpp b/src/mbgl/sprite/sprite_atlas.cpp
index 198b0a6c57..ea055ce5ec 100644
--- a/src/mbgl/sprite/sprite_atlas.cpp
+++ b/src/mbgl/sprite/sprite_atlas.cpp
@@ -1,10 +1,9 @@
#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/sprite/sprite_atlas_observer.hpp>
#include <mbgl/sprite/sprite_parser.hpp>
-#include <mbgl/gl/gl.hpp>
#include <mbgl/gl/context.hpp>
-#include <mbgl/platform/log.hpp>
-#include <mbgl/platform/platform.hpp>
+#include <mbgl/util/logging.hpp>
+#include <mbgl/util/platform.hpp>
#include <mbgl/util/math.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/util/constants.hpp>
@@ -28,15 +27,12 @@ struct SpriteAtlas::Loader {
std::unique_ptr<AsyncRequest> spriteRequest;
};
-SpriteAtlas::SpriteAtlas(dimension width_, dimension height_, float pixelRatio_)
- : width(width_),
- height(height_),
- pixelWidth(std::ceil(width * pixelRatio_)),
- pixelHeight(std::ceil(height * pixelRatio_)),
+SpriteAtlas::SpriteAtlas(Size size_, float pixelRatio_)
+ : size(std::move(size_)),
pixelRatio(pixelRatio_),
observer(&nullObserver),
- bin(width_, height_),
- dirtyFlag(true) {
+ bin(size.width, size.height),
+ dirty(true) {
}
SpriteAtlas::~SpriteAtlas() = default;
@@ -128,7 +124,7 @@ void SpriteAtlas::_setSprite(const std::string& name,
auto it = sprites.find(name);
if (it != sprites.end()) {
// There is already a sprite with that name in our store.
- if ((it->second->image.width != sprite->image.width || it->second->image.height != sprite->image.height)) {
+ if (it->second->image.size != sprite->image.size) {
Log::Warning(Event::Sprite, "Can't change sprite dimensions for '%s'", name.c_str());
return;
}
@@ -162,10 +158,10 @@ std::shared_ptr<const SpriteImage> SpriteAtlas::getSprite(const std::string& nam
}
}
-Rect<SpriteAtlas::dimension> SpriteAtlas::allocateImage(const SpriteImage& spriteImage) {
+Rect<uint16_t> SpriteAtlas::allocateImage(const SpriteImage& spriteImage) {
- const uint16_t pixel_width = std::ceil(spriteImage.image.width / pixelRatio);
- const uint16_t pixel_height = std::ceil(spriteImage.image.height / pixelRatio);
+ const uint16_t pixel_width = std::ceil(spriteImage.image.size.width / pixelRatio);
+ const uint16_t pixel_height = std::ceil(spriteImage.image.size.height / pixelRatio);
// Increase to next number divisible by 4, but at least 1.
// This is so we can scale down the texture coordinates and pack them
@@ -175,7 +171,7 @@ Rect<SpriteAtlas::dimension> SpriteAtlas::allocateImage(const SpriteImage& sprit
// We have to allocate a new area in the bin, and store an empty image in it.
// Add a 1px border around every image.
- Rect<dimension> rect = bin.allocate(pack_width, pack_height);
+ Rect<uint16_t> rect = bin.allocate(pack_width, pack_height);
if (rect.w == 0) {
return rect;
}
@@ -197,7 +193,7 @@ optional<SpriteAtlasElement> SpriteAtlas::getImage(const std::string& name,
return {};
}
- Rect<dimension> rect = allocateImage(*sprite);
+ Rect<uint16_t> rect = allocateImage(*sprite);
if (rect.w == 0) {
if (debug::spriteWarnings) {
Log::Warning(Event::Sprite, "sprite atlas bitmap overflow");
@@ -230,8 +226,8 @@ optional<SpriteAtlasPosition> SpriteAtlas::getPosition(const std::string& name,
return SpriteAtlasPosition {
{{ float(spriteImage->getWidth()), spriteImage->getHeight() }},
- {{ float(rect.x + padding) / width, float(rect.y + padding) / height }},
- {{ float(rect.x + padding + w) / width, float(rect.y + padding + h) / height }}
+ {{ float(rect.x + padding) / size.width, float(rect.y + padding) / size.height }},
+ {{ float(rect.x + padding + w) / size.width, float(rect.y + padding + h) / size.height }}
};
}
@@ -264,28 +260,25 @@ void copyBitmap(const uint32_t *src, const uint32_t srcStride, const uint32_t sr
}
void SpriteAtlas::copy(const Holder& holder, const SpritePatternMode mode) {
- if (!data) {
- data = std::make_unique<uint32_t[]>(pixelWidth * pixelHeight);
- std::fill(data.get(), data.get() + pixelWidth * pixelHeight, 0);
+ if (!image.valid()) {
+ image = PremultipliedImage({ static_cast<uint32_t>(std::ceil(size.width * pixelRatio)),
+ static_cast<uint32_t>(std::ceil(size.height * pixelRatio)) });
+ std::fill(image.data.get(), image.data.get() + image.bytes(), 0);
}
- const uint32_t *srcData = reinterpret_cast<const uint32_t *>(holder.spriteImage->image.data.get());
+ const uint32_t* srcData =
+ reinterpret_cast<const uint32_t*>(holder.spriteImage->image.data.get());
if (!srcData) return;
- uint32_t *const dstData = data.get();
+ uint32_t* const dstData = reinterpret_cast<uint32_t*>(image.data.get());
const int padding = 1;
- copyBitmap(srcData, uint32_t(holder.spriteImage->image.width), 0, 0,
- dstData, pixelWidth, (holder.pos.x + padding) * pixelRatio, (holder.pos.y + padding) * pixelRatio, pixelWidth * pixelHeight,
- uint32_t(holder.spriteImage->image.width), uint32_t(holder.spriteImage->image.height), mode);
+ copyBitmap(srcData, holder.spriteImage->image.size.width, 0, 0, dstData, image.size.width,
+ (holder.pos.x + padding) * pixelRatio, (holder.pos.y + padding) * pixelRatio,
+ image.size.width * image.size.height, holder.spriteImage->image.size.width,
+ holder.spriteImage->image.size.height, mode);
- dirtyFlag = true;
-}
-
-void SpriteAtlas::upload(gl::Context& context, gl::TextureUnit unit) {
- if (dirtyFlag) {
- bind(false, context, unit);
- }
+ dirty = true;
}
void SpriteAtlas::updateDirty() {
@@ -316,77 +309,31 @@ void SpriteAtlas::updateDirty() {
dirtySprites.clear();
}
-void SpriteAtlas::bind(bool linear, gl::Context& context, gl::TextureUnit unit) {
- if (!data) {
- return; // Empty atlas
+void SpriteAtlas::upload(gl::Context& context, gl::TextureUnit unit) {
+ if (!texture) {
+ texture = context.createTexture(image, unit);
+ } else if (dirty) {
+ context.updateTexture(*texture, image, unit);
}
- if (!texture) {
- texture = context.createTexture();
- context.activeTexture = unit;
- context.texture[unit] = *texture;
#if not MBGL_USE_GLES2
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
+// if (dirty) {
+// platform::showColorDebugImage("Sprite Atlas",
+// reinterpret_cast<const char*>(image.data.get()), size.width,
+// size.height, image.size.width, image.size.height);
+// }
#endif // MBGL_USE_GLES2
- // We are using clamp to edge here since OpenGL ES doesn't allow GL_REPEAT on NPOT textures.
- // We use those when the pixelRatio isn't a power of two, e.g. on iPhone 6 Plus.
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
- fullUploadRequired = true;
- } else if (context.texture[unit] != *texture) {
- context.activeTexture = unit;
- context.texture[unit] = *texture;
- }
- GLuint filter_val = linear ? GL_LINEAR : GL_NEAREST;
- if (filter_val != filter) {
- context.activeTexture = unit;
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter_val));
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter_val));
- filter = filter_val;
- }
-
- if (dirtyFlag) {
- std::lock_guard<std::recursive_mutex> lock(mtx);
-
- context.activeTexture = unit;
- if (fullUploadRequired) {
- MBGL_CHECK_ERROR(glTexImage2D(
- GL_TEXTURE_2D, // GLenum target
- 0, // GLint level
- GL_RGBA, // GLint internalformat
- pixelWidth, // GLsizei width
- pixelHeight, // GLsizei height
- 0, // GLint border
- GL_RGBA, // GLenum format
- GL_UNSIGNED_BYTE, // GLenum type
- data.get() // const GLvoid * data
- ));
- fullUploadRequired = false;
- } else {
- MBGL_CHECK_ERROR(glTexSubImage2D(
- GL_TEXTURE_2D, // GLenum target
- 0, // GLint level
- 0, // GLint xoffset
- 0, // GLint yoffset
- pixelWidth, // GLsizei width
- pixelHeight, // GLsizei height
- GL_RGBA, // GLenum format
- GL_UNSIGNED_BYTE, // GLenum type
- data.get() // const GLvoid *pixels
- ));
- }
-
- dirtyFlag = false;
+ dirty = false;
+}
-#if not MBGL_USE_GLES2
- // platform::showColorDebugImage("Sprite Atlas", reinterpret_cast<const char*>(data.get()),
- // pixelWidth, pixelHeight, pixelWidth, pixelHeight);
-#endif // MBGL_USE_GLES2
- }
+void SpriteAtlas::bind(bool linear, gl::Context& context, gl::TextureUnit unit) {
+ upload(context, unit);
+ context.bindTexture(*texture, unit,
+ linear ? gl::TextureFilter::Linear : gl::TextureFilter::Nearest);
}
-SpriteAtlas::Holder::Holder(std::shared_ptr<const SpriteImage> spriteImage_, Rect<dimension> pos_)
+SpriteAtlas::Holder::Holder(std::shared_ptr<const SpriteImage> spriteImage_, Rect<uint16_t> pos_)
: spriteImage(std::move(spriteImage_)), pos(std::move(pos_)) {
}
diff --git a/src/mbgl/sprite/sprite_atlas.hpp b/src/mbgl/sprite/sprite_atlas.hpp
index 3a0aea2dad..c79aec135e 100644
--- a/src/mbgl/sprite/sprite_atlas.hpp
+++ b/src/mbgl/sprite/sprite_atlas.hpp
@@ -1,7 +1,7 @@
#pragma once
#include <mbgl/geometry/binpack.hpp>
-#include <mbgl/gl/object.hpp>
+#include <mbgl/gl/texture.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/optional.hpp>
#include <mbgl/sprite/sprite_image.hpp>
@@ -26,13 +26,15 @@ class Context;
class SpriteImage;
class SpritePosition;
-struct SpriteAtlasPosition {
+class SpriteAtlasPosition {
+public:
std::array<float, 2> size = {{ 0, 0 }};
std::array<float, 2> tl = {{ 0, 0 }};
std::array<float, 2> br = {{ 0, 0 }};
};
-struct SpriteAtlasElement {
+class SpriteAtlasElement {
+public:
Rect<uint16_t> pos;
std::shared_ptr<const SpriteImage> spriteImage;
float relativePixelRatio;
@@ -45,10 +47,9 @@ enum class SpritePatternMode : bool {
class SpriteAtlas : public util::noncopyable {
public:
- typedef uint16_t dimension;
using Sprites = std::map<std::string, std::shared_ptr<const SpriteImage>>;
- SpriteAtlas(dimension width, dimension height, float pixelRatio);
+ SpriteAtlas(Size, float pixelRatio);
~SpriteAtlas();
void load(const std::string& url, FileSource&);
@@ -91,21 +92,19 @@ public:
// the texture is only bound when the data is out of date (=dirty).
void upload(gl::Context&, gl::TextureUnit unit);
- dimension getWidth() const { return width; }
- dimension getHeight() const { return height; }
- dimension getTextureWidth() const { return pixelWidth; }
- dimension getTextureHeight() const { return pixelHeight; }
+ Size getSize() const { return size; }
float getPixelRatio() const { return pixelRatio; }
// Only for use in tests.
- const uint32_t* getData() const { return data.get(); }
+ const PremultipliedImage& getAtlasImage() const {
+ return image;
+ }
private:
void _setSprite(const std::string&, const std::shared_ptr<const SpriteImage>& = nullptr);
void emitSpriteLoadedIfComplete();
- const uint16_t width, height;
- const dimension pixelWidth, pixelHeight;
+ const Size size;
const float pixelRatio;
struct Loader;
@@ -125,26 +124,24 @@ private:
Sprites dirtySprites;
struct Holder : private util::noncopyable {
- Holder(std::shared_ptr<const SpriteImage>, Rect<dimension>);
+ Holder(std::shared_ptr<const SpriteImage>, Rect<uint16_t>);
Holder(Holder&&);
std::shared_ptr<const SpriteImage> spriteImage;
- const Rect<dimension> pos;
+ const Rect<uint16_t> pos;
};
using Key = std::pair<std::string, SpritePatternMode>;
- Rect<SpriteAtlas::dimension> allocateImage(const SpriteImage&);
+ Rect<uint16_t> allocateImage(const SpriteImage&);
void copy(const Holder& holder, SpritePatternMode mode);
std::recursive_mutex mtx;
- BinPack<dimension> bin;
+ BinPack<uint16_t> bin;
std::map<Key, Holder> images;
std::unordered_set<std::string> uninitialized;
- std::unique_ptr<uint32_t[]> data;
- std::atomic<bool> dirtyFlag;
- bool fullUploadRequired = true;
- mbgl::optional<gl::UniqueTexture> texture;
- uint32_t filter = 0;
+ PremultipliedImage image;
+ mbgl::optional<gl::Texture> texture;
+ std::atomic<bool> dirty;
static const int buffer = 1;
};
diff --git a/src/mbgl/sprite/sprite_image.cpp b/src/mbgl/sprite/sprite_image.cpp
index d7e422ed1d..1579d9d89e 100644
--- a/src/mbgl/sprite/sprite_image.cpp
+++ b/src/mbgl/sprite/sprite_image.cpp
@@ -13,7 +13,7 @@ SpriteImage::SpriteImage(PremultipliedImage&& image_,
pixelRatio(pixelRatio_),
sdf(sdf_) {
- if (image.size() == 0) {
+ if (!image.valid()) {
throw util::SpriteImageException("Sprite image dimensions may not be zero");
} else if (pixelRatio <= 0) {
throw util::SpriteImageException("Sprite pixelRatio may not be <= 0");
diff --git a/src/mbgl/sprite/sprite_parser.cpp b/src/mbgl/sprite/sprite_parser.cpp
index 34b1d875b6..9de8515e14 100644
--- a/src/mbgl/sprite/sprite_parser.cpp
+++ b/src/mbgl/sprite/sprite_parser.cpp
@@ -1,10 +1,11 @@
#include <mbgl/sprite/sprite_parser.hpp>
#include <mbgl/sprite/sprite_image.hpp>
-#include <mbgl/platform/log.hpp>
+#include <mbgl/util/logging.hpp>
#include <mbgl/util/image.hpp>
#include <mbgl/util/rapidjson.hpp>
+#include <mbgl/util/string.hpp>
#include <cmath>
#include <limits>
@@ -13,30 +14,34 @@
namespace mbgl {
SpriteImagePtr createSpriteImage(const PremultipliedImage& image,
- const uint16_t srcX,
- const uint16_t srcY,
- const uint16_t width,
- const uint16_t height,
+ const uint32_t srcX,
+ const uint32_t srcY,
+ const uint32_t width,
+ const uint32_t height,
const double ratio,
const bool sdf) {
// Disallow invalid parameter configurations.
if (width <= 0 || height <= 0 || width > 1024 || height > 1024 ||
ratio <= 0 || ratio > 10 ||
- srcX + width > image.width || srcY + height > image.height) {
- Log::Error(Event::Sprite, "Can't create sprite with invalid metrics");
+ srcX >= image.size.width || srcY >= image.size.height ||
+ srcX + width > image.size.width || srcY + height > image.size.height) {
+ Log::Error(Event::Sprite, "Can't create sprite with invalid metrics: %ux%u@%u,%u in %ux%u@%sx sprite",
+ width, height, srcX, srcY,
+ image.size.width, image.size.height,
+ util::toString(ratio).c_str());
return nullptr;
}
- PremultipliedImage dstImage(width, height);
+ PremultipliedImage dstImage({ width, height });
auto srcData = reinterpret_cast<const uint32_t*>(image.data.get());
auto dstData = reinterpret_cast<uint32_t*>(dstImage.data.get());
// Copy from the source image into our individual sprite image
- for (uint16_t y = 0; y < height; ++y) {
+ for (uint32_t y = 0; y < height; ++y) {
const auto dstRow = y * width;
- const auto srcRow = (y + srcY) * image.width + srcX;
- for (uint16_t x = 0; x < width; ++x) {
+ const auto srcRow = (y + srcY) * image.size.width + srcX;
+ for (uint32_t x = 0; x < width; ++x) {
dstData[dstRow + x] = srcData[srcRow + x];
}
}
diff --git a/src/mbgl/sprite/sprite_parser.hpp b/src/mbgl/sprite/sprite_parser.hpp
index 6a564ce330..4a63d4858a 100644
--- a/src/mbgl/sprite/sprite_parser.hpp
+++ b/src/mbgl/sprite/sprite_parser.hpp
@@ -17,10 +17,10 @@ using SpriteImagePtr = std::shared_ptr<const SpriteImage>;
// Extracts an individual image from a spritesheet from the given location.
SpriteImagePtr createSpriteImage(const PremultipliedImage&,
- uint16_t srcX,
- uint16_t srcY,
- uint16_t srcWidth,
- uint16_t srcHeight,
+ uint32_t srcX,
+ uint32_t srcY,
+ uint32_t srcWidth,
+ uint32_t srcHeight,
double ratio,
bool sdf);
diff --git a/src/mbgl/style/class_dictionary.hpp b/src/mbgl/style/class_dictionary.hpp
index e609fb5303..37eb488240 100644
--- a/src/mbgl/style/class_dictionary.hpp
+++ b/src/mbgl/style/class_dictionary.hpp
@@ -9,7 +9,6 @@ namespace mbgl {
namespace style {
enum class ClassID : uint32_t {
- Fallback = 0, // These values are from the fallback properties
Default = 1, // These values are from the default style for a layer
Named = 2 // These values (and all subsequent IDs) are from a named style from the layer
};
diff --git a/src/mbgl/style/cross_faded_property_evaluator.cpp b/src/mbgl/style/cross_faded_property_evaluator.cpp
new file mode 100644
index 0000000000..4de939576e
--- /dev/null
+++ b/src/mbgl/style/cross_faded_property_evaluator.cpp
@@ -0,0 +1,53 @@
+#include <mbgl/style/cross_faded_property_evaluator.hpp>
+#include <mbgl/util/chrono.hpp>
+
+#include <cmath>
+
+namespace mbgl {
+namespace style {
+
+template <typename T>
+Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const Undefined&) const {
+ return calculate(defaultValue, defaultValue, defaultValue);
+}
+
+template <typename T>
+Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const T& constant) const {
+ return calculate(constant, constant, constant);
+}
+
+template <typename T>
+T getBiggestStopLessThan(const Function<T>& function, float z) {
+ const auto& stops = function.getStops();
+ for (uint32_t i = 0; i < stops.size(); i++) {
+ if (stops[i].first > z) {
+ return stops[i == 0 ? i : i - 1].second;
+ }
+ }
+ return stops.at(stops.size() - 1).second;
+}
+
+template <typename T>
+Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const Function<T>& function) const {
+ return calculate(getBiggestStopLessThan(function, parameters.z - 1.0f),
+ getBiggestStopLessThan(function, parameters.z),
+ getBiggestStopLessThan(function, parameters.z + 1.0f));
+}
+
+template <typename T>
+Faded<T> CrossFadedPropertyEvaluator<T>::calculate(const T& min, const T& mid, const T& max) const {
+ const float z = parameters.z;
+ const float fraction = z - std::floor(z);
+ const std::chrono::duration<float> d = parameters.defaultFadeDuration;
+ const float t = std::min((parameters.now - parameters.zoomHistory.lastIntegerZoomTime) / d, 1.0f);
+
+ return z > parameters.zoomHistory.lastIntegerZoom
+ ? Faded<T> { min, mid, 2.0f, 1.0f, fraction + (1.0f - fraction) * t }
+ : Faded<T> { max, mid, 0.5f, 1.0f, 1 - (1 - t) * fraction };
+}
+
+template class CrossFadedPropertyEvaluator<std::string>;
+template class CrossFadedPropertyEvaluator<std::vector<float>>;
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/cross_faded_property_evaluator.hpp b/src/mbgl/style/cross_faded_property_evaluator.hpp
new file mode 100644
index 0000000000..70c8c0c978
--- /dev/null
+++ b/src/mbgl/style/cross_faded_property_evaluator.hpp
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/property_evaluation_parameters.hpp>
+#include <mbgl/util/interpolate.hpp>
+
+namespace mbgl {
+namespace style {
+
+template <typename T>
+class Faded {
+public:
+ T from;
+ T to;
+ float fromScale;
+ float toScale;
+ float t;
+};
+
+template <typename T>
+class CrossFadedPropertyEvaluator {
+public:
+ using ResultType = Faded<T>;
+
+ CrossFadedPropertyEvaluator(const PropertyEvaluationParameters& parameters_, T defaultValue_)
+ : parameters(parameters_),
+ defaultValue(std::move(defaultValue_)) {}
+
+ Faded<T> operator()(const Undefined&) const;
+ Faded<T> operator()(const T& constant) const;
+ Faded<T> operator()(const Function<T>&) const;
+
+private:
+ Faded<T> calculate(const T& min, const T& mid, const T& max) const;
+
+ const PropertyEvaluationParameters& parameters;
+ T defaultValue;
+};
+
+} // namespace style
+
+namespace util {
+template <typename T>
+struct Interpolator<style::Faded<T>>
+ : Uninterpolated {};
+} // namespace util
+
+} // namespace mbgl
diff --git a/src/mbgl/style/function.cpp b/src/mbgl/style/function.cpp
new file mode 100644
index 0000000000..02750c7d2e
--- /dev/null
+++ b/src/mbgl/style/function.cpp
@@ -0,0 +1,81 @@
+#include <mbgl/style/function.hpp>
+#include <mbgl/style/types.hpp>
+#include <mbgl/util/color.hpp>
+#include <mbgl/util/interpolate.hpp>
+
+#include <cmath>
+
+namespace mbgl {
+namespace style {
+
+template <typename T>
+T Function<T>::evaluate(float z) const {
+ bool smaller = false;
+ float smaller_z = 0.0f;
+ T smaller_val = T();
+ bool larger = false;
+ float larger_z = 0.0f;
+ T larger_val = T();
+
+ for (uint32_t i = 0; i < stops.size(); i++) {
+ float stop_z = stops[i].first;
+ T stop_val = stops[i].second;
+ if (stop_z <= z && (!smaller || smaller_z < stop_z)) {
+ smaller = true;
+ smaller_z = stop_z;
+ smaller_val = stop_val;
+ }
+ if (stop_z >= z && (!larger || larger_z > stop_z)) {
+ larger = true;
+ larger_z = stop_z;
+ larger_val = stop_val;
+ }
+ }
+
+ if (smaller && larger) {
+ if (larger_z == smaller_z || larger_val == smaller_val) {
+ return smaller_val;
+ }
+ const float zoomDiff = larger_z - smaller_z;
+ const float zoomProgress = z - smaller_z;
+ if (base == 1.0f) {
+ const float t = zoomProgress / zoomDiff;
+ return util::interpolate(smaller_val, larger_val, t);
+ } else {
+ const float t = (std::pow(base, zoomProgress) - 1) / (std::pow(base, zoomDiff) - 1);
+ return util::interpolate(smaller_val, larger_val, t);
+ }
+ } else if (larger) {
+ return larger_val;
+ } else if (smaller) {
+ return smaller_val;
+ } else {
+ // No stop defined.
+ assert(false);
+ return T();
+ }
+}
+
+template class Function<bool>;
+template class Function<float>;
+template class Function<Color>;
+template class Function<std::vector<float>>;
+template class Function<std::vector<std::string>>;
+template class Function<std::array<float, 2>>;
+template class Function<std::array<float, 4>>;
+
+template class Function<std::string>;
+template class Function<TranslateAnchorType>;
+template class Function<RotateAnchorType>;
+template class Function<CirclePitchScaleType>;
+template class Function<LineCapType>;
+template class Function<LineJoinType>;
+template class Function<SymbolPlacementType>;
+template class Function<TextAnchorType>;
+template class Function<TextJustifyType>;
+template class Function<TextTransformType>;
+template class Function<AlignmentType>;
+template class Function<IconTextFitType>;
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/layer_impl.hpp b/src/mbgl/style/layer_impl.hpp
index 4bf2956a6d..38ac32e1de 100644
--- a/src/mbgl/style/layer_impl.hpp
+++ b/src/mbgl/style/layer_impl.hpp
@@ -19,7 +19,7 @@ class Bucket;
namespace style {
class CascadeParameters;
-class CalculationParameters;
+class PropertyEvaluationParameters;
class BucketParameters;
/**
@@ -57,7 +57,7 @@ public:
// Fully evaluate cascaded paint properties based on a zoom level.
// Returns true if any paint properties have active transitions.
- virtual bool recalculate(const CalculationParameters&) = 0;
+ virtual bool evaluate(const PropertyEvaluationParameters&) = 0;
virtual std::unique_ptr<Bucket> createBucket(BucketParameters&) const = 0;
diff --git a/src/mbgl/style/layers/background_layer.cpp b/src/mbgl/style/layers/background_layer.cpp
index 5e5faf37e6..a54115d1a7 100644
--- a/src/mbgl/style/layers/background_layer.cpp
+++ b/src/mbgl/style/layers/background_layer.cpp
@@ -42,13 +42,13 @@ PropertyValue<Color> BackgroundLayer::getDefaultBackgroundColor() {
}
PropertyValue<Color> BackgroundLayer::getBackgroundColor(const optional<std::string>& klass) const {
- return impl->paint.backgroundColor.get(klass);
+ return impl->paint.get<BackgroundColor>(klass);
}
void BackgroundLayer::setBackgroundColor(PropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getBackgroundColor(klass))
return;
- impl->paint.backgroundColor.set(value, klass);
+ impl->paint.set<BackgroundColor>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -57,13 +57,13 @@ PropertyValue<std::string> BackgroundLayer::getDefaultBackgroundPattern() {
}
PropertyValue<std::string> BackgroundLayer::getBackgroundPattern(const optional<std::string>& klass) const {
- return impl->paint.backgroundPattern.get(klass);
+ return impl->paint.get<BackgroundPattern>(klass);
}
void BackgroundLayer::setBackgroundPattern(PropertyValue<std::string> value, const optional<std::string>& klass) {
if (value == getBackgroundPattern(klass))
return;
- impl->paint.backgroundPattern.set(value, klass);
+ impl->paint.set<BackgroundPattern>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -72,13 +72,13 @@ PropertyValue<float> BackgroundLayer::getDefaultBackgroundOpacity() {
}
PropertyValue<float> BackgroundLayer::getBackgroundOpacity(const optional<std::string>& klass) const {
- return impl->paint.backgroundOpacity.get(klass);
+ return impl->paint.get<BackgroundOpacity>(klass);
}
void BackgroundLayer::setBackgroundOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
if (value == getBackgroundOpacity(klass))
return;
- impl->paint.backgroundOpacity.set(value, klass);
+ impl->paint.set<BackgroundOpacity>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
diff --git a/src/mbgl/style/layers/background_layer_impl.cpp b/src/mbgl/style/layers/background_layer_impl.cpp
index ea389b828e..9a7db9416e 100644
--- a/src/mbgl/style/layers/background_layer_impl.cpp
+++ b/src/mbgl/style/layers/background_layer_impl.cpp
@@ -8,12 +8,12 @@ void BackgroundLayer::Impl::cascade(const CascadeParameters& parameters) {
paint.cascade(parameters);
}
-bool BackgroundLayer::Impl::recalculate(const CalculationParameters& parameters) {
- bool hasTransitions = paint.recalculate(parameters);
+bool BackgroundLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) {
+ paint.evaluate(parameters);
- passes = paint.backgroundOpacity > 0 ? RenderPass::Translucent : RenderPass::None;
+ passes = paint.evaluated.get<BackgroundOpacity>() > 0 ? RenderPass::Translucent : RenderPass::None;
- return hasTransitions;
+ return paint.hasTransition();
}
std::unique_ptr<Bucket> BackgroundLayer::Impl::createBucket(BucketParameters&) const {
diff --git a/src/mbgl/style/layers/background_layer_impl.hpp b/src/mbgl/style/layers/background_layer_impl.hpp
index abbb740f42..6ede1b7d97 100644
--- a/src/mbgl/style/layers/background_layer_impl.hpp
+++ b/src/mbgl/style/layers/background_layer_impl.hpp
@@ -13,7 +13,7 @@ public:
std::unique_ptr<Layer> cloneRef(const std::string& id) const override;
void cascade(const CascadeParameters&) override;
- bool recalculate(const CalculationParameters&) override;
+ bool evaluate(const PropertyEvaluationParameters&) override;
std::unique_ptr<Bucket> createBucket(BucketParameters&) const override;
diff --git a/src/mbgl/style/layers/background_layer_properties.cpp b/src/mbgl/style/layers/background_layer_properties.cpp
index 558093a255..ba3e638977 100644
--- a/src/mbgl/style/layers/background_layer_properties.cpp
+++ b/src/mbgl/style/layers/background_layer_properties.cpp
@@ -5,21 +5,5 @@
namespace mbgl {
namespace style {
-void BackgroundPaintProperties::cascade(const CascadeParameters& parameters) {
- backgroundColor.cascade(parameters);
- backgroundPattern.cascade(parameters);
- backgroundOpacity.cascade(parameters);
-}
-
-bool BackgroundPaintProperties::recalculate(const CalculationParameters& parameters) {
- bool hasTransitions = false;
-
- hasTransitions |= backgroundColor.calculate(parameters);
- hasTransitions |= backgroundPattern.calculate(parameters);
- hasTransitions |= backgroundOpacity.calculate(parameters);
-
- return hasTransitions;
-}
-
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layers/background_layer_properties.hpp b/src/mbgl/style/layers/background_layer_properties.hpp
index 78a35a4f0c..792bf3de94 100644
--- a/src/mbgl/style/layers/background_layer_properties.hpp
+++ b/src/mbgl/style/layers/background_layer_properties.hpp
@@ -9,18 +9,23 @@
namespace mbgl {
namespace style {
-class CascadeParameters;
-class CalculationParameters;
+struct BackgroundColor : PaintProperty<Color> {
+ static Color defaultValue() { return Color::black(); }
+};
-class BackgroundPaintProperties {
-public:
- void cascade(const CascadeParameters&);
- bool recalculate(const CalculationParameters&);
+struct BackgroundPattern : CrossFadedPaintProperty<std::string> {
+ static std::string defaultValue() { return ""; }
+};
- PaintProperty<Color> backgroundColor { Color::black() };
- PaintProperty<std::string, CrossFadedPropertyEvaluator> backgroundPattern { "" };
- PaintProperty<float> backgroundOpacity { 1 };
+struct BackgroundOpacity : PaintProperty<float> {
+ static float defaultValue() { return 1; }
};
+class BackgroundPaintProperties : public PaintProperties<
+ BackgroundColor,
+ BackgroundPattern,
+ BackgroundOpacity
+> {};
+
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp
index a2b8d316d6..e3a506e895 100644
--- a/src/mbgl/style/layers/circle_layer.cpp
+++ b/src/mbgl/style/layers/circle_layer.cpp
@@ -67,13 +67,13 @@ PropertyValue<float> CircleLayer::getDefaultCircleRadius() {
}
PropertyValue<float> CircleLayer::getCircleRadius(const optional<std::string>& klass) const {
- return impl->paint.circleRadius.get(klass);
+ return impl->paint.get<CircleRadius>(klass);
}
void CircleLayer::setCircleRadius(PropertyValue<float> value, const optional<std::string>& klass) {
if (value == getCircleRadius(klass))
return;
- impl->paint.circleRadius.set(value, klass);
+ impl->paint.set<CircleRadius>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -82,13 +82,13 @@ PropertyValue<Color> CircleLayer::getDefaultCircleColor() {
}
PropertyValue<Color> CircleLayer::getCircleColor(const optional<std::string>& klass) const {
- return impl->paint.circleColor.get(klass);
+ return impl->paint.get<CircleColor>(klass);
}
void CircleLayer::setCircleColor(PropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getCircleColor(klass))
return;
- impl->paint.circleColor.set(value, klass);
+ impl->paint.set<CircleColor>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -97,13 +97,13 @@ PropertyValue<float> CircleLayer::getDefaultCircleBlur() {
}
PropertyValue<float> CircleLayer::getCircleBlur(const optional<std::string>& klass) const {
- return impl->paint.circleBlur.get(klass);
+ return impl->paint.get<CircleBlur>(klass);
}
void CircleLayer::setCircleBlur(PropertyValue<float> value, const optional<std::string>& klass) {
if (value == getCircleBlur(klass))
return;
- impl->paint.circleBlur.set(value, klass);
+ impl->paint.set<CircleBlur>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -112,13 +112,13 @@ PropertyValue<float> CircleLayer::getDefaultCircleOpacity() {
}
PropertyValue<float> CircleLayer::getCircleOpacity(const optional<std::string>& klass) const {
- return impl->paint.circleOpacity.get(klass);
+ return impl->paint.get<CircleOpacity>(klass);
}
void CircleLayer::setCircleOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
if (value == getCircleOpacity(klass))
return;
- impl->paint.circleOpacity.set(value, klass);
+ impl->paint.set<CircleOpacity>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -127,13 +127,13 @@ PropertyValue<std::array<float, 2>> CircleLayer::getDefaultCircleTranslate() {
}
PropertyValue<std::array<float, 2>> CircleLayer::getCircleTranslate(const optional<std::string>& klass) const {
- return impl->paint.circleTranslate.get(klass);
+ return impl->paint.get<CircleTranslate>(klass);
}
void CircleLayer::setCircleTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) {
if (value == getCircleTranslate(klass))
return;
- impl->paint.circleTranslate.set(value, klass);
+ impl->paint.set<CircleTranslate>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -142,13 +142,13 @@ PropertyValue<TranslateAnchorType> CircleLayer::getDefaultCircleTranslateAnchor(
}
PropertyValue<TranslateAnchorType> CircleLayer::getCircleTranslateAnchor(const optional<std::string>& klass) const {
- return impl->paint.circleTranslateAnchor.get(klass);
+ return impl->paint.get<CircleTranslateAnchor>(klass);
}
void CircleLayer::setCircleTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) {
if (value == getCircleTranslateAnchor(klass))
return;
- impl->paint.circleTranslateAnchor.set(value, klass);
+ impl->paint.set<CircleTranslateAnchor>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -157,13 +157,58 @@ PropertyValue<CirclePitchScaleType> CircleLayer::getDefaultCirclePitchScale() {
}
PropertyValue<CirclePitchScaleType> CircleLayer::getCirclePitchScale(const optional<std::string>& klass) const {
- return impl->paint.circlePitchScale.get(klass);
+ return impl->paint.get<CirclePitchScale>(klass);
}
void CircleLayer::setCirclePitchScale(PropertyValue<CirclePitchScaleType> value, const optional<std::string>& klass) {
if (value == getCirclePitchScale(klass))
return;
- impl->paint.circlePitchScale.set(value, klass);
+ impl->paint.set<CirclePitchScale>(value, klass);
+ impl->observer->onLayerPaintPropertyChanged(*this);
+}
+
+PropertyValue<float> CircleLayer::getDefaultCircleStrokeWidth() {
+ return { 0 };
+}
+
+PropertyValue<float> CircleLayer::getCircleStrokeWidth(const optional<std::string>& klass) const {
+ return impl->paint.get<CircleStrokeWidth>(klass);
+}
+
+void CircleLayer::setCircleStrokeWidth(PropertyValue<float> value, const optional<std::string>& klass) {
+ if (value == getCircleStrokeWidth(klass))
+ return;
+ impl->paint.set<CircleStrokeWidth>(value, klass);
+ impl->observer->onLayerPaintPropertyChanged(*this);
+}
+
+PropertyValue<Color> CircleLayer::getDefaultCircleStrokeColor() {
+ return { Color::black() };
+}
+
+PropertyValue<Color> CircleLayer::getCircleStrokeColor(const optional<std::string>& klass) const {
+ return impl->paint.get<CircleStrokeColor>(klass);
+}
+
+void CircleLayer::setCircleStrokeColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+ if (value == getCircleStrokeColor(klass))
+ return;
+ impl->paint.set<CircleStrokeColor>(value, klass);
+ impl->observer->onLayerPaintPropertyChanged(*this);
+}
+
+PropertyValue<float> CircleLayer::getDefaultCircleStrokeOpacity() {
+ return { 1 };
+}
+
+PropertyValue<float> CircleLayer::getCircleStrokeOpacity(const optional<std::string>& klass) const {
+ return impl->paint.get<CircleStrokeOpacity>(klass);
+}
+
+void CircleLayer::setCircleStrokeOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
+ if (value == getCircleStrokeOpacity(klass))
+ return;
+ impl->paint.set<CircleStrokeOpacity>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
diff --git a/src/mbgl/style/layers/circle_layer_impl.cpp b/src/mbgl/style/layers/circle_layer_impl.cpp
index 33699b6665..6599126702 100644
--- a/src/mbgl/style/layers/circle_layer_impl.cpp
+++ b/src/mbgl/style/layers/circle_layer_impl.cpp
@@ -12,13 +12,13 @@ void CircleLayer::Impl::cascade(const CascadeParameters& parameters) {
paint.cascade(parameters);
}
-bool CircleLayer::Impl::recalculate(const CalculationParameters& parameters) {
- bool hasTransitions = paint.recalculate(parameters);
+bool CircleLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) {
+ paint.evaluate(parameters);
- passes = (paint.circleRadius > 0 && paint.circleColor.value.a > 0 && paint.circleOpacity > 0)
+ passes = (paint.evaluated.get<CircleRadius>() > 0 && paint.evaluated.get<CircleColor>().a > 0 && paint.evaluated.get<CircleOpacity>() > 0)
? RenderPass::Translucent : RenderPass::None;
- return hasTransitions;
+ return paint.hasTransition();
}
std::unique_ptr<Bucket> CircleLayer::Impl::createBucket(BucketParameters& parameters) const {
@@ -35,8 +35,8 @@ std::unique_ptr<Bucket> CircleLayer::Impl::createBucket(BucketParameters& parame
}
float CircleLayer::Impl::getQueryRadius() const {
- const std::array<float, 2>& translate = paint.circleTranslate;
- return paint.circleRadius + util::length(translate[0], translate[1]);
+ const std::array<float, 2>& translate = paint.evaluated.get<CircleTranslate>();
+ return paint.evaluated.get<CircleRadius>() + util::length(translate[0], translate[1]);
}
bool CircleLayer::Impl::queryIntersectsGeometry(
@@ -46,9 +46,9 @@ bool CircleLayer::Impl::queryIntersectsGeometry(
const float pixelsToTileUnits) const {
auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry(
- queryGeometry, paint.circleTranslate, paint.circleTranslateAnchor, bearing, pixelsToTileUnits);
+ queryGeometry, paint.evaluated.get<CircleTranslate>(), paint.evaluated.get<CircleTranslateAnchor>(), bearing, pixelsToTileUnits);
- auto circleRadius = paint.circleRadius * pixelsToTileUnits;
+ auto circleRadius = paint.evaluated.get<CircleRadius>() * pixelsToTileUnits;
return util::polygonIntersectsBufferedMultiPoint(
translatedQueryGeometry.value_or(queryGeometry), geometry, circleRadius);
diff --git a/src/mbgl/style/layers/circle_layer_impl.hpp b/src/mbgl/style/layers/circle_layer_impl.hpp
index 14baaf84e4..df3b34cc1a 100644
--- a/src/mbgl/style/layers/circle_layer_impl.hpp
+++ b/src/mbgl/style/layers/circle_layer_impl.hpp
@@ -13,7 +13,7 @@ public:
std::unique_ptr<Layer> cloneRef(const std::string& id) const override;
void cascade(const CascadeParameters&) override;
- bool recalculate(const CalculationParameters&) override;
+ bool evaluate(const PropertyEvaluationParameters&) override;
std::unique_ptr<Bucket> createBucket(BucketParameters&) const override;
diff --git a/src/mbgl/style/layers/circle_layer_properties.cpp b/src/mbgl/style/layers/circle_layer_properties.cpp
index 7243cf87f4..af727fa36f 100644
--- a/src/mbgl/style/layers/circle_layer_properties.cpp
+++ b/src/mbgl/style/layers/circle_layer_properties.cpp
@@ -5,29 +5,5 @@
namespace mbgl {
namespace style {
-void CirclePaintProperties::cascade(const CascadeParameters& parameters) {
- circleRadius.cascade(parameters);
- circleColor.cascade(parameters);
- circleBlur.cascade(parameters);
- circleOpacity.cascade(parameters);
- circleTranslate.cascade(parameters);
- circleTranslateAnchor.cascade(parameters);
- circlePitchScale.cascade(parameters);
-}
-
-bool CirclePaintProperties::recalculate(const CalculationParameters& parameters) {
- bool hasTransitions = false;
-
- hasTransitions |= circleRadius.calculate(parameters);
- hasTransitions |= circleColor.calculate(parameters);
- hasTransitions |= circleBlur.calculate(parameters);
- hasTransitions |= circleOpacity.calculate(parameters);
- hasTransitions |= circleTranslate.calculate(parameters);
- hasTransitions |= circleTranslateAnchor.calculate(parameters);
- hasTransitions |= circlePitchScale.calculate(parameters);
-
- return hasTransitions;
-}
-
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layers/circle_layer_properties.hpp b/src/mbgl/style/layers/circle_layer_properties.hpp
index 0166bc8be4..ea36b31949 100644
--- a/src/mbgl/style/layers/circle_layer_properties.hpp
+++ b/src/mbgl/style/layers/circle_layer_properties.hpp
@@ -9,22 +9,58 @@
namespace mbgl {
namespace style {
-class CascadeParameters;
-class CalculationParameters;
-
-class CirclePaintProperties {
-public:
- void cascade(const CascadeParameters&);
- bool recalculate(const CalculationParameters&);
-
- PaintProperty<float> circleRadius { 5 };
- PaintProperty<Color> circleColor { Color::black() };
- PaintProperty<float> circleBlur { 0 };
- PaintProperty<float> circleOpacity { 1 };
- PaintProperty<std::array<float, 2>> circleTranslate { {{ 0, 0 }} };
- PaintProperty<TranslateAnchorType> circleTranslateAnchor { TranslateAnchorType::Map };
- PaintProperty<CirclePitchScaleType> circlePitchScale { CirclePitchScaleType::Map };
+struct CircleRadius : PaintProperty<float> {
+ static float defaultValue() { return 5; }
};
+struct CircleColor : PaintProperty<Color> {
+ static Color defaultValue() { return Color::black(); }
+};
+
+struct CircleBlur : PaintProperty<float> {
+ static float defaultValue() { return 0; }
+};
+
+struct CircleOpacity : PaintProperty<float> {
+ static float defaultValue() { return 1; }
+};
+
+struct CircleTranslate : PaintProperty<std::array<float, 2>> {
+ static std::array<float, 2> defaultValue() { return {{ 0, 0 }}; }
+};
+
+struct CircleTranslateAnchor : PaintProperty<TranslateAnchorType> {
+ static TranslateAnchorType defaultValue() { return TranslateAnchorType::Map; }
+};
+
+struct CirclePitchScale : PaintProperty<CirclePitchScaleType> {
+ static CirclePitchScaleType defaultValue() { return CirclePitchScaleType::Map; }
+};
+
+struct CircleStrokeWidth : PaintProperty<float> {
+ static float defaultValue() { return 0; }
+};
+
+struct CircleStrokeColor : PaintProperty<Color> {
+ static Color defaultValue() { return Color::black(); }
+};
+
+struct CircleStrokeOpacity : PaintProperty<float> {
+ static float defaultValue() { return 1; }
+};
+
+class CirclePaintProperties : public PaintProperties<
+ CircleRadius,
+ CircleColor,
+ CircleBlur,
+ CircleOpacity,
+ CircleTranslate,
+ CircleTranslateAnchor,
+ CirclePitchScale,
+ CircleStrokeWidth,
+ CircleStrokeColor,
+ CircleStrokeOpacity
+> {};
+
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layers/custom_layer_impl.cpp b/src/mbgl/style/layers/custom_layer_impl.cpp
index 8896d04ca1..50dcc0dda9 100644
--- a/src/mbgl/style/layers/custom_layer_impl.cpp
+++ b/src/mbgl/style/layers/custom_layer_impl.cpp
@@ -50,8 +50,8 @@ void CustomLayer::Impl::render(const TransformState& state) const {
CustomLayerRenderParameters parameters;
- parameters.width = state.getWidth();
- parameters.height = state.getHeight();
+ parameters.width = state.getSize().width;
+ parameters.height = state.getSize().height;
parameters.latitude = state.getLatLng().latitude;
parameters.longitude = state.getLatLng().longitude;
parameters.zoom = state.getZoom();
@@ -62,7 +62,7 @@ void CustomLayer::Impl::render(const TransformState& state) const {
renderFn(context, parameters);
}
-bool CustomLayer::Impl::recalculate(const CalculationParameters&) {
+bool CustomLayer::Impl::evaluate(const PropertyEvaluationParameters&) {
passes = RenderPass::Translucent;
return false;
}
diff --git a/src/mbgl/style/layers/custom_layer_impl.hpp b/src/mbgl/style/layers/custom_layer_impl.hpp
index b5b626ca5e..56e3f3146c 100644
--- a/src/mbgl/style/layers/custom_layer_impl.hpp
+++ b/src/mbgl/style/layers/custom_layer_impl.hpp
@@ -29,7 +29,7 @@ private:
std::unique_ptr<Layer> cloneRef(const std::string& id) const override;
void cascade(const CascadeParameters&) final {}
- bool recalculate(const CalculationParameters&) final;
+ bool evaluate(const PropertyEvaluationParameters&) final;
std::unique_ptr<Bucket> createBucket(BucketParameters&) const final;
diff --git a/src/mbgl/style/layers/fill_extrusion_layer.cpp b/src/mbgl/style/layers/fill_extrusion_layer.cpp
new file mode 100644
index 0000000000..64efb1dd6a
--- /dev/null
+++ b/src/mbgl/style/layers/fill_extrusion_layer.cpp
@@ -0,0 +1,171 @@
+// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`.
+
+#include <mbgl/style/layers/fill_extrusion_layer.hpp>
+#include <mbgl/style/layers/fill_extrusion_layer_impl.hpp>
+
+namespace mbgl {
+namespace style {
+
+FillExtrusionLayer::FillExtrusionLayer(const std::string& layerID, const std::string& sourceID)
+ : Layer(Type::FillExtrusion, std::make_unique<Impl>())
+ , impl(static_cast<Impl*>(baseImpl.get())) {
+ impl->id = layerID;
+ impl->source = sourceID;
+}
+
+FillExtrusionLayer::FillExtrusionLayer(const Impl& other)
+ : Layer(Type::FillExtrusion, std::make_unique<Impl>(other))
+ , impl(static_cast<Impl*>(baseImpl.get())) {
+}
+
+FillExtrusionLayer::~FillExtrusionLayer() = default;
+
+std::unique_ptr<Layer> FillExtrusionLayer::Impl::clone() const {
+ return std::make_unique<FillExtrusionLayer>(*this);
+}
+
+std::unique_ptr<Layer> FillExtrusionLayer::Impl::cloneRef(const std::string& id_) const {
+ auto result = std::make_unique<FillExtrusionLayer>(*this);
+ result->impl->id = id_;
+ result->impl->ref = this->id;
+ result->impl->paint = FillExtrusionPaintProperties();
+ return std::move(result);
+}
+
+// Source
+
+const std::string& FillExtrusionLayer::getSourceID() const {
+ return impl->source;
+}
+
+void FillExtrusionLayer::setSourceLayer(const std::string& sourceLayer) {
+ impl->sourceLayer = sourceLayer;
+}
+
+const std::string& FillExtrusionLayer::getSourceLayer() const {
+ return impl->sourceLayer;
+}
+
+// Filter
+
+void FillExtrusionLayer::setFilter(const Filter& filter) {
+ impl->filter = filter;
+ impl->observer->onLayerFilterChanged(*this);
+}
+
+const Filter& FillExtrusionLayer::getFilter() const {
+ return impl->filter;
+}
+
+// Layout properties
+
+
+// Paint properties
+
+PropertyValue<float> FillExtrusionLayer::getDefaultFillExtrusionOpacity() {
+ return { 1 };
+}
+
+PropertyValue<float> FillExtrusionLayer::getFillExtrusionOpacity(const optional<std::string>& klass) const {
+ return impl->paint.get<FillExtrusionOpacity>(klass);
+}
+
+void FillExtrusionLayer::setFillExtrusionOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
+ if (value == getFillExtrusionOpacity(klass))
+ return;
+ impl->paint.set<FillExtrusionOpacity>(value, klass);
+ impl->observer->onLayerPaintPropertyChanged(*this);
+}
+
+PropertyValue<Color> FillExtrusionLayer::getDefaultFillExtrusionColor() {
+ return { Color::black() };
+}
+
+PropertyValue<Color> FillExtrusionLayer::getFillExtrusionColor(const optional<std::string>& klass) const {
+ return impl->paint.get<FillExtrusionColor>(klass);
+}
+
+void FillExtrusionLayer::setFillExtrusionColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+ if (value == getFillExtrusionColor(klass))
+ return;
+ impl->paint.set<FillExtrusionColor>(value, klass);
+ impl->observer->onLayerPaintPropertyChanged(*this);
+}
+
+PropertyValue<std::array<float, 2>> FillExtrusionLayer::getDefaultFillExtrusionTranslate() {
+ return { {{ 0, 0 }} };
+}
+
+PropertyValue<std::array<float, 2>> FillExtrusionLayer::getFillExtrusionTranslate(const optional<std::string>& klass) const {
+ return impl->paint.get<FillExtrusionTranslate>(klass);
+}
+
+void FillExtrusionLayer::setFillExtrusionTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) {
+ if (value == getFillExtrusionTranslate(klass))
+ return;
+ impl->paint.set<FillExtrusionTranslate>(value, klass);
+ impl->observer->onLayerPaintPropertyChanged(*this);
+}
+
+PropertyValue<TranslateAnchorType> FillExtrusionLayer::getDefaultFillExtrusionTranslateAnchor() {
+ return { TranslateAnchorType::Map };
+}
+
+PropertyValue<TranslateAnchorType> FillExtrusionLayer::getFillExtrusionTranslateAnchor(const optional<std::string>& klass) const {
+ return impl->paint.get<FillExtrusionTranslateAnchor>(klass);
+}
+
+void FillExtrusionLayer::setFillExtrusionTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) {
+ if (value == getFillExtrusionTranslateAnchor(klass))
+ return;
+ impl->paint.set<FillExtrusionTranslateAnchor>(value, klass);
+ impl->observer->onLayerPaintPropertyChanged(*this);
+}
+
+PropertyValue<std::string> FillExtrusionLayer::getDefaultFillExtrusionPattern() {
+ return { "" };
+}
+
+PropertyValue<std::string> FillExtrusionLayer::getFillExtrusionPattern(const optional<std::string>& klass) const {
+ return impl->paint.get<FillExtrusionPattern>(klass);
+}
+
+void FillExtrusionLayer::setFillExtrusionPattern(PropertyValue<std::string> value, const optional<std::string>& klass) {
+ if (value == getFillExtrusionPattern(klass))
+ return;
+ impl->paint.set<FillExtrusionPattern>(value, klass);
+ impl->observer->onLayerPaintPropertyChanged(*this);
+}
+
+PropertyValue<float> FillExtrusionLayer::getDefaultFillExtrusionHeight() {
+ return { 0 };
+}
+
+PropertyValue<float> FillExtrusionLayer::getFillExtrusionHeight(const optional<std::string>& klass) const {
+ return impl->paint.get<FillExtrusionHeight>(klass);
+}
+
+void FillExtrusionLayer::setFillExtrusionHeight(PropertyValue<float> value, const optional<std::string>& klass) {
+ if (value == getFillExtrusionHeight(klass))
+ return;
+ impl->paint.set<FillExtrusionHeight>(value, klass);
+ impl->observer->onLayerPaintPropertyChanged(*this);
+}
+
+PropertyValue<float> FillExtrusionLayer::getDefaultFillExtrusionBase() {
+ return { 0 };
+}
+
+PropertyValue<float> FillExtrusionLayer::getFillExtrusionBase(const optional<std::string>& klass) const {
+ return impl->paint.get<FillExtrusionBase>(klass);
+}
+
+void FillExtrusionLayer::setFillExtrusionBase(PropertyValue<float> value, const optional<std::string>& klass) {
+ if (value == getFillExtrusionBase(klass))
+ return;
+ impl->paint.set<FillExtrusionBase>(value, klass);
+ impl->observer->onLayerPaintPropertyChanged(*this);
+}
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp b/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp
new file mode 100644
index 0000000000..239f7754d0
--- /dev/null
+++ b/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp
@@ -0,0 +1,19 @@
+#include <mbgl/style/layers/fill_extrusion_layer_impl.hpp>
+#include <mbgl/renderer/bucket.hpp>
+
+namespace mbgl {
+namespace style {
+
+void FillExtrusionLayer::Impl::cascade(const CascadeParameters&) {
+}
+
+bool FillExtrusionLayer::Impl::evaluate(const PropertyEvaluationParameters&) {
+ return false;
+}
+
+std::unique_ptr<Bucket> FillExtrusionLayer::Impl::createBucket(BucketParameters&) const {
+ return nullptr;
+}
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp b/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp
new file mode 100644
index 0000000000..79ae02dd5b
--- /dev/null
+++ b/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <mbgl/style/layer_impl.hpp>
+#include <mbgl/style/layers/fill_extrusion_layer.hpp>
+#include <mbgl/style/layers/fill_extrusion_layer_properties.hpp>
+
+namespace mbgl {
+namespace style {
+
+class FillExtrusionLayer::Impl : public Layer::Impl {
+public:
+ std::unique_ptr<Layer> clone() const override;
+ std::unique_ptr<Layer> cloneRef(const std::string& id) const override;
+
+ void cascade(const CascadeParameters&) override;
+ bool evaluate(const PropertyEvaluationParameters&) override;
+
+ std::unique_ptr<Bucket> createBucket(BucketParameters&) const override;
+
+ FillExtrusionPaintProperties paint;
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/layers/fill_extrusion_layer_properties.cpp b/src/mbgl/style/layers/fill_extrusion_layer_properties.cpp
new file mode 100644
index 0000000000..59572bd3ab
--- /dev/null
+++ b/src/mbgl/style/layers/fill_extrusion_layer_properties.cpp
@@ -0,0 +1,9 @@
+// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`.
+
+#include <mbgl/style/layers/fill_extrusion_layer_properties.hpp>
+
+namespace mbgl {
+namespace style {
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp b/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp
new file mode 100644
index 0000000000..a2d01199a5
--- /dev/null
+++ b/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp
@@ -0,0 +1,51 @@
+// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`.
+
+#pragma once
+
+#include <mbgl/style/types.hpp>
+#include <mbgl/style/layout_property.hpp>
+#include <mbgl/style/paint_property.hpp>
+
+namespace mbgl {
+namespace style {
+
+struct FillExtrusionOpacity : PaintProperty<float> {
+ static float defaultValue() { return 1; }
+};
+
+struct FillExtrusionColor : PaintProperty<Color> {
+ static Color defaultValue() { return Color::black(); }
+};
+
+struct FillExtrusionTranslate : PaintProperty<std::array<float, 2>> {
+ static std::array<float, 2> defaultValue() { return {{ 0, 0 }}; }
+};
+
+struct FillExtrusionTranslateAnchor : PaintProperty<TranslateAnchorType> {
+ static TranslateAnchorType defaultValue() { return TranslateAnchorType::Map; }
+};
+
+struct FillExtrusionPattern : CrossFadedPaintProperty<std::string> {
+ static std::string defaultValue() { return ""; }
+};
+
+struct FillExtrusionHeight : PaintProperty<float> {
+ static float defaultValue() { return 0; }
+};
+
+struct FillExtrusionBase : PaintProperty<float> {
+ static float defaultValue() { return 0; }
+};
+
+class FillExtrusionPaintProperties : public PaintProperties<
+ FillExtrusionOpacity,
+ FillExtrusionColor,
+ FillExtrusionTranslate,
+ FillExtrusionTranslateAnchor,
+ FillExtrusionPattern,
+ FillExtrusionHeight,
+ FillExtrusionBase
+> {};
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/layers/fill_layer.cpp b/src/mbgl/style/layers/fill_layer.cpp
index c61de81d1a..3bea9b56b0 100644
--- a/src/mbgl/style/layers/fill_layer.cpp
+++ b/src/mbgl/style/layers/fill_layer.cpp
@@ -67,13 +67,13 @@ PropertyValue<bool> FillLayer::getDefaultFillAntialias() {
}
PropertyValue<bool> FillLayer::getFillAntialias(const optional<std::string>& klass) const {
- return impl->paint.fillAntialias.get(klass);
+ return impl->paint.get<FillAntialias>(klass);
}
void FillLayer::setFillAntialias(PropertyValue<bool> value, const optional<std::string>& klass) {
if (value == getFillAntialias(klass))
return;
- impl->paint.fillAntialias.set(value, klass);
+ impl->paint.set<FillAntialias>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -82,13 +82,13 @@ PropertyValue<float> FillLayer::getDefaultFillOpacity() {
}
PropertyValue<float> FillLayer::getFillOpacity(const optional<std::string>& klass) const {
- return impl->paint.fillOpacity.get(klass);
+ return impl->paint.get<FillOpacity>(klass);
}
void FillLayer::setFillOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
if (value == getFillOpacity(klass))
return;
- impl->paint.fillOpacity.set(value, klass);
+ impl->paint.set<FillOpacity>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -97,13 +97,13 @@ PropertyValue<Color> FillLayer::getDefaultFillColor() {
}
PropertyValue<Color> FillLayer::getFillColor(const optional<std::string>& klass) const {
- return impl->paint.fillColor.get(klass);
+ return impl->paint.get<FillColor>(klass);
}
void FillLayer::setFillColor(PropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getFillColor(klass))
return;
- impl->paint.fillColor.set(value, klass);
+ impl->paint.set<FillColor>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -112,13 +112,13 @@ PropertyValue<Color> FillLayer::getDefaultFillOutlineColor() {
}
PropertyValue<Color> FillLayer::getFillOutlineColor(const optional<std::string>& klass) const {
- return impl->paint.fillOutlineColor.get(klass);
+ return impl->paint.get<FillOutlineColor>(klass);
}
void FillLayer::setFillOutlineColor(PropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getFillOutlineColor(klass))
return;
- impl->paint.fillOutlineColor.set(value, klass);
+ impl->paint.set<FillOutlineColor>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -127,13 +127,13 @@ PropertyValue<std::array<float, 2>> FillLayer::getDefaultFillTranslate() {
}
PropertyValue<std::array<float, 2>> FillLayer::getFillTranslate(const optional<std::string>& klass) const {
- return impl->paint.fillTranslate.get(klass);
+ return impl->paint.get<FillTranslate>(klass);
}
void FillLayer::setFillTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) {
if (value == getFillTranslate(klass))
return;
- impl->paint.fillTranslate.set(value, klass);
+ impl->paint.set<FillTranslate>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -142,13 +142,13 @@ PropertyValue<TranslateAnchorType> FillLayer::getDefaultFillTranslateAnchor() {
}
PropertyValue<TranslateAnchorType> FillLayer::getFillTranslateAnchor(const optional<std::string>& klass) const {
- return impl->paint.fillTranslateAnchor.get(klass);
+ return impl->paint.get<FillTranslateAnchor>(klass);
}
void FillLayer::setFillTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) {
if (value == getFillTranslateAnchor(klass))
return;
- impl->paint.fillTranslateAnchor.set(value, klass);
+ impl->paint.set<FillTranslateAnchor>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -157,13 +157,13 @@ PropertyValue<std::string> FillLayer::getDefaultFillPattern() {
}
PropertyValue<std::string> FillLayer::getFillPattern(const optional<std::string>& klass) const {
- return impl->paint.fillPattern.get(klass);
+ return impl->paint.get<FillPattern>(klass);
}
void FillLayer::setFillPattern(PropertyValue<std::string> value, const optional<std::string>& klass) {
if (value == getFillPattern(klass))
return;
- impl->paint.fillPattern.set(value, klass);
+ impl->paint.set<FillPattern>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
diff --git a/src/mbgl/style/layers/fill_layer_impl.cpp b/src/mbgl/style/layers/fill_layer_impl.cpp
index fc439f1cd1..6a690ba447 100644
--- a/src/mbgl/style/layers/fill_layer_impl.cpp
+++ b/src/mbgl/style/layers/fill_layer_impl.cpp
@@ -12,22 +12,22 @@ void FillLayer::Impl::cascade(const CascadeParameters& parameters) {
paint.cascade(parameters);
}
-bool FillLayer::Impl::recalculate(const CalculationParameters& parameters) {
- bool hasTransitions = paint.recalculate(parameters);
+bool FillLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) {
+ paint.evaluate(parameters);
passes = RenderPass::None;
- if (paint.fillAntialias) {
+ if (paint.evaluated.get<FillAntialias>()) {
passes |= RenderPass::Translucent;
}
- if (!paint.fillPattern.value.from.empty() || (paint.fillColor.value.a * paint.fillOpacity) < 1.0f) {
+ if (!paint.evaluated.get<FillPattern>().from.empty() || (paint.evaluated.get<FillColor>().a * paint.evaluated.get<FillOpacity>()) < 1.0f) {
passes |= RenderPass::Translucent;
} else {
passes |= RenderPass::Opaque;
}
- return hasTransitions;
+ return paint.hasTransition();
}
std::unique_ptr<Bucket> FillLayer::Impl::createBucket(BucketParameters& parameters) const {
@@ -44,7 +44,7 @@ std::unique_ptr<Bucket> FillLayer::Impl::createBucket(BucketParameters& paramete
}
float FillLayer::Impl::getQueryRadius() const {
- const std::array<float, 2>& translate = paint.fillTranslate;
+ const std::array<float, 2>& translate = paint.evaluated.get<FillTranslate>();
return util::length(translate[0], translate[1]);
}
@@ -55,7 +55,7 @@ bool FillLayer::Impl::queryIntersectsGeometry(
const float pixelsToTileUnits) const {
auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry(
- queryGeometry, paint.fillTranslate, paint.fillTranslateAnchor, bearing, pixelsToTileUnits);
+ queryGeometry, paint.evaluated.get<FillTranslate>(), paint.evaluated.get<FillTranslateAnchor>(), bearing, pixelsToTileUnits);
return util::polygonIntersectsMultiPolygon(translatedQueryGeometry.value_or(queryGeometry), geometry);
}
diff --git a/src/mbgl/style/layers/fill_layer_impl.hpp b/src/mbgl/style/layers/fill_layer_impl.hpp
index 54cfb80c86..53276d744a 100644
--- a/src/mbgl/style/layers/fill_layer_impl.hpp
+++ b/src/mbgl/style/layers/fill_layer_impl.hpp
@@ -13,7 +13,7 @@ public:
std::unique_ptr<Layer> cloneRef(const std::string& id) const override;
void cascade(const CascadeParameters&) override;
- bool recalculate(const CalculationParameters&) override;
+ bool evaluate(const PropertyEvaluationParameters&) override;
std::unique_ptr<Bucket> createBucket(BucketParameters&) const override;
diff --git a/src/mbgl/style/layers/fill_layer_properties.cpp b/src/mbgl/style/layers/fill_layer_properties.cpp
index 9a55cbc145..b07a083950 100644
--- a/src/mbgl/style/layers/fill_layer_properties.cpp
+++ b/src/mbgl/style/layers/fill_layer_properties.cpp
@@ -5,29 +5,5 @@
namespace mbgl {
namespace style {
-void FillPaintProperties::cascade(const CascadeParameters& parameters) {
- fillAntialias.cascade(parameters);
- fillOpacity.cascade(parameters);
- fillColor.cascade(parameters);
- fillOutlineColor.cascade(parameters);
- fillTranslate.cascade(parameters);
- fillTranslateAnchor.cascade(parameters);
- fillPattern.cascade(parameters);
-}
-
-bool FillPaintProperties::recalculate(const CalculationParameters& parameters) {
- bool hasTransitions = false;
-
- hasTransitions |= fillAntialias.calculate(parameters);
- hasTransitions |= fillOpacity.calculate(parameters);
- hasTransitions |= fillColor.calculate(parameters);
- hasTransitions |= fillOutlineColor.calculate(parameters);
- hasTransitions |= fillTranslate.calculate(parameters);
- hasTransitions |= fillTranslateAnchor.calculate(parameters);
- hasTransitions |= fillPattern.calculate(parameters);
-
- return hasTransitions;
-}
-
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layers/fill_layer_properties.hpp b/src/mbgl/style/layers/fill_layer_properties.hpp
index d12eb8d6f4..b2d926c31e 100644
--- a/src/mbgl/style/layers/fill_layer_properties.hpp
+++ b/src/mbgl/style/layers/fill_layer_properties.hpp
@@ -9,22 +9,43 @@
namespace mbgl {
namespace style {
-class CascadeParameters;
-class CalculationParameters;
-
-class FillPaintProperties {
-public:
- void cascade(const CascadeParameters&);
- bool recalculate(const CalculationParameters&);
-
- PaintProperty<bool> fillAntialias { true };
- PaintProperty<float> fillOpacity { 1 };
- PaintProperty<Color> fillColor { Color::black() };
- PaintProperty<Color> fillOutlineColor { {} };
- PaintProperty<std::array<float, 2>> fillTranslate { {{ 0, 0 }} };
- PaintProperty<TranslateAnchorType> fillTranslateAnchor { TranslateAnchorType::Map };
- PaintProperty<std::string, CrossFadedPropertyEvaluator> fillPattern { "" };
+struct FillAntialias : PaintProperty<bool> {
+ static bool defaultValue() { return true; }
};
+struct FillOpacity : PaintProperty<float> {
+ static float defaultValue() { return 1; }
+};
+
+struct FillColor : PaintProperty<Color> {
+ static Color defaultValue() { return Color::black(); }
+};
+
+struct FillOutlineColor : PaintProperty<Color> {
+ static Color defaultValue() { return {}; }
+};
+
+struct FillTranslate : PaintProperty<std::array<float, 2>> {
+ static std::array<float, 2> defaultValue() { return {{ 0, 0 }}; }
+};
+
+struct FillTranslateAnchor : PaintProperty<TranslateAnchorType> {
+ static TranslateAnchorType defaultValue() { return TranslateAnchorType::Map; }
+};
+
+struct FillPattern : CrossFadedPaintProperty<std::string> {
+ static std::string defaultValue() { return ""; }
+};
+
+class FillPaintProperties : public PaintProperties<
+ FillAntialias,
+ FillOpacity,
+ FillColor,
+ FillOutlineColor,
+ FillTranslate,
+ FillTranslateAnchor,
+ FillPattern
+> {};
+
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs
index c2cbc56a09..5fe78519ec 100644
--- a/src/mbgl/style/layers/layer.cpp.ejs
+++ b/src/mbgl/style/layers/layer.cpp.ejs
@@ -5,8 +5,8 @@
-%>
// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`.
-#include <mbgl/style/layers/<%- type %>_layer.hpp>
-#include <mbgl/style/layers/<%- type %>_layer_impl.hpp>
+#include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer.hpp>
+#include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer_impl.hpp>
namespace mbgl {
namespace style {
@@ -78,17 +78,17 @@ const Filter& <%- camelize(type) %>Layer::getFilter() const {
<% for (const property of layoutProperties) { -%>
PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::getDefault<%- camelize(property.name) %>() {
- return { <%- defaultValue(property) %> };
+ return <%- camelize(property.name) %>::defaultValue();
}
PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>() const {
- return impl->layout.<%- camelizeWithLeadingLowercase(property.name) %>.get();
+ return impl->layout.unevaluated.get<<%- camelize(property.name) %>>();
}
void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(PropertyValue<<%- propertyType(property) %>> value) {
if (value == get<%- camelize(property.name) %>())
return;
- impl->layout.<%- camelizeWithLeadingLowercase(property.name) %>.set(value);
+ impl->layout.unevaluated.get<<%- camelize(property.name) %>>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "<%- property.name %>");
}
<% } -%>
@@ -100,13 +100,13 @@ PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::getDefa
}
PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>(const optional<std::string>& klass) const {
- return impl->paint.<%- camelizeWithLeadingLowercase(property.name) %>.get(klass);
+ return impl->paint.get<<%- camelize(property.name) %>>(klass);
}
void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(PropertyValue<<%- propertyType(property) %>> value, const optional<std::string>& klass) {
if (value == get<%- camelize(property.name) %>(klass))
return;
- impl->paint.<%- camelizeWithLeadingLowercase(property.name) %>.set(value, klass);
+ impl->paint.set<<%- camelize(property.name) %>>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
<% } -%>
diff --git a/src/mbgl/style/layers/layer_properties.cpp.ejs b/src/mbgl/style/layers/layer_properties.cpp.ejs
index b781a4a9d9..e5523e5439 100644
--- a/src/mbgl/style/layers/layer_properties.cpp.ejs
+++ b/src/mbgl/style/layers/layer_properties.cpp.ejs
@@ -5,34 +5,10 @@
-%>
// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`.
-#include <mbgl/style/layers/<%- type %>_layer_properties.hpp>
+#include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer_properties.hpp>
namespace mbgl {
namespace style {
-<% if (layoutProperties.length) { -%>
-void <%- camelize(type) %>LayoutProperties::recalculate(const CalculationParameters& parameters) {
-<% for (const property of layoutProperties) { -%>
- <%- camelizeWithLeadingLowercase(property.name) %>.calculate(parameters);
-<% } -%>
-}
-
-<% } -%>
-void <%- camelize(type) %>PaintProperties::cascade(const CascadeParameters& parameters) {
-<% for (const property of paintProperties) { -%>
- <%- camelizeWithLeadingLowercase(property.name) %>.cascade(parameters);
-<% } -%>
-}
-
-bool <%- camelize(type) %>PaintProperties::recalculate(const CalculationParameters& parameters) {
- bool hasTransitions = false;
-
-<% for (const property of paintProperties) { -%>
- hasTransitions |= <%- camelizeWithLeadingLowercase(property.name) %>.calculate(parameters);
-<% } -%>
-
- return hasTransitions;
-}
-
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layers/layer_properties.hpp.ejs b/src/mbgl/style/layers/layer_properties.hpp.ejs
index 0c91ecba8c..f490a636f9 100644
--- a/src/mbgl/style/layers/layer_properties.hpp.ejs
+++ b/src/mbgl/style/layers/layer_properties.hpp.ejs
@@ -14,33 +14,35 @@
namespace mbgl {
namespace style {
-class CascadeParameters;
-class CalculationParameters;
-
-<% if (layoutProperties.length) { -%>
-class <%- camelize(type) %>LayoutProperties {
-public:
- void recalculate(const CalculationParameters&);
-
<% for (const property of layoutProperties) { -%>
- LayoutProperty<<%- propertyType(property) %>> <%- camelizeWithLeadingLowercase(property.name) %> { <%- defaultValue(property) %> };
+struct <%- camelize(property.name) %> : LayoutProperty<<%- propertyType(property) %>> {
+ static <%- propertyType(property) %> defaultValue() { return <%- defaultValue(property) %>; }
+};
+
<% } -%>
+<% for (const property of paintProperties) { -%>
+struct <%- camelize(property.name) %> : <%
+if (/-pattern$/.test(property.name) || property.name === 'line-dasharray') {
+%>CrossFaded<% } -%>PaintProperty<<%- propertyType(property) %>> {
+ static <%- propertyType(property) %> defaultValue() { return <%- defaultValue(property) %>; }
};
<% } -%>
-class <%- camelize(type) %>PaintProperties {
-public:
- void cascade(const CascadeParameters&);
- bool recalculate(const CalculationParameters&);
+<% if (layoutProperties.length) { -%>
+class <%- camelize(type) %>LayoutProperties : public LayoutProperties<
+<% for (const property of layoutProperties.slice(0, -1)) { -%>
+ <%- camelize(property.name) %>,
+<% } -%>
+ <%- camelize(layoutProperties.slice(-1)[0].name) %>
+> {};
-<% for (const property of paintProperties) { -%>
-<% if (/-pattern$/.test(property.name) || property.name === 'line-dasharray') { -%>
- PaintProperty<<%- propertyType(property) %>, CrossFadedPropertyEvaluator> <%- camelizeWithLeadingLowercase(property.name) %> { <%- defaultValue(property) %> };
-<% } else { -%>
- PaintProperty<<%- propertyType(property) %>> <%- camelizeWithLeadingLowercase(property.name) %> { <%- defaultValue(property) %> };
<% } -%>
+class <%- camelize(type) %>PaintProperties : public PaintProperties<
+<% for (const property of paintProperties.slice(0, -1)) { -%>
+ <%- camelize(property.name) %>,
<% } -%>
-};
+ <%- camelize(paintProperties.slice(-1)[0].name) %>
+> {};
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layers/line_layer.cpp b/src/mbgl/style/layers/line_layer.cpp
index 49ecf63c18..8c38ef5694 100644
--- a/src/mbgl/style/layers/line_layer.cpp
+++ b/src/mbgl/style/layers/line_layer.cpp
@@ -60,59 +60,59 @@ const Filter& LineLayer::getFilter() const {
// Layout properties
PropertyValue<LineCapType> LineLayer::getDefaultLineCap() {
- return { LineCapType::Butt };
+ return LineCap::defaultValue();
}
PropertyValue<LineCapType> LineLayer::getLineCap() const {
- return impl->layout.lineCap.get();
+ return impl->layout.unevaluated.get<LineCap>();
}
void LineLayer::setLineCap(PropertyValue<LineCapType> value) {
if (value == getLineCap())
return;
- impl->layout.lineCap.set(value);
+ impl->layout.unevaluated.get<LineCap>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "line-cap");
}
PropertyValue<LineJoinType> LineLayer::getDefaultLineJoin() {
- return { LineJoinType::Miter };
+ return LineJoin::defaultValue();
}
PropertyValue<LineJoinType> LineLayer::getLineJoin() const {
- return impl->layout.lineJoin.get();
+ return impl->layout.unevaluated.get<LineJoin>();
}
void LineLayer::setLineJoin(PropertyValue<LineJoinType> value) {
if (value == getLineJoin())
return;
- impl->layout.lineJoin.set(value);
+ impl->layout.unevaluated.get<LineJoin>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "line-join");
}
PropertyValue<float> LineLayer::getDefaultLineMiterLimit() {
- return { 2 };
+ return LineMiterLimit::defaultValue();
}
PropertyValue<float> LineLayer::getLineMiterLimit() const {
- return impl->layout.lineMiterLimit.get();
+ return impl->layout.unevaluated.get<LineMiterLimit>();
}
void LineLayer::setLineMiterLimit(PropertyValue<float> value) {
if (value == getLineMiterLimit())
return;
- impl->layout.lineMiterLimit.set(value);
+ impl->layout.unevaluated.get<LineMiterLimit>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "line-miter-limit");
}
PropertyValue<float> LineLayer::getDefaultLineRoundLimit() {
- return { 1 };
+ return LineRoundLimit::defaultValue();
}
PropertyValue<float> LineLayer::getLineRoundLimit() const {
- return impl->layout.lineRoundLimit.get();
+ return impl->layout.unevaluated.get<LineRoundLimit>();
}
void LineLayer::setLineRoundLimit(PropertyValue<float> value) {
if (value == getLineRoundLimit())
return;
- impl->layout.lineRoundLimit.set(value);
+ impl->layout.unevaluated.get<LineRoundLimit>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "line-round-limit");
}
@@ -123,13 +123,13 @@ PropertyValue<float> LineLayer::getDefaultLineOpacity() {
}
PropertyValue<float> LineLayer::getLineOpacity(const optional<std::string>& klass) const {
- return impl->paint.lineOpacity.get(klass);
+ return impl->paint.get<LineOpacity>(klass);
}
void LineLayer::setLineOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
if (value == getLineOpacity(klass))
return;
- impl->paint.lineOpacity.set(value, klass);
+ impl->paint.set<LineOpacity>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -138,13 +138,13 @@ PropertyValue<Color> LineLayer::getDefaultLineColor() {
}
PropertyValue<Color> LineLayer::getLineColor(const optional<std::string>& klass) const {
- return impl->paint.lineColor.get(klass);
+ return impl->paint.get<LineColor>(klass);
}
void LineLayer::setLineColor(PropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getLineColor(klass))
return;
- impl->paint.lineColor.set(value, klass);
+ impl->paint.set<LineColor>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -153,13 +153,13 @@ PropertyValue<std::array<float, 2>> LineLayer::getDefaultLineTranslate() {
}
PropertyValue<std::array<float, 2>> LineLayer::getLineTranslate(const optional<std::string>& klass) const {
- return impl->paint.lineTranslate.get(klass);
+ return impl->paint.get<LineTranslate>(klass);
}
void LineLayer::setLineTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) {
if (value == getLineTranslate(klass))
return;
- impl->paint.lineTranslate.set(value, klass);
+ impl->paint.set<LineTranslate>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -168,13 +168,13 @@ PropertyValue<TranslateAnchorType> LineLayer::getDefaultLineTranslateAnchor() {
}
PropertyValue<TranslateAnchorType> LineLayer::getLineTranslateAnchor(const optional<std::string>& klass) const {
- return impl->paint.lineTranslateAnchor.get(klass);
+ return impl->paint.get<LineTranslateAnchor>(klass);
}
void LineLayer::setLineTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) {
if (value == getLineTranslateAnchor(klass))
return;
- impl->paint.lineTranslateAnchor.set(value, klass);
+ impl->paint.set<LineTranslateAnchor>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -183,13 +183,13 @@ PropertyValue<float> LineLayer::getDefaultLineWidth() {
}
PropertyValue<float> LineLayer::getLineWidth(const optional<std::string>& klass) const {
- return impl->paint.lineWidth.get(klass);
+ return impl->paint.get<LineWidth>(klass);
}
void LineLayer::setLineWidth(PropertyValue<float> value, const optional<std::string>& klass) {
if (value == getLineWidth(klass))
return;
- impl->paint.lineWidth.set(value, klass);
+ impl->paint.set<LineWidth>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -198,13 +198,13 @@ PropertyValue<float> LineLayer::getDefaultLineGapWidth() {
}
PropertyValue<float> LineLayer::getLineGapWidth(const optional<std::string>& klass) const {
- return impl->paint.lineGapWidth.get(klass);
+ return impl->paint.get<LineGapWidth>(klass);
}
void LineLayer::setLineGapWidth(PropertyValue<float> value, const optional<std::string>& klass) {
if (value == getLineGapWidth(klass))
return;
- impl->paint.lineGapWidth.set(value, klass);
+ impl->paint.set<LineGapWidth>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -213,13 +213,13 @@ PropertyValue<float> LineLayer::getDefaultLineOffset() {
}
PropertyValue<float> LineLayer::getLineOffset(const optional<std::string>& klass) const {
- return impl->paint.lineOffset.get(klass);
+ return impl->paint.get<LineOffset>(klass);
}
void LineLayer::setLineOffset(PropertyValue<float> value, const optional<std::string>& klass) {
if (value == getLineOffset(klass))
return;
- impl->paint.lineOffset.set(value, klass);
+ impl->paint.set<LineOffset>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -228,13 +228,13 @@ PropertyValue<float> LineLayer::getDefaultLineBlur() {
}
PropertyValue<float> LineLayer::getLineBlur(const optional<std::string>& klass) const {
- return impl->paint.lineBlur.get(klass);
+ return impl->paint.get<LineBlur>(klass);
}
void LineLayer::setLineBlur(PropertyValue<float> value, const optional<std::string>& klass) {
if (value == getLineBlur(klass))
return;
- impl->paint.lineBlur.set(value, klass);
+ impl->paint.set<LineBlur>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -243,13 +243,13 @@ PropertyValue<std::vector<float>> LineLayer::getDefaultLineDasharray() {
}
PropertyValue<std::vector<float>> LineLayer::getLineDasharray(const optional<std::string>& klass) const {
- return impl->paint.lineDasharray.get(klass);
+ return impl->paint.get<LineDasharray>(klass);
}
void LineLayer::setLineDasharray(PropertyValue<std::vector<float>> value, const optional<std::string>& klass) {
if (value == getLineDasharray(klass))
return;
- impl->paint.lineDasharray.set(value, klass);
+ impl->paint.set<LineDasharray>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -258,13 +258,13 @@ PropertyValue<std::string> LineLayer::getDefaultLinePattern() {
}
PropertyValue<std::string> LineLayer::getLinePattern(const optional<std::string>& klass) const {
- return impl->paint.linePattern.get(klass);
+ return impl->paint.get<LinePattern>(klass);
}
void LineLayer::setLinePattern(PropertyValue<std::string> value, const optional<std::string>& klass) {
if (value == getLinePattern(klass))
return;
- impl->paint.linePattern.set(value, klass);
+ impl->paint.set<LinePattern>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
diff --git a/src/mbgl/style/layers/line_layer_impl.cpp b/src/mbgl/style/layers/line_layer_impl.cpp
index c116af5fc2..e6ec21a659 100644
--- a/src/mbgl/style/layers/line_layer_impl.cpp
+++ b/src/mbgl/style/layers/line_layer_impl.cpp
@@ -12,26 +12,24 @@ void LineLayer::Impl::cascade(const CascadeParameters& parameters) {
paint.cascade(parameters);
}
-bool LineLayer::Impl::recalculate(const CalculationParameters& parameters) {
+bool LineLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) {
// for scaling dasharrays
- CalculationParameters dashArrayParams = parameters;
+ PropertyEvaluationParameters dashArrayParams = parameters;
dashArrayParams.z = std::floor(dashArrayParams.z);
- paint.lineWidth.calculate(dashArrayParams);
- dashLineWidth = paint.lineWidth;
+ dashLineWidth = paint.evaluate<LineWidth>(dashArrayParams);
- bool hasTransitions = paint.recalculate(parameters);
+ paint.evaluate(parameters);
- passes = (paint.lineOpacity > 0 && paint.lineColor.value.a > 0 && paint.lineWidth > 0)
+ passes = (paint.evaluated.get<LineOpacity>() > 0 && paint.evaluated.get<LineColor>().a > 0 && paint.evaluated.get<LineWidth>() > 0)
? RenderPass::Translucent : RenderPass::None;
- return hasTransitions;
+ return paint.hasTransition();
}
std::unique_ptr<Bucket> LineLayer::Impl::createBucket(BucketParameters& parameters) const {
auto bucket = std::make_unique<LineBucket>(parameters.tileID.overscaleFactor());
- bucket->layout = layout;
- bucket->layout.recalculate(CalculationParameters(parameters.tileID.overscaledZ));
+ bucket->layout = layout.evaluate(PropertyEvaluationParameters(parameters.tileID.overscaledZ));
auto& name = bucketName();
parameters.eachFilteredFeature(filter, [&] (const auto& feature, std::size_t index, const std::string& layerName) {
@@ -44,10 +42,10 @@ std::unique_ptr<Bucket> LineLayer::Impl::createBucket(BucketParameters& paramete
}
float LineLayer::Impl::getLineWidth() const {
- if (paint.lineGapWidth > 0) {
- return paint.lineGapWidth + 2 * paint.lineWidth;
+ if (paint.evaluated.get<LineGapWidth>() > 0) {
+ return paint.evaluated.get<LineGapWidth>() + 2 * paint.evaluated.get<LineWidth>();
} else {
- return paint.lineWidth;
+ return paint.evaluated.get<LineWidth>();
}
}
@@ -82,8 +80,8 @@ optional<GeometryCollection> offsetLine(const GeometryCollection& rings, const d
}
float LineLayer::Impl::getQueryRadius() const {
- const std::array<float, 2>& translate = paint.lineTranslate;
- return getLineWidth() / 2.0 + std::abs(paint.lineOffset) + util::length(translate[0], translate[1]);
+ const std::array<float, 2>& translate = paint.evaluated.get<LineTranslate>();
+ return getLineWidth() / 2.0 + std::abs(paint.evaluated.get<LineOffset>()) + util::length(translate[0], translate[1]);
}
bool LineLayer::Impl::queryIntersectsGeometry(
@@ -95,8 +93,8 @@ bool LineLayer::Impl::queryIntersectsGeometry(
const float halfWidth = getLineWidth() / 2.0 * pixelsToTileUnits;
auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry(
- queryGeometry, paint.lineTranslate, paint.lineTranslateAnchor, bearing, pixelsToTileUnits);
- auto offsetGeometry = offsetLine(geometry, paint.lineOffset * pixelsToTileUnits);
+ queryGeometry, paint.evaluated.get<LineTranslate>(), paint.evaluated.get<LineTranslateAnchor>(), bearing, pixelsToTileUnits);
+ auto offsetGeometry = offsetLine(geometry, paint.evaluated.get<LineOffset>() * pixelsToTileUnits);
return util::polygonIntersectsBufferedMultiLine(
translatedQueryGeometry.value_or(queryGeometry),
diff --git a/src/mbgl/style/layers/line_layer_impl.hpp b/src/mbgl/style/layers/line_layer_impl.hpp
index c6b4be3bec..3387db07f0 100644
--- a/src/mbgl/style/layers/line_layer_impl.hpp
+++ b/src/mbgl/style/layers/line_layer_impl.hpp
@@ -13,7 +13,7 @@ public:
std::unique_ptr<Layer> cloneRef(const std::string& id) const override;
void cascade(const CascadeParameters&) override;
- bool recalculate(const CalculationParameters&) override;
+ bool evaluate(const PropertyEvaluationParameters&) override;
std::unique_ptr<Bucket> createBucket(BucketParameters&) const override;
diff --git a/src/mbgl/style/layers/line_layer_properties.cpp b/src/mbgl/style/layers/line_layer_properties.cpp
index 2d6092745e..174239bcc8 100644
--- a/src/mbgl/style/layers/line_layer_properties.cpp
+++ b/src/mbgl/style/layers/line_layer_properties.cpp
@@ -5,42 +5,5 @@
namespace mbgl {
namespace style {
-void LineLayoutProperties::recalculate(const CalculationParameters& parameters) {
- lineCap.calculate(parameters);
- lineJoin.calculate(parameters);
- lineMiterLimit.calculate(parameters);
- lineRoundLimit.calculate(parameters);
-}
-
-void LinePaintProperties::cascade(const CascadeParameters& parameters) {
- lineOpacity.cascade(parameters);
- lineColor.cascade(parameters);
- lineTranslate.cascade(parameters);
- lineTranslateAnchor.cascade(parameters);
- lineWidth.cascade(parameters);
- lineGapWidth.cascade(parameters);
- lineOffset.cascade(parameters);
- lineBlur.cascade(parameters);
- lineDasharray.cascade(parameters);
- linePattern.cascade(parameters);
-}
-
-bool LinePaintProperties::recalculate(const CalculationParameters& parameters) {
- bool hasTransitions = false;
-
- hasTransitions |= lineOpacity.calculate(parameters);
- hasTransitions |= lineColor.calculate(parameters);
- hasTransitions |= lineTranslate.calculate(parameters);
- hasTransitions |= lineTranslateAnchor.calculate(parameters);
- hasTransitions |= lineWidth.calculate(parameters);
- hasTransitions |= lineGapWidth.calculate(parameters);
- hasTransitions |= lineOffset.calculate(parameters);
- hasTransitions |= lineBlur.calculate(parameters);
- hasTransitions |= lineDasharray.calculate(parameters);
- hasTransitions |= linePattern.calculate(parameters);
-
- return hasTransitions;
-}
-
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layers/line_layer_properties.hpp b/src/mbgl/style/layers/line_layer_properties.hpp
index b73e3f2ef2..07458cd634 100644
--- a/src/mbgl/style/layers/line_layer_properties.hpp
+++ b/src/mbgl/style/layers/line_layer_properties.hpp
@@ -9,35 +9,81 @@
namespace mbgl {
namespace style {
-class CascadeParameters;
-class CalculationParameters;
-
-class LineLayoutProperties {
-public:
- void recalculate(const CalculationParameters&);
-
- LayoutProperty<LineCapType> lineCap { LineCapType::Butt };
- LayoutProperty<LineJoinType> lineJoin { LineJoinType::Miter };
- LayoutProperty<float> lineMiterLimit { 2 };
- LayoutProperty<float> lineRoundLimit { 1 };
-};
-
-class LinePaintProperties {
-public:
- void cascade(const CascadeParameters&);
- bool recalculate(const CalculationParameters&);
-
- PaintProperty<float> lineOpacity { 1 };
- PaintProperty<Color> lineColor { Color::black() };
- PaintProperty<std::array<float, 2>> lineTranslate { {{ 0, 0 }} };
- PaintProperty<TranslateAnchorType> lineTranslateAnchor { TranslateAnchorType::Map };
- PaintProperty<float> lineWidth { 1 };
- PaintProperty<float> lineGapWidth { 0 };
- PaintProperty<float> lineOffset { 0 };
- PaintProperty<float> lineBlur { 0 };
- PaintProperty<std::vector<float>, CrossFadedPropertyEvaluator> lineDasharray { { } };
- PaintProperty<std::string, CrossFadedPropertyEvaluator> linePattern { "" };
+struct LineCap : LayoutProperty<LineCapType> {
+ static LineCapType defaultValue() { return LineCapType::Butt; }
};
+struct LineJoin : LayoutProperty<LineJoinType> {
+ static LineJoinType defaultValue() { return LineJoinType::Miter; }
+};
+
+struct LineMiterLimit : LayoutProperty<float> {
+ static float defaultValue() { return 2; }
+};
+
+struct LineRoundLimit : LayoutProperty<float> {
+ static float defaultValue() { return 1; }
+};
+
+struct LineOpacity : PaintProperty<float> {
+ static float defaultValue() { return 1; }
+};
+
+struct LineColor : PaintProperty<Color> {
+ static Color defaultValue() { return Color::black(); }
+};
+
+struct LineTranslate : PaintProperty<std::array<float, 2>> {
+ static std::array<float, 2> defaultValue() { return {{ 0, 0 }}; }
+};
+
+struct LineTranslateAnchor : PaintProperty<TranslateAnchorType> {
+ static TranslateAnchorType defaultValue() { return TranslateAnchorType::Map; }
+};
+
+struct LineWidth : PaintProperty<float> {
+ static float defaultValue() { return 1; }
+};
+
+struct LineGapWidth : PaintProperty<float> {
+ static float defaultValue() { return 0; }
+};
+
+struct LineOffset : PaintProperty<float> {
+ static float defaultValue() { return 0; }
+};
+
+struct LineBlur : PaintProperty<float> {
+ static float defaultValue() { return 0; }
+};
+
+struct LineDasharray : CrossFadedPaintProperty<std::vector<float>> {
+ static std::vector<float> defaultValue() { return { }; }
+};
+
+struct LinePattern : CrossFadedPaintProperty<std::string> {
+ static std::string defaultValue() { return ""; }
+};
+
+class LineLayoutProperties : public LayoutProperties<
+ LineCap,
+ LineJoin,
+ LineMiterLimit,
+ LineRoundLimit
+> {};
+
+class LinePaintProperties : public PaintProperties<
+ LineOpacity,
+ LineColor,
+ LineTranslate,
+ LineTranslateAnchor,
+ LineWidth,
+ LineGapWidth,
+ LineOffset,
+ LineBlur,
+ LineDasharray,
+ LinePattern
+> {};
+
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layers/raster_layer.cpp b/src/mbgl/style/layers/raster_layer.cpp
index 238bfef6e4..21d72a0fdc 100644
--- a/src/mbgl/style/layers/raster_layer.cpp
+++ b/src/mbgl/style/layers/raster_layer.cpp
@@ -49,13 +49,13 @@ PropertyValue<float> RasterLayer::getDefaultRasterOpacity() {
}
PropertyValue<float> RasterLayer::getRasterOpacity(const optional<std::string>& klass) const {
- return impl->paint.rasterOpacity.get(klass);
+ return impl->paint.get<RasterOpacity>(klass);
}
void RasterLayer::setRasterOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
if (value == getRasterOpacity(klass))
return;
- impl->paint.rasterOpacity.set(value, klass);
+ impl->paint.set<RasterOpacity>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -64,13 +64,13 @@ PropertyValue<float> RasterLayer::getDefaultRasterHueRotate() {
}
PropertyValue<float> RasterLayer::getRasterHueRotate(const optional<std::string>& klass) const {
- return impl->paint.rasterHueRotate.get(klass);
+ return impl->paint.get<RasterHueRotate>(klass);
}
void RasterLayer::setRasterHueRotate(PropertyValue<float> value, const optional<std::string>& klass) {
if (value == getRasterHueRotate(klass))
return;
- impl->paint.rasterHueRotate.set(value, klass);
+ impl->paint.set<RasterHueRotate>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -79,13 +79,13 @@ PropertyValue<float> RasterLayer::getDefaultRasterBrightnessMin() {
}
PropertyValue<float> RasterLayer::getRasterBrightnessMin(const optional<std::string>& klass) const {
- return impl->paint.rasterBrightnessMin.get(klass);
+ return impl->paint.get<RasterBrightnessMin>(klass);
}
void RasterLayer::setRasterBrightnessMin(PropertyValue<float> value, const optional<std::string>& klass) {
if (value == getRasterBrightnessMin(klass))
return;
- impl->paint.rasterBrightnessMin.set(value, klass);
+ impl->paint.set<RasterBrightnessMin>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -94,13 +94,13 @@ PropertyValue<float> RasterLayer::getDefaultRasterBrightnessMax() {
}
PropertyValue<float> RasterLayer::getRasterBrightnessMax(const optional<std::string>& klass) const {
- return impl->paint.rasterBrightnessMax.get(klass);
+ return impl->paint.get<RasterBrightnessMax>(klass);
}
void RasterLayer::setRasterBrightnessMax(PropertyValue<float> value, const optional<std::string>& klass) {
if (value == getRasterBrightnessMax(klass))
return;
- impl->paint.rasterBrightnessMax.set(value, klass);
+ impl->paint.set<RasterBrightnessMax>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -109,13 +109,13 @@ PropertyValue<float> RasterLayer::getDefaultRasterSaturation() {
}
PropertyValue<float> RasterLayer::getRasterSaturation(const optional<std::string>& klass) const {
- return impl->paint.rasterSaturation.get(klass);
+ return impl->paint.get<RasterSaturation>(klass);
}
void RasterLayer::setRasterSaturation(PropertyValue<float> value, const optional<std::string>& klass) {
if (value == getRasterSaturation(klass))
return;
- impl->paint.rasterSaturation.set(value, klass);
+ impl->paint.set<RasterSaturation>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -124,13 +124,13 @@ PropertyValue<float> RasterLayer::getDefaultRasterContrast() {
}
PropertyValue<float> RasterLayer::getRasterContrast(const optional<std::string>& klass) const {
- return impl->paint.rasterContrast.get(klass);
+ return impl->paint.get<RasterContrast>(klass);
}
void RasterLayer::setRasterContrast(PropertyValue<float> value, const optional<std::string>& klass) {
if (value == getRasterContrast(klass))
return;
- impl->paint.rasterContrast.set(value, klass);
+ impl->paint.set<RasterContrast>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -139,13 +139,13 @@ PropertyValue<float> RasterLayer::getDefaultRasterFadeDuration() {
}
PropertyValue<float> RasterLayer::getRasterFadeDuration(const optional<std::string>& klass) const {
- return impl->paint.rasterFadeDuration.get(klass);
+ return impl->paint.get<RasterFadeDuration>(klass);
}
void RasterLayer::setRasterFadeDuration(PropertyValue<float> value, const optional<std::string>& klass) {
if (value == getRasterFadeDuration(klass))
return;
- impl->paint.rasterFadeDuration.set(value, klass);
+ impl->paint.set<RasterFadeDuration>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
diff --git a/src/mbgl/style/layers/raster_layer_impl.cpp b/src/mbgl/style/layers/raster_layer_impl.cpp
index 879bfa4559..3be4bb4fbd 100644
--- a/src/mbgl/style/layers/raster_layer_impl.cpp
+++ b/src/mbgl/style/layers/raster_layer_impl.cpp
@@ -8,12 +8,12 @@ void RasterLayer::Impl::cascade(const CascadeParameters& parameters) {
paint.cascade(parameters);
}
-bool RasterLayer::Impl::recalculate(const CalculationParameters& parameters) {
- bool hasTransitions = paint.recalculate(parameters);
+bool RasterLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) {
+ paint.evaluate(parameters);
- passes = paint.rasterOpacity > 0 ? RenderPass::Translucent : RenderPass::None;
+ passes = paint.evaluated.get<RasterOpacity>() > 0 ? RenderPass::Translucent : RenderPass::None;
- return hasTransitions;
+ return paint.hasTransition();
}
std::unique_ptr<Bucket> RasterLayer::Impl::createBucket(BucketParameters&) const {
diff --git a/src/mbgl/style/layers/raster_layer_impl.hpp b/src/mbgl/style/layers/raster_layer_impl.hpp
index a5b396e2ed..df5d388bdf 100644
--- a/src/mbgl/style/layers/raster_layer_impl.hpp
+++ b/src/mbgl/style/layers/raster_layer_impl.hpp
@@ -13,7 +13,7 @@ public:
std::unique_ptr<Layer> cloneRef(const std::string& id) const override;
void cascade(const CascadeParameters&) override;
- bool recalculate(const CalculationParameters&) override;
+ bool evaluate(const PropertyEvaluationParameters&) override;
std::unique_ptr<Bucket> createBucket(BucketParameters&) const override;
diff --git a/src/mbgl/style/layers/raster_layer_properties.cpp b/src/mbgl/style/layers/raster_layer_properties.cpp
index 68d9d1d35d..303719af40 100644
--- a/src/mbgl/style/layers/raster_layer_properties.cpp
+++ b/src/mbgl/style/layers/raster_layer_properties.cpp
@@ -5,29 +5,5 @@
namespace mbgl {
namespace style {
-void RasterPaintProperties::cascade(const CascadeParameters& parameters) {
- rasterOpacity.cascade(parameters);
- rasterHueRotate.cascade(parameters);
- rasterBrightnessMin.cascade(parameters);
- rasterBrightnessMax.cascade(parameters);
- rasterSaturation.cascade(parameters);
- rasterContrast.cascade(parameters);
- rasterFadeDuration.cascade(parameters);
-}
-
-bool RasterPaintProperties::recalculate(const CalculationParameters& parameters) {
- bool hasTransitions = false;
-
- hasTransitions |= rasterOpacity.calculate(parameters);
- hasTransitions |= rasterHueRotate.calculate(parameters);
- hasTransitions |= rasterBrightnessMin.calculate(parameters);
- hasTransitions |= rasterBrightnessMax.calculate(parameters);
- hasTransitions |= rasterSaturation.calculate(parameters);
- hasTransitions |= rasterContrast.calculate(parameters);
- hasTransitions |= rasterFadeDuration.calculate(parameters);
-
- return hasTransitions;
-}
-
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layers/raster_layer_properties.hpp b/src/mbgl/style/layers/raster_layer_properties.hpp
index ddfb833e12..caa6d0c58d 100644
--- a/src/mbgl/style/layers/raster_layer_properties.hpp
+++ b/src/mbgl/style/layers/raster_layer_properties.hpp
@@ -9,22 +9,43 @@
namespace mbgl {
namespace style {
-class CascadeParameters;
-class CalculationParameters;
-
-class RasterPaintProperties {
-public:
- void cascade(const CascadeParameters&);
- bool recalculate(const CalculationParameters&);
-
- PaintProperty<float> rasterOpacity { 1 };
- PaintProperty<float> rasterHueRotate { 0 };
- PaintProperty<float> rasterBrightnessMin { 0 };
- PaintProperty<float> rasterBrightnessMax { 1 };
- PaintProperty<float> rasterSaturation { 0 };
- PaintProperty<float> rasterContrast { 0 };
- PaintProperty<float> rasterFadeDuration { 300 };
+struct RasterOpacity : PaintProperty<float> {
+ static float defaultValue() { return 1; }
};
+struct RasterHueRotate : PaintProperty<float> {
+ static float defaultValue() { return 0; }
+};
+
+struct RasterBrightnessMin : PaintProperty<float> {
+ static float defaultValue() { return 0; }
+};
+
+struct RasterBrightnessMax : PaintProperty<float> {
+ static float defaultValue() { return 1; }
+};
+
+struct RasterSaturation : PaintProperty<float> {
+ static float defaultValue() { return 0; }
+};
+
+struct RasterContrast : PaintProperty<float> {
+ static float defaultValue() { return 0; }
+};
+
+struct RasterFadeDuration : PaintProperty<float> {
+ static float defaultValue() { return 300; }
+};
+
+class RasterPaintProperties : public PaintProperties<
+ RasterOpacity,
+ RasterHueRotate,
+ RasterBrightnessMin,
+ RasterBrightnessMax,
+ RasterSaturation,
+ RasterContrast,
+ RasterFadeDuration
+> {};
+
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp
index d49e8d7fe3..61f360ff64 100644
--- a/src/mbgl/style/layers/symbol_layer.cpp
+++ b/src/mbgl/style/layers/symbol_layer.cpp
@@ -60,479 +60,479 @@ const Filter& SymbolLayer::getFilter() const {
// Layout properties
PropertyValue<SymbolPlacementType> SymbolLayer::getDefaultSymbolPlacement() {
- return { SymbolPlacementType::Point };
+ return SymbolPlacement::defaultValue();
}
PropertyValue<SymbolPlacementType> SymbolLayer::getSymbolPlacement() const {
- return impl->layout.symbolPlacement.get();
+ return impl->layout.unevaluated.get<SymbolPlacement>();
}
void SymbolLayer::setSymbolPlacement(PropertyValue<SymbolPlacementType> value) {
if (value == getSymbolPlacement())
return;
- impl->layout.symbolPlacement.set(value);
+ impl->layout.unevaluated.get<SymbolPlacement>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "symbol-placement");
}
PropertyValue<float> SymbolLayer::getDefaultSymbolSpacing() {
- return { 250 };
+ return SymbolSpacing::defaultValue();
}
PropertyValue<float> SymbolLayer::getSymbolSpacing() const {
- return impl->layout.symbolSpacing.get();
+ return impl->layout.unevaluated.get<SymbolSpacing>();
}
void SymbolLayer::setSymbolSpacing(PropertyValue<float> value) {
if (value == getSymbolSpacing())
return;
- impl->layout.symbolSpacing.set(value);
+ impl->layout.unevaluated.get<SymbolSpacing>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "symbol-spacing");
}
PropertyValue<bool> SymbolLayer::getDefaultSymbolAvoidEdges() {
- return { false };
+ return SymbolAvoidEdges::defaultValue();
}
PropertyValue<bool> SymbolLayer::getSymbolAvoidEdges() const {
- return impl->layout.symbolAvoidEdges.get();
+ return impl->layout.unevaluated.get<SymbolAvoidEdges>();
}
void SymbolLayer::setSymbolAvoidEdges(PropertyValue<bool> value) {
if (value == getSymbolAvoidEdges())
return;
- impl->layout.symbolAvoidEdges.set(value);
+ impl->layout.unevaluated.get<SymbolAvoidEdges>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "symbol-avoid-edges");
}
PropertyValue<bool> SymbolLayer::getDefaultIconAllowOverlap() {
- return { false };
+ return IconAllowOverlap::defaultValue();
}
PropertyValue<bool> SymbolLayer::getIconAllowOverlap() const {
- return impl->layout.iconAllowOverlap.get();
+ return impl->layout.unevaluated.get<IconAllowOverlap>();
}
void SymbolLayer::setIconAllowOverlap(PropertyValue<bool> value) {
if (value == getIconAllowOverlap())
return;
- impl->layout.iconAllowOverlap.set(value);
+ impl->layout.unevaluated.get<IconAllowOverlap>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "icon-allow-overlap");
}
PropertyValue<bool> SymbolLayer::getDefaultIconIgnorePlacement() {
- return { false };
+ return IconIgnorePlacement::defaultValue();
}
PropertyValue<bool> SymbolLayer::getIconIgnorePlacement() const {
- return impl->layout.iconIgnorePlacement.get();
+ return impl->layout.unevaluated.get<IconIgnorePlacement>();
}
void SymbolLayer::setIconIgnorePlacement(PropertyValue<bool> value) {
if (value == getIconIgnorePlacement())
return;
- impl->layout.iconIgnorePlacement.set(value);
+ impl->layout.unevaluated.get<IconIgnorePlacement>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "icon-ignore-placement");
}
PropertyValue<bool> SymbolLayer::getDefaultIconOptional() {
- return { false };
+ return IconOptional::defaultValue();
}
PropertyValue<bool> SymbolLayer::getIconOptional() const {
- return impl->layout.iconOptional.get();
+ return impl->layout.unevaluated.get<IconOptional>();
}
void SymbolLayer::setIconOptional(PropertyValue<bool> value) {
if (value == getIconOptional())
return;
- impl->layout.iconOptional.set(value);
+ impl->layout.unevaluated.get<IconOptional>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "icon-optional");
}
PropertyValue<AlignmentType> SymbolLayer::getDefaultIconRotationAlignment() {
- return { AlignmentType::Auto };
+ return IconRotationAlignment::defaultValue();
}
PropertyValue<AlignmentType> SymbolLayer::getIconRotationAlignment() const {
- return impl->layout.iconRotationAlignment.get();
+ return impl->layout.unevaluated.get<IconRotationAlignment>();
}
void SymbolLayer::setIconRotationAlignment(PropertyValue<AlignmentType> value) {
if (value == getIconRotationAlignment())
return;
- impl->layout.iconRotationAlignment.set(value);
+ impl->layout.unevaluated.get<IconRotationAlignment>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "icon-rotation-alignment");
}
PropertyValue<float> SymbolLayer::getDefaultIconSize() {
- return { 1 };
+ return IconSize::defaultValue();
}
PropertyValue<float> SymbolLayer::getIconSize() const {
- return impl->layout.iconSize.get();
+ return impl->layout.unevaluated.get<IconSize>();
}
void SymbolLayer::setIconSize(PropertyValue<float> value) {
if (value == getIconSize())
return;
- impl->layout.iconSize.set(value);
+ impl->layout.unevaluated.get<IconSize>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "icon-size");
}
PropertyValue<IconTextFitType> SymbolLayer::getDefaultIconTextFit() {
- return { IconTextFitType::None };
+ return IconTextFit::defaultValue();
}
PropertyValue<IconTextFitType> SymbolLayer::getIconTextFit() const {
- return impl->layout.iconTextFit.get();
+ return impl->layout.unevaluated.get<IconTextFit>();
}
void SymbolLayer::setIconTextFit(PropertyValue<IconTextFitType> value) {
if (value == getIconTextFit())
return;
- impl->layout.iconTextFit.set(value);
+ impl->layout.unevaluated.get<IconTextFit>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "icon-text-fit");
}
PropertyValue<std::array<float, 4>> SymbolLayer::getDefaultIconTextFitPadding() {
- return { {{ 0, 0, 0, 0 }} };
+ return IconTextFitPadding::defaultValue();
}
PropertyValue<std::array<float, 4>> SymbolLayer::getIconTextFitPadding() const {
- return impl->layout.iconTextFitPadding.get();
+ return impl->layout.unevaluated.get<IconTextFitPadding>();
}
void SymbolLayer::setIconTextFitPadding(PropertyValue<std::array<float, 4>> value) {
if (value == getIconTextFitPadding())
return;
- impl->layout.iconTextFitPadding.set(value);
+ impl->layout.unevaluated.get<IconTextFitPadding>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "icon-text-fit-padding");
}
PropertyValue<std::string> SymbolLayer::getDefaultIconImage() {
- return { "" };
+ return IconImage::defaultValue();
}
PropertyValue<std::string> SymbolLayer::getIconImage() const {
- return impl->layout.iconImage.get();
+ return impl->layout.unevaluated.get<IconImage>();
}
void SymbolLayer::setIconImage(PropertyValue<std::string> value) {
if (value == getIconImage())
return;
- impl->layout.iconImage.set(value);
+ impl->layout.unevaluated.get<IconImage>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "icon-image");
}
PropertyValue<float> SymbolLayer::getDefaultIconRotate() {
- return { 0 };
+ return IconRotate::defaultValue();
}
PropertyValue<float> SymbolLayer::getIconRotate() const {
- return impl->layout.iconRotate.get();
+ return impl->layout.unevaluated.get<IconRotate>();
}
void SymbolLayer::setIconRotate(PropertyValue<float> value) {
if (value == getIconRotate())
return;
- impl->layout.iconRotate.set(value);
+ impl->layout.unevaluated.get<IconRotate>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "icon-rotate");
}
PropertyValue<float> SymbolLayer::getDefaultIconPadding() {
- return { 2 };
+ return IconPadding::defaultValue();
}
PropertyValue<float> SymbolLayer::getIconPadding() const {
- return impl->layout.iconPadding.get();
+ return impl->layout.unevaluated.get<IconPadding>();
}
void SymbolLayer::setIconPadding(PropertyValue<float> value) {
if (value == getIconPadding())
return;
- impl->layout.iconPadding.set(value);
+ impl->layout.unevaluated.get<IconPadding>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "icon-padding");
}
PropertyValue<bool> SymbolLayer::getDefaultIconKeepUpright() {
- return { false };
+ return IconKeepUpright::defaultValue();
}
PropertyValue<bool> SymbolLayer::getIconKeepUpright() const {
- return impl->layout.iconKeepUpright.get();
+ return impl->layout.unevaluated.get<IconKeepUpright>();
}
void SymbolLayer::setIconKeepUpright(PropertyValue<bool> value) {
if (value == getIconKeepUpright())
return;
- impl->layout.iconKeepUpright.set(value);
+ impl->layout.unevaluated.get<IconKeepUpright>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "icon-keep-upright");
}
PropertyValue<std::array<float, 2>> SymbolLayer::getDefaultIconOffset() {
- return { {{ 0, 0 }} };
+ return IconOffset::defaultValue();
}
PropertyValue<std::array<float, 2>> SymbolLayer::getIconOffset() const {
- return impl->layout.iconOffset.get();
+ return impl->layout.unevaluated.get<IconOffset>();
}
void SymbolLayer::setIconOffset(PropertyValue<std::array<float, 2>> value) {
if (value == getIconOffset())
return;
- impl->layout.iconOffset.set(value);
+ impl->layout.unevaluated.get<IconOffset>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "icon-offset");
}
PropertyValue<AlignmentType> SymbolLayer::getDefaultTextPitchAlignment() {
- return { AlignmentType::Auto };
+ return TextPitchAlignment::defaultValue();
}
PropertyValue<AlignmentType> SymbolLayer::getTextPitchAlignment() const {
- return impl->layout.textPitchAlignment.get();
+ return impl->layout.unevaluated.get<TextPitchAlignment>();
}
void SymbolLayer::setTextPitchAlignment(PropertyValue<AlignmentType> value) {
if (value == getTextPitchAlignment())
return;
- impl->layout.textPitchAlignment.set(value);
+ impl->layout.unevaluated.get<TextPitchAlignment>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "text-pitch-alignment");
}
PropertyValue<AlignmentType> SymbolLayer::getDefaultTextRotationAlignment() {
- return { AlignmentType::Auto };
+ return TextRotationAlignment::defaultValue();
}
PropertyValue<AlignmentType> SymbolLayer::getTextRotationAlignment() const {
- return impl->layout.textRotationAlignment.get();
+ return impl->layout.unevaluated.get<TextRotationAlignment>();
}
void SymbolLayer::setTextRotationAlignment(PropertyValue<AlignmentType> value) {
if (value == getTextRotationAlignment())
return;
- impl->layout.textRotationAlignment.set(value);
+ impl->layout.unevaluated.get<TextRotationAlignment>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "text-rotation-alignment");
}
PropertyValue<std::string> SymbolLayer::getDefaultTextField() {
- return { "" };
+ return TextField::defaultValue();
}
PropertyValue<std::string> SymbolLayer::getTextField() const {
- return impl->layout.textField.get();
+ return impl->layout.unevaluated.get<TextField>();
}
void SymbolLayer::setTextField(PropertyValue<std::string> value) {
if (value == getTextField())
return;
- impl->layout.textField.set(value);
+ impl->layout.unevaluated.get<TextField>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "text-field");
}
PropertyValue<std::vector<std::string>> SymbolLayer::getDefaultTextFont() {
- return { { "Open Sans Regular", "Arial Unicode MS Regular" } };
+ return TextFont::defaultValue();
}
PropertyValue<std::vector<std::string>> SymbolLayer::getTextFont() const {
- return impl->layout.textFont.get();
+ return impl->layout.unevaluated.get<TextFont>();
}
void SymbolLayer::setTextFont(PropertyValue<std::vector<std::string>> value) {
if (value == getTextFont())
return;
- impl->layout.textFont.set(value);
+ impl->layout.unevaluated.get<TextFont>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "text-font");
}
PropertyValue<float> SymbolLayer::getDefaultTextSize() {
- return { 16 };
+ return TextSize::defaultValue();
}
PropertyValue<float> SymbolLayer::getTextSize() const {
- return impl->layout.textSize.get();
+ return impl->layout.unevaluated.get<TextSize>();
}
void SymbolLayer::setTextSize(PropertyValue<float> value) {
if (value == getTextSize())
return;
- impl->layout.textSize.set(value);
+ impl->layout.unevaluated.get<TextSize>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "text-size");
}
PropertyValue<float> SymbolLayer::getDefaultTextMaxWidth() {
- return { 10 };
+ return TextMaxWidth::defaultValue();
}
PropertyValue<float> SymbolLayer::getTextMaxWidth() const {
- return impl->layout.textMaxWidth.get();
+ return impl->layout.unevaluated.get<TextMaxWidth>();
}
void SymbolLayer::setTextMaxWidth(PropertyValue<float> value) {
if (value == getTextMaxWidth())
return;
- impl->layout.textMaxWidth.set(value);
+ impl->layout.unevaluated.get<TextMaxWidth>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "text-max-width");
}
PropertyValue<float> SymbolLayer::getDefaultTextLineHeight() {
- return { 1.2 };
+ return TextLineHeight::defaultValue();
}
PropertyValue<float> SymbolLayer::getTextLineHeight() const {
- return impl->layout.textLineHeight.get();
+ return impl->layout.unevaluated.get<TextLineHeight>();
}
void SymbolLayer::setTextLineHeight(PropertyValue<float> value) {
if (value == getTextLineHeight())
return;
- impl->layout.textLineHeight.set(value);
+ impl->layout.unevaluated.get<TextLineHeight>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "text-line-height");
}
PropertyValue<float> SymbolLayer::getDefaultTextLetterSpacing() {
- return { 0 };
+ return TextLetterSpacing::defaultValue();
}
PropertyValue<float> SymbolLayer::getTextLetterSpacing() const {
- return impl->layout.textLetterSpacing.get();
+ return impl->layout.unevaluated.get<TextLetterSpacing>();
}
void SymbolLayer::setTextLetterSpacing(PropertyValue<float> value) {
if (value == getTextLetterSpacing())
return;
- impl->layout.textLetterSpacing.set(value);
+ impl->layout.unevaluated.get<TextLetterSpacing>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "text-letter-spacing");
}
PropertyValue<TextJustifyType> SymbolLayer::getDefaultTextJustify() {
- return { TextJustifyType::Center };
+ return TextJustify::defaultValue();
}
PropertyValue<TextJustifyType> SymbolLayer::getTextJustify() const {
- return impl->layout.textJustify.get();
+ return impl->layout.unevaluated.get<TextJustify>();
}
void SymbolLayer::setTextJustify(PropertyValue<TextJustifyType> value) {
if (value == getTextJustify())
return;
- impl->layout.textJustify.set(value);
+ impl->layout.unevaluated.get<TextJustify>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "text-justify");
}
PropertyValue<TextAnchorType> SymbolLayer::getDefaultTextAnchor() {
- return { TextAnchorType::Center };
+ return TextAnchor::defaultValue();
}
PropertyValue<TextAnchorType> SymbolLayer::getTextAnchor() const {
- return impl->layout.textAnchor.get();
+ return impl->layout.unevaluated.get<TextAnchor>();
}
void SymbolLayer::setTextAnchor(PropertyValue<TextAnchorType> value) {
if (value == getTextAnchor())
return;
- impl->layout.textAnchor.set(value);
+ impl->layout.unevaluated.get<TextAnchor>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "text-anchor");
}
PropertyValue<float> SymbolLayer::getDefaultTextMaxAngle() {
- return { 45 };
+ return TextMaxAngle::defaultValue();
}
PropertyValue<float> SymbolLayer::getTextMaxAngle() const {
- return impl->layout.textMaxAngle.get();
+ return impl->layout.unevaluated.get<TextMaxAngle>();
}
void SymbolLayer::setTextMaxAngle(PropertyValue<float> value) {
if (value == getTextMaxAngle())
return;
- impl->layout.textMaxAngle.set(value);
+ impl->layout.unevaluated.get<TextMaxAngle>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "text-max-angle");
}
PropertyValue<float> SymbolLayer::getDefaultTextRotate() {
- return { 0 };
+ return TextRotate::defaultValue();
}
PropertyValue<float> SymbolLayer::getTextRotate() const {
- return impl->layout.textRotate.get();
+ return impl->layout.unevaluated.get<TextRotate>();
}
void SymbolLayer::setTextRotate(PropertyValue<float> value) {
if (value == getTextRotate())
return;
- impl->layout.textRotate.set(value);
+ impl->layout.unevaluated.get<TextRotate>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "text-rotate");
}
PropertyValue<float> SymbolLayer::getDefaultTextPadding() {
- return { 2 };
+ return TextPadding::defaultValue();
}
PropertyValue<float> SymbolLayer::getTextPadding() const {
- return impl->layout.textPadding.get();
+ return impl->layout.unevaluated.get<TextPadding>();
}
void SymbolLayer::setTextPadding(PropertyValue<float> value) {
if (value == getTextPadding())
return;
- impl->layout.textPadding.set(value);
+ impl->layout.unevaluated.get<TextPadding>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "text-padding");
}
PropertyValue<bool> SymbolLayer::getDefaultTextKeepUpright() {
- return { true };
+ return TextKeepUpright::defaultValue();
}
PropertyValue<bool> SymbolLayer::getTextKeepUpright() const {
- return impl->layout.textKeepUpright.get();
+ return impl->layout.unevaluated.get<TextKeepUpright>();
}
void SymbolLayer::setTextKeepUpright(PropertyValue<bool> value) {
if (value == getTextKeepUpright())
return;
- impl->layout.textKeepUpright.set(value);
+ impl->layout.unevaluated.get<TextKeepUpright>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "text-keep-upright");
}
PropertyValue<TextTransformType> SymbolLayer::getDefaultTextTransform() {
- return { TextTransformType::None };
+ return TextTransform::defaultValue();
}
PropertyValue<TextTransformType> SymbolLayer::getTextTransform() const {
- return impl->layout.textTransform.get();
+ return impl->layout.unevaluated.get<TextTransform>();
}
void SymbolLayer::setTextTransform(PropertyValue<TextTransformType> value) {
if (value == getTextTransform())
return;
- impl->layout.textTransform.set(value);
+ impl->layout.unevaluated.get<TextTransform>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "text-transform");
}
PropertyValue<std::array<float, 2>> SymbolLayer::getDefaultTextOffset() {
- return { {{ 0, 0 }} };
+ return TextOffset::defaultValue();
}
PropertyValue<std::array<float, 2>> SymbolLayer::getTextOffset() const {
- return impl->layout.textOffset.get();
+ return impl->layout.unevaluated.get<TextOffset>();
}
void SymbolLayer::setTextOffset(PropertyValue<std::array<float, 2>> value) {
if (value == getTextOffset())
return;
- impl->layout.textOffset.set(value);
+ impl->layout.unevaluated.get<TextOffset>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "text-offset");
}
PropertyValue<bool> SymbolLayer::getDefaultTextAllowOverlap() {
- return { false };
+ return TextAllowOverlap::defaultValue();
}
PropertyValue<bool> SymbolLayer::getTextAllowOverlap() const {
- return impl->layout.textAllowOverlap.get();
+ return impl->layout.unevaluated.get<TextAllowOverlap>();
}
void SymbolLayer::setTextAllowOverlap(PropertyValue<bool> value) {
if (value == getTextAllowOverlap())
return;
- impl->layout.textAllowOverlap.set(value);
+ impl->layout.unevaluated.get<TextAllowOverlap>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "text-allow-overlap");
}
PropertyValue<bool> SymbolLayer::getDefaultTextIgnorePlacement() {
- return { false };
+ return TextIgnorePlacement::defaultValue();
}
PropertyValue<bool> SymbolLayer::getTextIgnorePlacement() const {
- return impl->layout.textIgnorePlacement.get();
+ return impl->layout.unevaluated.get<TextIgnorePlacement>();
}
void SymbolLayer::setTextIgnorePlacement(PropertyValue<bool> value) {
if (value == getTextIgnorePlacement())
return;
- impl->layout.textIgnorePlacement.set(value);
+ impl->layout.unevaluated.get<TextIgnorePlacement>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "text-ignore-placement");
}
PropertyValue<bool> SymbolLayer::getDefaultTextOptional() {
- return { false };
+ return TextOptional::defaultValue();
}
PropertyValue<bool> SymbolLayer::getTextOptional() const {
- return impl->layout.textOptional.get();
+ return impl->layout.unevaluated.get<TextOptional>();
}
void SymbolLayer::setTextOptional(PropertyValue<bool> value) {
if (value == getTextOptional())
return;
- impl->layout.textOptional.set(value);
+ impl->layout.unevaluated.get<TextOptional>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "text-optional");
}
@@ -543,13 +543,13 @@ PropertyValue<float> SymbolLayer::getDefaultIconOpacity() {
}
PropertyValue<float> SymbolLayer::getIconOpacity(const optional<std::string>& klass) const {
- return impl->paint.iconOpacity.get(klass);
+ return impl->paint.get<IconOpacity>(klass);
}
void SymbolLayer::setIconOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
if (value == getIconOpacity(klass))
return;
- impl->paint.iconOpacity.set(value, klass);
+ impl->paint.set<IconOpacity>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -558,13 +558,13 @@ PropertyValue<Color> SymbolLayer::getDefaultIconColor() {
}
PropertyValue<Color> SymbolLayer::getIconColor(const optional<std::string>& klass) const {
- return impl->paint.iconColor.get(klass);
+ return impl->paint.get<IconColor>(klass);
}
void SymbolLayer::setIconColor(PropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getIconColor(klass))
return;
- impl->paint.iconColor.set(value, klass);
+ impl->paint.set<IconColor>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -573,13 +573,13 @@ PropertyValue<Color> SymbolLayer::getDefaultIconHaloColor() {
}
PropertyValue<Color> SymbolLayer::getIconHaloColor(const optional<std::string>& klass) const {
- return impl->paint.iconHaloColor.get(klass);
+ return impl->paint.get<IconHaloColor>(klass);
}
void SymbolLayer::setIconHaloColor(PropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getIconHaloColor(klass))
return;
- impl->paint.iconHaloColor.set(value, klass);
+ impl->paint.set<IconHaloColor>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -588,13 +588,13 @@ PropertyValue<float> SymbolLayer::getDefaultIconHaloWidth() {
}
PropertyValue<float> SymbolLayer::getIconHaloWidth(const optional<std::string>& klass) const {
- return impl->paint.iconHaloWidth.get(klass);
+ return impl->paint.get<IconHaloWidth>(klass);
}
void SymbolLayer::setIconHaloWidth(PropertyValue<float> value, const optional<std::string>& klass) {
if (value == getIconHaloWidth(klass))
return;
- impl->paint.iconHaloWidth.set(value, klass);
+ impl->paint.set<IconHaloWidth>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -603,13 +603,13 @@ PropertyValue<float> SymbolLayer::getDefaultIconHaloBlur() {
}
PropertyValue<float> SymbolLayer::getIconHaloBlur(const optional<std::string>& klass) const {
- return impl->paint.iconHaloBlur.get(klass);
+ return impl->paint.get<IconHaloBlur>(klass);
}
void SymbolLayer::setIconHaloBlur(PropertyValue<float> value, const optional<std::string>& klass) {
if (value == getIconHaloBlur(klass))
return;
- impl->paint.iconHaloBlur.set(value, klass);
+ impl->paint.set<IconHaloBlur>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -618,13 +618,13 @@ PropertyValue<std::array<float, 2>> SymbolLayer::getDefaultIconTranslate() {
}
PropertyValue<std::array<float, 2>> SymbolLayer::getIconTranslate(const optional<std::string>& klass) const {
- return impl->paint.iconTranslate.get(klass);
+ return impl->paint.get<IconTranslate>(klass);
}
void SymbolLayer::setIconTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) {
if (value == getIconTranslate(klass))
return;
- impl->paint.iconTranslate.set(value, klass);
+ impl->paint.set<IconTranslate>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -633,13 +633,13 @@ PropertyValue<TranslateAnchorType> SymbolLayer::getDefaultIconTranslateAnchor()
}
PropertyValue<TranslateAnchorType> SymbolLayer::getIconTranslateAnchor(const optional<std::string>& klass) const {
- return impl->paint.iconTranslateAnchor.get(klass);
+ return impl->paint.get<IconTranslateAnchor>(klass);
}
void SymbolLayer::setIconTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) {
if (value == getIconTranslateAnchor(klass))
return;
- impl->paint.iconTranslateAnchor.set(value, klass);
+ impl->paint.set<IconTranslateAnchor>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -648,13 +648,13 @@ PropertyValue<float> SymbolLayer::getDefaultTextOpacity() {
}
PropertyValue<float> SymbolLayer::getTextOpacity(const optional<std::string>& klass) const {
- return impl->paint.textOpacity.get(klass);
+ return impl->paint.get<TextOpacity>(klass);
}
void SymbolLayer::setTextOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
if (value == getTextOpacity(klass))
return;
- impl->paint.textOpacity.set(value, klass);
+ impl->paint.set<TextOpacity>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -663,13 +663,13 @@ PropertyValue<Color> SymbolLayer::getDefaultTextColor() {
}
PropertyValue<Color> SymbolLayer::getTextColor(const optional<std::string>& klass) const {
- return impl->paint.textColor.get(klass);
+ return impl->paint.get<TextColor>(klass);
}
void SymbolLayer::setTextColor(PropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getTextColor(klass))
return;
- impl->paint.textColor.set(value, klass);
+ impl->paint.set<TextColor>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -678,13 +678,13 @@ PropertyValue<Color> SymbolLayer::getDefaultTextHaloColor() {
}
PropertyValue<Color> SymbolLayer::getTextHaloColor(const optional<std::string>& klass) const {
- return impl->paint.textHaloColor.get(klass);
+ return impl->paint.get<TextHaloColor>(klass);
}
void SymbolLayer::setTextHaloColor(PropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getTextHaloColor(klass))
return;
- impl->paint.textHaloColor.set(value, klass);
+ impl->paint.set<TextHaloColor>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -693,13 +693,13 @@ PropertyValue<float> SymbolLayer::getDefaultTextHaloWidth() {
}
PropertyValue<float> SymbolLayer::getTextHaloWidth(const optional<std::string>& klass) const {
- return impl->paint.textHaloWidth.get(klass);
+ return impl->paint.get<TextHaloWidth>(klass);
}
void SymbolLayer::setTextHaloWidth(PropertyValue<float> value, const optional<std::string>& klass) {
if (value == getTextHaloWidth(klass))
return;
- impl->paint.textHaloWidth.set(value, klass);
+ impl->paint.set<TextHaloWidth>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -708,13 +708,13 @@ PropertyValue<float> SymbolLayer::getDefaultTextHaloBlur() {
}
PropertyValue<float> SymbolLayer::getTextHaloBlur(const optional<std::string>& klass) const {
- return impl->paint.textHaloBlur.get(klass);
+ return impl->paint.get<TextHaloBlur>(klass);
}
void SymbolLayer::setTextHaloBlur(PropertyValue<float> value, const optional<std::string>& klass) {
if (value == getTextHaloBlur(klass))
return;
- impl->paint.textHaloBlur.set(value, klass);
+ impl->paint.set<TextHaloBlur>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -723,13 +723,13 @@ PropertyValue<std::array<float, 2>> SymbolLayer::getDefaultTextTranslate() {
}
PropertyValue<std::array<float, 2>> SymbolLayer::getTextTranslate(const optional<std::string>& klass) const {
- return impl->paint.textTranslate.get(klass);
+ return impl->paint.get<TextTranslate>(klass);
}
void SymbolLayer::setTextTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) {
if (value == getTextTranslate(klass))
return;
- impl->paint.textTranslate.set(value, klass);
+ impl->paint.set<TextTranslate>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
@@ -738,13 +738,13 @@ PropertyValue<TranslateAnchorType> SymbolLayer::getDefaultTextTranslateAnchor()
}
PropertyValue<TranslateAnchorType> SymbolLayer::getTextTranslateAnchor(const optional<std::string>& klass) const {
- return impl->paint.textTranslateAnchor.get(klass);
+ return impl->paint.get<TextTranslateAnchor>(klass);
}
void SymbolLayer::setTextTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) {
if (value == getTextTranslateAnchor(klass))
return;
- impl->paint.textTranslateAnchor.set(value, klass);
+ impl->paint.set<TextTranslateAnchor>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
diff --git a/src/mbgl/style/layers/symbol_layer_impl.cpp b/src/mbgl/style/layers/symbol_layer_impl.cpp
index e85f3a90f9..957bc1993e 100644
--- a/src/mbgl/style/layers/symbol_layer_impl.cpp
+++ b/src/mbgl/style/layers/symbol_layer_impl.cpp
@@ -10,20 +10,18 @@ void SymbolLayer::Impl::cascade(const CascadeParameters& parameters) {
paint.cascade(parameters);
}
-bool SymbolLayer::Impl::recalculate(const CalculationParameters& parameters) {
- bool hasTransitions = paint.recalculate(parameters);
+bool SymbolLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) {
+ paint.evaluate(parameters);
// text-size and icon-size are layout properties but they also need to be evaluated as paint properties:
- layout.iconSize.calculate(parameters);
- layout.textSize.calculate(parameters);
- iconSize = layout.iconSize;
- textSize = layout.textSize;
+ iconSize = layout.evaluate<IconSize>(parameters);
+ textSize = layout.evaluate<TextSize>(parameters);
- passes = ((paint.iconOpacity > 0 && (paint.iconColor.value.a > 0 || paint.iconHaloColor.value.a > 0) && iconSize > 0)
- || (paint.textOpacity > 0 && (paint.textColor.value.a > 0 || paint.textHaloColor.value.a > 0) && textSize > 0))
+ passes = ((paint.evaluated.get<IconOpacity>() > 0 && (paint.evaluated.get<IconColor>().a > 0 || paint.evaluated.get<IconHaloColor>().a > 0) && iconSize > 0)
+ || (paint.evaluated.get<TextOpacity>() > 0 && (paint.evaluated.get<TextColor>().a > 0 || paint.evaluated.get<TextHaloColor>().a > 0) && textSize > 0))
? RenderPass::Translucent : RenderPass::None;
- return hasTransitions;
+ return paint.hasTransition();
}
std::unique_ptr<Bucket> SymbolLayer::Impl::createBucket(BucketParameters&) const {
@@ -32,37 +30,34 @@ std::unique_ptr<Bucket> SymbolLayer::Impl::createBucket(BucketParameters&) const
}
std::unique_ptr<SymbolLayout> SymbolLayer::Impl::createLayout(BucketParameters& parameters) const {
- SymbolLayoutProperties layoutProperties = layout;
+ PropertyEvaluationParameters p(parameters.tileID.overscaledZ);
+ SymbolLayoutProperties::Evaluated evaluated = layout.evaluate(p);
- CalculationParameters p(parameters.tileID.overscaledZ);
- layoutProperties.recalculate(p);
-
- if (layoutProperties.iconRotationAlignment.value == AlignmentType::Auto) {
- if (layoutProperties.symbolPlacement.value == SymbolPlacementType::Line) {
- layoutProperties.iconRotationAlignment.value = AlignmentType::Map;
+ if (evaluated.get<IconRotationAlignment>() == AlignmentType::Auto) {
+ if (evaluated.get<SymbolPlacement>() == SymbolPlacementType::Line) {
+ evaluated.get<IconRotationAlignment>() = AlignmentType::Map;
} else {
- layoutProperties.iconRotationAlignment.value = AlignmentType::Viewport;
+ evaluated.get<IconRotationAlignment>() = AlignmentType::Viewport;
}
}
- if (layoutProperties.textRotationAlignment.value == AlignmentType::Auto) {
- if (layoutProperties.symbolPlacement.value == SymbolPlacementType::Line) {
- layoutProperties.textRotationAlignment.value = AlignmentType::Map;
+ if (evaluated.get<TextRotationAlignment>() == AlignmentType::Auto) {
+ if (evaluated.get<SymbolPlacement>() == SymbolPlacementType::Line) {
+ evaluated.get<TextRotationAlignment>() = AlignmentType::Map;
} else {
- layoutProperties.textRotationAlignment.value = AlignmentType::Viewport;
+ evaluated.get<TextRotationAlignment>() = AlignmentType::Viewport;
}
}
// If unspecified `text-pitch-alignment` inherits `text-rotation-alignment`
- if (layoutProperties.textPitchAlignment.value == AlignmentType::Auto) {
- layoutProperties.textPitchAlignment.value = layoutProperties.textRotationAlignment.value;
+ if (evaluated.get<TextPitchAlignment>() == AlignmentType::Auto) {
+ evaluated.get<TextPitchAlignment>() = evaluated.get<TextRotationAlignment>();
}
- layoutProperties.textSize.calculate(CalculationParameters(18));
- float textMaxSize = layoutProperties.textSize;
+ float textMaxSize = layout.evaluate<TextSize>(PropertyEvaluationParameters(18));
- layoutProperties.iconSize.calculate(CalculationParameters(p.z + 1));
- layoutProperties.textSize.calculate(CalculationParameters(p.z + 1));
+ evaluated.get<IconSize>() = layout.evaluate<IconSize>(PropertyEvaluationParameters(p.z + 1));
+ evaluated.get<TextSize>() = layout.evaluate<TextSize>(PropertyEvaluationParameters(p.z + 1));
return std::make_unique<SymbolLayout>(id,
parameters.layer.getName(),
@@ -71,10 +66,44 @@ std::unique_ptr<SymbolLayout> SymbolLayer::Impl::createLayout(BucketParameters&
parameters.mode,
parameters.layer,
filter,
- layoutProperties,
+ evaluated,
textMaxSize,
*spriteAtlas);
}
+SymbolPropertyValues SymbolLayer::Impl::iconPropertyValues(const SymbolLayoutProperties::Evaluated& layout_) const {
+ return SymbolPropertyValues {
+ layout_.get<IconRotationAlignment>(), // icon-pitch-alignment is not yet implemented; inherit the rotation alignment
+ layout_.get<IconRotationAlignment>(),
+ layout_.get<IconSize>(),
+ paint.evaluated.get<IconOpacity>(),
+ paint.evaluated.get<IconColor>(),
+ paint.evaluated.get<IconHaloColor>(),
+ paint.evaluated.get<IconHaloWidth>(),
+ paint.evaluated.get<IconHaloBlur>(),
+ paint.evaluated.get<IconTranslate>(),
+ paint.evaluated.get<IconTranslateAnchor>(),
+ iconSize,
+ 1.0f
+ };
+}
+
+SymbolPropertyValues SymbolLayer::Impl::textPropertyValues(const SymbolLayoutProperties::Evaluated& layout_) const {
+ return SymbolPropertyValues {
+ layout_.get<TextPitchAlignment>(),
+ layout_.get<TextRotationAlignment>(),
+ layout_.get<TextSize>(),
+ paint.evaluated.get<TextOpacity>(),
+ paint.evaluated.get<TextColor>(),
+ paint.evaluated.get<TextHaloColor>(),
+ paint.evaluated.get<TextHaloWidth>(),
+ paint.evaluated.get<TextHaloBlur>(),
+ paint.evaluated.get<TextTranslate>(),
+ paint.evaluated.get<TextTranslateAnchor>(),
+ textSize,
+ 24.0f
+ };
+}
+
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layers/symbol_layer_impl.hpp b/src/mbgl/style/layers/symbol_layer_impl.hpp
index fe37ba86ea..46ed75b231 100644
--- a/src/mbgl/style/layers/symbol_layer_impl.hpp
+++ b/src/mbgl/style/layers/symbol_layer_impl.hpp
@@ -11,17 +11,50 @@ class SymbolLayout;
namespace style {
+// Repackaging evaluated values from SymbolLayoutProperties + SymbolPaintProperties
+// for genericity over icons vs. text.
+class SymbolPropertyValues {
+public:
+ // Layout
+ AlignmentType pitchAlignment;
+ AlignmentType rotationAlignment;
+ float layoutSize;
+
+ // Paint
+ float opacity;
+ Color color;
+ Color haloColor;
+ float haloWidth;
+ float haloBlur;
+ std::array<float, 2> translate;
+ TranslateAnchorType translateAnchor;
+ float paintSize;
+
+ float sdfScale; // Constant (1.0 or 24.0)
+
+ bool hasHalo() const {
+ return haloColor.a > 0.0f && haloWidth > 0.0f;
+ }
+
+ bool hasForeground() const {
+ return color.a > 0.0f;
+ }
+};
+
class SymbolLayer::Impl : public Layer::Impl {
public:
std::unique_ptr<Layer> clone() const override;
std::unique_ptr<Layer> cloneRef(const std::string& id) const override;
void cascade(const CascadeParameters&) override;
- bool recalculate(const CalculationParameters&) override;
+ bool evaluate(const PropertyEvaluationParameters&) override;
std::unique_ptr<Bucket> createBucket(BucketParameters&) const override;
std::unique_ptr<SymbolLayout> createLayout(BucketParameters&) const;
+ SymbolPropertyValues iconPropertyValues(const SymbolLayoutProperties::Evaluated&) const;
+ SymbolPropertyValues textPropertyValues(const SymbolLayoutProperties::Evaluated&) const;
+
SymbolLayoutProperties layout;
SymbolPaintProperties paint;
diff --git a/src/mbgl/style/layers/symbol_layer_properties.cpp b/src/mbgl/style/layers/symbol_layer_properties.cpp
index 59a73d3d59..5a1ce713ba 100644
--- a/src/mbgl/style/layers/symbol_layer_properties.cpp
+++ b/src/mbgl/style/layers/symbol_layer_properties.cpp
@@ -5,80 +5,5 @@
namespace mbgl {
namespace style {
-void SymbolLayoutProperties::recalculate(const CalculationParameters& parameters) {
- symbolPlacement.calculate(parameters);
- symbolSpacing.calculate(parameters);
- symbolAvoidEdges.calculate(parameters);
- iconAllowOverlap.calculate(parameters);
- iconIgnorePlacement.calculate(parameters);
- iconOptional.calculate(parameters);
- iconRotationAlignment.calculate(parameters);
- iconSize.calculate(parameters);
- iconTextFit.calculate(parameters);
- iconTextFitPadding.calculate(parameters);
- iconImage.calculate(parameters);
- iconRotate.calculate(parameters);
- iconPadding.calculate(parameters);
- iconKeepUpright.calculate(parameters);
- iconOffset.calculate(parameters);
- textPitchAlignment.calculate(parameters);
- textRotationAlignment.calculate(parameters);
- textField.calculate(parameters);
- textFont.calculate(parameters);
- textSize.calculate(parameters);
- textMaxWidth.calculate(parameters);
- textLineHeight.calculate(parameters);
- textLetterSpacing.calculate(parameters);
- textJustify.calculate(parameters);
- textAnchor.calculate(parameters);
- textMaxAngle.calculate(parameters);
- textRotate.calculate(parameters);
- textPadding.calculate(parameters);
- textKeepUpright.calculate(parameters);
- textTransform.calculate(parameters);
- textOffset.calculate(parameters);
- textAllowOverlap.calculate(parameters);
- textIgnorePlacement.calculate(parameters);
- textOptional.calculate(parameters);
-}
-
-void SymbolPaintProperties::cascade(const CascadeParameters& parameters) {
- iconOpacity.cascade(parameters);
- iconColor.cascade(parameters);
- iconHaloColor.cascade(parameters);
- iconHaloWidth.cascade(parameters);
- iconHaloBlur.cascade(parameters);
- iconTranslate.cascade(parameters);
- iconTranslateAnchor.cascade(parameters);
- textOpacity.cascade(parameters);
- textColor.cascade(parameters);
- textHaloColor.cascade(parameters);
- textHaloWidth.cascade(parameters);
- textHaloBlur.cascade(parameters);
- textTranslate.cascade(parameters);
- textTranslateAnchor.cascade(parameters);
-}
-
-bool SymbolPaintProperties::recalculate(const CalculationParameters& parameters) {
- bool hasTransitions = false;
-
- hasTransitions |= iconOpacity.calculate(parameters);
- hasTransitions |= iconColor.calculate(parameters);
- hasTransitions |= iconHaloColor.calculate(parameters);
- hasTransitions |= iconHaloWidth.calculate(parameters);
- hasTransitions |= iconHaloBlur.calculate(parameters);
- hasTransitions |= iconTranslate.calculate(parameters);
- hasTransitions |= iconTranslateAnchor.calculate(parameters);
- hasTransitions |= textOpacity.calculate(parameters);
- hasTransitions |= textColor.calculate(parameters);
- hasTransitions |= textHaloColor.calculate(parameters);
- hasTransitions |= textHaloWidth.calculate(parameters);
- hasTransitions |= textHaloBlur.calculate(parameters);
- hasTransitions |= textTranslate.calculate(parameters);
- hasTransitions |= textTranslateAnchor.calculate(parameters);
-
- return hasTransitions;
-}
-
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layers/symbol_layer_properties.hpp b/src/mbgl/style/layers/symbol_layer_properties.hpp
index fefa0ae05e..8b72c4347a 100644
--- a/src/mbgl/style/layers/symbol_layer_properties.hpp
+++ b/src/mbgl/style/layers/symbol_layer_properties.hpp
@@ -9,69 +9,251 @@
namespace mbgl {
namespace style {
-class CascadeParameters;
-class CalculationParameters;
-
-class SymbolLayoutProperties {
-public:
- void recalculate(const CalculationParameters&);
-
- LayoutProperty<SymbolPlacementType> symbolPlacement { SymbolPlacementType::Point };
- LayoutProperty<float> symbolSpacing { 250 };
- LayoutProperty<bool> symbolAvoidEdges { false };
- LayoutProperty<bool> iconAllowOverlap { false };
- LayoutProperty<bool> iconIgnorePlacement { false };
- LayoutProperty<bool> iconOptional { false };
- LayoutProperty<AlignmentType> iconRotationAlignment { AlignmentType::Auto };
- LayoutProperty<float> iconSize { 1 };
- LayoutProperty<IconTextFitType> iconTextFit { IconTextFitType::None };
- LayoutProperty<std::array<float, 4>> iconTextFitPadding { {{ 0, 0, 0, 0 }} };
- LayoutProperty<std::string> iconImage { "" };
- LayoutProperty<float> iconRotate { 0 };
- LayoutProperty<float> iconPadding { 2 };
- LayoutProperty<bool> iconKeepUpright { false };
- LayoutProperty<std::array<float, 2>> iconOffset { {{ 0, 0 }} };
- LayoutProperty<AlignmentType> textPitchAlignment { AlignmentType::Auto };
- LayoutProperty<AlignmentType> textRotationAlignment { AlignmentType::Auto };
- LayoutProperty<std::string> textField { "" };
- LayoutProperty<std::vector<std::string>> textFont { { "Open Sans Regular", "Arial Unicode MS Regular" } };
- LayoutProperty<float> textSize { 16 };
- LayoutProperty<float> textMaxWidth { 10 };
- LayoutProperty<float> textLineHeight { 1.2 };
- LayoutProperty<float> textLetterSpacing { 0 };
- LayoutProperty<TextJustifyType> textJustify { TextJustifyType::Center };
- LayoutProperty<TextAnchorType> textAnchor { TextAnchorType::Center };
- LayoutProperty<float> textMaxAngle { 45 };
- LayoutProperty<float> textRotate { 0 };
- LayoutProperty<float> textPadding { 2 };
- LayoutProperty<bool> textKeepUpright { true };
- LayoutProperty<TextTransformType> textTransform { TextTransformType::None };
- LayoutProperty<std::array<float, 2>> textOffset { {{ 0, 0 }} };
- LayoutProperty<bool> textAllowOverlap { false };
- LayoutProperty<bool> textIgnorePlacement { false };
- LayoutProperty<bool> textOptional { false };
-};
-
-class SymbolPaintProperties {
-public:
- void cascade(const CascadeParameters&);
- bool recalculate(const CalculationParameters&);
-
- PaintProperty<float> iconOpacity { 1 };
- PaintProperty<Color> iconColor { Color::black() };
- PaintProperty<Color> iconHaloColor { {} };
- PaintProperty<float> iconHaloWidth { 0 };
- PaintProperty<float> iconHaloBlur { 0 };
- PaintProperty<std::array<float, 2>> iconTranslate { {{ 0, 0 }} };
- PaintProperty<TranslateAnchorType> iconTranslateAnchor { TranslateAnchorType::Map };
- PaintProperty<float> textOpacity { 1 };
- PaintProperty<Color> textColor { Color::black() };
- PaintProperty<Color> textHaloColor { {} };
- PaintProperty<float> textHaloWidth { 0 };
- PaintProperty<float> textHaloBlur { 0 };
- PaintProperty<std::array<float, 2>> textTranslate { {{ 0, 0 }} };
- PaintProperty<TranslateAnchorType> textTranslateAnchor { TranslateAnchorType::Map };
+struct SymbolPlacement : LayoutProperty<SymbolPlacementType> {
+ static SymbolPlacementType defaultValue() { return SymbolPlacementType::Point; }
};
+struct SymbolSpacing : LayoutProperty<float> {
+ static float defaultValue() { return 250; }
+};
+
+struct SymbolAvoidEdges : LayoutProperty<bool> {
+ static bool defaultValue() { return false; }
+};
+
+struct IconAllowOverlap : LayoutProperty<bool> {
+ static bool defaultValue() { return false; }
+};
+
+struct IconIgnorePlacement : LayoutProperty<bool> {
+ static bool defaultValue() { return false; }
+};
+
+struct IconOptional : LayoutProperty<bool> {
+ static bool defaultValue() { return false; }
+};
+
+struct IconRotationAlignment : LayoutProperty<AlignmentType> {
+ static AlignmentType defaultValue() { return AlignmentType::Auto; }
+};
+
+struct IconSize : LayoutProperty<float> {
+ static float defaultValue() { return 1; }
+};
+
+struct IconTextFit : LayoutProperty<IconTextFitType> {
+ static IconTextFitType defaultValue() { return IconTextFitType::None; }
+};
+
+struct IconTextFitPadding : LayoutProperty<std::array<float, 4>> {
+ static std::array<float, 4> defaultValue() { return {{ 0, 0, 0, 0 }}; }
+};
+
+struct IconImage : LayoutProperty<std::string> {
+ static std::string defaultValue() { return ""; }
+};
+
+struct IconRotate : LayoutProperty<float> {
+ static float defaultValue() { return 0; }
+};
+
+struct IconPadding : LayoutProperty<float> {
+ static float defaultValue() { return 2; }
+};
+
+struct IconKeepUpright : LayoutProperty<bool> {
+ static bool defaultValue() { return false; }
+};
+
+struct IconOffset : LayoutProperty<std::array<float, 2>> {
+ static std::array<float, 2> defaultValue() { return {{ 0, 0 }}; }
+};
+
+struct TextPitchAlignment : LayoutProperty<AlignmentType> {
+ static AlignmentType defaultValue() { return AlignmentType::Auto; }
+};
+
+struct TextRotationAlignment : LayoutProperty<AlignmentType> {
+ static AlignmentType defaultValue() { return AlignmentType::Auto; }
+};
+
+struct TextField : LayoutProperty<std::string> {
+ static std::string defaultValue() { return ""; }
+};
+
+struct TextFont : LayoutProperty<std::vector<std::string>> {
+ static std::vector<std::string> defaultValue() { return { "Open Sans Regular", "Arial Unicode MS Regular" }; }
+};
+
+struct TextSize : LayoutProperty<float> {
+ static float defaultValue() { return 16; }
+};
+
+struct TextMaxWidth : LayoutProperty<float> {
+ static float defaultValue() { return 10; }
+};
+
+struct TextLineHeight : LayoutProperty<float> {
+ static float defaultValue() { return 1.2; }
+};
+
+struct TextLetterSpacing : LayoutProperty<float> {
+ static float defaultValue() { return 0; }
+};
+
+struct TextJustify : LayoutProperty<TextJustifyType> {
+ static TextJustifyType defaultValue() { return TextJustifyType::Center; }
+};
+
+struct TextAnchor : LayoutProperty<TextAnchorType> {
+ static TextAnchorType defaultValue() { return TextAnchorType::Center; }
+};
+
+struct TextMaxAngle : LayoutProperty<float> {
+ static float defaultValue() { return 45; }
+};
+
+struct TextRotate : LayoutProperty<float> {
+ static float defaultValue() { return 0; }
+};
+
+struct TextPadding : LayoutProperty<float> {
+ static float defaultValue() { return 2; }
+};
+
+struct TextKeepUpright : LayoutProperty<bool> {
+ static bool defaultValue() { return true; }
+};
+
+struct TextTransform : LayoutProperty<TextTransformType> {
+ static TextTransformType defaultValue() { return TextTransformType::None; }
+};
+
+struct TextOffset : LayoutProperty<std::array<float, 2>> {
+ static std::array<float, 2> defaultValue() { return {{ 0, 0 }}; }
+};
+
+struct TextAllowOverlap : LayoutProperty<bool> {
+ static bool defaultValue() { return false; }
+};
+
+struct TextIgnorePlacement : LayoutProperty<bool> {
+ static bool defaultValue() { return false; }
+};
+
+struct TextOptional : LayoutProperty<bool> {
+ static bool defaultValue() { return false; }
+};
+
+struct IconOpacity : PaintProperty<float> {
+ static float defaultValue() { return 1; }
+};
+
+struct IconColor : PaintProperty<Color> {
+ static Color defaultValue() { return Color::black(); }
+};
+
+struct IconHaloColor : PaintProperty<Color> {
+ static Color defaultValue() { return {}; }
+};
+
+struct IconHaloWidth : PaintProperty<float> {
+ static float defaultValue() { return 0; }
+};
+
+struct IconHaloBlur : PaintProperty<float> {
+ static float defaultValue() { return 0; }
+};
+
+struct IconTranslate : PaintProperty<std::array<float, 2>> {
+ static std::array<float, 2> defaultValue() { return {{ 0, 0 }}; }
+};
+
+struct IconTranslateAnchor : PaintProperty<TranslateAnchorType> {
+ static TranslateAnchorType defaultValue() { return TranslateAnchorType::Map; }
+};
+
+struct TextOpacity : PaintProperty<float> {
+ static float defaultValue() { return 1; }
+};
+
+struct TextColor : PaintProperty<Color> {
+ static Color defaultValue() { return Color::black(); }
+};
+
+struct TextHaloColor : PaintProperty<Color> {
+ static Color defaultValue() { return {}; }
+};
+
+struct TextHaloWidth : PaintProperty<float> {
+ static float defaultValue() { return 0; }
+};
+
+struct TextHaloBlur : PaintProperty<float> {
+ static float defaultValue() { return 0; }
+};
+
+struct TextTranslate : PaintProperty<std::array<float, 2>> {
+ static std::array<float, 2> defaultValue() { return {{ 0, 0 }}; }
+};
+
+struct TextTranslateAnchor : PaintProperty<TranslateAnchorType> {
+ static TranslateAnchorType defaultValue() { return TranslateAnchorType::Map; }
+};
+
+class SymbolLayoutProperties : public LayoutProperties<
+ SymbolPlacement,
+ SymbolSpacing,
+ SymbolAvoidEdges,
+ IconAllowOverlap,
+ IconIgnorePlacement,
+ IconOptional,
+ IconRotationAlignment,
+ IconSize,
+ IconTextFit,
+ IconTextFitPadding,
+ IconImage,
+ IconRotate,
+ IconPadding,
+ IconKeepUpright,
+ IconOffset,
+ TextPitchAlignment,
+ TextRotationAlignment,
+ TextField,
+ TextFont,
+ TextSize,
+ TextMaxWidth,
+ TextLineHeight,
+ TextLetterSpacing,
+ TextJustify,
+ TextAnchor,
+ TextMaxAngle,
+ TextRotate,
+ TextPadding,
+ TextKeepUpright,
+ TextTransform,
+ TextOffset,
+ TextAllowOverlap,
+ TextIgnorePlacement,
+ TextOptional
+> {};
+
+class SymbolPaintProperties : public PaintProperties<
+ IconOpacity,
+ IconColor,
+ IconHaloColor,
+ IconHaloWidth,
+ IconHaloBlur,
+ IconTranslate,
+ IconTranslateAnchor,
+ TextOpacity,
+ TextColor,
+ TextHaloColor,
+ TextHaloWidth,
+ TextHaloBlur,
+ TextTranslate,
+ TextTranslateAnchor
+> {};
+
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layout_property.hpp b/src/mbgl/style/layout_property.hpp
index db1a1ebf28..6ea06ce556 100644
--- a/src/mbgl/style/layout_property.hpp
+++ b/src/mbgl/style/layout_property.hpp
@@ -1,43 +1,55 @@
#pragma once
-#include <mbgl/style/property_value.hpp>
-#include <mbgl/style/property_parsing.hpp>
#include <mbgl/style/property_evaluator.hpp>
-
-#include <utility>
+#include <mbgl/util/indexed_tuple.hpp>
namespace mbgl {
namespace style {
-template <typename T>
+class PropertyEvaluationParameters;
+
+template <class T>
class LayoutProperty {
public:
- explicit LayoutProperty(T v)
- : value(std::move(v)),
- defaultValue(value) {}
-
- const PropertyValue<T>& get() const {
- return currentValue;
- }
+ using EvaluatorType = PropertyEvaluator<T>;
+ using UnevaluatedType = PropertyValue<T>;
+ using EvaluatedType = T;
+};
- void set(const PropertyValue<T>& value_) {
- currentValue = value_;
+template <class... Ps>
+class LayoutProperties {
+public:
+ using Properties = TypeList<Ps...>;
+ using EvaluatedTypes = TypeList<typename Ps::EvaluatedType...>;
+ using UnevaluatedTypes = TypeList<typename Ps::UnevaluatedType...>;
+
+ template <class TypeList>
+ using Tuple = IndexedTuple<Properties, TypeList>;
+
+ class Evaluated : public Tuple<EvaluatedTypes> {
+ public:
+ using Tuple<EvaluatedTypes>::Tuple;
+ };
+
+ class Unevaluated : public Tuple<UnevaluatedTypes> {
+ public:
+ using Tuple<UnevaluatedTypes>::Tuple;
+ };
+
+ template <class P>
+ auto evaluate(const PropertyEvaluationParameters& parameters) const {
+ using Evaluator = typename P::EvaluatorType;
+ return unevaluated.template get<P>()
+ .evaluate(Evaluator(parameters, P::defaultValue()));
}
- void calculate(const CalculationParameters& parameters) {
- if (currentValue) {
- PropertyEvaluator<T> evaluator(parameters, defaultValue);
- value = PropertyValue<T>::visit(currentValue, evaluator);
- }
+ Evaluated evaluate(const PropertyEvaluationParameters& parameters) const {
+ return Evaluated {
+ evaluate<Ps>(parameters)...
+ };
}
- // TODO: remove / privatize
- operator T() const { return value; }
- T value;
-
-private:
- T defaultValue;
- PropertyValue<T> currentValue;
+ Unevaluated unevaluated;
};
} // namespace style
diff --git a/src/mbgl/style/paint_property.hpp b/src/mbgl/style/paint_property.hpp
index 4a620706ec..15df2a77c7 100644
--- a/src/mbgl/style/paint_property.hpp
+++ b/src/mbgl/style/paint_property.hpp
@@ -1,14 +1,15 @@
#pragma once
#include <mbgl/style/class_dictionary.hpp>
-#include <mbgl/style/property_parsing.hpp>
#include <mbgl/style/property_evaluator.hpp>
+#include <mbgl/style/cross_faded_property_evaluator.hpp>
#include <mbgl/style/transition_options.hpp>
#include <mbgl/style/cascade_parameters.hpp>
-#include <mbgl/style/calculation_parameters.hpp>
+#include <mbgl/style/property_evaluation_parameters.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/interpolate.hpp>
-#include <mbgl/util/rapidjson.hpp>
+#include <mbgl/util/indexed_tuple.hpp>
+#include <mbgl/util/ignore.hpp>
#include <unordered_map>
#include <utility>
@@ -16,29 +17,59 @@
namespace mbgl {
namespace style {
-template <class T, template <class S> class Evaluator = PropertyEvaluator>
-class PaintProperty {
+template <class T, class Evaluator>
+class UnevaluatedPaintProperty {
public:
- using Result = typename Evaluator<T>::ResultType;
+ using Result = typename Evaluator::ResultType;
+
+ UnevaluatedPaintProperty() = default;
+
+ UnevaluatedPaintProperty(PropertyValue<T> value_,
+ UnevaluatedPaintProperty<T, Evaluator> prior_,
+ TransitionOptions transition,
+ TimePoint now)
+ : begin(now + transition.delay.value_or(Duration::zero())),
+ end(begin + transition.duration.value_or(Duration::zero())),
+ value(std::move(value_)) {
+ if (transition) {
+ prior = { std::move(prior_) };
+ }
+ }
- explicit PaintProperty(T defaultValue_)
- : defaultValue(defaultValue_) {
- values.emplace(ClassID::Fallback, defaultValue_);
+ Result evaluate(const PropertyEvaluationParameters& parameters, T defaultValue) {
+ Result finalValue = value.evaluate(Evaluator(parameters, defaultValue));
+ if (!prior) {
+ // No prior value.
+ return finalValue;
+ } else if (parameters.now >= end) {
+ // Transition from prior value is now complete.
+ prior = {};
+ return finalValue;
+ } else {
+ // Interpolate between recursively-calculated prior value and final.
+ float t = std::chrono::duration<float>(parameters.now - begin) / (end - begin);
+ return util::interpolate(prior->get().evaluate(parameters, defaultValue), finalValue, util::DEFAULT_TRANSITION_EASE.solve(t, 0.001));
+ }
}
- PaintProperty(const PaintProperty& other)
- : defaultValue(other.defaultValue),
- values(other.values),
- transitions(other.transitions) {
+ bool hasTransition() const {
+ return bool(prior);
}
- PaintProperty& operator=(const PaintProperty& other) {
- defaultValue = other.defaultValue;
- values = other.values;
- transitions = other.transitions;
- return *this;
+ bool isUndefined() const {
+ return value.isUndefined();
}
+private:
+ optional<mapbox::util::recursive_wrapper<UnevaluatedPaintProperty<T, Evaluator>>> prior;
+ TimePoint begin;
+ TimePoint end;
+ PropertyValue<T> value;
+};
+
+template <class T>
+class CascadingPaintProperty {
+public:
bool isUndefined() const {
return values.find(ClassID::Default) == values.end();
}
@@ -57,82 +88,119 @@ public:
transitions[klass ? ClassDictionary::Get().lookup(*klass) : ClassID::Default] = transition;
}
- void cascade(const CascadeParameters& params) {
- const bool overrideTransition = !params.transition.delay && !params.transition.duration;
- Duration delay = params.transition.delay.value_or(Duration::zero());
- Duration duration = params.transition.duration.value_or(Duration::zero());
+ template <class UnevaluatedPaintProperty>
+ UnevaluatedPaintProperty cascade(const CascadeParameters& params, UnevaluatedPaintProperty prior) const {
+ TransitionOptions transition;
+ PropertyValue<T> value;
for (const auto classID : params.classes) {
- if (values.find(classID) == values.end())
- continue;
-
- if (overrideTransition && transitions.find(classID) != transitions.end()) {
- const TransitionOptions& transition = transitions[classID];
- if (transition.delay) delay = *transition.delay;
- if (transition.duration) duration = *transition.duration;
+ if (values.find(classID) != values.end()) {
+ value = values.at(classID);
+ break;
}
-
- cascaded = std::make_unique<CascadedValue>(std::move(cascaded),
- params.now + delay,
- params.now + delay + duration,
- values.at(classID));
-
- break;
}
- assert(cascaded);
- }
+ for (const auto classID : params.classes) {
+ if (transitions.find(classID) != transitions.end()) {
+ transition = transitions.at(classID).reverseMerge(transition);
+ break;
+ }
+ }
- bool calculate(const CalculationParameters& parameters) {
- assert(cascaded);
- Evaluator<T> evaluator(parameters, defaultValue);
- value = cascaded->calculate(evaluator, parameters.now);
- return cascaded->prior.operator bool();
+ return UnevaluatedPaintProperty(std::move(value),
+ std::move(prior),
+ transition.reverseMerge(params.transition),
+ params.now);
}
- // TODO: remove / privatize
- operator T() const { return value; }
- Result value;
-
private:
- T defaultValue;
std::unordered_map<ClassID, PropertyValue<T>> values;
std::unordered_map<ClassID, TransitionOptions> transitions;
+};
- struct CascadedValue {
- CascadedValue(std::unique_ptr<CascadedValue> prior_,
- TimePoint begin_,
- TimePoint end_,
- PropertyValue<T> value_)
- : prior(std::move(prior_)),
- begin(std::move(begin_)),
- end(std::move(end_)),
- value(std::move(value_)) {
- }
+template <class T>
+class PaintProperty {
+public:
+ using ValueType = PropertyValue<T>;
+ using CascadingType = CascadingPaintProperty<T>;
+ using EvaluatorType = PropertyEvaluator<T>;
+ using UnevaluatedType = UnevaluatedPaintProperty<T, EvaluatorType>;
+ using EvaluatedType = T;
+};
- Result calculate(const Evaluator<T>& evaluator, const TimePoint& now) {
- Result finalValue = PropertyValue<T>::visit(value, evaluator);
- if (!prior) {
- // No prior value.
- return finalValue;
- } else if (now >= end) {
- // Transition from prior value is now complete.
- prior.reset();
- return finalValue;
- } else {
- // Interpolate between recursively-calculated prior value and final.
- float t = std::chrono::duration<float>(now - begin) / (end - begin);
- return util::interpolate(prior->calculate(evaluator, now), finalValue, util::DEFAULT_TRANSITION_EASE.solve(t, 0.001));
- }
- }
+template <class T>
+class CrossFadedPaintProperty {
+public:
+ using ValueType = PropertyValue<T>;
+ using CascadingType = CascadingPaintProperty<T>;
+ using EvaluatorType = CrossFadedPropertyEvaluator<T>;
+ using UnevaluatedType = UnevaluatedPaintProperty<T, EvaluatorType>;
+ using EvaluatedType = Faded<T>;
+};
- std::unique_ptr<CascadedValue> prior;
- TimePoint begin;
- TimePoint end;
- PropertyValue<T> value;
+template <class... Ps>
+class PaintProperties {
+public:
+ using Properties = TypeList<Ps...>;
+ using EvaluatedTypes = TypeList<typename Ps::EvaluatedType...>;
+ using UnevaluatedTypes = TypeList<typename Ps::UnevaluatedType...>;
+ using CascadingTypes = TypeList<typename Ps::CascadingType...>;
+
+ template <class TypeList>
+ using Tuple = IndexedTuple<Properties, TypeList>;
+
+ class Evaluated : public Tuple<EvaluatedTypes> {
+ public:
+ using Tuple<EvaluatedTypes>::Tuple;
+ };
+
+ class Unevaluated : public Tuple<UnevaluatedTypes> {
+ public:
+ using Tuple<UnevaluatedTypes>::Tuple;
};
- std::unique_ptr<CascadedValue> cascaded;
+ class Cascading : public Tuple<CascadingTypes> {
+ public:
+ using Tuple<CascadingTypes>::Tuple;
+ };
+
+ template <class P>
+ auto get(const optional<std::string>& klass) const {
+ return cascading.template get<P>().get(klass);
+ }
+
+ template <class P>
+ void set(const typename P::ValueType& value, const optional<std::string>& klass) {
+ cascading.template get<P>().set(value, klass);
+ }
+
+ void cascade(const CascadeParameters& parameters) {
+ unevaluated = Unevaluated {
+ cascading.template get<Ps>().cascade(parameters,
+ std::move(unevaluated.template get<Ps>()))...
+ };
+ }
+
+ template <class P>
+ auto evaluate(const PropertyEvaluationParameters& parameters) {
+ return unevaluated.template get<P>().evaluate(parameters, P::defaultValue());
+ }
+
+ void evaluate(const PropertyEvaluationParameters& parameters) {
+ evaluated = Evaluated {
+ evaluate<Ps>(parameters)...
+ };
+ }
+
+ bool hasTransition() const {
+ bool result = false;
+ util::ignore({ result |= unevaluated.template get<Ps>().hasTransition()... });
+ return result;
+ }
+
+ Cascading cascading;
+ Unevaluated unevaluated;
+ Evaluated evaluated;
};
} // namespace style
diff --git a/src/mbgl/style/parser.cpp b/src/mbgl/style/parser.cpp
index 059082980d..c6c6e50dd7 100644
--- a/src/mbgl/style/parser.cpp
+++ b/src/mbgl/style/parser.cpp
@@ -5,7 +5,7 @@
#include <mbgl/style/conversion/source.hpp>
#include <mbgl/style/conversion/layer.hpp>
-#include <mbgl/platform/log.hpp>
+#include <mbgl/util/logging.hpp>
#include <mapbox/geojsonvt.hpp>
diff --git a/src/mbgl/style/calculation_parameters.hpp b/src/mbgl/style/property_evaluation_parameters.hpp
index e1f059c524..2591fc07a1 100644
--- a/src/mbgl/style/calculation_parameters.hpp
+++ b/src/mbgl/style/property_evaluation_parameters.hpp
@@ -6,12 +6,12 @@
namespace mbgl {
namespace style {
-class CalculationParameters {
+class PropertyEvaluationParameters {
public:
- explicit CalculationParameters(float z_)
+ explicit PropertyEvaluationParameters(float z_)
: z(z_) {}
- CalculationParameters(float z_,
+ PropertyEvaluationParameters(float z_,
TimePoint now_,
ZoomHistory zoomHistory_,
Duration defaultFadeDuration_)
diff --git a/src/mbgl/style/property_evaluator.cpp b/src/mbgl/style/property_evaluator.cpp
deleted file mode 100644
index abb3681efa..0000000000
--- a/src/mbgl/style/property_evaluator.cpp
+++ /dev/null
@@ -1,152 +0,0 @@
-#include <mbgl/style/property_evaluator.hpp>
-#include <mbgl/style/calculation_parameters.hpp>
-#include <mbgl/style/types.hpp>
-#include <mbgl/util/interpolate.hpp>
-#include <mbgl/util/chrono.hpp>
-#include <mbgl/util/color.hpp>
-
-#include <cmath>
-
-namespace mbgl {
-namespace style {
-
-template <typename T>
-T defaultStopsValue();
-
-template <> bool defaultStopsValue() { return true; }
-template <> float defaultStopsValue() { return 1.0f; }
-template <> Color defaultStopsValue() { return { 0, 0, 0, 1 }; }
-template <> std::vector<float> defaultStopsValue() { return {{ 1, 0 }}; }
-template <> std::vector<std::string> defaultStopsValue() { return {{}}; }
-template <> std::array<float, 2> defaultStopsValue() { return {{ 0, 0 }}; }
-template <> std::array<float, 4> defaultStopsValue() { return {{ 0, 0, 0, 0 }}; }
-
-template <> std::string defaultStopsValue() { return {}; }
-template <> TranslateAnchorType defaultStopsValue() { return {}; }
-template <> RotateAnchorType defaultStopsValue() { return {}; }
-template <> CirclePitchScaleType defaultStopsValue() { return {}; }
-template <> LineCapType defaultStopsValue() { return {}; }
-template <> LineJoinType defaultStopsValue() { return {}; }
-template <> SymbolPlacementType defaultStopsValue() { return {}; }
-template <> TextAnchorType defaultStopsValue() { return {}; }
-template <> TextJustifyType defaultStopsValue() { return {}; }
-template <> TextTransformType defaultStopsValue() { return {}; }
-template <> AlignmentType defaultStopsValue() { return {}; }
-template <> IconTextFitType defaultStopsValue() { return {}; };
-
-template <typename T>
-T PropertyEvaluator<T>::operator()(const Function<T>& fn) const {
- float base = fn.getBase();
- const std::vector<std::pair<float, T>>& stops = fn.getStops();
- float z = parameters.z;
- bool smaller = false;
- float smaller_z = 0.0f;
- T smaller_val = T();
- bool larger = false;
- float larger_z = 0.0f;
- T larger_val = T();
-
- for (uint32_t i = 0; i < stops.size(); i++) {
- float stop_z = stops[i].first;
- T stop_val = stops[i].second;
- if (stop_z <= z && (!smaller || smaller_z < stop_z)) {
- smaller = true;
- smaller_z = stop_z;
- smaller_val = stop_val;
- }
- if (stop_z >= z && (!larger || larger_z > stop_z)) {
- larger = true;
- larger_z = stop_z;
- larger_val = stop_val;
- }
- }
-
- if (smaller && larger) {
- if (larger_z == smaller_z || larger_val == smaller_val) {
- return smaller_val;
- }
- const float zoomDiff = larger_z - smaller_z;
- const float zoomProgress = z - smaller_z;
- if (base == 1.0f) {
- const float t = zoomProgress / zoomDiff;
- return util::interpolate(smaller_val, larger_val, t);
- } else {
- const float t = (std::pow(base, zoomProgress) - 1) / (std::pow(base, zoomDiff) - 1);
- return util::interpolate(smaller_val, larger_val, t);
- }
- } else if (larger) {
- return larger_val;
- } else if (smaller) {
- return smaller_val;
- } else {
- // No stop defined.
- return defaultStopsValue<T>();
- }
-}
-
-template class PropertyEvaluator<bool>;
-template class PropertyEvaluator<float>;
-template class PropertyEvaluator<Color>;
-template class PropertyEvaluator<std::vector<float>>;
-template class PropertyEvaluator<std::vector<std::string>>;
-template class PropertyEvaluator<std::array<float, 2>>;
-template class PropertyEvaluator<std::array<float, 4>>;
-
-template class PropertyEvaluator<std::string>;
-template class PropertyEvaluator<TranslateAnchorType>;
-template class PropertyEvaluator<RotateAnchorType>;
-template class PropertyEvaluator<CirclePitchScaleType>;
-template class PropertyEvaluator<LineCapType>;
-template class PropertyEvaluator<LineJoinType>;
-template class PropertyEvaluator<SymbolPlacementType>;
-template class PropertyEvaluator<TextAnchorType>;
-template class PropertyEvaluator<TextJustifyType>;
-template class PropertyEvaluator<TextTransformType>;
-template class PropertyEvaluator<AlignmentType>;
-template class PropertyEvaluator<IconTextFitType>;
-
-template <typename T>
-Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const Undefined&) const {
- return calculate(defaultValue, defaultValue, defaultValue);
-}
-
-template <typename T>
-Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const T& constant) const {
- return calculate(constant, constant, constant);
-}
-
-template <typename T>
-T getBiggestStopLessThan(const Function<T>& function, float z) {
- const auto& stops = function.getStops();
- for (uint32_t i = 0; i < stops.size(); i++) {
- if (stops[i].first > z) {
- return stops[i == 0 ? i : i - 1].second;
- }
- }
- return stops.at(stops.size() - 1).second;
-}
-
-template <typename T>
-Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const Function<T>& function) const {
- return calculate(getBiggestStopLessThan(function, parameters.z - 1.0f),
- getBiggestStopLessThan(function, parameters.z),
- getBiggestStopLessThan(function, parameters.z + 1.0f));
-}
-
-template <typename T>
-Faded<T> CrossFadedPropertyEvaluator<T>::calculate(const T& min, const T& mid, const T& max) const {
- const float z = parameters.z;
- const float fraction = z - std::floor(z);
- const std::chrono::duration<float> d = parameters.defaultFadeDuration;
- const float t = std::min((parameters.now - parameters.zoomHistory.lastIntegerZoomTime) / d, 1.0f);
-
- return z > parameters.zoomHistory.lastIntegerZoom
- ? Faded<T> { min, mid, 2.0f, 1.0f, fraction + (1.0f - fraction) * t }
- : Faded<T> { max, mid, 0.5f, 1.0f, 1 - (1 - t) * fraction };
-}
-
-template class CrossFadedPropertyEvaluator<std::string>;
-template class CrossFadedPropertyEvaluator<std::vector<float>>;
-
-} // namespace style
-} // namespace mbgl
diff --git a/src/mbgl/style/property_evaluator.hpp b/src/mbgl/style/property_evaluator.hpp
index a0bce2f499..ca4962d948 100644
--- a/src/mbgl/style/property_evaluator.hpp
+++ b/src/mbgl/style/property_evaluator.hpp
@@ -1,66 +1,28 @@
#pragma once
#include <mbgl/style/property_value.hpp>
-#include <mbgl/util/interpolate.hpp>
+#include <mbgl/style/property_evaluation_parameters.hpp>
namespace mbgl {
namespace style {
-class CalculationParameters;
-
template <typename T>
class PropertyEvaluator {
public:
using ResultType = T;
- PropertyEvaluator(const CalculationParameters& parameters_, T defaultValue_)
+ PropertyEvaluator(const PropertyEvaluationParameters& parameters_, T defaultValue_)
: parameters(parameters_),
defaultValue(std::move(defaultValue_)) {}
T operator()(const Undefined&) const { return defaultValue; }
T operator()(const T& constant) const { return constant; }
- T operator()(const Function<T>&) const;
+ T operator()(const Function<T>& fn) const { return fn.evaluate(parameters.z); }
private:
- const CalculationParameters& parameters;
- T defaultValue;
-};
-
-template <typename T>
-struct Faded {
- T from;
- T to;
- float fromScale;
- float toScale;
- float t;
-};
-
-template <typename T>
-class CrossFadedPropertyEvaluator {
-public:
- using ResultType = Faded<T>;
-
- CrossFadedPropertyEvaluator(const CalculationParameters& parameters_, T defaultValue_)
- : parameters(parameters_),
- defaultValue(std::move(defaultValue_)) {}
-
- Faded<T> operator()(const Undefined&) const;
- Faded<T> operator()(const T& constant) const;
- Faded<T> operator()(const Function<T>&) const;
-
-private:
- Faded<T> calculate(const T& min, const T& mid, const T& max) const;
-
- const CalculationParameters& parameters;
+ const PropertyEvaluationParameters& parameters;
T defaultValue;
};
} // namespace style
-
-namespace util {
-template <typename T>
-struct Interpolator<style::Faded<T>>
- : Uninterpolated {};
-} // namespace util
-
} // namespace mbgl
diff --git a/src/mbgl/style/property_parsing.hpp b/src/mbgl/style/property_parsing.hpp
index 8c2bd2c0f4..b542c8ae47 100644
--- a/src/mbgl/style/property_parsing.hpp
+++ b/src/mbgl/style/property_parsing.hpp
@@ -5,7 +5,7 @@
#include <mbgl/style/rapidjson_conversion.hpp>
#include <mbgl/style/conversion/property_value.hpp>
-#include <mbgl/platform/log.hpp>
+#include <mbgl/util/logging.hpp>
namespace mbgl {
namespace style {
diff --git a/src/mbgl/style/source_impl.cpp b/src/mbgl/style/source_impl.cpp
index d0ae54092d..149bf99f9d 100644
--- a/src/mbgl/style/source_impl.cpp
+++ b/src/mbgl/style/source_impl.cpp
@@ -6,7 +6,7 @@
#include <mbgl/style/update_parameters.hpp>
#include <mbgl/style/query_parameters.hpp>
#include <mbgl/text/placement_config.hpp>
-#include <mbgl/platform/log.hpp>
+#include <mbgl/util/logging.hpp>
#include <mbgl/math/clamp.hpp>
#include <mbgl/util/tile_cover.hpp>
#include <mbgl/util/enum.hpp>
@@ -70,11 +70,13 @@ void Source::Impl::startRender(algorithm::ClipIDGenerator& generator,
void Source::Impl::finishRender(Painter& painter) {
for (auto& pair : renderTiles) {
auto& tile = pair.second;
- painter.renderTileDebug(tile);
+ if (tile.used) {
+ painter.renderTileDebug(tile);
+ }
}
}
-const std::map<UnwrappedTileID, RenderTile>& Source::Impl::getRenderTiles() const {
+std::map<UnwrappedTileID, RenderTile>& Source::Impl::getRenderTiles() {
return renderTiles;
}
@@ -139,13 +141,26 @@ void Source::Impl::updateTiles(const UpdateParameters& parameters) {
if (type != SourceType::Annotations && cache.getSize() == 0) {
size_t conservativeCacheSize =
- std::max((float)parameters.transformState.getWidth() / util::tileSize, 1.0f) *
- std::max((float)parameters.transformState.getHeight() / util::tileSize, 1.0f) *
+ std::max((float)parameters.transformState.getSize().width / util::tileSize, 1.0f) *
+ std::max((float)parameters.transformState.getSize().height / util::tileSize, 1.0f) *
(parameters.transformState.getMaxZoom() - parameters.transformState.getMinZoom() + 1) *
0.5;
cache.setSize(conservativeCacheSize);
}
+ removeStaleTiles(retain);
+
+ const PlacementConfig config { parameters.transformState.getAngle(),
+ parameters.transformState.getPitch(),
+ parameters.debugOptions & MapDebugOptions::Collision };
+
+ for (auto& pair : tiles) {
+ pair.second->setPlacementConfig(config);
+ }
+}
+
+// Moves all tiles to the cache except for those specified in the retain set.
+void Source::Impl::removeStaleTiles(const std::set<OverscaledTileID>& retain) {
// Remove stale tiles. This goes through the (sorted!) tiles map and retain set in lockstep
// and removes items from tiles that don't have the corresponding key in the retain set.
auto tilesIt = tiles.begin();
@@ -162,13 +177,12 @@ void Source::Impl::updateTiles(const UpdateParameters& parameters) {
++retainIt;
}
}
+}
- const PlacementConfig config { parameters.transformState.getAngle(),
- parameters.transformState.getPitch(),
- parameters.debugOptions & MapDebugOptions::Collision };
-
- for (auto& pair : tiles) {
- pair.second->setPlacementConfig(config);
+void Source::Impl::removeTiles() {
+ renderTiles.clear();
+ if (!tiles.empty()) {
+ removeStaleTiles({});
}
}
@@ -196,7 +210,7 @@ std::unordered_map<std::string, std::vector<Feature>> Source::Impl::queryRendere
for (const auto& p : parameters.geometry) {
queryGeometry.push_back(TileCoordinate::fromScreenCoordinate(
- parameters.transformState, 0, { p.x, parameters.transformState.getHeight() - p.y }).p);
+ parameters.transformState, 0, { p.x, parameters.transformState.getSize().height - p.y }).p);
}
mapbox::geometry::box<double> box = mapbox::geometry::envelope(queryGeometry);
diff --git a/src/mbgl/style/source_impl.hpp b/src/mbgl/style/source_impl.hpp
index a4dd48444e..e6340ae1cb 100644
--- a/src/mbgl/style/source_impl.hpp
+++ b/src/mbgl/style/source_impl.hpp
@@ -63,7 +63,7 @@ public:
const TransformState&);
void finishRender(Painter&);
- const std::map<UnwrappedTileID, RenderTile>& getRenderTiles() const;
+ std::map<UnwrappedTileID, RenderTile>& getRenderTiles();
std::unordered_map<std::string, std::vector<Feature>>
queryRenderedFeatures(const QueryParameters&) const;
@@ -88,6 +88,7 @@ public:
protected:
void invalidateTiles();
+ void removeStaleTiles(const std::set<OverscaledTileID>&);
Source& base;
SourceObserver* observer = nullptr;
diff --git a/src/mbgl/style/sources/geojson_source_impl.cpp b/src/mbgl/style/sources/geojson_source_impl.cpp
index 4800b9c4be..7f41e0e321 100644
--- a/src/mbgl/style/sources/geojson_source_impl.cpp
+++ b/src/mbgl/style/sources/geojson_source_impl.cpp
@@ -1,4 +1,4 @@
-#include <mbgl/platform/log.hpp>
+#include <mbgl/util/logging.hpp>
#include <mbgl/storage/file_source.hpp>
#include <mbgl/style/conversion/geojson.hpp>
#include <mbgl/style/source_observer.hpp>
diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp
index d28963aa64..2d11d16b1f 100644
--- a/src/mbgl/style/style.cpp
+++ b/src/mbgl/style/style.cpp
@@ -8,6 +8,7 @@
#include <mbgl/style/layers/background_layer.hpp>
#include <mbgl/style/layers/background_layer_impl.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
+#include <mbgl/style/layers/fill_extrusion_layer.hpp>
#include <mbgl/style/layers/line_layer.hpp>
#include <mbgl/style/layers/circle_layer.hpp>
#include <mbgl/style/layers/raster_layer.hpp>
@@ -18,7 +19,7 @@
#include <mbgl/style/class_dictionary.hpp>
#include <mbgl/style/update_parameters.hpp>
#include <mbgl/style/cascade_parameters.hpp>
-#include <mbgl/style/calculation_parameters.hpp>
+#include <mbgl/style/property_evaluation_parameters.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/text/glyph_atlas.hpp>
#include <mbgl/geometry/line_atlas.hpp>
@@ -26,7 +27,7 @@
#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/string.hpp>
-#include <mbgl/platform/log.hpp>
+#include <mbgl/util/logging.hpp>
#include <mbgl/math/minmax.hpp>
#include <algorithm>
@@ -38,9 +39,9 @@ static Observer nullObserver;
Style::Style(FileSource& fileSource_, float pixelRatio)
: fileSource(fileSource_),
- glyphAtlas(std::make_unique<GlyphAtlas>(2048, 2048, fileSource)),
- spriteAtlas(std::make_unique<SpriteAtlas>(1024, 1024, pixelRatio)),
- lineAtlas(std::make_unique<LineAtlas>(256, 512)),
+ glyphAtlas(std::make_unique<GlyphAtlas>(Size{ 2048, 2048 }, fileSource)),
+ spriteAtlas(std::make_unique<SpriteAtlas>(Size{ 1024, 1024 }, pixelRatio)),
+ lineAtlas(std::make_unique<LineAtlas>(Size{ 256, 512 })),
observer(&nullObserver) {
glyphAtlas->setObserver(this);
spriteAtlas->setObserver(this);
@@ -262,7 +263,9 @@ double Style::getDefaultPitch() const {
void Style::updateTiles(const UpdateParameters& parameters) {
for (const auto& source : sources) {
- source->baseImpl->updateTiles(parameters);
+ if (source->baseImpl->enabled) {
+ source->baseImpl->updateTiles(parameters);
+ }
}
}
@@ -275,8 +278,9 @@ void Style::updateSymbolDependentTiles() {
void Style::relayout() {
for (const auto& sourceID : updateBatch.sourceIDs) {
Source* source = getSource(sourceID);
- if (!source) continue;
- source->baseImpl->reloadTiles();
+ if (source && source->baseImpl->enabled) {
+ source->baseImpl->reloadTiles();
+ }
}
updateBatch.sourceIDs.clear();
}
@@ -291,7 +295,6 @@ void Style::cascade(const TimePoint& timePoint, MapMode mode) {
classIDs.push_back(ClassDictionary::Get().lookup(className));
}
classIDs.push_back(ClassID::Default);
- classIDs.push_back(ClassID::Fallback);
const CascadeParameters parameters {
classIDs,
@@ -305,13 +308,15 @@ void Style::cascade(const TimePoint& timePoint, MapMode mode) {
}
void Style::recalculate(float z, const TimePoint& timePoint, MapMode mode) {
+ // Disable all sources first. If we find an enabled layer that uses this source, we will
+ // re-enable it later.
for (const auto& source : sources) {
source->baseImpl->enabled = false;
}
zoomHistory.update(z, timePoint);
- const CalculationParameters parameters {
+ const PropertyEvaluationParameters parameters {
z,
mode == MapMode::Continuous ? timePoint : Clock::time_point::max(),
zoomHistory,
@@ -320,7 +325,7 @@ void Style::recalculate(float z, const TimePoint& timePoint, MapMode mode) {
hasPendingTransitions = false;
for (const auto& layer : layers) {
- const bool hasTransitions = layer->baseImpl->recalculate(parameters);
+ const bool hasTransitions = layer->baseImpl->evaluate(parameters);
// Disable this layer if it doesn't need to be rendered.
const bool needsRendering = layer->baseImpl->needsRendering(zoomHistory.lastZoom);
@@ -338,6 +343,13 @@ void Style::recalculate(float z, const TimePoint& timePoint, MapMode mode) {
}
}
}
+
+ // Remove the existing tiles if we didn't end up re-enabling the source.
+ for (const auto& source : sources) {
+ if (!source->baseImpl->enabled) {
+ source->baseImpl->removeTiles();
+ }
+ }
}
std::vector<const Source*> Style::getSources() const {
@@ -388,7 +400,7 @@ bool Style::isLoaded() const {
return true;
}
-RenderData Style::getRenderData(MapDebugOptions debugOptions) const {
+RenderData Style::getRenderData(MapDebugOptions debugOptions, float angle) const {
RenderData result;
for (const auto& source : sources) {
@@ -397,6 +409,9 @@ RenderData Style::getRenderData(MapDebugOptions debugOptions) const {
}
}
+ const bool isLeft = std::abs(angle) > M_PI_2;
+ const bool isBottom = angle < 0;
+
for (const auto& layer : layers) {
if (!layer->baseImpl->needsRendering(zoomHistory.lastZoom)) {
continue;
@@ -408,10 +423,10 @@ RenderData Style::getRenderData(MapDebugOptions debugOptions) const {
result.order.emplace_back(*layer);
continue;
}
- const BackgroundPaintProperties& paint = background->impl->paint;
- if (layer.get() == layers[0].get() && paint.backgroundPattern.value.from.empty()) {
+ const BackgroundPaintProperties::Evaluated& paint = background->impl->paint.evaluated;
+ if (layer.get() == layers[0].get() && paint.get<BackgroundPattern>().from.empty()) {
// This is a solid background. We can use glClear().
- result.backgroundColor = paint.backgroundColor * paint.backgroundOpacity;
+ result.backgroundColor = paint.get<BackgroundColor>() * paint.get<BackgroundOpacity>();
} else {
// This is a textured background, or not the bottommost layer. We need to render it with a quad.
result.order.emplace_back(*layer);
@@ -430,8 +445,29 @@ RenderData Style::getRenderData(MapDebugOptions debugOptions) const {
continue;
}
- for (auto& pair : source->baseImpl->getRenderTiles()) {
- auto& tile = pair.second;
+ auto& renderTiles = source->baseImpl->getRenderTiles();
+ const bool symbolLayer = layer->is<SymbolLayer>();
+
+ // Sort symbol tiles in opposite y position, so tiles with overlapping
+ // symbols are drawn on top of each other, with lower symbols being
+ // drawn on top of higher symbols.
+ std::vector<std::reference_wrapper<RenderTile>> sortedTiles;
+ std::transform(renderTiles.begin(), renderTiles.end(), std::back_inserter(sortedTiles),
+ [](auto& pair) { return std::ref(pair.second); });
+ if (symbolLayer) {
+ std::sort(sortedTiles.begin(), sortedTiles.end(),
+ [isLeft, isBottom](const RenderTile& a, const RenderTile& b) {
+ bool sortX = a.id.canonical.x > b.id.canonical.x;
+ bool sortW = a.id.wrap > b.id.wrap;
+ bool sortY = a.id.canonical.y > b.id.canonical.y;
+ return
+ a.id.canonical.y != b.id.canonical.y ? (isLeft ? sortY : !sortY) :
+ a.id.wrap != b.id.wrap ? (isBottom ? sortW : !sortW) : (isBottom ? sortX : !sortX);
+ });
+ }
+
+ for (auto& tileRef : sortedTiles) {
+ auto& tile = tileRef.get();
if (!tile.tile.isRenderable()) {
continue;
}
@@ -439,7 +475,7 @@ RenderData Style::getRenderData(MapDebugOptions debugOptions) const {
// We're not clipping symbol layers, so when we have both parents and children of symbol
// layers, we drop all children in favor of their parent to avoid duplicate labels.
// See https://github.com/mapbox/mapbox-gl-native/issues/2482
- if (layer->is<SymbolLayer>()) {
+ if (symbolLayer) {
bool skip = false;
// Look back through the buckets we decided to render to find out whether there is
// already a bucket from this layer that is a parent of this tile. Tiles are ordered
@@ -458,6 +494,7 @@ RenderData Style::getRenderData(MapDebugOptions debugOptions) const {
auto bucket = tile.tile.getBucket(*layer);
if (bucket) {
result.order.emplace_back(*layer, &tile, bucket);
+ tile.used = true;
}
}
}
diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp
index 1da22b8cf3..d46e80e8bf 100644
--- a/src/mbgl/style/style.hpp
+++ b/src/mbgl/style/style.hpp
@@ -93,7 +93,7 @@ public:
bool hasClass(const std::string&) const;
std::vector<std::string> getClasses() const;
- RenderData getRenderData(MapDebugOptions) const;
+ RenderData getRenderData(MapDebugOptions, float angle) const;
std::vector<Feature> queryRenderedFeatures(const QueryParameters&) const;
@@ -118,9 +118,9 @@ private:
// Defaults
std::string name;
LatLng defaultLatLng;
- double defaultZoom;
- double defaultBearing;
- double defaultPitch;
+ double defaultZoom = 0;
+ double defaultBearing = 0;
+ double defaultPitch = 0;
std::vector<std::unique_ptr<Layer>>::const_iterator findLayer(const std::string& layerID) const;
void reloadLayerSource(Layer&);
diff --git a/src/mbgl/text/bidi.hpp b/src/mbgl/text/bidi.hpp
new file mode 100644
index 0000000000..6c209c427c
--- /dev/null
+++ b/src/mbgl/text/bidi.hpp
@@ -0,0 +1,46 @@
+#pragma once
+
+#include <set>
+#include <string>
+#include <vector>
+#include <memory>
+
+#include <mbgl/util/noncopyable.hpp>
+
+namespace mbgl {
+
+class BiDi;
+class BiDiImpl;
+
+std::u16string applyArabicShaping(const std::u16string&);
+
+class ProcessedBiDiText {
+public:
+ ProcessedBiDiText(BiDi&);
+
+ std::vector<std::u16string> applyLineBreaking(std::set<int32_t>);
+
+private:
+ void mergeParagraphLineBreaks(std::set<int32_t>&);
+
+ BiDi& bidi;
+};
+
+class BiDi : private util::noncopyable {
+public:
+ BiDi();
+ ~BiDi();
+
+ // Calling processText resets internal state, invalidating any existing ProcessedBiDiText
+ // objects
+ ProcessedBiDiText processText(const std::u16string&);
+
+ friend class ProcessedBiDiText;
+
+private:
+ std::u16string getLine(int32_t start, int32_t end);
+
+ std::unique_ptr<BiDiImpl> impl;
+};
+
+} // end namespace mbgl
diff --git a/src/mbgl/text/collision_tile.cpp b/src/mbgl/text/collision_tile.cpp
index e485fbf36c..419ab31a79 100644
--- a/src/mbgl/text/collision_tile.cpp
+++ b/src/mbgl/text/collision_tile.cpp
@@ -1,5 +1,6 @@
#include <mbgl/text/collision_tile.hpp>
#include <mbgl/geometry/feature_index.hpp>
+#include <mbgl/math/log2.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/math.hpp>
#include <mbgl/math/minmax.hpp>
diff --git a/src/mbgl/text/get_anchors.cpp b/src/mbgl/text/get_anchors.cpp
index ce45e05d9c..b912c7763e 100644
--- a/src/mbgl/text/get_anchors.cpp
+++ b/src/mbgl/text/get_anchors.cpp
@@ -72,6 +72,7 @@ Anchors getAnchors(const GeometryCoordinates &line, float spacing,
const float maxAngle, const float textLeft, const float textRight,
const float iconLeft, const float iconRight,
const float glyphSize, const float boxScale, const float overscaling) {
+ if (line.empty()) return {};
// Resample a line to get anchor points for labels and check that each
// potential label passes text-max-angle check and has enough froom to fit
diff --git a/src/mbgl/text/glyph.cpp b/src/mbgl/text/glyph.cpp
index a877d7a799..29929b73e6 100644
--- a/src/mbgl/text/glyph.cpp
+++ b/src/mbgl/text/glyph.cpp
@@ -3,7 +3,7 @@
namespace mbgl {
// Note: this only works for the BMP
-GlyphRange getGlyphRange(char32_t glyph) {
+GlyphRange getGlyphRange(char16_t glyph) {
unsigned start = (glyph/256) * 256;
unsigned end = (start + 255);
if (start > 65280) start = 65280;
diff --git a/src/mbgl/text/glyph.hpp b/src/mbgl/text/glyph.hpp
index 975dc4ad23..d07fbdff21 100644
--- a/src/mbgl/text/glyph.hpp
+++ b/src/mbgl/text/glyph.hpp
@@ -11,10 +11,10 @@
namespace mbgl {
// Note: this only works for the BMP
-GlyphRange getGlyphRange(char32_t glyph);
+GlyphRange getGlyphRange(char16_t glyph);
struct GlyphMetrics {
- operator bool() const {
+ explicit operator bool() const {
return !(width == 0 && height == 0 && advance == 0);
}
@@ -27,12 +27,20 @@ struct GlyphMetrics {
};
+inline bool operator==(const GlyphMetrics& lhs, const GlyphMetrics& rhs) {
+ return lhs.width == rhs.width &&
+ lhs.height == rhs.height &&
+ lhs.left == rhs.left &&
+ lhs.top == rhs.top &&
+ lhs.advance == rhs.advance;
+}
+
struct Glyph {
explicit Glyph() : rect(0, 0, 0, 0), metrics() {}
explicit Glyph(Rect<uint16_t> rect_, GlyphMetrics metrics_)
: rect(std::move(rect_)), metrics(std::move(metrics_)) {}
- operator bool() const {
+ explicit operator bool() const {
return metrics || rect.hasArea();
}
@@ -55,16 +63,16 @@ public:
class Shaping {
public:
explicit Shaping() : top(0), bottom(0), left(0), right(0) {}
- explicit Shaping(float x, float y, std::u32string text_)
+ explicit Shaping(float x, float y, std::u16string text_)
: text(std::move(text_)), top(y), bottom(y), left(x), right(x) {}
std::vector<PositionedGlyph> positionedGlyphs;
- std::u32string text;
+ std::u16string text;
int32_t top;
int32_t bottom;
int32_t left;
int32_t right;
- operator bool() const { return !positionedGlyphs.empty(); }
+ explicit operator bool() const { return !positionedGlyphs.empty(); }
};
class SDFGlyph {
diff --git a/src/mbgl/text/glyph_atlas.cpp b/src/mbgl/text/glyph_atlas.cpp
index 2f8c44db59..5d30dacdce 100644
--- a/src/mbgl/text/glyph_atlas.cpp
+++ b/src/mbgl/text/glyph_atlas.cpp
@@ -1,10 +1,9 @@
#include <mbgl/text/glyph_atlas.hpp>
#include <mbgl/text/glyph_atlas_observer.hpp>
#include <mbgl/text/glyph_pbf.hpp>
-#include <mbgl/gl/gl.hpp>
#include <mbgl/gl/context.hpp>
-#include <mbgl/platform/log.hpp>
-#include <mbgl/platform/platform.hpp>
+#include <mbgl/util/logging.hpp>
+#include <mbgl/util/platform.hpp>
#include <cassert>
#include <algorithm>
@@ -13,13 +12,11 @@ namespace mbgl {
static GlyphAtlasObserver nullObserver;
-GlyphAtlas::GlyphAtlas(uint16_t width_, uint16_t height_, FileSource& fileSource_)
- : width(width_),
- height(height_),
- fileSource(fileSource_),
+GlyphAtlas::GlyphAtlas(const Size size, FileSource& fileSource_)
+ : fileSource(fileSource_),
observer(&nullObserver),
- bin(width_, height_),
- data(std::make_unique<uint8_t[]>(width_ * height_)),
+ bin(size.width, size.height),
+ image(size),
dirty(true) {
}
@@ -84,7 +81,7 @@ void GlyphAtlas::setObserver(GlyphAtlasObserver* observer_) {
}
void GlyphAtlas::addGlyphs(uintptr_t tileUID,
- const std::u32string& text,
+ const std::u16string& text,
const FontStack& fontStack,
const GlyphSet& glyphSet,
GlyphPositions& face)
@@ -93,7 +90,7 @@ void GlyphAtlas::addGlyphs(uintptr_t tileUID,
const std::map<uint32_t, SDFGlyph>& sdfs = glyphSet.getSDFs();
- for (uint32_t chr : text)
+ for (char16_t chr : text)
{
auto sdf_it = sdfs.find(chr);
if (sdf_it == sdfs.end()) {
@@ -148,18 +145,18 @@ Rect<uint16_t> GlyphAtlas::addGlyph(uintptr_t tileUID,
return rect;
}
- assert(rect.x + rect.w <= width);
- assert(rect.y + rect.h <= height);
+ assert(rect.x + rect.w <= image.size.width);
+ assert(rect.y + rect.h <= image.size.height);
face.emplace(glyph.id, GlyphValue { rect, tileUID });
// Copy the bitmap
const uint8_t* source = reinterpret_cast<const uint8_t*>(glyph.bitmap.data());
for (uint32_t y = 0; y < buffered_height; y++) {
- uint32_t y1 = width * (rect.y + y + padding) + rect.x + padding;
+ uint32_t y1 = image.size.width * (rect.y + y + padding) + rect.x + padding;
uint32_t y2 = buffered_width * y;
for (uint32_t x = 0; x < buffered_width; x++) {
- data[y1 + x] = source[y2 + x];
+ image.data[y1 + x] = source[y2 + x];
}
}
@@ -181,9 +178,9 @@ void GlyphAtlas::removeGlyphs(uintptr_t tileUID) {
const Rect<uint16_t>& rect = value.rect;
// Clear out the bitmap.
- uint8_t *target = data.get();
+ uint8_t *target = image.data.get();
for (uint32_t y = 0; y < rect.h; y++) {
- uint32_t y1 = width * (rect.y + y) + rect.x;
+ uint32_t y1 = image.size.width * (rect.y + y) + rect.x;
for (uint32_t x = 0; x < rect.w; x++) {
target[y1 + x] = 0;
}
@@ -203,60 +200,25 @@ void GlyphAtlas::removeGlyphs(uintptr_t tileUID) {
}
}
+Size GlyphAtlas::getSize() const {
+ return image.size;
+}
+
void GlyphAtlas::upload(gl::Context& context, gl::TextureUnit unit) {
- if (dirty) {
- const bool first = !texture;
- bind(context, unit);
-
- std::lock_guard<std::mutex> lock(mtx);
-
- context.activeTexture = unit;
- if (first) {
- MBGL_CHECK_ERROR(glTexImage2D(
- GL_TEXTURE_2D, // GLenum target
- 0, // GLint level
- GL_ALPHA, // GLint internalformat
- width, // GLsizei width
- height, // GLsizei height
- 0, // GLint border
- GL_ALPHA, // GLenum format
- GL_UNSIGNED_BYTE, // GLenum type
- data.get() // const GLvoid* data
- ));
- } else {
- MBGL_CHECK_ERROR(glTexSubImage2D(
- GL_TEXTURE_2D, // GLenum target
- 0, // GLint level
- 0, // GLint xoffset
- 0, // GLint yoffset
- width, // GLsizei width
- height, // GLsizei height
- GL_ALPHA, // GLenum format
- GL_UNSIGNED_BYTE, // GLenum type
- data.get() // const GLvoid* data
- ));
- }
+ std::lock_guard<std::mutex> lock(mtx);
- dirty = false;
+ if (!texture) {
+ texture = context.createTexture(image, unit);
+ } else if (dirty) {
+ context.updateTexture(*texture, image, unit);
}
+
+ dirty = false;
}
void GlyphAtlas::bind(gl::Context& context, gl::TextureUnit unit) {
- if (!texture) {
- texture = context.createTexture();
- context.activeTexture = unit;
- context.texture[unit] = *texture;
-#if not MBGL_USE_GLES2
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
-#endif
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
- } else if (context.texture[unit] != *texture) {
- context.activeTexture = unit;
- context.texture[unit] = *texture;
- }
+ upload(context, unit);
+ context.bindTexture(*texture, unit, gl::TextureFilter::Linear);
}
} // namespace mbgl
diff --git a/src/mbgl/text/glyph_atlas.hpp b/src/mbgl/text/glyph_atlas.hpp
index 84875bdd78..af14aace5b 100644
--- a/src/mbgl/text/glyph_atlas.hpp
+++ b/src/mbgl/text/glyph_atlas.hpp
@@ -8,6 +8,8 @@
#include <mbgl/util/font_stack.hpp>
#include <mbgl/util/exclusive.hpp>
#include <mbgl/util/work_queue.hpp>
+#include <mbgl/util/image.hpp>
+#include <mbgl/gl/texture.hpp>
#include <mbgl/gl/object.hpp>
#include <atomic>
@@ -30,7 +32,7 @@ class Context;
class GlyphAtlas : public util::noncopyable {
public:
- GlyphAtlas(uint16_t width, uint16_t height, FileSource&);
+ GlyphAtlas(Size, FileSource&);
~GlyphAtlas();
util::exclusive<GlyphSet> getGlyphSet(const FontStack&);
@@ -53,7 +55,7 @@ public:
void setObserver(GlyphAtlasObserver* observer);
void addGlyphs(uintptr_t tileUID,
- const std::u32string& text,
+ const std::u16string& text,
const FontStack&,
const GlyphSet&,
GlyphPositions&);
@@ -66,8 +68,7 @@ public:
// the texture is only bound when the data is out of date (=dirty).
void upload(gl::Context&, gl::TextureUnit unit);
- const uint16_t width;
- const uint16_t height;
+ Size getSize() const;
private:
void requestGlyphRange(const FontStack&, const GlyphRange&);
@@ -100,9 +101,9 @@ private:
std::mutex mtx;
BinPack<uint16_t> bin;
std::unordered_map<FontStack, std::map<uint32_t, GlyphValue>, FontStackHash> index;
- const std::unique_ptr<uint8_t[]> data;
+ const AlphaImage image;
std::atomic<bool> dirty;
- mbgl::optional<gl::UniqueTexture> texture;
+ mbgl::optional<gl::Texture> texture;
};
} // namespace mbgl
diff --git a/src/mbgl/text/glyph_set.cpp b/src/mbgl/text/glyph_set.cpp
index 0875a83850..f1cb85a03a 100644
--- a/src/mbgl/text/glyph_set.cpp
+++ b/src/mbgl/text/glyph_set.cpp
@@ -1,7 +1,11 @@
-#include <mbgl/text/glyph_set.hpp>
-#include <mbgl/platform/log.hpp>
#include <mbgl/math/minmax.hpp>
+#include <mbgl/text/glyph_set.hpp>
+#include <mbgl/util/i18n.hpp>
+#include <mbgl/util/logging.hpp>
+
+#include <boost/algorithm/string.hpp>
+#include <algorithm>
#include <cassert>
namespace mbgl {
@@ -26,44 +30,47 @@ void GlyphSet::insert(uint32_t id, SDFGlyph&& glyph) {
}
}
-const std::map<uint32_t, SDFGlyph> &GlyphSet::getSDFs() const {
+const std::map<uint32_t, SDFGlyph>& GlyphSet::getSDFs() const {
return sdfs;
}
-const Shaping GlyphSet::getShaping(const std::u32string &string, const float maxWidth,
- const float lineHeight, const float horizontalAlign,
- const float verticalAlign, const float justify,
- const float spacing, const Point<float> &translate) const {
- Shaping shaping(translate.x * 24, translate.y * 24, string);
+const Shaping GlyphSet::getShaping(const std::u16string& logicalInput,
+ const float maxWidth,
+ const float lineHeight,
+ const float horizontalAlign,
+ const float verticalAlign,
+ const float justify,
+ const float spacing,
+ const Point<float>& translate,
+ BiDi& bidi) const {
- // the y offset *should* be part of the font metadata
- const int32_t yOffset = -17;
+ // The string stored in shaping.text is used for finding duplicates, but may end up quite
+ // different from the glyphs that get shown
+ Shaping shaping(translate.x * 24, translate.y * 24, logicalInput);
- float x = 0;
- const float y = yOffset;
+ ProcessedBiDiText processedText = bidi.processText(logicalInput);
- // Loop through all characters of this label and shape.
- for (uint32_t chr : string) {
- auto it = sdfs.find(chr);
- if (it != sdfs.end()) {
- shaping.positionedGlyphs.emplace_back(chr, x, y);
- x += it->second.metrics.advance + spacing;
- }
- }
+ std::vector<std::u16string> reorderedLines =
+ processedText.applyLineBreaking(determineLineBreaks(logicalInput, spacing, maxWidth));
- if (shaping.positionedGlyphs.empty())
- return shaping;
-
- lineWrap(shaping, lineHeight, maxWidth, horizontalAlign, verticalAlign, justify, translate);
+ shapeLines(shaping, reorderedLines, spacing, lineHeight, horizontalAlign, verticalAlign,
+ justify, translate);
return shaping;
}
-void align(Shaping &shaping, const float justify, const float horizontalAlign,
- const float verticalAlign, const uint32_t maxLineLength, const float lineHeight,
- const uint32_t line, const Point<float> &translate) {
- const float shiftX = (justify - horizontalAlign) * maxLineLength + ::round(translate.x * 24/* one em */);
- const float shiftY = (-verticalAlign * (line + 1) + 0.5) * lineHeight + ::round(translate.y * 24/* one em */);
+void align(Shaping& shaping,
+ const float justify,
+ const float horizontalAlign,
+ const float verticalAlign,
+ const float maxLineLength,
+ const float lineHeight,
+ const uint32_t lineCount,
+ const Point<float>& translate) {
+ const float shiftX =
+ (justify - horizontalAlign) * maxLineLength + ::round(translate.x * 24 /* one em */);
+ const float shiftY =
+ (-verticalAlign * lineCount + 0.5) * lineHeight + ::round(translate.y * 24 /* one em */);
for (auto& glyph : shaping.positionedGlyphs) {
glyph.x += shiftX;
@@ -71,9 +78,16 @@ void align(Shaping &shaping, const float justify, const float horizontalAlign,
}
}
-void justifyLine(std::vector<PositionedGlyph> &positionedGlyphs, const std::map<uint32_t, SDFGlyph> &sdfs, uint32_t start,
- uint32_t end, float justify) {
- PositionedGlyph &glyph = positionedGlyphs[end];
+// justify left = 0, right = 1, center = .5
+void justifyLine(std::vector<PositionedGlyph>& positionedGlyphs,
+ const std::map<uint32_t, SDFGlyph>& sdfs,
+ uint32_t start,
+ uint32_t end,
+ float justify) {
+ if (!justify)
+ return;
+
+ PositionedGlyph& glyph = positionedGlyphs[end];
auto it = sdfs.find(glyph.glyph);
if (it != sdfs.end()) {
const uint32_t lastAdvance = it->second.metrics.advance;
@@ -85,80 +99,122 @@ void justifyLine(std::vector<PositionedGlyph> &positionedGlyphs, const std::map<
}
}
-void GlyphSet::lineWrap(Shaping &shaping, const float lineHeight, const float maxWidth,
- const float horizontalAlign, const float verticalAlign,
- const float justify, const Point<float> &translate) const {
+float GlyphSet::determineIdeographicLineWidth(const std::u16string& logicalInput,
+ const float spacing,
+ float maxWidth) const {
+ float totalWidth = 0;
+
+ // totalWidth doesn't include the last character for magical tuning reasons. This makes the
+ // algorithm a little
+ // more agressive about trying to fit the text into fewer lines, taking advantage of the
+ // tolerance for going a little
+ // over maxWidth
+ for (uint32_t i = 0; i < logicalInput.size() - 1; i++) {
+ auto it = sdfs.find(logicalInput[i]);
+ if (it != sdfs.end())
+ totalWidth += it->second.metrics.advance + spacing;
+ }
+
+ int32_t lineCount = std::fmax(1, std::ceil(totalWidth / maxWidth));
+ return totalWidth / lineCount;
+}
+
+// We determine line breaks based on shaped text in logical order. Working in visual order would be
+// more intuitive, but we can't do that because the visual order may be changed by line breaks!
+std::set<int32_t> GlyphSet::determineLineBreaks(const std::u16string& logicalInput,
+ const float spacing,
+ float maxWidth) const {
+ if (!maxWidth)
+ return {};
+
+ if (logicalInput.empty())
+ return {};
+
+ if (util::i18n::allowsIdeographicBreaking(logicalInput))
+ maxWidth = determineIdeographicLineWidth(logicalInput, spacing, maxWidth);
+
+ std::set<int32_t> lineBreakPoints;
+ float currentX = 0;
uint32_t lastSafeBreak = 0;
+ float lastSafeBreakX = 0;
+
+ for (uint32_t i = 0; i < logicalInput.size(); i++) {
+ auto it = sdfs.find(logicalInput[i]);
+ if (it == sdfs.end())
+ continue;
+
+ const SDFGlyph& glyph = it->second;
- uint32_t lengthBeforeCurrentLine = 0;
- uint32_t lineStartIndex = 0;
- uint32_t line = 0;
-
- uint32_t maxLineLength = 0;
-
- std::vector<PositionedGlyph> &positionedGlyphs = shaping.positionedGlyphs;
-
- if (maxWidth) {
- for (uint32_t i = 0; i < positionedGlyphs.size(); i++) {
- PositionedGlyph &shape = positionedGlyphs[i];
-
- shape.x -= lengthBeforeCurrentLine;
- shape.y += lineHeight * line;
-
- if (shape.x > maxWidth && lastSafeBreak > 0) {
-
- uint32_t lineLength = positionedGlyphs[lastSafeBreak + 1].x;
- maxLineLength = util::max(lineLength, maxLineLength);
-
- for (uint32_t k = lastSafeBreak + 1; k <= i; k++) {
- positionedGlyphs[k].y += lineHeight;
- positionedGlyphs[k].x -= lineLength;
- }
-
- if (justify) {
- // Collapse invisible characters.
- uint32_t breakGlyph = positionedGlyphs[lastSafeBreak].glyph;
- uint32_t lineEnd = lastSafeBreak;
- if (breakGlyph == 0x20 /* space */
- || breakGlyph == 0x200b /* zero-width space */) {
- lineEnd--;
- }
-
- justifyLine(positionedGlyphs, sdfs, lineStartIndex, lineEnd, justify);
- }
-
- lineStartIndex = lastSafeBreak + 1;
- lastSafeBreak = 0;
- lengthBeforeCurrentLine += lineLength;
- line++;
- }
-
- // Spaces, plus word-breaking punctuation that often appears without surrounding spaces.
- if (shape.glyph == 0x20 /* space */
- || shape.glyph == 0x26 /* ampersand */
- || shape.glyph == 0x2b /* plus sign */
- || shape.glyph == 0x2d /* hyphen-minus */
- || shape.glyph == 0x2f /* solidus */
- || shape.glyph == 0xad /* soft hyphen */
- || shape.glyph == 0xb7 /* middle dot */
- || shape.glyph == 0x200b /* zero-width space */
- || shape.glyph == 0x2010 /* hyphen */
- || shape.glyph == 0x2013 /* en dash */) {
- lastSafeBreak = i;
- }
+ // Ideographic characters, spaces, and word-breaking punctuation that often appear without
+ // surrounding spaces.
+ if (util::i18n::allowsWordBreaking(glyph.id) ||
+ util::i18n::allowsIdeographicBreaking(glyph.id)) {
+ lastSafeBreak = i;
+ lastSafeBreakX = currentX;
}
+
+ if (currentX > maxWidth && lastSafeBreak > 0) {
+ lineBreakPoints.insert(lastSafeBreak);
+ currentX -= lastSafeBreakX;
+ lastSafeBreakX = 0;
+ }
+
+ currentX += glyph.metrics.advance + spacing;
}
- const PositionedGlyph& lastPositionedGlyph = positionedGlyphs.back();
- const auto lastGlyphIt = sdfs.find(lastPositionedGlyph.glyph);
- assert(lastGlyphIt != sdfs.end());
- const uint32_t lastLineLength = lastPositionedGlyph.x + lastGlyphIt->second.metrics.advance;
- maxLineLength = std::max(maxLineLength, lastLineLength);
+ return lineBreakPoints;
+}
+
+void GlyphSet::shapeLines(Shaping& shaping,
+ const std::vector<std::u16string>& lines,
+ const float spacing,
+ const float lineHeight,
+ const float horizontalAlign,
+ const float verticalAlign,
+ const float justify,
+ const Point<float>& translate) const {
+
+ // the y offset *should* be part of the font metadata
+ const int32_t yOffset = -17;
+
+ float x = 0;
+ float y = yOffset;
+
+ float maxLineLength = 0;
- const uint32_t height = (line + 1) * lineHeight;
+ for (std::u16string line : lines) {
+ // Collapse whitespace so it doesn't throw off justification
+ boost::algorithm::trim_if(line, boost::algorithm::is_any_of(u" \t\n\v\f\r"));
+
+ if (line.empty())
+ continue;
+
+ uint32_t lineStartIndex = static_cast<uint32_t>(shaping.positionedGlyphs.size());
+ for (char16_t chr : line) {
+ auto it = sdfs.find(chr);
+ if (it == sdfs.end())
+ continue;
+
+ const SDFGlyph& glyph = it->second;
+ shaping.positionedGlyphs.emplace_back(chr, x, y);
+ x += glyph.metrics.advance + spacing;
+ }
+
+ if (static_cast<uint32_t>(shaping.positionedGlyphs.size()) == lineStartIndex)
+ continue;
+
+ maxLineLength = util::max(x, maxLineLength);
+
+ justifyLine(shaping.positionedGlyphs, sdfs, lineStartIndex,
+ static_cast<uint32_t>(shaping.positionedGlyphs.size()) - 1, justify);
+
+ x = 0;
+ y += lineHeight; // Move to next line
+ }
- justifyLine(positionedGlyphs, sdfs, lineStartIndex, uint32_t(positionedGlyphs.size()) - 1, justify);
- align(shaping, justify, horizontalAlign, verticalAlign, maxLineLength, lineHeight, line, translate);
+ align(shaping, justify, horizontalAlign, verticalAlign, maxLineLength, lineHeight,
+ static_cast<uint32_t>(lines.size()), translate);
+ const uint32_t height = lines.size() * lineHeight;
// Calculate the bounding box
shaping.top += -verticalAlign * height;
diff --git a/src/mbgl/text/glyph_set.hpp b/src/mbgl/text/glyph_set.hpp
index 37ffdb070a..b48973b6ea 100644
--- a/src/mbgl/text/glyph_set.hpp
+++ b/src/mbgl/text/glyph_set.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include <mbgl/text/bidi.hpp>
#include <mbgl/text/glyph.hpp>
#include <mbgl/util/geometry.hpp>
@@ -8,14 +9,34 @@ namespace mbgl {
class GlyphSet {
public:
void insert(uint32_t id, SDFGlyph&&);
- const std::map<uint32_t, SDFGlyph> &getSDFs() const;
- const Shaping getShaping(const std::u32string &string, float maxWidth, float lineHeight,
- float horizontalAlign, float verticalAlign, float justify,
- float spacing, const Point<float> &translate) const;
- void lineWrap(Shaping &shaping, float lineHeight, float maxWidth, float horizontalAlign,
- float verticalAlign, float justify, const Point<float> &translate) const;
+ const std::map<uint32_t, SDFGlyph>& getSDFs() const;
+ const Shaping getShaping(const std::u16string& string,
+ float maxWidth,
+ float lineHeight,
+ float horizontalAlign,
+ float verticalAlign,
+ float justify,
+ float spacing,
+ const Point<float>& translate,
+ BiDi& bidi) const;
private:
+ float determineIdeographicLineWidth(const std::u16string& logicalInput,
+ const float spacing,
+ float maxWidth) const;
+ std::set<int32_t> determineLineBreaks(const std::u16string& logicalInput,
+ const float spacing,
+ float maxWidth) const;
+
+ void shapeLines(Shaping& shaping,
+ const std::vector<std::u16string>& lines,
+ const float spacing,
+ float lineHeight,
+ float horizontalAlign,
+ float verticalAlign,
+ float justify,
+ const Point<float>& translate) const;
+
std::map<uint32_t, SDFGlyph> sdfs;
};
diff --git a/src/mbgl/text/quads.cpp b/src/mbgl/text/quads.cpp
index 3f142cd908..1a05e6f94f 100644
--- a/src/mbgl/text/quads.cpp
+++ b/src/mbgl/text/quads.cpp
@@ -14,7 +14,7 @@ using namespace style;
const float globalMinScale = 0.5f; // underscale by 1 zoom level
SymbolQuads getIconQuads(Anchor& anchor, const PositionedIcon& shapedIcon,
- const GeometryCoordinates& line, const SymbolLayoutProperties& layout,
+ const GeometryCoordinates& line, const SymbolLayoutProperties::Evaluated& layout,
const style::SymbolPlacementType placement, const Shaping& shapedText) {
auto image = *(shapedIcon.image);
@@ -29,24 +29,24 @@ SymbolQuads getIconQuads(Anchor& anchor, const PositionedIcon& shapedIcon,
Point<float> br;
Point<float> bl;
- if (layout.iconTextFit != IconTextFitType::None && shapedText) {
+ if (layout.get<IconTextFit>() != IconTextFitType::None && shapedText) {
auto iconWidth = right - left;
auto iconHeight = bottom - top;
- auto size = layout.textSize / 24.0f;
+ auto size = layout.get<TextSize>() / 24.0f;
auto textLeft = shapedText.left * size;
auto textRight = shapedText.right * size;
auto textTop = shapedText.top * size;
auto textBottom = shapedText.bottom * size;
auto textWidth = textRight - textLeft;
auto textHeight = textBottom - textTop;;
- auto padT = layout.iconTextFitPadding.value[0];
- auto padR = layout.iconTextFitPadding.value[1];
- auto padB = layout.iconTextFitPadding.value[2];
- auto padL = layout.iconTextFitPadding.value[3];
- auto offsetY = layout.iconTextFit == IconTextFitType::Width ? (textHeight - iconHeight) * 0.5 : 0;
- auto offsetX = layout.iconTextFit == IconTextFitType::Height ? (textWidth - iconWidth) * 0.5 : 0;
- auto width = layout.iconTextFit == IconTextFitType::Width || layout.iconTextFit == IconTextFitType::Both ? textWidth : iconWidth;
- auto height = layout.iconTextFit == IconTextFitType::Height || layout.iconTextFit == IconTextFitType::Both ? textHeight : iconHeight;
+ auto padT = layout.get<IconTextFitPadding>()[0];
+ auto padR = layout.get<IconTextFitPadding>()[1];
+ auto padB = layout.get<IconTextFitPadding>()[2];
+ auto padL = layout.get<IconTextFitPadding>()[3];
+ auto offsetY = layout.get<IconTextFit>() == IconTextFitType::Width ? (textHeight - iconHeight) * 0.5 : 0;
+ auto offsetX = layout.get<IconTextFit>() == IconTextFitType::Height ? (textWidth - iconWidth) * 0.5 : 0;
+ auto width = layout.get<IconTextFit>() == IconTextFitType::Width || layout.get<IconTextFit>() == IconTextFitType::Both ? textWidth : iconWidth;
+ auto height = layout.get<IconTextFit>() == IconTextFitType::Height || layout.get<IconTextFit>() == IconTextFitType::Both ? textHeight : iconHeight;
left = textLeft + offsetX - padL;
top = textTop + offsetY - padT;
right = textLeft + offsetX + padR + width;
@@ -62,7 +62,7 @@ SymbolQuads getIconQuads(Anchor& anchor, const PositionedIcon& shapedIcon,
bl = {left, bottom};
}
- float angle = layout.iconRotate * util::DEG2RAD;
+ float angle = layout.get<IconRotate>() * util::DEG2RAD;
if (placement == style::SymbolPlacementType::Line) {
assert(static_cast<unsigned int>(anchor.segment) < line.size());
const GeometryCoordinate &prev= line[anchor.segment];
@@ -165,11 +165,11 @@ void getSegmentGlyphs(std::back_insert_iterator<GlyphInstances> glyphs, Anchor &
}
SymbolQuads getGlyphQuads(Anchor& anchor, const Shaping& shapedText,
- const float boxScale, const GeometryCoordinates& line, const SymbolLayoutProperties& layout,
+ const float boxScale, const GeometryCoordinates& line, const SymbolLayoutProperties::Evaluated& layout,
const style::SymbolPlacementType placement, const GlyphPositions& face) {
- const float textRotate = layout.textRotate * util::DEG2RAD;
- const bool keepUpright = layout.textKeepUpright;
+ const float textRotate = layout.get<TextRotate>() * util::DEG2RAD;
+ const bool keepUpright = layout.get<TextKeepUpright>();
SymbolQuads quads;
diff --git a/src/mbgl/text/quads.hpp b/src/mbgl/text/quads.hpp
index d4edbf9493..75fb53aade 100644
--- a/src/mbgl/text/quads.hpp
+++ b/src/mbgl/text/quads.hpp
@@ -2,6 +2,7 @@
#include <mbgl/text/glyph.hpp>
#include <mbgl/style/types.hpp>
+#include <mbgl/style/layers/symbol_layer_properties.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <vector>
@@ -11,10 +12,6 @@ namespace mbgl {
struct Anchor;
class PositionedIcon;
-namespace style {
-class SymbolLayoutProperties;
-} // namespace style
-
struct SymbolQuad {
explicit SymbolQuad(Point<float> tl_, Point<float> tr_, Point<float> bl_, Point<float> br_,
Rect<uint16_t> tex_, float anchorAngle_, float glyphAngle_, Point<float> anchorPoint_,
@@ -40,11 +37,11 @@ struct SymbolQuad {
typedef std::vector<SymbolQuad> SymbolQuads;
SymbolQuads getIconQuads(Anchor& anchor, const PositionedIcon& shapedIcon,
- const GeometryCoordinates& line, const style::SymbolLayoutProperties&,
+ const GeometryCoordinates& line, const style::SymbolLayoutProperties::Evaluated&,
style::SymbolPlacementType placement, const Shaping& shapedText);
SymbolQuads getGlyphQuads(Anchor& anchor, const Shaping& shapedText,
- const float boxScale, const GeometryCoordinates& line, const style::SymbolLayoutProperties&,
+ const float boxScale, const GeometryCoordinates& line, const style::SymbolLayoutProperties::Evaluated&,
style::SymbolPlacementType placement, const GlyphPositions& face);
} // namespace mbgl
diff --git a/src/mbgl/text/shaping.cpp b/src/mbgl/text/shaping.cpp
index 1091cd6e94..062066aaf4 100644
--- a/src/mbgl/text/shaping.cpp
+++ b/src/mbgl/text/shaping.cpp
@@ -3,9 +3,11 @@
namespace mbgl {
-PositionedIcon shapeIcon(const SpriteAtlasElement& image, const style::SymbolLayoutProperties& layout) {
- float dx = layout.iconOffset.value[0];
- float dy = layout.iconOffset.value[1];
+using namespace style;
+
+PositionedIcon shapeIcon(const SpriteAtlasElement& image, const SymbolLayoutProperties::Evaluated& layout) {
+ float dx = layout.get<IconOffset>()[0];
+ float dy = layout.get<IconOffset>()[1];
float x1 = dx - image.spriteImage->getWidth() / 2.0f;
float x2 = x1 + image.spriteImage->getWidth();
float y1 = dy - image.spriteImage->getHeight() / 2.0f;
diff --git a/src/mbgl/text/shaping.hpp b/src/mbgl/text/shaping.hpp
index cd5e8105fd..30375179b6 100644
--- a/src/mbgl/text/shaping.hpp
+++ b/src/mbgl/text/shaping.hpp
@@ -3,15 +3,12 @@
#include <mbgl/text/glyph.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/sprite/sprite_image.hpp>
+#include <mbgl/style/layers/symbol_layer_properties.hpp>
#include <mbgl/util/optional.hpp>
namespace mbgl {
-struct SpriteAtlasElement;
-
-namespace style {
-class SymbolLayoutProperties;
-} // namespace style
+class SpriteAtlasElement;
class PositionedIcon {
public:
@@ -26,9 +23,9 @@ class PositionedIcon {
float left = 0;
float right = 0;
- operator bool() const { return image && (*image).pos.hasArea(); }
+ explicit operator bool() const { return image && (*image).pos.hasArea(); }
};
-PositionedIcon shapeIcon(const SpriteAtlasElement& image, const style::SymbolLayoutProperties&);
+PositionedIcon shapeIcon(const SpriteAtlasElement& image, const style::SymbolLayoutProperties::Evaluated&);
} // namespace mbgl
diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp
index 84455e4787..10c0e1b244 100644
--- a/src/mbgl/tile/geometry_tile.cpp
+++ b/src/mbgl/tile/geometry_tile.cpp
@@ -61,6 +61,12 @@ void GeometryTile::setPlacementConfig(const PlacementConfig& desiredConfig) {
return;
}
+ // Mark the tile as pending again if it was complete before to prevent signaling a complete
+ // state despite pending parse operations.
+ if (availableData == DataAvailability::All) {
+ availableData = DataAvailability::Some;
+ }
+
++correlationID;
requestedConfig = desiredConfig;
worker.invoke(&GeometryTileWorker::setPlacementConfig, desiredConfig, correlationID);
diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp
index abb3894d34..738c78572d 100644
--- a/src/mbgl/tile/geometry_tile_worker.cpp
+++ b/src/mbgl/tile/geometry_tile_worker.cpp
@@ -8,7 +8,7 @@
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <mbgl/renderer/symbol_bucket.hpp>
-#include <mbgl/platform/log.hpp>
+#include <mbgl/util/logging.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/exception.hpp>
diff --git a/src/mbgl/tile/tile.cpp b/src/mbgl/tile/tile.cpp
index 1375263107..e84eaaf780 100644
--- a/src/mbgl/tile/tile.cpp
+++ b/src/mbgl/tile/tile.cpp
@@ -2,7 +2,7 @@
#include <mbgl/tile/tile_observer.hpp>
#include <mbgl/renderer/debug_bucket.hpp>
#include <mbgl/util/string.hpp>
-#include <mbgl/platform/log.hpp>
+#include <mbgl/util/logging.hpp>
namespace mbgl {
diff --git a/src/mbgl/tile/tile.hpp b/src/mbgl/tile/tile.hpp
index eea89bd634..cebf913f56 100644
--- a/src/mbgl/tile/tile.hpp
+++ b/src/mbgl/tile/tile.hpp
@@ -75,9 +75,6 @@ public:
bool isComplete() const {
return availableData == DataAvailability::All;
}
- bool isIncomplete() const {
- return availableData == DataAvailability::Some;
- }
void dumpDebugLogs() const;
diff --git a/src/mbgl/util/default_styles.cpp b/src/mbgl/util/default_styles.cpp
deleted file mode 100644
index 17cc2f5740..0000000000
--- a/src/mbgl/util/default_styles.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-#include <mbgl/util/default_styles.hpp>
-
-namespace mbgl {
-namespace util {
-namespace default_styles {
-
-const DefaultStyle streets = { "mapbox://styles/mapbox/streets-v9", "Streets" };
-const DefaultStyle outdoors = { "mapbox://styles/mapbox/outdoors-v9", "Outdoors" };
-const DefaultStyle light = { "mapbox://styles/mapbox/light-v9", "Light" };
-const DefaultStyle dark = { "mapbox://styles/mapbox/dark-v9", "Dark" };
-const DefaultStyle satellite = { "mapbox://styles/mapbox/satellite-v9", "Satellite" };
-const DefaultStyle satelliteStreets = { "mapbox://styles/mapbox/satellite-streets-v9", "Satellite Streets" };
-
-} // namespace default_styles
-} // end namespace util
-} // end namespace mbgl
diff --git a/src/mbgl/platform/event.cpp b/src/mbgl/util/event.cpp
index 68d75a2941..3a3be20f5c 100644
--- a/src/mbgl/platform/event.cpp
+++ b/src/mbgl/util/event.cpp
@@ -1,4 +1,4 @@
-#include <mbgl/platform/event.hpp>
+#include <mbgl/util/event.hpp>
#include <mbgl/util/enum.hpp>
namespace mbgl {
diff --git a/src/mbgl/util/i18n.cpp b/src/mbgl/util/i18n.cpp
new file mode 100644
index 0000000000..4be624d2e5
--- /dev/null
+++ b/src/mbgl/util/i18n.cpp
@@ -0,0 +1,355 @@
+#include "i18n.hpp"
+
+namespace {
+
+/** Defines a function that returns true if a codepoint is in a named block.
+ @param name The name of the block in CamelCase.
+ @param first The first codepoint in the block, inclusive.
+ @param last The last codepoint in the block, inclusive.
+ */
+#define DEFINE_IS_IN_UNICODE_BLOCK(name, first, last) \
+ inline bool isIn##name(uint16_t codepoint) { \
+ return codepoint >= first && codepoint <= last; \
+ }
+
+// The following table comes from <http://www.unicode.org/Public/9.0.0/ucd/Blocks.txt>.
+// Keep it synchronized with <http://www.unicode.org/Public/UCD/latest/ucd/Blocks.txt>.
+
+// DEFINE_IS_IN_UNICODE_BLOCK(BasicLatin, 0x0000, 0x007F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Latin1Supplement, 0x0080, 0x00FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(LatinExtendedA, 0x0100, 0x017F)
+// DEFINE_IS_IN_UNICODE_BLOCK(LatinExtendedB, 0x0180, 0x024F)
+// DEFINE_IS_IN_UNICODE_BLOCK(IPAExtensions, 0x0250, 0x02AF)
+// DEFINE_IS_IN_UNICODE_BLOCK(SpacingModifierLetters, 0x02B0, 0x02FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(CombiningDiacriticalMarks, 0x0300, 0x036F)
+// DEFINE_IS_IN_UNICODE_BLOCK(GreekandCoptic, 0x0370, 0x03FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Cyrillic, 0x0400, 0x04FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(CyrillicSupplement, 0x0500, 0x052F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Armenian, 0x0530, 0x058F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Hebrew, 0x0590, 0x05FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Arabic, 0x0600, 0x06FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Syriac, 0x0700, 0x074F)
+// DEFINE_IS_IN_UNICODE_BLOCK(ArabicSupplement, 0x0750, 0x077F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Thaana, 0x0780, 0x07BF)
+// DEFINE_IS_IN_UNICODE_BLOCK(NKo, 0x07C0, 0x07FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Samaritan, 0x0800, 0x083F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Mandaic, 0x0840, 0x085F)
+// DEFINE_IS_IN_UNICODE_BLOCK(ArabicExtendedA, 0x08A0, 0x08FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Devanagari, 0x0900, 0x097F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Bengali, 0x0980, 0x09FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Gurmukhi, 0x0A00, 0x0A7F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Gujarati, 0x0A80, 0x0AFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Oriya, 0x0B00, 0x0B7F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Tamil, 0x0B80, 0x0BFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Telugu, 0x0C00, 0x0C7F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Kannada, 0x0C80, 0x0CFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Malayalam, 0x0D00, 0x0D7F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Sinhala, 0x0D80, 0x0DFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Thai, 0x0E00, 0x0E7F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Lao, 0x0E80, 0x0EFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Tibetan, 0x0F00, 0x0FFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Myanmar, 0x1000, 0x109F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Georgian, 0x10A0, 0x10FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(HangulJamo, 0x1100, 0x11FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Ethiopic, 0x1200, 0x137F)
+// DEFINE_IS_IN_UNICODE_BLOCK(EthiopicSupplement, 0x1380, 0x139F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Cherokee, 0x13A0, 0x13FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(UnifiedCanadianAboriginalSyllabics, 0x1400, 0x167F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Ogham, 0x1680, 0x169F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Runic, 0x16A0, 0x16FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Tagalog, 0x1700, 0x171F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Hanunoo, 0x1720, 0x173F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Buhid, 0x1740, 0x175F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Tagbanwa, 0x1760, 0x177F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Khmer, 0x1780, 0x17FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Mongolian, 0x1800, 0x18AF)
+// DEFINE_IS_IN_UNICODE_BLOCK(UnifiedCanadianAboriginalSyllabicsExtended, 0x18B0, 0x18FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Limbu, 0x1900, 0x194F)
+// DEFINE_IS_IN_UNICODE_BLOCK(TaiLe, 0x1950, 0x197F)
+// DEFINE_IS_IN_UNICODE_BLOCK(NewTaiLue, 0x1980, 0x19DF)
+// DEFINE_IS_IN_UNICODE_BLOCK(KhmerSymbols, 0x19E0, 0x19FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Buginese, 0x1A00, 0x1A1F)
+// DEFINE_IS_IN_UNICODE_BLOCK(TaiTham, 0x1A20, 0x1AAF)
+// DEFINE_IS_IN_UNICODE_BLOCK(CombiningDiacriticalMarksExtended, 0x1AB0, 0x1AFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Balinese, 0x1B00, 0x1B7F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Sundanese, 0x1B80, 0x1BBF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Batak, 0x1BC0, 0x1BFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Lepcha, 0x1C00, 0x1C4F)
+// DEFINE_IS_IN_UNICODE_BLOCK(OlChiki, 0x1C50, 0x1C7F)
+// DEFINE_IS_IN_UNICODE_BLOCK(CyrillicExtendedC, 0x1C80, 0x1C8F)
+// DEFINE_IS_IN_UNICODE_BLOCK(SundaneseSupplement, 0x1CC0, 0x1CCF)
+// DEFINE_IS_IN_UNICODE_BLOCK(VedicExtensions, 0x1CD0, 0x1CFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(PhoneticExtensions, 0x1D00, 0x1D7F)
+// DEFINE_IS_IN_UNICODE_BLOCK(PhoneticExtensionsSupplement, 0x1D80, 0x1DBF)
+// DEFINE_IS_IN_UNICODE_BLOCK(CombiningDiacriticalMarksSupplement, 0x1DC0, 0x1DFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(LatinExtendedAdditional, 0x1E00, 0x1EFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(GreekExtended, 0x1F00, 0x1FFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(GeneralPunctuation, 0x2000, 0x206F)
+// DEFINE_IS_IN_UNICODE_BLOCK(SuperscriptsandSubscripts, 0x2070, 0x209F)
+// DEFINE_IS_IN_UNICODE_BLOCK(CurrencySymbols, 0x20A0, 0x20CF)
+// DEFINE_IS_IN_UNICODE_BLOCK(CombiningDiacriticalMarksforSymbols, 0x20D0, 0x20FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(LetterlikeSymbols, 0x2100, 0x214F)
+// DEFINE_IS_IN_UNICODE_BLOCK(NumberForms, 0x2150, 0x218F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Arrows, 0x2190, 0x21FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(MathematicalOperators, 0x2200, 0x22FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(MiscellaneousTechnical, 0x2300, 0x23FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(ControlPictures, 0x2400, 0x243F)
+// DEFINE_IS_IN_UNICODE_BLOCK(OpticalCharacterRecognition, 0x2440, 0x245F)
+// DEFINE_IS_IN_UNICODE_BLOCK(EnclosedAlphanumerics, 0x2460, 0x24FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(BoxDrawing, 0x2500, 0x257F)
+// DEFINE_IS_IN_UNICODE_BLOCK(BlockElements, 0x2580, 0x259F)
+// DEFINE_IS_IN_UNICODE_BLOCK(GeometricShapes, 0x25A0, 0x25FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(MiscellaneousSymbols, 0x2600, 0x26FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Dingbats, 0x2700, 0x27BF)
+// DEFINE_IS_IN_UNICODE_BLOCK(MiscellaneousMathematicalSymbolsA, 0x27C0, 0x27EF)
+// DEFINE_IS_IN_UNICODE_BLOCK(SupplementalArrowsA, 0x27F0, 0x27FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(BraillePatterns, 0x2800, 0x28FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(SupplementalArrowsB, 0x2900, 0x297F)
+// DEFINE_IS_IN_UNICODE_BLOCK(MiscellaneousMathematicalSymbolsB, 0x2980, 0x29FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(SupplementalMathematicalOperators, 0x2A00, 0x2AFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(MiscellaneousSymbolsandArrows, 0x2B00, 0x2BFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Glagolitic, 0x2C00, 0x2C5F)
+// DEFINE_IS_IN_UNICODE_BLOCK(LatinExtendedC, 0x2C60, 0x2C7F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Coptic, 0x2C80, 0x2CFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(GeorgianSupplement, 0x2D00, 0x2D2F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Tifinagh, 0x2D30, 0x2D7F)
+// DEFINE_IS_IN_UNICODE_BLOCK(EthiopicExtended, 0x2D80, 0x2DDF)
+// DEFINE_IS_IN_UNICODE_BLOCK(CyrillicExtendedA, 0x2DE0, 0x2DFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(SupplementalPunctuation, 0x2E00, 0x2E7F)
+DEFINE_IS_IN_UNICODE_BLOCK(CJKRadicalsSupplement, 0x2E80, 0x2EFF)
+DEFINE_IS_IN_UNICODE_BLOCK(KangxiRadicals, 0x2F00, 0x2FDF)
+DEFINE_IS_IN_UNICODE_BLOCK(IdeographicDescriptionCharacters, 0x2FF0, 0x2FFF)
+DEFINE_IS_IN_UNICODE_BLOCK(CJKSymbolsandPunctuation, 0x3000, 0x303F)
+DEFINE_IS_IN_UNICODE_BLOCK(Hiragana, 0x3040, 0x309F)
+DEFINE_IS_IN_UNICODE_BLOCK(Katakana, 0x30A0, 0x30FF)
+DEFINE_IS_IN_UNICODE_BLOCK(Bopomofo, 0x3100, 0x312F)
+// DEFINE_IS_IN_UNICODE_BLOCK(HangulCompatibilityJamo, 0x3130, 0x318F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Kanbun, 0x3190, 0x319F)
+DEFINE_IS_IN_UNICODE_BLOCK(BopomofoExtended, 0x31A0, 0x31BF)
+DEFINE_IS_IN_UNICODE_BLOCK(CJKStrokes, 0x31C0, 0x31EF)
+DEFINE_IS_IN_UNICODE_BLOCK(KatakanaPhoneticExtensions, 0x31F0, 0x31FF)
+DEFINE_IS_IN_UNICODE_BLOCK(EnclosedCJKLettersandMonths, 0x3200, 0x32FF)
+DEFINE_IS_IN_UNICODE_BLOCK(CJKCompatibility, 0x3300, 0x33FF)
+DEFINE_IS_IN_UNICODE_BLOCK(CJKUnifiedIdeographsExtensionA, 0x3400, 0x4DBF)
+// DEFINE_IS_IN_UNICODE_BLOCK(YijingHexagramSymbols, 0x4DC0, 0x4DFF)
+DEFINE_IS_IN_UNICODE_BLOCK(CJKUnifiedIdeographs, 0x4E00, 0x9FFF)
+DEFINE_IS_IN_UNICODE_BLOCK(YiSyllables, 0xA000, 0xA48F)
+DEFINE_IS_IN_UNICODE_BLOCK(YiRadicals, 0xA490, 0xA4CF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Lisu, 0xA4D0, 0xA4FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Vai, 0xA500, 0xA63F)
+// DEFINE_IS_IN_UNICODE_BLOCK(CyrillicExtendedB, 0xA640, 0xA69F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Bamum, 0xA6A0, 0xA6FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(ModifierToneLetters, 0xA700, 0xA71F)
+// DEFINE_IS_IN_UNICODE_BLOCK(LatinExtendedD, 0xA720, 0xA7FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(SylotiNagri, 0xA800, 0xA82F)
+// DEFINE_IS_IN_UNICODE_BLOCK(CommonIndicNumberForms, 0xA830, 0xA83F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Phagspa, 0xA840, 0xA87F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Saurashtra, 0xA880, 0xA8DF)
+// DEFINE_IS_IN_UNICODE_BLOCK(DevanagariExtended, 0xA8E0, 0xA8FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(KayahLi, 0xA900, 0xA92F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Rejang, 0xA930, 0xA95F)
+// DEFINE_IS_IN_UNICODE_BLOCK(HangulJamoExtendedA, 0xA960, 0xA97F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Javanese, 0xA980, 0xA9DF)
+// DEFINE_IS_IN_UNICODE_BLOCK(MyanmarExtendedB, 0xA9E0, 0xA9FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Cham, 0xAA00, 0xAA5F)
+// DEFINE_IS_IN_UNICODE_BLOCK(MyanmarExtendedA, 0xAA60, 0xAA7F)
+// DEFINE_IS_IN_UNICODE_BLOCK(TaiViet, 0xAA80, 0xAADF)
+// DEFINE_IS_IN_UNICODE_BLOCK(MeeteiMayekExtensions, 0xAAE0, 0xAAFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(EthiopicExtendedA, 0xAB00, 0xAB2F)
+// DEFINE_IS_IN_UNICODE_BLOCK(LatinExtendedE, 0xAB30, 0xAB6F)
+// DEFINE_IS_IN_UNICODE_BLOCK(CherokeeSupplement, 0xAB70, 0xABBF)
+// DEFINE_IS_IN_UNICODE_BLOCK(MeeteiMayek, 0xABC0, 0xABFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(HangulSyllables, 0xAC00, 0xD7AF)
+// DEFINE_IS_IN_UNICODE_BLOCK(HangulJamoExtendedB, 0xD7B0, 0xD7FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(HighSurrogates, 0xD800, 0xDB7F)
+// DEFINE_IS_IN_UNICODE_BLOCK(HighPrivateUseSurrogates, 0xDB80, 0xDBFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(LowSurrogates, 0xDC00, 0xDFFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(PrivateUseArea, 0xE000, 0xF8FF)
+DEFINE_IS_IN_UNICODE_BLOCK(CJKCompatibilityIdeographs, 0xF900, 0xFAFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(AlphabeticPresentationForms, 0xFB00, 0xFB4F)
+// DEFINE_IS_IN_UNICODE_BLOCK(ArabicPresentationFormsA, 0xFB50, 0xFDFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(VariationSelectors, 0xFE00, 0xFE0F)
+DEFINE_IS_IN_UNICODE_BLOCK(VerticalForms, 0xFE10, 0xFE1F)
+// DEFINE_IS_IN_UNICODE_BLOCK(CombiningHalfMarks, 0xFE20, 0xFE2F)
+DEFINE_IS_IN_UNICODE_BLOCK(CJKCompatibilityForms, 0xFE30, 0xFE4F)
+// DEFINE_IS_IN_UNICODE_BLOCK(SmallFormVariants, 0xFE50, 0xFE6F)
+// DEFINE_IS_IN_UNICODE_BLOCK(ArabicPresentationFormsB, 0xFE70, 0xFEFF)
+DEFINE_IS_IN_UNICODE_BLOCK(HalfwidthandFullwidthForms, 0xFF00, 0xFFEF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Specials, 0xFFF0, 0xFFFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(LinearBSyllabary, 0x10000, 0x1007F)
+// DEFINE_IS_IN_UNICODE_BLOCK(LinearBIdeograms, 0x10080, 0x100FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(AegeanNumbers, 0x10100, 0x1013F)
+// DEFINE_IS_IN_UNICODE_BLOCK(AncientGreekNumbers, 0x10140, 0x1018F)
+// DEFINE_IS_IN_UNICODE_BLOCK(AncientSymbols, 0x10190, 0x101CF)
+// DEFINE_IS_IN_UNICODE_BLOCK(PhaistosDisc, 0x101D0, 0x101FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Lycian, 0x10280, 0x1029F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Carian, 0x102A0, 0x102DF)
+// DEFINE_IS_IN_UNICODE_BLOCK(CopticEpactNumbers, 0x102E0, 0x102FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(OldItalic, 0x10300, 0x1032F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Gothic, 0x10330, 0x1034F)
+// DEFINE_IS_IN_UNICODE_BLOCK(OldPermic, 0x10350, 0x1037F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Ugaritic, 0x10380, 0x1039F)
+// DEFINE_IS_IN_UNICODE_BLOCK(OldPersian, 0x103A0, 0x103DF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Deseret, 0x10400, 0x1044F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Shavian, 0x10450, 0x1047F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Osmanya, 0x10480, 0x104AF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Osage, 0x104B0, 0x104FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Elbasan, 0x10500, 0x1052F)
+// DEFINE_IS_IN_UNICODE_BLOCK(CaucasianAlbanian, 0x10530, 0x1056F)
+// DEFINE_IS_IN_UNICODE_BLOCK(LinearA, 0x10600, 0x1077F)
+// DEFINE_IS_IN_UNICODE_BLOCK(CypriotSyllabary, 0x10800, 0x1083F)
+// DEFINE_IS_IN_UNICODE_BLOCK(ImperialAramaic, 0x10840, 0x1085F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Palmyrene, 0x10860, 0x1087F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Nabataean, 0x10880, 0x108AF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Hatran, 0x108E0, 0x108FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Phoenician, 0x10900, 0x1091F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Lydian, 0x10920, 0x1093F)
+// DEFINE_IS_IN_UNICODE_BLOCK(MeroiticHieroglyphs, 0x10980, 0x1099F)
+// DEFINE_IS_IN_UNICODE_BLOCK(MeroiticCursive, 0x109A0, 0x109FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Kharoshthi, 0x10A00, 0x10A5F)
+// DEFINE_IS_IN_UNICODE_BLOCK(OldSouthArabian, 0x10A60, 0x10A7F)
+// DEFINE_IS_IN_UNICODE_BLOCK(OldNorthArabian, 0x10A80, 0x10A9F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Manichaean, 0x10AC0, 0x10AFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Avestan, 0x10B00, 0x10B3F)
+// DEFINE_IS_IN_UNICODE_BLOCK(InscriptionalParthian, 0x10B40, 0x10B5F)
+// DEFINE_IS_IN_UNICODE_BLOCK(InscriptionalPahlavi, 0x10B60, 0x10B7F)
+// DEFINE_IS_IN_UNICODE_BLOCK(PsalterPahlavi, 0x10B80, 0x10BAF)
+// DEFINE_IS_IN_UNICODE_BLOCK(OldTurkic, 0x10C00, 0x10C4F)
+// DEFINE_IS_IN_UNICODE_BLOCK(OldHungarian, 0x10C80, 0x10CFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(RumiNumeralSymbols, 0x10E60, 0x10E7F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Brahmi, 0x11000, 0x1107F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Kaithi, 0x11080, 0x110CF)
+// DEFINE_IS_IN_UNICODE_BLOCK(SoraSompeng, 0x110D0, 0x110FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Chakma, 0x11100, 0x1114F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Mahajani, 0x11150, 0x1117F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Sharada, 0x11180, 0x111DF)
+// DEFINE_IS_IN_UNICODE_BLOCK(SinhalaArchaicNumbers, 0x111E0, 0x111FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Khojki, 0x11200, 0x1124F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Multani, 0x11280, 0x112AF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Khudawadi, 0x112B0, 0x112FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Grantha, 0x11300, 0x1137F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Newa, 0x11400, 0x1147F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Tirhuta, 0x11480, 0x114DF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Siddham, 0x11580, 0x115FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Modi, 0x11600, 0x1165F)
+// DEFINE_IS_IN_UNICODE_BLOCK(MongolianSupplement, 0x11660, 0x1167F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Takri, 0x11680, 0x116CF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Ahom, 0x11700, 0x1173F)
+// DEFINE_IS_IN_UNICODE_BLOCK(WarangCiti, 0x118A0, 0x118FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(PauCinHau, 0x11AC0, 0x11AFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Bhaiksuki, 0x11C00, 0x11C6F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Marchen, 0x11C70, 0x11CBF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Cuneiform, 0x12000, 0x123FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(CuneiformNumbersandPunctuation, 0x12400, 0x1247F)
+// DEFINE_IS_IN_UNICODE_BLOCK(EarlyDynasticCuneiform, 0x12480, 0x1254F)
+// DEFINE_IS_IN_UNICODE_BLOCK(EgyptianHieroglyphs, 0x13000, 0x1342F)
+// DEFINE_IS_IN_UNICODE_BLOCK(AnatolianHieroglyphs, 0x14400, 0x1467F)
+// DEFINE_IS_IN_UNICODE_BLOCK(BamumSupplement, 0x16800, 0x16A3F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Mro, 0x16A40, 0x16A6F)
+// DEFINE_IS_IN_UNICODE_BLOCK(BassaVah, 0x16AD0, 0x16AFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(PahawhHmong, 0x16B00, 0x16B8F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Miao, 0x16F00, 0x16F9F)
+// DEFINE_IS_IN_UNICODE_BLOCK(IdeographicSymbolsandPunctuation, 0x16FE0, 0x16FFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Tangut, 0x17000, 0x187FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(TangutComponents, 0x18800, 0x18AFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(KanaSupplement, 0x1B000, 0x1B0FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Duployan, 0x1BC00, 0x1BC9F)
+// DEFINE_IS_IN_UNICODE_BLOCK(ShorthandFormatControls, 0x1BCA0, 0x1BCAF)
+// DEFINE_IS_IN_UNICODE_BLOCK(ByzantineMusicalSymbols, 0x1D000, 0x1D0FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(MusicalSymbols, 0x1D100, 0x1D1FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(AncientGreekMusicalNotation, 0x1D200, 0x1D24F)
+// DEFINE_IS_IN_UNICODE_BLOCK(TaiXuanJingSymbols, 0x1D300, 0x1D35F)
+// DEFINE_IS_IN_UNICODE_BLOCK(CountingRodNumerals, 0x1D360, 0x1D37F)
+// DEFINE_IS_IN_UNICODE_BLOCK(MathematicalAlphanumericSymbols, 0x1D400, 0x1D7FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(SuttonSignWriting, 0x1D800, 0x1DAAF)
+// DEFINE_IS_IN_UNICODE_BLOCK(GlagoliticSupplement, 0x1E000, 0x1E02F)
+// DEFINE_IS_IN_UNICODE_BLOCK(MendeKikakui, 0x1E800, 0x1E8DF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Adlam, 0x1E900, 0x1E95F)
+// DEFINE_IS_IN_UNICODE_BLOCK(ArabicMathematicalAlphabeticSymbols, 0x1EE00, 0x1EEFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(MahjongTiles, 0x1F000, 0x1F02F)
+// DEFINE_IS_IN_UNICODE_BLOCK(DominoTiles, 0x1F030, 0x1F09F)
+// DEFINE_IS_IN_UNICODE_BLOCK(PlayingCards, 0x1F0A0, 0x1F0FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(EnclosedAlphanumericSupplement, 0x1F100, 0x1F1FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(EnclosedIdeographicSupplement, 0x1F200, 0x1F2FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(MiscellaneousSymbolsandPictographs, 0x1F300, 0x1F5FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(Emoticons, 0x1F600, 0x1F64F)
+// DEFINE_IS_IN_UNICODE_BLOCK(OrnamentalDingbats, 0x1F650, 0x1F67F)
+// DEFINE_IS_IN_UNICODE_BLOCK(TransportandMapSymbols, 0x1F680, 0x1F6FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(AlchemicalSymbols, 0x1F700, 0x1F77F)
+// DEFINE_IS_IN_UNICODE_BLOCK(GeometricShapesExtended, 0x1F780, 0x1F7FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(SupplementalArrowsC, 0x1F800, 0x1F8FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(SupplementalSymbolsandPictographs, 0x1F900, 0x1F9FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(CJKUnifiedIdeographsExtensionB, 0x20000, 0x2A6DF)
+// DEFINE_IS_IN_UNICODE_BLOCK(CJKUnifiedIdeographsExtensionC, 0x2A700, 0x2B73F)
+// DEFINE_IS_IN_UNICODE_BLOCK(CJKUnifiedIdeographsExtensionD, 0x2B740, 0x2B81F)
+// DEFINE_IS_IN_UNICODE_BLOCK(CJKUnifiedIdeographsExtensionE, 0x2B820, 0x2CEAF)
+// DEFINE_IS_IN_UNICODE_BLOCK(CJKCompatibilityIdeographsSupplement, 0x2F800, 0x2FA1F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Tags, 0xE0000, 0xE007F)
+// DEFINE_IS_IN_UNICODE_BLOCK(VariationSelectorsSupplement, 0xE0100, 0xE01EF)
+// DEFINE_IS_IN_UNICODE_BLOCK(SupplementaryPrivateUseAreaA, 0xF0000, 0xFFFFF)
+// DEFINE_IS_IN_UNICODE_BLOCK(SupplementaryPrivateUseAreaB, 0x100000, 0x10FFFF)
+}
+
+namespace mbgl {
+namespace util {
+namespace i18n {
+
+bool allowsWordBreaking(uint16_t chr) {
+ return (chr == 0x0a /* newline */
+ || chr == 0x20 /* space */
+ || chr == 0x26 /* ampersand */
+ || chr == 0x2b /* plus sign */
+ || chr == 0x2d /* hyphen-minus */
+ || chr == 0x2f /* solidus */
+ || chr == 0xad /* soft hyphen */
+ || chr == 0xb7 /* middle dot */
+ || chr == 0x200b /* zero-width space */
+ || chr == 0x2010 /* hyphen */
+ || chr == 0x2013 /* en dash */);
+}
+
+bool allowsIdeographicBreaking(const std::u16string& string) {
+ for (uint16_t chr : string) {
+ if (!allowsIdeographicBreaking(chr)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool allowsIdeographicBreaking(uint16_t chr) {
+ // Allow U+2027 "Interpunct" for hyphenation of Chinese words
+ if (chr == 0x2027)
+ return true;
+
+ // Return early for characters outside all ideographic ranges.
+ if (chr < 0x2E80)
+ return false;
+
+ return (isInBopomofo(chr) || isInBopomofoExtended(chr) || isInCJKCompatibility(chr) ||
+ isInCJKCompatibilityForms(chr) || isInCJKCompatibilityIdeographs(chr) ||
+ isInCJKRadicalsSupplement(chr) || isInCJKStrokes(chr) ||
+ isInCJKSymbolsandPunctuation(chr) || isInCJKUnifiedIdeographs(chr) ||
+ isInCJKUnifiedIdeographsExtensionA(chr) || isInEnclosedCJKLettersandMonths(chr) ||
+ isInHalfwidthandFullwidthForms(chr) || isInHiragana(chr) ||
+ isInIdeographicDescriptionCharacters(chr) || isInKangxiRadicals(chr) ||
+ isInKatakana(chr) || isInKatakanaPhoneticExtensions(chr) || isInVerticalForms(chr) ||
+ isInYiRadicals(chr) || isInYiSyllables(chr));
+
+ // The following blocks also allow ideographic breaking; however, for other
+ // reasons, Mapbox GL lacks support for codepoints beyond U+FFFF.
+ // https://github.com/mapbox/mapbox-gl/issues/29
+ // return (isInTangut(chr)
+ // || isInTangutComponents(chr)
+ // || isInIdeographicSymbolsandPunctuation(chr)
+ // || isInEnclosedIdeographicSupplement(chr)
+ // || isInCJKUnifiedIdeographsExtensionB(chr)
+ // || isInCJKUnifiedIdeographsExtensionC(chr)
+ // || isInCJKUnifiedIdeographsExtensionD(chr)
+ // || isInCJKUnifiedIdeographsExtensionE(chr)
+ // || isInCJKCompatibilityIdeographsSupplement(chr));
+}
+
+} // namespace i18n
+} // namespace util
+} // namespace mbgl
diff --git a/src/mbgl/util/i18n.hpp b/src/mbgl/util/i18n.hpp
new file mode 100644
index 0000000000..f1d3f53f72
--- /dev/null
+++ b/src/mbgl/util/i18n.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <string>
+
+namespace mbgl {
+namespace util {
+namespace i18n {
+
+/** Returns whether a line break can be inserted after the character indicated
+ by the given Unicode codepoint due to word breaking. */
+bool allowsWordBreaking(uint16_t chr);
+
+/** Returns whether a line break can be inserted after any character in the
+ given string. If false, line breaking should occur on word boundaries
+ instead. */
+bool allowsIdeographicBreaking(const std::u16string& string);
+
+/** Returns whether a line break can be inserted after the character indicated
+ by the given Unicode codepoint due to ideographic breaking. */
+bool allowsIdeographicBreaking(uint16_t chr);
+
+} // namespace i18n
+} // namespace util
+} // namespace mbgl
diff --git a/src/mbgl/util/ignore.hpp b/src/mbgl/util/ignore.hpp
new file mode 100644
index 0000000000..955b1de2fa
--- /dev/null
+++ b/src/mbgl/util/ignore.hpp
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <initializer_list>
+
+namespace mbgl {
+namespace util {
+
+// Accept any number of parameters of any types, and do nothing with them.
+// Useful for providing a context for parameter pack expansion where a legal
+// expansion context is not otherwise available.
+//
+// See https://github.com/mapbox/cpp/blob/master/C%2B%2B%20Structural%20Metaprogramming.md
+// for more details.
+//
+template <class... Ts> void ignore(Ts&&...) {}
+
+// std::initializer_list overload, for situations where you need sequenced
+// modifications.
+//
+template <class T> void ignore(const std::initializer_list<T>&) {}
+
+} // namespace util
+} // namespace mbgl
diff --git a/src/mbgl/util/indexed_tuple.hpp b/src/mbgl/util/indexed_tuple.hpp
new file mode 100644
index 0000000000..110e7dce12
--- /dev/null
+++ b/src/mbgl/util/indexed_tuple.hpp
@@ -0,0 +1,47 @@
+#pragma once
+
+#include <type_traits>
+#include <tuple>
+
+namespace mbgl {
+
+template <class T, class... Ts>
+struct TypeIndex;
+
+template <class T, class... Ts>
+struct TypeIndex<T, T, Ts...> : std::integral_constant<std::size_t, 0> {};
+
+template <class T, class U, class... Ts>
+struct TypeIndex<T, U, Ts...> : std::integral_constant<std::size_t, 1 + TypeIndex<T, Ts...>::value> {};
+
+template <class...> class TypeList {};
+
+template <class...> class IndexedTuple;
+
+// A tuple of Ts, where individual members can be accessed via `t.get<I>()` for I ∈ Is.
+//
+// See https://github.com/mapbox/cpp/blob/master/C%2B%2B%20Structural%20Metaprogramming.md
+// for motivation.
+//
+template <class... Is, class... Ts>
+class IndexedTuple<TypeList<Is...>, TypeList<Ts...>> : public std::tuple<Ts...> {
+public:
+ static_assert(sizeof...(Is) == sizeof...(Ts), "IndexedTuple size mismatch");
+
+ using std::tuple<Ts...>::tuple;
+
+ template <class I>
+ static constexpr std::size_t Index = TypeIndex<I, Is...>::value;
+
+ template <class I>
+ auto& get() {
+ return std::get<Index<I>>(*this);
+ }
+
+ template <class I>
+ const auto& get() const {
+ return std::get<Index<I>>(*this);
+ }
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/platform/log.cpp b/src/mbgl/util/logging.cpp
index b140485dd6..939f1def64 100644
--- a/src/mbgl/platform/log.cpp
+++ b/src/mbgl/util/logging.cpp
@@ -1,4 +1,4 @@
-#include <mbgl/platform/log.hpp>
+#include <mbgl/util/logging.hpp>
#include <mbgl/util/enum.hpp>
#include <mbgl/util/thread.hpp>
diff --git a/src/mbgl/util/mapbox.cpp b/src/mbgl/util/mapbox.cpp
index 9cf250f7a3..839924d77c 100644
--- a/src/mbgl/util/mapbox.cpp
+++ b/src/mbgl/util/mapbox.cpp
@@ -1,11 +1,10 @@
#include <mbgl/util/mapbox.hpp>
#include <mbgl/util/constants.hpp>
-#include <mbgl/platform/log.hpp>
+#include <mbgl/util/logging.hpp>
#include <stdexcept>
#include <vector>
#include <iostream>
-#include <regex>
namespace {
@@ -192,14 +191,22 @@ std::string canonicalizeTileURL(const std::string& url, SourceType type, uint16_
}
result += "." + extension;
-
+
// get the query and remove access_token, if more parameters exist, add them to the final result
if (queryIdx != url.length()) {
- const auto query = url.substr(queryIdx + 1);
- std::regex re ("&?access_token=([^&]*)");
- std::string replace = std::regex_replace(query, re, "");
- std::string subQuery = (replace.find("&") == 0) ? replace.substr(1, replace.length()) : replace;
- if (subQuery.length() > 0) result += "?" + subQuery;
+ auto idx = queryIdx;
+ bool hasQuery = false;
+ while (idx != std::string::npos) {
+ idx++; // skip & or ?
+ auto ampersandIdx = url.find("&", idx);
+ if (url.substr(idx, 13) != "access_token=") {
+ result += hasQuery ? "&" : "?";
+ result += url.substr(idx, ampersandIdx != std::string::npos ? ampersandIdx - idx
+ : std::string::npos);
+ hasQuery = true;
+ }
+ idx = ampersandIdx;
+ }
}
return result;
diff --git a/src/mbgl/util/math.hpp b/src/mbgl/util/math.hpp
index 5d4220d0a2..f969ecaedd 100644
--- a/src/mbgl/util/math.hpp
+++ b/src/mbgl/util/math.hpp
@@ -106,11 +106,5 @@ T smoothstep(T edge0, T edge1, T x) {
return t * t * (T(3) - T(2) * t);
}
-// Computes the log2(x) rounded up to the next integer.
-// (== number of bits required to store x)
-uint32_t ceil_log2(uint64_t x);
-
-double log2(double x);
-
} // namespace util
} // namespace mbgl
diff --git a/src/mbgl/util/offscreen_texture.cpp b/src/mbgl/util/offscreen_texture.cpp
index 40bb70b70e..aad20e59d3 100644
--- a/src/mbgl/util/offscreen_texture.cpp
+++ b/src/mbgl/util/offscreen_texture.cpp
@@ -1,15 +1,14 @@
#include <mbgl/util/offscreen_texture.hpp>
#include <mbgl/gl/context.hpp>
-#include <mbgl/gl/gl.hpp>
#include <cstring>
#include <cassert>
namespace mbgl {
-OffscreenTexture::OffscreenTexture(gl::Context& context_, std::array<uint16_t, 2> size_)
- : context(context_), size(std::move(size_)) {
- assert(size[0] > 0 && size[1] > 0);
+OffscreenTexture::OffscreenTexture(gl::Context& context_, const Size size_)
+ : size(std::move(size_)), context(context_) {
+ assert(size);
}
void OffscreenTexture::bind() {
@@ -20,7 +19,7 @@ void OffscreenTexture::bind() {
context.bindFramebuffer = framebuffer->framebuffer;
}
- context.viewport = { 0, 0, size[0], size[1] };
+ context.viewport = { 0, 0, size };
}
gl::Texture& OffscreenTexture::getTexture() {
@@ -29,19 +28,7 @@ gl::Texture& OffscreenTexture::getTexture() {
}
PremultipliedImage OffscreenTexture::readStillImage() {
- PremultipliedImage image { size[0], size[1] };
- MBGL_CHECK_ERROR(glReadPixels(0, 0, size[0], size[1], GL_RGBA, GL_UNSIGNED_BYTE, image.data.get()));
-
- const auto stride = image.stride();
- auto tmp = std::make_unique<uint8_t[]>(stride);
- uint8_t* rgba = image.data.get();
- for (int i = 0, j = size[1] - 1; i < j; i++, j--) {
- std::memcpy(tmp.get(), rgba + i * stride, stride);
- std::memcpy(rgba + i * stride, rgba + j * stride, stride);
- std::memcpy(rgba + j * stride, tmp.get(), stride);
- }
-
- return image;
+ return context.readFramebuffer<PremultipliedImage>(size);
}
diff --git a/src/mbgl/util/offscreen_texture.hpp b/src/mbgl/util/offscreen_texture.hpp
index 8928bc2434..64eb7bc565 100644
--- a/src/mbgl/util/offscreen_texture.hpp
+++ b/src/mbgl/util/offscreen_texture.hpp
@@ -14,7 +14,7 @@ class Context;
class OffscreenTexture : public View {
public:
- OffscreenTexture(gl::Context&, std::array<uint16_t, 2> size = {{ 256, 256 }});
+ OffscreenTexture(gl::Context&, Size size = { 256, 256 });
void bind() override;
@@ -22,9 +22,11 @@ public:
gl::Texture& getTexture();
+public:
+ const Size size;
+
private:
gl::Context& context;
- std::array<uint16_t, 2> size;
optional<gl::Framebuffer> framebuffer;
optional<gl::Texture> texture;
};
diff --git a/src/mbgl/util/premultiply.cpp b/src/mbgl/util/premultiply.cpp
index e0178fda33..219273d7cc 100644
--- a/src/mbgl/util/premultiply.cpp
+++ b/src/mbgl/util/premultiply.cpp
@@ -8,12 +8,11 @@ namespace util {
PremultipliedImage premultiply(UnassociatedImage&& src) {
PremultipliedImage dst;
- dst.width = src.width;
- dst.height = src.height;
+ dst.size = src.size;
dst.data = std::move(src.data);
uint8_t* data = dst.data.get();
- for (size_t i = 0; i < dst.size(); i += 4) {
+ for (size_t i = 0; i < dst.bytes(); i += 4) {
uint8_t& r = data[i + 0];
uint8_t& g = data[i + 1];
uint8_t& b = data[i + 2];
@@ -29,12 +28,11 @@ PremultipliedImage premultiply(UnassociatedImage&& src) {
UnassociatedImage unpremultiply(PremultipliedImage&& src) {
UnassociatedImage dst;
- dst.width = src.width;
- dst.height = src.height;
+ dst.size = src.size;
dst.data = std::move(src.data);
uint8_t* data = dst.data.get();
- for (size_t i = 0; i < dst.size(); i += 4) {
+ for (size_t i = 0; i < dst.bytes(); i += 4) {
uint8_t& r = data[i + 0];
uint8_t& g = data[i + 1];
uint8_t& b = data[i + 2];
diff --git a/src/mbgl/util/stopwatch.cpp b/src/mbgl/util/stopwatch.cpp
index d588b79254..3883d8535f 100644
--- a/src/mbgl/util/stopwatch.cpp
+++ b/src/mbgl/util/stopwatch.cpp
@@ -2,7 +2,7 @@
#include <mbgl/util/stopwatch.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/chrono.hpp>
-#include <mbgl/platform/log.hpp>
+#include <mbgl/util/logging.hpp>
#include <iostream>
#include <atomic>
diff --git a/src/mbgl/util/stopwatch.hpp b/src/mbgl/util/stopwatch.hpp
index 74cc2c412d..6214dae958 100644
--- a/src/mbgl/util/stopwatch.hpp
+++ b/src/mbgl/util/stopwatch.hpp
@@ -1,6 +1,6 @@
#pragma once
-#include <mbgl/platform/event.hpp>
+#include <mbgl/util/event.hpp>
#include <mbgl/util/chrono.hpp>
#include <string>
diff --git a/src/mbgl/util/thread.hpp b/src/mbgl/util/thread.hpp
index 91eef745fa..8cfef8a764 100644
--- a/src/mbgl/util/thread.hpp
+++ b/src/mbgl/util/thread.hpp
@@ -8,7 +8,7 @@
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/thread_context.hpp>
-#include <mbgl/platform/platform.hpp>
+#include <mbgl/util/platform.hpp>
#include <pthread.h>
diff --git a/src/mbgl/util/tile_cover.cpp b/src/mbgl/util/tile_cover.cpp
index c6bf7d362a..2fb7371aba 100644
--- a/src/mbgl/util/tile_cover.cpp
+++ b/src/mbgl/util/tile_cover.cpp
@@ -157,8 +157,8 @@ std::vector<UnwrappedTileID> tileCover(const LatLngBounds& bounds_, int32_t z) {
}
std::vector<UnwrappedTileID> tileCover(const TransformState& state, int32_t z) {
- const double w = state.getWidth();
- const double h = state.getHeight();
+ const double w = state.getSize().width;
+ const double h = state.getSize().height;
return tileCover(
TileCoordinate::fromScreenCoordinate(state, z, { 0, 0 }).p,
TileCoordinate::fromScreenCoordinate(state, z, { w, 0 }).p,
diff --git a/src/mbgl/util/url.cpp b/src/mbgl/util/url.cpp
index bf6fc70ff5..9831bc9038 100644
--- a/src/mbgl/util/url.cpp
+++ b/src/mbgl/util/url.cpp
@@ -1,12 +1,30 @@
#include <mbgl/util/url.hpp>
-#include <cctype>
#include <iomanip>
#include <sstream>
#include <string>
#include <cstdlib>
#include <algorithm>
+
+namespace {
+
+// std::alnum etc. suffer from locale-dependence.
+
+inline bool isAlphaCharacter(char c) {
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+}
+
+inline bool isAlphaNumericCharacter(char c) {
+ return isAlphaCharacter(c) || (c >= '0' && c <= '9');
+}
+
+inline bool isSchemeCharacter(char c) {
+ return isAlphaNumericCharacter(c) || c == '-' || c == '+' || c == '.';
+}
+
+} // namespace
+
namespace mbgl {
namespace util {
@@ -17,7 +35,7 @@ std::string percentEncode(const std::string& input) {
encoded << std::hex;
for (auto c : input) {
- if (std::isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
+ if (isAlphaNumericCharacter(c) || c == '-' || c == '_' || c == '.' || c == '~') {
encoded << c;
} else {
encoded << '%' << std::setw(2) << int(c);
@@ -47,5 +65,18 @@ std::string percentDecode(const std::string& input) {
return decoded;
}
+// Checks whether the input string contains ://, and the part before it is all alphanumeric ASCII.
+bool isURL(const std::string& input) {
+ auto it = input.begin();
+ // First character has to be alphabetic
+ if (it == input.end() || !isAlphaCharacter(*it++)) return false;
+ // The remaining characters of the scheme can be alphanumeric, or be one of +.-
+ while (it != input.end() && isSchemeCharacter(*it)) ++it;
+ // Check that :// follows
+ return (it != input.end() && *it++ == ':') &&
+ (it != input.end() && *it++ == '/') &&
+ (it != input.end() && *it++ == '/');
+}
+
} // namespace util
} // namespace mbgl
diff --git a/src/mbgl/util/url.hpp b/src/mbgl/util/url.hpp
index b9c66261df..2d18f7476a 100644
--- a/src/mbgl/util/url.hpp
+++ b/src/mbgl/util/url.hpp
@@ -8,6 +8,7 @@ namespace util {
std::string percentEncode(const std::string&);
std::string percentDecode(const std::string&);
+bool isURL(const std::string&);
} // namespace util
} // namespace mbgl
diff --git a/src/mbgl/util/utf.hpp b/src/mbgl/util/utf.hpp
index 560ca3ba7f..81330cfc83 100644
--- a/src/mbgl/util/utf.hpp
+++ b/src/mbgl/util/utf.hpp
@@ -2,18 +2,17 @@
#include <memory>
-#include <boost/regex/pending/unicode_iterator.hpp>
+#include <locale>
+#include <codecvt>
namespace mbgl {
namespace util {
-class utf8_to_utf32 {
- public:
- static std::u32string convert(std::string const& utf8)
- {
- boost::u8_to_u32_iterator<std::string::const_iterator> begin(utf8.begin());
- boost::u8_to_u32_iterator<std::string::const_iterator> end(utf8.end());
- return std::u32string(begin,end);
+class utf8_to_utf16 {
+public:
+ static std::u16string convert(std::string const& utf8) {
+ std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter;
+ return converter.from_bytes(utf8);
}
};