summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorm-stephen <truestyle2005@163.com>2019-09-17 10:46:33 +0800
committerGitHub <noreply@github.com>2019-09-17 10:46:33 +0800
commiteb1f8eb32286dd7b89ae76b839b774b0071ca5a5 (patch)
tree0db6df1811ffb8c9a5139687817386dee23cfef1 /src
parentb0018568b84f9bb1c185f0441a41741e9fde5a84 (diff)
parenta99240a54ffd5eb77568d41e10186411b1b759eb (diff)
downloadqtlocation-mapboxgl-eb1f8eb32286dd7b89ae76b839b774b0071ca5a5.tar.gz
Merge branch 'master' into stephen-ios-error-report
Diffstat (limited to 'src')
-rw-r--r--src/core-files.json2
-rw-r--r--src/mbgl/annotation/annotation_source.hpp7
-rw-r--r--src/mbgl/geometry/dem_data.cpp70
-rw-r--r--src/mbgl/geometry/dem_data.hpp28
-rw-r--r--src/mbgl/layout/symbol_instance.cpp47
-rw-r--r--src/mbgl/layout/symbol_instance.hpp29
-rw-r--r--src/mbgl/layout/symbol_layout.cpp228
-rw-r--r--src/mbgl/layout/symbol_layout.hpp18
-rw-r--r--src/mbgl/map/map.cpp2
-rw-r--r--src/mbgl/map/map_impl.cpp4
-rw-r--r--src/mbgl/map/map_impl.hpp2
-rw-r--r--src/mbgl/map/transform.cpp11
-rw-r--r--src/mbgl/map/transform.hpp2
-rw-r--r--src/mbgl/map/transform_state.cpp17
-rw-r--r--src/mbgl/map/transform_state.hpp5
-rw-r--r--src/mbgl/programs/gl/hillshade.cpp4
-rw-r--r--src/mbgl/programs/gl/hillshade_prepare.cpp6
-rw-r--r--src/mbgl/programs/gl/line.cpp4
-rw-r--r--src/mbgl/programs/gl/line_gradient.cpp4
-rw-r--r--src/mbgl/programs/gl/line_pattern.cpp4
-rw-r--r--src/mbgl/programs/gl/line_sdf.cpp4
-rw-r--r--src/mbgl/programs/gl/raster.cpp4
-rw-r--r--src/mbgl/programs/gl/shader_source.cpp895
-rw-r--r--src/mbgl/programs/gl/symbol_icon.cpp4
-rw-r--r--src/mbgl/programs/gl/symbol_sdf_icon.cpp4
-rw-r--r--src/mbgl/programs/gl/symbol_sdf_text.cpp4
-rw-r--r--src/mbgl/programs/hillshade_prepare_program.hpp4
-rw-r--r--src/mbgl/programs/program_parameters.cpp22
-rw-r--r--src/mbgl/programs/program_parameters.hpp4
-rw-r--r--src/mbgl/programs/symbol_program.cpp2
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.cpp101
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.hpp47
-rw-r--r--src/mbgl/renderer/image_manager.cpp1
-rw-r--r--src/mbgl/renderer/layers/render_background_layer.cpp5
-rw-r--r--src/mbgl/renderer/layers/render_circle_layer.cpp5
-rw-r--r--src/mbgl/renderer/layers/render_custom_layer.cpp5
-rw-r--r--src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp5
-rw-r--r--src/mbgl/renderer/layers/render_fill_layer.cpp5
-rw-r--r--src/mbgl/renderer/layers/render_heatmap_layer.cpp5
-rw-r--r--src/mbgl/renderer/layers/render_hillshade_layer.cpp6
-rw-r--r--src/mbgl/renderer/layers/render_line_layer.cpp5
-rw-r--r--src/mbgl/renderer/layers/render_raster_layer.cpp5
-rw-r--r--src/mbgl/renderer/layers/render_symbol_layer.cpp181
-rw-r--r--src/mbgl/renderer/layers/render_symbol_layer.hpp6
-rw-r--r--src/mbgl/renderer/render_layer.cpp2
-rw-r--r--src/mbgl/renderer/render_orchestrator.cpp29
-rw-r--r--src/mbgl/renderer/render_pass.hpp15
-rw-r--r--src/mbgl/renderer/render_static_data.cpp6
-rw-r--r--src/mbgl/renderer/render_static_data.hpp2
-rw-r--r--src/mbgl/renderer/render_tree.hpp1
-rw-r--r--src/mbgl/renderer/renderer.cpp2
-rw-r--r--src/mbgl/renderer/renderer_impl.cpp9
-rw-r--r--src/mbgl/renderer/renderer_impl.hpp2
-rw-r--r--src/mbgl/renderer/sources/render_geojson_source.cpp2
-rw-r--r--src/mbgl/renderer/tile_pyramid.cpp6
-rw-r--r--src/mbgl/style/conversion/geojson_options.cpp69
-rw-r--r--src/mbgl/style/expression/compound_expression.cpp13
-rw-r--r--src/mbgl/style/expression/dsl.cpp23
-rw-r--r--src/mbgl/style/expression/expression.cpp8
-rw-r--r--src/mbgl/style/expression/parsing_context.cpp3
-rw-r--r--src/mbgl/style/layers/background_layer.cpp15
-rw-r--r--src/mbgl/style/layers/circle_layer.cpp47
-rw-r--r--src/mbgl/style/layers/fill_extrusion_layer.cpp35
-rw-r--r--src/mbgl/style/layers/fill_layer.cpp31
-rw-r--r--src/mbgl/style/layers/fill_layer_impl.cpp1
-rw-r--r--src/mbgl/style/layers/heatmap_layer.cpp23
-rw-r--r--src/mbgl/style/layers/hillshade_layer.cpp27
-rw-r--r--src/mbgl/style/layers/layer.cpp.ejs9
-rw-r--r--src/mbgl/style/layers/line_layer.cpp55
-rw-r--r--src/mbgl/style/layers/raster_layer.cpp35
-rw-r--r--src/mbgl/style/layers/symbol_layer.cpp141
-rw-r--r--src/mbgl/style/light.cpp120
-rw-r--r--src/mbgl/style/light.cpp.ejs78
-rw-r--r--src/mbgl/style/sources/custom_geometry_source.cpp2
-rw-r--r--src/mbgl/style/sources/geojson_source.cpp2
-rw-r--r--src/mbgl/style/sources/geojson_source_impl.cpp69
-rw-r--r--src/mbgl/style/sources/geojson_source_impl.hpp2
-rw-r--r--src/mbgl/style/sources/raster_source.cpp1
-rw-r--r--src/mbgl/style/sources/vector_source.cpp1
-rw-r--r--src/mbgl/style/style_impl.cpp5
-rw-r--r--src/mbgl/text/cross_tile_symbol_index.cpp19
-rw-r--r--src/mbgl/text/cross_tile_symbol_index.hpp9
-rw-r--r--src/mbgl/text/glyph.hpp21
-rw-r--r--src/mbgl/text/glyph_manager.cpp7
-rw-r--r--src/mbgl/text/placement.cpp304
-rw-r--r--src/mbgl/text/placement.hpp13
-rw-r--r--src/mbgl/text/quads.cpp48
-rw-r--r--src/mbgl/text/quads.hpp4
-rw-r--r--src/mbgl/text/shaping.cpp49
-rw-r--r--src/mbgl/text/shaping.hpp9
-rw-r--r--src/mbgl/tile/geojson_tile.cpp4
-rw-r--r--src/mbgl/tile/geojson_tile.hpp2
-rw-r--r--src/mbgl/tile/geometry_tile.cpp4
-rw-r--r--src/mbgl/tile/geometry_tile.hpp2
-rw-r--r--src/mbgl/tile/geometry_tile_data.cpp5
-rw-r--r--src/mbgl/tile/geometry_tile_worker.cpp3
-rw-r--r--src/mbgl/tile/geometry_tile_worker.hpp2
-rw-r--r--src/mbgl/util/chrono.cpp9
-rw-r--r--src/mbgl/util/tile_coordinate.hpp5
-rw-r--r--src/mbgl/util/tile_cover.cpp12
-rw-r--r--src/mbgl/util/tile_cover.hpp10
101 files changed, 1994 insertions, 1261 deletions
diff --git a/src/core-files.json b/src/core-files.json
index f2da5a3d05..9453e504bb 100644
--- a/src/core-files.json
+++ b/src/core-files.json
@@ -456,6 +456,7 @@
"mbgl/tile/tile_necessity.hpp": "include/mbgl/tile/tile_necessity.hpp",
"mbgl/util/async_request.hpp": "include/mbgl/util/async_request.hpp",
"mbgl/util/async_task.hpp": "include/mbgl/util/async_task.hpp",
+ "mbgl/util/bitmask_operations.hpp": "include/mbgl/util/bitmask_operations.hpp",
"mbgl/util/char_array_buffer.hpp": "include/mbgl/util/char_array_buffer.hpp",
"mbgl/util/chrono.hpp": "include/mbgl/util/chrono.hpp",
"mbgl/util/color.hpp": "include/mbgl/util/color.hpp",
@@ -479,7 +480,6 @@
"mbgl/util/logging.hpp": "include/mbgl/util/logging.hpp",
"mbgl/util/noncopyable.hpp": "include/mbgl/util/noncopyable.hpp",
"mbgl/util/optional.hpp": "include/mbgl/util/optional.hpp",
- "mbgl/util/peer.hpp": "include/mbgl/util/peer.hpp",
"mbgl/util/platform.hpp": "include/mbgl/util/platform.hpp",
"mbgl/util/premultiply.hpp": "include/mbgl/util/premultiply.hpp",
"mbgl/util/projection.hpp": "include/mbgl/util/projection.hpp",
diff --git a/src/mbgl/annotation/annotation_source.hpp b/src/mbgl/annotation/annotation_source.hpp
index 0728f3207e..018e2136ea 100644
--- a/src/mbgl/annotation/annotation_source.hpp
+++ b/src/mbgl/annotation/annotation_source.hpp
@@ -5,17 +5,22 @@
namespace mbgl {
-class AnnotationSource : public style::Source {
+class AnnotationSource final : public style::Source {
public:
AnnotationSource();
class Impl;
const Impl& impl() const;
+ mapbox::base::WeakPtr<Source> makeWeakPtr() override {
+ return weakFactory.makeWeakPtr();
+ }
+
private:
void loadDescription(FileSource&) final;
Mutable<Impl> mutableImpl() const;
+ mapbox::base::WeakPtrFactory<Source> weakFactory {this};
};
class AnnotationSource::Impl : public style::Source::Impl {
diff --git a/src/mbgl/geometry/dem_data.cpp b/src/mbgl/geometry/dem_data.cpp
index 92dd7aee26..79998a9c43 100644
--- a/src/mbgl/geometry/dem_data.cpp
+++ b/src/mbgl/geometry/dem_data.cpp
@@ -3,36 +3,23 @@
namespace mbgl {
-DEMData::DEMData(const PremultipliedImage& _image, Tileset::DEMEncoding encoding):
+DEMData::DEMData(const PremultipliedImage& _image, Tileset::DEMEncoding _encoding):
dim(_image.size.height),
// extra two pixels per row for border backfilling on either edge
stride(dim + 2),
+ encoding(_encoding),
image({ static_cast<uint32_t>(stride), static_cast<uint32_t>(stride) }) {
if (_image.size.height != _image.size.width){
throw std::runtime_error("raster-dem tiles must be square.");
}
- auto decodeMapbox = [] (const uint8_t r, const uint8_t g, const uint8_t b){
- // https://www.mapbox.com/help/access-elevation-data/#mapbox-terrain-rgb
- return (r * 256 * 256 + g * 256 + b)/10 - 10000;
- };
-
- auto decodeTerrarium = [] (const uint8_t r, const uint8_t g, const uint8_t b){
- // https://aws.amazon.com/public-datasets/terrain/
- return ((r * 256 + g + b / 256) - 32768);
- };
-
- auto decodeRGB = encoding == Tileset::DEMEncoding::Terrarium ? decodeTerrarium : decodeMapbox;
-
- std::memset(image.data.get(), 0, image.bytes());
-
+ auto* dest = reinterpret_cast<uint32_t*>(image.data.get()) + stride + 1;
+ auto* source = reinterpret_cast<uint32_t*>(_image.data.get());
for (int32_t y = 0; y < dim; y++) {
- for (int32_t x = 0; x < dim; x++) {
- const int32_t i = y * dim + x;
- const int32_t j = i * 4;
- set(x, y, decodeRGB(_image.data[j], _image.data[j+1], _image.data[j+2]));
- }
+ memcpy(dest, source, dim * 4);
+ dest += stride;
+ source += dim;
}
// in order to avoid flashing seams between tiles, here we are initially populating a 1px border of
@@ -40,25 +27,20 @@ DEMData::DEMData(const PremultipliedImage& _image, Tileset::DEMEncoding encoding
// replaced when the tile's neighboring tiles are loaded and the accurate data can be backfilled using
// DEMData#backfillBorder
+ auto* data = reinterpret_cast<uint32_t*>(image.data.get());
for (int32_t x = 0; x < dim; x++) {
+ auto rowOffset = stride * (x + 1);
// left vertical border
- set(-1, x, get(0, x));
+ data[rowOffset] = data[rowOffset + 1];
// right vertical border
- set(dim, x, get(dim - 1, x));
-
- //left horizontal border
- set(x, -1, get(x, 0));
-
- // right horizontal border
- set(x, dim, get(x, dim - 1));
+ data[rowOffset + dim + 1] = data[rowOffset + dim];
}
-
- // corners
- set(-1, -1, get(0, 0));
- set(dim, -1, get(dim - 1, 0));
- set( -1, dim, get(0, dim - 1));
- set(dim, dim, get(dim - 1, dim - 1));
+
+ // top horizontal border with corners
+ memcpy(data, data + stride, stride * 4);
+ // bottom horizontal border with corners
+ memcpy(data + (dim + 1) * stride, data + dim * stride, stride * 4);
}
// This function takes the DEMData from a neighboring tile and backfills the edge/corner
@@ -90,11 +72,29 @@ void DEMData::backfillBorder(const DEMData& borderTileData, int8_t dx, int8_t dy
int32_t ox = -dx * dim;
int32_t oy = -dy * dim;
+ auto* dest = reinterpret_cast<uint32_t*>(image.data.get());
+ auto* source = reinterpret_cast<uint32_t*>(o.image.data.get());
+
for (int32_t y = yMin; y < yMax; y++) {
for (int32_t x = xMin; x < xMax; x++) {
- set(x, y, o.get(x + ox, y + oy));
+ dest[idx(x, y)] = source[idx(x + ox, y + oy)];
}
}
}
+int32_t DEMData::get(const int32_t x, const int32_t y) const {
+ const auto& unpack = getUnpackVector();
+ const uint8_t* value = image.data.get() + idx(x, y) * 4;
+ return value[0] * unpack[0] + value[1] * unpack[1] + value[2] * unpack[2] - unpack[3];
+}
+
+const std::array<float, 4>& DEMData::getUnpackVector() const {
+ // https://www.mapbox.com/help/access-elevation-data/#mapbox-terrain-rgb
+ static const std::array<float, 4> unpackMapbox = {{ 6553.6, 25.6, 0.1, 10000.0 }};
+ // https://aws.amazon.com/public-datasets/terrain/
+ static const std::array<float, 4> unpackTerrarium = {{ 256.0, 1.0, 1.0 / 256.0, 32768.0 }};
+
+ return encoding == Tileset::DEMEncoding::Terrarium ? unpackTerrarium : unpackMapbox;
+}
+
} // namespace mbgl
diff --git a/src/mbgl/geometry/dem_data.hpp b/src/mbgl/geometry/dem_data.hpp
index 21146bc468..537575873f 100644
--- a/src/mbgl/geometry/dem_data.hpp
+++ b/src/mbgl/geometry/dem_data.hpp
@@ -16,13 +16,8 @@ public:
DEMData(const PremultipliedImage& image, Tileset::DEMEncoding encoding);
void backfillBorder(const DEMData& borderTileData, int8_t dx, int8_t dy);
- void set(const int32_t x, const int32_t y, const int32_t value) {
- reinterpret_cast<int32_t*>(image.data.get())[idx(x, y)] = value + 65536;
- }
-
- int32_t get(const int32_t x, const int32_t y) const {
- return reinterpret_cast<const int32_t*>(image.data.get())[idx(x, y)] - 65536;
- }
+ int32_t get(const int32_t x, const int32_t y) const;
+ const std::array<float, 4>& getUnpackVector() const;
const PremultipliedImage* getImage() const {
return &image;
@@ -32,16 +27,17 @@ public:
const int32_t stride;
- private:
- PremultipliedImage image;
+private:
+ Tileset::DEMEncoding encoding;
+ PremultipliedImage image;
- size_t idx(const int32_t x, const int32_t y) const {
- assert(x >= -1);
- assert(x < dim + 1);
- assert(y >= -1);
- assert(y < dim + 1);
- return (y + 1) * stride + (x + 1);
- }
+ size_t idx(const int32_t x, const int32_t y) const {
+ assert(x >= -1);
+ assert(x < dim + 1);
+ assert(y >= -1);
+ assert(y < dim + 1);
+ return (y + 1) * stride + (x + 1);
+ }
};
diff --git a/src/mbgl/layout/symbol_instance.cpp b/src/mbgl/layout/symbol_instance.cpp
index 113bf5bd35..41a00e0131 100644
--- a/src/mbgl/layout/symbol_instance.cpp
+++ b/src/mbgl/layout/symbol_instance.cpp
@@ -21,15 +21,18 @@ const Shaping& getAnyShaping(const ShapedTextOrientations& shapedTextOrientation
SymbolInstanceSharedData::SymbolInstanceSharedData(GeometryCoordinates line_,
const ShapedTextOrientations& shapedTextOrientations,
const optional<PositionedIcon>& shapedIcon,
+ const optional<PositionedIcon>& verticallyShapedIcon,
const style::SymbolLayoutProperties::Evaluated& layout,
- const float layoutTextSize,
const style::SymbolPlacementType textPlacement,
const std::array<float, 2>& textOffset,
const GlyphPositions& positions,
bool allowVerticalPlacement) : line(std::move(line_)) {
// Create the quads used for rendering the icon and glyphs.
if (shapedIcon) {
- iconQuad = getIconQuad(*shapedIcon, layout, layoutTextSize, shapedTextOrientations.horizontal);
+ iconQuad = getIconQuad(*shapedIcon, getAnyShaping(shapedTextOrientations).writingMode);
+ if (verticallyShapedIcon) {
+ verticalIconQuad = getIconQuad(*verticallyShapedIcon, shapedTextOrientations.vertical.writingMode);
+ }
}
bool singleLineInitialized = false;
@@ -69,6 +72,7 @@ SymbolInstance::SymbolInstance(Anchor& anchor_,
std::shared_ptr<SymbolInstanceSharedData> sharedData_,
const ShapedTextOrientations& shapedTextOrientations,
const optional<PositionedIcon>& shapedIcon,
+ const optional<PositionedIcon>& verticallyShapedIcon,
const float textBoxScale_,
const float textPadding,
const SymbolPlacementType textPlacement,
@@ -83,13 +87,12 @@ SymbolInstance::SymbolInstance(Anchor& anchor_,
const float overscaling,
const float iconRotation,
const float textRotation,
- float radialTextOffset_,
- bool allowVerticalPlacement) :
+ const std::array<float, 2>& variableTextOffset_,
+ bool allowVerticalPlacement,
+ const SymbolContent iconType) :
sharedData(std::move(sharedData_)),
anchor(anchor_),
- // 'hasText' depends on finding at least one glyph in the shaping that's also in the GlyphPositionMap
- hasText(!sharedData->empty()),
- hasIcon(shapedIcon),
+ symbolContent(iconType),
// Create the collision features that will be used to check whether this symbol instance can be placed
// As a collision approximation, we can use either the vertical or any of the horizontal versions of the feature
textCollisionFeature(sharedData->line, anchor, getAnyShaping(shapedTextOrientations), textBoxScale_, textPadding, textPlacement, indexedFeature, overscaling, textRotation),
@@ -101,12 +104,21 @@ SymbolInstance::SymbolInstance(Anchor& anchor_,
iconOffset(iconOffset_),
key(std::move(key_)),
textBoxScale(textBoxScale_),
- radialTextOffset(radialTextOffset_),
+ variableTextOffset(variableTextOffset_),
singleLine(shapedTextOrientations.singleLine) {
-
+ // 'hasText' depends on finding at least one glyph in the shaping that's also in the GlyphPositionMap
+ if(!sharedData->empty()) symbolContent |= SymbolContent::Text;
if (allowVerticalPlacement && shapedTextOrientations.vertical) {
const float verticalPointLabelAngle = 90.0f;
verticalTextCollisionFeature = CollisionFeature(line(), anchor, shapedTextOrientations.vertical, textBoxScale_, textPadding, textPlacement, indexedFeature, overscaling, textRotation + verticalPointLabelAngle);
+ if (verticallyShapedIcon) {
+ verticalIconCollisionFeature = CollisionFeature(sharedData->line,
+ anchor,
+ verticallyShapedIcon,
+ iconBoxScale, iconPadding,
+ indexedFeature,
+ iconRotation + verticalPointLabelAngle);
+ }
}
rightJustifiedGlyphQuadsSize = sharedData->rightJustifiedGlyphQuads.size();
@@ -152,6 +164,23 @@ const optional<SymbolQuad>& SymbolInstance::iconQuad() const {
assert(sharedData);
return sharedData->iconQuad;
}
+
+bool SymbolInstance::hasText() const {
+ return static_cast<bool>(symbolContent & SymbolContent::Text);
+}
+
+bool SymbolInstance::hasIcon() const {
+ return static_cast<bool>(symbolContent & SymbolContent::IconRGBA) || hasSdfIcon();
+}
+
+bool SymbolInstance::hasSdfIcon() const {
+ return static_cast<bool>(symbolContent & SymbolContent::IconSDF);
+}
+
+const optional<SymbolQuad>& SymbolInstance::verticalIconQuad() const {
+ assert(sharedData);
+ return sharedData->verticalIconQuad;
+}
void SymbolInstance::releaseSharedData() {
sharedData.reset();
diff --git a/src/mbgl/layout/symbol_instance.hpp b/src/mbgl/layout/symbol_instance.hpp
index 2c6aad653f..4a57b527f7 100644
--- a/src/mbgl/layout/symbol_instance.hpp
+++ b/src/mbgl/layout/symbol_instance.hpp
@@ -4,7 +4,7 @@
#include <mbgl/text/glyph_atlas.hpp>
#include <mbgl/text/collision_feature.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
-
+#include <mbgl/util/bitmask_operations.hpp>
namespace mbgl {
@@ -25,8 +25,8 @@ struct SymbolInstanceSharedData {
SymbolInstanceSharedData(GeometryCoordinates line,
const ShapedTextOrientations& shapedTextOrientations,
const optional<PositionedIcon>& shapedIcon,
+ const optional<PositionedIcon>& verticallyShapedIcon,
const style::SymbolLayoutProperties::Evaluated& layout,
- const float layoutTextSize,
const style::SymbolPlacementType textPlacement,
const std::array<float, 2>& textOffset,
const GlyphPositions& positions,
@@ -39,6 +39,14 @@ struct SymbolInstanceSharedData {
SymbolQuads leftJustifiedGlyphQuads;
SymbolQuads verticalGlyphQuads;
optional<SymbolQuad> iconQuad;
+ optional<SymbolQuad> verticalIconQuad;
+};
+
+enum class SymbolContent : uint8_t {
+ None = 0,
+ Text = 1 << 0,
+ IconRGBA = 1 << 1,
+ IconSDF = 1 << 2
};
class SymbolInstance {
@@ -47,6 +55,7 @@ public:
std::shared_ptr<SymbolInstanceSharedData> sharedData,
const ShapedTextOrientations& shapedTextOrientations,
const optional<PositionedIcon>& shapedIcon,
+ const optional<PositionedIcon>& verticallyShapedIcon,
const float textBoxScale,
const float textPadding,
const style::SymbolPlacementType textPlacement,
@@ -61,8 +70,9 @@ public:
const float overscaling,
const float iconRotation,
const float textRotation,
- float radialTextOffset,
- bool allowVerticalPlacement);
+ const std::array<float, 2>& variableTextOffset,
+ bool allowVerticalPlacement,
+ const SymbolContent iconType = SymbolContent::None);
optional<size_t> getDefaultHorizontalPlacedTextIndex() const;
const GeometryCoordinates& line() const;
@@ -70,7 +80,11 @@ public:
const SymbolQuads& leftJustifiedGlyphQuads() const;
const SymbolQuads& centerJustifiedGlyphQuads() const;
const SymbolQuads& verticalGlyphQuads() const;
+ bool hasText() const;
+ bool hasIcon() const;
+ bool hasSdfIcon() const;
const optional<SymbolQuad>& iconQuad() const;
+ const optional<SymbolQuad>& verticalIconQuad() const;
void releaseSharedData();
private:
@@ -78,8 +92,7 @@ private:
public:
Anchor anchor;
- bool hasText;
- bool hasIcon;
+ SymbolContent symbolContent;
std::size_t rightJustifiedGlyphQuadsSize;
std::size_t centerJustifiedGlyphQuadsSize;
@@ -89,6 +102,7 @@ public:
CollisionFeature textCollisionFeature;
CollisionFeature iconCollisionFeature;
optional<CollisionFeature> verticalTextCollisionFeature = nullopt;
+ optional<CollisionFeature> verticalIconCollisionFeature = nullopt;
WritingModeType writingModes;
std::size_t layoutFeatureIndex; // Index into the set of features included at layout time
std::size_t dataFeatureIndex; // Index into the underlying tile data feature set
@@ -101,8 +115,9 @@ public:
optional<size_t> placedLeftTextIndex;
optional<size_t> placedVerticalTextIndex;
optional<size_t> placedIconIndex;
+ optional<size_t> placedVerticalIconIndex;
float textBoxScale;
- float radialTextOffset;
+ std::array<float, 2> variableTextOffset;
bool singleLine;
uint32_t crossTileID = 0;
};
diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp
index dbf209b414..1dbb5d91dc 100644
--- a/src/mbgl/layout/symbol_layout.cpp
+++ b/src/mbgl/layout/symbol_layout.cpp
@@ -91,11 +91,13 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
pixelRatio(parameters.pixelRatio),
tileSize(util::tileSize * overscaling),
tilePixelRatio(float(util::EXTENT) / tileSize),
- textSize(toSymbolLayerProperties(layers.at(0)).layerImpl().layout.get<TextSize>()),
- iconSize(toSymbolLayerProperties(layers.at(0)).layerImpl().layout.get<IconSize>()),
layout(createLayout(toSymbolLayerProperties(layers.at(0)).layerImpl().layout, zoom)) {
const SymbolLayer::Impl& leader = toSymbolLayerProperties(layers.at(0)).layerImpl();
+ textSize = leader.layout.get<TextSize>();
+ iconSize = leader.layout.get<IconSize>();
+ textRadialOffset = leader.layout.get<TextRadialOffset>();
+
const bool hasText = has<TextField>(*layout) && has<TextFont>(*layout);
const bool hasIcon = has<IconImage>(*layout);
@@ -235,11 +237,9 @@ Shaping& shapingForTextJustifyType(ShapedTextOrientations& shapedTextOrientation
}
}
-} // namespace
-
-// static
-Point<float> SymbolLayout::evaluateRadialOffset(SymbolAnchorType anchor, float radialOffset) {
- Point<float> result{};
+std::array<float, 2> evaluateRadialOffset(style::SymbolAnchorType anchor, float radialOffset) {
+ std::array<float, 2> result{{0.0f, 0.0f}};
+ if (radialOffset < 0.0f) radialOffset = 0.0f; // Ignore negative offset.
// solve for r where r^2 + r^2 = radialOffset^2
const float sqrt2 = 1.41421356237f;
const float hypotenuse = radialOffset / sqrt2;
@@ -247,17 +247,17 @@ Point<float> SymbolLayout::evaluateRadialOffset(SymbolAnchorType anchor, float r
switch (anchor) {
case SymbolAnchorType::TopRight:
case SymbolAnchorType::TopLeft:
- result.y = hypotenuse - baselineOffset;
+ result[1] = hypotenuse - baselineOffset;
break;
case SymbolAnchorType::BottomRight:
case SymbolAnchorType::BottomLeft:
- result.y = -hypotenuse + baselineOffset;
+ result[1] = -hypotenuse + baselineOffset;
break;
case SymbolAnchorType::Bottom:
- result.y = -radialOffset + baselineOffset;
+ result[1] = -radialOffset + baselineOffset;
break;
case SymbolAnchorType::Top:
- result.y = radialOffset - baselineOffset;
+ result[1] = radialOffset - baselineOffset;
break;
default:
break;
@@ -266,17 +266,17 @@ Point<float> SymbolLayout::evaluateRadialOffset(SymbolAnchorType anchor, float r
switch (anchor) {
case SymbolAnchorType::TopRight:
case SymbolAnchorType::BottomRight:
- result.x = -hypotenuse;
+ result[0] = -hypotenuse;
break;
case SymbolAnchorType::TopLeft:
case SymbolAnchorType::BottomLeft:
- result.x = hypotenuse;
+ result[0] = hypotenuse;
break;
case SymbolAnchorType::Left:
- result.x = radialOffset;
+ result[0] = radialOffset;
break;
case SymbolAnchorType::Right:
- result.x = -radialOffset;
+ result[0] = -radialOffset;
break;
default:
break;
@@ -285,6 +285,54 @@ Point<float> SymbolLayout::evaluateRadialOffset(SymbolAnchorType anchor, float r
return result;
}
+} // namespace
+
+// static
+std::array<float, 2> SymbolLayout::evaluateVariableOffset(style::SymbolAnchorType anchor, std::array<float, 2> offset) {
+ if (offset[1] == INVALID_OFFSET_VALUE) {
+ return evaluateRadialOffset(anchor, offset[0]);
+ }
+ std::array<float, 2> result{{0.0f, 0.0f}};
+ offset[0] = std::abs(offset[0]);
+ offset[1] = std::abs(offset[1]);
+
+ switch (anchor) {
+ case SymbolAnchorType::TopRight:
+ case SymbolAnchorType::TopLeft:
+ case SymbolAnchorType::Top:
+ result[1] = offset[1] - baselineOffset;
+ break;
+ case SymbolAnchorType::BottomRight:
+ case SymbolAnchorType::BottomLeft:
+ case SymbolAnchorType::Bottom:
+ result[1] = -offset[1] + baselineOffset;
+ break;
+ case SymbolAnchorType::Center:
+ case SymbolAnchorType::Left:
+ case SymbolAnchorType::Right:
+ break;
+ }
+
+ switch (anchor) {
+ case SymbolAnchorType::TopRight:
+ case SymbolAnchorType::BottomRight:
+ case SymbolAnchorType::Right:
+ result[0] = -offset[0];
+ break;
+ case SymbolAnchorType::TopLeft:
+ case SymbolAnchorType::BottomLeft:
+ case SymbolAnchorType::Left:
+ result[0] = offset[0];
+ break;
+ case SymbolAnchorType::Center:
+ case SymbolAnchorType::Top:
+ case SymbolAnchorType::Bottom:
+ break;
+ }
+
+ return result;
+}
+
void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions& glyphPositions,
const ImageMap& imageMap, const ImagePositions& imagePositions) {
const bool isPointPlacement = layout->get<SymbolPlacement>() == SymbolPlacementType::Point;
@@ -296,7 +344,7 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions
ShapedTextOrientations shapedTextOrientations;
optional<PositionedIcon> shapedIcon;
- Point<float> textOffset;
+ std::array<float, 2> textOffset{{0.0f, 0.0f}};
// if feature has text, shape the text
if (feature.formattedText) {
@@ -320,18 +368,18 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions
return result;
};
const std::vector<style::TextVariableAnchorType> variableTextAnchor = layout->evaluate<TextVariableAnchor>(zoom, feature);
- const float radialOffset = layout->evaluate<TextRadialOffset>(zoom, feature);
const SymbolAnchorType textAnchor = layout->evaluate<TextAnchor>(zoom, feature);
if (variableTextAnchor.empty()) {
// Layers with variable anchors use the `text-radial-offset` property and the [x, y] offset vector
// is calculated at placement time instead of layout time
+ const float radialOffset = layout->evaluate<TextRadialOffset>(zoom, feature);
if (radialOffset > 0.0f) {
// The style spec says don't use `text-offset` and `text-radial-offset` together
// but doesn't actually specify what happens if you use both. We go with the radial offset.
textOffset = evaluateRadialOffset(textAnchor, radialOffset * util::ONE_EM);
} else {
- textOffset = { layout->evaluate<TextOffset>(zoom, feature)[0] * util::ONE_EM,
- layout->evaluate<TextOffset>(zoom, feature)[1] * util::ONE_EM};
+ textOffset = {{layout->evaluate<TextOffset>(zoom, feature)[0] * util::ONE_EM,
+ layout->evaluate<TextOffset>(zoom, feature)[1] * util::ONE_EM}};
}
}
TextJustifyType textJustify = textAlongLine ? TextJustifyType::Center : layout->evaluate<TextJustify>(zoom, feature);
@@ -366,7 +414,7 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions
Shaping shaping = applyShaping(*feature.formattedText, WritingModeType::Horizontal, SymbolAnchorType::Center, justification);
if (shaping) {
shapingForJustification = std::move(shaping);
- if (shaping.lineCount == 1u) {
+ if (shapingForJustification.lineCount == 1u) {
shapedTextOrientations.singleLine = true;
break;
}
@@ -398,16 +446,18 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions
}
// if feature has icon, get sprite atlas position
+ SymbolContent iconType{SymbolContent::None};
if (feature.icon) {
auto image = imageMap.find(*feature.icon);
if (image != imageMap.end()) {
+ iconType = SymbolContent::IconRGBA;
shapedIcon = PositionedIcon::shapeIcon(
imagePositions.at(*feature.icon),
layout->evaluate<IconOffset>(zoom, feature),
layout->evaluate<IconAnchor>(zoom, feature),
layout->evaluate<IconRotate>(zoom, feature) * util::DEG2RAD);
if (image->second->sdf) {
- sdfIcons = true;
+ iconType = SymbolContent::IconSDF;
}
if (image->second->pixelRatio != pixelRatio) {
iconsNeedLinear = true;
@@ -419,7 +469,7 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions
// if either shapedText or icon position is present, add the feature
if (getDefaultHorizontalShaping(shapedTextOrientations) || shapedIcon) {
- addFeature(std::distance(features.begin(), it), feature, shapedTextOrientations, shapedIcon, glyphPositions, textOffset);
+ addFeature(std::distance(features.begin(), it), feature, shapedTextOrientations, std::move(shapedIcon), glyphPositions, textOffset, iconType);
}
feature.geometry.clear();
@@ -431,15 +481,15 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions
void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex,
const SymbolFeature& feature,
const ShapedTextOrientations& shapedTextOrientations,
- const optional<PositionedIcon>& shapedIcon,
+ optional<PositionedIcon> shapedIcon,
const GlyphPositions& glyphPositions,
- Point<float> offset) {
+ std::array<float, 2> textOffset,
+ const SymbolContent iconType) {
const float minScale = 0.5f;
const float glyphSize = 24.0f;
const float layoutTextSize = layout->evaluate<TextSize>(zoom + 1, feature);
const float layoutIconSize = layout->evaluate<IconSize>(zoom + 1, feature);
- const std::array<float, 2> textOffset = {{ offset.x, offset.y }};
const std::array<float, 2> iconOffset = layout->evaluate<IconOffset>(zoom, feature);
@@ -459,7 +509,15 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex,
const float textMaxAngle = layout->get<TextMaxAngle>() * util::DEG2RAD;
const float iconRotation = layout->evaluate<IconRotate>(zoom, feature);
const float textRotation = layout->evaluate<TextRotate>(zoom, feature);
- const float radialTextOffset = layout->evaluate<TextRadialOffset>(zoom, feature) * util::ONE_EM;
+ std::array<float, 2> variableTextOffset;
+ if (!textRadialOffset.isUndefined()) {
+ variableTextOffset = {{layout->evaluate<TextRadialOffset>(zoom, feature) * util::ONE_EM,
+ INVALID_OFFSET_VALUE}};
+ } else {
+ variableTextOffset = {{layout->evaluate<TextOffset>(zoom, feature)[0] * util::ONE_EM,
+ layout->evaluate<TextOffset>(zoom, feature)[1] * util::ONE_EM}};
+ }
+
const SymbolPlacementType textPlacement = layout->get<TextRotationAlignment>() != AlignmentType::Map
? SymbolPlacementType::Point
: layout->get<SymbolPlacement>();
@@ -467,6 +525,22 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex,
const float textRepeatDistance = symbolSpacing / 2;
const auto evaluatedLayoutProperties = layout->evaluate(zoom, feature);
IndexedSubfeature indexedFeature(feature.index, sourceLayer->getName(), bucketLeaderID, symbolInstances.size());
+ const bool hasIconTextFit = evaluatedLayoutProperties.get<style::IconTextFit>() != IconTextFitType::None;
+
+ // Adjust shaped icon size when icon-text-fit is used.
+ optional<PositionedIcon> verticallyShapedIcon;
+ if (shapedIcon && hasIconTextFit) {
+ // Create vertically shaped icon for vertical writing mode if needed.
+ if (allowVerticalPlacement && shapedTextOrientations.vertical) {
+ verticallyShapedIcon = shapedIcon;
+ verticallyShapedIcon->fitIconToText(evaluatedLayoutProperties,
+ shapedTextOrientations.vertical,
+ layoutTextSize);
+ }
+ shapedIcon->fitIconToText(evaluatedLayoutProperties,
+ getDefaultHorizontalShaping(shapedTextOrientations),
+ layoutTextSize);
+ }
auto addSymbolInstance = [&] (Anchor& anchor, std::shared_ptr<SymbolInstanceSharedData> sharedData) {
assert(sharedData);
@@ -478,18 +552,19 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex,
// In tiled rendering mode, add all symbols in the buffers so that we can:
// (1) render symbols that overlap into this tile
// (2) approximate collision detection effects from neighboring symbols
- symbolInstances.emplace_back(anchor, std::move(sharedData), shapedTextOrientations, shapedIcon,
+ symbolInstances.emplace_back(anchor, std::move(sharedData), shapedTextOrientations,
+ shapedIcon, verticallyShapedIcon,
textBoxScale, textPadding, textPlacement, textOffset,
iconBoxScale, iconPadding, iconOffset, indexedFeature,
layoutFeatureIndex, feature.index,
feature.formattedText ? feature.formattedText->rawText() : std::u16string(),
- overscaling, iconRotation, textRotation, radialTextOffset, allowVerticalPlacement);
+ overscaling, iconRotation, textRotation, variableTextOffset, allowVerticalPlacement, iconType);
}
};
const auto createSymbolInstanceSharedData = [&] (GeometryCoordinates line) {
return std::make_shared<SymbolInstanceSharedData>(std::move(line),
- shapedTextOrientations, shapedIcon, evaluatedLayoutProperties, layoutTextSize,
+ shapedTextOrientations, shapedIcon, verticallyShapedIcon, evaluatedLayoutProperties,
textPlacement, textOffset, glyphPositions, allowVerticalPlacement);
};
@@ -603,20 +678,45 @@ std::vector<float> CalculateTileDistances(const GeometryCoordinates& line, const
}
void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr<FeatureIndex>&, std::unordered_map<std::string, LayerRenderData>& renderData, const bool firstLoad, const bool showCollisionBoxes) {
- auto bucket = std::make_shared<SymbolBucket>(layout, layerPaintProperties, textSize, iconSize, zoom, sdfIcons, iconsNeedLinear,
+ auto bucket = std::make_shared<SymbolBucket>(layout, layerPaintProperties, textSize, iconSize, zoom, iconsNeedLinear,
sortFeaturesByY, bucketLeaderID, std::move(symbolInstances), tilePixelRatio,
allowVerticalPlacement,
std::move(placementModes));
for (SymbolInstance &symbolInstance : bucket->symbolInstances) {
- const bool hasText = symbolInstance.hasText;
- const bool hasIcon = symbolInstance.hasIcon;
+ const bool hasText = symbolInstance.hasText();
+ const bool hasIcon = symbolInstance.hasIcon();
const bool singleLine = symbolInstance.singleLine;
const auto& feature = features.at(symbolInstance.layoutFeatureIndex);
// Insert final placement into collision tree and add glyphs/icons to buffers
+ // Process icon first, so that text symbols would have reference to iconIndex which
+ // is used when dynamic vertices for icon-text-fit image have to be updated.
+ if (hasIcon) {
+ const Range<float> sizeData = bucket->iconSizeBinder->getVertexSizeData(feature);
+ auto& iconBuffer = symbolInstance.hasSdfIcon() ? bucket->sdfIcon : bucket->icon;
+ const auto placeIcon = [&] (const SymbolQuad& iconQuad, auto& index, const WritingModeType writingMode) {
+ iconBuffer.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max,
+ symbolInstance.iconOffset, writingMode, symbolInstance.line(), std::vector<float>());
+ index = iconBuffer.placedSymbols.size() - 1;
+ PlacedSymbol& iconSymbol = iconBuffer.placedSymbols.back();
+ iconSymbol.angle = (allowVerticalPlacement && writingMode == WritingModeType::Vertical) ? M_PI_2 : 0;
+ iconSymbol.vertexStartIndex = addSymbol(iconBuffer, sizeData, iconQuad,
+ symbolInstance.anchor, iconSymbol, feature.sortKey);
+ };
+
+ placeIcon(*symbolInstance.iconQuad(), symbolInstance.placedIconIndex, WritingModeType::None);
+ if (symbolInstance.verticalIconQuad()) {
+ placeIcon(*symbolInstance.verticalIconQuad(), symbolInstance.placedVerticalIconIndex, WritingModeType::Vertical);
+ }
+
+ for (auto& pair : bucket->paintProperties) {
+ pair.second.iconBinders.populateVertexVectors(feature, iconBuffer.vertices.elements(), {}, {});
+ }
+ }
+
if (hasText && feature.formattedText) {
optional<std::size_t> lastAddedSection;
if (singleLine) {
@@ -643,21 +743,6 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr<FeatureIn
updatePaintPropertiesForSection(*bucket, feature, *lastAddedSection);
}
- if (hasIcon) {
- if (symbolInstance.hasIcon) {
- const Range<float> sizeData = bucket->iconSizeBinder->getVertexSizeData(feature);
- bucket->icon.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max,
- symbolInstance.iconOffset, WritingModeType::None, symbolInstance.line(), std::vector<float>());
- symbolInstance.placedIconIndex = bucket->icon.placedSymbols.size() - 1;
- PlacedSymbol& iconSymbol = bucket->icon.placedSymbols.back();
- iconSymbol.vertexStartIndex = addSymbol(bucket->icon, sizeData, *symbolInstance.iconQuad(),
- symbolInstance.anchor, iconSymbol, feature.sortKey);
-
- for (auto& pair : bucket->paintProperties) {
- pair.second.iconBinders.populateVertexVectors(feature, bucket->icon.vertices.elements(), {}, {});
- }
- }
- }
symbolInstance.releaseSharedData();
}
@@ -693,9 +778,9 @@ std::size_t SymbolLayout::addSymbolGlyphQuads(SymbolBucket& bucket,
optional<std::size_t> lastAddedSection) {
const Range<float> sizeData = bucket.textSizeBinder->getVertexSizeData(feature);
const bool hasFormatSectionOverrides = bucket.hasFormatSectionOverrides();
-
+ const auto& placedIconIndex = writingMode == WritingModeType::Vertical ? symbolInstance.placedVerticalIconIndex : symbolInstance.placedIconIndex;
bucket.text.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max,
- symbolInstance.textOffset, writingMode, symbolInstance.line(), CalculateTileDistances(symbolInstance.line(), symbolInstance.anchor));
+ symbolInstance.textOffset, writingMode, symbolInstance.line(), CalculateTileDistances(symbolInstance.line(), symbolInstance.anchor), placedIconIndex);
placedIndex = bucket.text.placedSymbols.size() - 1;
PlacedSymbol& placedSymbol = bucket.text.placedSymbols.back();
placedSymbol.angle = (allowVerticalPlacement && writingMode == WritingModeType::Vertical) ? M_PI_2 : 0;
@@ -782,12 +867,15 @@ void SymbolLayout::addToDebugBuffers(SymbolBucket& bucket) {
return;
}
- for (const SymbolInstance &symbolInstance : symbolInstances) {
- auto populateCollisionBox = [&](const auto& feature) {
- SymbolBucket::CollisionBuffer& collisionBuffer = feature.alongLine ?
- static_cast<SymbolBucket::CollisionBuffer&>(bucket.getOrCreateCollisionCircleBuffer()) :
- static_cast<SymbolBucket::CollisionBuffer&>(bucket.getOrCreateCollisionBox());
- for (const CollisionBox &box : feature.boxes) {
+ for (const SymbolInstance& symbolInstance : symbolInstances) {
+ auto populateCollisionBox = [&](const auto& feature, bool isText) {
+ SymbolBucket::CollisionBuffer& collisionBuffer =
+ feature.alongLine ? (isText ? static_cast<SymbolBucket::CollisionBuffer&>(bucket.getOrCreateTextCollisionCircleBuffer())
+ : static_cast<SymbolBucket::CollisionBuffer&>(bucket.getOrCreateIconCollisionCircleBuffer()))
+ : (isText ? static_cast<SymbolBucket::CollisionBuffer&>(bucket.getOrCreateTextCollisionBox())
+ : static_cast<SymbolBucket::CollisionBuffer&>(bucket.getOrCreateIconCollisionBox()));
+
+ for (const CollisionBox& box : feature.boxes) {
auto& anchor = box.anchor;
Point<float> tl{box.x1, box.y1};
@@ -799,8 +887,11 @@ void SymbolLayout::addToDebugBuffers(SymbolBucket& bucket) {
const std::size_t indexLength = feature.alongLine ? 6 : 8;
if (collisionBuffer.segments.empty() || collisionBuffer.segments.back().vertexLength + vertexLength > std::numeric_limits<uint16_t>::max()) {
- collisionBuffer.segments.emplace_back(collisionBuffer.vertices.elements(),
- feature.alongLine ? bucket.collisionCircle->triangles.elements() : bucket.collisionBox->lines.elements());
+ collisionBuffer.segments.emplace_back(
+ collisionBuffer.vertices.elements(),
+ feature.alongLine
+ ? (isText ? bucket.textCollisionCircle->triangles.elements() : bucket.iconCollisionCircle->triangles.elements())
+ : (isText ? bucket.textCollisionBox->lines.elements() : bucket.iconCollisionBox->lines.elements()));
}
auto& segment = collisionBuffer.segments.back();
@@ -820,24 +911,29 @@ void SymbolLayout::addToDebugBuffers(SymbolBucket& bucket) {
collisionBuffer.dynamicVertices.emplace_back(dynamicVertex);
if (feature.alongLine) {
- bucket.collisionCircle->triangles.emplace_back(index, index + 1, index + 2);
- bucket.collisionCircle->triangles.emplace_back(index, index + 2, index + 3);
+ auto& collisionCircle = (isText ? bucket.textCollisionCircle : bucket.iconCollisionCircle);
+ collisionCircle->triangles.emplace_back(index, index + 1, index + 2);
+ collisionCircle->triangles.emplace_back(index, index + 2, index + 3);
} else {
- bucket.collisionBox->lines.emplace_back(index + 0, index + 1);
- bucket.collisionBox->lines.emplace_back(index + 1, index + 2);
- bucket.collisionBox->lines.emplace_back(index + 2, index + 3);
- bucket.collisionBox->lines.emplace_back(index + 3, index + 0);
+ auto& collisionBox = (isText ? bucket.textCollisionBox : bucket.iconCollisionBox);
+ 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);
}
segment.vertexLength += vertexLength;
segment.indexLength += indexLength;
}
};
- populateCollisionBox(symbolInstance.textCollisionFeature);
+ populateCollisionBox(symbolInstance.textCollisionFeature, true /*isText*/);
if (symbolInstance.verticalTextCollisionFeature) {
- populateCollisionBox(*symbolInstance.verticalTextCollisionFeature);
+ populateCollisionBox(*symbolInstance.verticalTextCollisionFeature, true /*isText*/);
+ }
+ if (symbolInstance.verticalIconCollisionFeature) {
+ populateCollisionBox(*symbolInstance.verticalIconCollisionFeature, false /*isText*/);
}
- populateCollisionBox(symbolInstance.iconCollisionFeature);
+ populateCollisionBox(symbolInstance.iconCollisionFeature, false /*isText*/);
}
}
diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp
index 70a3482644..1abcaaa5d6 100644
--- a/src/mbgl/layout/symbol_layout.hpp
+++ b/src/mbgl/layout/symbol_layout.hpp
@@ -45,15 +45,25 @@ public:
const std::string bucketLeaderID;
std::vector<SymbolInstance> symbolInstances;
- static Point<float> evaluateRadialOffset(style::SymbolAnchorType anchor, float radialOffset);
+ static constexpr float INVALID_OFFSET_VALUE = std::numeric_limits<float>::max();
+ /**
+ * @brief Calculates variable text offset.
+ *
+ * @param anchor text anchor
+ * @param textOffset Either `text-offset` or [ `text-radial-offset`, INVALID_OFFSET_VALUE ]
+ * @return std::array<float, 2> offset along x- and y- axis correspondingly.
+ */
+ static std::array<float, 2> evaluateVariableOffset(style::SymbolAnchorType anchor, std::array<float, 2> textOffset);
+
private:
void addFeature(const size_t,
const SymbolFeature&,
const ShapedTextOrientations& shapedTextOrientations,
- const optional<PositionedIcon>& shapedIcon,
+ optional<PositionedIcon> shapedIcon,
const GlyphPositions&,
- Point<float> textOffset);
+ std::array<float, 2> textOffset,
+ const SymbolContent iconType);
bool anchorIsTooClose(const std::u16string& text, const float repeatDistance, const Anchor&);
std::map<std::u16string, std::vector<Anchor>> compareText;
@@ -93,7 +103,6 @@ private:
const uint32_t tileSize;
const float tilePixelRatio;
- bool sdfIcons = false;
bool iconsNeedLinear = false;
bool sortFeaturesByY = false;
bool allowVerticalPlacement = false;
@@ -101,6 +110,7 @@ private:
style::TextSize::UnevaluatedType textSize;
style::IconSize::UnevaluatedType iconSize;
+ style::TextRadialOffset::UnevaluatedType textRadialOffset;
Immutable<style::SymbolLayoutProperties::PossiblyEvaluated> layout;
std::vector<SymbolFeature> features;
diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp
index c35f33305c..649e0e321e 100644
--- a/src/mbgl/map/map.cpp
+++ b/src/mbgl/map/map.cpp
@@ -124,7 +124,7 @@ bool Map::isPanning() const {
#pragma mark -
-CameraOptions Map::getCameraOptions(const EdgeInsets& padding) const {
+CameraOptions Map::getCameraOptions(optional<EdgeInsets> padding) const {
return impl->transform.getCameraOptions(padding);
}
diff --git a/src/mbgl/map/map_impl.cpp b/src/mbgl/map/map_impl.cpp
index ce36583ab3..69c3de9783 100644
--- a/src/mbgl/map/map_impl.cpp
+++ b/src/mbgl/map/map_impl.cpp
@@ -130,11 +130,11 @@ void Map::Impl::onWillStartRenderingFrame() {
}
}
-void Map::Impl::onDidFinishRenderingFrame(RenderMode renderMode, bool needsRepaint) {
+void Map::Impl::onDidFinishRenderingFrame(RenderMode renderMode, bool needsRepaint, bool placemenChanged) {
rendererFullyLoaded = renderMode == RenderMode::Full;
if (mode == MapMode::Continuous) {
- observer.onDidFinishRenderingFrame(MapObserver::RenderMode(renderMode));
+ observer.onDidFinishRenderingFrame({MapObserver::RenderMode(renderMode), needsRepaint, placemenChanged});
if (needsRepaint || transform.inTransition()) {
onUpdate();
diff --git a/src/mbgl/map/map_impl.hpp b/src/mbgl/map/map_impl.hpp
index 13a68fb25e..416662f9e5 100644
--- a/src/mbgl/map/map_impl.hpp
+++ b/src/mbgl/map/map_impl.hpp
@@ -42,7 +42,7 @@ public:
void onInvalidate() final;
void onResourceError(std::exception_ptr) final;
void onWillStartRenderingFrame() final;
- void onDidFinishRenderingFrame(RenderMode, bool) final;
+ void onDidFinishRenderingFrame(RenderMode, bool, bool) final;
void onWillStartRenderingMap() final;
void onDidFinishRenderingMap() final;
void onStyleImageMissing(const std::string&, std::function<void()>) final;
diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp
index d386898c3b..7ec41be37a 100644
--- a/src/mbgl/map/transform.cpp
+++ b/src/mbgl/map/transform.cpp
@@ -63,7 +63,7 @@ void Transform::resize(const Size size) {
#pragma mark - Camera
-CameraOptions Transform::getCameraOptions(const EdgeInsets& padding) const {
+CameraOptions Transform::getCameraOptions(optional<EdgeInsets> padding) const {
return state.getCameraOptions(padding);
}
@@ -96,6 +96,9 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim
double pitch = camera.pitch ? *camera.pitch * util::DEG2RAD : getPitch();
if (std::isnan(zoom) || std::isnan(bearing) || std::isnan(pitch)) {
+ if (animation.transitionFinishFn) {
+ animation.transitionFinishFn();
+ }
return;
}
@@ -172,6 +175,9 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
double pitch = camera.pitch ? *camera.pitch * util::DEG2RAD : getPitch();
if (std::isnan(zoom) || std::isnan(bearing) || std::isnan(pitch) || state.size.isEmpty()) {
+ if (animation.transitionFinishFn) {
+ animation.transitionFinishFn();
+ }
return;
}
@@ -274,6 +280,9 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
if (duration == Duration::zero()) {
// Perform an instantaneous transition.
jumpTo(camera);
+ if (animation.transitionFinishFn) {
+ animation.transitionFinishFn();
+ }
return;
}
diff --git a/src/mbgl/map/transform.hpp b/src/mbgl/map/transform.hpp
index ffeff3859c..30ce8a37a4 100644
--- a/src/mbgl/map/transform.hpp
+++ b/src/mbgl/map/transform.hpp
@@ -29,7 +29,7 @@ public:
// Camera
/** Returns the current camera options. */
- CameraOptions getCameraOptions(const EdgeInsets&) const;
+ CameraOptions getCameraOptions(optional<EdgeInsets>) const;
/** Instantaneously, synchronously applies the given camera options. */
void jumpTo(const CameraOptions&);
diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp
index 77309a2a55..61007422cb 100644
--- a/src/mbgl/map/transform_state.cpp
+++ b/src/mbgl/map/transform_state.cpp
@@ -3,6 +3,7 @@
#include <mbgl/util/constants.hpp>
#include <mbgl/util/interpolate.hpp>
#include <mbgl/util/projection.hpp>
+#include <mbgl/util/tile_coordinate.hpp>
#include <mbgl/math/log2.hpp>
#include <mbgl/math/clamp.hpp>
@@ -145,10 +146,10 @@ ViewportMode TransformState::getViewportMode() const {
#pragma mark - Camera options
-CameraOptions TransformState::getCameraOptions(const EdgeInsets& padding) const {
+CameraOptions TransformState::getCameraOptions(optional<EdgeInsets> padding) const {
return CameraOptions()
.withCenter(getLatLng())
- .withPadding(padding)
+ .withPadding(padding ? padding : edgeInsets)
.withZoom(getZoom())
.withBearing(-bearing * util::RAD2DEG)
.withPitch(pitch * util::RAD2DEG);
@@ -289,9 +290,9 @@ ScreenCoordinate TransformState::latLngToScreenCoordinate(const LatLng& latLng)
return { p[0] / p[3], size.height - p[1] / p[3] };
}
-LatLng TransformState::screenCoordinateToLatLng(const ScreenCoordinate& point, LatLng::WrapMode wrapMode) const {
+TileCoordinate TransformState::screenCoordinateToTileCoordinate(const ScreenCoordinate& point, uint8_t atZoom) const {
if (size.isEmpty()) {
- return {};
+ return { {}, 0 };
}
float targetZ = 0;
@@ -325,7 +326,13 @@ LatLng TransformState::screenCoordinateToLatLng(const ScreenCoordinate& point, L
double z1 = coord1[2] / w1;
double t = z0 == z1 ? 0 : (targetZ - z0) / (z1 - z0);
- return Projection::unproject(util::interpolate(p0, p1, t), scale / util::tileSize, wrapMode);
+ Point<double> p = util::interpolate(p0, p1, t) / scale * static_cast<double>(1 << atZoom);
+ return { { p.x, p.y }, static_cast<double>(atZoom) };
+}
+
+LatLng TransformState::screenCoordinateToLatLng(const ScreenCoordinate& point, LatLng::WrapMode wrapMode) const {
+ auto coord = screenCoordinateToTileCoordinate(point, 0);
+ return Projection::unproject(coord.p, 1 / util::tileSize, wrapMode);
}
mat4 TransformState::coordinatePointMatrix() const {
diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp
index cca42db20f..10a92187d5 100644
--- a/src/mbgl/map/transform_state.hpp
+++ b/src/mbgl/map/transform_state.hpp
@@ -17,6 +17,7 @@
namespace mbgl {
class UnwrappedTileID;
+class TileCoordinate;
class TransformState {
friend class Transform;
@@ -42,7 +43,7 @@ public:
// Viewport mode
ViewportMode getViewportMode() const;
- CameraOptions getCameraOptions(const EdgeInsets&) const;
+ CameraOptions getCameraOptions(optional<EdgeInsets>) const;
// Position
LatLng getLatLng(LatLng::WrapMode = LatLng::Unwrapped) const;
@@ -81,6 +82,8 @@ public:
// Conversion
ScreenCoordinate latLngToScreenCoordinate(const LatLng&) const;
LatLng screenCoordinateToLatLng(const ScreenCoordinate&, LatLng::WrapMode = LatLng::Unwrapped) const;
+ // Implements mapbox-gl-js pointCoordinate() : MercatorCoordinate.
+ TileCoordinate screenCoordinateToTileCoordinate(const ScreenCoordinate&, uint8_t atZoom) const;
double zoomScale(double zoom) const;
double scaleZoom(double scale) const;
diff --git a/src/mbgl/programs/gl/hillshade.cpp b/src/mbgl/programs/gl/hillshade.cpp
index b0c2c95aa8..18dd5a4caa 100644
--- a/src/mbgl/programs/gl/hillshade.cpp
+++ b/src/mbgl/programs/gl/hillshade.cpp
@@ -16,8 +16,8 @@ template <>
struct ShaderSource<HillshadeProgram> {
static constexpr const char* name = "hillshade";
static constexpr const uint8_t hash[8] = { 0x8a, 0x11, 0x29, 0x18, 0x52, 0x7f, 0x3b, 0xbb };
- static constexpr const auto vertexOffset = 29113;
- static constexpr const auto fragmentOffset = 29284;
+ static constexpr const auto vertexOffset = 29125;
+ static constexpr const auto fragmentOffset = 29296;
};
constexpr const char* ShaderSource<HillshadeProgram>::name;
diff --git a/src/mbgl/programs/gl/hillshade_prepare.cpp b/src/mbgl/programs/gl/hillshade_prepare.cpp
index 1aef64293b..81f0296763 100644
--- a/src/mbgl/programs/gl/hillshade_prepare.cpp
+++ b/src/mbgl/programs/gl/hillshade_prepare.cpp
@@ -15,7 +15,7 @@ struct ShaderSource;
template <>
struct ShaderSource<HillshadePrepareProgram> {
static constexpr const char* name = "hillshade_prepare";
- static constexpr const uint8_t hash[8] = { 0xe6, 0x01, 0xf2, 0xbb, 0xa0, 0x77, 0x1d, 0xeb };
+ static constexpr const uint8_t hash[8] = { 0xbd, 0xa0, 0x8a, 0x88, 0x91, 0xe3, 0x73, 0x66 };
static constexpr const auto vertexOffset = 27698;
static constexpr const auto fragmentOffset = 27991;
};
@@ -68,11 +68,13 @@ varying vec2 v_pos;
uniform vec2 u_dimension;
uniform float u_zoom;
uniform float u_maxzoom;
+uniform vec4 u_unpack;
float getElevation(vec2 coord, float bias) {
// Convert encoded elevation value to meters
vec4 data = texture2D(u_image, coord) * 255.0;
- return (data.r + data.g * 256.0 + data.b * 256.0 * 256.0) / 4.0;
+ data.a = -1.0;
+ return dot(data, u_unpack) / 4.0;
}
void main() {
diff --git a/src/mbgl/programs/gl/line.cpp b/src/mbgl/programs/gl/line.cpp
index 8a04f86a5f..6bc7eb1fb0 100644
--- a/src/mbgl/programs/gl/line.cpp
+++ b/src/mbgl/programs/gl/line.cpp
@@ -16,8 +16,8 @@ template <>
struct ShaderSource<LineProgram> {
static constexpr const char* name = "line";
static constexpr const uint8_t hash[8] = { 0x7f, 0x8e, 0xaa, 0x53, 0x75, 0x78, 0xac, 0x2c };
- static constexpr const auto vertexOffset = 30358;
- static constexpr const auto fragmentOffset = 33355;
+ static constexpr const auto vertexOffset = 30370;
+ static constexpr const auto fragmentOffset = 33367;
};
constexpr const char* ShaderSource<LineProgram>::name;
diff --git a/src/mbgl/programs/gl/line_gradient.cpp b/src/mbgl/programs/gl/line_gradient.cpp
index 189af6dbbc..776258bcdd 100644
--- a/src/mbgl/programs/gl/line_gradient.cpp
+++ b/src/mbgl/programs/gl/line_gradient.cpp
@@ -16,8 +16,8 @@ template <>
struct ShaderSource<LineGradientProgram> {
static constexpr const char* name = "line_gradient";
static constexpr const uint8_t hash[8] = { 0x3f, 0xba, 0xc6, 0x33, 0xcd, 0x86, 0xa2, 0xe8 };
- static constexpr const auto vertexOffset = 34224;
- static constexpr const auto fragmentOffset = 37016;
+ static constexpr const auto vertexOffset = 34236;
+ static constexpr const auto fragmentOffset = 37028;
};
constexpr const char* ShaderSource<LineGradientProgram>::name;
diff --git a/src/mbgl/programs/gl/line_pattern.cpp b/src/mbgl/programs/gl/line_pattern.cpp
index 96da8a4f2a..df34ac572b 100644
--- a/src/mbgl/programs/gl/line_pattern.cpp
+++ b/src/mbgl/programs/gl/line_pattern.cpp
@@ -16,8 +16,8 @@ template <>
struct ShaderSource<LinePatternProgram> {
static constexpr const char* name = "line_pattern";
static constexpr const uint8_t hash[8] = { 0x38, 0x9c, 0x3d, 0xde, 0xb4, 0xe0, 0xd1, 0x61 };
- static constexpr const auto vertexOffset = 37846;
- static constexpr const auto fragmentOffset = 41240;
+ static constexpr const auto vertexOffset = 37858;
+ static constexpr const auto fragmentOffset = 41252;
};
constexpr const char* ShaderSource<LinePatternProgram>::name;
diff --git a/src/mbgl/programs/gl/line_sdf.cpp b/src/mbgl/programs/gl/line_sdf.cpp
index 493cc76d01..cbf659ef3c 100644
--- a/src/mbgl/programs/gl/line_sdf.cpp
+++ b/src/mbgl/programs/gl/line_sdf.cpp
@@ -16,8 +16,8 @@ template <>
struct ShaderSource<LineSDFProgram> {
static constexpr const char* name = "line_sdf";
static constexpr const uint8_t hash[8] = { 0x25, 0x94, 0x7f, 0xad, 0x84, 0xfe, 0x96, 0xad };
- static constexpr const auto vertexOffset = 43595;
- static constexpr const auto fragmentOffset = 47282;
+ static constexpr const auto vertexOffset = 43607;
+ static constexpr const auto fragmentOffset = 47294;
};
constexpr const char* ShaderSource<LineSDFProgram>::name;
diff --git a/src/mbgl/programs/gl/raster.cpp b/src/mbgl/programs/gl/raster.cpp
index ce46b1f299..5743348c9f 100644
--- a/src/mbgl/programs/gl/raster.cpp
+++ b/src/mbgl/programs/gl/raster.cpp
@@ -16,8 +16,8 @@ template <>
struct ShaderSource<RasterProgram> {
static constexpr const char* name = "raster";
static constexpr const uint8_t hash[8] = { 0x40, 0x3d, 0x6c, 0xf4, 0xd0, 0x41, 0x51, 0x0e };
- static constexpr const auto vertexOffset = 48827;
- static constexpr const auto fragmentOffset = 49176;
+ static constexpr const auto vertexOffset = 48839;
+ static constexpr const auto fragmentOffset = 49188;
};
constexpr const char* ShaderSource<RasterProgram>::name;
diff --git a/src/mbgl/programs/gl/shader_source.cpp b/src/mbgl/programs/gl/shader_source.cpp
index 6e61578b5e..5d0e377d96 100644
--- a/src/mbgl/programs/gl/shader_source.cpp
+++ b/src/mbgl/programs/gl/shader_source.cpp
@@ -12,453 +12,454 @@ namespace gl {
constexpr const uint8_t compressedShaderSource[] = {
0x78, 0xda, 0xed, 0x3d, 0xfd, 0x6f, 0xe3, 0x36, 0xb2, 0xf7, 0x73, 0xfe, 0x0a, 0x17, 0x05, 0x0e,
0x92, 0x2c, 0x5b, 0xb6, 0x93, 0xec, 0x47, 0x75, 0x7a, 0xc5, 0xa2, 0xbb, 0xed, 0x0b, 0xd0, 0xee,
- 0x2e, 0x36, 0xed, 0xbd, 0xc3, 0x15, 0x0b, 0x43, 0xb2, 0x65, 0x47, 0xef, 0x6c, 0xcb, 0x4f, 0x56,
- 0x12, 0x3b, 0x87, 0xfc, 0xef, 0x8f, 0x33, 0xfc, 0x10, 0x49, 0x51, 0xf2, 0x47, 0x62, 0x27, 0x9b,
- 0x33, 0x8a, 0x6e, 0x2c, 0x72, 0x38, 0x1c, 0x92, 0xc3, 0xe1, 0xcc, 0x90, 0x1c, 0x7e, 0x9f, 0x8c,
- 0x86, 0xf1, 0xa8, 0xf1, 0xcb, 0xaf, 0xfd, 0x0f, 0x97, 0x27, 0xf3, 0x2c, 0x1e, 0x24, 0x8b, 0x24,
- 0x9d, 0x35, 0xae, 0x92, 0xf1, 0xd5, 0xbc, 0x31, 0x9a, 0xa4, 0x61, 0xee, 0x9f, 0x7c, 0x1f, 0x4f,
- 0x16, 0xf1, 0xc9, 0xf7, 0xc9, 0xa8, 0xf1, 0x1d, 0x81, 0x4d, 0x66, 0xf1, 0xd0, 0x9a, 0xa4, 0xb7,
- 0x73, 0xfb, 0xe4, 0x7b, 0xfa, 0xd9, 0x80, 0x2f, 0x02, 0x35, 0x1b, 0x26, 0x23, 0x15, 0x6c, 0x1a,
- 0x0f, 0x93, 0xeb, 0xa9, 0x04, 0xc9, 0x12, 0x8c, 0xc0, 0x58, 0x67, 0x01, 0x8a, 0x9f, 0x02, 0x90,
- 0xfe, 0xb9, 0x89, 0x07, 0xbd, 0xc6, 0xf5, 0x6c, 0x1e, 0x0e, 0xfe, 0xd5, 0x47, 0xe2, 0xac, 0x41,
- 0x3a, 0x5b, 0xe4, 0x94, 0xd0, 0x06, 0x24, 0xc7, 0xc3, 0xbf, 0x87, 0x93, 0xeb, 0xd8, 0x6e, 0xfc,
- 0x3b, 0x99, 0xf1, 0x94, 0x8b, 0x59, 0x8e, 0x89, 0x01, 0x49, 0xb2, 0x64, 0x20, 0x1f, 0x60, 0x6e,
- 0x3a, 0x81, 0x0a, 0xe6, 0xf5, 0xce, 0x5f, 0xf9, 0x59, 0x9c, 0x5f, 0x67, 0xb3, 0x06, 0x54, 0x68,
- 0xdd, 0x74, 0x5c, 0x15, 0xa2, 0x75, 0xd3, 0x71, 0x08, 0x90, 0xed, 0xdf, 0xcb, 0x04, 0xa5, 0xe4,
- 0xdf, 0x24, 0x5f, 0x19, 0x48, 0xfa, 0x44, 0x73, 0x18, 0x51, 0xe4, 0x7f, 0x96, 0x20, 0x11, 0xc4,
- 0x41, 0xbc, 0x9e, 0x52, 0x35, 0x6d, 0x64, 0x51, 0xc2, 0xf6, 0xba, 0xbd, 0xd7, 0xed, 0x8e, 0x3b,
- 0x4d, 0x87, 0x6a, 0x41, 0xb7, 0xd7, 0xee, 0xd8, 0x94, 0xa0, 0xb3, 0xc6, 0x30, 0x1e, 0xa4, 0xc3,
- 0xb8, 0x3f, 0x48, 0x27, 0x69, 0xc6, 0xc8, 0x41, 0x42, 0xe3, 0x19, 0xa4, 0x0f, 0x7f, 0x82, 0x74,
- 0x42, 0x4c, 0x51, 0xd1, 0x99, 0xa5, 0x74, 0xaa, 0x0c, 0xf7, 0x67, 0xe7, 0x2b, 0x21, 0xea, 0xfc,
- 0x9c, 0x54, 0x5a, 0x0d, 0xd3, 0xe5, 0x30, 0x27, 0x84, 0x04, 0xda, 0x72, 0x06, 0x3c, 0x4d, 0x96,
- 0x7d, 0x6c, 0x89, 0x44, 0x86, 0x34, 0x04, 0xae, 0xdc, 0x59, 0x79, 0x41, 0x13, 0x29, 0x26, 0x8f,
- 0x14, 0x21, 0xc2, 0x95, 0x3f, 0xbb, 0x5f, 0xdd, 0x9c, 0x37, 0x56, 0xaa, 0x48, 0x6b, 0xf0, 0x19,
- 0xab, 0x09, 0x69, 0x5c, 0x94, 0xaa, 0x42, 0x88, 0x69, 0x32, 0xc3, 0xec, 0x40, 0xe9, 0x33, 0xa4,
- 0x58, 0x2e, 0x5c, 0x10, 0xc0, 0xbe, 0x49, 0x8b, 0x6d, 0x9f, 0x62, 0x08, 0x97, 0x1b, 0x61, 0xe8,
- 0x69, 0x18, 0x4e, 0x01, 0x83, 0xd4, 0x5c, 0x4e, 0x89, 0xcb, 0x11, 0xf2, 0x26, 0xf6, 0x1a, 0xe3,
- 0x38, 0xef, 0xcf, 0xc3, 0x3c, 0x8f, 0xb3, 0x59, 0x7f, 0x9e, 0x2e, 0x94, 0xbe, 0x4c, 0x96, 0xf1,
- 0x84, 0xd4, 0x99, 0x66, 0xc3, 0xfe, 0xf5, 0x7c, 0x1e, 0x67, 0x6e, 0x45, 0x26, 0x99, 0xa3, 0x5a,
- 0x26, 0x43, 0xb8, 0x48, 0xee, 0xb4, 0x61, 0x48, 0x26, 0x71, 0xff, 0x7a, 0x96, 0xe4, 0x8b, 0x7e,
- 0x9e, 0xf6, 0x11, 0xc7, 0x42, 0x29, 0x98, 0x2e, 0x68, 0xef, 0xf5, 0x1a, 0xe9, 0x68, 0xb4, 0x88,
- 0xf3, 0x00, 0xb8, 0x91, 0xff, 0x5f, 0x26, 0x48, 0xae, 0xc8, 0x86, 0x79, 0xd3, 0xee, 0x98, 0xd2,
- 0x9a, 0x65, 0x6a, 0x15, 0x28, 0xde, 0x57, 0x96, 0x89, 0x3e, 0x87, 0x10, 0xd5, 0xa4, 0xd4, 0xd8,
- 0x9e, 0x5c, 0xcc, 0xbf, 0x3f, 0xf9, 0xcb, 0xf7, 0x66, 0x19, 0xc7, 0x64, 0xd1, 0xf3, 0x93, 0x72,
- 0x7f, 0x21, 0xf4, 0x67, 0x49, 0x74, 0x9d, 0xc7, 0xb4, 0xc3, 0x43, 0x18, 0x74, 0x9f, 0xb4, 0x78,
- 0x94, 0x66, 0x53, 0xc2, 0x6f, 0x39, 0x61, 0xfa, 0x3e, 0xf9, 0x93, 0x25, 0x4b, 0xff, 0x26, 0x4d,
- 0x86, 0x24, 0x29, 0x99, 0x59, 0x64, 0x4c, 0xc6, 0x93, 0xfe, 0xe7, 0x74, 0x91, 0xe4, 0xa4, 0x75,
- 0x01, 0x87, 0x70, 0x70, 0x7a, 0x23, 0x0a, 0xb7, 0xe3, 0x76, 0x6d, 0xe8, 0x10, 0x8e, 0x8a, 0xce,
- 0x1f, 0xca, 0xb1, 0x02, 0x3f, 0x9b, 0xbe, 0x5c, 0x9c, 0x95, 0x6a, 0xf8, 0x39, 0x0b, 0xc7, 0x94,
- 0xe1, 0x59, 0x49, 0xa7, 0x80, 0x3d, 0x61, 0x5d, 0xfd, 0xe9, 0xef, 0x1f, 0xbe, 0xbc, 0xff, 0xf2,
- 0xee, 0x7f, 0xfa, 0x17, 0x1f, 0x2f, 0x3f, 0x7f, 0xf8, 0xe9, 0xf7, 0x4f, 0x5f, 0x4e, 0x94, 0x92,
- 0x48, 0x53, 0x97, 0x48, 0x2c, 0x9f, 0xb7, 0x59, 0xa2, 0x4a, 0x6d, 0xa0, 0x44, 0x2b, 0x91, 0xb4,
- 0x7d, 0x79, 0x6c, 0xfb, 0x61, 0x6d, 0x6e, 0x54, 0xca, 0xd5, 0x59, 0xb3, 0x0e, 0x00, 0x39, 0xb0,
- 0xd4, 0x29, 0x8b, 0x41, 0x38, 0x91, 0xeb, 0x55, 0xd3, 0xa3, 0x52, 0xba, 0x89, 0x57, 0x7d, 0xe3,
- 0xf0, 0xde, 0x84, 0xd9, 0x2a, 0x99, 0x8d, 0x69, 0xd2, 0x0d, 0x24, 0x91, 0x6a, 0x0c, 0x89, 0xd1,
- 0x0e, 0x43, 0xce, 0xd0, 0x05, 0xba, 0x1c, 0x31, 0x74, 0x89, 0x6b, 0xe8, 0x05, 0x57, 0xb4, 0xdb,
- 0xd1, 0x07, 0xc0, 0x35, 0x37, 0xd1, 0xc5, 0xca, 0x79, 0xc5, 0xd1, 0x83, 0x2b, 0x8e, 0xf4, 0x8a,
- 0xa3, 0x35, 0x15, 0xab, 0x4c, 0x2e, 0xb3, 0x46, 0x3e, 0xa9, 0x66, 0x9b, 0x28, 0xab, 0xce, 0x23,
- 0xe5, 0xa2, 0x9a, 0x72, 0xa5, 0xbc, 0x3c, 0x5e, 0xa2, 0xfc, 0xd1, 0x39, 0x62, 0x2a, 0xf1, 0xb4,
- 0x3e, 0xd5, 0x78, 0xfa, 0x22, 0x9c, 0xce, 0x27, 0x71, 0xd6, 0x7b, 0x4f, 0xf2, 0x92, 0x69, 0x38,
- 0x8e, 0x77, 0xe5, 0x0e, 0xcc, 0x41, 0x0c, 0xd8, 0xab, 0x28, 0xa8, 0x59, 0x69, 0x17, 0xa7, 0x1f,
- 0x17, 0xe8, 0x01, 0xac, 0x40, 0x6a, 0x27, 0x79, 0xa2, 0x0d, 0xae, 0xda, 0x43, 0x52, 0x46, 0x81,
- 0x9a, 0x2d, 0x86, 0x28, 0x10, 0xba, 0x01, 0xc9, 0x27, 0xb2, 0x3a, 0xee, 0xbd, 0xb7, 0x58, 0x03,
- 0x5c, 0xca, 0x0e, 0x2a, 0x39, 0x84, 0x31, 0x0a, 0x82, 0x22, 0x95, 0xa0, 0x5e, 0x99, 0xa2, 0xa8,
- 0x8a, 0xa2, 0xc8, 0x48, 0x51, 0x3f, 0x92, 0x69, 0xea, 0x99, 0x69, 0xea, 0xd9, 0xbe, 0x22, 0x98,
- 0xa0, 0x52, 0xda, 0x06, 0x97, 0x16, 0x73, 0x71, 0xc4, 0xec, 0xc3, 0xc8, 0xb8, 0x28, 0x4d, 0x27,
- 0x42, 0x98, 0xdc, 0x26, 0xf9, 0x15, 0x01, 0x98, 0xeb, 0xb9, 0xf3, 0x24, 0x1f, 0x5c, 0x95, 0x73,
- 0x19, 0xdb, 0x91, 0x46, 0x66, 0xd7, 0x44, 0x0b, 0x41, 0x1c, 0x22, 0x13, 0x96, 0x2e, 0xc1, 0x6d,
- 0xc3, 0xf8, 0x26, 0x19, 0xc4, 0x6c, 0xb6, 0x65, 0x21, 0x11, 0x1d, 0x02, 0x4e, 0x52, 0xfb, 0x61,
- 0x5d, 0x08, 0xa7, 0x71, 0x16, 0xc2, 0xe4, 0x1a, 0xc4, 0x33, 0xd2, 0xd9, 0xfd, 0x61, 0xb2, 0xc8,
- 0xc3, 0xd9, 0x20, 0x5e, 0x2b, 0xc1, 0x4e, 0x09, 0x3b, 0x0e, 0xc3, 0x3c, 0xc4, 0xce, 0x9a, 0x41,
- 0x6f, 0xfd, 0xf7, 0xbb, 0xcb, 0xfe, 0x1f, 0x1f, 0x2f, 0x7e, 0xfe, 0xf4, 0xe5, 0xb7, 0x3e, 0x5b,
- 0x37, 0x4e, 0x8c, 0xd4, 0x61, 0x56, 0x3f, 0x97, 0xaa, 0xa0, 0x44, 0xe1, 0x50, 0x86, 0x6c, 0xad,
- 0xe2, 0x55, 0x49, 0x59, 0x34, 0x83, 0xad, 0xe2, 0x6a, 0x7b, 0x94, 0x65, 0x4e, 0x5a, 0x94, 0x0d,
- 0x84, 0x65, 0x21, 0x59, 0xb9, 0x17, 0x66, 0xca, 0x68, 0x9e, 0x42, 0x1a, 0x57, 0x21, 0x58, 0x2f,
- 0x50, 0x08, 0x41, 0x9d, 0xa2, 0x60, 0x34, 0x58, 0xa6, 0x46, 0xa1, 0x0a, 0xc3, 0x2b, 0x59, 0x43,
- 0x65, 0x34, 0xb9, 0xae, 0xe8, 0x3d, 0xc8, 0x51, 0x28, 0xc4, 0x5c, 0x46, 0x1e, 0x64, 0x0a, 0xe2,
- 0xa4, 0x62, 0x98, 0xae, 0xd1, 0x55, 0xc2, 0xba, 0x86, 0x24, 0x36, 0x3b, 0xcc, 0xe5, 0x59, 0x66,
- 0x25, 0x61, 0x42, 0xd5, 0x28, 0xd3, 0x56, 0xcc, 0xba, 0x6a, 0xf2, 0x24, 0x98, 0x1a, 0x0a, 0x17,
- 0x79, 0x96, 0xfe, 0x2b, 0xae, 0x63, 0x3d, 0x19, 0xa2, 0x9a, 0x03, 0x65, 0x28, 0x13, 0x23, 0x2a,
- 0xf9, 0x75, 0xfc, 0xa8, 0x03, 0xae, 0xa7, 0xfd, 0x36, 0x19, 0xe6, 0x57, 0xb5, 0xb4, 0x23, 0x44,
- 0x1d, 0x8b, 0xca, 0x70, 0x15, 0x8c, 0xaa, 0x80, 0xac, 0x61, 0x57, 0x1d, 0x76, 0x7d, 0x1b, 0x6a,
- 0x19, 0x45, 0x85, 0xa9, 0xe4, 0x17, 0x15, 0xcc, 0xc4, 0x36, 0x1a, 0x44, 0x1d, 0xf7, 0x94, 0x41,
- 0xa9, 0xab, 0x41, 0xac, 0xa3, 0xf0, 0x8b, 0xac, 0xa5, 0xb5, 0xa2, 0x6c, 0x40, 0x15, 0x62, 0xdd,
- 0x14, 0x65, 0xf2, 0xca, 0x15, 0x62, 0xcd, 0xe6, 0xa4, 0xe8, 0x92, 0x2b, 0xd8, 0x4a, 0x3e, 0xd1,
- 0x3f, 0x81, 0x6e, 0x63, 0x73, 0x09, 0xe4, 0x16, 0xc2, 0x4a, 0x54, 0x68, 0x12, 0x46, 0xc1, 0x36,
- 0xf2, 0x06, 0xfe, 0x31, 0xd4, 0x08, 0xc9, 0x2e, 0x17, 0x3c, 0xa2, 0x36, 0x4d, 0xba, 0x04, 0x5b,
- 0xc9, 0x10, 0xf6, 0xd7, 0x50, 0x19, 0xcb, 0x71, 0x25, 0x91, 0x62, 0xaa, 0x52, 0x20, 0xd8, 0x45,
- 0x34, 0xc8, 0x1f, 0xa6, 0x11, 0x95, 0xf3, 0x5d, 0x5d, 0x68, 0x98, 0xc6, 0x57, 0x45, 0xb8, 0xf3,
- 0xb4, 0x97, 0x3f, 0x0c, 0x5d, 0x23, 0x67, 0xbb, 0xba, 0x3c, 0xa8, 0xe0, 0x02, 0x15, 0xe5, 0x03,
- 0x26, 0xb3, 0xfa, 0x59, 0x4d, 0x5d, 0x31, 0x7e, 0xfa, 0x4c, 0x37, 0x0d, 0xa3, 0x8e, 0xb5, 0x72,
- 0xaa, 0xa2, 0x6f, 0x8b, 0x2a, 0x3e, 0x01, 0x56, 0x08, 0x6a, 0x25, 0xb5, 0x7f, 0xc0, 0x2d, 0xe6,
- 0x90, 0x7f, 0x5a, 0x85, 0x76, 0x39, 0x48, 0xb2, 0x01, 0xd1, 0xaf, 0xa8, 0x4e, 0x13, 0x90, 0xaa,
- 0x70, 0x58, 0x09, 0xb0, 0xd3, 0x69, 0x9f, 0xdb, 0x3e, 0x31, 0xd6, 0x2d, 0x5d, 0xcb, 0xe2, 0xaa,
- 0xf4, 0x20, 0xcd, 0x66, 0x44, 0x0f, 0x9a, 0x73, 0x8b, 0x4b, 0x41, 0xc5, 0x4a, 0xaa, 0xda, 0x1b,
- 0x29, 0xa9, 0x15, 0x6a, 0x06, 0x8c, 0x54, 0xc7, 0xa2, 0x93, 0xaf, 0x29, 0xf7, 0x3b, 0x68, 0x9a,
- 0xaa, 0x0e, 0x77, 0xdf, 0x80, 0x7e, 0x61, 0xee, 0xaa, 0x79, 0x96, 0xfe, 0x6f, 0x3c, 0xc8, 0xe3,
- 0x21, 0x27, 0x5f, 0xb5, 0xf9, 0x14, 0x7a, 0xa8, 0xed, 0xf7, 0xb0, 0xda, 0x1d, 0x4b, 0xaf, 0xb1,
- 0x7d, 0xeb, 0xd5, 0x68, 0x86, 0xc4, 0xf2, 0xaa, 0xb6, 0x48, 0x35, 0x52, 0x98, 0x3b, 0x82, 0x35,
- 0xaf, 0xa6, 0x58, 0xb9, 0x51, 0x15, 0x3d, 0x2d, 0xe1, 0x68, 0x2f, 0x57, 0xdb, 0x36, 0xb5, 0x4e,
- 0xe1, 0x35, 0x50, 0xb9, 0x43, 0x0d, 0x72, 0xe9, 0x5b, 0xff, 0xfe, 0x5e, 0xe2, 0xf5, 0x70, 0x96,
- 0x27, 0xe1, 0x24, 0x09, 0x17, 0x28, 0x2e, 0x09, 0xb3, 0x7a, 0x26, 0x45, 0xdd, 0x33, 0xd6, 0xe3,
- 0x53, 0x65, 0x1b, 0x58, 0xff, 0xd4, 0x62, 0x35, 0xb6, 0x97, 0x2e, 0xff, 0xb5, 0x72, 0x15, 0xe4,
- 0x68, 0x1c, 0x6f, 0xad, 0xab, 0xef, 0x5b, 0xe3, 0x3e, 0x8c, 0xce, 0xbc, 0x67, 0xe5, 0xf7, 0x70,
- 0xfa, 0xeb, 0x53, 0xe8, 0x9d, 0x4f, 0xa9, 0x2d, 0xee, 0x59, 0xc5, 0x63, 0xea, 0x5d, 0x15, 0xf3,
- 0x6f, 0xa2, 0xac, 0x55, 0x72, 0xf6, 0xc6, 0x8a, 0x57, 0x05, 0xcf, 0xae, 0x57, 0xa5, 0xaa, 0x19,
- 0x72, 0x53, 0x9d, 0x68, 0x0d, 0xb7, 0x6d, 0xaf, 0xcc, 0xac, 0x61, 0xa5, 0x9d, 0xd4, 0x90, 0xb5,
- 0x4c, 0xf2, 0x60, 0xd5, 0x01, 0xe5, 0x20, 0x91, 0xeb, 0x3e, 0x45, 0xc2, 0x85, 0xf7, 0x24, 0x9e,
- 0x8d, 0x09, 0x65, 0xf4, 0x0f, 0x17, 0xb0, 0xb6, 0x5f, 0x29, 0xbd, 0x19, 0x9e, 0x3b, 0x5f, 0xcb,
- 0x24, 0x6b, 0x28, 0xe6, 0xb7, 0xa6, 0xe1, 0xd2, 0x42, 0xbd, 0x59, 0x13, 0xcc, 0xca, 0x48, 0xf5,
- 0xf3, 0x60, 0x31, 0x4d, 0xd3, 0xfc, 0x6a, 0x91, 0xc7, 0x73, 0xab, 0xd3, 0xee, 0xb8, 0x3a, 0x22,
- 0x57, 0x25, 0x90, 0xaa, 0x38, 0x14, 0x07, 0x53, 0x47, 0x03, 0xb9, 0x2f, 0x1b, 0x7f, 0x6b, 0x10,
- 0x2c, 0xdd, 0xc6, 0x8f, 0xf0, 0xa7, 0xf1, 0x43, 0x43, 0xc2, 0x5e, 0xc2, 0x0c, 0xd5, 0x69, 0xd8,
- 0x29, 0xc3, 0x9a, 0x57, 0x20, 0xcd, 0x8b, 0x26, 0x5a, 0xe0, 0x08, 0x7f, 0x9a, 0xc3, 0x55, 0x3f,
- 0x99, 0x63, 0x1c, 0x4d, 0x2d, 0x94, 0x94, 0xe8, 0x07, 0xf8, 0xd8, 0xf6, 0xbd, 0x7b, 0x52, 0xbd,
- 0x21, 0x52, 0x90, 0xb3, 0xd6, 0xd5, 0xc7, 0x45, 0x93, 0xd9, 0x5f, 0x57, 0xe5, 0x18, 0xe6, 0xe9,
- 0x09, 0xd1, 0x4e, 0x66, 0x0b, 0xc8, 0xd9, 0x64, 0x2f, 0x81, 0xd5, 0x51, 0xb5, 0xc0, 0xdf, 0xc6,
- 0x64, 0x7a, 0xe7, 0x66, 0xc9, 0x49, 0xf3, 0xcc, 0xce, 0x10, 0xa8, 0x8d, 0xe6, 0x6b, 0x6e, 0x10,
- 0x5a, 0x98, 0x65, 0x19, 0x57, 0x22, 0x15, 0xfd, 0x21, 0x7c, 0x72, 0xdb, 0xa9, 0x10, 0x74, 0xb7,
- 0x53, 0xa6, 0xf5, 0x9f, 0x1f, 0xbe, 0x7c, 0x42, 0xb5, 0x0c, 0xb7, 0xb9, 0xbd, 0xee, 0xab, 0x76,
- 0xc7, 0x17, 0x9b, 0x78, 0xbf, 0xbc, 0xfb, 0xe3, 0xf2, 0xb2, 0xff, 0xd3, 0xa7, 0x0f, 0x3f, 0x93,
- 0xa9, 0x75, 0xfa, 0xf6, 0xcd, 0xdb, 0xb3, 0x5e, 0xef, 0x4d, 0xe7, 0xac, 0xd3, 0x3d, 0x3b, 0xed,
- 0xbd, 0xde, 0xd8, 0x93, 0xc0, 0xc6, 0x81, 0xfe, 0x31, 0xd8, 0x50, 0x34, 0xc3, 0x2d, 0x06, 0x45,
- 0x33, 0x36, 0xe5, 0x6e, 0x0f, 0xb6, 0xeb, 0x5b, 0xf3, 0x1a, 0xf5, 0xe8, 0xde, 0x05, 0x76, 0x5a,
- 0x02, 0x79, 0x7d, 0xd8, 0xdf, 0xc8, 0x62, 0xa3, 0x08, 0x2f, 0x83, 0xc5, 0xff, 0x65, 0xb9, 0xd5,
- 0x22, 0xc9, 0xce, 0x24, 0x1d, 0x5b, 0x30, 0x1a, 0x1e, 0x6d, 0xa0, 0x27, 0xcd, 0x06, 0xaf, 0x18,
- 0x08, 0xdb, 0xf6, 0x4e, 0xc9, 0x10, 0x09, 0xe6, 0x0f, 0x2e, 0x1d, 0xbd, 0x62, 0x5f, 0x13, 0xfe,
- 0x5c, 0x97, 0xa7, 0x44, 0x97, 0xec, 0x30, 0x6a, 0x7f, 0xa5, 0x0b, 0x3a, 0xcb, 0x75, 0xb3, 0xb1,
- 0xc9, 0x80, 0xa9, 0x94, 0x30, 0x8a, 0x12, 0x98, 0x99, 0x92, 0x5c, 0x50, 0x67, 0x42, 0x31, 0xa3,
- 0x77, 0x9a, 0xbc, 0x8f, 0x35, 0x01, 0xb7, 0x64, 0xe8, 0x4a, 0xbd, 0x89, 0x91, 0xb5, 0x09, 0x63,
- 0xd2, 0xdc, 0x61, 0xd0, 0x22, 0xdd, 0xe8, 0x90, 0x31, 0xc3, 0xff, 0x87, 0x69, 0x6e, 0x89, 0xb6,
- 0xbb, 0xe2, 0x17, 0xe7, 0x87, 0x9b, 0x70, 0x12, 0x50, 0x34, 0x8e, 0xd4, 0x75, 0x4e, 0x41, 0xb6,
- 0x13, 0x2f, 0xe7, 0xd6, 0x50, 0x5b, 0x96, 0x70, 0xe0, 0x48, 0x51, 0xd8, 0x69, 0xe2, 0xff, 0xdb,
- 0x07, 0xd8, 0xb3, 0xbe, 0x4d, 0xb3, 0xc9, 0x70, 0xd3, 0x5d, 0xdf, 0xad, 0xd6, 0x24, 0x87, 0x21,
- 0x97, 0xb6, 0x79, 0xdb, 0xcb, 0x20, 0xa4, 0x7f, 0xd9, 0xf7, 0x0a, 0xc4, 0x56, 0x8b, 0xa6, 0xad,
- 0x64, 0x06, 0x2c, 0xef, 0x32, 0x9a, 0x72, 0xe8, 0x9a, 0x9c, 0x91, 0x94, 0xea, 0x13, 0x02, 0x6b,
- 0x1a, 0xc1, 0x8e, 0x95, 0x18, 0x76, 0xe0, 0x10, 0xd8, 0x6e, 0x67, 0xd2, 0x46, 0x9d, 0x02, 0x55,
- 0x54, 0xee, 0xa2, 0x94, 0xc8, 0x5d, 0x98, 0x6b, 0xda, 0xb0, 0x3e, 0xe8, 0x10, 0x42, 0x67, 0x13,
- 0xe5, 0xa1, 0x94, 0x18, 0xce, 0x06, 0x57, 0x69, 0x66, 0xce, 0xe3, 0x13, 0xb6, 0x8c, 0x69, 0x12,
- 0x0e, 0x62, 0x03, 0x1f, 0x2c, 0xae, 0x92, 0x51, 0xee, 0x6f, 0xc4, 0x49, 0xf5, 0xda, 0x42, 0xb5,
- 0xfb, 0x82, 0x8f, 0x10, 0x9b, 0x3d, 0x9c, 0x14, 0x3d, 0x79, 0x96, 0xe6, 0x7f, 0x2c, 0x20, 0x5d,
- 0xdb, 0x43, 0x96, 0xfc, 0x4e, 0x9f, 0x53, 0x32, 0xdd, 0x4a, 0xac, 0x58, 0xf4, 0x07, 0xe5, 0x44,
- 0x79, 0xde, 0x17, 0x54, 0x31, 0x28, 0x4e, 0x55, 0xa0, 0x22, 0x6d, 0xdf, 0xaa, 0xc5, 0xd2, 0xc9,
- 0x04, 0xcf, 0xe9, 0xf4, 0xe7, 0x71, 0xb6, 0x98, 0x13, 0xb8, 0xe4, 0x26, 0xa6, 0x5e, 0x90, 0x60,
- 0x30, 0x21, 0x1c, 0x41, 0x86, 0xee, 0xbc, 0x09, 0x32, 0xc3, 0xaa, 0x69, 0xb9, 0x57, 0x59, 0xbb,
- 0x8d, 0x3a, 0xee, 0x19, 0x0c, 0xff, 0x5a, 0xc5, 0x8f, 0x8b, 0x0a, 0xdd, 0xfb, 0x63, 0x89, 0xd1,
- 0x6e, 0xb2, 0x61, 0x5c, 0xe3, 0xf3, 0x71, 0x6a, 0x5a, 0xe5, 0xf3, 0x61, 0x09, 0x38, 0xab, 0xe0,
- 0x14, 0x66, 0x63, 0x52, 0x24, 0xae, 0x64, 0xff, 0xcd, 0x2e, 0x03, 0xca, 0xac, 0x92, 0xc9, 0xfc,
- 0x2a, 0x0c, 0x48, 0xff, 0xf9, 0x46, 0x29, 0x87, 0x8d, 0xe6, 0x0d, 0x77, 0x10, 0x18, 0xbd, 0x6e,
- 0xbc, 0xaa, 0xc6, 0x7f, 0x35, 0x60, 0x2a, 0x9a, 0x14, 0x60, 0xa9, 0x24, 0x4e, 0x57, 0x56, 0xfa,
- 0x9e, 0x16, 0x67, 0x24, 0x19, 0xcb, 0x3b, 0x41, 0xbb, 0xeb, 0xdf, 0x1f, 0x64, 0x16, 0x3e, 0xab,
- 0xe9, 0xa6, 0xa5, 0x6b, 0xdb, 0xc8, 0x9a, 0x22, 0x60, 0x4e, 0xe6, 0x4a, 0xca, 0x71, 0xe6, 0x1a,
- 0x67, 0xae, 0x4c, 0xdf, 0x3c, 0x1c, 0x0e, 0x49, 0x07, 0xf6, 0x47, 0xe1, 0x20, 0x4f, 0xc1, 0xd7,
- 0xda, 0x2b, 0x4d, 0x6c, 0xc1, 0x3f, 0xa5, 0xe9, 0xac, 0x16, 0xde, 0xc7, 0xec, 0xe6, 0xe3, 0x1f,
- 0x84, 0xd1, 0xa2, 0x10, 0x30, 0xed, 0x95, 0x2d, 0x29, 0xb3, 0x05, 0x7d, 0x2a, 0x3d, 0xbe, 0xc6,
- 0x0f, 0xc1, 0x16, 0x3e, 0xee, 0x5a, 0xea, 0x25, 0xb5, 0x41, 0xac, 0xfe, 0x37, 0x04, 0x0a, 0x3d,
- 0xf0, 0xbc, 0xee, 0xe7, 0xc1, 0xf5, 0xba, 0x78, 0x93, 0x54, 0x8b, 0xad, 0x85, 0xdb, 0x60, 0x57,
- 0xa9, 0x36, 0x60, 0xe2, 0xac, 0xc7, 0x8f, 0x43, 0x2b, 0x04, 0x6b, 0x1e, 0x25, 0xad, 0x39, 0x76,
- 0xad, 0xfb, 0xa9, 0xd0, 0x85, 0x1d, 0x13, 0x4e, 0xdf, 0xe0, 0x52, 0xeb, 0x12, 0x8b, 0xd5, 0x08,
- 0xec, 0x19, 0x46, 0x51, 0xb1, 0xe0, 0xf8, 0xa8, 0xd4, 0x55, 0xc5, 0xf9, 0x07, 0x58, 0x2a, 0x1e,
- 0x8e, 0x63, 0xe4, 0x5b, 0xa3, 0xef, 0xa8, 0xd6, 0xc1, 0xd5, 0x52, 0x36, 0x30, 0xa1, 0xa7, 0x5b,
- 0x3a, 0xe6, 0x4a, 0x2f, 0x13, 0x75, 0x3f, 0xde, 0x1f, 0xee, 0xe0, 0xac, 0x61, 0x97, 0x63, 0xed,
- 0x31, 0xd9, 0x2d, 0xe9, 0xfb, 0xd6, 0x4e, 0x4e, 0x3d, 0xa7, 0x03, 0x40, 0x25, 0x03, 0xf5, 0xc9,
- 0xcf, 0x6d, 0x1c, 0xe0, 0x68, 0xc3, 0xa6, 0x3c, 0xfc, 0x24, 0xbb, 0x7c, 0x8f, 0xbc, 0x43, 0xb6,
- 0xe7, 0x9d, 0x9b, 0xad, 0xb6, 0x4f, 0x0c, 0xb6, 0xe8, 0xa3, 0x1c, 0x15, 0xdd, 0x42, 0x56, 0x18,
- 0xfd, 0x0d, 0x06, 0xab, 0xbc, 0x6a, 0x70, 0xae, 0xf3, 0x49, 0x32, 0xab, 0x3d, 0x1a, 0xa7, 0x80,
- 0x54, 0xcb, 0x18, 0x05, 0xcc, 0x24, 0x6b, 0x54, 0x80, 0x3a, 0xae, 0x2a, 0x41, 0xbe, 0x20, 0xd9,
- 0xa3, 0x76, 0xb8, 0xf2, 0x65, 0x92, 0x45, 0x0a, 0x80, 0x5b, 0x1a, 0x0c, 0x93, 0x6c, 0xd2, 0x70,
- 0xee, 0xd4, 0x9b, 0x4f, 0x2d, 0xab, 0x90, 0x67, 0x03, 0x4b, 0xd5, 0xcd, 0x3d, 0x45, 0xe3, 0x6e,
- 0xc2, 0xa4, 0xf1, 0xc0, 0x2b, 0xcc, 0xb9, 0x5e, 0x3d, 0xdb, 0xb0, 0x15, 0xe3, 0x1f, 0x9c, 0x5d,
- 0x0f, 0x27, 0x0c, 0xd5, 0x86, 0xee, 0xc2, 0x27, 0x0f, 0x14, 0x92, 0x85, 0xaa, 0x58, 0xe8, 0xb1,
- 0x64, 0x60, 0x5a, 0x42, 0x0c, 0xa6, 0x19, 0x31, 0x88, 0x56, 0x5c, 0x43, 0xa4, 0xda, 0x3b, 0xf8,
- 0x2d, 0xb5, 0x2d, 0x50, 0xd0, 0xbe, 0x01, 0x8b, 0xae, 0x0a, 0xca, 0x64, 0x3b, 0x16, 0x16, 0xe7,
- 0x52, 0xf8, 0x70, 0x1e, 0xde, 0xc7, 0xbb, 0x6e, 0xc4, 0x4f, 0x6a, 0xa0, 0x75, 0xf3, 0xd0, 0xeb,
- 0x42, 0x9b, 0x4f, 0x87, 0x67, 0x7f, 0x86, 0x9b, 0x5f, 0xfa, 0x18, 0x65, 0xe9, 0xd4, 0x8c, 0x47,
- 0x86, 0x30, 0xd2, 0x0a, 0xcb, 0x94, 0x0c, 0xa4, 0x12, 0xcc, 0x6e, 0x8d, 0x4a, 0xd9, 0x26, 0xa2,
- 0xd9, 0xf0, 0xe8, 0x70, 0x1b, 0x10, 0x9e, 0xa7, 0xf5, 0x64, 0x13, 0x4b, 0x67, 0x1d, 0xd1, 0x79,
- 0x5a, 0x43, 0x32, 0xc9, 0xdc, 0x80, 0x60, 0x0a, 0xb5, 0xf9, 0x72, 0xf5, 0x54, 0xe7, 0x72, 0x95,
- 0xe1, 0x96, 0x3f, 0x82, 0xb0, 0x6f, 0x1a, 0x24, 0x69, 0xeb, 0x57, 0x1d, 0xc5, 0x60, 0xd7, 0xc1,
- 0x2a, 0x7e, 0x06, 0x61, 0xbf, 0xdc, 0xc9, 0xc6, 0x0a, 0x09, 0xac, 0xb9, 0xab, 0xe5, 0x5b, 0xb7,
- 0x70, 0xc3, 0x2a, 0x90, 0x69, 0x82, 0x63, 0x27, 0x0a, 0x04, 0x5c, 0xb5, 0x52, 0x21, 0xee, 0x6e,
- 0x7d, 0x1d, 0x47, 0x14, 0x14, 0x15, 0x99, 0x30, 0x28, 0xf9, 0xa4, 0x3c, 0xf3, 0x80, 0x81, 0xe0,
- 0xf9, 0x82, 0x0e, 0x39, 0x26, 0x64, 0xda, 0x4b, 0xbf, 0xb8, 0xfc, 0xab, 0xe6, 0xf0, 0xd3, 0x30,
- 0x40, 0xc2, 0x25, 0x73, 0x2a, 0xd1, 0x1c, 0x7e, 0xc0, 0x25, 0x4f, 0xd5, 0xf4, 0x5b, 0x7f, 0xb3,
- 0xf5, 0x1d, 0x68, 0x25, 0xc2, 0x7c, 0x3e, 0x09, 0x57, 0xec, 0x3a, 0x21, 0xdd, 0x0b, 0xb6, 0xe4,
- 0x2e, 0x68, 0x2f, 0x5b, 0x72, 0x9f, 0xb5, 0x97, 0xb6, 0x57, 0x90, 0xef, 0xaa, 0xa0, 0x2b, 0x15,
- 0x74, 0x25, 0x83, 0x9a, 0xea, 0x8b, 0xca, 0xf5, 0x45, 0x6a, 0x7d, 0x51, 0x4d, 0x7d, 0x91, 0x5a,
- 0x5f, 0x54, 0xaa, 0xef, 0x81, 0xb7, 0x2e, 0x45, 0x87, 0x3b, 0x6a, 0x27, 0xb9, 0x62, 0x8c, 0x1e,
- 0xeb, 0x9a, 0x25, 0x1b, 0x40, 0xb5, 0x9e, 0xa8, 0xa2, 0x9e, 0x1d, 0x34, 0xb2, 0x35, 0x57, 0x23,
- 0xab, 0x37, 0x22, 0xb9, 0x78, 0x1c, 0x85, 0xc3, 0x78, 0xaf, 0x4b, 0xde, 0xe1, 0x56, 0xad, 0x43,
- 0x2f, 0x37, 0xfb, 0x5c, 0x2b, 0xf6, 0x71, 0xf0, 0x50, 0xe9, 0xac, 0x5d, 0x04, 0x7a, 0x6d, 0x6f,
- 0x7c, 0x73, 0x02, 0x7b, 0xbb, 0x1b, 0xbc, 0x15, 0xf7, 0x77, 0x9f, 0xe8, 0xf6, 0x6e, 0xc5, 0xdd,
- 0xdd, 0x47, 0xbb, 0xb9, 0xbb, 0x67, 0xa3, 0xc2, 0x74, 0x17, 0x18, 0x04, 0x11, 0x73, 0xfd, 0x3b,
- 0x07, 0x0c, 0x7a, 0xf0, 0x3c, 0x2c, 0x89, 0xa3, 0xd9, 0x70, 0x34, 0x1b, 0x8e, 0x66, 0xc3, 0xd1,
- 0x6c, 0xa8, 0x30, 0x1b, 0xfe, 0x99, 0xa6, 0xd3, 0x87, 0x9b, 0x0e, 0x2f, 0xdd, 0x2a, 0x38, 0x48,
- 0xc0, 0x96, 0x5a, 0xd3, 0x41, 0x8c, 0xd3, 0x01, 0xcc, 0x87, 0x52, 0x5d, 0xeb, 0xad, 0x01, 0x45,
- 0xe7, 0x7f, 0x8c, 0x88, 0x28, 0x47, 0xd5, 0xff, 0xa8, 0xfa, 0x1f, 0x55, 0xff, 0x97, 0xa5, 0xfa,
- 0x6f, 0xa8, 0xa8, 0x1f, 0x46, 0x45, 0x3f, 0x25, 0xa9, 0x13, 0x38, 0x8c, 0xae, 0x06, 0x52, 0xe3,
- 0x53, 0x4a, 0x64, 0xcb, 0x1b, 0xb8, 0x8a, 0x2c, 0xc1, 0xdc, 0xe2, 0x06, 0x80, 0x2e, 0x09, 0x6f,
- 0xe2, 0x2c, 0x4f, 0x88, 0x84, 0xed, 0x8f, 0xe1, 0x1c, 0x4d, 0x3c, 0xcb, 0xfd, 0x5a, 0x89, 0xb4,
- 0xfe, 0xf0, 0x24, 0xe8, 0x85, 0x33, 0x52, 0x9e, 0xa0, 0x8c, 0x95, 0x8d, 0xe2, 0x33, 0x22, 0x34,
- 0xf9, 0xd6, 0x8f, 0xf9, 0x16, 0x6d, 0x58, 0x79, 0x4d, 0x96, 0xe4, 0x54, 0xdf, 0x13, 0x82, 0xdc,
- 0xfa, 0x9b, 0x08, 0x1c, 0xa2, 0x46, 0xb4, 0x5d, 0xd5, 0x5c, 0x54, 0xba, 0x5a, 0x73, 0x51, 0xe9,
- 0x6a, 0x83, 0xcb, 0x10, 0x57, 0x9b, 0xdc, 0x98, 0x79, 0xe8, 0x01, 0x9c, 0xcd, 0x4f, 0x52, 0x6c,
- 0xa2, 0x63, 0xe3, 0x78, 0xc8, 0xad, 0x80, 0x04, 0x53, 0x94, 0x0e, 0x92, 0xec, 0xf2, 0x41, 0x32,
- 0xde, 0x1b, 0xa2, 0x05, 0xb7, 0x18, 0x06, 0xb9, 0xf0, 0x55, 0xd5, 0x9d, 0xa5, 0x2b, 0x7e, 0x67,
- 0xe9, 0xaa, 0xee, 0xce, 0x12, 0x2f, 0xbe, 0xcd, 0x08, 0x94, 0x4f, 0x76, 0x3c, 0xe2, 0x21, 0x1e,
- 0x9c, 0xb5, 0x74, 0x86, 0x04, 0xd2, 0x54, 0x21, 0x52, 0xfb, 0xce, 0xc7, 0x8e, 0x82, 0x1b, 0x9c,
- 0xe0, 0x3a, 0x80, 0x0f, 0xdb, 0x67, 0xf4, 0xf3, 0x44, 0xfa, 0xc9, 0xdd, 0x0e, 0x34, 0x3c, 0x26,
- 0xc5, 0xd1, 0x5e, 0xe2, 0xf5, 0xa6, 0xb5, 0x4a, 0x60, 0x8e, 0x07, 0x09, 0x3b, 0x8d, 0x1f, 0x59,
- 0xd7, 0x34, 0x7e, 0xc0, 0xf1, 0x01, 0xd5, 0x50, 0xba, 0xdf, 0x79, 0x83, 0x41, 0x6d, 0xf1, 0x67,
- 0x3b, 0x73, 0x3a, 0xed, 0x5e, 0xb7, 0xf7, 0xaa, 0x49, 0x3f, 0xc7, 0xe4, 0xf3, 0x75, 0xf7, 0xbc,
- 0xc7, 0x3e, 0x23, 0xf2, 0xd9, 0x79, 0xdd, 0xeb, 0xf9, 0x6c, 0x7a, 0xab, 0x47, 0x1a, 0xc5, 0x29,
- 0x59, 0xca, 0xa8, 0xd3, 0x08, 0x64, 0x0c, 0xca, 0x24, 0x01, 0x77, 0xea, 0x16, 0xff, 0x20, 0x28,
- 0xa2, 0x69, 0x06, 0x32, 0xb0, 0xf0, 0xc7, 0x64, 0x70, 0x74, 0x34, 0x9d, 0x91, 0xbe, 0xa3, 0xc7,
- 0x7d, 0xe1, 0x32, 0x0f, 0x6d, 0xbf, 0xd7, 0x7d, 0x75, 0xfa, 0xe6, 0x0c, 0x42, 0xc9, 0x0a, 0x89,
- 0x68, 0x17, 0xd5, 0xcb, 0x25, 0x41, 0xa6, 0x83, 0x24, 0x6e, 0xe9, 0xd2, 0xd1, 0x86, 0xf8, 0xa8,
- 0x34, 0xab, 0xe8, 0x84, 0x66, 0x19, 0x0a, 0x30, 0xba, 0x12, 0x46, 0x1a, 0x34, 0x82, 0x0d, 0xc3,
- 0xaa, 0xf1, 0x5d, 0x00, 0x37, 0x3f, 0x1a, 0xff, 0x96, 0x20, 0x9c, 0x80, 0xd7, 0x58, 0x12, 0xb8,
- 0x76, 0xd3, 0x32, 0xa4, 0x3a, 0xb4, 0x79, 0x56, 0xde, 0x44, 0x36, 0x70, 0xe6, 0xe9, 0xad, 0x45,
- 0xc7, 0xcb, 0xeb, 0x9e, 0x77, 0xd8, 0x39, 0x51, 0x17, 0x5a, 0x42, 0x06, 0x83, 0x7c, 0xbc, 0x7d,
- 0xe3, 0x9a, 0x5b, 0x04, 0xb4, 0x62, 0xf0, 0xde, 0x3e, 0x1b, 0xcc, 0x26, 0xeb, 0x39, 0x3e, 0xb6,
- 0x32, 0x95, 0xf2, 0x5a, 0xd3, 0xce, 0x18, 0x7a, 0xa8, 0xeb, 0x54, 0xc6, 0xce, 0xb2, 0x6d, 0x36,
- 0xb0, 0x0c, 0xf1, 0x58, 0x45, 0x3c, 0xae, 0x46, 0x3c, 0xae, 0x47, 0x3c, 0xd6, 0x10, 0x47, 0x2a,
- 0xe2, 0xa8, 0x1a, 0x71, 0x54, 0x8f, 0x38, 0x52, 0x11, 0x3b, 0x92, 0xee, 0xa8, 0x1e, 0xed, 0x28,
- 0x96, 0xaa, 0x9a, 0xfb, 0xb8, 0xd2, 0x62, 0xf6, 0x6c, 0x3d, 0x74, 0xda, 0x0a, 0xc6, 0x8e, 0xe1,
- 0x1a, 0xfd, 0x77, 0x0f, 0x54, 0x0c, 0xf6, 0xa8, 0xb2, 0x3c, 0x40, 0xe7, 0xd8, 0x7c, 0x2f, 0x07,
- 0x86, 0x9c, 0xd5, 0x3b, 0x7e, 0x04, 0x05, 0x45, 0x09, 0x8d, 0x07, 0xcb, 0x9e, 0x29, 0x3a, 0x88,
- 0x41, 0x6f, 0x29, 0x61, 0x7d, 0x5c, 0xb5, 0x45, 0x26, 0xeb, 0x4a, 0xbd, 0x5e, 0x2d, 0x15, 0x35,
- 0xeb, 0x33, 0x06, 0xdc, 0x47, 0xd7, 0xe8, 0x33, 0x74, 0x8d, 0x22, 0x97, 0x6e, 0xa5, 0xaa, 0x69,
- 0x3c, 0xb9, 0x9d, 0xa6, 0xb6, 0xbd, 0x76, 0x56, 0xe2, 0xb4, 0x60, 0x17, 0x7e, 0x3a, 0xfa, 0x5e,
- 0xbf, 0x9d, 0x23, 0x1b, 0x75, 0x2a, 0x2f, 0xbb, 0x8f, 0x32, 0x1c, 0xc7, 0xe2, 0x06, 0x98, 0x0c,
- 0xf2, 0xf2, 0x9d, 0xb6, 0x8f, 0xa1, 0xf3, 0xd3, 0x9c, 0xbb, 0xa0, 0x42, 0xb7, 0x5f, 0x6b, 0x13,
- 0xdc, 0x89, 0x33, 0x33, 0xe0, 0xf2, 0xe1, 0xb8, 0x03, 0xd8, 0xd0, 0x6c, 0xfc, 0xf5, 0xaf, 0x0d,
- 0xae, 0xd9, 0x06, 0xa0, 0xd8, 0x4a, 0x09, 0x77, 0x04, 0x82, 0x2a, 0xdd, 0x27, 0x3f, 0xd2, 0x75,
- 0xf9, 0xe4, 0x07, 0xfa, 0xb6, 0x84, 0x3c, 0x9e, 0xee, 0x9d, 0xa3, 0x69, 0x20, 0x07, 0x39, 0xbf,
- 0x72, 0x98, 0xd3, 0x2b, 0xac, 0x16, 0xae, 0x3a, 0x54, 0x18, 0x3f, 0x1b, 0x5a, 0x2f, 0xa7, 0x8f,
- 0x61, 0xbd, 0xc0, 0x05, 0xc8, 0x97, 0x62, 0xb2, 0xf0, 0x6e, 0x6d, 0x67, 0x63, 0x61, 0x05, 0x54,
- 0x69, 0xff, 0x88, 0x19, 0xc3, 0xd4, 0x41, 0x53, 0x5c, 0xf6, 0xeb, 0xd4, 0x2e, 0xd9, 0x01, 0x2c,
- 0x0f, 0x6b, 0x91, 0x86, 0x4e, 0x33, 0x07, 0x0e, 0xbd, 0x93, 0xb0, 0x8b, 0x2e, 0xba, 0x5f, 0xa5,
- 0xf2, 0x50, 0x9a, 0xe1, 0xcb, 0xde, 0xba, 0xc0, 0x81, 0x5a, 0xaf, 0x61, 0x55, 0x8e, 0xc2, 0x66,
- 0xda, 0xd2, 0x71, 0xc3, 0xe3, 0xb8, 0xe1, 0xb1, 0xf3, 0x86, 0x07, 0x7b, 0xac, 0x68, 0xc9, 0x9e,
- 0x0f, 0xaa, 0xde, 0xf3, 0x28, 0x6d, 0x8d, 0xb0, 0x12, 0x8e, 0x26, 0xaf, 0xf6, 0xeb, 0x0f, 0x19,
- 0x26, 0x53, 0x58, 0x29, 0xd2, 0x99, 0xbf, 0x59, 0x28, 0x07, 0xd6, 0xec, 0xc7, 0x88, 0x89, 0x23,
- 0xc7, 0x31, 0xa0, 0x11, 0x9e, 0xe6, 0x8b, 0x64, 0x42, 0x60, 0x59, 0x50, 0x55, 0x41, 0x19, 0xbb,
- 0x29, 0x8d, 0x7a, 0xb0, 0x25, 0x65, 0x10, 0xb5, 0x11, 0x14, 0x36, 0x4f, 0x49, 0xe2, 0x67, 0x5f,
- 0x15, 0x52, 0xbd, 0x37, 0xdd, 0xb7, 0x18, 0xae, 0x0a, 0x91, 0x34, 0x59, 0x45, 0x35, 0x4f, 0x0e,
- 0x69, 0xcf, 0xaa, 0x61, 0x97, 0x6e, 0xb3, 0x30, 0x55, 0x77, 0xb3, 0xbe, 0xe6, 0xdd, 0xa5, 0x44,
- 0x52, 0x94, 0xde, 0x1e, 0x09, 0x97, 0x98, 0x4e, 0xbf, 0x89, 0xbe, 0xf5, 0x61, 0x12, 0xdf, 0x80,
- 0x8a, 0x34, 0xb3, 0x58, 0x78, 0x63, 0xc2, 0x91, 0x2e, 0x93, 0x81, 0x49, 0xb8, 0xe0, 0x31, 0x24,
- 0x30, 0xba, 0x6c, 0x99, 0x33, 0xe9, 0x74, 0x72, 0x30, 0x22, 0x9a, 0x78, 0x9d, 0x09, 0x43, 0x1f,
- 0x66, 0x4d, 0xfc, 0x33, 0x66, 0x2f, 0x3b, 0xe1, 0x47, 0x44, 0x3f, 0xe8, 0xbf, 0xb6, 0x47, 0x14,
- 0x52, 0xa2, 0x3d, 0x94, 0x1e, 0x2b, 0xa9, 0x1f, 0x2c, 0x54, 0x46, 0x25, 0xa2, 0xa1, 0x4f, 0x9a,
- 0xa8, 0xcc, 0xb6, 0x58, 0x41, 0xa2, 0x6d, 0x8b, 0x9f, 0x2b, 0xd4, 0xce, 0xb8, 0x66, 0x17, 0x55,
- 0x96, 0xed, 0x54, 0x15, 0x19, 0x54, 0x16, 0x59, 0x5b, 0xdb, 0x70, 0x13, 0x4a, 0x3b, 0x4a, 0x91,
- 0xd8, 0x50, 0x44, 0xce, 0x1f, 0x6d, 0x40, 0x8d, 0x8a, 0x71, 0xbc, 0x09, 0x11, 0x66, 0xfa, 0xaf,
- 0x6a, 0x7a, 0xcb, 0x5c, 0x22, 0xd9, 0x80, 0x3c, 0x73, 0xc9, 0x78, 0x19, 0x8e, 0xc7, 0x31, 0x06,
- 0x9a, 0x80, 0x19, 0x0d, 0x2c, 0xda, 0xf8, 0x5b, 0xa3, 0x87, 0x36, 0x52, 0xa7, 0x7d, 0x46, 0x0c,
- 0x24, 0x91, 0x78, 0xd6, 0x3e, 0xc7, 0xc4, 0xd3, 0x73, 0x92, 0x4a, 0xfe, 0x30, 0x4b, 0x30, 0xce,
- 0x92, 0x1b, 0x66, 0x00, 0x0e, 0x9a, 0x23, 0xf2, 0x5f, 0x62, 0xb7, 0xac, 0xb0, 0x39, 0x24, 0xff,
- 0x8d, 0x6d, 0xd7, 0x1a, 0x37, 0xaf, 0xc8, 0x7f, 0x34, 0x2d, 0x22, 0xff, 0x0d, 0x6c, 0xdb, 0x6b,
- 0x80, 0xea, 0x4b, 0xea, 0x70, 0x2d, 0x8a, 0xbc, 0x25, 0xa6, 0x07, 0x04, 0x56, 0x28, 0x08, 0x6a,
- 0x76, 0xdf, 0xb6, 0x09, 0xcb, 0xf6, 0x5a, 0x14, 0x4c, 0x8f, 0x3d, 0x85, 0xea, 0x2e, 0x0a, 0x1f,
- 0x24, 0xa2, 0xbd, 0x84, 0xb3, 0xef, 0x10, 0xdc, 0xc4, 0xa5, 0xdf, 0x2b, 0xf1, 0xcd, 0x03, 0x8e,
- 0x15, 0x16, 0xc3, 0x1e, 0xc4, 0xf0, 0x13, 0x49, 0x5b, 0x2a, 0x1c, 0x4d, 0xb2, 0xb1, 0x3e, 0xe0,
- 0xd8, 0x7a, 0x09, 0x37, 0x21, 0x15, 0x86, 0x33, 0xe9, 0x4a, 0x00, 0x4f, 0x47, 0xed, 0x4a, 0xf7,
- 0x92, 0x5f, 0x85, 0xc3, 0xf4, 0x56, 0x4f, 0x05, 0xa1, 0x6b, 0x04, 0x0f, 0x07, 0x10, 0x02, 0xa5,
- 0x08, 0xe3, 0xf8, 0xf9, 0xa2, 0x71, 0xda, 0xee, 0x9e, 0x75, 0xcf, 0xdf, 0xf6, 0x5e, 0x9d, 0x9f,
- 0x9e, 0xbf, 0x79, 0xfb, 0xfa, 0xed, 0xe9, 0x89, 0x21, 0xa2, 0x0e, 0x58, 0xa0, 0x95, 0xc1, 0xcc,
- 0x64, 0x8e, 0xb4, 0xe8, 0x6b, 0x78, 0xc4, 0x32, 0x82, 0x80, 0x86, 0xb6, 0x1c, 0xd1, 0x10, 0x57,
- 0x8c, 0x9f, 0x69, 0x04, 0x9a, 0x01, 0x31, 0x76, 0xc1, 0x3e, 0x0b, 0x67, 0x0b, 0xcb, 0x2a, 0x9a,
- 0xfc, 0x67, 0xe7, 0x6b, 0x4b, 0xfa, 0xea, 0x7e, 0xb5, 0x1d, 0x34, 0xf6, 0x58, 0x58, 0x37, 0xbb,
- 0xa9, 0x66, 0x0a, 0xcc, 0x93, 0x74, 0x1e, 0x07, 0x44, 0xe2, 0xce, 0x08, 0x74, 0xef, 0xdc, 0x61,
- 0x47, 0xa3, 0x91, 0x22, 0xdb, 0x93, 0xea, 0x15, 0xe7, 0xa2, 0x31, 0xd6, 0x4b, 0xc0, 0xf8, 0x97,
- 0x9a, 0x99, 0x64, 0x92, 0x21, 0x06, 0xc6, 0xc4, 0x6e, 0x8b, 0xe5, 0xda, 0x64, 0xda, 0x7d, 0xbe,
- 0xc0, 0xfb, 0x1d, 0x3c, 0x4f, 0xb8, 0x33, 0xc0, 0x11, 0xf1, 0x83, 0xdc, 0x46, 0x61, 0x2e, 0x06,
- 0x6c, 0xbc, 0x84, 0xcb, 0x2a, 0xbc, 0x4b, 0xa6, 0xd7, 0x18, 0xec, 0x97, 0xa6, 0xaf, 0x9a, 0x9f,
- 0x2f, 0x7c, 0x49, 0xf7, 0xee, 0xb6, 0xdf, 0xbc, 0x3e, 0x6f, 0x15, 0x81, 0xfd, 0xba, 0xed, 0xd7,
- 0xe7, 0x2c, 0x9f, 0x4c, 0x52, 0xfa, 0x98, 0x27, 0x04, 0x10, 0x12, 0xa5, 0x68, 0x64, 0xc7, 0x4b,
- 0x6c, 0xba, 0x28, 0x86, 0x4d, 0x01, 0x79, 0x41, 0xc6, 0x81, 0x4c, 0x76, 0x74, 0xac, 0x62, 0xef,
- 0xd0, 0x91, 0xf0, 0x8a, 0x54, 0x8e, 0x94, 0x66, 0xd8, 0x0e, 0xff, 0x86, 0x28, 0xb9, 0x50, 0x80,
- 0x93, 0x8d, 0x0c, 0x83, 0xe3, 0x25, 0x55, 0xc8, 0xf7, 0x4d, 0x31, 0x93, 0xed, 0xaf, 0xe2, 0x40,
- 0xd1, 0x14, 0x08, 0x09, 0x46, 0x7f, 0x31, 0xe3, 0xbb, 0x68, 0x56, 0xaf, 0xec, 0x7f, 0x00, 0x16,
- 0xa6, 0x21, 0x54, 0x40, 0xe1, 0xb4, 0xe8, 0xd8, 0x34, 0x59, 0x7f, 0xd9, 0xde, 0xe7, 0x0b, 0x94,
- 0x25, 0x05, 0x37, 0xd1, 0xa0, 0xcc, 0x50, 0x88, 0xd5, 0x4c, 0x9f, 0xcd, 0xa2, 0x33, 0xc1, 0x95,
- 0x98, 0xdf, 0x45, 0x20, 0xa2, 0xaa, 0x10, 0x4e, 0x96, 0x89, 0xaf, 0x27, 0x4a, 0x91, 0x43, 0x72,
- 0x0b, 0x29, 0x2b, 0x4a, 0x15, 0xb7, 0x43, 0xbb, 0x29, 0x7d, 0x3e, 0x4c, 0xb8, 0x89, 0x29, 0x89,
- 0x94, 0x62, 0xd8, 0xe2, 0xf3, 0x37, 0xaf, 0x4f, 0x3b, 0xdd, 0x57, 0x27, 0x26, 0x09, 0xc7, 0x7c,
- 0x91, 0xe5, 0x0d, 0x27, 0x8c, 0x6b, 0x5f, 0xaf, 0xb0, 0x96, 0x23, 0xc1, 0xca, 0x0f, 0x62, 0x31,
- 0x69, 0xa3, 0xbf, 0xe0, 0xb7, 0xe9, 0xbb, 0x5a, 0x9a, 0x7c, 0x63, 0x64, 0x6a, 0xa9, 0x18, 0xf1,
- 0xa6, 0x57, 0x8a, 0x87, 0x34, 0x0e, 0xa7, 0xd3, 0x90, 0x07, 0x38, 0x32, 0x84, 0xf7, 0x04, 0x7d,
- 0x7e, 0x16, 0x2f, 0xd2, 0x51, 0x98, 0x7d, 0x73, 0xc1, 0x62, 0x8e, 0x0f, 0x58, 0xed, 0x70, 0x96,
- 0x74, 0x1c, 0xce, 0x6b, 0x1e, 0x80, 0xe2, 0xb9, 0x75, 0xb1, 0x90, 0x39, 0xcc, 0xba, 0x68, 0xc8,
- 0x32, 0x5c, 0x5d, 0x97, 0xe1, 0x7b, 0xab, 0x15, 0x4d, 0xc2, 0xbc, 0xea, 0x0e, 0xc3, 0xec, 0xfa,
- 0x4e, 0x11, 0x20, 0x35, 0x24, 0xd4, 0x74, 0xc8, 0xda, 0xde, 0xd8, 0xa8, 0x2b, 0xd4, 0x7e, 0x78,
- 0x7e, 0x81, 0x85, 0x5e, 0xfa, 0xd3, 0x4c, 0x82, 0xe9, 0xd5, 0x81, 0xe1, 0xc9, 0x06, 0x42, 0x78,
- 0x96, 0x2b, 0xcf, 0x89, 0x8a, 0x40, 0xd5, 0x05, 0x9a, 0x2d, 0x79, 0x5e, 0x6e, 0x11, 0x7d, 0x03,
- 0xd9, 0xd0, 0x23, 0x98, 0xe1, 0x16, 0x73, 0xc1, 0xd8, 0x1f, 0xac, 0xf4, 0x36, 0xec, 0xae, 0xb6,
- 0xa1, 0xaa, 0x1f, 0x78, 0x27, 0xd4, 0xf7, 0x00, 0x6f, 0xbe, 0xda, 0x76, 0x9a, 0xf7, 0xee, 0xe3,
- 0xef, 0x17, 0xef, 0x7e, 0xbd, 0x78, 0x77, 0x79, 0xf1, 0xf1, 0x97, 0xea, 0x27, 0x69, 0x40, 0xc9,
- 0x57, 0x83, 0x6e, 0x06, 0x21, 0x7f, 0x48, 0xa1, 0xd5, 0xed, 0xbd, 0x21, 0xd9, 0x4c, 0x7b, 0xea,
- 0x8b, 0x6d, 0x81, 0x80, 0x86, 0xfb, 0xa6, 0xcf, 0x24, 0x60, 0x28, 0x47, 0xd0, 0x66, 0x7c, 0x69,
- 0x49, 0x0b, 0x44, 0x84, 0x6d, 0x0a, 0x04, 0xfe, 0x02, 0xbb, 0xc9, 0xbe, 0x6e, 0x9d, 0x57, 0x67,
- 0x2c, 0x4a, 0x78, 0xe1, 0x13, 0x94, 0x22, 0x72, 0xb3, 0x85, 0x96, 0xbe, 0xe7, 0xa4, 0xcc, 0x7a,
- 0xb1, 0xc1, 0x59, 0x40, 0x61, 0x50, 0x71, 0xb0, 0x3c, 0xc4, 0x0e, 0x1a, 0xff, 0xc1, 0xa3, 0x90,
- 0xfb, 0x7c, 0xe5, 0x66, 0x39, 0xbe, 0x60, 0x1b, 0xfe, 0x03, 0x3b, 0x81, 0x19, 0xce, 0xe1, 0x64,
- 0x44, 0x33, 0x8b, 0x1c, 0x36, 0xc8, 0x80, 0xcb, 0x61, 0xe3, 0xcc, 0x35, 0x64, 0x48, 0xe7, 0x58,
- 0x9a, 0x16, 0xff, 0x25, 0x74, 0x6a, 0x79, 0x08, 0xd0, 0xe2, 0x15, 0x8a, 0x62, 0x7a, 0x9d, 0x2b,
- 0x65, 0x45, 0xbd, 0x4e, 0x19, 0x4b, 0x0f, 0xdf, 0x7b, 0x00, 0x25, 0xab, 0x69, 0x15, 0xf4, 0x31,
- 0x3d, 0x9f, 0x3e, 0x06, 0x21, 0x57, 0xa4, 0xf5, 0x19, 0x5e, 0xb0, 0xa4, 0xd5, 0x39, 0x45, 0xe0,
- 0x49, 0xaa, 0x98, 0x68, 0xe2, 0x12, 0x95, 0x72, 0x69, 0x9c, 0xb5, 0xfc, 0x9c, 0x86, 0xa2, 0x26,
- 0xca, 0xed, 0xb5, 0x56, 0x07, 0xed, 0x95, 0x5e, 0x40, 0xff, 0xea, 0xd5, 0x38, 0x62, 0x44, 0x88,
- 0xf2, 0x06, 0x51, 0xa0, 0x5b, 0xd7, 0xee, 0x35, 0x3c, 0x8f, 0xae, 0xbd, 0x89, 0xc5, 0xf9, 0x4f,
- 0xb5, 0x53, 0x81, 0x7e, 0x8f, 0x29, 0x76, 0x7c, 0xcb, 0xaf, 0xee, 0x08, 0x66, 0xf1, 0x94, 0x78,
- 0x4f, 0x29, 0x86, 0xfd, 0x57, 0xaa, 0xcc, 0x18, 0xac, 0x11, 0x1f, 0xa5, 0x22, 0x5d, 0x26, 0x47,
- 0xd2, 0xe4, 0x77, 0x54, 0xe9, 0x4d, 0xd3, 0xca, 0x52, 0xa6, 0x22, 0xa5, 0x4a, 0x4b, 0xd7, 0xee,
- 0x9d, 0x92, 0x8e, 0x0a, 0x46, 0xb9, 0xa4, 0x42, 0x06, 0xeb, 0x09, 0xf4, 0xd6, 0x50, 0xe3, 0x73,
- 0x55, 0x95, 0x7a, 0x5a, 0x28, 0x47, 0xb8, 0xc8, 0xc2, 0xca, 0xbd, 0x9e, 0x2d, 0x95, 0x62, 0x4d,
- 0xfd, 0x35, 0xab, 0xca, 0x26, 0xa5, 0xf8, 0x69, 0xde, 0xab, 0xfa, 0x86, 0xde, 0x91, 0xda, 0x73,
- 0x94, 0xbc, 0xc3, 0xbc, 0x4e, 0x64, 0xba, 0xe4, 0x4d, 0x99, 0xc3, 0x76, 0x38, 0xf3, 0xb4, 0x17,
- 0x7e, 0x41, 0x42, 0x2f, 0xc0, 0xb7, 0x75, 0x9a, 0x55, 0x0b, 0x16, 0x14, 0x93, 0xd9, 0x48, 0xbe,
- 0x1c, 0x4e, 0x6d, 0xe1, 0x29, 0xe9, 0x31, 0xa8, 0xb0, 0x65, 0x89, 0x0a, 0xf2, 0x16, 0xa2, 0xb6,
- 0xdd, 0xa2, 0x4a, 0x0c, 0x4f, 0x6a, 0x7b, 0x98, 0x5e, 0x61, 0x30, 0xef, 0x21, 0x1c, 0x95, 0xb0,
- 0x8c, 0x7f, 0x7b, 0xf7, 0x8f, 0xfe, 0xaf, 0x17, 0x1f, 0x3f, 0xf4, 0xdf, 0x5f, 0x5c, 0xfe, 0xfe,
- 0xee, 0xe3, 0x4f, 0x1f, 0x1a, 0xa7, 0xbd, 0xd7, 0xaf, 0x5e, 0xb7, 0x3b, 0xcf, 0xc6, 0x76, 0xde,
- 0xf4, 0xd1, 0xe9, 0x0a, 0x1b, 0x7b, 0xff, 0xb6, 0x33, 0x11, 0xab, 0xe3, 0x2c, 0x5e, 0x54, 0x06,
- 0x07, 0x39, 0x5a, 0xa9, 0x47, 0x2b, 0xf5, 0xa5, 0x5a, 0xa9, 0x47, 0xbb, 0xf1, 0x68, 0x37, 0xbe,
- 0x30, 0xbb, 0x91, 0x8b, 0xf3, 0x4d, 0x4d, 0x47, 0xaf, 0xb4, 0x84, 0x1e, 0x8d, 0xc9, 0xa3, 0x31,
- 0x79, 0x34, 0x26, 0xbf, 0x29, 0x63, 0x72, 0xe3, 0xbd, 0xe5, 0x9d, 0xcd, 0xcc, 0x07, 0xea, 0x8f,
- 0x2f, 0xc6, 0x54, 0x3c, 0x9a, 0x7b, 0x06, 0x73, 0xaf, 0xe2, 0xdd, 0x32, 0x76, 0x20, 0x00, 0x38,
- 0x5b, 0x65, 0x95, 0xea, 0xf7, 0xcb, 0xf6, 0x63, 0x25, 0x96, 0x6d, 0x40, 0x9e, 0xa3, 0x2c, 0x7c,
- 0xfd, 0xcb, 0x9f, 0xde, 0xfd, 0xfa, 0x01, 0x44, 0xfb, 0xa3, 0xdb, 0x88, 0x6b, 0x76, 0x50, 0x1f,
- 0x66, 0x42, 0x3e, 0xc4, 0x46, 0x2c, 0x76, 0x4f, 0x77, 0x70, 0x32, 0x1d, 0x4d, 0xc3, 0x1d, 0x4c,
- 0xc3, 0x67, 0x60, 0x89, 0x3d, 0x3b, 0xeb, 0xf4, 0xc0, 0xa6, 0xe1, 0xf1, 0x12, 0xe8, 0x33, 0xba,
- 0x04, 0xfa, 0xc2, 0x4d, 0xf0, 0xa7, 0x35, 0x79, 0x9f, 0x9b, 0x03, 0xe0, 0x50, 0x26, 0xf8, 0x7f,
- 0xc2, 0xb5, 0xdc, 0x27, 0x72, 0x33, 0x70, 0xb8, 0xed, 0x36, 0xa9, 0x0d, 0x8a, 0xd6, 0xd1, 0xcf,
- 0x70, 0xf4, 0x33, 0x1c, 0xfd, 0x0c, 0x87, 0xf2, 0x33, 0x14, 0xd3, 0x35, 0x94, 0x95, 0xfe, 0xc7,
- 0xf5, 0x3f, 0x6c, 0x73, 0x05, 0x55, 0x91, 0x75, 0x7a, 0x6c, 0x97, 0xb5, 0x8e, 0x8c, 0xc3, 0x19,
- 0x39, 0x2f, 0xe5, 0x06, 0xe8, 0x7f, 0x82, 0x77, 0xe6, 0x19, 0x5d, 0x25, 0x7d, 0x42, 0xef, 0xd1,
- 0x31, 0x56, 0xf2, 0xcb, 0x7a, 0x41, 0x45, 0xee, 0x6a, 0xb9, 0x7d, 0x6a, 0x9b, 0xdb, 0x4b, 0x47,
- 0xf4, 0x9a, 0xa7, 0x46, 0x1d, 0xd6, 0x00, 0x57, 0x26, 0x9c, 0x91, 0x01, 0x27, 0xa1, 0xda, 0x61,
- 0xfd, 0x5d, 0x87, 0x11, 0x28, 0xf6, 0xbf, 0x31, 0x97, 0x25, 0xc5, 0xb6, 0x24, 0x5d, 0x49, 0xaf,
- 0x34, 0x8b, 0x25, 0xc2, 0x53, 0x7b, 0xba, 0xbd, 0x54, 0xe1, 0xa3, 0x7a, 0xf8, 0x48, 0x85, 0x5f,
- 0xf5, 0xf1, 0xf5, 0xe5, 0xa6, 0xe8, 0x0b, 0xa2, 0x07, 0xb1, 0xcb, 0x72, 0x82, 0x3e, 0xa4, 0xc9,
- 0xd2, 0x6a, 0x5d, 0x35, 0x7b, 0xec, 0x05, 0x19, 0x5b, 0x27, 0x68, 0x55, 0x20, 0x8f, 0x76, 0x41,
- 0x1e, 0x55, 0x23, 0x8f, 0x0a, 0xd6, 0xc0, 0x98, 0x27, 0xdb, 0x5f, 0x30, 0x47, 0x1e, 0x22, 0xbd,
- 0xea, 0x92, 0x96, 0xdb, 0x12, 0xae, 0x68, 0x87, 0xeb, 0xe1, 0x0c, 0x57, 0x44, 0x70, 0x45, 0xb6,
- 0xe2, 0x64, 0x06, 0x5c, 0xc6, 0x2b, 0xe2, 0xa4, 0x52, 0xd7, 0x9c, 0x11, 0xd9, 0xe6, 0xab, 0xe1,
- 0xd4, 0xed, 0xfc, 0x88, 0x4f, 0x59, 0x3c, 0x23, 0xa7, 0xf3, 0xa3, 0x1e, 0x4c, 0x62, 0x83, 0x44,
- 0x9f, 0xbe, 0x0e, 0x4b, 0xaa, 0x1d, 0xe9, 0xf5, 0xfe, 0x4a, 0x4a, 0x37, 0x95, 0x8a, 0x2a, 0x4a,
- 0x45, 0xfb, 0x38, 0x04, 0xc5, 0x52, 0xa1, 0x86, 0xd0, 0x94, 0x18, 0xed, 0x7e, 0xaa, 0xf2, 0x78,
- 0x95, 0xe8, 0x78, 0x48, 0xeb, 0x78, 0x48, 0xab, 0xca, 0x13, 0xcf, 0x87, 0xcc, 0xe0, 0xa6, 0x7b,
- 0x0c, 0x2f, 0x3d, 0xfa, 0x8a, 0x6a, 0xa8, 0x2c, 0xf2, 0x2b, 0xfb, 0xaa, 0x00, 0x31, 0xf1, 0x97,
- 0x94, 0x5b, 0xd7, 0x9b, 0x2a, 0xd8, 0xf1, 0x5e, 0xd4, 0xf1, 0x7c, 0xdb, 0x33, 0x39, 0xdf, 0x76,
- 0x38, 0x77, 0xba, 0x34, 0x15, 0x8b, 0x9f, 0x86, 0x9a, 0x8b, 0x4c, 0x57, 0x9d, 0x9f, 0xa6, 0x26,
- 0xcb, 0x98, 0x4c, 0x93, 0xec, 0xe8, 0xf5, 0x3e, 0x7a, 0xbd, 0x8f, 0x5e, 0xef, 0xa3, 0xd7, 0x7b,
- 0x33, 0xaf, 0x37, 0xaa, 0xff, 0x01, 0x93, 0x43, 0x62, 0xee, 0x3a, 0xba, 0x39, 0xd3, 0x5e, 0x7a,
- 0x92, 0x90, 0x12, 0x83, 0x57, 0x02, 0x5b, 0x35, 0x85, 0xa5, 0x63, 0x33, 0xec, 0xd1, 0x5a, 0xec,
- 0xd1, 0x66, 0xd8, 0x23, 0x09, 0x3b, 0x84, 0x43, 0xdb, 0xf7, 0xc9, 0x40, 0xdd, 0x16, 0x5b, 0x0c,
- 0x47, 0xd8, 0xfd, 0xe5, 0x78, 0x59, 0xc4, 0xa4, 0x7c, 0x66, 0x16, 0xd8, 0xf1, 0x5e, 0x5b, 0xbd,
- 0x0e, 0x70, 0x38, 0x1d, 0x7c, 0xbf, 0x0a, 0xf4, 0xb7, 0x78, 0x55, 0xcf, 0x88, 0xa1, 0xe6, 0xdc,
- 0x43, 0xb9, 0xc7, 0x6b, 0x3b, 0x7c, 0x6b, 0x55, 0xe9, 0x1b, 0x73, 0xc9, 0x12, 0x31, 0x04, 0xb9,
- 0xfd, 0xd0, 0x18, 0x5b, 0x0a, 0x85, 0x89, 0xdd, 0x0e, 0x35, 0xe0, 0xa8, 0x12, 0x38, 0x2a, 0x01,
- 0xa3, 0xf7, 0x50, 0xd4, 0xe2, 0x0a, 0x14, 0x2e, 0x4a, 0x3a, 0xdb, 0xa7, 0xbe, 0xc0, 0x40, 0x79,
- 0x1d, 0xf7, 0xbc, 0x55, 0xc8, 0x47, 0x59, 0x96, 0xd3, 0x08, 0xc6, 0xa6, 0x1c, 0x86, 0x76, 0xff,
- 0x87, 0x5c, 0x37, 0x3a, 0x77, 0x9a, 0x4f, 0xc8, 0x5a, 0x93, 0xc9, 0x4f, 0x63, 0x08, 0xa9, 0x8f,
- 0x6b, 0x4f, 0x45, 0x66, 0x74, 0x3d, 0x1a, 0xc5, 0x59, 0xdd, 0xb3, 0xb9, 0x5b, 0x06, 0x55, 0xeb,
- 0x18, 0xd2, 0xba, 0xbb, 0x46, 0x5a, 0xeb, 0x04, 0x96, 0x65, 0x8e, 0x44, 0xd9, 0x02, 0x3d, 0xda,
- 0x53, 0xe9, 0x6f, 0xd8, 0x10, 0x33, 0x8a, 0x96, 0xec, 0x06, 0x34, 0x30, 0x1f, 0x3c, 0xcf, 0x2e,
- 0x77, 0x00, 0x04, 0x13, 0x2b, 0xba, 0x4a, 0xea, 0x5c, 0x79, 0x03, 0xbb, 0x5f, 0xee, 0x27, 0xfd,
- 0x69, 0x91, 0xd2, 0x62, 0xdb, 0xa9, 0xce, 0xea, 0x6e, 0xdc, 0x4d, 0xa5, 0xd1, 0xc9, 0x20, 0xa2,
- 0x15, 0x51, 0x3a, 0x16, 0x10, 0x02, 0xbc, 0x2e, 0x1b, 0xc4, 0x65, 0x79, 0xe4, 0x43, 0xd2, 0x6d,
- 0x18, 0xdc, 0x4f, 0x7f, 0x6d, 0xa5, 0x70, 0x69, 0xce, 0xf2, 0x2c, 0x5c, 0x98, 0x5e, 0x63, 0x81,
- 0xa7, 0x51, 0x16, 0xf3, 0x64, 0xd6, 0xbf, 0xc5, 0x00, 0xbf, 0x5a, 0xb4, 0xbc, 0x42, 0x30, 0x77,
- 0xca, 0x13, 0xb3, 0x43, 0x43, 0xc4, 0x75, 0xd6, 0x44, 0xa0, 0xed, 0x52, 0xb0, 0x2e, 0x0d, 0xff,
- 0x4d, 0x91, 0xb5, 0x43, 0x6a, 0x21, 0x90, 0x2a, 0x58, 0x42, 0x36, 0x8e, 0x82, 0xe2, 0xa7, 0xc7,
- 0xc1, 0xfc, 0x7b, 0x51, 0xa8, 0xab, 0x17, 0xea, 0x16, 0x85, 0xba, 0x45, 0xa1, 0x2e, 0x14, 0xd2,
- 0xb6, 0x18, 0x28, 0x36, 0x97, 0x05, 0x98, 0xe5, 0xa3, 0xcf, 0x5e, 0x7d, 0x6a, 0x87, 0x72, 0x18,
- 0x6e, 0xec, 0x12, 0x81, 0x17, 0xd0, 0xfa, 0xf0, 0x85, 0xe1, 0xbb, 0x21, 0x74, 0x3a, 0xf9, 0x70,
- 0xd5, 0x1e, 0x83, 0x27, 0x05, 0x6c, 0xb7, 0x22, 0xef, 0x6e, 0xb9, 0xaa, 0xcc, 0x5b, 0xdd, 0x2d,
- 0x45, 0x94, 0xbb, 0xf0, 0x26, 0x26, 0xd2, 0x21, 0x0e, 0xf8, 0x13, 0x49, 0xfc, 0xdd, 0x2b, 0xfe,
- 0xe0, 0x95, 0xed, 0x9d, 0x42, 0x50, 0x52, 0x08, 0x49, 0x6e, 0x31, 0xd8, 0x16, 0xf9, 0x82, 0x60,
- 0x6c, 0xe5, 0xe1, 0x07, 0x82, 0xa1, 0x42, 0x9c, 0x3d, 0x4e, 0x69, 0xf8, 0xe9, 0xf4, 0xa1, 0x43,
- 0x0f, 0x0c, 0x05, 0xd6, 0x3d, 0x6d, 0xa0, 0xce, 0x8a, 0xee, 0xda, 0x04, 0x9b, 0x23, 0x22, 0xbf,
- 0x2b, 0xf0, 0x40, 0x15, 0xee, 0x06, 0x29, 0x9a, 0x84, 0x45, 0x49, 0x41, 0xa3, 0xbf, 0x71, 0x22,
- 0x5d, 0x51, 0x8d, 0x8b, 0x6d, 0x67, 0xc3, 0xe7, 0xf2, 0x80, 0x6d, 0x0f, 0x93, 0xbf, 0xa4, 0x97,
- 0x16, 0x39, 0x9b, 0x32, 0x9f, 0x2f, 0x82, 0x52, 0xe8, 0xc4, 0xf2, 0xce, 0x0d, 0x58, 0xf2, 0xcc,
- 0xa8, 0x36, 0xef, 0xea, 0x28, 0xa9, 0xa7, 0x50, 0x42, 0x98, 0x53, 0xaa, 0xcc, 0xe5, 0x4e, 0x09,
- 0x64, 0x4c, 0x5d, 0x08, 0x45, 0x69, 0x3a, 0x01, 0x21, 0xb3, 0xa0, 0x7b, 0x7b, 0x10, 0xb6, 0xb3,
- 0x8f, 0xc4, 0x86, 0x92, 0xa4, 0xd7, 0x80, 0x46, 0x71, 0x88, 0xb2, 0xb4, 0x04, 0xa7, 0x3e, 0x11,
- 0x88, 0xb0, 0x75, 0x99, 0x15, 0x59, 0x83, 0x70, 0x4a, 0x78, 0x10, 0x4c, 0x3e, 0x08, 0xa1, 0x47,
- 0x24, 0x33, 0x7f, 0x78, 0xa1, 0x02, 0x7e, 0x9e, 0xe4, 0x83, 0x2b, 0x9d, 0xd6, 0x2c, 0xcd, 0xc3,
- 0x3c, 0xee, 0x2f, 0x56, 0xd3, 0x28, 0x9d, 0x54, 0x14, 0xa4, 0x01, 0x03, 0x35, 0x13, 0x48, 0x11,
- 0xe2, 0x83, 0x2b, 0x25, 0x9e, 0x66, 0xc5, 0x06, 0x1a, 0x4d, 0x9d, 0x84, 0x11, 0xd1, 0x80, 0xe6,
- 0x93, 0x70, 0x16, 0x57, 0x40, 0xd0, 0x20, 0xd6, 0x5a, 0x5e, 0xd1, 0xb7, 0x20, 0xdc, 0xf4, 0x64,
- 0x6c, 0x1b, 0x35, 0x59, 0xa7, 0xe1, 0xbc, 0xea, 0x04, 0x55, 0xd9, 0x6c, 0x2a, 0x19, 0x4d, 0xca,
- 0xe0, 0x7f, 0x03, 0x7b, 0x31, 0xcf, 0xe4, 0xd1, 0xf4, 0x42, 0x89, 0x09, 0xe4, 0x29, 0x29, 0xce,
- 0xb6, 0x70, 0x0f, 0xad, 0x9a, 0xcb, 0x4f, 0xc6, 0xa0, 0xda, 0x51, 0x38, 0x13, 0x79, 0x22, 0x8c,
- 0x19, 0x4f, 0x25, 0xa0, 0x32, 0x53, 0x2e, 0xe2, 0xf1, 0x14, 0xe2, 0x46, 0x12, 0xb6, 0x9b, 0xc4,
- 0x41, 0x4b, 0x9b, 0xd4, 0x7f, 0xf6, 0xbe, 0x72, 0x2d, 0x15, 0x86, 0x1d, 0x56, 0xaf, 0xef, 0x2a,
- 0xe6, 0x2e, 0xbc, 0x6a, 0xf2, 0x5d, 0xf5, 0x94, 0x25, 0x9d, 0x8a, 0x54, 0x80, 0x0c, 0xa4, 0x04,
- 0xfd, 0xd9, 0xf9, 0xea, 0xb2, 0x5f, 0xdd, 0xaf, 0x2e, 0x9f, 0xbd, 0xb6, 0x87, 0x21, 0xa8, 0xfd,
- 0xfb, 0x06, 0xf4, 0x59, 0x03, 0x6a, 0x7c, 0x58, 0x85, 0xa2, 0xb2, 0x32, 0xe2, 0xba, 0xa6, 0xac,
- 0x47, 0xcc, 0x44, 0x0a, 0xc3, 0xa7, 0xa6, 0xa9, 0xfe, 0xb4, 0xcf, 0x69, 0x32, 0xcb, 0xd7, 0x45,
- 0x43, 0x67, 0x41, 0xad, 0x85, 0x28, 0x22, 0xf2, 0xe7, 0x2a, 0x2d, 0x44, 0x51, 0xa0, 0x62, 0x6b,
- 0xab, 0xa3, 0xc8, 0xa1, 0xa8, 0x68, 0x09, 0xf4, 0x69, 0xdc, 0xf8, 0xf1, 0xa4, 0x12, 0xb1, 0x57,
- 0x23, 0xff, 0x1a, 0x3f, 0x9c, 0xd4, 0xe4, 0x7a, 0x95, 0x38, 0x15, 0xda, 0x24, 0xcf, 0x17, 0x23,
- 0x8f, 0xda, 0x64, 0x60, 0xa4, 0x80, 0x9b, 0x53, 0xa5, 0x1d, 0xed, 0x2e, 0x70, 0x52, 0xfb, 0xd0,
- 0x93, 0x4e, 0x50, 0x2a, 0xcd, 0x4f, 0x62, 0x11, 0x2d, 0x80, 0x9f, 0xb8, 0x62, 0xa2, 0xac, 0xf1,
- 0x23, 0x72, 0xa9, 0xd7, 0x3b, 0x43, 0x4f, 0x2c, 0x8e, 0x84, 0xc2, 0xea, 0x28, 0x9a, 0xa9, 0xa0,
- 0x06, 0x35, 0x9e, 0xd4, 0xe4, 0x53, 0xfe, 0x52, 0x64, 0x37, 0x57, 0x14, 0xe9, 0xd4, 0xfa, 0xbc,
- 0x76, 0x10, 0x69, 0x18, 0xed, 0x2e, 0x46, 0xf7, 0x16, 0xaf, 0x00, 0x85, 0xfa, 0x78, 0x2d, 0x57,
- 0x5e, 0x69, 0x04, 0x11, 0x32, 0x0a, 0x4c, 0x15, 0x01, 0xbc, 0x31, 0xfd, 0xd6, 0xd7, 0x9b, 0x81,
- 0xa1, 0x80, 0x2d, 0x38, 0xad, 0x85, 0x47, 0xc2, 0xd4, 0x55, 0xc6, 0x85, 0x03, 0x5f, 0x70, 0xaa,
- 0xcc, 0xbf, 0x97, 0xbb, 0x02, 0x67, 0x3b, 0xe1, 0xd5, 0x59, 0x80, 0x11, 0x67, 0x65, 0x19, 0xd0,
- 0xd4, 0xf0, 0xab, 0xfc, 0x49, 0x0b, 0x0e, 0x88, 0x74, 0xc2, 0x38, 0xbb, 0xf5, 0x05, 0xc1, 0xc9,
- 0xdc, 0xe0, 0x9f, 0xac, 0xe3, 0x02, 0xf4, 0x3c, 0x0b, 0x34, 0x2e, 0xfa, 0xf2, 0x05, 0x39, 0xae,
- 0xfe, 0x6b, 0xc0, 0x82, 0x36, 0xcb, 0xde, 0x69, 0x90, 0x8d, 0xa6, 0xd5, 0x4f, 0x8c, 0x89, 0x0c,
- 0x49, 0x3a, 0x52, 0x89, 0xff, 0x23, 0x19, 0x71, 0xf2, 0xea, 0xc8, 0x3c, 0xd6, 0x5a, 0x49, 0x4f,
- 0x4d, 0xb8, 0x6d, 0x6a, 0x8d, 0x71, 0xc4, 0x86, 0x99, 0x77, 0x0a, 0xbb, 0x1f, 0x82, 0x29, 0xa5,
- 0x38, 0xe2, 0x37, 0x4c, 0x24, 0x93, 0x7f, 0x3d, 0x69, 0x01, 0x85, 0xa1, 0x97, 0x97, 0x48, 0xbe,
- 0x96, 0xb0, 0x4f, 0x4b, 0xd5, 0x9e, 0x44, 0x94, 0xf9, 0x42, 0x47, 0x08, 0xe4, 0x7c, 0x22, 0x41,
- 0xd1, 0x9a, 0x80, 0x78, 0xca, 0x8a, 0x26, 0xd1, 0xf8, 0xa1, 0xa5, 0x6a, 0x16, 0xea, 0xc2, 0x2c,
- 0x5e, 0xc8, 0x02, 0x07, 0x09, 0xc4, 0x40, 0x57, 0x90, 0x76, 0xbe, 0x36, 0xa5, 0xa2, 0xb6, 0x5d,
- 0x15, 0x2e, 0x9c, 0x19, 0x49, 0x8f, 0xad, 0x15, 0x1c, 0xee, 0x7c, 0xee, 0x56, 0x8e, 0x34, 0x09,
- 0x88, 0xba, 0x98, 0x18, 0x80, 0xa3, 0xb5, 0x4e, 0xd1, 0xd1, 0x65, 0x3b, 0x92, 0xfd, 0xa6, 0x9e,
- 0x20, 0x9b, 0x1e, 0xf2, 0x3a, 0x2a, 0xfb, 0xfb, 0x53, 0xf6, 0x9f, 0x8d, 0x12, 0xbd, 0x4f, 0x2b,
- 0x62, 0x5b, 0x8b, 0xa6, 0xce, 0xea, 0xa8, 0x57, 0xf6, 0x81, 0x3d, 0x14, 0x4f, 0xd0, 0x29, 0x4b,
- 0xec, 0x56, 0x4d, 0xe8, 0x51, 0x32, 0x99, 0xd4, 0x9d, 0x51, 0x2b, 0xf2, 0xab, 0x0f, 0xaa, 0x15,
- 0x30, 0xa6, 0xd3, 0x6a, 0x52, 0x6e, 0xdd, 0x56, 0x8b, 0x0a, 0x56, 0xf7, 0x80, 0x57, 0x38, 0x49,
- 0xeb, 0x28, 0x2e, 0xf2, 0xab, 0x29, 0x2e, 0x60, 0x4c, 0x14, 0x4b, 0xb9, 0x75, 0x14, 0xab, 0x60,
- 0xdf, 0xf4, 0xb1, 0x36, 0x6c, 0x4a, 0xcd, 0x09, 0xa9, 0x22, 0xbf, 0xfa, 0xc5, 0x5d, 0x01, 0x62,
- 0x7c, 0x75, 0xb7, 0xc8, 0xad, 0x7d, 0x5f, 0x4d, 0x01, 0x5b, 0x47, 0x70, 0xf5, 0x09, 0x46, 0x91,
- 0x5d, 0x4f, 0x6e, 0xd5, 0x59, 0xc6, 0x22, 0x73, 0x2d, 0xb1, 0xca, 0x4e, 0xd0, 0x26, 0x76, 0xaa,
- 0x34, 0xe1, 0x8a, 0x9f, 0xa6, 0x73, 0x5d, 0x45, 0xae, 0xab, 0x4e, 0x43, 0xd3, 0x09, 0x2f, 0x19,
- 0xd5, 0x4e, 0x53, 0xa9, 0xf8, 0x69, 0xa2, 0xa5, 0xc8, 0x75, 0xd5, 0x09, 0x66, 0xa2, 0x45, 0x46,
- 0xb5, 0xfd, 0x24, 0x39, 0xf8, 0x81, 0x30, 0x89, 0xf7, 0x8b, 0x9f, 0xa6, 0x37, 0x7f, 0x45, 0xa6,
- 0xab, 0x4e, 0x08, 0xe3, 0xdb, 0xbf, 0x12, 0xa6, 0x5d, 0xb8, 0x5a, 0xfc, 0xaa, 0x22, 0x84, 0x1d,
- 0xc5, 0x93, 0x18, 0xbd, 0x92, 0x0c, 0xb6, 0x67, 0x69, 0x60, 0xd7, 0xa3, 0x3f, 0xe3, 0xe8, 0xcf,
- 0x38, 0xfa, 0x33, 0x8e, 0xfe, 0x8c, 0xa3, 0x3f, 0xe3, 0x65, 0xf8, 0x33, 0xf8, 0x19, 0xe4, 0xe2,
- 0x44, 0x9c, 0x72, 0x80, 0x8e, 0x32, 0xc1, 0xb3, 0x72, 0x79, 0x14, 0xef, 0x5d, 0x65, 0xf3, 0x74,
- 0x12, 0x42, 0xeb, 0x1f, 0xe0, 0x03, 0x61, 0x06, 0x10, 0x3d, 0xff, 0x46, 0xda, 0xd6, 0x5e, 0xc2,
- 0xd5, 0x2e, 0xbc, 0xa1, 0x46, 0xad, 0x20, 0xba, 0x69, 0x28, 0x75, 0x90, 0x4b, 0x5f, 0x15, 0xad,
- 0xaa, 0x1f, 0xdd, 0x2a, 0xfc, 0x0e, 0xd6, 0xe5, 0xfb, 0x9f, 0xfb, 0x9f, 0xff, 0xd1, 0x78, 0xd3,
- 0xee, 0x9c, 0x94, 0x4d, 0x4d, 0x58, 0x5d, 0xfd, 0x3a, 0x07, 0x8c, 0xd9, 0x18, 0x94, 0x8f, 0xc6,
- 0x6c, 0x7b, 0x3e, 0x4f, 0xb3, 0x73, 0x1f, 0xd3, 0x14, 0x3c, 0xac, 0x19, 0x77, 0x40, 0x13, 0xec,
- 0x50, 0x56, 0xd4, 0x41, 0x4d, 0xa0, 0x7d, 0x5a, 0x30, 0xb5, 0x6c, 0xb2, 0x9d, 0x01, 0x52, 0x6f,
- 0x7f, 0x6c, 0x65, 0x3f, 0xec, 0xe3, 0xbc, 0x9d, 0x34, 0x7a, 0xdb, 0x29, 0xf2, 0x75, 0x43, 0xb3,
- 0xb1, 0x2e, 0x4e, 0x61, 0x3e, 0xbc, 0xff, 0xe5, 0x43, 0xff, 0x97, 0x77, 0xbf, 0xfd, 0xf6, 0x8e,
- 0x68, 0x0c, 0xdd, 0xce, 0xb9, 0x67, 0x0e, 0xde, 0xc7, 0xc5, 0x38, 0x9b, 0xe5, 0xa0, 0x7d, 0x97,
- 0x45, 0x3f, 0x9b, 0xed, 0xe2, 0xf6, 0x3c, 0x2a, 0x8d, 0x3c, 0x71, 0x25, 0x4b, 0x70, 0xde, 0x51,
- 0x2c, 0xb3, 0x50, 0xc4, 0x37, 0x54, 0x7c, 0x8a, 0x28, 0x12, 0x74, 0xd4, 0xa4, 0xe1, 0x97, 0xa5,
- 0x1d, 0x12, 0x17, 0x14, 0x4d, 0xf4, 0x2c, 0x81, 0xdf, 0x51, 0x24, 0xa1, 0xed, 0xcb, 0x27, 0x2e,
- 0xaf, 0x47, 0xa3, 0xc0, 0x42, 0x7d, 0xba, 0x85, 0x37, 0x24, 0x98, 0x6e, 0x2d, 0xb4, 0x75, 0xe8,
- 0x4b, 0x7e, 0x50, 0x27, 0x90, 0xd8, 0x85, 0x56, 0x67, 0x89, 0xae, 0x76, 0xba, 0xed, 0xee, 0x5b,
- 0x8f, 0x0a, 0xf1, 0x66, 0x41, 0x85, 0x5d, 0x43, 0x06, 0xad, 0x1b, 0x6a, 0x2e, 0x46, 0xde, 0x2b,
- 0x16, 0x5e, 0x86, 0xcc, 0xbf, 0x97, 0xc8, 0xc5, 0xe3, 0x82, 0x26, 0x8f, 0x32, 0xf8, 0x93, 0xdb,
- 0x61, 0xb9, 0x43, 0x68, 0x5d, 0xc3, 0x00, 0x3f, 0x1c, 0x79, 0x3d, 0x50, 0x74, 0x21, 0xf4, 0x66,
- 0x4b, 0x07, 0x0c, 0x81, 0xb4, 0x96, 0x8c, 0xc0, 0x85, 0x94, 0xa6, 0x92, 0xb2, 0xe1, 0x69, 0x42,
- 0x47, 0x5d, 0xf1, 0x1e, 0xe4, 0xed, 0xfe, 0x7f, 0xa7, 0x8d, 0x81, 0x68
+ 0x2e, 0x36, 0xed, 0xbd, 0xc3, 0x15, 0x0b, 0x43, 0xb2, 0x15, 0x47, 0xef, 0x6c, 0xcb, 0xcf, 0x56,
+ 0x12, 0x3b, 0x87, 0xfd, 0xdf, 0x1f, 0x67, 0xf8, 0x4d, 0x51, 0xf2, 0x47, 0x62, 0x6f, 0x36, 0x67,
+ 0x14, 0xdd, 0x58, 0xe4, 0x70, 0x38, 0x24, 0x87, 0xc3, 0x99, 0x21, 0x39, 0xfc, 0x3e, 0xbb, 0x1a,
+ 0xa6, 0x57, 0x8d, 0x5f, 0x7e, 0xed, 0xbf, 0xbb, 0x3c, 0x99, 0xcd, 0xd3, 0x41, 0xb6, 0xc8, 0xf2,
+ 0x69, 0xe3, 0x3a, 0x1b, 0x5d, 0xcf, 0x1a, 0x57, 0xe3, 0x3c, 0x2e, 0xc2, 0x93, 0xef, 0xd3, 0xf1,
+ 0x22, 0x3d, 0xf9, 0x3e, 0xbb, 0x6a, 0x7c, 0x47, 0x60, 0xb3, 0x69, 0x3a, 0x74, 0xc6, 0xf9, 0xdd,
+ 0xcc, 0x3d, 0xf9, 0x9e, 0x7e, 0x36, 0xe0, 0x8b, 0x40, 0x4d, 0x87, 0xd9, 0x95, 0x0e, 0x36, 0x49,
+ 0x87, 0xd9, 0xcd, 0x44, 0x81, 0x64, 0x09, 0x56, 0x60, 0xac, 0x53, 0x82, 0xe2, 0xa7, 0x00, 0xa4,
+ 0x7f, 0x6e, 0xd3, 0x41, 0xaf, 0x71, 0x33, 0x9d, 0xc5, 0x83, 0x7f, 0xf5, 0x91, 0x38, 0x67, 0x90,
+ 0x4f, 0x17, 0x05, 0x25, 0xb4, 0x01, 0xc9, 0xe9, 0xf0, 0xef, 0xf1, 0xf8, 0x26, 0x75, 0x1b, 0xff,
+ 0xce, 0xa6, 0x3c, 0xe5, 0x62, 0x5a, 0x60, 0x62, 0x44, 0x92, 0x1c, 0x15, 0x28, 0x04, 0x98, 0xdb,
+ 0x4e, 0xa4, 0x83, 0x05, 0xbd, 0xf3, 0x17, 0xe1, 0x3c, 0x2d, 0x6e, 0xe6, 0xd3, 0x06, 0x54, 0xe8,
+ 0xdc, 0x76, 0x7c, 0x1d, 0xa2, 0x75, 0xdb, 0xf1, 0x08, 0x90, 0x1b, 0x7e, 0x51, 0x09, 0xca, 0xc9,
+ 0xbf, 0x59, 0xb1, 0xb2, 0x90, 0xf4, 0x81, 0xe6, 0x30, 0xa2, 0xc8, 0xff, 0x2c, 0x41, 0x21, 0x88,
+ 0x83, 0x04, 0x3d, 0xad, 0x6a, 0xda, 0x48, 0x59, 0xc2, 0x0d, 0xba, 0xbd, 0x97, 0xed, 0x8e, 0x3f,
+ 0xc9, 0x87, 0x7a, 0x41, 0xbf, 0xd7, 0xee, 0xb8, 0x94, 0xa0, 0xb3, 0xc6, 0x30, 0x1d, 0xe4, 0xc3,
+ 0xb4, 0x3f, 0xc8, 0xc7, 0xf9, 0x9c, 0x91, 0x83, 0x84, 0xa6, 0x53, 0x48, 0x1f, 0xfe, 0x04, 0xe9,
+ 0x84, 0x18, 0x59, 0xd1, 0x99, 0xa3, 0x75, 0xaa, 0x0a, 0xf7, 0x67, 0xe7, 0x33, 0x21, 0xea, 0xfc,
+ 0x9c, 0x54, 0x5a, 0x0d, 0xd3, 0xe5, 0x30, 0x27, 0x84, 0x04, 0xda, 0x72, 0x06, 0x3c, 0xc9, 0x96,
+ 0x7d, 0x6c, 0x89, 0x42, 0x86, 0x32, 0x04, 0xbe, 0xda, 0x59, 0x85, 0xa4, 0x89, 0x14, 0x53, 0x47,
+ 0x8a, 0x10, 0xe1, 0xab, 0x9f, 0xdd, 0xcf, 0x7e, 0xc1, 0x1b, 0xab, 0x54, 0x64, 0x34, 0xf8, 0x8c,
+ 0xd5, 0x84, 0x34, 0x2e, 0x4a, 0x55, 0x21, 0xc4, 0x24, 0x9b, 0x62, 0x76, 0xa4, 0xf5, 0x19, 0x52,
+ 0xac, 0x16, 0x96, 0x04, 0xb0, 0x6f, 0xd2, 0x62, 0x37, 0xa4, 0x18, 0xe2, 0xe5, 0x46, 0x18, 0x7a,
+ 0x06, 0x86, 0x53, 0xc0, 0xa0, 0x34, 0x97, 0x53, 0xe2, 0x73, 0x84, 0xbc, 0x89, 0xbd, 0xc6, 0x28,
+ 0x2d, 0xfa, 0xb3, 0xb8, 0x28, 0xd2, 0xf9, 0xb4, 0x3f, 0xcb, 0x17, 0x5a, 0x5f, 0x66, 0xcb, 0x74,
+ 0x4c, 0xea, 0xcc, 0xe7, 0xc3, 0xfe, 0xcd, 0x6c, 0x96, 0xce, 0xfd, 0x8a, 0x4c, 0x32, 0x47, 0x8d,
+ 0x4c, 0x86, 0x70, 0x91, 0xdd, 0x1b, 0xc3, 0x90, 0x8d, 0xd3, 0xfe, 0xcd, 0x34, 0x2b, 0x16, 0xfd,
+ 0x22, 0xef, 0x23, 0x8e, 0x85, 0x56, 0x30, 0x5f, 0xd0, 0xde, 0xeb, 0x35, 0xf2, 0xab, 0xab, 0x45,
+ 0x5a, 0x44, 0xc0, 0x8d, 0xfc, 0xff, 0x32, 0x41, 0x6a, 0x45, 0x2e, 0xcc, 0x9b, 0x76, 0xc7, 0x96,
+ 0xd6, 0x2c, 0x53, 0xab, 0x41, 0xf1, 0xbe, 0x72, 0x6c, 0xf4, 0x79, 0x84, 0xa8, 0x26, 0xa5, 0xc6,
+ 0x0d, 0xd4, 0x62, 0xe1, 0x97, 0x93, 0xbf, 0x7c, 0x6f, 0x97, 0x71, 0x4c, 0x16, 0x3d, 0x3d, 0x29,
+ 0xf7, 0x17, 0x42, 0xff, 0x3c, 0x4b, 0x6e, 0x8a, 0x94, 0x76, 0x78, 0x0c, 0x83, 0x1e, 0x92, 0x16,
+ 0x5f, 0xe5, 0xf3, 0x09, 0xe1, 0xb7, 0x82, 0x30, 0x7d, 0x9f, 0xfc, 0x99, 0x67, 0xcb, 0xf0, 0x36,
+ 0xcf, 0x86, 0x24, 0x29, 0x9b, 0x3a, 0x64, 0x4c, 0x46, 0xe3, 0xfe, 0xc7, 0x7c, 0x91, 0x15, 0xa4,
+ 0x75, 0x11, 0x87, 0xf0, 0x70, 0x7a, 0x23, 0x0a, 0xbf, 0xe3, 0x77, 0x5d, 0xe8, 0x10, 0x8e, 0x8a,
+ 0xce, 0x1f, 0xca, 0xb1, 0x02, 0x3f, 0x9b, 0xbe, 0x5c, 0x9c, 0x95, 0x6a, 0xf8, 0x79, 0x1e, 0x8f,
+ 0x28, 0xc3, 0xb3, 0x92, 0x9e, 0x84, 0x3d, 0x61, 0x5d, 0xfd, 0xe1, 0xef, 0xef, 0x3e, 0xbd, 0xfd,
+ 0xf4, 0xe6, 0x7f, 0xfa, 0x17, 0xef, 0x2f, 0x3f, 0xbe, 0xfb, 0xe9, 0xf7, 0x0f, 0x9f, 0x4e, 0xb4,
+ 0x92, 0x48, 0x53, 0x97, 0x48, 0xac, 0x90, 0xb7, 0x59, 0xa1, 0x4a, 0x6f, 0xa0, 0x42, 0x2b, 0x91,
+ 0xb4, 0x7d, 0x75, 0x6c, 0xfb, 0x71, 0x6d, 0x6e, 0x52, 0xca, 0x35, 0x59, 0xb3, 0x0e, 0x00, 0x39,
+ 0xb0, 0xd4, 0x29, 0x8b, 0x41, 0x3c, 0x56, 0xeb, 0xd5, 0xd3, 0x93, 0x52, 0xba, 0x8d, 0x57, 0x43,
+ 0xeb, 0xf0, 0xde, 0xc6, 0xf3, 0x55, 0x36, 0x1d, 0xd1, 0xa4, 0x5b, 0x48, 0x22, 0xd5, 0x58, 0x12,
+ 0x93, 0x1d, 0x86, 0x9c, 0xa1, 0x8b, 0x4c, 0x39, 0x62, 0xe9, 0x12, 0xdf, 0xd2, 0x0b, 0xbe, 0x68,
+ 0xb7, 0x67, 0x0e, 0x80, 0x6f, 0x6f, 0xa2, 0x8f, 0x95, 0xf3, 0x8a, 0x93, 0x07, 0x57, 0x9c, 0x98,
+ 0x15, 0x27, 0x6b, 0x2a, 0xd6, 0x99, 0x5c, 0x65, 0x8d, 0x62, 0x5c, 0xcd, 0x36, 0xc9, 0xbc, 0x3a,
+ 0x8f, 0x94, 0x4b, 0x6a, 0xca, 0x95, 0xf2, 0x8a, 0x74, 0x89, 0xf2, 0xc7, 0xe4, 0x88, 0x89, 0xc2,
+ 0xd3, 0xe6, 0x54, 0xe3, 0xe9, 0x8b, 0x78, 0x32, 0x1b, 0xa7, 0xf3, 0xde, 0x5b, 0x92, 0x97, 0x4d,
+ 0xe2, 0x51, 0xba, 0x2b, 0x77, 0x60, 0x0e, 0x62, 0xc0, 0x5e, 0x45, 0x41, 0xcd, 0x4a, 0xfb, 0x38,
+ 0xfd, 0xb8, 0x40, 0x8f, 0x60, 0x05, 0xd2, 0x3b, 0x29, 0x10, 0x6d, 0xf0, 0xf5, 0x1e, 0x52, 0x32,
+ 0x24, 0x6a, 0xb6, 0x18, 0xa2, 0x40, 0xe8, 0x46, 0x24, 0x9f, 0xc8, 0xea, 0xb4, 0xf7, 0xd6, 0x61,
+ 0x0d, 0xf0, 0x29, 0x3b, 0xe8, 0xe4, 0x10, 0xc6, 0x90, 0x04, 0x25, 0x3a, 0x41, 0xbd, 0x32, 0x45,
+ 0x49, 0x15, 0x45, 0x89, 0x95, 0xa2, 0x7e, 0xa2, 0xd2, 0xd4, 0xb3, 0xd3, 0xd4, 0x73, 0x43, 0x4d,
+ 0x30, 0x41, 0xa5, 0xb4, 0x0d, 0x3e, 0x2d, 0xe6, 0xe3, 0x88, 0xb9, 0x87, 0x91, 0x71, 0x49, 0x9e,
+ 0x8f, 0x85, 0x30, 0xb9, 0xcb, 0x8a, 0x6b, 0x02, 0x30, 0x33, 0x73, 0x67, 0x59, 0x31, 0xb8, 0x2e,
+ 0xe7, 0x32, 0xb6, 0x23, 0x8d, 0x9c, 0xdf, 0x10, 0x2d, 0x04, 0x71, 0x88, 0x4c, 0x58, 0xba, 0x04,
+ 0xb7, 0x0d, 0xd3, 0xdb, 0x6c, 0x90, 0xb2, 0xd9, 0x36, 0x8f, 0x89, 0xe8, 0x10, 0x70, 0x8a, 0xda,
+ 0x0f, 0xeb, 0x42, 0x3c, 0x49, 0xe7, 0x31, 0x4c, 0xae, 0x41, 0x3a, 0x25, 0x9d, 0xdd, 0x1f, 0x66,
+ 0x8b, 0x22, 0x9e, 0x0e, 0xd2, 0xb5, 0x12, 0xec, 0x94, 0xb0, 0xe3, 0x30, 0x2e, 0x62, 0xec, 0xac,
+ 0x29, 0xf4, 0xd6, 0x7f, 0xbf, 0xb9, 0xec, 0xff, 0xf1, 0xfe, 0xe2, 0xe7, 0x0f, 0x9f, 0x7e, 0xeb,
+ 0xb3, 0x75, 0xe3, 0xc4, 0x4a, 0x1d, 0x66, 0xf5, 0x0b, 0xa5, 0x0a, 0x4a, 0x14, 0x0e, 0x65, 0xcc,
+ 0xd6, 0x2a, 0x5e, 0x95, 0x92, 0x45, 0x33, 0xd8, 0x2a, 0xae, 0xb7, 0x47, 0x5b, 0xe6, 0x94, 0x45,
+ 0xd9, 0x42, 0xd8, 0x3c, 0x26, 0x2b, 0xf7, 0xc2, 0x4e, 0x19, 0xcd, 0xd3, 0x48, 0xe3, 0x2a, 0x04,
+ 0xeb, 0x05, 0x0a, 0x21, 0xa8, 0xd3, 0x14, 0x8c, 0x06, 0xcb, 0x34, 0x28, 0xd4, 0x61, 0x78, 0x25,
+ 0x6b, 0xa8, 0x4c, 0xc6, 0x37, 0x15, 0xbd, 0x07, 0x39, 0x1a, 0x85, 0x98, 0xcb, 0xc8, 0x83, 0x4c,
+ 0x41, 0x9c, 0x52, 0x0c, 0xd3, 0x0d, 0xba, 0x4a, 0x58, 0xd7, 0x90, 0xc4, 0x66, 0x87, 0xbd, 0x3c,
+ 0xcb, 0xac, 0x24, 0x4c, 0xa8, 0x1a, 0x65, 0xda, 0xe4, 0xac, 0xab, 0x26, 0x4f, 0x81, 0xa9, 0xa1,
+ 0x70, 0x51, 0xcc, 0xf3, 0x7f, 0xa5, 0x75, 0xac, 0xa7, 0x42, 0x54, 0x73, 0xa0, 0x0a, 0x65, 0x63,
+ 0x44, 0x2d, 0xbf, 0x8e, 0x1f, 0x4d, 0xc0, 0xf5, 0xb4, 0xdf, 0x65, 0xc3, 0xe2, 0xba, 0x96, 0x76,
+ 0x84, 0xa8, 0x63, 0x51, 0x15, 0xae, 0x82, 0x51, 0x35, 0x90, 0x35, 0xec, 0x6a, 0xc2, 0xae, 0x6f,
+ 0x43, 0x2d, 0xa3, 0xe8, 0x30, 0x95, 0xfc, 0xa2, 0x83, 0xd9, 0xd8, 0xc6, 0x80, 0xa8, 0xe3, 0x9e,
+ 0x32, 0x28, 0x75, 0x35, 0x88, 0x75, 0x14, 0x7e, 0x91, 0xb5, 0xb4, 0x56, 0x94, 0x0d, 0xa8, 0x42,
+ 0x6c, 0x9a, 0xa2, 0x4c, 0x5e, 0xf9, 0x42, 0xac, 0xb9, 0x9c, 0x14, 0x53, 0x72, 0x45, 0x5b, 0xc9,
+ 0x27, 0xfa, 0x27, 0x32, 0x6d, 0x6c, 0x2e, 0x81, 0x7c, 0x29, 0xac, 0x44, 0x85, 0x36, 0x61, 0x14,
+ 0x6d, 0x23, 0x6f, 0xe0, 0x1f, 0x4b, 0x8d, 0x90, 0xec, 0x73, 0xc1, 0x23, 0x6a, 0x33, 0xa4, 0x4b,
+ 0xb4, 0x95, 0x0c, 0x61, 0x7f, 0x2d, 0x95, 0xb1, 0x1c, 0x5f, 0x11, 0x29, 0xb6, 0x2a, 0x05, 0x82,
+ 0x5d, 0x44, 0x83, 0xfa, 0x61, 0x1b, 0x51, 0x35, 0xdf, 0x37, 0x85, 0x86, 0x6d, 0x7c, 0x75, 0x84,
+ 0x3b, 0x4f, 0x7b, 0xf5, 0xc3, 0xd2, 0x35, 0x6a, 0xb6, 0x6f, 0xca, 0x83, 0x0a, 0x2e, 0xd0, 0x51,
+ 0x3e, 0x60, 0x32, 0xeb, 0x9f, 0xd5, 0xd4, 0xc9, 0xf1, 0x33, 0x67, 0xba, 0x6d, 0x18, 0x4d, 0xac,
+ 0x95, 0x53, 0x15, 0x7d, 0x5b, 0x54, 0xf1, 0x89, 0xb0, 0x42, 0x50, 0x2b, 0xa9, 0xfd, 0x03, 0x6e,
+ 0x31, 0x8f, 0xfc, 0xd3, 0x92, 0xda, 0xe5, 0x20, 0x9b, 0x0f, 0x88, 0x7e, 0x45, 0x75, 0x9a, 0x88,
+ 0x54, 0x85, 0xc3, 0x4a, 0x80, 0xbd, 0x4e, 0xfb, 0xdc, 0x0d, 0x89, 0xb1, 0xee, 0x98, 0x5a, 0x16,
+ 0x57, 0xa5, 0x07, 0xf9, 0x7c, 0x4a, 0xf4, 0xa0, 0x19, 0xb7, 0xb8, 0x34, 0x54, 0xac, 0xa4, 0xae,
+ 0xbd, 0x91, 0x92, 0x46, 0xa1, 0x66, 0xc4, 0x48, 0xf5, 0x1c, 0x3a, 0xf9, 0x9a, 0x6a, 0xbf, 0x83,
+ 0xa6, 0xa9, 0xeb, 0x70, 0x5f, 0x1a, 0xd0, 0x2f, 0xcc, 0x5d, 0x35, 0x9b, 0xe7, 0xff, 0x9b, 0x0e,
+ 0x8a, 0x74, 0xc8, 0xc9, 0xd7, 0x6d, 0x3e, 0x8d, 0x1e, 0x6a, 0xfb, 0x3d, 0xac, 0x76, 0xcf, 0x31,
+ 0x6b, 0x6c, 0xdf, 0x05, 0x35, 0x9a, 0x21, 0xb1, 0xbc, 0xaa, 0x2d, 0x52, 0x83, 0x14, 0xe6, 0x8e,
+ 0x60, 0xcd, 0xab, 0x29, 0x56, 0x6e, 0x54, 0x45, 0x4f, 0x2b, 0x38, 0xda, 0xcb, 0xd5, 0xb6, 0x4d,
+ 0xad, 0x53, 0x78, 0x2d, 0x54, 0xee, 0x50, 0x83, 0x5a, 0xfa, 0x2e, 0xfc, 0xf2, 0x45, 0xe1, 0xf5,
+ 0x78, 0x5a, 0x64, 0xf1, 0x38, 0x8b, 0x17, 0x28, 0x2e, 0x09, 0xb3, 0x06, 0x36, 0x45, 0x3d, 0xb0,
+ 0xd6, 0x13, 0x52, 0x65, 0x1b, 0x58, 0xff, 0xd4, 0x61, 0x35, 0xb6, 0x97, 0x3e, 0xff, 0xb5, 0xf2,
+ 0x35, 0xe4, 0x68, 0x1c, 0x6f, 0xad, 0xab, 0xef, 0x5b, 0xe3, 0x3e, 0x8c, 0xce, 0xbc, 0x67, 0xe5,
+ 0xf7, 0x70, 0xfa, 0xeb, 0xd7, 0xd0, 0x3b, 0xbf, 0xa6, 0xb6, 0xb8, 0x67, 0x15, 0x8f, 0xa9, 0x77,
+ 0x55, 0xcc, 0xbf, 0x89, 0xb2, 0x56, 0xc9, 0xd9, 0x1b, 0x2b, 0x5e, 0x15, 0x3c, 0xbb, 0x5e, 0x95,
+ 0xaa, 0x66, 0xc8, 0x4d, 0x75, 0xa2, 0x35, 0xdc, 0xb6, 0xbd, 0x32, 0xb3, 0x86, 0x95, 0x76, 0x52,
+ 0x43, 0xd6, 0x32, 0xc9, 0x83, 0x55, 0x07, 0x94, 0x83, 0x44, 0xae, 0x87, 0x14, 0x09, 0x17, 0xde,
+ 0xe3, 0x74, 0x3a, 0x22, 0x94, 0xd1, 0x3f, 0x5c, 0xc0, 0xba, 0x61, 0xa5, 0xf4, 0x66, 0x78, 0xee,
+ 0x43, 0x23, 0x93, 0xac, 0xa1, 0x98, 0xdf, 0x9a, 0xc4, 0x4b, 0x07, 0xf5, 0x66, 0x43, 0x30, 0x6b,
+ 0x23, 0xd5, 0x2f, 0xa2, 0xc5, 0x24, 0xcf, 0x8b, 0xeb, 0x45, 0x91, 0xce, 0x9c, 0x4e, 0xbb, 0xe3,
+ 0x9b, 0x88, 0x7c, 0x9d, 0x40, 0xaa, 0xe2, 0x50, 0x1c, 0x4c, 0x1d, 0x8d, 0xd4, 0xbe, 0x6c, 0xfc,
+ 0xad, 0x41, 0xb0, 0x74, 0x1b, 0x3f, 0xc2, 0x9f, 0xc6, 0x0f, 0x0d, 0x05, 0x7b, 0x09, 0x33, 0x54,
+ 0x67, 0x60, 0xa7, 0x0c, 0x6b, 0x5f, 0x81, 0x0c, 0x2f, 0x9a, 0x68, 0x81, 0x27, 0xfc, 0x69, 0x1e,
+ 0x57, 0xfd, 0x54, 0x8e, 0xf1, 0x0c, 0xb5, 0x50, 0x51, 0xa2, 0x1f, 0xe0, 0x63, 0xdb, 0xf7, 0xee,
+ 0x49, 0xf5, 0x86, 0x88, 0x24, 0x67, 0xad, 0xab, 0x8f, 0x8b, 0x26, 0xbb, 0xbf, 0xae, 0xca, 0x31,
+ 0xcc, 0xd3, 0x33, 0xa2, 0x9d, 0x4c, 0x17, 0x90, 0xb3, 0xc9, 0x5e, 0x02, 0xab, 0xa3, 0x6a, 0x81,
+ 0xbf, 0x4b, 0xc9, 0xf4, 0x2e, 0xec, 0x92, 0x93, 0xe6, 0xd9, 0x9d, 0x21, 0x50, 0x1b, 0xcd, 0x37,
+ 0xdc, 0x20, 0xb4, 0x30, 0xcb, 0xb2, 0xae, 0x44, 0x3a, 0xfa, 0x43, 0xf8, 0xe4, 0xb6, 0x53, 0x21,
+ 0xe8, 0x6e, 0xa7, 0x4a, 0xeb, 0x3f, 0xdf, 0x7d, 0xfa, 0x80, 0x6a, 0x19, 0x6e, 0x73, 0x07, 0xdd,
+ 0x17, 0xed, 0x4e, 0x28, 0x36, 0xf1, 0x7e, 0x79, 0xf3, 0xc7, 0xe5, 0x65, 0xff, 0xa7, 0x0f, 0xef,
+ 0x7e, 0x26, 0x53, 0xeb, 0xf4, 0xf5, 0xab, 0xd7, 0x67, 0xbd, 0xde, 0xab, 0xce, 0x59, 0xa7, 0x7b,
+ 0x76, 0xda, 0x7b, 0xb9, 0xb1, 0x27, 0x81, 0x8d, 0x03, 0xfd, 0x63, 0xb1, 0xa1, 0x68, 0x86, 0x2f,
+ 0x07, 0xc5, 0x30, 0x36, 0xd5, 0x6e, 0x8f, 0xb6, 0xeb, 0x5b, 0xfb, 0x1a, 0xf5, 0xe8, 0xde, 0x05,
+ 0x76, 0x5a, 0x02, 0x79, 0x7d, 0xd8, 0xdf, 0xc8, 0x62, 0xa3, 0x08, 0x2f, 0xa3, 0xc5, 0xff, 0xcd,
+ 0x0b, 0xa7, 0x45, 0x92, 0xbd, 0x71, 0x3e, 0x72, 0x60, 0x34, 0x02, 0xda, 0xc0, 0x40, 0x99, 0x0d,
+ 0x81, 0x1c, 0x08, 0xd7, 0x0d, 0x4e, 0xc9, 0x10, 0x09, 0xe6, 0x8f, 0x2e, 0x3d, 0xb3, 0xe2, 0xd0,
+ 0x10, 0xfe, 0x5c, 0x97, 0xa7, 0x44, 0x97, 0xec, 0x30, 0x6a, 0x7f, 0xe5, 0x0b, 0x3a, 0xcb, 0x4d,
+ 0xb3, 0xb1, 0xc9, 0x80, 0xa9, 0x94, 0xb0, 0x8a, 0x12, 0x98, 0x99, 0x8a, 0x5c, 0xd0, 0x67, 0x82,
+ 0x9c, 0xd1, 0x3b, 0x4d, 0xde, 0xc7, 0x9a, 0x80, 0x5b, 0x32, 0x74, 0xa5, 0xde, 0xc4, 0xc8, 0xda,
+ 0x84, 0x31, 0x69, 0xee, 0x30, 0x6a, 0x91, 0x6e, 0xf4, 0xc8, 0x98, 0xe1, 0xff, 0xc3, 0xbc, 0x70,
+ 0x44, 0xdb, 0x7d, 0xf1, 0x8b, 0xf3, 0xc3, 0x6d, 0x3c, 0x8e, 0x28, 0x1a, 0x4f, 0xe9, 0x3a, 0x4f,
+ 0x92, 0xed, 0xa5, 0xcb, 0x99, 0x33, 0x34, 0x96, 0x25, 0x1c, 0x38, 0x52, 0x14, 0x76, 0x9a, 0xf8,
+ 0xff, 0xee, 0x01, 0xf6, 0xac, 0xef, 0xf2, 0xf9, 0x78, 0xb8, 0xe9, 0xae, 0xef, 0x56, 0x6b, 0x92,
+ 0xc7, 0x90, 0x2b, 0xdb, 0xbc, 0xed, 0x65, 0x14, 0xd3, 0xbf, 0xec, 0x7b, 0x05, 0x62, 0xab, 0x45,
+ 0xd3, 0x56, 0x2a, 0x03, 0x96, 0x77, 0x19, 0x6d, 0x39, 0x74, 0x4d, 0x9e, 0x93, 0x94, 0xea, 0x13,
+ 0x02, 0x6b, 0x1a, 0xc1, 0x8e, 0x95, 0x58, 0x76, 0xe0, 0x10, 0xd8, 0x6d, 0xcf, 0x95, 0x8d, 0x3a,
+ 0x0d, 0x4a, 0x56, 0xee, 0xa3, 0x94, 0x28, 0x7c, 0x98, 0x6b, 0xc6, 0xb0, 0x3e, 0xe8, 0x10, 0x42,
+ 0x67, 0x13, 0xe5, 0xa1, 0x94, 0x18, 0x4f, 0x07, 0xd7, 0xf9, 0xdc, 0x9e, 0xc7, 0x27, 0x6c, 0x19,
+ 0xd3, 0x38, 0x1e, 0xa4, 0x16, 0x3e, 0x58, 0x5c, 0x67, 0x57, 0x45, 0xb8, 0x11, 0x27, 0xd5, 0x6b,
+ 0x0b, 0xd5, 0xee, 0x0b, 0x3e, 0x42, 0x6c, 0xf6, 0x70, 0x52, 0xcc, 0xe4, 0x69, 0x5e, 0xfc, 0xb1,
+ 0x80, 0x74, 0x63, 0x0f, 0x59, 0xf1, 0x3b, 0x7d, 0xcc, 0xc9, 0x74, 0x2b, 0xb1, 0xa2, 0xec, 0x0f,
+ 0xca, 0x89, 0xea, 0xbc, 0x97, 0x54, 0x31, 0x28, 0x4e, 0x55, 0xa4, 0x23, 0x6d, 0xdf, 0xe9, 0xc5,
+ 0xf2, 0xf1, 0x18, 0xcf, 0xe9, 0xf4, 0x67, 0xe9, 0x7c, 0x31, 0x23, 0x70, 0xd9, 0x6d, 0x4a, 0xbd,
+ 0x20, 0xd1, 0x60, 0x4c, 0x38, 0x82, 0x0c, 0xdd, 0x79, 0x13, 0x64, 0x86, 0x53, 0xd3, 0xf2, 0xa0,
+ 0xb2, 0x76, 0x17, 0x75, 0xdc, 0x33, 0x18, 0xfe, 0xb5, 0x8a, 0x1f, 0x17, 0x15, 0xa6, 0xf7, 0xc7,
+ 0x11, 0xa3, 0xdd, 0x64, 0xc3, 0xb8, 0xc6, 0xe7, 0xe3, 0xd5, 0xb4, 0x2a, 0xe4, 0xc3, 0x12, 0x71,
+ 0x56, 0xc1, 0x29, 0xcc, 0xc6, 0x44, 0x26, 0xae, 0x54, 0xff, 0xcd, 0x2e, 0x03, 0xca, 0xac, 0x92,
+ 0xf1, 0xec, 0x3a, 0x8e, 0x48, 0xff, 0x85, 0x56, 0x29, 0x87, 0x8d, 0xe6, 0x0d, 0xf7, 0x10, 0x18,
+ 0xbd, 0x6e, 0xbc, 0xaa, 0xc6, 0x7f, 0x35, 0x60, 0x2a, 0xda, 0x14, 0x60, 0xa5, 0x24, 0x4e, 0x57,
+ 0x56, 0xfa, 0x0b, 0x2d, 0xce, 0x48, 0xb2, 0x96, 0xf7, 0xa2, 0x76, 0x37, 0xfc, 0x72, 0x90, 0x59,
+ 0xf8, 0xa4, 0xa6, 0x9b, 0x91, 0x6e, 0x6c, 0x23, 0x1b, 0x8a, 0x80, 0x3d, 0x99, 0x2b, 0x29, 0xc7,
+ 0x99, 0x6b, 0x9d, 0xb9, 0x2a, 0x7d, 0xb3, 0x78, 0x38, 0x24, 0x1d, 0xd8, 0xbf, 0x8a, 0x07, 0x45,
+ 0x0e, 0xbe, 0xd6, 0x5e, 0x69, 0x62, 0x0b, 0xfe, 0x29, 0x4d, 0x67, 0xbd, 0xf0, 0x3e, 0x66, 0x37,
+ 0x1f, 0xff, 0x28, 0x4e, 0x16, 0x52, 0xc0, 0xb4, 0x57, 0xae, 0xa2, 0xcc, 0x4a, 0xfa, 0x74, 0x7a,
+ 0x42, 0x83, 0x1f, 0xa2, 0x2d, 0x7c, 0xdc, 0xb5, 0xd4, 0x2b, 0x6a, 0x83, 0x58, 0xfd, 0x6f, 0x09,
+ 0x14, 0x7a, 0xe0, 0x79, 0xdd, 0x4f, 0x83, 0xeb, 0x4d, 0xf1, 0xa6, 0xa8, 0x16, 0x5b, 0x0b, 0xb7,
+ 0xc1, 0xae, 0x52, 0x6d, 0xc0, 0xc4, 0x59, 0x8f, 0x1f, 0x87, 0xd6, 0x08, 0x36, 0x3c, 0x4a, 0x46,
+ 0x73, 0xdc, 0x5a, 0xf7, 0x93, 0xd4, 0x85, 0x3d, 0x1b, 0xce, 0xd0, 0xe2, 0x52, 0xeb, 0x12, 0x8b,
+ 0xd5, 0x0a, 0x1c, 0x58, 0x46, 0x51, 0xb3, 0xe0, 0xf8, 0xa8, 0xd4, 0x55, 0xc5, 0xf9, 0x07, 0x58,
+ 0x2a, 0x1d, 0x8e, 0x52, 0xe4, 0x5b, 0xab, 0xef, 0xa8, 0xd6, 0xc1, 0xd5, 0xd2, 0x36, 0x30, 0xa1,
+ 0xa7, 0x5b, 0x26, 0xe6, 0x4a, 0x2f, 0x13, 0x75, 0x3f, 0x7e, 0x39, 0xdc, 0xc1, 0x59, 0xcb, 0x2e,
+ 0xc7, 0xda, 0x63, 0xb2, 0x5b, 0xd2, 0xf7, 0xad, 0x9d, 0x9c, 0x7a, 0x4a, 0x07, 0x80, 0x4a, 0x06,
+ 0xea, 0x57, 0x3f, 0xb7, 0x71, 0x80, 0xa3, 0x0d, 0x9b, 0xf2, 0xf0, 0x57, 0xd9, 0xe5, 0x7b, 0xe4,
+ 0x1d, 0xb2, 0x3d, 0xef, 0xdc, 0x6c, 0xb5, 0x7d, 0x62, 0xb1, 0x45, 0x1f, 0xe5, 0xa8, 0xe8, 0x16,
+ 0xb2, 0xc2, 0xea, 0x6f, 0xb0, 0x58, 0xe5, 0x55, 0x83, 0x73, 0x53, 0x8c, 0xb3, 0x69, 0xed, 0xd1,
+ 0x38, 0x0d, 0xa4, 0x5a, 0xc6, 0x68, 0x60, 0x36, 0x59, 0xa3, 0x03, 0xd4, 0x71, 0x55, 0x09, 0xf2,
+ 0x19, 0xc9, 0x1e, 0xbd, 0xc3, 0xb5, 0x2f, 0x9b, 0x2c, 0xd2, 0x00, 0xfc, 0xd2, 0x60, 0xd8, 0x64,
+ 0x93, 0x81, 0x73, 0xa7, 0xde, 0xfc, 0xda, 0xb2, 0x0a, 0x79, 0x36, 0x72, 0x74, 0xdd, 0x3c, 0xd0,
+ 0x34, 0xee, 0x26, 0x4c, 0x9a, 0x00, 0xbc, 0xc2, 0x9c, 0xeb, 0xf5, 0xb3, 0x0d, 0x5b, 0x31, 0xfe,
+ 0xc1, 0xd9, 0xf5, 0x70, 0xc2, 0x50, 0x6f, 0xe8, 0x2e, 0x7c, 0xf2, 0x40, 0x21, 0x29, 0x55, 0x45,
+ 0xa9, 0xc7, 0x92, 0x81, 0x69, 0x09, 0x31, 0x98, 0xcf, 0x89, 0x41, 0xb4, 0xe2, 0x1a, 0x22, 0xd5,
+ 0xde, 0xc1, 0x6f, 0x69, 0x6c, 0x81, 0x82, 0xf6, 0x0d, 0x58, 0x4c, 0x55, 0x50, 0x25, 0xdb, 0x73,
+ 0xb0, 0x38, 0x97, 0xc2, 0x87, 0xf3, 0xf0, 0x3e, 0xde, 0x75, 0x23, 0x7e, 0x52, 0x03, 0xad, 0x9b,
+ 0x87, 0x5e, 0x17, 0xda, 0x7c, 0x3a, 0x3c, 0xf9, 0x33, 0xdc, 0xfc, 0xd2, 0xc7, 0xd5, 0x3c, 0x9f,
+ 0xd8, 0xf1, 0xa8, 0x10, 0x56, 0x5a, 0x61, 0x99, 0x52, 0x81, 0x74, 0x82, 0xd9, 0xad, 0x51, 0x25,
+ 0xdb, 0x46, 0x34, 0x1b, 0x1e, 0x13, 0x6e, 0x03, 0xc2, 0x8b, 0xbc, 0x9e, 0x6c, 0x62, 0xe9, 0xac,
+ 0x23, 0xba, 0xc8, 0x6b, 0x48, 0x26, 0x99, 0x1b, 0x10, 0x4c, 0xa1, 0x36, 0x5f, 0xae, 0xbe, 0xd6,
+ 0xb9, 0x5c, 0x6d, 0xb8, 0xd5, 0x8f, 0x28, 0xee, 0xdb, 0x06, 0x49, 0xd9, 0xfa, 0xd5, 0x47, 0x31,
+ 0xda, 0x75, 0xb0, 0xe4, 0xcf, 0x28, 0xee, 0x97, 0x3b, 0xd9, 0x5a, 0x21, 0x81, 0xb5, 0x77, 0xb5,
+ 0x7a, 0xeb, 0x16, 0x6e, 0x58, 0x45, 0x2a, 0x4d, 0x70, 0xec, 0x44, 0x83, 0x80, 0xab, 0x56, 0x3a,
+ 0xc4, 0xfd, 0x5d, 0x68, 0xe2, 0x48, 0x22, 0x59, 0x91, 0x0d, 0x83, 0x96, 0x4f, 0xca, 0x33, 0x0f,
+ 0x18, 0x08, 0x9e, 0x4f, 0xe8, 0x90, 0x63, 0x42, 0xa6, 0xbd, 0x0c, 0xe5, 0xe5, 0x5f, 0x3d, 0x87,
+ 0x9f, 0x86, 0x01, 0x12, 0x2e, 0x99, 0x53, 0x89, 0xe6, 0xf0, 0x03, 0x2e, 0x45, 0xae, 0xa7, 0xdf,
+ 0x85, 0x9b, 0xad, 0xef, 0x40, 0x2b, 0x11, 0xe6, 0xb3, 0x71, 0xbc, 0x62, 0xd7, 0x09, 0xe9, 0x5e,
+ 0xb0, 0xa3, 0x76, 0x41, 0x7b, 0xd9, 0x52, 0xfb, 0xac, 0xbd, 0x74, 0x03, 0x49, 0xbe, 0xaf, 0x83,
+ 0xae, 0x74, 0xd0, 0x95, 0x0a, 0x6a, 0xab, 0x2f, 0x29, 0xd7, 0x97, 0xe8, 0xf5, 0x25, 0x35, 0xf5,
+ 0x25, 0x7a, 0x7d, 0x49, 0xa9, 0xbe, 0x07, 0xde, 0xba, 0x14, 0x1d, 0xee, 0xe9, 0x9d, 0xe4, 0x8b,
+ 0x31, 0x7a, 0xac, 0x6b, 0x96, 0x6c, 0x00, 0xf5, 0x7a, 0x92, 0x8a, 0x7a, 0x76, 0xd0, 0xc8, 0xd6,
+ 0x5c, 0x8d, 0xac, 0xde, 0x88, 0xe4, 0xe2, 0xf1, 0x2a, 0x1e, 0xa6, 0x7b, 0x5d, 0xf2, 0x0e, 0xb7,
+ 0x6a, 0x1d, 0x7a, 0xb9, 0xd9, 0xe7, 0x5a, 0xb1, 0x8f, 0x83, 0x87, 0x5a, 0x67, 0xed, 0x22, 0xd0,
+ 0x6b, 0x7b, 0xe3, 0x9b, 0x13, 0xd8, 0xdb, 0xdd, 0xe0, 0xad, 0xb8, 0xbf, 0xfb, 0x95, 0x6e, 0xef,
+ 0x56, 0xdc, 0xdd, 0x7d, 0xb4, 0x9b, 0xbb, 0x7b, 0x36, 0x2a, 0x6c, 0x77, 0x81, 0x41, 0x10, 0x31,
+ 0xd7, 0xbf, 0x77, 0xc0, 0xa0, 0x07, 0x4f, 0xc3, 0x92, 0x38, 0x9a, 0x0d, 0x47, 0xb3, 0xe1, 0x68,
+ 0x36, 0x1c, 0xcd, 0x86, 0x0a, 0xb3, 0xe1, 0x9f, 0x79, 0x3e, 0x79, 0xb8, 0xe9, 0xf0, 0xdc, 0xad,
+ 0x82, 0x83, 0x04, 0x6c, 0xa9, 0x35, 0x1d, 0xc4, 0x38, 0x1d, 0xc0, 0x7c, 0x28, 0xd5, 0xb5, 0xde,
+ 0x1a, 0xd0, 0x74, 0xfe, 0xc7, 0x88, 0x88, 0x72, 0x54, 0xfd, 0x8f, 0xaa, 0xff, 0x51, 0xf5, 0x7f,
+ 0x5e, 0xaa, 0xff, 0x86, 0x8a, 0xfa, 0x61, 0x54, 0xf4, 0x53, 0x92, 0x3a, 0x86, 0xc3, 0xe8, 0x7a,
+ 0x20, 0x35, 0x3e, 0xa5, 0x44, 0xb6, 0xba, 0x81, 0xab, 0xc9, 0x12, 0xcc, 0x95, 0x37, 0x00, 0x4c,
+ 0x49, 0x78, 0x9b, 0xce, 0x8b, 0x8c, 0x48, 0xd8, 0xfe, 0x08, 0xce, 0xd1, 0xa4, 0xd3, 0x22, 0xac,
+ 0x95, 0x48, 0xeb, 0x0f, 0x4f, 0x82, 0x5e, 0x38, 0x25, 0xe5, 0x09, 0xca, 0x54, 0xdb, 0x28, 0x3e,
+ 0x23, 0x42, 0x93, 0x6f, 0xfd, 0xd8, 0x6f, 0xd1, 0xc6, 0x95, 0xd7, 0x64, 0x49, 0x4e, 0xf5, 0x3d,
+ 0x21, 0xc8, 0xad, 0xbf, 0x89, 0xc0, 0x21, 0x6a, 0x44, 0xdb, 0x75, 0xcd, 0x45, 0xa5, 0xeb, 0x35,
+ 0x17, 0x95, 0xae, 0x37, 0xb8, 0x0c, 0x71, 0xbd, 0xc9, 0x8d, 0x99, 0x87, 0x1e, 0xc0, 0xd9, 0xfc,
+ 0x24, 0xc5, 0x26, 0x3a, 0x36, 0x8e, 0x87, 0xda, 0x0a, 0x48, 0xb0, 0x45, 0xe9, 0x20, 0xc9, 0x3e,
+ 0x1f, 0x24, 0xeb, 0xbd, 0x21, 0x5a, 0x70, 0x8b, 0x61, 0x50, 0x0b, 0x5f, 0x57, 0xdd, 0x59, 0xba,
+ 0xe6, 0x77, 0x96, 0xae, 0xeb, 0xee, 0x2c, 0xf1, 0xe2, 0xdb, 0x8c, 0x40, 0xf9, 0x64, 0xc7, 0x23,
+ 0x1e, 0xe2, 0xc1, 0x59, 0x4b, 0x67, 0x48, 0xa4, 0x4c, 0x15, 0x22, 0xb5, 0xef, 0x43, 0xec, 0x28,
+ 0xb8, 0xc1, 0x09, 0xae, 0x03, 0xf8, 0x70, 0x43, 0x46, 0x3f, 0x4f, 0xa4, 0x9f, 0xdc, 0xed, 0x40,
+ 0xc3, 0x63, 0x52, 0x1c, 0xed, 0x25, 0x5e, 0x6f, 0x5a, 0xab, 0x04, 0x16, 0x78, 0x90, 0xb0, 0xd3,
+ 0xf8, 0x91, 0x75, 0x4d, 0xe3, 0x07, 0x1c, 0x1f, 0x50, 0x0d, 0x95, 0xfb, 0x9d, 0xb7, 0x18, 0xd4,
+ 0x16, 0x7f, 0xb6, 0xe7, 0x5e, 0xa7, 0xdd, 0xeb, 0xf6, 0x5e, 0x34, 0xe9, 0xe7, 0x88, 0x7c, 0xbe,
+ 0xec, 0x9e, 0xf7, 0xd8, 0x67, 0x42, 0x3e, 0x3b, 0x2f, 0x7b, 0xbd, 0x90, 0x4d, 0x6f, 0xfd, 0x48,
+ 0xa3, 0x38, 0x25, 0x4b, 0x19, 0x75, 0x92, 0x80, 0x8c, 0x41, 0x99, 0x24, 0xe0, 0x4e, 0x7d, 0xf9,
+ 0x0f, 0x82, 0x22, 0x9a, 0x66, 0xa4, 0x02, 0x0b, 0x7f, 0xcc, 0x1c, 0x8e, 0x8e, 0xe6, 0x53, 0xd2,
+ 0x77, 0xf4, 0xb8, 0x2f, 0x5c, 0xe6, 0xa1, 0xed, 0x0f, 0xba, 0x2f, 0x4e, 0x5f, 0x9d, 0x41, 0x28,
+ 0x59, 0x21, 0x11, 0x5d, 0x59, 0xbd, 0x5a, 0x12, 0x64, 0x3a, 0x48, 0xe2, 0x96, 0x29, 0x1d, 0x5d,
+ 0x88, 0x8f, 0x4a, 0xb3, 0x64, 0x27, 0x34, 0xcb, 0x50, 0x80, 0xd1, 0x57, 0x30, 0xd2, 0xa0, 0x11,
+ 0x6c, 0x18, 0x56, 0x8d, 0xef, 0x22, 0xb8, 0xf9, 0xd1, 0xf8, 0xb7, 0x02, 0xe1, 0x45, 0xbc, 0xc6,
+ 0x92, 0xc0, 0x75, 0x9b, 0x8e, 0x25, 0xd5, 0xa3, 0xcd, 0x73, 0x8a, 0x26, 0xb2, 0x81, 0x37, 0xcb,
+ 0xef, 0x1c, 0x3a, 0x5e, 0x41, 0xf7, 0xbc, 0xc3, 0xce, 0x89, 0xfa, 0xd0, 0x12, 0x32, 0x18, 0xe4,
+ 0xe3, 0xf5, 0x2b, 0xdf, 0xde, 0x22, 0xa0, 0x15, 0x83, 0xf7, 0xf6, 0xd9, 0x60, 0x36, 0x59, 0xcf,
+ 0xf1, 0xb1, 0x55, 0xa9, 0x54, 0xd7, 0x9a, 0xf6, 0x9c, 0xa1, 0x87, 0xba, 0x4e, 0x55, 0xec, 0x2c,
+ 0xdb, 0x65, 0x03, 0xcb, 0x10, 0x8f, 0x74, 0xc4, 0xa3, 0x6a, 0xc4, 0xa3, 0x7a, 0xc4, 0x23, 0x03,
+ 0x71, 0xa2, 0x23, 0x4e, 0xaa, 0x11, 0x27, 0xf5, 0x88, 0x13, 0x1d, 0xb1, 0xa7, 0xe8, 0x8e, 0xfa,
+ 0xd1, 0x0e, 0xb9, 0x54, 0xd5, 0xdc, 0xc7, 0x55, 0x16, 0xb3, 0x27, 0xeb, 0xa1, 0x33, 0x56, 0x30,
+ 0x76, 0x0c, 0xd7, 0xea, 0xbf, 0x7b, 0xa0, 0x62, 0xb0, 0x47, 0x95, 0xe5, 0x01, 0x3a, 0xc7, 0xe6,
+ 0x7b, 0x39, 0x30, 0xe4, 0xac, 0xde, 0xd1, 0x23, 0x28, 0x28, 0x5a, 0x68, 0x3c, 0x58, 0xf6, 0x6c,
+ 0xd1, 0x41, 0x2c, 0x7a, 0x4b, 0x09, 0xeb, 0xe3, 0xaa, 0x2d, 0x2a, 0x59, 0xd7, 0xfa, 0xf5, 0x6a,
+ 0xa5, 0xa8, 0x5d, 0x9f, 0xb1, 0xe0, 0x3e, 0xba, 0x46, 0x9f, 0xa0, 0x6b, 0x14, 0xb9, 0x74, 0x2b,
+ 0x55, 0xcd, 0xe0, 0xc9, 0xed, 0x34, 0xb5, 0xed, 0xb5, 0xb3, 0x12, 0xa7, 0x45, 0xbb, 0xf0, 0xd3,
+ 0xd1, 0xf7, 0xfa, 0xed, 0x1c, 0xd9, 0xa8, 0x53, 0x79, 0xd9, 0x7d, 0x94, 0xe1, 0x28, 0x15, 0x37,
+ 0xc0, 0x54, 0x90, 0xe7, 0xef, 0xb4, 0x7d, 0x0c, 0x9d, 0x9f, 0xe6, 0xdc, 0x47, 0x15, 0xba, 0xfd,
+ 0x5a, 0x9b, 0xe0, 0x5e, 0x9c, 0x99, 0x01, 0x97, 0x0f, 0xc7, 0x1d, 0xc1, 0x86, 0x66, 0xe3, 0xaf,
+ 0x7f, 0x6d, 0x70, 0xcd, 0x36, 0x02, 0xc5, 0x56, 0x49, 0xb8, 0x27, 0x10, 0x54, 0xe9, 0x3e, 0xf9,
+ 0x91, 0xae, 0xcb, 0x27, 0x3f, 0xd0, 0xb7, 0x25, 0xd4, 0xf1, 0xf4, 0xef, 0x3d, 0x43, 0x03, 0x39,
+ 0xc8, 0xf9, 0x95, 0xc3, 0x9c, 0x5e, 0x61, 0xb5, 0x70, 0xd5, 0xa1, 0xc2, 0xf8, 0xd9, 0xd0, 0x7a,
+ 0x39, 0x7d, 0x0c, 0xeb, 0x05, 0x2e, 0x40, 0x3e, 0x17, 0x93, 0x85, 0x77, 0x6b, 0x7b, 0x3e, 0x12,
+ 0x56, 0x40, 0x95, 0xf6, 0x8f, 0x98, 0x31, 0x4c, 0x1d, 0x34, 0xc5, 0x67, 0xbf, 0x4e, 0xdd, 0x92,
+ 0x1d, 0xc0, 0xf2, 0xb0, 0x16, 0x65, 0xe8, 0x0c, 0x73, 0xe0, 0xd0, 0x3b, 0x09, 0xbb, 0xe8, 0xa2,
+ 0xfb, 0x55, 0x2a, 0x0f, 0xa5, 0x19, 0x3e, 0xef, 0xad, 0x0b, 0x1c, 0xa8, 0xf5, 0x1a, 0x56, 0xe5,
+ 0x28, 0x6c, 0xa6, 0x2d, 0x1d, 0x37, 0x3c, 0x8e, 0x1b, 0x1e, 0x3b, 0x6f, 0x78, 0xb0, 0xc7, 0x8a,
+ 0x96, 0xec, 0xf9, 0xa0, 0xea, 0x3d, 0x8f, 0xd2, 0xd6, 0x08, 0x2b, 0xe1, 0x19, 0xf2, 0x6a, 0xbf,
+ 0xfe, 0x90, 0x61, 0x36, 0x81, 0x95, 0x22, 0x9f, 0x86, 0x9b, 0x85, 0x72, 0x60, 0xcd, 0x7e, 0x8c,
+ 0x98, 0x38, 0x6a, 0x1c, 0x03, 0x1a, 0xe1, 0x69, 0xb6, 0xc8, 0xc6, 0x04, 0x96, 0x05, 0x55, 0x15,
+ 0x94, 0xb1, 0x9b, 0xd2, 0xa8, 0x07, 0x3b, 0x4a, 0x06, 0x51, 0x1b, 0x41, 0x61, 0x0b, 0xb4, 0x24,
+ 0x7e, 0xf6, 0x55, 0x23, 0x35, 0x78, 0xd5, 0x7d, 0x8d, 0xe1, 0xaa, 0x10, 0x49, 0x93, 0x55, 0x54,
+ 0xf3, 0xe4, 0x90, 0xf1, 0xac, 0x1a, 0x76, 0xe9, 0x36, 0x0b, 0x53, 0x75, 0x37, 0x9b, 0x6b, 0xde,
+ 0x7d, 0x4e, 0x24, 0x45, 0xe9, 0xed, 0x91, 0x78, 0xa9, 0xa5, 0x33, 0xa1, 0x49, 0x0d, 0x43, 0xd6,
+ 0x1f, 0x44, 0x0b, 0x7b, 0x37, 0x4e, 0x6f, 0x41, 0x71, 0x9a, 0x3a, 0x2c, 0xe8, 0x31, 0xe1, 0x53,
+ 0x9f, 0x49, 0xc6, 0x2c, 0x5e, 0xf0, 0xc8, 0x12, 0x18, 0x73, 0xb6, 0xcc, 0xaf, 0x74, 0x92, 0x79,
+ 0x18, 0x27, 0x2d, 0xc4, 0x40, 0x88, 0x71, 0x04, 0xb1, 0xbc, 0xf8, 0xfb, 0x4d, 0xa0, 0x4f, 0x41,
+ 0xb2, 0xcf, 0x2b, 0x76, 0x03, 0xa2, 0x9c, 0x12, 0x4d, 0xa2, 0xf4, 0x70, 0x49, 0xfd, 0xc0, 0xa1,
+ 0x62, 0xaa, 0x90, 0x0a, 0xfd, 0xd3, 0x44, 0xc5, 0xb6, 0xc5, 0x0a, 0x12, 0xcd, 0x5b, 0xfc, 0x5c,
+ 0xa1, 0xa6, 0xc6, 0xb5, 0xbc, 0xa4, 0xb2, 0x6c, 0xa7, 0xaa, 0xc8, 0xa0, 0xb2, 0xc8, 0xda, 0xda,
+ 0x86, 0x9b, 0x50, 0xda, 0xd1, 0x8a, 0xa4, 0x96, 0x22, 0x6a, 0xfe, 0xd5, 0x06, 0xd4, 0xe8, 0x18,
+ 0x47, 0x9b, 0x10, 0x61, 0xa7, 0xff, 0xba, 0xa6, 0xb7, 0xec, 0x25, 0xb2, 0x0d, 0xc8, 0xb3, 0x97,
+ 0x4c, 0x97, 0xf1, 0x68, 0x94, 0x62, 0xd0, 0x09, 0x98, 0xdd, 0xc0, 0xae, 0x8d, 0xbf, 0x35, 0x7a,
+ 0x68, 0x2f, 0x75, 0xda, 0x67, 0xc4, 0x58, 0x12, 0x89, 0x67, 0xed, 0x73, 0x4c, 0x3c, 0x3d, 0x27,
+ 0xa9, 0xe4, 0x0f, 0xb3, 0x0a, 0xd3, 0x79, 0x76, 0xcb, 0x8c, 0xc1, 0x41, 0xf3, 0x8a, 0xfc, 0x97,
+ 0xb9, 0x2d, 0x27, 0x6e, 0x0e, 0xc9, 0x7f, 0x23, 0xd7, 0x77, 0x46, 0xcd, 0x6b, 0xf2, 0x1f, 0x4d,
+ 0x4b, 0xc8, 0x7f, 0x03, 0xd7, 0x0d, 0x1a, 0xa0, 0x06, 0x93, 0x3a, 0x7c, 0x87, 0x22, 0x6f, 0x89,
+ 0xa9, 0x02, 0x41, 0x16, 0x24, 0x41, 0xcd, 0xee, 0xeb, 0x76, 0xef, 0xfc, 0x45, 0xaf, 0x45, 0xc1,
+ 0xcc, 0x38, 0x54, 0xa8, 0xfa, 0xa2, 0x20, 0x42, 0x22, 0xda, 0x4b, 0x38, 0x07, 0x0f, 0x81, 0x4e,
+ 0x7c, 0xfa, 0xbd, 0x12, 0xdf, 0x3c, 0xf8, 0x98, 0xb4, 0x1e, 0xf6, 0x20, 0x92, 0xbf, 0x92, 0xe4,
+ 0xa5, 0x82, 0xd2, 0x26, 0x27, 0xeb, 0x83, 0x8f, 0xad, 0x97, 0x76, 0x63, 0x52, 0x61, 0x3c, 0x55,
+ 0xae, 0x07, 0xf0, 0x74, 0xd4, 0xb4, 0x4c, 0x8f, 0xf9, 0x75, 0x3c, 0xcc, 0xef, 0xcc, 0x54, 0x10,
+ 0xc0, 0x56, 0xf0, 0x78, 0x00, 0xe1, 0x50, 0x64, 0x48, 0xc7, 0x8f, 0x17, 0x8d, 0xd3, 0x76, 0xf7,
+ 0xac, 0x7b, 0xfe, 0xba, 0xf7, 0xe2, 0xfc, 0xf4, 0xfc, 0xd5, 0xeb, 0x97, 0xaf, 0x4f, 0x4f, 0x2c,
+ 0xd1, 0x75, 0xc0, 0x1a, 0xad, 0x0c, 0x6c, 0xa6, 0x72, 0xa4, 0x43, 0x5f, 0xc6, 0x23, 0x56, 0x12,
+ 0x04, 0x37, 0x74, 0xd5, 0xe8, 0x86, 0xb8, 0x7a, 0xfc, 0x4c, 0xa3, 0xd1, 0x0c, 0x88, 0xe1, 0x0b,
+ 0xb6, 0x5a, 0x3c, 0x5d, 0x38, 0x8e, 0x6c, 0xf2, 0x9f, 0x9d, 0xcf, 0x2d, 0xe5, 0xab, 0xfb, 0xd9,
+ 0xf5, 0xd0, 0xf0, 0x63, 0x21, 0xde, 0xdc, 0xa6, 0x9e, 0x29, 0x30, 0x8f, 0xf3, 0x59, 0x1a, 0x11,
+ 0x61, 0x3b, 0x25, 0xd0, 0xbd, 0x73, 0x8f, 0x1d, 0x93, 0x46, 0x8a, 0xdc, 0x40, 0xa9, 0x57, 0x9c,
+ 0x91, 0xc6, 0xb8, 0x2f, 0x11, 0xe3, 0x5f, 0x6a, 0x72, 0x92, 0x49, 0x86, 0x18, 0x18, 0x13, 0xfb,
+ 0x2d, 0x96, 0xeb, 0x92, 0x69, 0xf7, 0xf1, 0x02, 0xef, 0x7a, 0xf0, 0x3c, 0xe1, 0xda, 0x00, 0xa7,
+ 0xc4, 0x0f, 0x6a, 0x1b, 0x85, 0xe9, 0x18, 0xb1, 0xf1, 0x12, 0xee, 0xab, 0xf8, 0x3e, 0x9b, 0xdc,
+ 0x60, 0xe0, 0x5f, 0x9a, 0xbe, 0x6a, 0x7e, 0xbc, 0x08, 0x15, 0x3d, 0xbc, 0xdb, 0x7e, 0xf5, 0xf2,
+ 0xbc, 0x25, 0x83, 0xfc, 0x75, 0xdb, 0x2f, 0xcf, 0x59, 0x3e, 0x99, 0xa4, 0xf4, 0x61, 0x4f, 0x08,
+ 0x26, 0x24, 0x4a, 0xd1, 0x28, 0x8f, 0x97, 0xd8, 0x74, 0x51, 0x0c, 0x9b, 0x02, 0xf2, 0x82, 0x8c,
+ 0x03, 0x99, 0xec, 0xe8, 0x64, 0xc5, 0xde, 0xa1, 0x23, 0x11, 0xc8, 0x54, 0x8e, 0x94, 0x66, 0xb8,
+ 0x1e, 0xff, 0x86, 0x88, 0xb9, 0x50, 0x80, 0x93, 0x8d, 0x0c, 0x83, 0xe3, 0xa5, 0x54, 0xc8, 0xf7,
+ 0x50, 0x31, 0x93, 0xed, 0xb5, 0xe2, 0x40, 0xd1, 0x14, 0x08, 0x0f, 0x46, 0x7f, 0x31, 0x43, 0x5c,
+ 0x36, 0xab, 0x57, 0xf6, 0x45, 0x00, 0x0b, 0xd3, 0x70, 0x2a, 0xa0, 0x7c, 0x3a, 0x74, 0x6c, 0x9a,
+ 0xac, 0xbf, 0xdc, 0xe0, 0xe3, 0x05, 0xca, 0x12, 0xc9, 0x4d, 0x34, 0x40, 0x33, 0x14, 0x62, 0x35,
+ 0xd3, 0x27, 0xb4, 0xe8, 0x4c, 0xf0, 0x15, 0xe6, 0xf7, 0x11, 0x88, 0xa8, 0x2d, 0x84, 0x93, 0x55,
+ 0xe2, 0xeb, 0x89, 0xd2, 0xe4, 0x90, 0xda, 0x42, 0xca, 0x8a, 0x4a, 0xc5, 0xed, 0xd8, 0x6d, 0x2a,
+ 0x9f, 0x0f, 0x13, 0x6e, 0x62, 0x4a, 0x22, 0xa5, 0x18, 0xc2, 0xf8, 0xfc, 0xd5, 0xcb, 0xd3, 0x4e,
+ 0xf7, 0xc5, 0x89, 0x4d, 0xc2, 0x31, 0xbf, 0x64, 0x79, 0xf3, 0x09, 0x63, 0xdc, 0xd7, 0x2b, 0xaf,
+ 0xe5, 0xa8, 0xb0, 0xea, 0xe3, 0x58, 0x4c, 0xda, 0x98, 0xaf, 0xf9, 0x6d, 0xfa, 0xc6, 0x96, 0x21,
+ 0xdf, 0x18, 0x99, 0x46, 0x2a, 0x46, 0xbf, 0xe9, 0x95, 0x62, 0x23, 0x8d, 0xe2, 0xc9, 0x24, 0xe6,
+ 0xc1, 0x8e, 0x2c, 0xa1, 0x3e, 0x41, 0xb7, 0x9f, 0xa6, 0x8b, 0xfc, 0x2a, 0x9e, 0x7f, 0x73, 0x81,
+ 0x63, 0x8e, 0x8f, 0x59, 0xed, 0x70, 0xae, 0x74, 0x14, 0xcf, 0x6a, 0x1e, 0x83, 0xe2, 0xb9, 0x75,
+ 0x71, 0x91, 0x39, 0xcc, 0xba, 0xc8, 0xc8, 0x2a, 0x5c, 0x5d, 0x97, 0xe1, 0xdb, 0xab, 0x15, 0x4d,
+ 0xc2, 0xbc, 0xea, 0x0e, 0xc3, 0xec, 0xfa, 0x4e, 0x11, 0x20, 0x35, 0x24, 0xd4, 0x74, 0xc8, 0xda,
+ 0xde, 0xd8, 0xa8, 0x2b, 0xf4, 0x7e, 0x78, 0x7a, 0x41, 0x86, 0x9e, 0xfb, 0x33, 0x4d, 0x82, 0xe9,
+ 0xf5, 0x81, 0xe1, 0xc9, 0x16, 0x42, 0x78, 0x96, 0xaf, 0xce, 0x89, 0x8a, 0xa0, 0xd5, 0x12, 0xcd,
+ 0x96, 0x3c, 0xaf, 0xb6, 0x88, 0xbe, 0x87, 0x6c, 0xe9, 0x11, 0xcc, 0xf0, 0xe5, 0x5c, 0xb0, 0xf6,
+ 0x07, 0x2b, 0xbd, 0x0d, 0xbb, 0xeb, 0x6d, 0xa8, 0xea, 0x07, 0xde, 0x09, 0xf5, 0x3d, 0xc0, 0x9b,
+ 0xaf, 0xb7, 0x9d, 0xe6, 0xbd, 0x79, 0xff, 0xfb, 0xc5, 0x9b, 0x5f, 0x2f, 0xde, 0x5c, 0x5e, 0xbc,
+ 0xff, 0xa5, 0xfa, 0x79, 0x1a, 0x50, 0xf2, 0xf5, 0x00, 0x9c, 0x51, 0xcc, 0x1f, 0x55, 0x68, 0x75,
+ 0x7b, 0xaf, 0x48, 0x36, 0xd3, 0x9e, 0xfa, 0x62, 0x8b, 0x20, 0xa2, 0xa1, 0xbf, 0xe9, 0x93, 0x09,
+ 0x18, 0xd6, 0x11, 0xbd, 0x05, 0xca, 0x92, 0x16, 0x89, 0x68, 0xdb, 0x14, 0x08, 0xfc, 0x05, 0x6e,
+ 0x93, 0x7d, 0xdd, 0x79, 0x2f, 0xce, 0x58, 0xc4, 0x70, 0xe9, 0x1f, 0x54, 0xa2, 0x73, 0xb3, 0x85,
+ 0x96, 0xbe, 0xed, 0xa4, 0xcd, 0x7a, 0xb1, 0xd9, 0x29, 0xa1, 0x30, 0xc0, 0x38, 0x58, 0x1e, 0x62,
+ 0x37, 0x8d, 0xff, 0xe0, 0x11, 0xc9, 0x43, 0xbe, 0x72, 0xb3, 0x9c, 0x50, 0xb0, 0x0d, 0xff, 0x81,
+ 0x9d, 0xc0, 0x0c, 0xe7, 0x78, 0x7c, 0x45, 0x33, 0x65, 0x0e, 0x1b, 0x64, 0xc0, 0xe5, 0xb1, 0x71,
+ 0xe6, 0x1a, 0x32, 0xa4, 0x73, 0x2c, 0x4d, 0x87, 0xff, 0x12, 0x3a, 0xb5, 0x3a, 0x04, 0x68, 0xf1,
+ 0x0a, 0x45, 0x31, 0xbf, 0x29, 0xb4, 0xb2, 0xa2, 0x5e, 0xaf, 0x8c, 0xa5, 0x87, 0x6f, 0x3f, 0x80,
+ 0x92, 0xd5, 0x74, 0x24, 0x7d, 0x4c, 0xcf, 0xa7, 0x0f, 0x43, 0xa8, 0x15, 0x19, 0x7d, 0x86, 0x97,
+ 0x2d, 0x69, 0x75, 0x9e, 0x0c, 0x42, 0x49, 0x15, 0x13, 0x43, 0x5c, 0xa2, 0x52, 0xae, 0x8c, 0xb3,
+ 0x91, 0x5f, 0xd0, 0xb0, 0xd4, 0x44, 0xb9, 0xbd, 0x31, 0xea, 0xa0, 0xbd, 0xd2, 0x8b, 0xe8, 0x5f,
+ 0xb3, 0x1a, 0x4f, 0x8c, 0x08, 0x51, 0xde, 0x20, 0x22, 0x74, 0xeb, 0xc6, 0xbf, 0x81, 0xa7, 0xd2,
+ 0x8d, 0xf7, 0xb1, 0x38, 0xff, 0xe9, 0x76, 0x2a, 0xd0, 0x1f, 0x30, 0xc5, 0x8e, 0x6f, 0xff, 0xd5,
+ 0x1d, 0xc7, 0x94, 0xcf, 0x8a, 0xf7, 0xb4, 0x62, 0xd8, 0x7f, 0xa5, 0xca, 0xac, 0x81, 0x1b, 0xf1,
+ 0x81, 0x2a, 0xd2, 0x65, 0x6a, 0x54, 0x4d, 0x7e, 0x5f, 0x95, 0xde, 0x3a, 0xad, 0x2c, 0x65, 0x2b,
+ 0x52, 0xaa, 0xb4, 0x74, 0x05, 0xdf, 0x2b, 0xe9, 0xa8, 0x60, 0x94, 0x2b, 0x2a, 0x64, 0xb4, 0x9e,
+ 0xc0, 0x60, 0x0d, 0x35, 0x21, 0x57, 0x55, 0xa9, 0xa7, 0x85, 0x72, 0x84, 0x8f, 0x2c, 0xac, 0xdd,
+ 0xf1, 0xd9, 0x52, 0x29, 0x36, 0xd4, 0x5f, 0xbb, 0xaa, 0x6c, 0x53, 0x8a, 0xbf, 0xce, 0xdb, 0x55,
+ 0xdf, 0xd0, 0x9b, 0x52, 0x7b, 0x8e, 0x98, 0x77, 0x98, 0x97, 0x8a, 0x6c, 0x17, 0xbe, 0x29, 0x73,
+ 0xb8, 0x1e, 0x67, 0x9e, 0xf6, 0x22, 0x94, 0x24, 0xf4, 0x22, 0x7c, 0x67, 0xa7, 0x59, 0xb5, 0x60,
+ 0x41, 0x31, 0x95, 0x8d, 0xd4, 0x8b, 0xe2, 0xd4, 0x16, 0x9e, 0x90, 0x1e, 0x83, 0x0a, 0x5b, 0x8e,
+ 0xa8, 0xa0, 0x68, 0x21, 0x6a, 0xd7, 0x97, 0x55, 0x62, 0xa8, 0x52, 0x37, 0xc0, 0xf4, 0x0a, 0x83,
+ 0x79, 0x0f, 0xa1, 0xa9, 0x84, 0x65, 0xfc, 0xdb, 0x9b, 0x7f, 0xf4, 0x7f, 0xbd, 0x78, 0xff, 0xae,
+ 0xff, 0xf6, 0xe2, 0xf2, 0xf7, 0x37, 0xef, 0x7f, 0x7a, 0xd7, 0x38, 0xed, 0xbd, 0x7c, 0xf1, 0xb2,
+ 0xdd, 0x79, 0x32, 0xb6, 0xf3, 0xa6, 0x0f, 0x50, 0x57, 0xd8, 0xd8, 0xfb, 0xb7, 0x9d, 0x89, 0x58,
+ 0x1d, 0xcd, 0xd3, 0x45, 0x65, 0xa0, 0x90, 0xa3, 0x95, 0x7a, 0xb4, 0x52, 0x9f, 0xab, 0x95, 0x7a,
+ 0xb4, 0x1b, 0x8f, 0x76, 0xe3, 0x33, 0xb3, 0x1b, 0xb9, 0x38, 0xdf, 0xd4, 0x74, 0x0c, 0x4a, 0x4b,
+ 0xe8, 0xd1, 0x98, 0x3c, 0x1a, 0x93, 0x47, 0x63, 0xf2, 0x9b, 0x32, 0x26, 0x37, 0xde, 0x5b, 0xde,
+ 0xd9, 0xcc, 0x7c, 0xa0, 0xfe, 0xf8, 0x6c, 0x4c, 0xc5, 0xa3, 0xb9, 0x67, 0x31, 0xf7, 0x2a, 0xde,
+ 0x30, 0x63, 0x07, 0x02, 0x80, 0xb3, 0x75, 0x56, 0xa9, 0x7e, 0xcb, 0x6c, 0x3f, 0x56, 0x62, 0xd9,
+ 0x06, 0xe4, 0x39, 0xda, 0xc2, 0xd7, 0xbf, 0xfc, 0xe9, 0xcd, 0xaf, 0xef, 0x40, 0xb4, 0x3f, 0xba,
+ 0x8d, 0xb8, 0x66, 0x07, 0xf5, 0x61, 0x26, 0xe4, 0x43, 0x6c, 0x44, 0xb9, 0x7b, 0xba, 0x83, 0x93,
+ 0xe9, 0x68, 0x1a, 0xee, 0x60, 0x1a, 0x3e, 0x01, 0x4b, 0xec, 0xc9, 0x59, 0xa7, 0x07, 0x36, 0x0d,
+ 0x8f, 0x17, 0x42, 0x9f, 0xd0, 0x85, 0xd0, 0x67, 0x6e, 0x82, 0x7f, 0x5d, 0x93, 0xf7, 0xa9, 0x39,
+ 0x00, 0x0e, 0x65, 0x82, 0xff, 0x27, 0x5c, 0xd1, 0xfd, 0x4a, 0x6e, 0x06, 0x0e, 0xb7, 0xdd, 0x26,
+ 0xb5, 0x45, 0xd1, 0x3a, 0xfa, 0x19, 0x8e, 0x7e, 0x86, 0xa3, 0x9f, 0xe1, 0x50, 0x7e, 0x06, 0x39,
+ 0x5d, 0x63, 0x55, 0xe9, 0x7f, 0x5c, 0xff, 0xc3, 0x36, 0xd7, 0x51, 0x35, 0x59, 0x67, 0xc6, 0x79,
+ 0x59, 0xeb, 0xc8, 0x38, 0x9c, 0x91, 0xf3, 0x5c, 0x6e, 0x83, 0xfe, 0x27, 0x78, 0x67, 0x9e, 0xd0,
+ 0xb5, 0xd2, 0xaf, 0xe8, 0x3d, 0x3a, 0xc6, 0x4d, 0x7e, 0x5e, 0xaf, 0xa9, 0xa8, 0x5d, 0xad, 0xb6,
+ 0x4f, 0x6f, 0x73, 0x7b, 0xe9, 0x89, 0x5e, 0x0b, 0xf4, 0x08, 0xc4, 0x06, 0xe0, 0xca, 0x86, 0x33,
+ 0xb1, 0xe0, 0x24, 0x54, 0x7b, 0xac, 0xbf, 0xeb, 0x30, 0x02, 0xc5, 0xe1, 0x37, 0xe6, 0xb2, 0xa4,
+ 0xd8, 0x96, 0xa4, 0x2b, 0xe9, 0xf5, 0x66, 0xb1, 0x44, 0x04, 0x7a, 0x4f, 0xb7, 0x97, 0x3a, 0x7c,
+ 0x52, 0x0f, 0x9f, 0xe8, 0xf0, 0xab, 0x3e, 0xbe, 0xc4, 0xdc, 0x14, 0x7d, 0x41, 0xf4, 0x20, 0x76,
+ 0x59, 0x4e, 0xd0, 0x87, 0x34, 0x39, 0x46, 0xad, 0xab, 0x66, 0x8f, 0xbd, 0x26, 0xe3, 0x9a, 0x04,
+ 0xad, 0x24, 0xf2, 0x64, 0x17, 0xe4, 0x49, 0x35, 0xf2, 0x44, 0xb2, 0x06, 0xc6, 0x3f, 0xd9, 0xfe,
+ 0xb2, 0x39, 0xf2, 0x10, 0xe9, 0x55, 0x9f, 0xb4, 0xdc, 0x55, 0x70, 0x25, 0x3b, 0x5c, 0x15, 0x67,
+ 0xb8, 0x12, 0x82, 0x2b, 0x71, 0x35, 0x27, 0x33, 0xe0, 0xb2, 0x5e, 0x17, 0x27, 0x95, 0xfa, 0xf6,
+ 0x8c, 0xc4, 0xb5, 0x5f, 0x13, 0xa7, 0x6e, 0xe7, 0x47, 0x7c, 0xd6, 0xe2, 0x09, 0x39, 0x9d, 0x1f,
+ 0xf5, 0x60, 0x12, 0x1b, 0x24, 0xfa, 0x0c, 0x76, 0x5c, 0x52, 0xed, 0x48, 0xaf, 0xf7, 0x57, 0x4a,
+ 0xba, 0xad, 0x54, 0x52, 0x51, 0x2a, 0xd9, 0xc7, 0x21, 0x28, 0x96, 0x0a, 0x35, 0xc4, 0xb6, 0xc4,
+ 0x64, 0xf7, 0x53, 0x95, 0xc7, 0xab, 0x44, 0xc7, 0x43, 0x5a, 0xc7, 0x43, 0x5a, 0x55, 0x9e, 0x78,
+ 0x3e, 0x64, 0x16, 0x37, 0xdd, 0x63, 0x78, 0xe9, 0xd1, 0x57, 0x54, 0x43, 0xa5, 0xcc, 0xaf, 0xec,
+ 0x2b, 0x09, 0x62, 0xe3, 0x2f, 0x25, 0xb7, 0xae, 0x37, 0x75, 0xb0, 0xe3, 0xbd, 0xa8, 0xe3, 0xf9,
+ 0xb6, 0x27, 0x72, 0xbe, 0xed, 0x70, 0xee, 0x74, 0x65, 0x2a, 0xca, 0x9f, 0x96, 0x9a, 0x65, 0xa6,
+ 0xaf, 0xcf, 0x4f, 0x5b, 0x93, 0x55, 0x4c, 0xb6, 0x49, 0x76, 0xf4, 0x7a, 0x1f, 0xbd, 0xde, 0x47,
+ 0xaf, 0xf7, 0xd1, 0xeb, 0xbd, 0x99, 0xd7, 0x1b, 0xd5, 0xff, 0x88, 0xc9, 0x21, 0x31, 0x77, 0x3d,
+ 0xd3, 0x9c, 0x69, 0x2f, 0x03, 0x45, 0x48, 0x89, 0xc1, 0x2b, 0x81, 0xad, 0x9a, 0xc2, 0xd2, 0x71,
+ 0x19, 0xf6, 0x64, 0x2d, 0xf6, 0x64, 0x33, 0xec, 0x89, 0x82, 0x1d, 0x42, 0xa3, 0xed, 0xfb, 0x64,
+ 0xa0, 0x69, 0x8b, 0x2d, 0x86, 0x57, 0xd8, 0xfd, 0xe5, 0xd8, 0x59, 0xc4, 0xa4, 0x7c, 0x62, 0x16,
+ 0xd8, 0xf1, 0x5e, 0x5b, 0xbd, 0x0e, 0x70, 0x38, 0x1d, 0x7c, 0xbf, 0x0a, 0xf4, 0xb7, 0x78, 0x55,
+ 0xcf, 0x8a, 0xa1, 0xe6, 0xdc, 0x43, 0xb9, 0xc7, 0x6b, 0x3b, 0x7c, 0x6b, 0x55, 0xe9, 0x1b, 0x73,
+ 0xc9, 0x12, 0x31, 0x04, 0xb9, 0xfd, 0xd8, 0x1a, 0x5b, 0x0a, 0x85, 0x89, 0xdb, 0x8e, 0x0d, 0xe0,
+ 0xa4, 0x12, 0x38, 0x29, 0x01, 0xa3, 0xf7, 0x50, 0xd4, 0xe2, 0x0b, 0x14, 0x3e, 0x4a, 0x3a, 0x37,
+ 0xa4, 0xbe, 0xc0, 0x48, 0x7b, 0x29, 0xf7, 0xbc, 0x25, 0xe5, 0xa3, 0x2a, 0xcb, 0x69, 0x34, 0x63,
+ 0x5b, 0x0e, 0x43, 0xbb, 0xff, 0x43, 0xae, 0x1b, 0x9d, 0x3b, 0x2d, 0xc6, 0x64, 0xad, 0x99, 0xab,
+ 0xcf, 0x64, 0x08, 0xa9, 0x8f, 0x6b, 0x4f, 0x45, 0x66, 0x72, 0x73, 0x75, 0x95, 0xce, 0xeb, 0x9e,
+ 0xd0, 0xdd, 0x32, 0xa8, 0x5a, 0xc7, 0x92, 0xd6, 0xdd, 0x35, 0xd2, 0x5a, 0x27, 0x72, 0x1c, 0x7b,
+ 0x54, 0xca, 0x16, 0xe8, 0xd1, 0x81, 0x4e, 0x7f, 0xc3, 0x85, 0x98, 0x51, 0xb4, 0x64, 0x37, 0xa2,
+ 0x81, 0xf9, 0xe0, 0xa9, 0x76, 0xb5, 0x03, 0x20, 0x98, 0x98, 0xec, 0x2a, 0xa5, 0x73, 0xd5, 0x0d,
+ 0xec, 0x7e, 0xb9, 0x9f, 0xcc, 0x67, 0x46, 0x4a, 0x8b, 0x6d, 0xa7, 0x3a, 0xab, 0xbb, 0x71, 0x37,
+ 0x95, 0x46, 0x67, 0x0e, 0x11, 0xad, 0x88, 0xd2, 0xb1, 0x80, 0x70, 0xe0, 0x75, 0xd9, 0x20, 0x2e,
+ 0xcb, 0x23, 0x1f, 0x93, 0x6e, 0xc3, 0xe0, 0x7e, 0xe6, 0xcb, 0x2b, 0xd2, 0xa5, 0x39, 0x2d, 0xe6,
+ 0xf1, 0xc2, 0xf6, 0x32, 0x0b, 0x3c, 0x93, 0xb2, 0x98, 0x65, 0xd3, 0xfe, 0x1d, 0x06, 0xfb, 0x35,
+ 0xa2, 0xe5, 0x49, 0xc1, 0xdc, 0x29, 0x4f, 0xcc, 0x0e, 0x0d, 0x11, 0xd7, 0x59, 0x13, 0x8d, 0xb6,
+ 0x4b, 0xc1, 0xba, 0x34, 0x14, 0x38, 0x45, 0xd6, 0x8e, 0xa9, 0x85, 0x40, 0xaa, 0x60, 0x09, 0xf3,
+ 0x51, 0x12, 0xc9, 0x9f, 0x01, 0x07, 0x0b, 0xbf, 0x88, 0x42, 0x5d, 0xb3, 0x50, 0x57, 0x16, 0xea,
+ 0xca, 0x42, 0x5d, 0x28, 0x64, 0x6c, 0x31, 0x50, 0x6c, 0x3e, 0x0b, 0x36, 0xcb, 0x47, 0x9f, 0xbd,
+ 0x00, 0xd5, 0x8e, 0xd5, 0x90, 0xdc, 0xd8, 0x25, 0x02, 0x2f, 0xa0, 0x0d, 0xe1, 0x0b, 0x43, 0x79,
+ 0x43, 0xd8, 0x4f, 0xf2, 0xe1, 0xeb, 0x3d, 0x06, 0xcf, 0x0b, 0xb8, 0x7e, 0x45, 0xde, 0xfd, 0x72,
+ 0x55, 0x99, 0xb7, 0xba, 0x5f, 0x8a, 0x28, 0x77, 0xf1, 0x6d, 0x4a, 0xa4, 0x43, 0x1a, 0xf1, 0xe7,
+ 0x92, 0xf8, 0x1b, 0x58, 0xfc, 0xf1, 0x2b, 0x37, 0x38, 0x85, 0xf0, 0xa3, 0x10, 0x9e, 0xdc, 0x61,
+ 0xb0, 0x2d, 0xf2, 0x05, 0xc1, 0xd8, 0xca, 0xc3, 0x0f, 0x04, 0x43, 0x85, 0x38, 0x7b, 0xbc, 0xd2,
+ 0xf0, 0xd3, 0xe9, 0x43, 0x87, 0x1e, 0x18, 0x0a, 0xac, 0x7b, 0xda, 0x40, 0x93, 0x15, 0xfd, 0xb5,
+ 0x09, 0x2e, 0x47, 0x44, 0x7e, 0x57, 0xe0, 0x81, 0x2a, 0xfc, 0x0d, 0x52, 0x0c, 0x09, 0x8b, 0x92,
+ 0x82, 0x46, 0x7f, 0xe3, 0x44, 0xfa, 0xa2, 0x1a, 0x1f, 0xdb, 0xce, 0x86, 0xcf, 0xe7, 0x01, 0xdb,
+ 0x1e, 0x26, 0x7f, 0x49, 0x2f, 0x2d, 0x0a, 0x36, 0x65, 0x3e, 0x5e, 0x44, 0xa5, 0xd0, 0x89, 0xe5,
+ 0x9d, 0x1b, 0xb0, 0xe4, 0x99, 0x51, 0x6d, 0xdf, 0xd5, 0xd1, 0x52, 0x4f, 0xa1, 0x84, 0x30, 0xa7,
+ 0x74, 0x99, 0xcb, 0x9d, 0x12, 0xc8, 0x98, 0xa6, 0x10, 0x4a, 0xf2, 0x7c, 0x0c, 0x42, 0x66, 0x41,
+ 0xf7, 0xf6, 0x20, 0x6c, 0x67, 0x1f, 0x89, 0x8d, 0x15, 0x49, 0x6f, 0x00, 0x5d, 0xa5, 0x31, 0xca,
+ 0xd2, 0x12, 0x9c, 0xfe, 0x5c, 0x20, 0xc2, 0xd6, 0x65, 0x56, 0x64, 0x0d, 0xe2, 0x09, 0xe1, 0x41,
+ 0x30, 0xf9, 0x20, 0x84, 0x1e, 0x91, 0xcc, 0xfc, 0x11, 0x86, 0x0a, 0xf8, 0x59, 0x56, 0x0c, 0xae,
+ 0x4d, 0x5a, 0xe7, 0x79, 0x11, 0x17, 0x69, 0x7f, 0xb1, 0x9a, 0x24, 0xf9, 0xb8, 0xa2, 0x20, 0x0d,
+ 0x18, 0x68, 0x98, 0x40, 0x9a, 0x10, 0x1f, 0x5c, 0x6b, 0xf1, 0x34, 0x2b, 0x36, 0xd0, 0x68, 0xea,
+ 0x38, 0x4e, 0x88, 0x06, 0x34, 0x1b, 0xc7, 0xd3, 0xb4, 0x02, 0x82, 0x06, 0xb4, 0x36, 0xf2, 0x64,
+ 0xdf, 0x82, 0x70, 0x33, 0x93, 0xb1, 0x6d, 0xd4, 0x64, 0x9d, 0xc4, 0xb3, 0xaa, 0x13, 0x54, 0x65,
+ 0xb3, 0xa9, 0x64, 0x34, 0x69, 0x83, 0xff, 0x0d, 0xec, 0xc5, 0x3c, 0x91, 0x07, 0xd4, 0xa5, 0x12,
+ 0x13, 0xa9, 0x53, 0x52, 0x9c, 0x6d, 0xe1, 0x1e, 0x5a, 0x3d, 0x97, 0x9f, 0x8c, 0x41, 0xb5, 0x43,
+ 0x3a, 0x13, 0x79, 0x22, 0x8c, 0x19, 0x4f, 0x25, 0xa0, 0x2a, 0x53, 0x2e, 0xd2, 0xd1, 0x04, 0xe2,
+ 0x46, 0x12, 0xb6, 0x1b, 0xa7, 0x51, 0xcb, 0x98, 0xd4, 0x7f, 0xf6, 0x3e, 0x73, 0x2d, 0x15, 0x86,
+ 0x1d, 0x56, 0xaf, 0xef, 0x2a, 0xe6, 0x2e, 0xbc, 0x70, 0xf2, 0x5d, 0xf5, 0x94, 0x25, 0x9d, 0x8a,
+ 0x54, 0x80, 0x0c, 0xa4, 0x04, 0xfd, 0xd9, 0xf9, 0xec, 0xb3, 0x5f, 0xdd, 0xcf, 0x3e, 0x9f, 0xbd,
+ 0x6e, 0xd0, 0x3b, 0x7f, 0x01, 0x91, 0x69, 0x1b, 0xd0, 0x67, 0x0d, 0xa8, 0xf1, 0x61, 0x15, 0x8a,
+ 0xca, 0xca, 0x88, 0xeb, 0x9a, 0xb2, 0x1e, 0x31, 0x13, 0x29, 0x0c, 0x9f, 0x9e, 0xa6, 0xfb, 0xd3,
+ 0x3e, 0xe6, 0xd9, 0xb4, 0x58, 0x17, 0x19, 0x9d, 0x05, 0xb5, 0x16, 0xa2, 0x88, 0xc8, 0x9f, 0xeb,
+ 0x5c, 0x8a, 0xa2, 0x48, 0xc7, 0xd6, 0xd6, 0x47, 0x91, 0x43, 0x51, 0xd1, 0x12, 0x99, 0xd3, 0xb8,
+ 0xf1, 0xe3, 0x49, 0x25, 0xe2, 0xa0, 0x46, 0xfe, 0x35, 0x7e, 0x38, 0xa9, 0xc9, 0x0d, 0x2a, 0x71,
+ 0x6a, 0xb4, 0x29, 0x9e, 0x2f, 0x46, 0x1e, 0xb5, 0xc9, 0xc0, 0x48, 0x01, 0x37, 0xa7, 0x4e, 0x3b,
+ 0xda, 0x5d, 0xe0, 0xa4, 0x0e, 0xa1, 0x27, 0xbd, 0xa8, 0x54, 0x9a, 0x9f, 0xc4, 0x22, 0x5a, 0x00,
+ 0x3f, 0x71, 0xc5, 0x44, 0x59, 0xe3, 0x47, 0xe4, 0xd2, 0xa0, 0x77, 0x86, 0x9e, 0x58, 0x1c, 0x09,
+ 0x8d, 0xd5, 0x51, 0x34, 0x53, 0x41, 0x0d, 0x6a, 0x3c, 0xa9, 0x29, 0xa4, 0xfc, 0xa5, 0xc9, 0x6e,
+ 0xae, 0x28, 0xd2, 0xa9, 0xf5, 0x71, 0xed, 0x20, 0xd2, 0x30, 0xda, 0x5d, 0x8c, 0xee, 0x2d, 0x5e,
+ 0x04, 0x8a, 0xcd, 0xf1, 0x5a, 0xae, 0x82, 0xd2, 0x08, 0x22, 0x64, 0x12, 0xd9, 0x2a, 0x02, 0x78,
+ 0x6b, 0xfa, 0x5d, 0x68, 0x36, 0x03, 0x43, 0x01, 0x3b, 0x70, 0x5a, 0x0b, 0x8f, 0x84, 0xe9, 0xab,
+ 0x8c, 0x0f, 0x07, 0xbe, 0xe0, 0x54, 0x59, 0xf8, 0x45, 0xed, 0x0a, 0x9c, 0xed, 0x84, 0x57, 0xa7,
+ 0x11, 0x46, 0x9c, 0x55, 0x65, 0x40, 0xd3, 0xc0, 0xaf, 0xf3, 0x27, 0x2d, 0x38, 0x20, 0xd2, 0x09,
+ 0xe3, 0xec, 0xd6, 0x17, 0x04, 0x27, 0x73, 0x83, 0x7f, 0xb2, 0x8e, 0x8b, 0xd0, 0xf3, 0x2c, 0xd0,
+ 0xf8, 0xe8, 0xcb, 0x17, 0xe4, 0xf8, 0xe6, 0xaf, 0x01, 0x0b, 0xda, 0xac, 0x7a, 0xa7, 0x41, 0x36,
+ 0xda, 0x56, 0x3f, 0x31, 0x26, 0x2a, 0x24, 0xe9, 0x48, 0x2d, 0xfe, 0x8f, 0x62, 0xc4, 0xa9, 0xab,
+ 0x23, 0xf3, 0x58, 0x1b, 0x25, 0x03, 0x3d, 0xe1, 0xae, 0x69, 0x34, 0xc6, 0x13, 0x1b, 0x66, 0xc1,
+ 0x29, 0xec, 0x7e, 0x08, 0xa6, 0x54, 0xe2, 0x88, 0xdf, 0x32, 0x91, 0x4c, 0xfe, 0x0d, 0x94, 0x05,
+ 0x14, 0x86, 0x5e, 0x5d, 0x22, 0xf9, 0x5a, 0xc2, 0x3e, 0x1d, 0x5d, 0x7b, 0x12, 0x51, 0xe6, 0xa5,
+ 0x8e, 0x10, 0xa9, 0xf9, 0x44, 0x82, 0xa2, 0x35, 0x01, 0xf1, 0x94, 0x35, 0x4d, 0xa2, 0xf1, 0x43,
+ 0x4b, 0xd7, 0x2c, 0xf4, 0x85, 0x59, 0xbc, 0x96, 0x05, 0x0e, 0x12, 0x88, 0x81, 0xae, 0x21, 0xed,
+ 0x7c, 0x6e, 0x2a, 0x45, 0x5d, 0xb7, 0x2a, 0x5c, 0x38, 0x33, 0x92, 0x1e, 0x5b, 0x2b, 0x38, 0xdc,
+ 0xf9, 0xdc, 0xad, 0x1c, 0x69, 0x0a, 0x10, 0x75, 0x31, 0x31, 0x00, 0xcf, 0x68, 0x9d, 0xa6, 0xa3,
+ 0xab, 0x76, 0x24, 0xfb, 0x4d, 0x3d, 0x41, 0x2e, 0x3d, 0xe4, 0x75, 0x54, 0xf6, 0xf7, 0xa7, 0xec,
+ 0x3f, 0x19, 0x25, 0x7a, 0x9f, 0x56, 0xc4, 0xb6, 0x16, 0x4d, 0x9d, 0xd5, 0x51, 0xaf, 0xec, 0x03,
+ 0x7b, 0x68, 0x9e, 0xa0, 0x53, 0x96, 0xd8, 0xad, 0x9a, 0xd0, 0x57, 0xd9, 0x78, 0x5c, 0x77, 0x46,
+ 0x4d, 0xe6, 0x57, 0x1f, 0x54, 0x93, 0x30, 0xb6, 0xd3, 0x6a, 0x4a, 0x6e, 0xdd, 0x56, 0x8b, 0x0e,
+ 0x56, 0xf7, 0x98, 0x57, 0x3c, 0xce, 0xeb, 0x28, 0x96, 0xf9, 0xd5, 0x14, 0x4b, 0x18, 0x1b, 0xc5,
+ 0x4a, 0x6e, 0x1d, 0xc5, 0x3a, 0xd8, 0x37, 0x7d, 0xac, 0x0d, 0x9b, 0x52, 0x73, 0x42, 0x4a, 0xe6,
+ 0x57, 0xbf, 0xbe, 0x2b, 0x40, 0xac, 0x2f, 0xf0, 0xca, 0xdc, 0xda, 0xb7, 0xd6, 0x34, 0xb0, 0x75,
+ 0x04, 0x57, 0x9f, 0x60, 0x14, 0xd9, 0xf5, 0xe4, 0x56, 0x9d, 0x65, 0x94, 0x99, 0x6b, 0x89, 0xd5,
+ 0x76, 0x82, 0x36, 0xb1, 0x53, 0x95, 0x09, 0x27, 0x7f, 0xda, 0xce, 0x75, 0xc9, 0x5c, 0x5f, 0x9f,
+ 0x86, 0xb6, 0x13, 0x5e, 0x2a, 0xaa, 0x9d, 0xa6, 0x92, 0xfc, 0x69, 0xa3, 0x45, 0xe6, 0xfa, 0xfa,
+ 0x04, 0xb3, 0xd1, 0xa2, 0xa2, 0xda, 0x7e, 0x92, 0x1c, 0xfc, 0x40, 0x98, 0xc2, 0xfb, 0xf2, 0xa7,
+ 0xed, 0xfd, 0x5f, 0x91, 0xe9, 0xeb, 0x13, 0xc2, 0xfa, 0x0e, 0xb0, 0x82, 0x69, 0x17, 0xae, 0x16,
+ 0xbf, 0xaa, 0x08, 0x61, 0x47, 0xf1, 0x14, 0x46, 0xaf, 0x24, 0x83, 0xed, 0x59, 0x5a, 0xd8, 0xf5,
+ 0xe8, 0xcf, 0x38, 0xfa, 0x33, 0x8e, 0xfe, 0x8c, 0xa3, 0x3f, 0xe3, 0xe8, 0xcf, 0x78, 0x1e, 0xfe,
+ 0x0c, 0x7e, 0x06, 0x59, 0x9e, 0x88, 0xd3, 0x0e, 0xd0, 0x51, 0x26, 0x78, 0x52, 0x2e, 0x0f, 0xf9,
+ 0xde, 0xd5, 0x7c, 0x96, 0x8f, 0x63, 0x68, 0xfd, 0x03, 0x7c, 0x20, 0xcc, 0x00, 0xa2, 0xe7, 0xdf,
+ 0x48, 0xdb, 0xda, 0x4b, 0xb8, 0xda, 0x85, 0x37, 0xd4, 0xa8, 0x15, 0x44, 0x37, 0x0d, 0x95, 0x0e,
+ 0xf2, 0xe9, 0x0b, 0xa3, 0x55, 0xf5, 0xa3, 0x5b, 0x85, 0xdf, 0xc1, 0xba, 0x7c, 0xfb, 0x73, 0xff,
+ 0xe3, 0x3f, 0x1a, 0xaf, 0xda, 0x9d, 0x93, 0xb2, 0xa9, 0x09, 0xab, 0x6b, 0x58, 0xe7, 0x80, 0xb1,
+ 0x1b, 0x83, 0xea, 0xd1, 0x98, 0x6d, 0xcf, 0xe7, 0x19, 0x76, 0xee, 0x63, 0x9a, 0x82, 0x87, 0x35,
+ 0xe3, 0x0e, 0x68, 0x82, 0x1d, 0xca, 0x8a, 0x3a, 0xa8, 0x09, 0xb4, 0x4f, 0x0b, 0xa6, 0x96, 0x4d,
+ 0xb6, 0x33, 0x40, 0xea, 0xed, 0x8f, 0xad, 0xec, 0x87, 0x7d, 0x9c, 0xb7, 0x53, 0x46, 0x6f, 0x3b,
+ 0x45, 0xbe, 0x6e, 0x68, 0x36, 0xd6, 0xc5, 0x29, 0xcc, 0xbb, 0xb7, 0xbf, 0xbc, 0xeb, 0xff, 0xf2,
+ 0xe6, 0xb7, 0xdf, 0xde, 0x10, 0x8d, 0xa1, 0xdb, 0x39, 0x0f, 0xec, 0xc1, 0xfb, 0xb8, 0x18, 0x67,
+ 0xb3, 0x1c, 0xb4, 0xef, 0xb2, 0xe8, 0x67, 0xb3, 0x5d, 0xdc, 0x9e, 0x47, 0xa5, 0x91, 0x27, 0xae,
+ 0x54, 0x09, 0xce, 0x3b, 0x8a, 0x65, 0x4a, 0x45, 0x7c, 0x43, 0xc5, 0x47, 0x46, 0x91, 0xa0, 0xa3,
+ 0xa6, 0x0c, 0xbf, 0x2a, 0xed, 0x90, 0xb8, 0x48, 0x36, 0x31, 0x70, 0x04, 0x7e, 0x4f, 0x93, 0x84,
+ 0x6e, 0xa8, 0x9e, 0xb8, 0xbc, 0xb9, 0xba, 0x8a, 0x1c, 0xd4, 0xa7, 0x5b, 0x78, 0x43, 0x82, 0xe9,
+ 0xd6, 0x42, 0x5b, 0x87, 0xbe, 0xe4, 0x07, 0x75, 0x22, 0x85, 0x5d, 0x68, 0x75, 0x8e, 0xe8, 0x6a,
+ 0xaf, 0xdb, 0xee, 0xbe, 0x0e, 0xa8, 0x10, 0x6f, 0x4a, 0x2a, 0xdc, 0x1a, 0x32, 0x68, 0xdd, 0x50,
+ 0xb3, 0x1c, 0xf9, 0x40, 0x2e, 0xbc, 0x0c, 0x59, 0xf8, 0x45, 0x21, 0x17, 0x8f, 0x0b, 0xda, 0x3c,
+ 0xca, 0xe0, 0x4f, 0x6e, 0xc7, 0xe5, 0x0e, 0xa1, 0x75, 0x0d, 0x23, 0xfc, 0xf0, 0xd4, 0xf5, 0x40,
+ 0xd3, 0x85, 0xd0, 0x9b, 0xad, 0x1c, 0x30, 0x04, 0xd2, 0x5a, 0x2a, 0x02, 0x1f, 0x52, 0x9a, 0x5a,
+ 0xca, 0x86, 0xa7, 0x09, 0x3d, 0x7d, 0xc5, 0x7b, 0x90, 0xb7, 0xfb, 0xff, 0x01, 0x20, 0xfc, 0x89,
+ 0x13
};
const char* shaderSource() {
diff --git a/src/mbgl/programs/gl/symbol_icon.cpp b/src/mbgl/programs/gl/symbol_icon.cpp
index b7f54b590b..49c7654cf8 100644
--- a/src/mbgl/programs/gl/symbol_icon.cpp
+++ b/src/mbgl/programs/gl/symbol_icon.cpp
@@ -16,8 +16,8 @@ template <>
struct ShaderSource<SymbolIconProgram> {
static constexpr const char* name = "symbol_icon";
static constexpr const uint8_t hash[8] = { 0xf3, 0x81, 0x62, 0xe8, 0x24, 0x49, 0xc6, 0x8f };
- static constexpr const auto vertexOffset = 50235;
- static constexpr const auto fragmentOffset = 52883;
+ static constexpr const auto vertexOffset = 50247;
+ static constexpr const auto fragmentOffset = 52895;
};
constexpr const char* ShaderSource<SymbolIconProgram>::name;
diff --git a/src/mbgl/programs/gl/symbol_sdf_icon.cpp b/src/mbgl/programs/gl/symbol_sdf_icon.cpp
index 76228062c6..661fc7d298 100644
--- a/src/mbgl/programs/gl/symbol_sdf_icon.cpp
+++ b/src/mbgl/programs/gl/symbol_sdf_icon.cpp
@@ -16,8 +16,8 @@ template <>
struct ShaderSource<SymbolSDFIconProgram> {
static constexpr const char* name = "symbol_sdf_icon";
static constexpr const uint8_t hash[8] = { 0x4b, 0x0b, 0x5f, 0x6b, 0xa9, 0xec, 0x84, 0x19 };
- static constexpr const auto vertexOffset = 53288;
- static constexpr const auto fragmentOffset = 57322;
+ static constexpr const auto vertexOffset = 53300;
+ static constexpr const auto fragmentOffset = 57334;
};
constexpr const char* ShaderSource<SymbolSDFIconProgram>::name;
diff --git a/src/mbgl/programs/gl/symbol_sdf_text.cpp b/src/mbgl/programs/gl/symbol_sdf_text.cpp
index 31acda6f55..7eb0dbabed 100644
--- a/src/mbgl/programs/gl/symbol_sdf_text.cpp
+++ b/src/mbgl/programs/gl/symbol_sdf_text.cpp
@@ -16,8 +16,8 @@ template <>
struct ShaderSource<SymbolSDFTextProgram> {
static constexpr const char* name = "symbol_sdf_text";
static constexpr const uint8_t hash[8] = { 0x4b, 0x0b, 0x5f, 0x6b, 0xa9, 0xec, 0x84, 0x19 };
- static constexpr const auto vertexOffset = 53288;
- static constexpr const auto fragmentOffset = 57322;
+ static constexpr const auto vertexOffset = 53300;
+ static constexpr const auto fragmentOffset = 57334;
};
constexpr const char* ShaderSource<SymbolSDFTextProgram>::name;
diff --git a/src/mbgl/programs/hillshade_prepare_program.hpp b/src/mbgl/programs/hillshade_prepare_program.hpp
index 2d76145bc3..c85b5bc609 100644
--- a/src/mbgl/programs/hillshade_prepare_program.hpp
+++ b/src/mbgl/programs/hillshade_prepare_program.hpp
@@ -11,6 +11,7 @@ namespace mbgl {
namespace uniforms {
MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 2, dimension);
MBGL_DEFINE_UNIFORM_SCALAR(float, maxzoom);
+MBGL_DEFINE_UNIFORM_VECTOR(float, 4, unpack);
} // namespace uniforms
class HillshadePrepareProgram : public Program<
@@ -23,7 +24,8 @@ class HillshadePrepareProgram : public Program<
uniforms::matrix,
uniforms::dimension,
uniforms::zoom,
- uniforms::maxzoom>,
+ uniforms::maxzoom,
+ uniforms::unpack>,
TypeList<
textures::image>,
style::Properties<>> {
diff --git a/src/mbgl/programs/program_parameters.cpp b/src/mbgl/programs/program_parameters.cpp
index a49dc2bc88..95d2d0f668 100644
--- a/src/mbgl/programs/program_parameters.cpp
+++ b/src/mbgl/programs/program_parameters.cpp
@@ -4,8 +4,7 @@
namespace mbgl {
ProgramParameters::ProgramParameters(const float pixelRatio,
- const bool overdraw,
- optional<std::string> cacheDir_)
+ const bool overdraw)
: defines([&] {
std::string result;
result.reserve(32);
@@ -16,28 +15,11 @@ ProgramParameters::ProgramParameters(const float pixelRatio,
result += "#define OVERDRAW_INSPECTOR\n";
}
return result;
- }()),
- cacheDir(std::move(cacheDir_)) {
+ }()) {
}
const std::string& ProgramParameters::getDefines() const {
return defines;
}
-optional<std::string> ProgramParameters::cachePath(const char* name) const {
- if (!cacheDir) {
- return {};
- } else {
- std::string result;
- result.reserve(cacheDir->length() + 64);
- result += *cacheDir;
- result += "/com.mapbox.gl.shader.";
- result += name;
- result += '.';
- result += util::toHex(static_cast<uint64_t>(std::hash<std::string>()(defines)));
- result += ".pbf";
- return result;
- }
-}
-
} // namespace mbgl
diff --git a/src/mbgl/programs/program_parameters.hpp b/src/mbgl/programs/program_parameters.hpp
index 71ad454399..8af7ab50c0 100644
--- a/src/mbgl/programs/program_parameters.hpp
+++ b/src/mbgl/programs/program_parameters.hpp
@@ -8,14 +8,12 @@ namespace mbgl {
class ProgramParameters {
public:
- ProgramParameters(float pixelRatio, bool overdraw, optional<std::string> cacheDir);
+ ProgramParameters(float pixelRatio, bool overdraw);
const std::string& getDefines() const;
- optional<std::string> cachePath(const char* name) const;
private:
std::string defines;
- optional<std::string> cacheDir;
};
} // namespace mbgl
diff --git a/src/mbgl/programs/symbol_program.cpp b/src/mbgl/programs/symbol_program.cpp
index 3633bd7c2a..bfc0133676 100644
--- a/src/mbgl/programs/symbol_program.cpp
+++ b/src/mbgl/programs/symbol_program.cpp
@@ -67,7 +67,7 @@ Values makeValues(const bool isText,
const bool rotateInShader = rotateWithMap && !pitchWithMap && !alongLine;
mat4 labelPlaneMatrix;
- if (alongLine || (isText && hasVariablePacement)) {
+ if (alongLine || hasVariablePacement) {
// For labels that follow lines the first part of the projection is handled on the cpu.
// Pass an identity matrix because no transformation needs to be done in the vertex shader.
matrix::identity(labelPlaneMatrix);
diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp
index 21a7870473..ff201e9c2c 100644
--- a/src/mbgl/renderer/buckets/symbol_bucket.cpp
+++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp
@@ -18,7 +18,6 @@ SymbolBucket::SymbolBucket(Immutable<style::SymbolLayoutProperties::PossiblyEval
const style::PropertyValue<float>& textSize,
const style::PropertyValue<float>& iconSize,
float zoom,
- bool sdfIcons_,
bool iconsNeedLinear_,
bool sortFeaturesByY_,
const std::string bucketName_,
@@ -28,7 +27,6 @@ SymbolBucket::SymbolBucket(Immutable<style::SymbolLayoutProperties::PossiblyEval
std::vector<style::TextWritingModeType> placementModes_)
: layout(std::move(layout_)),
bucketLeaderID(std::move(bucketName_)),
- sdfIcons(sdfIcons_),
iconsNeedLinear(iconsNeedLinear_ || iconSize.isDataDriven() || !iconSize.isZoomConstant()),
sortFeaturesByY(sortFeaturesByY_),
staticUploaded(false),
@@ -87,58 +85,78 @@ void SymbolBucket::upload(gfx::UploadPass& uploadPass) {
}
}
- if (hasIconData()) {
+ auto updateIconBuffer = [&](Buffer& iconBuffer) {
if (!staticUploaded) {
- icon.indexBuffer = uploadPass.createIndexBuffer(std::move(icon.triangles), sortFeaturesByY ? gfx::BufferUsageType::StreamDraw : gfx::BufferUsageType::StaticDraw);
- icon.vertexBuffer = uploadPass.createVertexBuffer(std::move(icon.vertices));
+ iconBuffer.indexBuffer = uploadPass.createIndexBuffer(std::move(iconBuffer.triangles), sortFeaturesByY ? gfx::BufferUsageType::StreamDraw : gfx::BufferUsageType::StaticDraw);
+ iconBuffer.vertexBuffer = uploadPass.createVertexBuffer(std::move(iconBuffer.vertices));
for (auto& pair : paintProperties) {
pair.second.iconBinders.upload(uploadPass);
}
} else if (!sortUploaded) {
- uploadPass.updateIndexBuffer(*icon.indexBuffer, std::move(icon.triangles));
+ uploadPass.updateIndexBuffer(*iconBuffer.indexBuffer, std::move(iconBuffer.triangles));
}
if (!dynamicUploaded) {
- if (!icon.dynamicVertexBuffer) {
- icon.dynamicVertexBuffer = uploadPass.createVertexBuffer(std::move(icon.dynamicVertices), gfx::BufferUsageType::StreamDraw);
+ if (!iconBuffer.dynamicVertexBuffer) {
+ iconBuffer.dynamicVertexBuffer = uploadPass.createVertexBuffer(std::move(iconBuffer.dynamicVertices), gfx::BufferUsageType::StreamDraw);
} else {
- uploadPass.updateVertexBuffer(*icon.dynamicVertexBuffer, std::move(icon.dynamicVertices));
+ uploadPass.updateVertexBuffer(*iconBuffer.dynamicVertexBuffer, std::move(iconBuffer.dynamicVertices));
}
}
if (!placementChangesUploaded) {
- if (!icon.opacityVertexBuffer) {
- icon.opacityVertexBuffer = uploadPass.createVertexBuffer(std::move(icon.opacityVertices), gfx::BufferUsageType::StreamDraw);
+ if (!iconBuffer.opacityVertexBuffer) {
+ iconBuffer.opacityVertexBuffer = uploadPass.createVertexBuffer(std::move(iconBuffer.opacityVertices), gfx::BufferUsageType::StreamDraw);
} else {
- uploadPass.updateVertexBuffer(*icon.opacityVertexBuffer, std::move(icon.opacityVertices));
+ uploadPass.updateVertexBuffer(*iconBuffer.opacityVertexBuffer, std::move(iconBuffer.opacityVertices));
}
}
+ };
+ if (hasIconData()) {
+ updateIconBuffer(icon);
+ }
+ if (hasSdfIconData()) {
+ updateIconBuffer(sdfIcon);
}
- if (hasCollisionBoxData()) {
+ const auto updateCollisionBox = [&](CollisionBoxBuffer& collisionBox) {
if (!staticUploaded) {
- collisionBox->indexBuffer = uploadPass.createIndexBuffer(std::move(collisionBox->lines));
- collisionBox->vertexBuffer = uploadPass.createVertexBuffer(std::move(collisionBox->vertices));
+ collisionBox.indexBuffer = uploadPass.createIndexBuffer(std::move(collisionBox.lines));
+ collisionBox.vertexBuffer = uploadPass.createVertexBuffer(std::move(collisionBox.vertices));
}
if (!placementChangesUploaded) {
- if (!collisionBox->dynamicVertexBuffer) {
- collisionBox->dynamicVertexBuffer = uploadPass.createVertexBuffer(std::move(collisionBox->dynamicVertices), gfx::BufferUsageType::StreamDraw);
+ if (!collisionBox.dynamicVertexBuffer) {
+ collisionBox.dynamicVertexBuffer = uploadPass.createVertexBuffer(std::move(collisionBox.dynamicVertices), gfx::BufferUsageType::StreamDraw);
} else {
- uploadPass.updateVertexBuffer(*collisionBox->dynamicVertexBuffer, std::move(collisionBox->dynamicVertices));
+ uploadPass.updateVertexBuffer(*collisionBox.dynamicVertexBuffer, std::move(collisionBox.dynamicVertices));
}
}
+ };
+ if (hasIconCollisionBoxData()) {
+ updateCollisionBox(*iconCollisionBox);
+ }
+
+ if (hasTextCollisionBoxData()) {
+ updateCollisionBox(*textCollisionBox);
}
- if (hasCollisionCircleData()) {
+ const auto updateCollisionCircle = [&](CollisionCircleBuffer& collisionCircle) {
if (!staticUploaded) {
- collisionCircle->indexBuffer = uploadPass.createIndexBuffer(std::move(collisionCircle->triangles));
- collisionCircle->vertexBuffer = uploadPass.createVertexBuffer(std::move(collisionCircle->vertices));
+ collisionCircle.indexBuffer = uploadPass.createIndexBuffer(std::move(collisionCircle.triangles));
+ collisionCircle.vertexBuffer = uploadPass.createVertexBuffer(std::move(collisionCircle.vertices));
}
if (!placementChangesUploaded) {
- if (!collisionCircle->dynamicVertexBuffer) {
- collisionCircle->dynamicVertexBuffer = uploadPass.createVertexBuffer(std::move(collisionCircle->dynamicVertices), gfx::BufferUsageType::StreamDraw);
+ if (!collisionCircle.dynamicVertexBuffer) {
+ collisionCircle.dynamicVertexBuffer = uploadPass.createVertexBuffer(std::move(collisionCircle.dynamicVertices), gfx::BufferUsageType::StreamDraw);
} else {
- uploadPass.updateVertexBuffer(*collisionCircle->dynamicVertexBuffer, std::move(collisionCircle->dynamicVertices));
+ uploadPass.updateVertexBuffer(*collisionCircle.dynamicVertexBuffer, std::move(collisionCircle.dynamicVertices));
}
}
+ };
+ if (hasIconCollisionCircleData()) {
+ updateCollisionCircle(*iconCollisionCircle);
+ }
+
+ if (hasTextCollisionCircleData()) {
+ updateCollisionCircle(*textCollisionCircle);
}
uploaded = true;
@@ -149,7 +167,8 @@ void SymbolBucket::upload(gfx::UploadPass& uploadPass) {
}
bool SymbolBucket::hasData() const {
- return hasTextData() || hasIconData() || hasCollisionBoxData();
+ return hasTextData() || hasIconData() || hasSdfIconData() || hasIconCollisionBoxData() ||
+ hasTextCollisionBoxData() || hasIconCollisionCircleData() || hasTextCollisionCircleData();
}
bool SymbolBucket::hasTextData() const {
@@ -160,12 +179,24 @@ bool SymbolBucket::hasIconData() const {
return !icon.segments.empty();
}
-bool SymbolBucket::hasCollisionBoxData() const {
- return collisionBox && !collisionBox->segments.empty();
+bool SymbolBucket::hasSdfIconData() const {
+ return !sdfIcon.segments.empty();
}
-bool SymbolBucket::hasCollisionCircleData() const {
- return collisionCircle && !collisionCircle->segments.empty();
+bool SymbolBucket::hasIconCollisionBoxData() const {
+ return iconCollisionBox && !iconCollisionBox->segments.empty();
+}
+
+bool SymbolBucket::hasIconCollisionCircleData() const {
+ return iconCollisionCircle && !iconCollisionCircle->segments.empty();
+}
+
+bool SymbolBucket::hasTextCollisionBoxData() const {
+ return textCollisionBox && !textCollisionBox->segments.empty();
+}
+
+bool SymbolBucket::hasTextCollisionCircleData() const {
+ return textCollisionCircle && !textCollisionCircle->segments.empty();
}
void addPlacedSymbol(gfx::IndexVector<gfx::Triangles>& triangles, const PlacedSymbol& placedSymbol) {
@@ -188,9 +219,9 @@ void SymbolBucket::sortFeatures(const float angle) {
sortedAngle = angle;
- // The current approach to sorting doesn't sort across segments so don't try.
+ // The current approach to sorting doesn't sort across text and icon segments so don't try.
// Sorting within segments separately seemed not to be worth the complexity.
- if (text.segments.size() > 1 || icon.segments.size() > 1) {
+ if (text.segments.size() > 1 || (icon.segments.size() > 1 || sdfIcon.segments.size() > 1)) {
return;
}
@@ -199,6 +230,7 @@ void SymbolBucket::sortFeatures(const float angle) {
text.triangles.clear();
icon.triangles.clear();
+ sdfIcon.triangles.clear();
featureSortOrder = std::make_unique<std::vector<size_t>>();
featureSortOrder->reserve(symbolInstances.size());
@@ -225,8 +257,13 @@ void SymbolBucket::sortFeatures(const float angle) {
addPlacedSymbol(text.triangles, text.placedSymbols[*symbolInstance.placedVerticalTextIndex]);
}
+ auto& iconBuffer = symbolInstance.hasSdfIcon() ? sdfIcon : icon;
if (symbolInstance.placedIconIndex) {
- addPlacedSymbol(icon.triangles, icon.placedSymbols[*symbolInstance.placedIconIndex]);
+ addPlacedSymbol(iconBuffer.triangles, iconBuffer.placedSymbols[*symbolInstance.placedIconIndex]);
+ }
+
+ if (symbolInstance.placedVerticalIconIndex) {
+ addPlacedSymbol(iconBuffer.triangles, iconBuffer.placedSymbols[*symbolInstance.placedVerticalIconIndex]);
}
}
}
diff --git a/src/mbgl/renderer/buckets/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp
index f47ced8331..020190b81f 100644
--- a/src/mbgl/renderer/buckets/symbol_bucket.hpp
+++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp
@@ -21,9 +21,9 @@ class CrossTileSymbolLayerIndex;
class PlacedSymbol {
public:
PlacedSymbol(Point<float> anchorPoint_, uint16_t segment_, float lowerSize_, float upperSize_,
- std::array<float, 2> lineOffset_, WritingModeType writingModes_, GeometryCoordinates line_, std::vector<float> tileDistances_) :
+ std::array<float, 2> lineOffset_, WritingModeType writingModes_, GeometryCoordinates line_, std::vector<float> tileDistances_, optional<size_t> placedIconIndex_ = nullopt) :
anchorPoint(anchorPoint_), segment(segment_), lowerSize(lowerSize_), upperSize(upperSize_),
- lineOffset(lineOffset_), writingModes(writingModes_), line(std::move(line_)), tileDistances(std::move(tileDistances_)), hidden(false), vertexStartIndex(0)
+ lineOffset(lineOffset_), writingModes(writingModes_), line(std::move(line_)), tileDistances(std::move(tileDistances_)), hidden(false), vertexStartIndex(0), placedIconIndex(std::move(placedIconIndex_))
{
}
Point<float> anchorPoint;
@@ -43,6 +43,9 @@ public:
// placement for orientation variants.
optional<style::TextWritingModeType> placedOrientation;
float angle = 0;
+
+ // Reference to placed icon, only applicable for text symbols.
+ optional<size_t> placedIconIndex;
};
class SymbolBucket final : public Bucket {
@@ -52,7 +55,6 @@ public:
const style::PropertyValue<float>& textSize,
const style::PropertyValue<float>& iconSize,
float zoom,
- bool sdfIcons,
bool iconsNeedLinear,
bool sortFeaturesByY,
const std::string bucketLeaderID,
@@ -69,8 +71,11 @@ public:
void updateVertices(Placement&, bool updateOpacities, const TransformState&, const RenderTile&, std::set<uint32_t>&) override;
bool hasTextData() const;
bool hasIconData() const;
- bool hasCollisionBoxData() const;
- bool hasCollisionCircleData() const;
+ bool hasSdfIconData() const;
+ bool hasIconCollisionBoxData() const;
+ bool hasIconCollisionCircleData() const;
+ bool hasTextCollisionBoxData() const;
+ bool hasTextCollisionCircleData() const;
bool hasFormatSectionOverrides() const;
@@ -83,7 +88,6 @@ public:
float sortedAngle = std::numeric_limits<float>::max();
// Flags
- const bool sdfIcons : 1;
const bool iconsNeedLinear : 1;
const bool sortFeaturesByY : 1;
bool staticUploaded : 1;
@@ -121,7 +125,8 @@ public:
std::unique_ptr<SymbolSizeBinder> iconSizeBinder;
Buffer icon;
-
+ Buffer sdfIcon;
+
struct CollisionBuffer {
gfx::VertexVector<gfx::Vertex<CollisionBoxLayoutAttributes>> vertices;
gfx::VertexVector<gfx::Vertex<CollisionBoxDynamicAttributes>> dynamicVertices;
@@ -135,22 +140,34 @@ public:
gfx::IndexVector<gfx::Lines> lines;
optional<gfx::IndexBuffer> indexBuffer;
};
- std::unique_ptr<CollisionBoxBuffer> collisionBox;
+ std::unique_ptr<CollisionBoxBuffer> iconCollisionBox;
+ std::unique_ptr<CollisionBoxBuffer> textCollisionBox;
+
+ CollisionBoxBuffer& getOrCreateIconCollisionBox() {
+ if (!iconCollisionBox) iconCollisionBox = std::make_unique<CollisionBoxBuffer>();
+ return *iconCollisionBox;
+ }
- CollisionBoxBuffer& getOrCreateCollisionBox() {
- if (!collisionBox) collisionBox = std::make_unique<CollisionBoxBuffer>();
- return *collisionBox;
+ CollisionBoxBuffer& getOrCreateTextCollisionBox() {
+ if (!textCollisionBox) textCollisionBox = std::make_unique<CollisionBoxBuffer>();
+ return *textCollisionBox;
}
struct CollisionCircleBuffer : public CollisionBuffer {
gfx::IndexVector<gfx::Triangles> triangles;
optional<gfx::IndexBuffer> indexBuffer;
};
- std::unique_ptr<CollisionCircleBuffer> collisionCircle;
+ std::unique_ptr<CollisionCircleBuffer> iconCollisionCircle;
+ std::unique_ptr<CollisionCircleBuffer> textCollisionCircle;
+
+ CollisionCircleBuffer& getOrCreateIconCollisionCircleBuffer() {
+ if (!iconCollisionCircle) iconCollisionCircle = std::make_unique<CollisionCircleBuffer>();
+ return *iconCollisionCircle;
+ }
- CollisionCircleBuffer& getOrCreateCollisionCircleBuffer() {
- if (!collisionCircle) collisionCircle = std::make_unique<CollisionCircleBuffer>();
- return *collisionCircle;
+ CollisionCircleBuffer& getOrCreateTextCollisionCircleBuffer() {
+ if (!textCollisionCircle) textCollisionCircle = std::make_unique<CollisionCircleBuffer>();
+ return *textCollisionCircle;
}
const float tilePixelRatio;
diff --git a/src/mbgl/renderer/image_manager.cpp b/src/mbgl/renderer/image_manager.cpp
index 3c22cdcf32..4bbdbca5d9 100644
--- a/src/mbgl/renderer/image_manager.cpp
+++ b/src/mbgl/renderer/image_manager.cpp
@@ -81,6 +81,7 @@ void ImageManager::removeImage(const std::string& id) {
requestedImages.erase(requestedIt);
}
images.erase(it);
+ updatedImageVersions.erase(id);
}
const style::Image::Impl* ImageManager::getImage(const std::string& id) const {
diff --git a/src/mbgl/renderer/layers/render_background_layer.cpp b/src/mbgl/renderer/layers/render_background_layer.cpp
index 4725bce435..6f76efda7a 100644
--- a/src/mbgl/renderer/layers/render_background_layer.cpp
+++ b/src/mbgl/renderer/layers/render_background_layer.cpp
@@ -16,10 +16,15 @@ namespace mbgl {
using namespace style;
+namespace {
+
inline const BackgroundLayer::Impl& impl(const Immutable<style::Layer::Impl>& impl) {
+ assert(impl->getTypeInfo() == BackgroundLayer::Impl::staticTypeInfo());
return static_cast<const style::BackgroundLayer::Impl&>(*impl);
}
+} // namespace
+
RenderBackgroundLayer::RenderBackgroundLayer(Immutable<style::BackgroundLayer::Impl> _impl)
: RenderLayer(makeMutable<BackgroundLayerProperties>(std::move(_impl))),
unevaluated(impl(baseImpl).paint.untransitioned()) {
diff --git a/src/mbgl/renderer/layers/render_circle_layer.cpp b/src/mbgl/renderer/layers/render_circle_layer.cpp
index 4f1620364f..ea0c20f124 100644
--- a/src/mbgl/renderer/layers/render_circle_layer.cpp
+++ b/src/mbgl/renderer/layers/render_circle_layer.cpp
@@ -15,10 +15,15 @@ namespace mbgl {
using namespace style;
+namespace {
+
inline const style::CircleLayer::Impl& impl(const Immutable<style::Layer::Impl>& impl) {
+ assert(impl->getTypeInfo() == CircleLayer::Impl::staticTypeInfo());
return static_cast<const style::CircleLayer::Impl&>(*impl);
}
+} // namespace
+
RenderCircleLayer::RenderCircleLayer(Immutable<style::CircleLayer::Impl> _impl)
: RenderLayer(makeMutable<CircleLayerProperties>(std::move(_impl))),
unevaluated(impl(baseImpl).paint.untransitioned()) {
diff --git a/src/mbgl/renderer/layers/render_custom_layer.cpp b/src/mbgl/renderer/layers/render_custom_layer.cpp
index 75c21997b0..c53286a2a0 100644
--- a/src/mbgl/renderer/layers/render_custom_layer.cpp
+++ b/src/mbgl/renderer/layers/render_custom_layer.cpp
@@ -14,10 +14,15 @@ namespace mbgl {
using namespace style;
+namespace {
+
inline const CustomLayer::Impl& impl(const Immutable<style::Layer::Impl>& impl) {
+ assert(impl->getTypeInfo() == CustomLayer::Impl::staticTypeInfo());
return static_cast<const CustomLayer::Impl&>(*impl);
}
+} // namespace
+
RenderCustomLayer::RenderCustomLayer(Immutable<style::CustomLayer::Impl> _impl)
: RenderLayer(makeMutable<CustomLayerProperties>(std::move(_impl))),
host(impl(baseImpl).host) {
diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp
index 3c97ab7431..835e8c8ee5 100644
--- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp
+++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp
@@ -20,10 +20,15 @@ namespace mbgl {
using namespace style;
+namespace {
+
inline const FillExtrusionLayer::Impl& impl(const Immutable<style::Layer::Impl>& impl) {
+ assert(impl->getTypeInfo() == FillExtrusionLayer::Impl::staticTypeInfo());
return static_cast<const FillExtrusionLayer::Impl&>(*impl);
}
+} // namespace
+
RenderFillExtrusionLayer::RenderFillExtrusionLayer(Immutable<style::FillExtrusionLayer::Impl> _impl)
: RenderLayer(makeMutable<FillExtrusionLayerProperties>(std::move(_impl))),
unevaluated(impl(baseImpl).paint.untransitioned()) {
diff --git a/src/mbgl/renderer/layers/render_fill_layer.cpp b/src/mbgl/renderer/layers/render_fill_layer.cpp
index 6a134a398a..27cb76fede 100644
--- a/src/mbgl/renderer/layers/render_fill_layer.cpp
+++ b/src/mbgl/renderer/layers/render_fill_layer.cpp
@@ -21,10 +21,15 @@ namespace mbgl {
using namespace style;
+namespace {
+
inline const FillLayer::Impl& impl(const Immutable<style::Layer::Impl>& impl) {
+ assert(impl->getTypeInfo() == FillLayer::Impl::staticTypeInfo());
return static_cast<const FillLayer::Impl&>(*impl);
}
+} // namespace
+
RenderFillLayer::RenderFillLayer(Immutable<style::FillLayer::Impl> _impl)
: RenderLayer(makeMutable<FillLayerProperties>(std::move(_impl))),
unevaluated(impl(baseImpl).paint.untransitioned()) {
diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.cpp b/src/mbgl/renderer/layers/render_heatmap_layer.cpp
index 478a8f8c47..4fa20ffd13 100644
--- a/src/mbgl/renderer/layers/render_heatmap_layer.cpp
+++ b/src/mbgl/renderer/layers/render_heatmap_layer.cpp
@@ -19,10 +19,15 @@ namespace mbgl {
using namespace style;
+namespace {
+
inline const HeatmapLayer::Impl& impl(const Immutable<Layer::Impl>& impl) {
+ assert(impl->getTypeInfo() == HeatmapLayer::Impl::staticTypeInfo());
return static_cast<const HeatmapLayer::Impl&>(*impl);
}
+} // namespace
+
RenderHeatmapLayer::RenderHeatmapLayer(Immutable<HeatmapLayer::Impl> _impl)
: RenderLayer(makeMutable<HeatmapLayerProperties>(std::move(_impl))),
unevaluated(impl(baseImpl).paint.untransitioned()), colorRamp({256, 1}) {
diff --git a/src/mbgl/renderer/layers/render_hillshade_layer.cpp b/src/mbgl/renderer/layers/render_hillshade_layer.cpp
index 2c7e0aef86..b570d9c4c9 100644
--- a/src/mbgl/renderer/layers/render_hillshade_layer.cpp
+++ b/src/mbgl/renderer/layers/render_hillshade_layer.cpp
@@ -18,10 +18,15 @@ namespace mbgl {
using namespace style;
+namespace {
+
inline const HillshadeLayer::Impl& impl(const Immutable<style::Layer::Impl>& impl) {
+ assert(impl->getTypeInfo() == HillshadeLayer::Impl::staticTypeInfo());
return static_cast<const HillshadeLayer::Impl&>(*impl);
}
+} // namespace
+
RenderHillshadeLayer::RenderHillshadeLayer(Immutable<style::HillshadeLayer::Impl> _impl)
: RenderLayer(makeMutable<HillshadeLayerProperties>(std::move(_impl))),
unevaluated(impl(baseImpl).paint.untransitioned()) {
@@ -158,6 +163,7 @@ void RenderHillshadeLayer::render(PaintParameters& parameters) {
uniforms::dimension::Value( {{stride, stride}} ),
uniforms::zoom::Value( float(tile.id.canonical.z) ),
uniforms::maxzoom::Value( float(maxzoom) ),
+ uniforms::unpack::Value( bucket.getDEMData().getUnpackVector() ),
},
paintAttributeData,
properties,
diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp
index fcd52b21df..6d635f65e7 100644
--- a/src/mbgl/renderer/layers/render_line_layer.cpp
+++ b/src/mbgl/renderer/layers/render_line_layer.cpp
@@ -20,10 +20,15 @@ namespace mbgl {
using namespace style;
+namespace {
+
inline const LineLayer::Impl& impl(const Immutable<style::Layer::Impl>& impl) {
+ assert(impl->getTypeInfo() == LineLayer::Impl::staticTypeInfo());
return static_cast<const LineLayer::Impl&>(*impl);
}
+} // namespace
+
RenderLineLayer::RenderLineLayer(Immutable<style::LineLayer::Impl> _impl)
: RenderLayer(makeMutable<LineLayerProperties>(std::move(_impl))),
unevaluated(impl(baseImpl).paint.untransitioned()),
diff --git a/src/mbgl/renderer/layers/render_raster_layer.cpp b/src/mbgl/renderer/layers/render_raster_layer.cpp
index 82d135b9ef..8a1a8a6c28 100644
--- a/src/mbgl/renderer/layers/render_raster_layer.cpp
+++ b/src/mbgl/renderer/layers/render_raster_layer.cpp
@@ -14,10 +14,15 @@ namespace mbgl {
using namespace style;
+namespace {
+
inline const RasterLayer::Impl& impl(const Immutable<style::Layer::Impl>& impl) {
+ assert(impl->getTypeInfo() == RasterLayer::Impl::staticTypeInfo());
return static_cast<const RasterLayer::Impl&>(*impl);
}
+} // namespace
+
RenderRasterLayer::RenderRasterLayer(Immutable<style::RasterLayer::Impl> _impl)
: RenderLayer(makeMutable<RasterLayerProperties>(std::move(_impl))),
unevaluated(impl(baseImpl).paint.untransitioned()) {
diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp
index 4dddd57009..06eacc041b 100644
--- a/src/mbgl/renderer/layers/render_symbol_layer.cpp
+++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp
@@ -67,20 +67,20 @@ struct RenderableSegment {
const LayerRenderData& renderData_,
const SymbolBucket::PaintProperties& bucketPaintProperties_,
float sortKey_,
- bool isText_) :
+ const SymbolType type_) :
segment(std::move(segment_)),
tile(tile_),
renderData(renderData_),
bucketPaintProperties(bucketPaintProperties_),
sortKey(sortKey_),
- isText(isText_) {}
+ type(type_) {}
SegmentWrapper segment;
const RenderTile& tile;
const LayerRenderData& renderData;
const SymbolBucket::PaintProperties& bucketPaintProperties;
float sortKey;
- bool isText;
+ SymbolType type;
friend bool operator < (const RenderableSegment& lhs, const RenderableSegment& rhs) {
// Sort renderable segments by a sort key.
@@ -91,11 +91,11 @@ struct RenderableSegment {
// In cases when sort key is the same, sort by the type of a segment (text over icons),
// and for segments of the same type with the same sort key, sort by a tile id.
if (lhs.sortKey == rhs.sortKey) {
- if (!lhs.isText && rhs.isText) {
+ if (lhs.type != SymbolType::Text && rhs.type == SymbolType::Text) {
return true;
}
- if (lhs.isText == rhs.isText) {
+ if (lhs.type == rhs.type) {
return lhs.tile.id < rhs.tile.id;
}
}
@@ -110,7 +110,8 @@ void drawIcon(const DrawFn& draw,
const LayerRenderData& renderData,
SegmentsWrapper iconSegments,
const SymbolBucket::PaintProperties& bucketPaintProperties,
- const PaintParameters& parameters) {
+ const PaintParameters& parameters,
+ const bool sdfIcons) {
auto& bucket = static_cast<SymbolBucket&>(*renderData.bucket);
const auto& evaluated = getEvaluated<SymbolLayerProperties>(renderData.layerProperties);
const auto& layout = *bucket.layout;
@@ -124,19 +125,20 @@ void drawIcon(const DrawFn& draw,
const bool iconTransformed = values.rotationAlignment == AlignmentType::Map || parameters.state.getPitch() != 0;
const gfx::TextureBinding textureBinding{ tile.getIconAtlasTexture().getResource(),
- bucket.sdfIcons ||
+ sdfIcons ||
parameters.state.isChanging() ||
iconScaled || iconTransformed
? gfx::TextureFilterType::Linear
: gfx::TextureFilterType::Nearest };
const Size& iconSize = tile.getIconAtlasTexture().size;
+ const bool variablePlacedIcon = bucket.hasVariablePlacement && layout.get<IconTextFit>() != IconTextFitType::None;
- if (bucket.sdfIcons) {
+ if (sdfIcons) {
if (values.hasHalo) {
draw(parameters.programs.getSymbolLayerPrograms().symbolIconSDF,
- SymbolSDFIconProgram::layoutUniformValues(false, false, values, iconSize, parameters.pixelsToGLUnits, parameters.pixelRatio, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo),
- bucket.icon,
+ SymbolSDFIconProgram::layoutUniformValues(false, variablePlacedIcon, values, iconSize, parameters.pixelsToGLUnits, parameters.pixelRatio, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo),
+ bucket.sdfIcon,
iconSegments,
bucket.iconSizeBinder,
bucketPaintProperties.iconBinders,
@@ -149,8 +151,8 @@ void drawIcon(const DrawFn& draw,
if (values.hasFill) {
draw(parameters.programs.getSymbolLayerPrograms().symbolIconSDF,
- SymbolSDFIconProgram::layoutUniformValues(false, false, values, iconSize, parameters.pixelsToGLUnits, parameters.pixelRatio, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill),
- bucket.icon,
+ SymbolSDFIconProgram::layoutUniformValues(false, variablePlacedIcon, values, iconSize, parameters.pixelsToGLUnits, parameters.pixelRatio, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill),
+ bucket.sdfIcon,
iconSegments,
bucket.iconSizeBinder,
bucketPaintProperties.iconBinders,
@@ -162,7 +164,7 @@ void drawIcon(const DrawFn& draw,
}
} else {
draw(parameters.programs.getSymbolLayerPrograms().symbolIcon,
- SymbolIconProgram::layoutUniformValues(false, false, values, iconSize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange),
+ SymbolIconProgram::layoutUniformValues(false, variablePlacedIcon, values, iconSize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange),
bucket.icon,
iconSegments,
bucket.iconSizeBinder,
@@ -227,6 +229,7 @@ void drawText(const DrawFn& draw,
}
inline const SymbolLayer::Impl& impl(const Immutable<style::Layer::Impl>& impl) {
+ assert(impl->getTypeInfo() == SymbolLayer::Impl::staticTypeInfo());
return static_cast<const SymbolLayer::Impl&>(*impl);
}
@@ -359,68 +362,41 @@ void RenderSymbolLayer::render(PaintParameters& parameters) {
assert(bucket.paintProperties.find(getID()) != bucket.paintProperties.end());
const auto& bucketPaintProperties = bucket.paintProperties.at(getID());
- auto addRenderables = [&renderableSegments, &tile, renderData, &bucketPaintProperties, it = renderableSegments.begin()] (auto& segments, bool isText) mutable {
+ auto addRenderables = [&renderableSegments, &tile, renderData, &bucketPaintProperties, it = renderableSegments.begin()] (auto& segments, const SymbolType type) mutable {
for (auto& segment : segments) {
- it = renderableSegments.emplace_hint(it, SegmentWrapper{std::ref(segment)}, tile, *renderData, bucketPaintProperties, segment.sortKey, isText);
+ it = renderableSegments.emplace_hint(it, SegmentWrapper{std::ref(segment)}, tile, *renderData, bucketPaintProperties, segment.sortKey, type);
}
};
if (bucket.hasIconData()) {
if (sortFeaturesByKey) {
- addRenderables(bucket.icon.segments, false /*isText*/);
+ addRenderables(bucket.icon.segments, SymbolType::IconRGBA);
+ } else {
+ drawIcon(draw, tile, *renderData, std::ref(bucket.icon.segments), bucketPaintProperties, parameters, false /*sdfIcon*/);
+ }
+ }
+
+ if (bucket.hasSdfIconData()) {
+ if (sortFeaturesByKey) {
+ addRenderables(bucket.sdfIcon.segments, SymbolType::IconSDF);
} else {
- drawIcon(draw, tile, *renderData, std::ref(bucket.icon.segments), bucketPaintProperties, parameters);
+ drawIcon(draw, tile, *renderData, std::ref(bucket.sdfIcon.segments), bucketPaintProperties, parameters, true /*sdfIcon*/);
}
}
if (bucket.hasTextData()) {
if (sortFeaturesByKey) {
- addRenderables(bucket.text.segments, true /*isText*/);
+ addRenderables(bucket.text.segments, SymbolType::Text);
} else {
drawText(draw, tile, *renderData, std::ref(bucket.text.segments), bucketPaintProperties, parameters);
}
}
- if (bucket.hasCollisionBoxData()) {
- static const style::Properties<>::PossiblyEvaluated properties {};
- static const CollisionBoxProgram::Binders paintAttributeData(properties, 0);
+ const auto drawCollisonData = [&](const bool isText, const bool hasCollisionBox, const bool hasCollisionCircle) {
+ if (!hasCollisionBox && !hasCollisionCircle) return;
- auto pixelRatio = tile.id.pixelsToTileUnits(1, parameters.state.getZoom());
- const float scale = std::pow(2, parameters.state.getZoom() - tile.getOverscaledTileID().overscaledZ);
- std::array<float,2> extrudeScale =
- {{
- parameters.pixelsToGLUnits[0] / (pixelRatio * scale),
- parameters.pixelsToGLUnits[1] / (pixelRatio * scale)
- }};
- parameters.programs.getSymbolLayerPrograms().collisionBox.draw(
- parameters.context,
- *parameters.renderPass,
- gfx::Lines { 1.0f },
- gfx::DepthMode::disabled(),
- gfx::StencilMode::disabled(),
- parameters.colorModeForRenderPass(),
- gfx::CullFaceMode::disabled(),
- CollisionBoxProgram::LayoutUniformValues {
- uniforms::matrix::Value( tile.matrix ),
- uniforms::extrude_scale::Value( extrudeScale ),
- uniforms::camera_to_center_distance::Value( parameters.state.getCameraToCenterDistance() )
- },
- *bucket.collisionBox->vertexBuffer,
- *bucket.collisionBox->dynamicVertexBuffer,
- *bucket.collisionBox->indexBuffer,
- bucket.collisionBox->segments,
- paintAttributeData,
- properties,
- CollisionBoxProgram::TextureBindings{},
- parameters.state.getZoom(),
- getID()
- );
- }
-
- if (bucket.hasCollisionCircleData()) {
- static const style::Properties<>::PossiblyEvaluated properties {};
+ static const style::Properties<>::PossiblyEvaluated properties{};
static const CollisionBoxProgram::Binders paintAttributeData(properties, 0);
-
auto pixelRatio = tile.id.pixelsToTileUnits(1, parameters.state.getZoom());
const float scale = std::pow(2, parameters.state.getZoom() - tile.getOverscaledTileID().overscaledZ);
std::array<float,2> extrudeScale =
@@ -428,40 +404,77 @@ void RenderSymbolLayer::render(PaintParameters& parameters) {
parameters.pixelsToGLUnits[0] / (pixelRatio * scale),
parameters.pixelsToGLUnits[1] / (pixelRatio * scale)
}};
-
- parameters.programs.getSymbolLayerPrograms().collisionCircle.draw(
- parameters.context,
- *parameters.renderPass,
- gfx::Triangles(),
- gfx::DepthMode::disabled(),
- gfx::StencilMode::disabled(),
- parameters.colorModeForRenderPass(),
- gfx::CullFaceMode::disabled(),
- CollisionCircleProgram::LayoutUniformValues {
- uniforms::matrix::Value( tile.matrix ),
- uniforms::extrude_scale::Value( extrudeScale ),
- uniforms::overscale_factor::Value( float(tile.getOverscaledTileID().overscaleFactor()) ),
- uniforms::camera_to_center_distance::Value( parameters.state.getCameraToCenterDistance() )
- },
- *bucket.collisionCircle->vertexBuffer,
- *bucket.collisionCircle->dynamicVertexBuffer,
- *bucket.collisionCircle->indexBuffer,
- bucket.collisionCircle->segments,
- paintAttributeData,
- properties,
- CollisionCircleProgram::TextureBindings{},
- parameters.state.getZoom(),
- getID()
- );
- }
+ const auto& evaluated = getEvaluated<SymbolLayerProperties>(renderData->layerProperties);
+ const auto& layout = *bucket.layout;
+ const auto values = isText ? textPropertyValues(evaluated, layout): iconPropertyValues(evaluated, layout);
+ const bool needTranslate = values.translate[0] != 0 || values.translate[1] != 0;
+
+ if (hasCollisionBox) {
+ const auto& collisionBox = isText ? bucket.textCollisionBox : bucket.iconCollisionBox;
+ parameters.programs.getSymbolLayerPrograms().collisionBox.draw(
+ parameters.context,
+ *parameters.renderPass,
+ gfx::Lines{ 1.0f },
+ gfx::DepthMode::disabled(),
+ gfx::StencilMode::disabled(),
+ parameters.colorModeForRenderPass(),
+ gfx::CullFaceMode::disabled(),
+ CollisionBoxProgram::LayoutUniformValues {
+ uniforms::matrix::Value((needTranslate
+ ? tile.translatedMatrix(values.translate, values.translateAnchor, parameters.state)
+ : tile.matrix)),
+ uniforms::extrude_scale::Value(extrudeScale),
+ uniforms::camera_to_center_distance::Value(parameters.state.getCameraToCenterDistance())
+ },
+ *collisionBox->vertexBuffer,
+ *collisionBox->dynamicVertexBuffer,
+ *collisionBox->indexBuffer,
+ collisionBox->segments,
+ paintAttributeData,
+ properties,
+ CollisionBoxProgram::TextureBindings{},
+ parameters.state.getZoom(),
+ getID());
+ }
+ if (hasCollisionCircle) {
+ const auto& collisionCircle = isText ? bucket.textCollisionCircle : bucket.iconCollisionCircle;
+ parameters.programs.getSymbolLayerPrograms().collisionCircle.draw(
+ parameters.context,
+ *parameters.renderPass,
+ gfx::Triangles(),
+ gfx::DepthMode::disabled(),
+ gfx::StencilMode::disabled(),
+ parameters.colorModeForRenderPass(),
+ gfx::CullFaceMode::disabled(),
+ CollisionCircleProgram::LayoutUniformValues {
+ uniforms::matrix::Value((needTranslate
+ ? tile.translatedMatrix(values.translate, values.translateAnchor, parameters.state)
+ : tile.matrix)),
+ uniforms::extrude_scale::Value(extrudeScale),
+ uniforms::overscale_factor::Value(float(tile.getOverscaledTileID().overscaleFactor())),
+ uniforms::camera_to_center_distance::Value(parameters.state.getCameraToCenterDistance())
+ },
+ *collisionCircle->vertexBuffer,
+ *collisionCircle->dynamicVertexBuffer,
+ *collisionCircle->indexBuffer,
+ collisionCircle->segments,
+ paintAttributeData,
+ properties,
+ CollisionCircleProgram::TextureBindings{},
+ parameters.state.getZoom(),
+ getID());
+ }
+ };
+ drawCollisonData(false /*isText*/, bucket.hasIconCollisionBoxData(), bucket.hasIconCollisionCircleData());
+ drawCollisonData(true /*isText*/, bucket.hasTextCollisionBoxData(), bucket.hasTextCollisionCircleData());
}
if (sortFeaturesByKey) {
for (auto& renderable : renderableSegments) {
- if (renderable.isText) {
+ if (renderable.type == SymbolType::Text) {
drawText(draw, renderable.tile, renderable.renderData, renderable.segment, renderable.bucketPaintProperties, parameters);
} else {
- drawIcon(draw, renderable.tile, renderable.renderData, renderable.segment, renderable.bucketPaintProperties, parameters);
+ drawIcon(draw, renderable.tile, renderable.renderData, renderable.segment, renderable.bucketPaintProperties, parameters, renderable.type == SymbolType::IconSDF);
}
}
}
diff --git a/src/mbgl/renderer/layers/render_symbol_layer.hpp b/src/mbgl/renderer/layers/render_symbol_layer.hpp
index d9ce8c688d..5fcb9e2c8c 100644
--- a/src/mbgl/renderer/layers/render_symbol_layer.hpp
+++ b/src/mbgl/renderer/layers/render_symbol_layer.hpp
@@ -50,6 +50,12 @@ public:
bool hasFill;
};
+enum class SymbolType : uint8_t {
+ Text,
+ IconRGBA,
+ IconSDF
+};
+
} // namespace style
class RenderSymbolLayer final: public RenderLayer {
diff --git a/src/mbgl/renderer/render_layer.cpp b/src/mbgl/renderer/render_layer.cpp
index c1ca1fd017..fe1b151b58 100644
--- a/src/mbgl/renderer/render_layer.cpp
+++ b/src/mbgl/renderer/render_layer.cpp
@@ -32,7 +32,7 @@ const std::string& RenderLayer::getID() const {
}
bool RenderLayer::hasRenderPass(RenderPass pass) const {
- return bool(passes & pass);
+ return passes & pass;
}
bool RenderLayer::needsRendering() const {
diff --git a/src/mbgl/renderer/render_orchestrator.cpp b/src/mbgl/renderer/render_orchestrator.cpp
index 5b6b27c185..a62ccb0a0a 100644
--- a/src/mbgl/renderer/render_orchestrator.cpp
+++ b/src/mbgl/renderer/render_orchestrator.cpp
@@ -360,28 +360,33 @@ std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(const UpdatePar
crossTileSymbolIndex.reset();
}
+ bool symbolBucketsAdded = false;
bool symbolBucketsChanged = false;
- const bool placementChanged = !placement->stillRecent(updateParameters.timePoint);
+ for (auto it = layersNeedPlacement.rbegin(); it != layersNeedPlacement.rend(); ++it) {
+ auto result = crossTileSymbolIndex.addLayer(*it, updateParameters.transformState.getLatLng().longitude());
+ symbolBucketsAdded = symbolBucketsAdded || (result & CrossTileSymbolIndex::AddLayerResult::BucketsAdded);
+ symbolBucketsChanged = symbolBucketsChanged || (result != CrossTileSymbolIndex::AddLayerResult::NoChanges);
+ }
+ // We want new symbols to show up faster, however simple setting `placementChanged` to `true` would
+ // initiate placement too often as new buckets ususally come from several rendered tiles in a row within
+ // a short period of time. Instead, we squeeze placement update period to coalesce buckets updates from several tiles.
+ if (symbolBucketsAdded) placement->setMaximumUpdatePeriod(Milliseconds(30));
+ renderTreeParameters->placementChanged = !placement->stillRecent(updateParameters.timePoint, updateParameters.transformState.getZoom());
+
std::set<std::string> usedSymbolLayers;
- if (placementChanged) {
+ if (renderTreeParameters->placementChanged) {
placement = std::make_unique<Placement>(
updateParameters.transformState, updateParameters.mode,
updateParameters.transitionOptions, updateParameters.crossSourceCollisions,
std::move(placement));
- }
- for (auto it = layersNeedPlacement.rbegin(); it != layersNeedPlacement.rend(); ++it) {
- const RenderLayer& layer = *it;
- if (crossTileSymbolIndex.addLayer(layer, updateParameters.transformState.getLatLng().longitude())) symbolBucketsChanged = true;
-
- if (placementChanged) {
+ for (auto it = layersNeedPlacement.rbegin(); it != layersNeedPlacement.rend(); ++it) {
+ const RenderLayer& layer = *it;
usedSymbolLayers.insert(layer.getID());
placement->placeLayer(layer, renderTreeParameters->transformParams.projMatrix, updateParameters.debugOptions & MapDebugOptions::Collision);
}
- }
- if (placementChanged) {
- placement->commit(updateParameters.timePoint);
+ placement->commit(updateParameters.timePoint, updateParameters.transformState.getZoom());
crossTileSymbolIndex.pruneUnusedLayers(usedSymbolLayers);
for (const auto& entry : renderSources) {
entry.second->updateFadingTiles();
@@ -391,7 +396,7 @@ std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(const UpdatePar
}
for (auto it = layersNeedPlacement.rbegin(); it != layersNeedPlacement.rend(); ++it) {
- placement->updateLayerBuckets(*it, updateParameters.transformState, placementChanged || symbolBucketsChanged);
+ placement->updateLayerBuckets(*it, updateParameters.transformState, renderTreeParameters->placementChanged || symbolBucketsChanged);
}
renderTreeParameters->symbolFadeChange = placement->symbolFadeChange(updateParameters.timePoint);
diff --git a/src/mbgl/renderer/render_pass.hpp b/src/mbgl/renderer/render_pass.hpp
index 5d18304129..4d1b1f91f9 100644
--- a/src/mbgl/renderer/render_pass.hpp
+++ b/src/mbgl/renderer/render_pass.hpp
@@ -1,7 +1,6 @@
#pragma once
-#include <mbgl/util/traits.hpp>
-#include <mbgl/util/util.hpp>
+#include <mbgl/util/bitmask_operations.hpp>
#include <cstdint>
@@ -14,18 +13,6 @@ enum class RenderPass : uint8_t {
Pass3D = 1 << 2,
};
-MBGL_CONSTEXPR RenderPass operator|(RenderPass a, RenderPass b) {
- return RenderPass(mbgl::underlying_type(a) | mbgl::underlying_type(b));
-}
-
-MBGL_CONSTEXPR RenderPass& operator|=(RenderPass& a, RenderPass b) {
- return (a = a | b);
-}
-
-MBGL_CONSTEXPR RenderPass operator&(RenderPass a, RenderPass b) {
- return RenderPass(mbgl::underlying_type(a) & mbgl::underlying_type(b));
-}
-
// Defines whether the overdraw shaders should be used instead of the regular shaders.
enum class PaintMode : bool {
Regular = false,
diff --git a/src/mbgl/renderer/render_static_data.cpp b/src/mbgl/renderer/render_static_data.cpp
index 9090ef6579..6378ad9989 100644
--- a/src/mbgl/renderer/render_static_data.cpp
+++ b/src/mbgl/renderer/render_static_data.cpp
@@ -49,10 +49,10 @@ static gfx::VertexVector<HeatmapTextureLayoutVertex> heatmapTextureVertices() {
return result;
}
-RenderStaticData::RenderStaticData(gfx::Context& context, float pixelRatio, const optional<std::string>& programCacheDir)
- : programs(context, ProgramParameters { pixelRatio, false, programCacheDir })
+RenderStaticData::RenderStaticData(gfx::Context& context, float pixelRatio)
+ : programs(context, ProgramParameters { pixelRatio, false })
#ifndef NDEBUG
- , overdrawPrograms(context, ProgramParameters { pixelRatio, true, programCacheDir })
+ , overdrawPrograms(context, ProgramParameters { pixelRatio, true })
#endif
{
tileTriangleSegments.emplace_back(0, 0, 4, 6);
diff --git a/src/mbgl/renderer/render_static_data.hpp b/src/mbgl/renderer/render_static_data.hpp
index 5b409933af..6bf2c846f4 100644
--- a/src/mbgl/renderer/render_static_data.hpp
+++ b/src/mbgl/renderer/render_static_data.hpp
@@ -19,7 +19,7 @@ class UploadPass;
class RenderStaticData {
public:
- RenderStaticData(gfx::Context&, float pixelRatio, const optional<std::string>& programCacheDir);
+ RenderStaticData(gfx::Context&, float pixelRatio);
void upload(gfx::UploadPass&);
diff --git a/src/mbgl/renderer/render_tree.hpp b/src/mbgl/renderer/render_tree.hpp
index cf62ccb03e..557442c0fa 100644
--- a/src/mbgl/renderer/render_tree.hpp
+++ b/src/mbgl/renderer/render_tree.hpp
@@ -52,6 +52,7 @@ public:
float symbolFadeChange = 0.0f;
bool needsRepaint = false;
bool loaded = false;
+ bool placementChanged = false;
};
class RenderTree {
diff --git a/src/mbgl/renderer/renderer.cpp b/src/mbgl/renderer/renderer.cpp
index dd715bd3bc..52cd7a4351 100644
--- a/src/mbgl/renderer/renderer.cpp
+++ b/src/mbgl/renderer/renderer.cpp
@@ -10,11 +10,9 @@ namespace mbgl {
Renderer::Renderer(gfx::RendererBackend& backend,
float pixelRatio_,
- const optional<std::string> programCacheDir_,
const optional<std::string> localFontFamily_)
: impl(std::make_unique<Impl>(backend,
pixelRatio_,
- std::move(programCacheDir_),
std::move(localFontFamily_))) {
}
diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp
index 990d9cd3ab..113840d059 100644
--- a/src/mbgl/renderer/renderer_impl.cpp
+++ b/src/mbgl/renderer/renderer_impl.cpp
@@ -26,13 +26,11 @@ static RendererObserver& nullObserver() {
Renderer::Impl::Impl(gfx::RendererBackend& backend_,
float pixelRatio_,
- optional<std::string> programCacheDir_,
optional<std::string> localFontFamily_)
: orchestrator(!backend_.contextIsShared(), std::move(localFontFamily_))
, backend(backend_)
, observer(&nullObserver())
- , pixelRatio(pixelRatio_)
- , programCacheDir(std::move(programCacheDir_)) {
+ , pixelRatio(pixelRatio_) {
}
@@ -53,7 +51,7 @@ void Renderer::Impl::render(const RenderTree& renderTree) {
const auto& renderTreeParameters = renderTree.getParameters();
if (!staticData) {
- staticData = std::make_unique<RenderStaticData>(backend.getContext(), pixelRatio, programCacheDir);
+ staticData = std::make_unique<RenderStaticData>(backend.getContext(), pixelRatio);
}
staticData->has3D = renderTreeParameters.has3D;
@@ -212,7 +210,8 @@ void Renderer::Impl::render(const RenderTree& renderTree) {
observer->onDidFinishRenderingFrame(
renderTreeParameters.loaded ? RendererObserver::RenderMode::Full : RendererObserver::RenderMode::Partial,
- renderTreeParameters.needsRepaint
+ renderTreeParameters.needsRepaint,
+ renderTreeParameters.placementChanged
);
if (!renderTreeParameters.loaded) {
diff --git a/src/mbgl/renderer/renderer_impl.hpp b/src/mbgl/renderer/renderer_impl.hpp
index 85e37a014a..5f04bfdfed 100644
--- a/src/mbgl/renderer/renderer_impl.hpp
+++ b/src/mbgl/renderer/renderer_impl.hpp
@@ -19,7 +19,6 @@ class Renderer::Impl {
public:
Impl(gfx::RendererBackend&,
float pixelRatio_,
- optional<std::string> programCacheDir,
optional<std::string> localFontFamily_);
~Impl();
@@ -40,7 +39,6 @@ private:
RendererObserver* observer;
const float pixelRatio;
- const optional<std::string> programCacheDir;
std::unique_ptr<RenderStaticData> staticData;
enum class RenderState {
diff --git a/src/mbgl/renderer/sources/render_geojson_source.cpp b/src/mbgl/renderer/sources/render_geojson_source.cpp
index e451dab6d3..035244e371 100644
--- a/src/mbgl/renderer/sources/render_geojson_source.cpp
+++ b/src/mbgl/renderer/sources/render_geojson_source.cpp
@@ -94,7 +94,7 @@ void RenderGeoJSONSource::update(Immutable<style::Source::Impl> baseImpl_,
const uint8_t maxZ = impl().getZoomRange().max;
for (const auto& pair : tilePyramid.getTiles()) {
if (pair.first.canonical.z <= maxZ) {
- static_cast<GeoJSONTile*>(pair.second.get())->updateData(data_->getTile(pair.first.canonical));
+ static_cast<GeoJSONTile*>(pair.second.get())->updateData(data_->getTile(pair.first.canonical), needsRelayout);
}
}
}
diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp
index 54e0b1eb26..7f0fad1500 100644
--- a/src/mbgl/renderer/tile_pyramid.cpp
+++ b/src/mbgl/renderer/tile_pyramid.cpp
@@ -221,8 +221,6 @@ void TilePyramid::update(const std::vector<Immutable<style::LayerProperties>>& l
pair.second->setShowCollisionBoxes(parameters.debugOptions & MapDebugOptions::Collision);
}
- fadingTiles = false;
-
// Initialize renderable tiles and update the contained layer render data.
for (auto& entry : renderedTiles) {
Tile& tile = entry.second;
@@ -230,7 +228,6 @@ void TilePyramid::update(const std::vector<Immutable<style::LayerProperties>>& l
tile.usedByRenderedLayers = false;
const bool holdForFade = tile.holdForFade();
- fadingTiles = (fadingTiles || holdForFade);
for (const auto& layerProperties : layers) {
const auto* typeInfo = layerProperties->baseImpl->getTypeInfo();
if (holdForFade && typeInfo->fadingTiles == LayerTypeInfo::FadingTiles::NotRequired) {
@@ -374,6 +371,7 @@ void TilePyramid::dumpDebugLogs() const {
}
void TilePyramid::clearAll() {
+ fadingTiles = false;
tiles.clear();
renderedTiles.clear();
cache.clear();
@@ -385,9 +383,11 @@ void TilePyramid::addRenderTile(const UnwrappedTileID& tileID, Tile& tile) {
}
void TilePyramid::updateFadingTiles() {
+ fadingTiles = false;
for (auto& entry : renderedTiles) {
Tile& tile = entry.second;
if (tile.holdForFade()) {
+ fadingTiles = true;
tile.performedFadePlacement();
}
}
diff --git a/src/mbgl/style/conversion/geojson_options.cpp b/src/mbgl/style/conversion/geojson_options.cpp
index 11bd7cc507..08553e34bb 100644
--- a/src/mbgl/style/conversion/geojson_options.cpp
+++ b/src/mbgl/style/conversion/geojson_options.cpp
@@ -1,11 +1,15 @@
#include <mbgl/style/conversion/geojson_options.hpp>
#include <mbgl/style/conversion_impl.hpp>
+#include <mbgl/style/expression/dsl.hpp>
+
+#include <sstream>
namespace mbgl {
namespace style {
namespace conversion {
-optional<GeoJSONOptions> Converter<GeoJSONOptions>::operator()(const Convertible& value, Error& error) const {
+optional<GeoJSONOptions> Converter<GeoJSONOptions>::operator()(const Convertible& value,
+ Error& error) const {
GeoJSONOptions options;
const auto minzoomValue = objectMember(value, "minzoom");
@@ -83,12 +87,71 @@ optional<GeoJSONOptions> Converter<GeoJSONOptions>::operator()(const Convertible
if (toBool(*lineMetricsValue)) {
options.lineMetrics = *toBool(*lineMetricsValue);
} else {
- error = { "GeoJSON source lineMetrics value must be a boolean" };
+ error.message = "GeoJSON source lineMetrics value must be a boolean";
+ return nullopt;
+ }
+ }
+
+ const auto clusterProperties = objectMember(value, "clusterProperties");
+ if (clusterProperties) {
+ if (!isObject(*clusterProperties)) {
+ error.message = "GeoJSON source clusterProperties value must be an object";
+ return nullopt;
+ }
+ GeoJSONOptions::ClusterProperties result;
+ assert(error.message.empty());
+ eachMember(
+ *clusterProperties,
+ [&](const std::string& k,
+ const mbgl::style::conversion::Convertible& v) -> optional<conversion::Error> {
+ // Each property shall be formed as ["key" : [operator, [mapExpression]]]
+ // or ["key" : [[operator, ['accumulated'], ['get', key]], [mapExpression]]]
+ if (!isArray(v) || arrayLength(v) != 2) {
+ error.message =
+ "GeoJSON source clusterProperties member must be an array with length of 2";
+ return nullopt;
+ }
+ auto map = expression::dsl::createExpression(arrayMember(v, 1));
+ if (!map) {
+ error.message =
+ "Failed to convert GeoJSON source clusterProperties map expression";
+ return nullopt;
+ }
+ std::unique_ptr<expression::Expression> reduce;
+ if (isArray(arrayMember(v, 0))) {
+ reduce = expression::dsl::createExpression(arrayMember(v, 0));
+ } else {
+ auto reduceOp = toString(arrayMember(v, 0));
+ if (!reduceOp) {
+ error.message =
+ "GeoJSON source clusterProperties member must contain a valid operator";
+ return nullopt;
+ }
+ std::stringstream ss;
+ // Reformulate reduce expression to [operator, ['accumulated'], ['get', key]]
+ // The reason to create expression via parsing string instead of invoking function
+ // createCompoundExpression is due to expression type disunity can’t be resolved
+ // with current logic of createCompoundExpression
+ ss << std::string(R"([")") << *reduceOp
+ << std::string(R"(", ["accumulated"], ["get", ")") << k
+ << std::string(R"("]])");
+ reduce = expression::dsl::createExpression(ss.str().c_str());
+ }
+ if (!reduce) {
+ error.message =
+ "Failed to convert GeoJSON source clusterProperties reduce expression";
+ return nullopt;
+ }
+ result.emplace(k, std::make_pair(std::move(map), std::move(reduce)));
+ return nullopt;
+ });
+ if (!error.message.empty()) {
return nullopt;
}
+ options.clusterProperties = std::move(result);
}
- return { options };
+ return { std::move(options) };
}
} // namespace conversion
diff --git a/src/mbgl/style/expression/compound_expression.cpp b/src/mbgl/style/expression/compound_expression.cpp
index 34f0f5dea3..c637856ad9 100644
--- a/src/mbgl/style/expression/compound_expression.cpp
+++ b/src/mbgl/style/expression/compound_expression.cpp
@@ -368,6 +368,18 @@ const auto& lineProgressCompoundExpression() {
return signature;
}
+const auto& accumulatedCompoundExpression() {
+ const static auto signature = detail::makeSignature("accumulated", [](const EvaluationContext& params) -> Result<Value> {
+ if (!params.accumulated) {
+ return EvaluationError {
+ "The 'accumulated' expression is unavailable in the current evaluation context."
+ };
+ }
+ return Value(toExpressionValue(*params.accumulated));
+ });
+ return signature;
+}
+
const auto& hasContextCompoundExpression() {
static auto signature = detail::makeSignature("has", [](const EvaluationContext& params, const std::string& key) -> Result<bool> {
if (!params.feature) {
@@ -871,6 +883,7 @@ MAPBOX_ETERNAL_CONSTEXPR const auto compoundExpressionRegistry = mapbox::eternal
{ "zoom", zoomCompoundExpression },
{ "heatmap-density", heatmapDensityCompoundExpression },
{ "line-progress", lineProgressCompoundExpression },
+ { "accumulated", accumulatedCompoundExpression },
{ "has", hasContextCompoundExpression },
{ "has", hasObjectCompoundExpression },
{ "get", getContextCompoundExpression },
diff --git a/src/mbgl/style/expression/dsl.cpp b/src/mbgl/style/expression/dsl.cpp
index 70442de968..fac7dfbbd9 100644
--- a/src/mbgl/style/expression/dsl.cpp
+++ b/src/mbgl/style/expression/dsl.cpp
@@ -10,6 +10,10 @@
#include <mbgl/style/expression/compound_expression.hpp>
#include <mbgl/style/expression/format_expression.hpp>
+#include <mapbox/geojsonvt.hpp>
+#include <mbgl/style/conversion/json.hpp>
+#include <rapidjson/document.h>
+
namespace mbgl {
namespace style {
namespace expression {
@@ -21,6 +25,25 @@ std::unique_ptr<Expression> compound(const char* op, std::vector<std::unique_ptr
assert(result);
return std::move(*result);
}
+
+std::unique_ptr<Expression> createExpression(const char* expr) {
+ using JSValue = rapidjson::GenericValue<rapidjson::UTF8<>, rapidjson::CrtAllocator>;
+ rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> document;
+ document.Parse<0>(expr);
+ if (document.HasParseError()) return nullptr;
+
+ const JSValue* expression = &document;
+ expression::ParsingContext ctx;
+ expression::ParseResult parsed =
+ ctx.parseExpression(mbgl::style::conversion::Convertible(expression));
+ return parsed ? std::move(*parsed) : nullptr;
+}
+
+std::unique_ptr<Expression> createExpression(const mbgl::style::conversion::Convertible& expr) {
+ expression::ParsingContext ctx;
+ expression::ParseResult parsed = ctx.parseExpression(expr);
+ return parsed ? std::move(*parsed) : nullptr;
+}
std::unique_ptr<Expression> error(std::string message) {
return std::make_unique<Error>(std::move(message));
diff --git a/src/mbgl/style/expression/expression.cpp b/src/mbgl/style/expression/expression.cpp
index d61f435eec..6bfda99064 100644
--- a/src/mbgl/style/expression/expression.cpp
+++ b/src/mbgl/style/expression/expression.cpp
@@ -25,13 +25,17 @@ public:
return optional<mbgl::Value>();
}
};
-
-
+
EvaluationResult Expression::evaluate(optional<float> zoom, const Feature& feature, optional<double> colorRampParameter) const {
GeoJSONFeature f(feature);
return this->evaluate(EvaluationContext(zoom, &f, colorRampParameter));
}
+EvaluationResult Expression::evaluate(optional<mbgl::Value> accumulated, const Feature& feature) const {
+ GeoJSONFeature f(feature);
+ return this->evaluate(EvaluationContext(accumulated, &f));
+}
+
} // namespace expression
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/expression/parsing_context.cpp b/src/mbgl/style/expression/parsing_context.cpp
index a7c04f563d..6ce3a9bfaa 100644
--- a/src/mbgl/style/expression/parsing_context.cpp
+++ b/src/mbgl/style/expression/parsing_context.cpp
@@ -73,7 +73,8 @@ bool isConstant(const Expression& expression) {
return isFeatureConstant(expression) &&
isGlobalPropertyConstant(expression, std::array<std::string, 2>{{"zoom", "heatmap-density"}}) &&
- isGlobalPropertyConstant(expression, std::array<std::string, 2>{{"zoom", "line-progress"}});
+ isGlobalPropertyConstant(expression, std::array<std::string, 2>{{"zoom", "line-progress"}}) &&
+ isGlobalPropertyConstant(expression, std::array<std::string, 2>{{"zoom", "accumulated"}});
}
using namespace mbgl::style::conversion;
diff --git a/src/mbgl/style/layers/background_layer.cpp b/src/mbgl/style/layers/background_layer.cpp
index 3c7a2a7569..1693c47204 100644
--- a/src/mbgl/style/layers/background_layer.cpp
+++ b/src/mbgl/style/layers/background_layer.cpp
@@ -9,6 +9,7 @@
#include <mbgl/style/conversion/transition_options.hpp>
#include <mbgl/style/conversion/json.hpp>
#include <mbgl/style/conversion_impl.hpp>
+#include <mbgl/util/traits.hpp>
#include <mapbox/eternal.hpp>
@@ -147,7 +148,7 @@ TransitionOptions BackgroundLayer::getBackgroundPatternTransition() const {
using namespace conversion;
optional<Error> BackgroundLayer::setPaintProperty(const std::string& name, const Convertible& value) {
- enum class Property : uint8_t {
+ enum class Property {
BackgroundColor,
BackgroundOpacity,
BackgroundPattern,
@@ -157,12 +158,12 @@ optional<Error> BackgroundLayer::setPaintProperty(const std::string& name, const
};
MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({
- { "background-color", static_cast<uint8_t>(Property::BackgroundColor) },
- { "background-opacity", static_cast<uint8_t>(Property::BackgroundOpacity) },
- { "background-pattern", static_cast<uint8_t>(Property::BackgroundPattern) },
- { "background-color-transition", static_cast<uint8_t>(Property::BackgroundColorTransition) },
- { "background-opacity-transition", static_cast<uint8_t>(Property::BackgroundOpacityTransition) },
- { "background-pattern-transition", static_cast<uint8_t>(Property::BackgroundPatternTransition) }
+ { "background-color", mbgl::underlying_type(Property::BackgroundColor) },
+ { "background-opacity", mbgl::underlying_type(Property::BackgroundOpacity) },
+ { "background-pattern", mbgl::underlying_type(Property::BackgroundPattern) },
+ { "background-color-transition", mbgl::underlying_type(Property::BackgroundColorTransition) },
+ { "background-opacity-transition", mbgl::underlying_type(Property::BackgroundOpacityTransition) },
+ { "background-pattern-transition", mbgl::underlying_type(Property::BackgroundPatternTransition) }
});
const auto it = properties.find(name.c_str());
diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp
index 8c3debd1ac..2293ed222e 100644
--- a/src/mbgl/style/layers/circle_layer.cpp
+++ b/src/mbgl/style/layers/circle_layer.cpp
@@ -9,6 +9,7 @@
#include <mbgl/style/conversion/transition_options.hpp>
#include <mbgl/style/conversion/json.hpp>
#include <mbgl/style/conversion_impl.hpp>
+#include <mbgl/util/traits.hpp>
#include <mapbox/eternal.hpp>
@@ -363,7 +364,7 @@ TransitionOptions CircleLayer::getCircleTranslateAnchorTransition() const {
using namespace conversion;
optional<Error> CircleLayer::setPaintProperty(const std::string& name, const Convertible& value) {
- enum class Property : uint8_t {
+ enum class Property {
CircleBlur,
CircleColor,
CircleOpacity,
@@ -389,28 +390,28 @@ optional<Error> CircleLayer::setPaintProperty(const std::string& name, const Con
};
MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({
- { "circle-blur", static_cast<uint8_t>(Property::CircleBlur) },
- { "circle-color", static_cast<uint8_t>(Property::CircleColor) },
- { "circle-opacity", static_cast<uint8_t>(Property::CircleOpacity) },
- { "circle-pitch-alignment", static_cast<uint8_t>(Property::CirclePitchAlignment) },
- { "circle-pitch-scale", static_cast<uint8_t>(Property::CirclePitchScale) },
- { "circle-radius", static_cast<uint8_t>(Property::CircleRadius) },
- { "circle-stroke-color", static_cast<uint8_t>(Property::CircleStrokeColor) },
- { "circle-stroke-opacity", static_cast<uint8_t>(Property::CircleStrokeOpacity) },
- { "circle-stroke-width", static_cast<uint8_t>(Property::CircleStrokeWidth) },
- { "circle-translate", static_cast<uint8_t>(Property::CircleTranslate) },
- { "circle-translate-anchor", static_cast<uint8_t>(Property::CircleTranslateAnchor) },
- { "circle-blur-transition", static_cast<uint8_t>(Property::CircleBlurTransition) },
- { "circle-color-transition", static_cast<uint8_t>(Property::CircleColorTransition) },
- { "circle-opacity-transition", static_cast<uint8_t>(Property::CircleOpacityTransition) },
- { "circle-pitch-alignment-transition", static_cast<uint8_t>(Property::CirclePitchAlignmentTransition) },
- { "circle-pitch-scale-transition", static_cast<uint8_t>(Property::CirclePitchScaleTransition) },
- { "circle-radius-transition", static_cast<uint8_t>(Property::CircleRadiusTransition) },
- { "circle-stroke-color-transition", static_cast<uint8_t>(Property::CircleStrokeColorTransition) },
- { "circle-stroke-opacity-transition", static_cast<uint8_t>(Property::CircleStrokeOpacityTransition) },
- { "circle-stroke-width-transition", static_cast<uint8_t>(Property::CircleStrokeWidthTransition) },
- { "circle-translate-transition", static_cast<uint8_t>(Property::CircleTranslateTransition) },
- { "circle-translate-anchor-transition", static_cast<uint8_t>(Property::CircleTranslateAnchorTransition) }
+ { "circle-blur", mbgl::underlying_type(Property::CircleBlur) },
+ { "circle-color", mbgl::underlying_type(Property::CircleColor) },
+ { "circle-opacity", mbgl::underlying_type(Property::CircleOpacity) },
+ { "circle-pitch-alignment", mbgl::underlying_type(Property::CirclePitchAlignment) },
+ { "circle-pitch-scale", mbgl::underlying_type(Property::CirclePitchScale) },
+ { "circle-radius", mbgl::underlying_type(Property::CircleRadius) },
+ { "circle-stroke-color", mbgl::underlying_type(Property::CircleStrokeColor) },
+ { "circle-stroke-opacity", mbgl::underlying_type(Property::CircleStrokeOpacity) },
+ { "circle-stroke-width", mbgl::underlying_type(Property::CircleStrokeWidth) },
+ { "circle-translate", mbgl::underlying_type(Property::CircleTranslate) },
+ { "circle-translate-anchor", mbgl::underlying_type(Property::CircleTranslateAnchor) },
+ { "circle-blur-transition", mbgl::underlying_type(Property::CircleBlurTransition) },
+ { "circle-color-transition", mbgl::underlying_type(Property::CircleColorTransition) },
+ { "circle-opacity-transition", mbgl::underlying_type(Property::CircleOpacityTransition) },
+ { "circle-pitch-alignment-transition", mbgl::underlying_type(Property::CirclePitchAlignmentTransition) },
+ { "circle-pitch-scale-transition", mbgl::underlying_type(Property::CirclePitchScaleTransition) },
+ { "circle-radius-transition", mbgl::underlying_type(Property::CircleRadiusTransition) },
+ { "circle-stroke-color-transition", mbgl::underlying_type(Property::CircleStrokeColorTransition) },
+ { "circle-stroke-opacity-transition", mbgl::underlying_type(Property::CircleStrokeOpacityTransition) },
+ { "circle-stroke-width-transition", mbgl::underlying_type(Property::CircleStrokeWidthTransition) },
+ { "circle-translate-transition", mbgl::underlying_type(Property::CircleTranslateTransition) },
+ { "circle-translate-anchor-transition", mbgl::underlying_type(Property::CircleTranslateAnchorTransition) }
});
const auto it = properties.find(name.c_str());
diff --git a/src/mbgl/style/layers/fill_extrusion_layer.cpp b/src/mbgl/style/layers/fill_extrusion_layer.cpp
index 2c07cc56c5..50e32cf812 100644
--- a/src/mbgl/style/layers/fill_extrusion_layer.cpp
+++ b/src/mbgl/style/layers/fill_extrusion_layer.cpp
@@ -9,6 +9,7 @@
#include <mbgl/style/conversion/transition_options.hpp>
#include <mbgl/style/conversion/json.hpp>
#include <mbgl/style/conversion_impl.hpp>
+#include <mbgl/util/traits.hpp>
#include <mapbox/eternal.hpp>
@@ -282,7 +283,7 @@ TransitionOptions FillExtrusionLayer::getFillExtrusionVerticalGradientTransition
using namespace conversion;
optional<Error> FillExtrusionLayer::setPaintProperty(const std::string& name, const Convertible& value) {
- enum class Property : uint8_t {
+ enum class Property {
FillExtrusionBase,
FillExtrusionColor,
FillExtrusionHeight,
@@ -302,22 +303,22 @@ optional<Error> FillExtrusionLayer::setPaintProperty(const std::string& name, co
};
MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({
- { "fill-extrusion-base", static_cast<uint8_t>(Property::FillExtrusionBase) },
- { "fill-extrusion-color", static_cast<uint8_t>(Property::FillExtrusionColor) },
- { "fill-extrusion-height", static_cast<uint8_t>(Property::FillExtrusionHeight) },
- { "fill-extrusion-opacity", static_cast<uint8_t>(Property::FillExtrusionOpacity) },
- { "fill-extrusion-pattern", static_cast<uint8_t>(Property::FillExtrusionPattern) },
- { "fill-extrusion-translate", static_cast<uint8_t>(Property::FillExtrusionTranslate) },
- { "fill-extrusion-translate-anchor", static_cast<uint8_t>(Property::FillExtrusionTranslateAnchor) },
- { "fill-extrusion-vertical-gradient", static_cast<uint8_t>(Property::FillExtrusionVerticalGradient) },
- { "fill-extrusion-base-transition", static_cast<uint8_t>(Property::FillExtrusionBaseTransition) },
- { "fill-extrusion-color-transition", static_cast<uint8_t>(Property::FillExtrusionColorTransition) },
- { "fill-extrusion-height-transition", static_cast<uint8_t>(Property::FillExtrusionHeightTransition) },
- { "fill-extrusion-opacity-transition", static_cast<uint8_t>(Property::FillExtrusionOpacityTransition) },
- { "fill-extrusion-pattern-transition", static_cast<uint8_t>(Property::FillExtrusionPatternTransition) },
- { "fill-extrusion-translate-transition", static_cast<uint8_t>(Property::FillExtrusionTranslateTransition) },
- { "fill-extrusion-translate-anchor-transition", static_cast<uint8_t>(Property::FillExtrusionTranslateAnchorTransition) },
- { "fill-extrusion-vertical-gradient-transition", static_cast<uint8_t>(Property::FillExtrusionVerticalGradientTransition) }
+ { "fill-extrusion-base", mbgl::underlying_type(Property::FillExtrusionBase) },
+ { "fill-extrusion-color", mbgl::underlying_type(Property::FillExtrusionColor) },
+ { "fill-extrusion-height", mbgl::underlying_type(Property::FillExtrusionHeight) },
+ { "fill-extrusion-opacity", mbgl::underlying_type(Property::FillExtrusionOpacity) },
+ { "fill-extrusion-pattern", mbgl::underlying_type(Property::FillExtrusionPattern) },
+ { "fill-extrusion-translate", mbgl::underlying_type(Property::FillExtrusionTranslate) },
+ { "fill-extrusion-translate-anchor", mbgl::underlying_type(Property::FillExtrusionTranslateAnchor) },
+ { "fill-extrusion-vertical-gradient", mbgl::underlying_type(Property::FillExtrusionVerticalGradient) },
+ { "fill-extrusion-base-transition", mbgl::underlying_type(Property::FillExtrusionBaseTransition) },
+ { "fill-extrusion-color-transition", mbgl::underlying_type(Property::FillExtrusionColorTransition) },
+ { "fill-extrusion-height-transition", mbgl::underlying_type(Property::FillExtrusionHeightTransition) },
+ { "fill-extrusion-opacity-transition", mbgl::underlying_type(Property::FillExtrusionOpacityTransition) },
+ { "fill-extrusion-pattern-transition", mbgl::underlying_type(Property::FillExtrusionPatternTransition) },
+ { "fill-extrusion-translate-transition", mbgl::underlying_type(Property::FillExtrusionTranslateTransition) },
+ { "fill-extrusion-translate-anchor-transition", mbgl::underlying_type(Property::FillExtrusionTranslateAnchorTransition) },
+ { "fill-extrusion-vertical-gradient-transition", mbgl::underlying_type(Property::FillExtrusionVerticalGradientTransition) }
});
const auto it = properties.find(name.c_str());
diff --git a/src/mbgl/style/layers/fill_layer.cpp b/src/mbgl/style/layers/fill_layer.cpp
index 0aa19b834a..e08c8f3962 100644
--- a/src/mbgl/style/layers/fill_layer.cpp
+++ b/src/mbgl/style/layers/fill_layer.cpp
@@ -9,6 +9,7 @@
#include <mbgl/style/conversion/transition_options.hpp>
#include <mbgl/style/conversion/json.hpp>
#include <mbgl/style/conversion_impl.hpp>
+#include <mbgl/util/traits.hpp>
#include <mapbox/eternal.hpp>
@@ -255,7 +256,7 @@ TransitionOptions FillLayer::getFillTranslateAnchorTransition() const {
using namespace conversion;
optional<Error> FillLayer::setPaintProperty(const std::string& name, const Convertible& value) {
- enum class Property : uint8_t {
+ enum class Property {
FillAntialias,
FillColor,
FillOpacity,
@@ -273,20 +274,20 @@ optional<Error> FillLayer::setPaintProperty(const std::string& name, const Conve
};
MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({
- { "fill-antialias", static_cast<uint8_t>(Property::FillAntialias) },
- { "fill-color", static_cast<uint8_t>(Property::FillColor) },
- { "fill-opacity", static_cast<uint8_t>(Property::FillOpacity) },
- { "fill-outline-color", static_cast<uint8_t>(Property::FillOutlineColor) },
- { "fill-pattern", static_cast<uint8_t>(Property::FillPattern) },
- { "fill-translate", static_cast<uint8_t>(Property::FillTranslate) },
- { "fill-translate-anchor", static_cast<uint8_t>(Property::FillTranslateAnchor) },
- { "fill-antialias-transition", static_cast<uint8_t>(Property::FillAntialiasTransition) },
- { "fill-color-transition", static_cast<uint8_t>(Property::FillColorTransition) },
- { "fill-opacity-transition", static_cast<uint8_t>(Property::FillOpacityTransition) },
- { "fill-outline-color-transition", static_cast<uint8_t>(Property::FillOutlineColorTransition) },
- { "fill-pattern-transition", static_cast<uint8_t>(Property::FillPatternTransition) },
- { "fill-translate-transition", static_cast<uint8_t>(Property::FillTranslateTransition) },
- { "fill-translate-anchor-transition", static_cast<uint8_t>(Property::FillTranslateAnchorTransition) }
+ { "fill-antialias", mbgl::underlying_type(Property::FillAntialias) },
+ { "fill-color", mbgl::underlying_type(Property::FillColor) },
+ { "fill-opacity", mbgl::underlying_type(Property::FillOpacity) },
+ { "fill-outline-color", mbgl::underlying_type(Property::FillOutlineColor) },
+ { "fill-pattern", mbgl::underlying_type(Property::FillPattern) },
+ { "fill-translate", mbgl::underlying_type(Property::FillTranslate) },
+ { "fill-translate-anchor", mbgl::underlying_type(Property::FillTranslateAnchor) },
+ { "fill-antialias-transition", mbgl::underlying_type(Property::FillAntialiasTransition) },
+ { "fill-color-transition", mbgl::underlying_type(Property::FillColorTransition) },
+ { "fill-opacity-transition", mbgl::underlying_type(Property::FillOpacityTransition) },
+ { "fill-outline-color-transition", mbgl::underlying_type(Property::FillOutlineColorTransition) },
+ { "fill-pattern-transition", mbgl::underlying_type(Property::FillPatternTransition) },
+ { "fill-translate-transition", mbgl::underlying_type(Property::FillTranslateTransition) },
+ { "fill-translate-anchor-transition", mbgl::underlying_type(Property::FillTranslateAnchorTransition) }
});
const auto it = properties.find(name.c_str());
diff --git a/src/mbgl/style/layers/fill_layer_impl.cpp b/src/mbgl/style/layers/fill_layer_impl.cpp
index 4df32e02fa..45e350e00e 100644
--- a/src/mbgl/style/layers/fill_layer_impl.cpp
+++ b/src/mbgl/style/layers/fill_layer_impl.cpp
@@ -8,6 +8,7 @@ bool FillLayer::Impl::hasLayoutDifference(const Layer::Impl& other) const {
const auto& impl = static_cast<const style::FillLayer::Impl&>(other);
return filter != impl.filter ||
visibility != impl.visibility ||
+ paint.get<FillPattern>().value != impl.paint.get<FillPattern>().value ||
paint.hasDataDrivenPropertyDifference(impl.paint);
}
diff --git a/src/mbgl/style/layers/heatmap_layer.cpp b/src/mbgl/style/layers/heatmap_layer.cpp
index d35cb10b78..cb99f76a51 100644
--- a/src/mbgl/style/layers/heatmap_layer.cpp
+++ b/src/mbgl/style/layers/heatmap_layer.cpp
@@ -9,6 +9,7 @@
#include <mbgl/style/conversion/transition_options.hpp>
#include <mbgl/style/conversion/json.hpp>
#include <mbgl/style/conversion_impl.hpp>
+#include <mbgl/util/traits.hpp>
#include <mapbox/eternal.hpp>
@@ -203,7 +204,7 @@ TransitionOptions HeatmapLayer::getHeatmapWeightTransition() const {
using namespace conversion;
optional<Error> HeatmapLayer::setPaintProperty(const std::string& name, const Convertible& value) {
- enum class Property : uint8_t {
+ enum class Property {
HeatmapColor,
HeatmapIntensity,
HeatmapOpacity,
@@ -217,16 +218,16 @@ optional<Error> HeatmapLayer::setPaintProperty(const std::string& name, const Co
};
MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({
- { "heatmap-color", static_cast<uint8_t>(Property::HeatmapColor) },
- { "heatmap-intensity", static_cast<uint8_t>(Property::HeatmapIntensity) },
- { "heatmap-opacity", static_cast<uint8_t>(Property::HeatmapOpacity) },
- { "heatmap-radius", static_cast<uint8_t>(Property::HeatmapRadius) },
- { "heatmap-weight", static_cast<uint8_t>(Property::HeatmapWeight) },
- { "heatmap-color-transition", static_cast<uint8_t>(Property::HeatmapColorTransition) },
- { "heatmap-intensity-transition", static_cast<uint8_t>(Property::HeatmapIntensityTransition) },
- { "heatmap-opacity-transition", static_cast<uint8_t>(Property::HeatmapOpacityTransition) },
- { "heatmap-radius-transition", static_cast<uint8_t>(Property::HeatmapRadiusTransition) },
- { "heatmap-weight-transition", static_cast<uint8_t>(Property::HeatmapWeightTransition) }
+ { "heatmap-color", mbgl::underlying_type(Property::HeatmapColor) },
+ { "heatmap-intensity", mbgl::underlying_type(Property::HeatmapIntensity) },
+ { "heatmap-opacity", mbgl::underlying_type(Property::HeatmapOpacity) },
+ { "heatmap-radius", mbgl::underlying_type(Property::HeatmapRadius) },
+ { "heatmap-weight", mbgl::underlying_type(Property::HeatmapWeight) },
+ { "heatmap-color-transition", mbgl::underlying_type(Property::HeatmapColorTransition) },
+ { "heatmap-intensity-transition", mbgl::underlying_type(Property::HeatmapIntensityTransition) },
+ { "heatmap-opacity-transition", mbgl::underlying_type(Property::HeatmapOpacityTransition) },
+ { "heatmap-radius-transition", mbgl::underlying_type(Property::HeatmapRadiusTransition) },
+ { "heatmap-weight-transition", mbgl::underlying_type(Property::HeatmapWeightTransition) }
});
const auto it = properties.find(name.c_str());
diff --git a/src/mbgl/style/layers/hillshade_layer.cpp b/src/mbgl/style/layers/hillshade_layer.cpp
index ba22ab25ab..95a395ef25 100644
--- a/src/mbgl/style/layers/hillshade_layer.cpp
+++ b/src/mbgl/style/layers/hillshade_layer.cpp
@@ -9,6 +9,7 @@
#include <mbgl/style/conversion/transition_options.hpp>
#include <mbgl/style/conversion/json.hpp>
#include <mbgl/style/conversion_impl.hpp>
+#include <mbgl/util/traits.hpp>
#include <mapbox/eternal.hpp>
@@ -228,7 +229,7 @@ TransitionOptions HillshadeLayer::getHillshadeShadowColorTransition() const {
using namespace conversion;
optional<Error> HillshadeLayer::setPaintProperty(const std::string& name, const Convertible& value) {
- enum class Property : uint8_t {
+ enum class Property {
HillshadeAccentColor,
HillshadeExaggeration,
HillshadeHighlightColor,
@@ -244,18 +245,18 @@ optional<Error> HillshadeLayer::setPaintProperty(const std::string& name, const
};
MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({
- { "hillshade-accent-color", static_cast<uint8_t>(Property::HillshadeAccentColor) },
- { "hillshade-exaggeration", static_cast<uint8_t>(Property::HillshadeExaggeration) },
- { "hillshade-highlight-color", static_cast<uint8_t>(Property::HillshadeHighlightColor) },
- { "hillshade-illumination-anchor", static_cast<uint8_t>(Property::HillshadeIlluminationAnchor) },
- { "hillshade-illumination-direction", static_cast<uint8_t>(Property::HillshadeIlluminationDirection) },
- { "hillshade-shadow-color", static_cast<uint8_t>(Property::HillshadeShadowColor) },
- { "hillshade-accent-color-transition", static_cast<uint8_t>(Property::HillshadeAccentColorTransition) },
- { "hillshade-exaggeration-transition", static_cast<uint8_t>(Property::HillshadeExaggerationTransition) },
- { "hillshade-highlight-color-transition", static_cast<uint8_t>(Property::HillshadeHighlightColorTransition) },
- { "hillshade-illumination-anchor-transition", static_cast<uint8_t>(Property::HillshadeIlluminationAnchorTransition) },
- { "hillshade-illumination-direction-transition", static_cast<uint8_t>(Property::HillshadeIlluminationDirectionTransition) },
- { "hillshade-shadow-color-transition", static_cast<uint8_t>(Property::HillshadeShadowColorTransition) }
+ { "hillshade-accent-color", mbgl::underlying_type(Property::HillshadeAccentColor) },
+ { "hillshade-exaggeration", mbgl::underlying_type(Property::HillshadeExaggeration) },
+ { "hillshade-highlight-color", mbgl::underlying_type(Property::HillshadeHighlightColor) },
+ { "hillshade-illumination-anchor", mbgl::underlying_type(Property::HillshadeIlluminationAnchor) },
+ { "hillshade-illumination-direction", mbgl::underlying_type(Property::HillshadeIlluminationDirection) },
+ { "hillshade-shadow-color", mbgl::underlying_type(Property::HillshadeShadowColor) },
+ { "hillshade-accent-color-transition", mbgl::underlying_type(Property::HillshadeAccentColorTransition) },
+ { "hillshade-exaggeration-transition", mbgl::underlying_type(Property::HillshadeExaggerationTransition) },
+ { "hillshade-highlight-color-transition", mbgl::underlying_type(Property::HillshadeHighlightColorTransition) },
+ { "hillshade-illumination-anchor-transition", mbgl::underlying_type(Property::HillshadeIlluminationAnchorTransition) },
+ { "hillshade-illumination-direction-transition", mbgl::underlying_type(Property::HillshadeIlluminationDirectionTransition) },
+ { "hillshade-shadow-color-transition", mbgl::underlying_type(Property::HillshadeShadowColorTransition) }
});
const auto it = properties.find(name.c_str());
diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs
index 189857434f..da34565461 100644
--- a/src/mbgl/style/layers/layer.cpp.ejs
+++ b/src/mbgl/style/layers/layer.cpp.ejs
@@ -14,6 +14,7 @@
#include <mbgl/style/conversion/transition_options.hpp>
#include <mbgl/style/conversion/json.hpp>
#include <mbgl/style/conversion_impl.hpp>
+#include <mbgl/util/traits.hpp>
#include <mapbox/eternal.hpp>
@@ -176,7 +177,7 @@ TransitionOptions <%- camelize(type) %>Layer::get<%- camelize(property.name) %>T
using namespace conversion;
optional<Error> <%- camelize(type) %>Layer::setPaintProperty(const std::string& name, const Convertible& value) {
- enum class Property : uint8_t {
+ enum class Property {
<% for (const property of paintProperties) { -%>
<%- camelize(property.name) %>,
<% } -%>
@@ -186,8 +187,8 @@ optional<Error> <%- camelize(type) %>Layer::setPaintProperty(const std::string&
};
MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({
- <%- paintProperties.map(p => `{ "${p.name}", static_cast<uint8_t>(Property::${camelize(p.name)}) }`).join(',\n ') %>,
- <%- paintProperties.map(p => `{ "${p.name}-transition", static_cast<uint8_t>(Property::${camelize(p.name)}Transition) }`).join(',\n ') %>
+ <%- paintProperties.map(p => `{ "${p.name}", mbgl::underlying_type(Property::${camelize(p.name)}) }`).join(',\n ') %>,
+ <%- paintProperties.map(p => `{ "${p.name}-transition", mbgl::underlying_type(Property::${camelize(p.name)}Transition) }`).join(',\n ') %>
});
const auto it = properties.find(name.c_str());
@@ -254,7 +255,7 @@ optional<Error> <%- camelize(type) %>Layer::setLayoutProperty(const std::string&
<% } -%>
};
MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({
- <%- layoutProperties.map(p => `{ "${p.name}", static_cast<uint8_t>(Property::${camelize(p.name)}) }`).join(',\n ') %>
+ <%- layoutProperties.map(p => `{ "${p.name}", mbgl::underlying_type(Property::${camelize(p.name)}) }`).join(',\n ') %>
});
const auto it = properties.find(name.c_str());
diff --git a/src/mbgl/style/layers/line_layer.cpp b/src/mbgl/style/layers/line_layer.cpp
index 878816f6e4..deb85cad66 100644
--- a/src/mbgl/style/layers/line_layer.cpp
+++ b/src/mbgl/style/layers/line_layer.cpp
@@ -9,6 +9,7 @@
#include <mbgl/style/conversion/transition_options.hpp>
#include <mbgl/style/conversion/json.hpp>
#include <mbgl/style/conversion_impl.hpp>
+#include <mbgl/util/traits.hpp>
#include <mapbox/eternal.hpp>
@@ -429,7 +430,7 @@ TransitionOptions LineLayer::getLineWidthTransition() const {
using namespace conversion;
optional<Error> LineLayer::setPaintProperty(const std::string& name, const Convertible& value) {
- enum class Property : uint8_t {
+ enum class Property {
LineBlur,
LineColor,
LineDasharray,
@@ -455,28 +456,28 @@ optional<Error> LineLayer::setPaintProperty(const std::string& name, const Conve
};
MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({
- { "line-blur", static_cast<uint8_t>(Property::LineBlur) },
- { "line-color", static_cast<uint8_t>(Property::LineColor) },
- { "line-dasharray", static_cast<uint8_t>(Property::LineDasharray) },
- { "line-gap-width", static_cast<uint8_t>(Property::LineGapWidth) },
- { "line-gradient", static_cast<uint8_t>(Property::LineGradient) },
- { "line-offset", static_cast<uint8_t>(Property::LineOffset) },
- { "line-opacity", static_cast<uint8_t>(Property::LineOpacity) },
- { "line-pattern", static_cast<uint8_t>(Property::LinePattern) },
- { "line-translate", static_cast<uint8_t>(Property::LineTranslate) },
- { "line-translate-anchor", static_cast<uint8_t>(Property::LineTranslateAnchor) },
- { "line-width", static_cast<uint8_t>(Property::LineWidth) },
- { "line-blur-transition", static_cast<uint8_t>(Property::LineBlurTransition) },
- { "line-color-transition", static_cast<uint8_t>(Property::LineColorTransition) },
- { "line-dasharray-transition", static_cast<uint8_t>(Property::LineDasharrayTransition) },
- { "line-gap-width-transition", static_cast<uint8_t>(Property::LineGapWidthTransition) },
- { "line-gradient-transition", static_cast<uint8_t>(Property::LineGradientTransition) },
- { "line-offset-transition", static_cast<uint8_t>(Property::LineOffsetTransition) },
- { "line-opacity-transition", static_cast<uint8_t>(Property::LineOpacityTransition) },
- { "line-pattern-transition", static_cast<uint8_t>(Property::LinePatternTransition) },
- { "line-translate-transition", static_cast<uint8_t>(Property::LineTranslateTransition) },
- { "line-translate-anchor-transition", static_cast<uint8_t>(Property::LineTranslateAnchorTransition) },
- { "line-width-transition", static_cast<uint8_t>(Property::LineWidthTransition) }
+ { "line-blur", mbgl::underlying_type(Property::LineBlur) },
+ { "line-color", mbgl::underlying_type(Property::LineColor) },
+ { "line-dasharray", mbgl::underlying_type(Property::LineDasharray) },
+ { "line-gap-width", mbgl::underlying_type(Property::LineGapWidth) },
+ { "line-gradient", mbgl::underlying_type(Property::LineGradient) },
+ { "line-offset", mbgl::underlying_type(Property::LineOffset) },
+ { "line-opacity", mbgl::underlying_type(Property::LineOpacity) },
+ { "line-pattern", mbgl::underlying_type(Property::LinePattern) },
+ { "line-translate", mbgl::underlying_type(Property::LineTranslate) },
+ { "line-translate-anchor", mbgl::underlying_type(Property::LineTranslateAnchor) },
+ { "line-width", mbgl::underlying_type(Property::LineWidth) },
+ { "line-blur-transition", mbgl::underlying_type(Property::LineBlurTransition) },
+ { "line-color-transition", mbgl::underlying_type(Property::LineColorTransition) },
+ { "line-dasharray-transition", mbgl::underlying_type(Property::LineDasharrayTransition) },
+ { "line-gap-width-transition", mbgl::underlying_type(Property::LineGapWidthTransition) },
+ { "line-gradient-transition", mbgl::underlying_type(Property::LineGradientTransition) },
+ { "line-offset-transition", mbgl::underlying_type(Property::LineOffsetTransition) },
+ { "line-opacity-transition", mbgl::underlying_type(Property::LineOpacityTransition) },
+ { "line-pattern-transition", mbgl::underlying_type(Property::LinePatternTransition) },
+ { "line-translate-transition", mbgl::underlying_type(Property::LineTranslateTransition) },
+ { "line-translate-anchor-transition", mbgl::underlying_type(Property::LineTranslateAnchorTransition) },
+ { "line-width-transition", mbgl::underlying_type(Property::LineWidthTransition) }
});
const auto it = properties.find(name.c_str());
@@ -670,10 +671,10 @@ optional<Error> LineLayer::setLayoutProperty(const std::string& name, const Conv
LineRoundLimit,
};
MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({
- { "line-cap", static_cast<uint8_t>(Property::LineCap) },
- { "line-join", static_cast<uint8_t>(Property::LineJoin) },
- { "line-miter-limit", static_cast<uint8_t>(Property::LineMiterLimit) },
- { "line-round-limit", static_cast<uint8_t>(Property::LineRoundLimit) }
+ { "line-cap", mbgl::underlying_type(Property::LineCap) },
+ { "line-join", mbgl::underlying_type(Property::LineJoin) },
+ { "line-miter-limit", mbgl::underlying_type(Property::LineMiterLimit) },
+ { "line-round-limit", mbgl::underlying_type(Property::LineRoundLimit) }
});
const auto it = properties.find(name.c_str());
diff --git a/src/mbgl/style/layers/raster_layer.cpp b/src/mbgl/style/layers/raster_layer.cpp
index 1e2cd748c1..ead2223ea6 100644
--- a/src/mbgl/style/layers/raster_layer.cpp
+++ b/src/mbgl/style/layers/raster_layer.cpp
@@ -9,6 +9,7 @@
#include <mbgl/style/conversion/transition_options.hpp>
#include <mbgl/style/conversion/json.hpp>
#include <mbgl/style/conversion_impl.hpp>
+#include <mbgl/util/traits.hpp>
#include <mapbox/eternal.hpp>
@@ -282,7 +283,7 @@ TransitionOptions RasterLayer::getRasterSaturationTransition() const {
using namespace conversion;
optional<Error> RasterLayer::setPaintProperty(const std::string& name, const Convertible& value) {
- enum class Property : uint8_t {
+ enum class Property {
RasterBrightnessMax,
RasterBrightnessMin,
RasterContrast,
@@ -302,22 +303,22 @@ optional<Error> RasterLayer::setPaintProperty(const std::string& name, const Con
};
MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({
- { "raster-brightness-max", static_cast<uint8_t>(Property::RasterBrightnessMax) },
- { "raster-brightness-min", static_cast<uint8_t>(Property::RasterBrightnessMin) },
- { "raster-contrast", static_cast<uint8_t>(Property::RasterContrast) },
- { "raster-fade-duration", static_cast<uint8_t>(Property::RasterFadeDuration) },
- { "raster-hue-rotate", static_cast<uint8_t>(Property::RasterHueRotate) },
- { "raster-opacity", static_cast<uint8_t>(Property::RasterOpacity) },
- { "raster-resampling", static_cast<uint8_t>(Property::RasterResampling) },
- { "raster-saturation", static_cast<uint8_t>(Property::RasterSaturation) },
- { "raster-brightness-max-transition", static_cast<uint8_t>(Property::RasterBrightnessMaxTransition) },
- { "raster-brightness-min-transition", static_cast<uint8_t>(Property::RasterBrightnessMinTransition) },
- { "raster-contrast-transition", static_cast<uint8_t>(Property::RasterContrastTransition) },
- { "raster-fade-duration-transition", static_cast<uint8_t>(Property::RasterFadeDurationTransition) },
- { "raster-hue-rotate-transition", static_cast<uint8_t>(Property::RasterHueRotateTransition) },
- { "raster-opacity-transition", static_cast<uint8_t>(Property::RasterOpacityTransition) },
- { "raster-resampling-transition", static_cast<uint8_t>(Property::RasterResamplingTransition) },
- { "raster-saturation-transition", static_cast<uint8_t>(Property::RasterSaturationTransition) }
+ { "raster-brightness-max", mbgl::underlying_type(Property::RasterBrightnessMax) },
+ { "raster-brightness-min", mbgl::underlying_type(Property::RasterBrightnessMin) },
+ { "raster-contrast", mbgl::underlying_type(Property::RasterContrast) },
+ { "raster-fade-duration", mbgl::underlying_type(Property::RasterFadeDuration) },
+ { "raster-hue-rotate", mbgl::underlying_type(Property::RasterHueRotate) },
+ { "raster-opacity", mbgl::underlying_type(Property::RasterOpacity) },
+ { "raster-resampling", mbgl::underlying_type(Property::RasterResampling) },
+ { "raster-saturation", mbgl::underlying_type(Property::RasterSaturation) },
+ { "raster-brightness-max-transition", mbgl::underlying_type(Property::RasterBrightnessMaxTransition) },
+ { "raster-brightness-min-transition", mbgl::underlying_type(Property::RasterBrightnessMinTransition) },
+ { "raster-contrast-transition", mbgl::underlying_type(Property::RasterContrastTransition) },
+ { "raster-fade-duration-transition", mbgl::underlying_type(Property::RasterFadeDurationTransition) },
+ { "raster-hue-rotate-transition", mbgl::underlying_type(Property::RasterHueRotateTransition) },
+ { "raster-opacity-transition", mbgl::underlying_type(Property::RasterOpacityTransition) },
+ { "raster-resampling-transition", mbgl::underlying_type(Property::RasterResamplingTransition) },
+ { "raster-saturation-transition", mbgl::underlying_type(Property::RasterSaturationTransition) }
});
const auto it = properties.find(name.c_str());
diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp
index 4b335ead3c..157d8c745f 100644
--- a/src/mbgl/style/layers/symbol_layer.cpp
+++ b/src/mbgl/style/layers/symbol_layer.cpp
@@ -9,6 +9,7 @@
#include <mbgl/style/conversion/transition_options.hpp>
#include <mbgl/style/conversion/json.hpp>
#include <mbgl/style/conversion_impl.hpp>
+#include <mbgl/util/traits.hpp>
#include <mapbox/eternal.hpp>
@@ -1101,7 +1102,7 @@ TransitionOptions SymbolLayer::getTextTranslateAnchorTransition() const {
using namespace conversion;
optional<Error> SymbolLayer::setPaintProperty(const std::string& name, const Convertible& value) {
- enum class Property : uint8_t {
+ enum class Property {
IconColor,
IconHaloBlur,
IconHaloColor,
@@ -1133,34 +1134,34 @@ optional<Error> SymbolLayer::setPaintProperty(const std::string& name, const Con
};
MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({
- { "icon-color", static_cast<uint8_t>(Property::IconColor) },
- { "icon-halo-blur", static_cast<uint8_t>(Property::IconHaloBlur) },
- { "icon-halo-color", static_cast<uint8_t>(Property::IconHaloColor) },
- { "icon-halo-width", static_cast<uint8_t>(Property::IconHaloWidth) },
- { "icon-opacity", static_cast<uint8_t>(Property::IconOpacity) },
- { "icon-translate", static_cast<uint8_t>(Property::IconTranslate) },
- { "icon-translate-anchor", static_cast<uint8_t>(Property::IconTranslateAnchor) },
- { "text-color", static_cast<uint8_t>(Property::TextColor) },
- { "text-halo-blur", static_cast<uint8_t>(Property::TextHaloBlur) },
- { "text-halo-color", static_cast<uint8_t>(Property::TextHaloColor) },
- { "text-halo-width", static_cast<uint8_t>(Property::TextHaloWidth) },
- { "text-opacity", static_cast<uint8_t>(Property::TextOpacity) },
- { "text-translate", static_cast<uint8_t>(Property::TextTranslate) },
- { "text-translate-anchor", static_cast<uint8_t>(Property::TextTranslateAnchor) },
- { "icon-color-transition", static_cast<uint8_t>(Property::IconColorTransition) },
- { "icon-halo-blur-transition", static_cast<uint8_t>(Property::IconHaloBlurTransition) },
- { "icon-halo-color-transition", static_cast<uint8_t>(Property::IconHaloColorTransition) },
- { "icon-halo-width-transition", static_cast<uint8_t>(Property::IconHaloWidthTransition) },
- { "icon-opacity-transition", static_cast<uint8_t>(Property::IconOpacityTransition) },
- { "icon-translate-transition", static_cast<uint8_t>(Property::IconTranslateTransition) },
- { "icon-translate-anchor-transition", static_cast<uint8_t>(Property::IconTranslateAnchorTransition) },
- { "text-color-transition", static_cast<uint8_t>(Property::TextColorTransition) },
- { "text-halo-blur-transition", static_cast<uint8_t>(Property::TextHaloBlurTransition) },
- { "text-halo-color-transition", static_cast<uint8_t>(Property::TextHaloColorTransition) },
- { "text-halo-width-transition", static_cast<uint8_t>(Property::TextHaloWidthTransition) },
- { "text-opacity-transition", static_cast<uint8_t>(Property::TextOpacityTransition) },
- { "text-translate-transition", static_cast<uint8_t>(Property::TextTranslateTransition) },
- { "text-translate-anchor-transition", static_cast<uint8_t>(Property::TextTranslateAnchorTransition) }
+ { "icon-color", mbgl::underlying_type(Property::IconColor) },
+ { "icon-halo-blur", mbgl::underlying_type(Property::IconHaloBlur) },
+ { "icon-halo-color", mbgl::underlying_type(Property::IconHaloColor) },
+ { "icon-halo-width", mbgl::underlying_type(Property::IconHaloWidth) },
+ { "icon-opacity", mbgl::underlying_type(Property::IconOpacity) },
+ { "icon-translate", mbgl::underlying_type(Property::IconTranslate) },
+ { "icon-translate-anchor", mbgl::underlying_type(Property::IconTranslateAnchor) },
+ { "text-color", mbgl::underlying_type(Property::TextColor) },
+ { "text-halo-blur", mbgl::underlying_type(Property::TextHaloBlur) },
+ { "text-halo-color", mbgl::underlying_type(Property::TextHaloColor) },
+ { "text-halo-width", mbgl::underlying_type(Property::TextHaloWidth) },
+ { "text-opacity", mbgl::underlying_type(Property::TextOpacity) },
+ { "text-translate", mbgl::underlying_type(Property::TextTranslate) },
+ { "text-translate-anchor", mbgl::underlying_type(Property::TextTranslateAnchor) },
+ { "icon-color-transition", mbgl::underlying_type(Property::IconColorTransition) },
+ { "icon-halo-blur-transition", mbgl::underlying_type(Property::IconHaloBlurTransition) },
+ { "icon-halo-color-transition", mbgl::underlying_type(Property::IconHaloColorTransition) },
+ { "icon-halo-width-transition", mbgl::underlying_type(Property::IconHaloWidthTransition) },
+ { "icon-opacity-transition", mbgl::underlying_type(Property::IconOpacityTransition) },
+ { "icon-translate-transition", mbgl::underlying_type(Property::IconTranslateTransition) },
+ { "icon-translate-anchor-transition", mbgl::underlying_type(Property::IconTranslateAnchorTransition) },
+ { "text-color-transition", mbgl::underlying_type(Property::TextColorTransition) },
+ { "text-halo-blur-transition", mbgl::underlying_type(Property::TextHaloBlurTransition) },
+ { "text-halo-color-transition", mbgl::underlying_type(Property::TextHaloColorTransition) },
+ { "text-halo-width-transition", mbgl::underlying_type(Property::TextHaloWidthTransition) },
+ { "text-opacity-transition", mbgl::underlying_type(Property::TextOpacityTransition) },
+ { "text-translate-transition", mbgl::underlying_type(Property::TextTranslateTransition) },
+ { "text-translate-anchor-transition", mbgl::underlying_type(Property::TextTranslateAnchorTransition) }
});
const auto it = properties.find(name.c_str());
@@ -1406,47 +1407,47 @@ optional<Error> SymbolLayer::setLayoutProperty(const std::string& name, const Co
TextWritingMode,
};
MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({
- { "icon-allow-overlap", static_cast<uint8_t>(Property::IconAllowOverlap) },
- { "icon-anchor", static_cast<uint8_t>(Property::IconAnchor) },
- { "icon-ignore-placement", static_cast<uint8_t>(Property::IconIgnorePlacement) },
- { "icon-image", static_cast<uint8_t>(Property::IconImage) },
- { "icon-keep-upright", static_cast<uint8_t>(Property::IconKeepUpright) },
- { "icon-offset", static_cast<uint8_t>(Property::IconOffset) },
- { "icon-optional", static_cast<uint8_t>(Property::IconOptional) },
- { "icon-padding", static_cast<uint8_t>(Property::IconPadding) },
- { "icon-pitch-alignment", static_cast<uint8_t>(Property::IconPitchAlignment) },
- { "icon-rotate", static_cast<uint8_t>(Property::IconRotate) },
- { "icon-rotation-alignment", static_cast<uint8_t>(Property::IconRotationAlignment) },
- { "icon-size", static_cast<uint8_t>(Property::IconSize) },
- { "icon-text-fit", static_cast<uint8_t>(Property::IconTextFit) },
- { "icon-text-fit-padding", static_cast<uint8_t>(Property::IconTextFitPadding) },
- { "symbol-avoid-edges", static_cast<uint8_t>(Property::SymbolAvoidEdges) },
- { "symbol-placement", static_cast<uint8_t>(Property::SymbolPlacement) },
- { "symbol-sort-key", static_cast<uint8_t>(Property::SymbolSortKey) },
- { "symbol-spacing", static_cast<uint8_t>(Property::SymbolSpacing) },
- { "symbol-z-order", static_cast<uint8_t>(Property::SymbolZOrder) },
- { "text-allow-overlap", static_cast<uint8_t>(Property::TextAllowOverlap) },
- { "text-anchor", static_cast<uint8_t>(Property::TextAnchor) },
- { "text-field", static_cast<uint8_t>(Property::TextField) },
- { "text-font", static_cast<uint8_t>(Property::TextFont) },
- { "text-ignore-placement", static_cast<uint8_t>(Property::TextIgnorePlacement) },
- { "text-justify", static_cast<uint8_t>(Property::TextJustify) },
- { "text-keep-upright", static_cast<uint8_t>(Property::TextKeepUpright) },
- { "text-letter-spacing", static_cast<uint8_t>(Property::TextLetterSpacing) },
- { "text-line-height", static_cast<uint8_t>(Property::TextLineHeight) },
- { "text-max-angle", static_cast<uint8_t>(Property::TextMaxAngle) },
- { "text-max-width", static_cast<uint8_t>(Property::TextMaxWidth) },
- { "text-offset", static_cast<uint8_t>(Property::TextOffset) },
- { "text-optional", static_cast<uint8_t>(Property::TextOptional) },
- { "text-padding", static_cast<uint8_t>(Property::TextPadding) },
- { "text-pitch-alignment", static_cast<uint8_t>(Property::TextPitchAlignment) },
- { "text-radial-offset", static_cast<uint8_t>(Property::TextRadialOffset) },
- { "text-rotate", static_cast<uint8_t>(Property::TextRotate) },
- { "text-rotation-alignment", static_cast<uint8_t>(Property::TextRotationAlignment) },
- { "text-size", static_cast<uint8_t>(Property::TextSize) },
- { "text-transform", static_cast<uint8_t>(Property::TextTransform) },
- { "text-variable-anchor", static_cast<uint8_t>(Property::TextVariableAnchor) },
- { "text-writing-mode", static_cast<uint8_t>(Property::TextWritingMode) }
+ { "icon-allow-overlap", mbgl::underlying_type(Property::IconAllowOverlap) },
+ { "icon-anchor", mbgl::underlying_type(Property::IconAnchor) },
+ { "icon-ignore-placement", mbgl::underlying_type(Property::IconIgnorePlacement) },
+ { "icon-image", mbgl::underlying_type(Property::IconImage) },
+ { "icon-keep-upright", mbgl::underlying_type(Property::IconKeepUpright) },
+ { "icon-offset", mbgl::underlying_type(Property::IconOffset) },
+ { "icon-optional", mbgl::underlying_type(Property::IconOptional) },
+ { "icon-padding", mbgl::underlying_type(Property::IconPadding) },
+ { "icon-pitch-alignment", mbgl::underlying_type(Property::IconPitchAlignment) },
+ { "icon-rotate", mbgl::underlying_type(Property::IconRotate) },
+ { "icon-rotation-alignment", mbgl::underlying_type(Property::IconRotationAlignment) },
+ { "icon-size", mbgl::underlying_type(Property::IconSize) },
+ { "icon-text-fit", mbgl::underlying_type(Property::IconTextFit) },
+ { "icon-text-fit-padding", mbgl::underlying_type(Property::IconTextFitPadding) },
+ { "symbol-avoid-edges", mbgl::underlying_type(Property::SymbolAvoidEdges) },
+ { "symbol-placement", mbgl::underlying_type(Property::SymbolPlacement) },
+ { "symbol-sort-key", mbgl::underlying_type(Property::SymbolSortKey) },
+ { "symbol-spacing", mbgl::underlying_type(Property::SymbolSpacing) },
+ { "symbol-z-order", mbgl::underlying_type(Property::SymbolZOrder) },
+ { "text-allow-overlap", mbgl::underlying_type(Property::TextAllowOverlap) },
+ { "text-anchor", mbgl::underlying_type(Property::TextAnchor) },
+ { "text-field", mbgl::underlying_type(Property::TextField) },
+ { "text-font", mbgl::underlying_type(Property::TextFont) },
+ { "text-ignore-placement", mbgl::underlying_type(Property::TextIgnorePlacement) },
+ { "text-justify", mbgl::underlying_type(Property::TextJustify) },
+ { "text-keep-upright", mbgl::underlying_type(Property::TextKeepUpright) },
+ { "text-letter-spacing", mbgl::underlying_type(Property::TextLetterSpacing) },
+ { "text-line-height", mbgl::underlying_type(Property::TextLineHeight) },
+ { "text-max-angle", mbgl::underlying_type(Property::TextMaxAngle) },
+ { "text-max-width", mbgl::underlying_type(Property::TextMaxWidth) },
+ { "text-offset", mbgl::underlying_type(Property::TextOffset) },
+ { "text-optional", mbgl::underlying_type(Property::TextOptional) },
+ { "text-padding", mbgl::underlying_type(Property::TextPadding) },
+ { "text-pitch-alignment", mbgl::underlying_type(Property::TextPitchAlignment) },
+ { "text-radial-offset", mbgl::underlying_type(Property::TextRadialOffset) },
+ { "text-rotate", mbgl::underlying_type(Property::TextRotate) },
+ { "text-rotation-alignment", mbgl::underlying_type(Property::TextRotationAlignment) },
+ { "text-size", mbgl::underlying_type(Property::TextSize) },
+ { "text-transform", mbgl::underlying_type(Property::TextTransform) },
+ { "text-variable-anchor", mbgl::underlying_type(Property::TextVariableAnchor) },
+ { "text-writing-mode", mbgl::underlying_type(Property::TextWritingMode) }
});
const auto it = properties.find(name.c_str());
diff --git a/src/mbgl/style/light.cpp b/src/mbgl/style/light.cpp
index a88cc02bd7..b01f4220f2 100644
--- a/src/mbgl/style/light.cpp
+++ b/src/mbgl/style/light.cpp
@@ -3,6 +3,14 @@
#include <mbgl/style/light.hpp>
#include <mbgl/style/light_impl.hpp>
#include <mbgl/style/light_observer.hpp>
+#include <mbgl/style/conversion/light.hpp>
+#include <mbgl/style/conversion/property_value.hpp>
+#include <mbgl/style/conversion/transition_options.hpp>
+#include <mbgl/style/conversion/json.hpp>
+#include <mbgl/style/conversion_impl.hpp>
+#include <mbgl/util/traits.hpp>
+
+#include <mapbox/eternal.hpp>
namespace mbgl {
namespace style {
@@ -24,6 +32,118 @@ Mutable<Light::Impl> Light::mutableImpl() const {
return makeMutable<Impl>(*impl);
}
+using namespace conversion;
+
+optional<Error> Light::setProperty(const std::string& name, const Convertible& value) {
+ enum class Property {
+ Anchor,
+ Color,
+ Intensity,
+ Position,
+ AnchorTransition,
+ ColorTransition,
+ IntensityTransition,
+ PositionTransition,
+ };
+
+ MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({
+ { "anchor", mbgl::underlying_type(Property::Anchor) },
+ { "color", mbgl::underlying_type(Property::Color) },
+ { "intensity", mbgl::underlying_type(Property::Intensity) },
+ { "position", mbgl::underlying_type(Property::Position) },
+ { "anchor-transition", mbgl::underlying_type(Property::AnchorTransition) },
+ { "color-transition", mbgl::underlying_type(Property::ColorTransition) },
+ { "intensity-transition", mbgl::underlying_type(Property::IntensityTransition) },
+ { "position-transition", mbgl::underlying_type(Property::PositionTransition) }
+ });
+
+ const auto it = properties.find(name.c_str());
+ if (it == properties.end()) {
+ return Error { "light doesn't support this property" };
+ }
+
+ auto property = static_cast<Property>(it->second);
+
+
+ if (property == Property::Anchor) {
+ Error error;
+ optional<PropertyValue<LightAnchorType>> typedValue = convert<PropertyValue<LightAnchorType>>(value, error, false, false);
+ if (!typedValue) {
+ return error;
+ }
+
+ setAnchor(*typedValue);
+ return nullopt;
+
+ }
+
+ if (property == Property::Color) {
+ Error error;
+ optional<PropertyValue<Color>> typedValue = convert<PropertyValue<Color>>(value, error, false, false);
+ if (!typedValue) {
+ return error;
+ }
+
+ setColor(*typedValue);
+ return nullopt;
+
+ }
+
+ if (property == Property::Intensity) {
+ Error error;
+ optional<PropertyValue<float>> typedValue = convert<PropertyValue<float>>(value, error, false, false);
+ if (!typedValue) {
+ return error;
+ }
+
+ setIntensity(*typedValue);
+ return nullopt;
+
+ }
+
+ if (property == Property::Position) {
+ Error error;
+ optional<PropertyValue<Position>> typedValue = convert<PropertyValue<Position>>(value, error, false, false);
+ if (!typedValue) {
+ return error;
+ }
+
+ setPosition(*typedValue);
+ return nullopt;
+
+ }
+
+
+ Error error;
+ optional<TransitionOptions> transition = convert<TransitionOptions>(value, error);
+ if (!transition) {
+ return error;
+ }
+
+ if (property == Property::AnchorTransition) {
+ setAnchorTransition(*transition);
+ return nullopt;
+ }
+
+ if (property == Property::ColorTransition) {
+ setColorTransition(*transition);
+ return nullopt;
+ }
+
+ if (property == Property::IntensityTransition) {
+ setIntensityTransition(*transition);
+ return nullopt;
+ }
+
+ if (property == Property::PositionTransition) {
+ setPositionTransition(*transition);
+ return nullopt;
+ }
+
+
+ return Error { "light doesn't support this property" };
+}
+
LightAnchorType Light::getDefaultAnchor() {
return LightAnchor::defaultValue();
}
diff --git a/src/mbgl/style/light.cpp.ejs b/src/mbgl/style/light.cpp.ejs
index 45241c60fd..579889ab0d 100644
--- a/src/mbgl/style/light.cpp.ejs
+++ b/src/mbgl/style/light.cpp.ejs
@@ -6,6 +6,14 @@
#include <mbgl/style/light.hpp>
#include <mbgl/style/light_impl.hpp>
#include <mbgl/style/light_observer.hpp>
+#include <mbgl/style/conversion/light.hpp>
+#include <mbgl/style/conversion/property_value.hpp>
+#include <mbgl/style/conversion/transition_options.hpp>
+#include <mbgl/style/conversion/json.hpp>
+#include <mbgl/style/conversion_impl.hpp>
+#include <mbgl/util/traits.hpp>
+
+#include <mapbox/eternal.hpp>
namespace mbgl {
namespace style {
@@ -27,6 +35,76 @@ Mutable<Light::Impl> Light::mutableImpl() const {
return makeMutable<Impl>(*impl);
}
+using namespace conversion;
+
+optional<Error> Light::setProperty(const std::string& name, const Convertible& value) {
+ enum class Property {
+<% for (const property of properties) { -%>
+ <%- camelize(property.name) %>,
+<% } -%>
+<% for (const property of properties) { -%>
+ <%- camelize(property.name) %>Transition,
+<% } -%>
+ };
+
+ MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>({
+ <%- properties.map(p => `{ "${p.name}", mbgl::underlying_type(Property::${camelize(p.name)}) }`).join(',\n ') %>,
+ <%- properties.map(p => `{ "${p.name}-transition", mbgl::underlying_type(Property::${camelize(p.name)}Transition) }`).join(',\n ') %>
+ });
+
+ const auto it = properties.find(name.c_str());
+ if (it == properties.end()) {
+ return Error { "light doesn't support this property" };
+ }
+
+ auto property = static_cast<Property>(it->second);
+
+ <%
+ const conversions = {};
+ for (const property of properties) {
+ const dataDriven = property['property-type'] === 'data-driven' || property['property-type'] === 'cross-faded-data-driven';
+ const convertTokens = property.name === 'icon-image' || property.name === 'text-field';
+ const conversion = `optional<${propertyValueType(property)}> typedValue = convert<${propertyValueType(property)}>(value, error, ${dataDriven}, ${convertTokens})`;
+ conversions[conversion] = conversions[conversion] || [];
+ conversions[conversion].push(property);
+ }
+ -%>
+ <% for (const key in conversions) {
+ const properties = conversions[key];
+ %>
+ if (<%- properties.map(p => `property == Property::${camelize(p.name)}`).join(' || ') %>) {
+ Error error;
+ <%- key %>;
+ if (!typedValue) {
+ return error;
+ }
+ <% if (properties.length == 1) { %>
+ set<%- camelize(properties[0].name) %>(*typedValue);
+ return nullopt;
+ <% } else for (const property of properties) { %>
+ if (property == Property::<%- camelize(property.name) %>) {
+ set<%- camelize(property.name) %>(*typedValue);
+ return nullopt;
+ }
+ <% } %>
+ }
+ <% } %>
+
+ Error error;
+ optional<TransitionOptions> transition = convert<TransitionOptions>(value, error);
+ if (!transition) {
+ return error;
+ }
+ <% for (const property of properties) { %>
+ if (property == Property::<%- camelize(property.name) %>Transition) {
+ set<%- camelize(property.name) %>Transition(*transition);
+ return nullopt;
+ }
+ <% } %>
+
+ return Error { "light doesn't support this property" };
+}
+
<% for (const property of properties) { -%>
<%- evaluatedType(property) %> Light::getDefault<%- camelize(property.name) %>() {
return Light<%- camelize(property.name) %>::defaultValue();
diff --git a/src/mbgl/style/sources/custom_geometry_source.cpp b/src/mbgl/style/sources/custom_geometry_source.cpp
index 6e9d8d65fb..73675c056f 100644
--- a/src/mbgl/style/sources/custom_geometry_source.cpp
+++ b/src/mbgl/style/sources/custom_geometry_source.cpp
@@ -1,6 +1,7 @@
#include <mbgl/style/sources/custom_geometry_source.hpp>
#include <mbgl/style/custom_tile_loader.hpp>
#include <mbgl/style/sources/custom_geometry_source_impl.hpp>
+#include <mbgl/style/source_observer.hpp>
#include <mbgl/actor/actor.hpp>
#include <mbgl/actor/scheduler.hpp>
#include <mbgl/tile/tile_id.hpp>
@@ -25,6 +26,7 @@ const CustomGeometrySource::Impl& CustomGeometrySource::impl() const {
void CustomGeometrySource::loadDescription(FileSource&) {
baseImpl = makeMutable<CustomGeometrySource::Impl>(impl(), loader->self());
loaded = true;
+ observer->onSourceLoaded(*this);
}
void CustomGeometrySource::setTileData(const CanonicalTileID& tileID,
diff --git a/src/mbgl/style/sources/geojson_source.cpp b/src/mbgl/style/sources/geojson_source.cpp
index 4e3478322d..72a51e212f 100644
--- a/src/mbgl/style/sources/geojson_source.cpp
+++ b/src/mbgl/style/sources/geojson_source.cpp
@@ -9,7 +9,7 @@
namespace mbgl {
namespace style {
-GeoJSONSource::GeoJSONSource(const std::string& id, const GeoJSONOptions& options)
+GeoJSONSource::GeoJSONSource(const std::string& id, optional<GeoJSONOptions> options)
: Source(makeMutable<Impl>(std::move(id), options)) {
}
diff --git a/src/mbgl/style/sources/geojson_source_impl.cpp b/src/mbgl/style/sources/geojson_source_impl.cpp
index 24ac1d7976..c3cb942709 100644
--- a/src/mbgl/style/sources/geojson_source_impl.cpp
+++ b/src/mbgl/style/sources/geojson_source_impl.cpp
@@ -1,6 +1,7 @@
#include <mbgl/style/sources/geojson_source_impl.hpp>
-#include <mbgl/util/constants.hpp>
#include <mbgl/tile/tile_id.hpp>
+#include <mbgl/util/constants.hpp>
+#include <mbgl/util/feature.hpp>
#include <mbgl/util/string.hpp>
#include <mapbox/geojsonvt.hpp>
@@ -13,9 +14,9 @@ namespace style {
class GeoJSONVTData : public GeoJSONData {
public:
- GeoJSONVTData(const GeoJSON& geoJSON,
- const mapbox::geojsonvt::Options& options)
- : impl(geoJSON, options) {}
+ GeoJSONVTData(const GeoJSON& geoJSON, const mapbox::geojsonvt::Options& options)
+ : impl(geoJSON, options) {
+ }
mapbox::feature::feature_collection<int16_t> getTile(const CanonicalTileID& tileID) final {
return impl.getTile(tileID.z, tileID.x, tileID.y).features;
@@ -25,9 +26,8 @@ public:
return {};
}
- mapbox::feature::feature_collection<double> getLeaves(const std::uint32_t,
- const std::uint32_t,
- const std::uint32_t) final {
+ mapbox::feature::feature_collection<double>
+ getLeaves(const std::uint32_t, const std::uint32_t, const std::uint32_t) final {
return {};
}
@@ -43,7 +43,8 @@ class SuperclusterData : public GeoJSONData {
public:
SuperclusterData(const mapbox::feature::feature_collection<double>& features,
const mapbox::supercluster::Options& options)
- : impl(features, options) {}
+ : impl(features, options) {
+ }
mapbox::feature::feature_collection<int16_t> getTile(const CanonicalTileID& tileID) final {
return impl.getTile(tileID.z, tileID.x, tileID.y);
@@ -54,8 +55,8 @@ public:
}
mapbox::feature::feature_collection<double> getLeaves(const std::uint32_t cluster_id,
- const std::uint32_t limit,
- const std::uint32_t offset) final {
+ const std::uint32_t limit,
+ const std::uint32_t offset) final {
return impl.getLeaves(cluster_id, limit, offset);
}
@@ -67,23 +68,53 @@ private:
mapbox::supercluster::Supercluster impl;
};
-GeoJSONSource::Impl::Impl(std::string id_, GeoJSONOptions options_)
- : Source::Impl(SourceType::GeoJSON, std::move(id_)),
- options(std::move(options_)) {
+template <class T>
+T evaluateFeature(const mapbox::feature::feature<double>& f,
+ const std::shared_ptr<expression::Expression>& expression,
+ optional<T> accumulated = nullopt) {
+ const expression::EvaluationResult result = expression->evaluate(accumulated, f);
+ if (result) {
+ optional<T> typed = expression::fromExpressionValue<T>(*result);
+ if (typed) {
+ return std::move(*typed);
+ }
+ }
+ return T();
+}
+
+GeoJSONSource::Impl::Impl(std::string id_, optional<GeoJSONOptions> options_)
+ : Source::Impl(SourceType::GeoJSON, std::move(id_)) {
+ options = options_ ? std::move(*options_) : GeoJSONOptions{};
}
GeoJSONSource::Impl::Impl(const Impl& other, const GeoJSON& geoJSON)
- : Source::Impl(other),
- options(other.options) {
+ : Source::Impl(other), options(other.options) {
constexpr double scale = util::EXTENT / util::tileSize;
-
- if (options.cluster
- && geoJSON.is<mapbox::feature::feature_collection<double>>()
- && !geoJSON.get<mapbox::feature::feature_collection<double>>().empty()) {
+ if (options.cluster && geoJSON.is<mapbox::feature::feature_collection<double>>() &&
+ !geoJSON.get<mapbox::feature::feature_collection<double>>().empty()) {
mapbox::supercluster::Options clusterOptions;
clusterOptions.maxZoom = options.clusterMaxZoom;
clusterOptions.extent = util::EXTENT;
clusterOptions.radius = ::round(scale * options.clusterRadius);
+ Feature feature;
+ clusterOptions.map = [&](const PropertyMap& properties) -> PropertyMap {
+ PropertyMap ret{};
+ for (const auto& p : options.clusterProperties) {
+ feature.properties = properties;
+ ret[p.first] = evaluateFeature<Value>(feature, p.second.first);
+ }
+ return ret;
+ };
+ clusterOptions.reduce = [&](PropertyMap& toReturn, const PropertyMap& toFill) {
+ for (const auto& p : options.clusterProperties) {
+ if (toFill.count(p.first) == 0) {
+ continue;
+ }
+ feature.properties = toFill;
+ optional<Value> accumulated(toReturn[p.first]);
+ toReturn[p.first] = evaluateFeature<Value>(feature, p.second.second, accumulated);
+ }
+ };
data = std::make_shared<SuperclusterData>(
geoJSON.get<mapbox::feature::feature_collection<double>>(), clusterOptions);
} else {
diff --git a/src/mbgl/style/sources/geojson_source_impl.hpp b/src/mbgl/style/sources/geojson_source_impl.hpp
index b88ab35ee0..26b9d95a39 100644
--- a/src/mbgl/style/sources/geojson_source_impl.hpp
+++ b/src/mbgl/style/sources/geojson_source_impl.hpp
@@ -26,7 +26,7 @@ public:
class GeoJSONSource::Impl : public Source::Impl {
public:
- Impl(std::string id, GeoJSONOptions);
+ Impl(std::string id, optional<GeoJSONOptions>);
Impl(const GeoJSONSource::Impl&, const GeoJSON&);
~Impl() final;
diff --git a/src/mbgl/style/sources/raster_source.cpp b/src/mbgl/style/sources/raster_source.cpp
index b4fbe22ae1..115887d004 100644
--- a/src/mbgl/style/sources/raster_source.cpp
+++ b/src/mbgl/style/sources/raster_source.cpp
@@ -41,6 +41,7 @@ void RasterSource::loadDescription(FileSource& fileSource) {
if (urlOrTileset.is<Tileset>()) {
baseImpl = makeMutable<Impl>(impl(), urlOrTileset.get<Tileset>());
loaded = true;
+ observer->onSourceLoaded(*this);
return;
}
diff --git a/src/mbgl/style/sources/vector_source.cpp b/src/mbgl/style/sources/vector_source.cpp
index 8fa694e4d0..f103a7768f 100644
--- a/src/mbgl/style/sources/vector_source.cpp
+++ b/src/mbgl/style/sources/vector_source.cpp
@@ -38,6 +38,7 @@ void VectorSource::loadDescription(FileSource& fileSource) {
if (urlOrTileset.is<Tileset>()) {
baseImpl = makeMutable<Impl>(impl(), urlOrTileset.get<Tileset>());
loaded = true;
+ observer->onSourceLoaded(*this);
return;
}
diff --git a/src/mbgl/style/style_impl.cpp b/src/mbgl/style/style_impl.cpp
index 10fee73cdd..d3298c5cac 100644
--- a/src/mbgl/style/style_impl.cpp
+++ b/src/mbgl/style/style_impl.cpp
@@ -140,9 +140,8 @@ void Style::Impl::addSource(std::unique_ptr<Source> source) {
}
source->setObserver(this);
- source->loadDescription(fileSource);
-
- sources.add(std::move(source));
+ auto item = sources.add(std::move(source));
+ item->loadDescription(fileSource);
}
std::unique_ptr<Source> Style::Impl::removeSource(const std::string& id) {
diff --git a/src/mbgl/text/cross_tile_symbol_index.cpp b/src/mbgl/text/cross_tile_symbol_index.cpp
index 43ed85d957..55ab2cc3c5 100644
--- a/src/mbgl/text/cross_tile_symbol_index.cpp
+++ b/src/mbgl/text/cross_tile_symbol_index.cpp
@@ -163,10 +163,10 @@ bool CrossTileSymbolLayerIndex::removeStaleBuckets(const std::unordered_set<uint
CrossTileSymbolIndex::CrossTileSymbolIndex() = default;
-bool CrossTileSymbolIndex::addLayer(const RenderLayer& layer, float lng) {
+auto CrossTileSymbolIndex::addLayer(const RenderLayer& layer, float lng) -> AddLayerResult {
auto& layerIndex = layerIndexes[layer.getID()];
- bool symbolBucketsChanged = false;
+ AddLayerResult result = AddLayerResult::NoChanges;
std::unordered_set<uint32_t> currentBucketIDs;
layerIndex.handleWrapJump(lng);
@@ -174,16 +174,15 @@ bool CrossTileSymbolIndex::addLayer(const RenderLayer& layer, float lng) {
for (const auto& item : layer.getPlacementData()) {
const RenderTile& renderTile = item.tile;
Bucket& bucket = item.bucket;
- auto result = bucket.registerAtCrossTileIndex(layerIndex, renderTile.getOverscaledTileID(), maxCrossTileID);
- assert(result.first != 0u);
- symbolBucketsChanged = symbolBucketsChanged || result.second;
- currentBucketIDs.insert(result.first);
+ auto pair = bucket.registerAtCrossTileIndex(layerIndex, renderTile.getOverscaledTileID(), maxCrossTileID);
+ assert(pair.first != 0u);
+ if (pair.second) result |= AddLayerResult::BucketsAdded;
+ currentBucketIDs.insert(pair.first);
}
- if (layerIndex.removeStaleBuckets(currentBucketIDs)) {
- symbolBucketsChanged = true;
- }
- return symbolBucketsChanged;
+ if (layerIndex.removeStaleBuckets(currentBucketIDs)) result |= AddLayerResult::BucketsRemoved;
+
+ return result;
}
void CrossTileSymbolIndex::pruneUnusedLayers(const std::set<std::string>& usedLayers) {
diff --git a/src/mbgl/text/cross_tile_symbol_index.hpp b/src/mbgl/text/cross_tile_symbol_index.hpp
index d905aeb569..4e32698b3e 100644
--- a/src/mbgl/text/cross_tile_symbol_index.hpp
+++ b/src/mbgl/text/cross_tile_symbol_index.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <mbgl/tile/tile_id.hpp>
+#include <mbgl/util/bitmask_operations.hpp>
#include <mbgl/util/geometry.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/optional.hpp>
@@ -58,7 +59,13 @@ class CrossTileSymbolIndex {
public:
CrossTileSymbolIndex();
- bool addLayer(const RenderLayer& layer, float lng);
+ enum class AddLayerResult : uint8_t {
+ NoChanges = 0,
+ BucketsAdded = 1 << 0,
+ BucketsRemoved = 1 << 1
+ };
+
+ AddLayerResult addLayer(const RenderLayer& layer, float lng);
void pruneUnusedLayers(const std::set<std::string>&);
void reset();
diff --git a/src/mbgl/text/glyph.hpp b/src/mbgl/text/glyph.hpp
index 234f718975..ba9c521f77 100644
--- a/src/mbgl/text/glyph.hpp
+++ b/src/mbgl/text/glyph.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <mbgl/text/glyph_range.hpp>
+#include <mbgl/util/bitmask_operations.hpp>
#include <mbgl/util/font_stack.hpp>
#include <mbgl/util/rect.hpp>
#include <mbgl/util/traits.hpp>
@@ -99,26 +100,6 @@ enum class WritingModeType : uint8_t {
Vertical = 1 << 1,
};
-MBGL_CONSTEXPR WritingModeType operator|(WritingModeType a, WritingModeType b) {
- return WritingModeType(mbgl::underlying_type(a) | mbgl::underlying_type(b));
-}
-
-MBGL_CONSTEXPR WritingModeType& operator|=(WritingModeType& a, WritingModeType b) {
- return (a = a | b);
-}
-
-MBGL_CONSTEXPR bool operator&(WritingModeType lhs, WritingModeType rhs) {
- return mbgl::underlying_type(lhs) & mbgl::underlying_type(rhs);
-}
-
-MBGL_CONSTEXPR WritingModeType& operator&=(WritingModeType& lhs, WritingModeType rhs) {
- return (lhs = WritingModeType(mbgl::underlying_type(lhs) & mbgl::underlying_type(rhs)));
-}
-
-MBGL_CONSTEXPR WritingModeType operator~(WritingModeType value) {
- return WritingModeType(~mbgl::underlying_type(value));
-}
-
using GlyphDependencies = std::map<FontStack, GlyphIDs>;
using GlyphRangeDependencies = std::map<FontStack, std::unordered_set<GlyphRange>>;
diff --git a/src/mbgl/text/glyph_manager.cpp b/src/mbgl/text/glyph_manager.cpp
index daa142e38f..35ea1031d5 100644
--- a/src/mbgl/text/glyph_manager.cpp
+++ b/src/mbgl/text/glyph_manager.cpp
@@ -98,8 +98,11 @@ void GlyphManager::processResponse(const Response& res, const FontStack& fontSta
}
for (auto& glyph : glyphs) {
- entry.glyphs.erase(glyph.id);
- entry.glyphs.emplace(glyph.id, makeMutable<Glyph>(std::move(glyph)));
+ auto id = glyph.id;
+ if (!localGlyphRasterizer->canRasterizeGlyph(fontStack, id)) {
+ entry.glyphs.erase(id);
+ entry.glyphs.emplace(id, makeMutable<Glyph>(std::move(glyph)));
+ }
}
}
diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp
index 27c4913c63..06777dea44 100644
--- a/src/mbgl/text/placement.cpp
+++ b/src/mbgl/text/placement.cpp
@@ -62,6 +62,7 @@ Placement::Placement(const TransformState& state_, MapMode mapMode_, style::Tran
: collisionIndex(state_)
, mapMode(mapMode_)
, transitionOptions(std::move(transitionOptions_))
+ , placementZoom(state_.getZoom())
, collisionGroups(crossSourceCollisions)
, prevPlacement(std::move(prevPlacement_))
{
@@ -85,15 +86,13 @@ void Placement::placeLayer(const RenderLayer& layer, const mat4& projMatrix, boo
}
namespace {
-Point<float> calculateVariableLayoutOffset(style::SymbolAnchorType anchor, float width, float height, float radialOffset, float textBoxScale) {
+Point<float> calculateVariableLayoutOffset(style::SymbolAnchorType anchor, float width, float height, std::array<float, 2> offset, float textBoxScale) {
AnchorAlignment alignment = AnchorAlignment::getAnchorAlignment(anchor);
float shiftX = -(alignment.horizontalAlign - 0.5f) * width;
float shiftY = -(alignment.verticalAlign - 0.5f) * height;
- Point<float> offset = SymbolLayout::evaluateRadialOffset(anchor, radialOffset);
- return Point<float>(
- shiftX + offset.x * textBoxScale,
- shiftY + offset.y * textBoxScale
- );
+ auto variableOffset = SymbolLayout::evaluateVariableOffset(anchor, offset);
+ return { shiftX + variableOffset[0] * textBoxScale,
+ shiftY + variableOffset[1] * textBoxScale };
}
} // namespace
@@ -152,12 +151,12 @@ void Placement::placeBucket(
// This is the reverse of our normal policy of "fade in on pan", but should look like any other
// collision and hopefully not be too noticeable.
// See https://github.com/mapbox/mapbox-gl-native/issues/12683
- const bool alwaysShowText = textAllowOverlap && (iconAllowOverlap || !bucket.hasIconData() || layout.get<style::IconOptional>());
+ const bool alwaysShowText = textAllowOverlap && (iconAllowOverlap || !(bucket.hasIconData() || bucket.hasSdfIconData()) || layout.get<style::IconOptional>());
const bool alwaysShowIcon = iconAllowOverlap && (textAllowOverlap || !bucket.hasTextData() || layout.get<style::TextOptional>());
std::vector<style::TextVariableAnchorType> variableTextAnchors = layout.get<style::TextVariableAnchor>();
const bool rotateWithMap = layout.get<style::TextRotationAlignment>() == style::AlignmentType::Map;
const bool pitchWithMap = layout.get<style::TextPitchAlignment>() == style::AlignmentType::Map;
- const bool hasCollisionCircleData = bucket.hasCollisionCircleData();
+ const bool hasIconTextFit = layout.get<style::IconTextFit>() != style::IconTextFitType::None;
const bool zOrderByViewportY = layout.get<style::SymbolZOrder>() == style::SymbolZOrderType::ViewportY;
std::vector<ProjectedCollisionBox> textBoxes;
@@ -179,7 +178,9 @@ void Placement::placeBucket(
bool placeIcon = false;
bool offscreen = true;
std::pair<bool, bool> placed{ false, false };
- std::pair<bool, bool> placedVertical{ false, false };
+ std::pair<bool, bool> placedVerticalText{ false, false };
+ std::pair<bool, bool> placedVerticalIcon{ false, false };
+ Point<float> shift{0.0f, 0.0f};
optional<size_t> horizontalTextIndex = symbolInstance.getDefaultHorizontalPlacedTextIndex();
if (horizontalTextIndex) {
const PlacedSymbol& placedSymbol = bucket.text.placedSymbols.at(*horizontalTextIndex);
@@ -200,7 +201,7 @@ void Placement::placeBucket(
assert(!bucket.placementModes.empty());
for (auto& placementMode : bucket.placementModes) {
if (placementMode == style::TextWritingModeType::Vertical) {
- placedVertical = placed = placeVerticalFn();
+ placedVerticalText = placed = placeVerticalFn();
} else {
placed = placeHorizontalFn();
}
@@ -280,7 +281,7 @@ void Placement::placeBucket(
for (size_t i = 0u; i < placementAttempts; ++i) {
auto anchor = variableTextAnchors[i % anchorsSize];
const bool allowOverlap = (i >= anchorsSize);
- Point<float> shift = calculateVariableLayoutOffset(anchor, width, height, symbolInstance.radialTextOffset, textBoxScale);
+ shift = calculateVariableLayoutOffset(anchor, width, height, symbolInstance.variableTextOffset, textBoxScale);
if (rotateWithMap) {
float angle = pitchWithMap ? state.getBearing() : -state.getBearing();
shift = util::rotate(shift, angle);
@@ -311,7 +312,7 @@ void Placement::placeBucket(
}
variableOffsets.insert(std::make_pair(symbolInstance.crossTileID, VariableOffset{
- symbolInstance.radialTextOffset,
+ symbolInstance.variableTextOffset,
width,
height,
anchor,
@@ -359,21 +360,35 @@ void Placement::placeBucket(
}
if (symbolInstance.placedIconIndex) {
- const PlacedSymbol& placedSymbol = bucket.icon.placedSymbols.at(*symbolInstance.placedIconIndex);
+ if (!hasIconTextFit || !placeText || variableTextAnchors.empty()) {
+ shift = {0.0f, 0.0f};
+ }
+
+ const auto& iconBuffer = symbolInstance.hasSdfIcon() ? bucket.sdfIcon : bucket.icon;
+ const PlacedSymbol& placedSymbol = iconBuffer.placedSymbols.at(*symbolInstance.placedIconIndex);
const float fontSize = evaluateSizeForFeature(partiallyEvaluatedIconSize, placedSymbol);
+ const auto& placeIconFeature = [&] (const CollisionFeature& collisionFeature) {
+ return collisionIndex.placeFeature(collisionFeature, shift,
+ posMatrix, iconLabelPlaneMatrix, pixelRatio,
+ placedSymbol, scale, fontSize,
+ layout.get<style::IconAllowOverlap>(),
+ pitchWithMap,
+ params.showCollisionBoxes, avoidEdges,
+ collisionGroup.second, iconBoxes);
+ };
- auto placedIcon = collisionIndex.placeFeature(symbolInstance.iconCollisionFeature, {},
- posMatrix, iconLabelPlaneMatrix, pixelRatio,
- placedSymbol, scale, fontSize,
- layout.get<style::IconAllowOverlap>(),
- pitchWithMap,
- params.showCollisionBoxes, avoidEdges, collisionGroup.second, iconBoxes);
+ std::pair<bool, bool> placedIcon = {false, false};
+ if (placedVerticalText.first && symbolInstance.verticalIconCollisionFeature) {
+ placedIcon = placedVerticalIcon = placeIconFeature(*symbolInstance.verticalIconCollisionFeature);
+ } else {
+ placedIcon = placeIconFeature(symbolInstance.iconCollisionFeature);
+ }
placeIcon = placedIcon.first;
offscreen &= placedIcon.second;
}
- const bool iconWithoutText = !symbolInstance.hasText || layout.get<style::TextOptional>();
- const bool textWithoutIcon = !symbolInstance.hasIcon || layout.get<style::IconOptional>();
+ const bool iconWithoutText = !symbolInstance.hasText() || layout.get<style::TextOptional>();
+ const bool textWithoutIcon = !symbolInstance.hasIcon() || layout.get<style::IconOptional>();
// combine placements for icon and text
if (!iconWithoutText && !textWithoutIcon) {
@@ -385,7 +400,7 @@ void Placement::placeBucket(
}
if (placeText) {
- if (placedVertical.first && symbolInstance.verticalTextCollisionFeature) {
+ if (placedVerticalText.first && symbolInstance.verticalTextCollisionFeature) {
collisionIndex.insertFeature(*symbolInstance.verticalTextCollisionFeature, textBoxes, layout.get<style::TextIgnorePlacement>(), bucket.bucketInstanceId, collisionGroup.first);
} else {
collisionIndex.insertFeature(symbolInstance.textCollisionFeature, textBoxes, layout.get<style::TextIgnorePlacement>(), bucket.bucketInstanceId, collisionGroup.first);
@@ -393,16 +408,21 @@ void Placement::placeBucket(
}
if (placeIcon) {
- collisionIndex.insertFeature(symbolInstance.iconCollisionFeature, iconBoxes, layout.get<style::IconIgnorePlacement>(), bucket.bucketInstanceId, collisionGroup.first);
+ if (placedVerticalIcon.first && symbolInstance.verticalIconCollisionFeature) {
+ collisionIndex.insertFeature(*symbolInstance.verticalIconCollisionFeature, iconBoxes, layout.get<style::IconIgnorePlacement>(), bucket.bucketInstanceId, collisionGroup.first);
+ } else {
+ collisionIndex.insertFeature(symbolInstance.iconCollisionFeature, iconBoxes, layout.get<style::IconIgnorePlacement>(), bucket.bucketInstanceId, collisionGroup.first);
+ }
}
- if (hasCollisionCircleData) {
- if (symbolInstance.iconCollisionFeature.alongLine && !iconBoxes.empty()) {
- collisionCircles[&symbolInstance.iconCollisionFeature] = iconBoxes;
- }
- if (symbolInstance.textCollisionFeature.alongLine && !textBoxes.empty()) {
- collisionCircles[&symbolInstance.textCollisionFeature] = textBoxes;
- }
+ const bool hasIconCollisionCircleData = bucket.hasIconCollisionCircleData();
+ const bool hasTextCollisionCircleData = bucket.hasTextCollisionCircleData();
+
+ if (hasIconCollisionCircleData && symbolInstance.iconCollisionFeature.alongLine && !iconBoxes.empty()) {
+ collisionCircles[&symbolInstance.iconCollisionFeature] = iconBoxes;
+ }
+ if (hasTextCollisionCircleData && symbolInstance.textCollisionFeature.alongLine && !textBoxes.empty()) {
+ collisionCircles[&symbolInstance.textCollisionFeature] = textBoxes;
}
assert(symbolInstance.crossTileID != 0);
@@ -438,17 +458,15 @@ void Placement::placeBucket(
std::forward_as_tuple(bucket.bucketInstanceId, params.featureIndex, overscaledID));
}
-void Placement::commit(TimePoint now) {
+void Placement::commit(TimePoint now, const double zoom) {
assert(prevPlacement);
commitTime = now;
bool placementChanged = false;
- float increment = mapMode == MapMode::Continuous &&
- transitionOptions.enablePlacementTransitions &&
- transitionOptions.duration.value_or(util::DEFAULT_TRANSITION_DURATION) > Milliseconds(0) ?
- std::chrono::duration<float>(commitTime - prevPlacement->commitTime) / transitionOptions.duration.value_or(util::DEFAULT_TRANSITION_DURATION) :
- 1.0;
+ prevZoomAdjustment = prevPlacement->zoomAdjustment(zoom);
+
+ float increment = prevPlacement->symbolFadeChange(commitTime);
// add the opacities from the current placement, and copy their current values from the previous placement
for (auto& jointPlacement : placements) {
@@ -504,13 +522,13 @@ void Placement::updateLayerBuckets(const RenderLayer& layer, const TransformStat
}
namespace {
-Point<float> calculateVariableRenderShift(style::SymbolAnchorType anchor, float width, float height, float radialOffset, float textBoxScale, float renderTextSize) {
+Point<float> calculateVariableRenderShift(style::SymbolAnchorType anchor, float width, float height, std::array<float, 2> textOffset, float textBoxScale, float renderTextSize) {
AnchorAlignment alignment = AnchorAlignment::getAnchorAlignment(anchor);
float shiftX = -(alignment.horizontalAlign - 0.5f) * width;
float shiftY = -(alignment.verticalAlign - 0.5f) * height;
- Point<float> offset = SymbolLayout::evaluateRadialOffset(anchor, radialOffset);
- return { (shiftX / textBoxScale + offset.x) * renderTextSize,
- (shiftY / textBoxScale + offset.y) * renderTextSize };
+ auto variablOffset = SymbolLayout::evaluateVariableOffset(anchor, textOffset);
+ return { (shiftX / textBoxScale + variablOffset[0]) * renderTextSize,
+ (shiftY / textBoxScale + variablOffset[1]) * renderTextSize };
}
} // namespace
@@ -518,16 +536,26 @@ bool Placement::updateBucketDynamicVertices(SymbolBucket& bucket, const Transfor
using namespace style;
const auto& layout = *bucket.layout;
const bool alongLine = layout.get<SymbolPlacement>() != SymbolPlacementType::Point;
+ const bool hasVariableAnchors = !layout.get<TextVariableAnchor>().empty() && bucket.hasTextData();
+ const bool updateTextFitIcon = layout.get<IconTextFit>() != IconTextFitType::None && (bucket.allowVerticalPlacement || hasVariableAnchors) && (bucket.hasIconData() || bucket.hasSdfIconData());
bool result = false;
if (alongLine) {
- if (bucket.hasIconData() && layout.get<IconRotationAlignment>() == AlignmentType::Map) {
+ if (layout.get<IconRotationAlignment>() == AlignmentType::Map) {
const bool pitchWithMap = layout.get<style::IconPitchAlignment>() == style::AlignmentType::Map;
const bool keepUpright = layout.get<style::IconKeepUpright>();
- reprojectLineLabels(bucket.icon.dynamicVertices, bucket.icon.placedSymbols,
- tile.matrix, pitchWithMap, true /*rotateWithMap*/, keepUpright,
- tile, *bucket.iconSizeBinder, state);
- result = true;
+ if (bucket.hasSdfIconData()) {
+ reprojectLineLabels(bucket.sdfIcon.dynamicVertices, bucket.sdfIcon.placedSymbols,
+ tile.matrix, pitchWithMap, true /*rotateWithMap*/, keepUpright,
+ tile, *bucket.iconSizeBinder, state);
+ result = true;
+ }
+ if (bucket.hasIconData()) {
+ reprojectLineLabels(bucket.icon.dynamicVertices, bucket.icon.placedSymbols,
+ tile.matrix, pitchWithMap, true /*rotateWithMap*/, keepUpright,
+ tile, *bucket.iconSizeBinder, state);
+ result = true;
+ }
}
if (bucket.hasTextData() && layout.get<TextRotationAlignment>() == AlignmentType::Map) {
@@ -538,7 +566,7 @@ bool Placement::updateBucketDynamicVertices(SymbolBucket& bucket, const Transfor
tile, *bucket.textSizeBinder, state);
result = true;
}
- } else if (!layout.get<TextVariableAnchor>().empty() && bucket.hasTextData()) {
+ } else if (hasVariableAnchors) {
bucket.text.dynamicVertices.clear();
bucket.hasVariablePlacement = false;
@@ -548,8 +576,10 @@ bool Placement::updateBucketDynamicVertices(SymbolBucket& bucket, const Transfor
const bool pitchWithMap = layout.get<TextPitchAlignment>() == AlignmentType::Map;
const float pixelsToTileUnits = tile.id.pixelsToTileUnits(1.0, state.getZoom());
const auto labelPlaneMatrix = getLabelPlaneMatrix(tile.matrix, pitchWithMap, rotateWithMap, state, pixelsToTileUnits);
+ std::unordered_map<std::size_t, std::pair<std::size_t, Point<float>>> placedTextShifts;
- for (const PlacedSymbol& symbol : bucket.text.placedSymbols) {
+ for (std::size_t i = 0; i < bucket.text.placedSymbols.size(); ++i) {
+ const PlacedSymbol& symbol = bucket.text.placedSymbols[i];
optional<VariableOffset> variableOffset;
const bool skipOrientation = bucket.allowVerticalPlacement && !symbol.placedOrientation;
if (!symbol.hidden && symbol.crossTileID != 0u && !skipOrientation) {
@@ -578,7 +608,7 @@ bool Placement::updateBucketDynamicVertices(SymbolBucket& bucket, const Transfor
(*variableOffset).anchor,
(*variableOffset).width,
(*variableOffset).height,
- (*variableOffset).radialOffset,
+ (*variableOffset).offset,
(*variableOffset).textBoxScale,
renderTextSize);
@@ -598,24 +628,62 @@ bool Placement::updateBucketDynamicVertices(SymbolBucket& bucket, const Transfor
projectedAnchor.first.y + shift.y);
}
- for (std::size_t i = 0; i < symbol.glyphOffsets.size(); ++i) {
+ if (updateTextFitIcon && symbol.placedIconIndex) {
+ placedTextShifts.emplace(*symbol.placedIconIndex,
+ std::pair<std::size_t, Point<float>>{i, shiftedAnchor});
+ }
+
+ for (std::size_t j = 0; j < symbol.glyphOffsets.size(); ++j) {
addDynamicAttributes(shiftedAnchor, symbol.angle, bucket.text.dynamicVertices);
}
}
}
+ if (updateTextFitIcon && bucket.hasVariablePlacement) {
+ auto updateIcon = [&](SymbolBucket::Buffer& iconBuffer) {
+ iconBuffer.dynamicVertices.clear();
+ for (std::size_t i = 0; i < iconBuffer.placedSymbols.size(); ++i) {
+ const PlacedSymbol& placedIcon = iconBuffer.placedSymbols[i];
+ if (placedIcon.hidden || (!placedIcon.placedOrientation && bucket.allowVerticalPlacement)) {
+ hideGlyphs(placedIcon.glyphOffsets.size(), iconBuffer.dynamicVertices);
+ } else {
+ const auto& pair = placedTextShifts.find(i);
+ if (pair == placedTextShifts.end()) {
+ hideGlyphs(placedIcon.glyphOffsets.size(), iconBuffer.dynamicVertices);
+ } else {
+ for (std::size_t j = 0; j < placedIcon.glyphOffsets.size(); ++j) {
+ addDynamicAttributes(pair->second.second, placedIcon.angle, iconBuffer.dynamicVertices);
+ }
+ }
+ }
+ }
+ };
+ updateIcon(bucket.icon);
+ updateIcon(bucket.sdfIcon);
+ }
+
result = true;
} else if (bucket.allowVerticalPlacement && bucket.hasTextData()) {
- bucket.text.dynamicVertices.clear();
- for (const PlacedSymbol& symbol : bucket.text.placedSymbols) {
- if (symbol.hidden || !symbol.placedOrientation) {
- hideGlyphs(symbol.glyphOffsets.size(), bucket.text.dynamicVertices);
- } else {
- for (std::size_t i = 0; i < symbol.glyphOffsets.size(); ++i) {
- addDynamicAttributes(symbol.anchorPoint, symbol.angle, bucket.text.dynamicVertices);
+ const auto updateDynamicVertices = [](SymbolBucket::Buffer& buffer) {
+ buffer.dynamicVertices.clear();
+ for (const PlacedSymbol& symbol : buffer.placedSymbols) {
+ if (symbol.hidden || !symbol.placedOrientation) {
+ hideGlyphs(symbol.glyphOffsets.size(), buffer.dynamicVertices);
+ } else {
+ for (std::size_t j = 0; j < symbol.glyphOffsets.size(); ++j) {
+ addDynamicAttributes(symbol.anchorPoint, symbol.angle, buffer.dynamicVertices);
+ }
}
}
+ };
+
+ updateDynamicVertices(bucket.text);
+ // When text box is rotated, icon-text-fit icon must be rotated as well.
+ if (updateTextFitIcon) {
+ updateDynamicVertices(bucket.icon);
+ updateDynamicVertices(bucket.sdfIcon);
}
+
result = true;
}
@@ -625,23 +693,27 @@ bool Placement::updateBucketDynamicVertices(SymbolBucket& bucket, const Transfor
void Placement::updateBucketOpacities(SymbolBucket& bucket, const TransformState& state, std::set<uint32_t>& seenCrossTileIDs) {
if (bucket.hasTextData()) bucket.text.opacityVertices.clear();
if (bucket.hasIconData()) bucket.icon.opacityVertices.clear();
- if (bucket.hasCollisionBoxData()) bucket.collisionBox->dynamicVertices.clear();
- if (bucket.hasCollisionCircleData()) bucket.collisionCircle->dynamicVertices.clear();
+ if (bucket.hasSdfIconData()) bucket.sdfIcon.opacityVertices.clear();
+ if (bucket.hasIconCollisionBoxData()) bucket.iconCollisionBox->dynamicVertices.clear();
+ if (bucket.hasIconCollisionCircleData()) bucket.iconCollisionCircle->dynamicVertices.clear();
+ if (bucket.hasTextCollisionBoxData()) bucket.textCollisionBox->dynamicVertices.clear();
+ if (bucket.hasTextCollisionCircleData()) bucket.textCollisionCircle->dynamicVertices.clear();
- JointOpacityState duplicateOpacityState(false, false, true);
+ const JointOpacityState duplicateOpacityState(false, false, true);
const bool textAllowOverlap = bucket.layout->get<style::TextAllowOverlap>();
const bool iconAllowOverlap = bucket.layout->get<style::IconAllowOverlap>();
const bool variablePlacement = !bucket.layout->get<style::TextVariableAnchor>().empty();
const bool rotateWithMap = bucket.layout->get<style::TextRotationAlignment>() == style::AlignmentType::Map;
const bool pitchWithMap = bucket.layout->get<style::TextPitchAlignment>() == style::AlignmentType::Map;
+ const bool hasIconTextFit = bucket.layout->get<style::IconTextFit>() != style::IconTextFitType::None;
// If allow-overlap is true, we can show symbols before placement runs on them
// But we have to wait for placement if we potentially depend on a paired icon/text
// with allow-overlap: false.
// See https://github.com/mapbox/mapbox-gl-native/issues/12483
- JointOpacityState defaultOpacityState(
- textAllowOverlap && (iconAllowOverlap || !bucket.hasIconData() || bucket.layout->get<style::IconOptional>()),
+ const JointOpacityState defaultOpacityState(
+ textAllowOverlap && (iconAllowOverlap || !(bucket.hasIconData() || bucket.hasSdfIconData()) || bucket.layout->get<style::IconOptional>()),
iconAllowOverlap && (textAllowOverlap || !bucket.hasTextData() || bucket.layout->get<style::TextOptional>()),
true);
@@ -656,13 +728,9 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, const TransformState
opacityState = it->second;
}
- if (it == opacities.end()) {
- opacities.emplace(symbolInstance.crossTileID, defaultOpacityState);
- }
-
seenCrossTileIDs.insert(symbolInstance.crossTileID);
- if (symbolInstance.hasText) {
+ if (symbolInstance.hasText()) {
size_t textOpacityVerticesSize = 0u;
const auto& opacityVertex = SymbolSDFTextProgram::opacityVertex(opacityState.text.placed, opacityState.text.opacity);
if (symbolInstance.placedRightTextIndex) {
@@ -701,27 +769,34 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, const TransformState
markUsedJustification(bucket, prevOffset->second.anchor, symbolInstance, previousOrientation);
}
}
- if (symbolInstance.hasIcon) {
+ if (symbolInstance.hasIcon()) {
const auto& opacityVertex = SymbolIconProgram::opacityVertex(opacityState.icon.placed, opacityState.icon.opacity);
- bucket.icon.opacityVertices.extend(4, opacityVertex);
+ auto& iconBuffer = symbolInstance.hasSdfIcon() ? bucket.sdfIcon : bucket.icon;
+
if (symbolInstance.placedIconIndex) {
- bucket.icon.placedSymbols[*symbolInstance.placedIconIndex].hidden = opacityState.isHidden();
+ iconBuffer.opacityVertices.extend(4, opacityVertex);
+ iconBuffer.placedSymbols[*symbolInstance.placedIconIndex].hidden = opacityState.isHidden();
+ }
+
+ if (symbolInstance.placedVerticalIconIndex) {
+ iconBuffer.opacityVertices.extend(4, opacityVertex);
+ iconBuffer.placedSymbols[*symbolInstance.placedVerticalIconIndex].hidden = opacityState.isHidden();
}
}
- auto updateCollisionBox = [&](const auto& feature, const bool placed) {
+ auto updateIconCollisionBox = [&](const auto& feature, const bool placed, const Point<float>& shift) {
if (feature.alongLine) {
return;
}
- const auto& dynamicVertex = CollisionBoxProgram::dynamicVertex(placed, false, {});
- bucket.collisionBox->dynamicVertices.extend(feature.boxes.size() * 4, dynamicVertex);
+ const auto& dynamicVertex = CollisionBoxProgram::dynamicVertex(placed, false, shift);
+ bucket.iconCollisionBox->dynamicVertices.extend(feature.boxes.size() * 4, dynamicVertex);
};
- auto updateCollisionTextBox = [this, &bucket, &symbolInstance, &state, variablePlacement, rotateWithMap, pitchWithMap](const auto& feature, const bool placed) {
+ auto updateTextCollisionBox = [this, &bucket, &symbolInstance, &state, variablePlacement, rotateWithMap, pitchWithMap](const auto& feature, const bool placed) {
+ Point<float> shift{0.0f, 0.0f};
if (feature.alongLine) {
- return;
+ return shift;
}
- Point<float> shift;
bool used = true;
if (variablePlacement) {
auto foundOffset = variableOffsets.find(symbolInstance.crossTileID);
@@ -734,7 +809,7 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, const TransformState
shift = calculateVariableLayoutOffset(variableOffset.anchor,
variableOffset.width,
variableOffset.height,
- variableOffset.radialOffset,
+ variableOffset.offset,
variableOffset.textBoxScale);
if (rotateWithMap) {
shift = util::rotate(shift, pitchWithMap ? state.getBearing() : -state.getBearing());
@@ -747,10 +822,11 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, const TransformState
}
}
const auto& dynamicVertex = CollisionBoxProgram::dynamicVertex(placed, !used, shift);
- bucket.collisionBox->dynamicVertices.extend(feature.boxes.size() * 4, dynamicVertex);
+ bucket.textCollisionBox->dynamicVertices.extend(feature.boxes.size() * 4, dynamicVertex);
+ return shift;
};
- auto updateCollisionCircles = [&](const auto& feature, const bool placed) {
+ auto updateCollisionCircles = [&](const auto& feature, const bool placed, bool isText) {
if (!feature.alongLine) {
return;
}
@@ -758,26 +834,36 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, const TransformState
if (circles != collisionCircles.end()) {
for (const auto& circle : circles->second) {
const auto& dynamicVertex = CollisionBoxProgram::dynamicVertex(placed, !circle.isCircle(), {});
- bucket.collisionCircle->dynamicVertices.extend(4, dynamicVertex);
+ isText ? bucket.textCollisionCircle->dynamicVertices.extend(4, dynamicVertex):
+ bucket.iconCollisionCircle->dynamicVertices.extend(4, dynamicVertex);
}
} else {
// This feature was not placed, because it was not loaded or from a fading tile. Apply default values.
static const auto dynamicVertex = CollisionBoxProgram::dynamicVertex(placed, false /*not used*/, {});
- bucket.collisionCircle->dynamicVertices.extend(4 * feature.boxes.size(), dynamicVertex);
+ isText ? bucket.textCollisionCircle->dynamicVertices.extend(4 * feature.boxes.size(), dynamicVertex):
+ bucket.iconCollisionCircle->dynamicVertices.extend(4 * feature.boxes.size(), dynamicVertex);
}
};
-
- if (bucket.hasCollisionBoxData()) {
- // TODO: update collision box opacity based on selected text variant (horizontal | vertical).
- updateCollisionTextBox(symbolInstance.textCollisionFeature, opacityState.text.placed);
+ Point<float> textShift{0.0f, 0.0f};
+ Point<float> verticalTextShift{0.0f, 0.0f};
+ if (bucket.hasTextCollisionBoxData()) {
+ textShift = updateTextCollisionBox(symbolInstance.textCollisionFeature, opacityState.text.placed);
if (bucket.allowVerticalPlacement && symbolInstance.verticalTextCollisionFeature) {
- updateCollisionTextBox(*symbolInstance.verticalTextCollisionFeature, opacityState.text.placed);
+ verticalTextShift = updateTextCollisionBox(*symbolInstance.verticalTextCollisionFeature, opacityState.text.placed);
}
- updateCollisionBox(symbolInstance.iconCollisionFeature, opacityState.icon.placed);
}
- if (bucket.hasCollisionCircleData()) {
- updateCollisionCircles(symbolInstance.textCollisionFeature, opacityState.text.placed);
- updateCollisionCircles(symbolInstance.iconCollisionFeature, opacityState.icon.placed);
+ if (bucket.hasIconCollisionBoxData()) {
+ updateIconCollisionBox(symbolInstance.iconCollisionFeature, opacityState.icon.placed, hasIconTextFit ? textShift : Point<float>{0.0f, 0.0f});
+ if (bucket.allowVerticalPlacement && symbolInstance.verticalIconCollisionFeature) {
+ updateIconCollisionBox(*symbolInstance.verticalIconCollisionFeature, opacityState.text.placed, hasIconTextFit ? verticalTextShift : Point<float>{0.0f, 0.0f});
+ }
+ }
+
+ if (bucket.hasIconCollisionCircleData()) {
+ updateCollisionCircles(symbolInstance.iconCollisionFeature, opacityState.icon.placed, false);
+ }
+ if (bucket.hasTextCollisionCircleData()) {
+ updateCollisionCircles(symbolInstance.textCollisionFeature, opacityState.text.placed, true);
}
}
@@ -850,17 +936,45 @@ void Placement::markUsedOrientation(SymbolBucket& bucket, style::TextWritingMode
if (symbolInstance.placedVerticalTextIndex) {
bucket.text.placedSymbols.at(*symbolInstance.placedVerticalTextIndex).placedOrientation = vertical;
}
+
+ auto& iconBuffer = symbolInstance.hasSdfIcon() ? bucket.sdfIcon : bucket.icon;
+ if (symbolInstance.placedIconIndex) {
+ iconBuffer.placedSymbols.at(*symbolInstance.placedIconIndex).placedOrientation = horizontal;
+ }
+
+ if (symbolInstance.placedVerticalIconIndex) {
+ iconBuffer.placedSymbols.at(*symbolInstance.placedVerticalIconIndex).placedOrientation = vertical;
+ }
}
float Placement::symbolFadeChange(TimePoint now) const {
if (mapMode == MapMode::Continuous && transitionOptions.enablePlacementTransitions &&
transitionOptions.duration.value_or(util::DEFAULT_TRANSITION_DURATION) > Milliseconds(0)) {
- return std::chrono::duration<float>(now - commitTime) / transitionOptions.duration.value_or(util::DEFAULT_TRANSITION_DURATION);
+ return std::chrono::duration<float>(now - commitTime) / transitionOptions.duration.value_or(util::DEFAULT_TRANSITION_DURATION) + prevZoomAdjustment;
} else {
return 1.0;
}
}
+float Placement::zoomAdjustment(const float zoom) const {
+ // When zooming out labels can overlap each other quickly. This
+ // adjustment is used to reduce the fade duration for symbols while zooming out quickly.
+ // It is also used to reduce the interval between placement calculations. Reducing the
+ // interval between placements means collisions are discovered and eliminated sooner.
+ return std::max(0.0, (placementZoom - zoom) / 1.5);
+}
+
+Duration Placement::getUpdatePeriod(const float zoom) const {
+ // Even if transitionOptions.duration is set to a value < 300ms, we still wait for this default transition duration
+ // before attempting another placement operation.
+ const auto fadeDuration = std::max(util::DEFAULT_TRANSITION_DURATION, transitionOptions.duration.value_or(util::DEFAULT_TRANSITION_DURATION));
+ const auto adjustedDuration = std::chrono::duration_cast<Duration>(fadeDuration * (1.0 - zoomAdjustment(zoom)));
+ if (maximumUpdatePeriod) {
+ return std::min(*maximumUpdatePeriod, adjustedDuration);
+ }
+ return adjustedDuration;
+}
+
bool Placement::hasTransitions(TimePoint now) const {
if (mapMode == MapMode::Continuous && transitionOptions.enablePlacementTransitions) {
return stale || std::chrono::duration<float>(now - fadeStartTime) < transitionOptions.duration.value_or(util::DEFAULT_TRANSITION_DURATION);
@@ -869,12 +983,14 @@ bool Placement::hasTransitions(TimePoint now) const {
}
}
-bool Placement::stillRecent(TimePoint now) const {
- // Even if transitionOptions.duration is set to a value < 300ms, we still wait for this default transition duration
- // before attempting another placement operation.
+bool Placement::stillRecent(TimePoint now, const float zoom) const {
return mapMode == MapMode::Continuous &&
transitionOptions.enablePlacementTransitions &&
- commitTime + std::max(util::DEFAULT_TRANSITION_DURATION, transitionOptions.duration.value_or(util::DEFAULT_TRANSITION_DURATION)) > now;
+ commitTime + getUpdatePeriod(zoom) > now;
+}
+
+void Placement::setMaximumUpdatePeriod(Duration duration) {
+ maximumUpdatePeriod = duration;
}
void Placement::setStale() {
diff --git a/src/mbgl/text/placement.hpp b/src/mbgl/text/placement.hpp
index 722a4a0926..b5405cbcd7 100644
--- a/src/mbgl/text/placement.hpp
+++ b/src/mbgl/text/placement.hpp
@@ -34,7 +34,7 @@ public:
class VariableOffset {
public:
- float radialOffset;
+ std::array<float, 2> offset;
float width;
float height;
style::TextVariableAnchorType anchor;
@@ -102,15 +102,15 @@ class Placement {
public:
Placement(const TransformState&, MapMode, style::TransitionOptions, const bool crossSourceCollisions, std::unique_ptr<Placement> prevPlacementOrNull = nullptr);
void placeLayer(const RenderLayer&, const mat4&, bool showCollisionBoxes);
- void commit(TimePoint);
+ void commit(TimePoint, const double zoom);
void updateLayerBuckets(const RenderLayer&, const TransformState&, bool updateOpacities);
float symbolFadeChange(TimePoint now) const;
bool hasTransitions(TimePoint now) const;
const CollisionIndex& getCollisionIndex() const;
- bool stillRecent(TimePoint now) const;
- void setRecent(TimePoint now);
+ bool stillRecent(TimePoint now, const float zoom) const;
+ void setMaximumUpdatePeriod(Duration);
void setStale();
const RetainedQueryData& getQueryData(uint32_t bucketInstanceId) const;
@@ -125,6 +125,8 @@ private:
void updateBucketOpacities(SymbolBucket&, const TransformState&, std::set<uint32_t>&);
void markUsedJustification(SymbolBucket&, style::TextVariableAnchorType, const SymbolInstance&, style::TextWritingModeType orientation);
void markUsedOrientation(SymbolBucket&, style::TextWritingModeType, const SymbolInstance&);
+ float zoomAdjustment(const float zoom) const;
+ Duration getUpdatePeriod(const float zoom) const;
CollisionIndex collisionIndex;
@@ -133,6 +135,8 @@ private:
TimePoint fadeStartTime;
TimePoint commitTime;
+ float placementZoom;
+ float prevZoomAdjustment = 0;
std::unordered_map<uint32_t, JointPlacement> placements;
std::unordered_map<uint32_t, JointOpacityState> opacities;
@@ -144,6 +148,7 @@ private:
std::unordered_map<uint32_t, RetainedQueryData> retainedQueryData;
CollisionGroups collisionGroups;
std::unique_ptr<Placement> prevPlacement;
+ optional<Duration> maximumUpdatePeriod;
// Used for debug purposes.
std::unordered_map<const CollisionFeature*, std::vector<ProjectedCollisionBox>> collisionCircles;
diff --git a/src/mbgl/text/quads.cpp b/src/mbgl/text/quads.cpp
index b08c2bc0ba..281c5d99de 100644
--- a/src/mbgl/text/quads.cpp
+++ b/src/mbgl/text/quads.cpp
@@ -14,9 +14,7 @@ namespace mbgl {
using namespace style;
SymbolQuad getIconQuad(const PositionedIcon& shapedIcon,
- const SymbolLayoutProperties::Evaluated& layout,
- const float layoutTextSize,
- const Shaping& shapedText) {
+ WritingModeType writingMode) {
const ImagePosition& image = shapedIcon.image();
// If you have a 10px icon that isn't perfectly aligned to the pixel grid it will cover 11 actual
@@ -28,43 +26,11 @@ SymbolQuad getIconQuad(const PositionedIcon& shapedIcon,
float left = shapedIcon.left() - border / image.pixelRatio;
float bottom = shapedIcon.bottom() + border / image.pixelRatio;
float right = shapedIcon.right() + border / image.pixelRatio;
- Point<float> tl;
- Point<float> tr;
- Point<float> br;
- Point<float> bl;
-
- if (layout.get<IconTextFit>() != IconTextFitType::None && shapedText) {
- auto iconWidth = right - left;
- auto iconHeight = bottom - top;
- auto size = layoutTextSize / 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.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;
- bottom = textTop + offsetY + padB + height;
- tl = {left, top};
- tr = {right, top};
- br = {right, bottom};
- bl = {left, bottom};
- } else {
- tl = {left, top};
- tr = {right, top};
- br = {right, bottom};
- bl = {left, bottom};
- }
+
+ Point<float> tl{left, top};
+ Point<float> tr{right, top};
+ Point<float> br{right, bottom};
+ Point<float> bl{left, bottom};
const float angle = shapedIcon.angle();
@@ -88,7 +54,7 @@ SymbolQuad getIconQuad(const PositionedIcon& shapedIcon,
static_cast<uint16_t>(image.textureRect.h + border * 2)
};
- return SymbolQuad { tl, tr, bl, br, textureRect, shapedText.writingMode, { 0.0f, 0.0f } };
+ return SymbolQuad { tl, tr, bl, br, textureRect, writingMode, { 0.0f, 0.0f } };
}
SymbolQuads getGlyphQuads(const Shaping& shapedText,
diff --git a/src/mbgl/text/quads.hpp b/src/mbgl/text/quads.hpp
index 1ec68189af..145fd2b153 100644
--- a/src/mbgl/text/quads.hpp
+++ b/src/mbgl/text/quads.hpp
@@ -44,9 +44,7 @@ public:
using SymbolQuads = std::vector<SymbolQuad>;
SymbolQuad getIconQuad(const PositionedIcon& shapedIcon,
- const style::SymbolLayoutProperties::Evaluated&,
- const float layoutTextSize,
- const Shaping& shapedText);
+ WritingModeType writingMode);
SymbolQuads getGlyphQuads(const Shaping& shapedText,
const std::array<float, 2> textOffset,
diff --git a/src/mbgl/text/shaping.cpp b/src/mbgl/text/shaping.cpp
index 7bf0e14f80..d6d9a3d34e 100644
--- a/src/mbgl/text/shaping.cpp
+++ b/src/mbgl/text/shaping.cpp
@@ -68,16 +68,49 @@ style::TextJustifyType getAnchorJustification(style::SymbolAnchorType anchor) {
}
}
-PositionedIcon PositionedIcon::shapeIcon(const ImagePosition& image, const std::array<float, 2>& iconOffset, style::SymbolAnchorType iconAnchor, const float iconRotation) {
+PositionedIcon PositionedIcon::shapeIcon(const ImagePosition& image,
+ const std::array<float, 2>& iconOffset,
+ style::SymbolAnchorType iconAnchor,
+ const float iconRotation) {
AnchorAlignment anchorAlign = AnchorAlignment::getAnchorAlignment(iconAnchor);
float dx = iconOffset[0];
float dy = iconOffset[1];
- float x1 = dx - image.displaySize()[0] * anchorAlign.horizontalAlign;
- float x2 = x1 + image.displaySize()[0];
- float y1 = dy - image.displaySize()[1] * anchorAlign.verticalAlign;
- float y2 = y1 + image.displaySize()[1];
+ float left = dx - image.displaySize()[0] * anchorAlign.horizontalAlign;
+ float right = left + image.displaySize()[0];
+ float top = dy - image.displaySize()[1] * anchorAlign.verticalAlign;
+ float bottom = top + image.displaySize()[1];
- return PositionedIcon { image, y1, y2, x1, x2, iconRotation };
+ return PositionedIcon { image, top, bottom, left, right, iconRotation };
+}
+
+void PositionedIcon::fitIconToText(const style::SymbolLayoutProperties::Evaluated& layout,
+ const Shaping& shapedText,
+ float layoutTextSize) {
+ using namespace style;
+ assert(layout.get<IconTextFit>() != IconTextFitType::None);
+ if (shapedText) {
+ auto iconWidth = _right - _left;
+ auto iconHeight = _bottom - _top;
+ auto size = layoutTextSize / 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.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;
+ _bottom = textTop + offsetY + padB + height;
+ }
}
void align(Shaping& shaping,
@@ -380,7 +413,7 @@ const Shaping getShaping(const TaggedString& formattedString,
const style::SymbolAnchorType textAnchor,
const style::TextJustifyType textJustify,
const float spacing,
- const Point<float>& translate,
+ const std::array<float, 2>& translate,
const WritingModeType writingMode,
BiDi& bidi,
const GlyphMap& glyphs,
@@ -399,7 +432,7 @@ const Shaping getShaping(const TaggedString& formattedString,
reorderedLines.emplace_back(line, formattedString.getSections());
}
}
- Shaping shaping(translate.x, translate.y, writingMode, reorderedLines.size());
+ Shaping shaping(translate[0], translate[1], writingMode, reorderedLines.size());
shapeLines(shaping, reorderedLines, spacing, lineHeight, textAnchor,
textJustify, writingMode, glyphs, allowVerticalPlacement);
diff --git a/src/mbgl/text/shaping.hpp b/src/mbgl/text/shaping.hpp
index f3a01e3caf..0e2f5515fe 100644
--- a/src/mbgl/text/shaping.hpp
+++ b/src/mbgl/text/shaping.hpp
@@ -4,6 +4,7 @@
#include <mbgl/text/tagged_string.hpp>
#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/style/types.hpp>
+#include <mbgl/style/layers/symbol_layer_properties.hpp>
namespace mbgl {
@@ -52,6 +53,12 @@ public:
style::SymbolAnchorType iconAnchor,
const float iconRotation);
+ // Updates shaped icon's bounds based on shaped text's bounds and provided
+ // layout properties.
+ void fitIconToText(const style::SymbolLayoutProperties::Evaluated& layout,
+ const Shaping& shapedText,
+ float layoutTextSize);
+
const ImagePosition& image() const { return _image; }
float top() const { return _top; }
float bottom() const { return _bottom; }
@@ -66,7 +73,7 @@ const Shaping getShaping(const TaggedString& string,
style::SymbolAnchorType textAnchor,
style::TextJustifyType textJustify,
float spacing,
- const Point<float>& translate,
+ const std::array<float, 2>& translate,
const WritingModeType,
BiDi& bidi,
const GlyphMap& glyphs,
diff --git a/src/mbgl/tile/geojson_tile.cpp b/src/mbgl/tile/geojson_tile.cpp
index 4cf971df84..0782f74d5d 100644
--- a/src/mbgl/tile/geojson_tile.cpp
+++ b/src/mbgl/tile/geojson_tile.cpp
@@ -13,8 +13,8 @@ GeoJSONTile::GeoJSONTile(const OverscaledTileID& overscaledTileID,
updateData(std::move(features));
}
-void GeoJSONTile::updateData(mapbox::feature::feature_collection<int16_t> features) {
- setData(std::make_unique<GeoJSONTileData>(std::move(features)));
+void GeoJSONTile::updateData(mapbox::feature::feature_collection<int16_t> features, bool resetLayers) {
+ setData(std::make_unique<GeoJSONTileData>(std::move(features)), resetLayers);
}
void GeoJSONTile::querySourceFeatures(
diff --git a/src/mbgl/tile/geojson_tile.hpp b/src/mbgl/tile/geojson_tile.hpp
index 725dc4850c..9161e33f0c 100644
--- a/src/mbgl/tile/geojson_tile.hpp
+++ b/src/mbgl/tile/geojson_tile.hpp
@@ -14,7 +14,7 @@ public:
const TileParameters&,
mapbox::feature::feature_collection<int16_t>);
- void updateData(mapbox::feature::feature_collection<int16_t>);
+ void updateData(mapbox::feature::feature_collection<int16_t>, bool resetLayers = false);
void querySourceFeatures(
std::vector<Feature>& result,
diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp
index a431ae423e..3087b4fc6a 100644
--- a/src/mbgl/tile/geometry_tile.cpp
+++ b/src/mbgl/tile/geometry_tile.cpp
@@ -176,13 +176,13 @@ void GeometryTile::setError(std::exception_ptr err) {
observer->onTileError(*this, err);
}
-void GeometryTile::setData(std::unique_ptr<const GeometryTileData> data_) {
+void GeometryTile::setData(std::unique_ptr<const GeometryTileData> data_, bool resetLayers) {
// Mark the tile as pending again if it was complete before to prevent signaling a complete
// state despite pending parse operations.
pending = true;
++correlationID;
- worker.self().invoke(&GeometryTileWorker::setData, std::move(data_), correlationID);
+ worker.self().invoke(&GeometryTileWorker::setData, std::move(data_), resetLayers, correlationID);
}
std::unique_ptr<TileRenderData> GeometryTile::createRenderData() {
diff --git a/src/mbgl/tile/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp
index 7c46edfc1d..8682c8c76b 100644
--- a/src/mbgl/tile/geometry_tile.hpp
+++ b/src/mbgl/tile/geometry_tile.hpp
@@ -34,7 +34,7 @@ public:
~GeometryTile() override;
void setError(std::exception_ptr);
- void setData(std::unique_ptr<const GeometryTileData>);
+ void setData(std::unique_ptr<const GeometryTileData>, bool resetLayers = false);
std::unique_ptr<TileRenderData> createRenderData() override;
void setLayers(const std::vector<Immutable<style::LayerProperties>>&) override;
diff --git a/src/mbgl/tile/geometry_tile_data.cpp b/src/mbgl/tile/geometry_tile_data.cpp
index 5320df6893..f723a94800 100644
--- a/src/mbgl/tile/geometry_tile_data.cpp
+++ b/src/mbgl/tile/geometry_tile_data.cpp
@@ -74,6 +74,7 @@ std::vector<GeometryCollection> classifyRings(const GeometryCollection& rings) {
if (ccw == (area < 0 ? -1 : 1) && !polygon.empty()) {
polygons.emplace_back(std::move(polygon));
+ polygon = GeometryCollection();
}
polygon.emplace_back(ring);
@@ -100,8 +101,8 @@ void limitHoles(GeometryCollection& polygon, uint32_t maxHoles) {
static Feature::geometry_type convertGeometry(const GeometryTileFeature& geometryTileFeature, const CanonicalTileID& tileID) {
const double size = util::EXTENT * std::pow(2, tileID.z);
- const double x0 = util::EXTENT * tileID.x;
- const double y0 = util::EXTENT * tileID.y;
+ const double x0 = util::EXTENT * static_cast<double>(tileID.x);
+ const double y0 = util::EXTENT * static_cast<double>(tileID.y);
auto tileCoordinatesToLatLng = [&] (const Point<int16_t>& p) {
double y2 = 180 - (p.y + y0) * 360 / size;
diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp
index f4d57e5bfc..428a5b0d5e 100644
--- a/src/mbgl/tile/geometry_tile_worker.cpp
+++ b/src/mbgl/tile/geometry_tile_worker.cpp
@@ -117,10 +117,11 @@ GeometryTileWorker::~GeometryTileWorker() = default;
completed parse.
*/
-void GeometryTileWorker::setData(std::unique_ptr<const GeometryTileData> data_, uint64_t correlationID_) {
+void GeometryTileWorker::setData(std::unique_ptr<const GeometryTileData> data_, bool resetLayers_, uint64_t correlationID_) {
try {
data = std::move(data_);
correlationID = correlationID_;
+ if (resetLayers_) layers = nullopt;
switch (state) {
case Idle:
diff --git a/src/mbgl/tile/geometry_tile_worker.hpp b/src/mbgl/tile/geometry_tile_worker.hpp
index 258f2cd186..96b4e2e83a 100644
--- a/src/mbgl/tile/geometry_tile_worker.hpp
+++ b/src/mbgl/tile/geometry_tile_worker.hpp
@@ -39,7 +39,7 @@ public:
~GeometryTileWorker();
void setLayers(std::vector<Immutable<style::LayerProperties>>, uint64_t correlationID);
- void setData(std::unique_ptr<const GeometryTileData>, uint64_t correlationID);
+ void setData(std::unique_ptr<const GeometryTileData>, bool resetLayers, uint64_t correlationID);
void setShowCollisionBoxes(bool showCollisionBoxes_, uint64_t correlationID_);
void onGlyphsAvailable(GlyphMap glyphs);
diff --git a/src/mbgl/util/chrono.cpp b/src/mbgl/util/chrono.cpp
index 6674e73c42..03e97eedf5 100644
--- a/src/mbgl/util/chrono.cpp
+++ b/src/mbgl/util/chrono.cpp
@@ -22,8 +22,13 @@ std::string rfc1123(Timestamp timestamp) {
std::time_t time = std::chrono::system_clock::to_time_t(timestamp);
std::tm info;
_gmtime(&time, &info);
- char buffer[30];
- snprintf(buffer, 30, "%s, %02d %s %4d %02d:%02d:%02d GMT", week[info.tm_wday], info.tm_mday,
+
+ // Buffer size 30 is OK assuming the year has 4 digits. However, In theory, it might have
+ // more digits. Under gcc 8.3.0 with -Os optimization flag, there is compiler warning
+ // complaining about the buffer size might be too small. Inceasing the buffer to 32 fixes
+ // the warning.
+ char buffer[32];
+ snprintf(buffer, 32, "%s, %02d %s %4d %02d:%02d:%02d GMT", week[info.tm_wday], info.tm_mday,
months[info.tm_mon], 1900 + info.tm_year, info.tm_hour, info.tm_min, info.tm_sec);
return buffer;
}
diff --git a/src/mbgl/util/tile_coordinate.hpp b/src/mbgl/util/tile_coordinate.hpp
index b6bdc5f590..6d78804947 100644
--- a/src/mbgl/util/tile_coordinate.hpp
+++ b/src/mbgl/util/tile_coordinate.hpp
@@ -13,6 +13,7 @@ using TileCoordinatePoint = Point<double>;
// Has floating point x/y coordinates.
// Used for computing the tiles that need to be visible in the viewport.
+// In mapbox-gl-js, this is named MercatorCoordinate.
class TileCoordinate {
public:
TileCoordinatePoint p;
@@ -23,8 +24,8 @@ public:
return { Projection::project(latLng, scale) / util::tileSize, zoom };
}
- static TileCoordinate fromScreenCoordinate(const TransformState& state, double zoom, const ScreenCoordinate& screenCoordinate) {
- return fromLatLng(zoom, state.screenCoordinateToLatLng(screenCoordinate));
+ static TileCoordinate fromScreenCoordinate(const TransformState& state, uint8_t zoom, const ScreenCoordinate& screenCoordinate) {
+ return state.screenCoordinateToTileCoordinate(screenCoordinate, zoom);
}
TileCoordinate zoomTo(double zoom) const {
diff --git a/src/mbgl/util/tile_cover.cpp b/src/mbgl/util/tile_cover.cpp
index 5189b79f26..9e2451e1af 100644
--- a/src/mbgl/util/tile_cover.cpp
+++ b/src/mbgl/util/tile_cover.cpp
@@ -84,7 +84,7 @@ std::vector<UnwrappedTileID> tileCover(const Point<double>& tl,
const Point<double>& br,
const Point<double>& bl,
const Point<double>& c,
- int32_t z) {
+ uint8_t z) {
const int32_t tiles = 1 << z;
struct ID {
@@ -139,7 +139,7 @@ int32_t coveringZoomLevel(double zoom, style::SourceType type, uint16_t size) {
}
}
-std::vector<UnwrappedTileID> tileCover(const LatLngBounds& bounds_, int32_t z) {
+std::vector<UnwrappedTileID> tileCover(const LatLngBounds& bounds_, uint8_t z) {
if (bounds_.isEmpty() ||
bounds_.south() > util::LATITUDE_MAX ||
bounds_.north() < -util::LATITUDE_MAX) {
@@ -159,7 +159,7 @@ std::vector<UnwrappedTileID> tileCover(const LatLngBounds& bounds_, int32_t z) {
z);
}
-std::vector<UnwrappedTileID> tileCover(const TransformState& state, int32_t z) {
+std::vector<UnwrappedTileID> tileCover(const TransformState& state, uint8_t z) {
assert(state.valid());
const double w = state.getSize().width;
@@ -173,7 +173,7 @@ std::vector<UnwrappedTileID> tileCover(const TransformState& state, int32_t z) {
z);
}
-std::vector<UnwrappedTileID> tileCover(const Geometry<double>& geometry, int32_t z) {
+std::vector<UnwrappedTileID> tileCover(const Geometry<double>& geometry, uint8_t z) {
std::vector<UnwrappedTileID> result;
TileCover tc(geometry, z, true);
while (tc.hasNext()) {
@@ -213,7 +213,7 @@ uint64_t tileCount(const Geometry<double>& geometry, uint8_t z) {
return tileCount;
}
-TileCover::TileCover(const LatLngBounds&bounds_, int32_t z) {
+TileCover::TileCover(const LatLngBounds&bounds_, uint8_t z) {
LatLngBounds bounds = LatLngBounds::hull(
{ std::max(bounds_.south(), -util::LATITUDE_MAX), bounds_.west() },
{ std::min(bounds_.north(), util::LATITUDE_MAX), bounds_.east() });
@@ -233,7 +233,7 @@ TileCover::TileCover(const LatLngBounds&bounds_, int32_t z) {
impl = std::make_unique<TileCover::Impl>(z, p, false);
}
-TileCover::TileCover(const Geometry<double>& geom, int32_t z, bool project/* = true*/)
+TileCover::TileCover(const Geometry<double>& geom, uint8_t z, bool project/* = true*/)
: impl( std::make_unique<TileCover::Impl>(z, geom, project)) {
}
diff --git a/src/mbgl/util/tile_cover.hpp b/src/mbgl/util/tile_cover.hpp
index c953d764d2..5ac3537bf6 100644
--- a/src/mbgl/util/tile_cover.hpp
+++ b/src/mbgl/util/tile_cover.hpp
@@ -18,9 +18,9 @@ namespace util {
// Helper class to stream tile-cover results per row
class TileCover {
public:
- TileCover(const LatLngBounds&, int32_t z);
+ TileCover(const LatLngBounds&, uint8_t z);
// When project == true, projects the geometry points to tile coordinates
- TileCover(const Geometry<double>&, int32_t z, bool project = true);
+ TileCover(const Geometry<double>&, uint8_t z, bool project = true);
~TileCover();
optional<UnwrappedTileID> next();
@@ -33,9 +33,9 @@ private:
int32_t coveringZoomLevel(double z, style::SourceType type, uint16_t tileSize);
-std::vector<UnwrappedTileID> tileCover(const TransformState&, int32_t z);
-std::vector<UnwrappedTileID> tileCover(const LatLngBounds&, int32_t z);
-std::vector<UnwrappedTileID> tileCover(const Geometry<double>&, int32_t z);
+std::vector<UnwrappedTileID> tileCover(const TransformState&, uint8_t z);
+std::vector<UnwrappedTileID> tileCover(const LatLngBounds&, uint8_t z);
+std::vector<UnwrappedTileID> tileCover(const Geometry<double>&, uint8_t z);
// Compute only the count of tiles needed for tileCover
uint64_t tileCount(const LatLngBounds&, uint8_t z);