diff options
author | m-stephen <truestyle2005@163.com> | 2019-09-17 10:46:33 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-09-17 10:46:33 +0800 |
commit | eb1f8eb32286dd7b89ae76b839b774b0071ca5a5 (patch) | |
tree | 0db6df1811ffb8c9a5139687817386dee23cfef1 /src | |
parent | b0018568b84f9bb1c185f0441a41741e9fde5a84 (diff) | |
parent | a99240a54ffd5eb77568d41e10186411b1b759eb (diff) | |
download | qtlocation-mapboxgl-eb1f8eb32286dd7b89ae76b839b774b0071ca5a5.tar.gz |
Merge branch 'master' into stephen-ios-error-report
Diffstat (limited to 'src')
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 ℑ @@ -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); |