From 1759603e128ad0a08f4a25009b82695420ec2840 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Thu, 18 May 2017 09:37:21 -0700 Subject: [core] Simplify and fix sprite atlas coordinate calculations * Always return image metrics exclusive of padding * Work with integer coordinates whenever possible * Eliminate redundant SpriteAtlasElement members * Fix asymmetric re-padding in getIconQuad when pixelRatio != 1 * Add explanatory comments --- mapbox-gl-js | 2 +- src/mbgl/layout/symbol_layout.cpp | 3 +- src/mbgl/layout/symbol_layout.hpp | 1 + src/mbgl/programs/fill_extrusion_program.cpp | 12 +- src/mbgl/programs/fill_program.cpp | 12 +- src/mbgl/programs/line_program.cpp | 16 +- src/mbgl/programs/uniforms.hpp | 8 +- src/mbgl/renderer/bucket_parameters.hpp | 1 + src/mbgl/renderer/painters/painter_background.cpp | 2 +- src/mbgl/renderer/painters/painter_fill.cpp | 2 +- .../renderer/painters/painter_fill_extrusion.cpp | 2 +- src/mbgl/renderer/painters/painter_line.cpp | 2 +- src/mbgl/renderer/painters/painter_symbol.cpp | 6 +- src/mbgl/sprite/sprite_atlas.cpp | 64 +++--- src/mbgl/sprite/sprite_atlas.hpp | 42 +++- src/mbgl/text/quads.cpp | 22 ++- src/mbgl/text/shaping.cpp | 8 +- src/mbgl/tile/geometry_tile.cpp | 3 +- src/mbgl/tile/geometry_tile_worker.cpp | 8 +- src/mbgl/tile/geometry_tile_worker.hpp | 4 +- test/gl/bucket.test.cpp | 6 +- test/sprite/sprite_atlas.test.cpp | 87 +++----- test/text/quads.test.cpp | 220 ++++++++++----------- 23 files changed, 272 insertions(+), 261 deletions(-) diff --git a/mapbox-gl-js b/mapbox-gl-js index 4a85df6853..ca1e1cf149 160000 --- a/mapbox-gl-js +++ b/mapbox-gl-js @@ -1 +1 @@ -Subproject commit 4a85df68533ae8fbf644f9f60df77eea344cd1c1 +Subproject commit ca1e1cf149c66508761009cfc547c10c8ab539d5 diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index bd9dbbc607..b1cfc113fb 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -48,6 +48,7 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, overscaling(parameters.tileID.overscaleFactor()), zoom(parameters.tileID.overscaledZ), mode(parameters.mode), + pixelRatio(parameters.pixelRatio), tileSize(util::tileSize * overscaling), tilePixelRatio(float(util::EXTENT) / tileSize), textSize(layers.at(0)->as()->impl().layout.get()), @@ -270,7 +271,7 @@ void SymbolLayout::prepare(const GlyphPositionMap& glyphs, const IconMap& icons) if (image->second.sdf) { sdfIcons = true; } - if (image->second.relativePixelRatio != 1.0f) { + if (image->second.pixelRatio != pixelRatio) { iconsNeedLinear = true; } else if (layout.get().constantOr(1) != 0) { iconsNeedLinear = true; diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index 7bdcf52f91..770820542d 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -78,6 +78,7 @@ private: const float overscaling; const float zoom; const MapMode mode; + const float pixelRatio; style::SymbolLayoutProperties::PossiblyEvaluated layout; diff --git a/src/mbgl/programs/fill_extrusion_program.cpp b/src/mbgl/programs/fill_extrusion_program.cpp index 1b0f483b1a..3f85d83788 100644 --- a/src/mbgl/programs/fill_extrusion_program.cpp +++ b/src/mbgl/programs/fill_extrusion_program.cpp @@ -59,12 +59,12 @@ FillExtrusionPatternUniforms::values(mat4 matrix, return FillExtrusionPatternUniforms::Values{ uniforms::u_matrix::Value{ matrix }, - uniforms::u_pattern_tl_a::Value{ a.tl }, - uniforms::u_pattern_br_a::Value{ a.br }, - uniforms::u_pattern_tl_b::Value{ b.tl }, - uniforms::u_pattern_br_b::Value{ b.br }, - uniforms::u_pattern_size_a::Value{ a.size }, - uniforms::u_pattern_size_b::Value{ b.size }, + uniforms::u_pattern_tl_a::Value{ a.tl() }, + uniforms::u_pattern_br_a::Value{ a.br() }, + uniforms::u_pattern_tl_b::Value{ b.tl() }, + uniforms::u_pattern_br_b::Value{ b.br() }, + uniforms::u_pattern_size_a::Value{ a.displaySize() }, + uniforms::u_pattern_size_b::Value{ b.displaySize() }, uniforms::u_scale_a::Value{ fading.fromScale }, uniforms::u_scale_b::Value{ fading.toScale }, uniforms::u_texsize::Value{ atlasSize }, diff --git a/src/mbgl/programs/fill_program.cpp b/src/mbgl/programs/fill_program.cpp index 13f7b00e35..6c19e503ce 100644 --- a/src/mbgl/programs/fill_program.cpp +++ b/src/mbgl/programs/fill_program.cpp @@ -28,12 +28,12 @@ FillPatternUniforms::values(mat4 matrix, uniforms::u_matrix::Value{ matrix }, uniforms::u_world::Value{ framebufferSize }, uniforms::u_texsize::Value{ atlasSize }, - uniforms::u_pattern_tl_a::Value{ a.tl }, - uniforms::u_pattern_br_a::Value{ a.br }, - uniforms::u_pattern_tl_b::Value{ b.tl }, - uniforms::u_pattern_br_b::Value{ b.br }, - uniforms::u_pattern_size_a::Value{ a.size }, - uniforms::u_pattern_size_b::Value{ b.size }, + uniforms::u_pattern_tl_a::Value{ a.tl() }, + uniforms::u_pattern_br_a::Value{ a.br() }, + uniforms::u_pattern_tl_b::Value{ b.tl() }, + uniforms::u_pattern_br_b::Value{ b.br() }, + uniforms::u_pattern_size_a::Value{ a.displaySize() }, + uniforms::u_pattern_size_b::Value{ b.displaySize() }, uniforms::u_scale_a::Value{ fading.fromScale }, uniforms::u_scale_b::Value{ fading.toScale }, uniforms::u_mix::Value{ fading.t }, diff --git a/src/mbgl/programs/line_program.cpp b/src/mbgl/programs/line_program.cpp index 1e296963f2..2c65cb74ed 100644 --- a/src/mbgl/programs/line_program.cpp +++ b/src/mbgl/programs/line_program.cpp @@ -92,13 +92,13 @@ LinePatternProgram::uniformValues(const LinePaintProperties::PossiblyEvaluated& const SpriteAtlasElement& posA, const SpriteAtlasElement& posB) { std::array sizeA {{ - tile.id.pixelsToTileUnits(posA.size[0] * properties.get().fromScale, state.getIntegerZoom()), - posA.size[1] + tile.id.pixelsToTileUnits(posA.displaySize()[0] * properties.get().fromScale, state.getIntegerZoom()), + posA.displaySize()[1] }}; std::array sizeB {{ - tile.id.pixelsToTileUnits(posB.size[0] * properties.get().toScale, state.getIntegerZoom()), - posB.size[1] + tile.id.pixelsToTileUnits(posB.displaySize()[0] * properties.get().toScale, state.getIntegerZoom()), + posB.displaySize()[1] }}; return makeValues( @@ -106,10 +106,10 @@ LinePatternProgram::uniformValues(const LinePaintProperties::PossiblyEvaluated& tile, state, pixelsToGLUnits, - uniforms::u_pattern_tl_a::Value{ posA.tl }, - uniforms::u_pattern_br_a::Value{ posA.br }, - uniforms::u_pattern_tl_b::Value{ posB.tl }, - uniforms::u_pattern_br_b::Value{ posB.br }, + uniforms::u_pattern_tl_a::Value{ posA.tl() }, + uniforms::u_pattern_br_a::Value{ posA.br() }, + uniforms::u_pattern_tl_b::Value{ posB.tl() }, + uniforms::u_pattern_br_b::Value{ posB.br() }, uniforms::u_pattern_size_a::Value{ sizeA }, uniforms::u_pattern_size_b::Value{ sizeB }, uniforms::u_texsize::Value{ atlasSize }, diff --git a/src/mbgl/programs/uniforms.hpp b/src/mbgl/programs/uniforms.hpp index a2bfe396b1..78ac09942c 100644 --- a/src/mbgl/programs/uniforms.hpp +++ b/src/mbgl/programs/uniforms.hpp @@ -22,10 +22,10 @@ MBGL_DEFINE_UNIFORM_SCALAR(Size, u_texsize); MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_extrude_scale); -MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_tl_a); -MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_br_a); -MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_tl_b); -MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_br_b); +MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 2, u_pattern_tl_a); +MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 2, u_pattern_br_a); +MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 2, u_pattern_tl_b); +MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 2, u_pattern_br_b); MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_size_a); MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_size_b); MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pixel_coord_upper); diff --git a/src/mbgl/renderer/bucket_parameters.hpp b/src/mbgl/renderer/bucket_parameters.hpp index 1774ba2bbe..50ec4cf521 100644 --- a/src/mbgl/renderer/bucket_parameters.hpp +++ b/src/mbgl/renderer/bucket_parameters.hpp @@ -9,6 +9,7 @@ class BucketParameters { public: const OverscaledTileID tileID; const MapMode mode; + const float pixelRatio; }; } // namespace mbgl diff --git a/src/mbgl/renderer/painters/painter_background.cpp b/src/mbgl/renderer/painters/painter_background.cpp index 9c6df06094..9cbc3d516c 100644 --- a/src/mbgl/renderer/painters/painter_background.cpp +++ b/src/mbgl/renderer/painters/painter_background.cpp @@ -42,7 +42,7 @@ void Painter::renderBackground(PaintParameters& parameters, const RenderBackgrou FillPatternUniforms::values( matrixForTile(tileID), context.viewport.getCurrentValue().size, - spriteAtlas->getSize(), + spriteAtlas->getPixelSize(), *imagePosA, *imagePosB, background.get(), diff --git a/src/mbgl/renderer/painters/painter_fill.cpp b/src/mbgl/renderer/painters/painter_fill.cpp index e34b4107a9..d15a871d98 100644 --- a/src/mbgl/renderer/painters/painter_fill.cpp +++ b/src/mbgl/renderer/painters/painter_fill.cpp @@ -49,7 +49,7 @@ void Painter::renderFill(PaintParameters& parameters, properties.get(), state), context.viewport.getCurrentValue().size, - spriteAtlas->getSize(), + spriteAtlas->getPixelSize(), *imagePosA, *imagePosB, properties.get(), diff --git a/src/mbgl/renderer/painters/painter_fill_extrusion.cpp b/src/mbgl/renderer/painters/painter_fill_extrusion.cpp index c7aede3aa6..c28cb76bff 100644 --- a/src/mbgl/renderer/painters/painter_fill_extrusion.cpp +++ b/src/mbgl/renderer/painters/painter_fill_extrusion.cpp @@ -46,7 +46,7 @@ void Painter::renderFillExtrusion(PaintParameters& parameters, tile.translatedClipMatrix(properties.get(), properties.get(), state), - spriteAtlas->getSize(), + spriteAtlas->getPixelSize(), *imagePosA, *imagePosB, properties.get(), diff --git a/src/mbgl/renderer/painters/painter_line.cpp b/src/mbgl/renderer/painters/painter_line.cpp index df627a76aa..40076726af 100644 --- a/src/mbgl/renderer/painters/painter_line.cpp +++ b/src/mbgl/renderer/painters/painter_line.cpp @@ -75,7 +75,7 @@ void Painter::renderLine(PaintParameters& parameters, tile, state, pixelsToGLUnits, - spriteAtlas->getSize(), + spriteAtlas->getPixelSize(), *posA, *posB)); diff --git a/src/mbgl/renderer/painters/painter_symbol.cpp b/src/mbgl/renderer/painters/painter_symbol.cpp index 45094777c6..a89e7db28d 100644 --- a/src/mbgl/renderer/painters/painter_symbol.cpp +++ b/src/mbgl/renderer/painters/painter_symbol.cpp @@ -68,13 +68,11 @@ void Painter::renderSymbol(PaintParameters& parameters, auto paintPropertyValues = layer.iconPaintProperties(); SpriteAtlas& atlas = *bucket.spriteAtlas; - const bool iconScaled = layout.get().constantOr(1.0) != 1.0 || - frame.pixelRatio != atlas.getPixelRatio() || - bucket.iconsNeedLinear; + const bool iconScaled = layout.get().constantOr(1.0) != 1.0 || bucket.iconsNeedLinear; const bool iconTransformed = values.rotationAlignment == AlignmentType::Map || state.getPitch() != 0; atlas.bind(bucket.sdfIcons || state.isChanging() || iconScaled || iconTransformed, context, 0); - const Size texsize = atlas.getSize(); + const Size texsize = atlas.getPixelSize(); if (bucket.sdfIcons) { if (values.hasHalo) { diff --git a/src/mbgl/sprite/sprite_atlas.cpp b/src/mbgl/sprite/sprite_atlas.cpp index bcf35050ab..57a5488105 100644 --- a/src/mbgl/sprite/sprite_atlas.cpp +++ b/src/mbgl/sprite/sprite_atlas.cpp @@ -14,28 +14,27 @@ namespace mbgl { -static constexpr uint32_t padding = 1; - -SpriteAtlasElement::SpriteAtlasElement(Rect rect_, - const style::Image::Impl& image, - float pixelRatio) - : pos(std::move(rect_)), - sdf(image.sdf), - relativePixelRatio(image.pixelRatio / pixelRatio), - size{{image.image.size.width / image.pixelRatio, - image.image.size.height / image.pixelRatio}} { - - const float w = image.image.size.width / pixelRatio; - const float h = image.image.size.height / pixelRatio; - - tl = {{ float(pos.x + padding), float(pos.y + padding) }}; - br = {{ float(pos.x + padding + w), float(pos.y + padding + h) }}; -} - -SpriteAtlas::SpriteAtlas(Size size_, float pixelRatio_) - : size(std::move(size_)), - pixelRatio(pixelRatio_), - bin(size.width, size.height), +// When copied into the atlas texture, image data is padded by one pixel on each side. Icon +// images are padded with fully transparent pixels, while pattern images are padded with a +// copy of the image data wrapped from the opposite side. In both cases, this ensures the +// correct behavior of GL_LINEAR texture sampling mode. +static constexpr uint16_t padding = 1; + +SpriteAtlasElement::SpriteAtlasElement(Rect rect, const style::Image::Impl& image) + : sdf(image.sdf), + pixelRatio(image.pixelRatio), + textureRect( + rect.x + padding, + rect.y + padding, + rect.w - padding * 2, + rect.h - padding * 2 + ) { +} + +SpriteAtlas::SpriteAtlas(Size size, float pixelRatio) + : pixelSize(std::ceil(size.width * pixelRatio), + std::ceil(size.height * pixelRatio)), + bin(pixelSize.width, pixelSize.height), dirty(true) { } @@ -141,13 +140,12 @@ optional SpriteAtlas::getImage(const std::string& id, assert(entry.image.get()); return SpriteAtlasElement { *(entry.*entryRect), - *entry.image, - pixelRatio + *entry.image }; } - const uint16_t width = std::ceil(entry.image->image.size.width / pixelRatio) + 2 * padding; - const uint16_t height = std::ceil(entry.image->image.size.height / pixelRatio) + 2 * padding; + const uint16_t width = entry.image->image.size.width + padding * 2; + const uint16_t height = entry.image->image.size.height + padding * 2; Rect rect = bin.allocate(width, height); if (rect.w == 0) { @@ -162,23 +160,25 @@ optional SpriteAtlas::getImage(const std::string& id, return SpriteAtlasElement { rect, - *entry.image, - pixelRatio + *entry.image }; } +Size SpriteAtlas::getPixelSize() const { + return pixelSize; +} + void SpriteAtlas::copy(const Entry& entry, optional> Entry::*entryRect) { if (!image.valid()) { - image = PremultipliedImage({ static_cast(std::ceil(size.width * pixelRatio)), - static_cast(std::ceil(size.height * pixelRatio)) }); + image = PremultipliedImage(getPixelSize()); image.fill(0); } const PremultipliedImage& src = entry.image->image; const Rect& rect = *(entry.*entryRect); - const uint32_t x = (rect.x + padding) * pixelRatio; - const uint32_t y = (rect.y + padding) * pixelRatio; + const uint32_t x = rect.x + padding; + const uint32_t y = rect.y + padding; const uint32_t w = src.size.width; const uint32_t h = src.size.height; diff --git a/src/mbgl/sprite/sprite_atlas.hpp b/src/mbgl/sprite/sprite_atlas.hpp index 52749d389b..3629ed6eb1 100644 --- a/src/mbgl/sprite/sprite_atlas.hpp +++ b/src/mbgl/sprite/sprite_atlas.hpp @@ -20,15 +20,32 @@ class Context; class SpriteAtlasElement { public: - SpriteAtlasElement(Rect, const style::Image::Impl&, float pixelRatio); + SpriteAtlasElement(Rect, const style::Image::Impl&); - Rect pos; bool sdf; + float pixelRatio; + Rect textureRect; + + std::array tl() const { + return {{ + textureRect.x, + textureRect.y + }}; + } + + std::array br() const { + return {{ + static_cast(textureRect.x + textureRect.w), + static_cast(textureRect.y + textureRect.h) + }}; + } - float relativePixelRatio; - std::array size; - std::array tl; - std::array br; + std::array displaySize() const { + return {{ + textureRect.w / pixelRatio, + textureRect.h / pixelRatio, + }}; + } }; using IconMap = std::unordered_map; @@ -64,7 +81,14 @@ public: void getIcons(IconRequestor& requestor); void removeRequestor(IconRequestor& requestor); + // Ensure that the atlas contains the named image suitable for rendering as an icon, and + // return its metrics. The image will be padded on each side with a one pixel wide transparent + // strip, but the returned metrics are exclusive of this padding. optional getIcon(const std::string& name); + + // Ensure that the atlas contains the named image suitable for rendering as an pattern, and + // return its metrics. The image will be padded on each side with a one pixel wide copy of + // pixels from the opposite side, but the returned metrics are exclusive of this padding. optional getPattern(const std::string& name); // Binds the atlas texture to the GPU, and uploads data if it is out of date. @@ -74,8 +98,7 @@ public: // the texture is only bound when the data is out of date (=dirty). void upload(gl::Context&, gl::TextureUnit unit); - Size getSize() const { return size; } - float getPixelRatio() const { return pixelRatio; } + Size getPixelSize() const; // Only for use in tests. const PremultipliedImage& getAtlasImage() const { @@ -83,8 +106,7 @@ public: } private: - const Size size; - const float pixelRatio; + const Size pixelSize; bool loaded = false; struct Entry { diff --git a/src/mbgl/text/quads.cpp b/src/mbgl/text/quads.cpp index dc48634fb0..33b94d7114 100644 --- a/src/mbgl/text/quads.cpp +++ b/src/mbgl/text/quads.cpp @@ -24,11 +24,15 @@ SymbolQuad getIconQuad(const Anchor& anchor, const Shaping& shapedText) { const SpriteAtlasElement& image = shapedIcon.image(); + // If you have a 10px icon that isn't perfectly aligned to the pixel grid it will cover 11 actual + // pixels. The quad needs to be padded to account for this, otherwise they'll look slightly clipped + // on one edge in some cases. const float border = 1.0; - auto left = shapedIcon.left() - border; - auto right = left + image.pos.w / image.relativePixelRatio; - auto top = shapedIcon.top() - border; - auto bottom = top + image.pos.h / image.relativePixelRatio; + + float top = shapedIcon.top() - border / image.pixelRatio; + float left = shapedIcon.left() - border / image.pixelRatio; + float bottom = shapedIcon.bottom() + border / image.pixelRatio; + float right = shapedIcon.right() + border / image.pixelRatio; Point tl; Point tr; Point br; @@ -92,7 +96,15 @@ SymbolQuad getIconQuad(const Anchor& anchor, br = util::matrixMultiply(matrix, br); } - return SymbolQuad { tl, tr, bl, br, image.pos, 0, 0, anchor.point, globalMinScale, std::numeric_limits::infinity(), shapedText.writingMode }; + // Icon quad is padded, so texture coordinates also need to be padded. + Rect textureRect { + static_cast(image.textureRect.x - border), + static_cast(image.textureRect.y - border), + static_cast(image.textureRect.w + border * 2), + static_cast(image.textureRect.h + border * 2) + }; + + return SymbolQuad { tl, tr, bl, br, textureRect, 0, 0, anchor.point, globalMinScale, std::numeric_limits::infinity(), shapedText.writingMode }; } struct GlyphInstance { diff --git a/src/mbgl/text/shaping.cpp b/src/mbgl/text/shaping.cpp index 6ee646be96..f9f90627d4 100644 --- a/src/mbgl/text/shaping.cpp +++ b/src/mbgl/text/shaping.cpp @@ -13,10 +13,10 @@ namespace mbgl { PositionedIcon PositionedIcon::shapeIcon(const SpriteAtlasElement& image, const std::array& iconOffset, const float iconRotation) { float dx = iconOffset[0]; float dy = iconOffset[1]; - float x1 = dx - image.size[0] / 2.0f; - float x2 = x1 + image.size[0]; - float y1 = dy - image.size[1] / 2.0f; - float y2 = y1 + image.size[1]; + float x1 = dx - image.displaySize()[0] / 2.0f; + float x2 = x1 + image.displaySize()[0]; + float y1 = dy - image.displaySize()[1] / 2.0f; + float y2 = y1 + image.displaySize()[1]; return PositionedIcon { image, y1, y2, x1, x2, iconRotation }; } diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp index 8f14a9c8aa..e3c4e7bf3b 100644 --- a/src/mbgl/tile/geometry_tile.cpp +++ b/src/mbgl/tile/geometry_tile.cpp @@ -40,7 +40,8 @@ GeometryTile::GeometryTile(const OverscaledTileID& id_, ActorRef(*this, mailbox), id_, obsolete, - parameters.mode), + parameters.mode, + parameters.pixelRatio), glyphAtlas(glyphAtlas_), spriteAtlas(spriteAtlas_), placementThrottler(Milliseconds(300), [this] { invokePlacement(); }) { diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp index 1d683b3a11..3fd6bb47f0 100644 --- a/src/mbgl/tile/geometry_tile_worker.cpp +++ b/src/mbgl/tile/geometry_tile_worker.cpp @@ -26,12 +26,14 @@ GeometryTileWorker::GeometryTileWorker(ActorRef self_, ActorRef parent_, OverscaledTileID id_, const std::atomic& obsolete_, - const MapMode mode_) + const MapMode mode_, + const float pixelRatio_) : self(std::move(self_)), parent(std::move(parent_)), id(std::move(id_)), obsolete(obsolete_), - mode(mode_) { + mode(mode_), + pixelRatio(pixelRatio_) { } GeometryTileWorker::~GeometryTileWorker() = default; @@ -275,7 +277,7 @@ void GeometryTileWorker::redoLayout() { std::unordered_map> symbolLayoutMap; std::unordered_map> buckets; auto featureIndex = std::make_unique(); - BucketParameters parameters { id, mode }; + BucketParameters parameters { id, mode, pixelRatio }; GlyphDependencies glyphDependencies; IconDependencies iconDependencies; diff --git a/src/mbgl/tile/geometry_tile_worker.hpp b/src/mbgl/tile/geometry_tile_worker.hpp index 0d4cba04b3..3a15763a82 100644 --- a/src/mbgl/tile/geometry_tile_worker.hpp +++ b/src/mbgl/tile/geometry_tile_worker.hpp @@ -31,7 +31,8 @@ public: ActorRef parent, OverscaledTileID, const std::atomic&, - const MapMode); + const MapMode, + const float pixelRatio); ~GeometryTileWorker(); void setLayers(std::vector>, uint64_t correlationID); @@ -61,6 +62,7 @@ private: const OverscaledTileID id; const std::atomic& obsolete; const MapMode mode; + const float pixelRatio; enum State { Idle, diff --git a/test/gl/bucket.test.cpp b/test/gl/bucket.test.cpp index e0ca635ddf..b291816562 100644 --- a/test/gl/bucket.test.cpp +++ b/test/gl/bucket.test.cpp @@ -12,17 +12,17 @@ using namespace mbgl; TEST(Buckets, CircleBucket) { - CircleBucket bucket { { {0, 0, 0}, MapMode::Still }, {} }; + CircleBucket bucket { { {0, 0, 0}, MapMode::Still, 1.0 }, {} }; ASSERT_FALSE(bucket.hasData()); } TEST(Buckets, FillBucket) { - FillBucket bucket { { {0, 0, 0}, MapMode::Still }, {} }; + FillBucket bucket { { {0, 0, 0}, MapMode::Still, 1.0 }, {} }; ASSERT_FALSE(bucket.hasData()); } TEST(Buckets, LineBucket) { - LineBucket bucket { { {0, 0, 0}, MapMode::Still }, {}, {} }; + LineBucket bucket { { {0, 0, 0}, MapMode::Still, 1.0 }, {}, {} }; ASSERT_FALSE(bucket.hasData()); } diff --git a/test/sprite/sprite_atlas.test.cpp b/test/sprite/sprite_atlas.test.cpp index f6953e61f7..c673c5ca0e 100644 --- a/test/sprite/sprite_atlas.test.cpp +++ b/test/sprite/sprite_atlas.test.cpp @@ -26,34 +26,21 @@ TEST(SpriteAtlas, Basic) { atlas.addImage(image->impl); } - EXPECT_EQ(1.0f, atlas.getPixelRatio()); - EXPECT_EQ(63u, atlas.getSize().width); - EXPECT_EQ(112u, atlas.getSize().height); + EXPECT_EQ(63u, atlas.getPixelSize().width); + EXPECT_EQ(112u, atlas.getPixelSize().height); auto metro = *atlas.getIcon("metro"); - float imagePixelRatio = metro.relativePixelRatio * atlas.getPixelRatio(); - EXPECT_EQ(0, metro.pos.x); - EXPECT_EQ(0, metro.pos.y); - EXPECT_EQ(20, metro.pos.w); - EXPECT_EQ(20, metro.pos.h); - EXPECT_EQ(18, metro.size[0]); - EXPECT_EQ(18, metro.size[1]); - EXPECT_EQ(18u, metro.size[0] * imagePixelRatio); - EXPECT_EQ(18u, metro.size[1] * imagePixelRatio); - EXPECT_EQ(1.0f, imagePixelRatio); - + EXPECT_EQ(1, metro.tl()[0]); + EXPECT_EQ(1, metro.tl()[1]); + EXPECT_EQ(19, metro.br()[0]); + EXPECT_EQ(19, metro.br()[1]); + EXPECT_EQ(18, metro.displaySize()[0]); + EXPECT_EQ(18, metro.displaySize()[1]); + EXPECT_EQ(1.0f, metro.pixelRatio); EXPECT_EQ(63u, atlas.getAtlasImage().size.width); EXPECT_EQ(112u, atlas.getAtlasImage().size.height); - auto pos = *atlas.getIcon("metro"); - EXPECT_DOUBLE_EQ(18, pos.size[0]); - EXPECT_DOUBLE_EQ(18, pos.size[1]); - EXPECT_DOUBLE_EQ(1.0f / 63, pos.tl[0]); - EXPECT_DOUBLE_EQ(1.0f / 112, pos.tl[1]); - EXPECT_DOUBLE_EQ(19.0f / 63, pos.br[0]); - EXPECT_DOUBLE_EQ(19.0f / 112, pos.br[1]); - auto missing = atlas.getIcon("doesnotexist"); EXPECT_FALSE(missing); @@ -66,10 +53,10 @@ TEST(SpriteAtlas, Basic) { // Different wrapping mode produces different image. auto metro2 = *atlas.getPattern("metro"); - EXPECT_EQ(20, metro2.pos.x); - EXPECT_EQ(0, metro2.pos.y); - EXPECT_EQ(20, metro2.pos.w); - EXPECT_EQ(20, metro2.pos.h); + EXPECT_EQ(21, metro2.tl()[0]); + EXPECT_EQ(1, metro2.tl()[1]); + EXPECT_EQ(39, metro2.br()[0]); + EXPECT_EQ(19, metro2.br()[1]); test::checkImage("test/fixtures/sprite_atlas/basic", atlas.getAtlasImage()); } @@ -83,25 +70,17 @@ TEST(SpriteAtlas, Size) { atlas.addImage(image->impl); } - EXPECT_DOUBLE_EQ(1.4f, atlas.getPixelRatio()); - EXPECT_EQ(63u, atlas.getSize().width); - EXPECT_EQ(112u, atlas.getSize().height); + EXPECT_EQ(89u, atlas.getPixelSize().width); + EXPECT_EQ(157u, atlas.getPixelSize().height); auto metro = *atlas.getIcon("metro"); - float imagePixelRatio = metro.relativePixelRatio * atlas.getPixelRatio(); - EXPECT_EQ(0, metro.pos.x); - EXPECT_EQ(0, metro.pos.y); - EXPECT_EQ(15, metro.pos.w); - EXPECT_EQ(15, metro.pos.h); - EXPECT_EQ(18, metro.size[0]); - EXPECT_EQ(18, metro.size[1]); - EXPECT_EQ(18u, metro.size[0] * imagePixelRatio); - EXPECT_EQ(18u, metro.size[1] * imagePixelRatio); - EXPECT_EQ(1.0f, imagePixelRatio); - - // Now the image was created lazily. - EXPECT_EQ(89u, atlas.getAtlasImage().size.width); - EXPECT_EQ(157u, atlas.getAtlasImage().size.height); + EXPECT_EQ(1, metro.tl()[0]); + EXPECT_EQ(1, metro.tl()[1]); + EXPECT_EQ(19, metro.br()[0]); + EXPECT_EQ(19, metro.br()[1]); + EXPECT_EQ(18, metro.displaySize()[0]); + EXPECT_EQ(18, metro.displaySize()[1]); + EXPECT_EQ(1.0f, metro.pixelRatio); test::checkImage("test/fixtures/sprite_atlas/size", atlas.getAtlasImage()); } @@ -109,22 +88,18 @@ TEST(SpriteAtlas, Size) { TEST(SpriteAtlas, Updates) { SpriteAtlas atlas({ 32, 32 }, 1); - EXPECT_EQ(1.0f, atlas.getPixelRatio()); - EXPECT_EQ(32u, atlas.getSize().width); - EXPECT_EQ(32u, atlas.getSize().height); + EXPECT_EQ(32u, atlas.getPixelSize().width); + EXPECT_EQ(32u, atlas.getPixelSize().height); atlas.addImage(makeMutable("one", PremultipliedImage({ 16, 12 }), 1)); auto one = *atlas.getIcon("one"); - float imagePixelRatio = one.relativePixelRatio * atlas.getPixelRatio(); - EXPECT_EQ(0, one.pos.x); - EXPECT_EQ(0, one.pos.y); - EXPECT_EQ(18, one.pos.w); - EXPECT_EQ(14, one.pos.h); - EXPECT_EQ(16, one.size[0]); - EXPECT_EQ(12, one.size[1]); - EXPECT_EQ(16u, one.size[0] * imagePixelRatio); - EXPECT_EQ(12u, one.size[1] * imagePixelRatio); - EXPECT_EQ(1.0f, imagePixelRatio); + EXPECT_EQ(1, one.tl()[0]); + EXPECT_EQ(1, one.tl()[1]); + EXPECT_EQ(17, one.br()[0]); + EXPECT_EQ(13, one.br()[1]); + EXPECT_EQ(16, one.displaySize()[0]); + EXPECT_EQ(12, one.displaySize()[1]); + EXPECT_EQ(1.0f, one.pixelRatio); // Now the image was created lazily. EXPECT_EQ(32u, atlas.getAtlasImage().size.width); diff --git a/test/text/quads.test.cpp b/test/text/quads.test.cpp index 1f2e24ca5e..4c40b41a97 100644 --- a/test/text/quads.test.cpp +++ b/test/text/quads.test.cpp @@ -14,9 +14,7 @@ TEST(getIconQuads, normal) { Anchor anchor(2.0, 3.0, 0.0, 0.5f, 0); SpriteAtlasElement image = { Rect( 0, 0, 15, 11 ), - style::Image::Impl("test", PremultipliedImage({1,1}), 1.0), - { 0, 0 }, - 1.0f + style::Image::Impl("test", PremultipliedImage({1,1}), 1.0) }; auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -6.5f, -4.5f }}, 0); @@ -27,28 +25,26 @@ TEST(getIconQuads, normal) { SymbolQuad quad = getIconQuad(anchor, shapedIcon, line, layout, 16.0f, SymbolPlacementType::Point, shapedText); - ASSERT_EQ(quad.anchorPoint.x, 2); - ASSERT_EQ(quad.anchorPoint.y, 3); - ASSERT_EQ(quad.tl.x, -8); - ASSERT_EQ(quad.tl.y, -6); - ASSERT_EQ(quad.tr.x, 7); - ASSERT_EQ(quad.tr.y, -6); - ASSERT_EQ(quad.bl.x, -8); - ASSERT_EQ(quad.bl.y, 5); - ASSERT_EQ(quad.br.x, 7); - ASSERT_EQ(quad.br.y, 5); - ASSERT_EQ(quad.anchorAngle, 0.0f); - ASSERT_EQ(quad.glyphAngle, 0.0f); - ASSERT_EQ(quad.minScale, 0.5f); + EXPECT_EQ(quad.anchorPoint.x, 2); + EXPECT_EQ(quad.anchorPoint.y, 3); + EXPECT_EQ(quad.tl.x, -14); + EXPECT_EQ(quad.tl.y, -10); + EXPECT_EQ(quad.tr.x, 1); + EXPECT_EQ(quad.tr.y, -10); + EXPECT_EQ(quad.bl.x, -14); + EXPECT_EQ(quad.bl.y, 1); + EXPECT_EQ(quad.br.x, 1); + EXPECT_EQ(quad.br.y, 1); + EXPECT_EQ(quad.anchorAngle, 0.0f); + EXPECT_EQ(quad.glyphAngle, 0.0f); + EXPECT_EQ(quad.minScale, 0.5f); } TEST(getIconQuads, style) { Anchor anchor(0.0, 0.0, 0.0, 0.5f, 0); SpriteAtlasElement image = { Rect( 0, 0, 20, 20 ), - style::Image::Impl("test", PremultipliedImage({1,1}), 1.0), - { 0, 0 }, - 1.0f + style::Image::Impl("test", PremultipliedImage({1,1}), 1.0) }; auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, 0); @@ -67,19 +63,19 @@ TEST(getIconQuads, style) { SymbolQuad quad = getIconQuad(anchor, shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, shapedText); - ASSERT_EQ(quad.anchorPoint.x, 0); - ASSERT_EQ(quad.anchorPoint.y, 0); - ASSERT_EQ(quad.tl.x, -11); - ASSERT_EQ(quad.tl.y, -11); - ASSERT_EQ(quad.tr.x, 9); - ASSERT_EQ(quad.tr.y, -11); - ASSERT_EQ(quad.bl.x, -11); - ASSERT_EQ(quad.bl.y, 9); - ASSERT_EQ(quad.br.x, 9); - ASSERT_EQ(quad.br.y, 9); - ASSERT_EQ(quad.anchorAngle, 0.0f); - ASSERT_EQ(quad.glyphAngle, 0.0f); - ASSERT_EQ(quad.minScale, 0.5f); + EXPECT_EQ(quad.anchorPoint.x, 0); + EXPECT_EQ(quad.anchorPoint.y, 0); + EXPECT_EQ(quad.tl.x, -19.5); + EXPECT_EQ(quad.tl.y, -19.5); + EXPECT_EQ(quad.tr.x, 0.5); + EXPECT_EQ(quad.tr.y, -19.5); + EXPECT_EQ(quad.bl.x, -19.5); + EXPECT_EQ(quad.bl.y, 0.5); + EXPECT_EQ(quad.br.x, 0.5); + EXPECT_EQ(quad.br.y, 0.5); + EXPECT_EQ(quad.anchorAngle, 0.0f); + EXPECT_EQ(quad.glyphAngle, 0.0f); + EXPECT_EQ(quad.minScale, 0.5f); } // width @@ -90,14 +86,14 @@ TEST(getIconQuads, style) { SymbolQuad quad = getIconQuad(anchor, shapedIcon, line, layout, 24.0f, SymbolPlacementType::Point, shapedText); - ASSERT_EQ(quad.tl.x, -60); - ASSERT_EQ(quad.tl.y, 0); - ASSERT_EQ(quad.tr.x, 20); - ASSERT_EQ(quad.tr.y, 0); - ASSERT_EQ(quad.bl.x, -60); - ASSERT_EQ(quad.bl.y, 20); - ASSERT_EQ(quad.br.x, 20); - ASSERT_EQ(quad.br.y, 20); + EXPECT_EQ(quad.tl.x, -60); + EXPECT_EQ(quad.tl.y, 0); + EXPECT_EQ(quad.tr.x, 20); + EXPECT_EQ(quad.tr.y, 0); + EXPECT_EQ(quad.bl.x, -60); + EXPECT_EQ(quad.bl.y, 20); + EXPECT_EQ(quad.br.x, 20); + EXPECT_EQ(quad.br.y, 20); } // width x textSize @@ -108,14 +104,14 @@ TEST(getIconQuads, style) { SymbolQuad quad = getIconQuad(anchor, shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, shapedText); - ASSERT_EQ(quad.tl.x, -30); - ASSERT_EQ(quad.tl.y, -5); - ASSERT_EQ(quad.tr.x, 10); - ASSERT_EQ(quad.tr.y, -5); - ASSERT_EQ(quad.bl.x, -30); - ASSERT_EQ(quad.bl.y, 15); - ASSERT_EQ(quad.br.x, 10); - ASSERT_EQ(quad.br.y, 15); + EXPECT_EQ(quad.tl.x, -30); + EXPECT_EQ(quad.tl.y, -5); + EXPECT_EQ(quad.tr.x, 10); + EXPECT_EQ(quad.tr.y, -5); + EXPECT_EQ(quad.bl.x, -30); + EXPECT_EQ(quad.bl.y, 15); + EXPECT_EQ(quad.br.x, 10); + EXPECT_EQ(quad.br.y, 15); } // width x textSize + padding @@ -130,14 +126,14 @@ TEST(getIconQuads, style) { SymbolQuad quad = getIconQuad(anchor, shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, shapedText); - ASSERT_EQ(quad.tl.x, -40); - ASSERT_EQ(quad.tl.y, -10); - ASSERT_EQ(quad.tr.x, 20); - ASSERT_EQ(quad.tr.y, -10); - ASSERT_EQ(quad.bl.x, -40); - ASSERT_EQ(quad.bl.y, 20); - ASSERT_EQ(quad.br.x, 20); - ASSERT_EQ(quad.br.y, 20); + EXPECT_EQ(quad.tl.x, -40); + EXPECT_EQ(quad.tl.y, -10); + EXPECT_EQ(quad.tr.x, 20); + EXPECT_EQ(quad.tr.y, -10); + EXPECT_EQ(quad.bl.x, -40); + EXPECT_EQ(quad.bl.y, 20); + EXPECT_EQ(quad.br.x, 20); + EXPECT_EQ(quad.br.y, 20); } // height @@ -148,14 +144,14 @@ TEST(getIconQuads, style) { SymbolQuad quad = getIconQuad(anchor, shapedIcon, line, layout, 24.0f, SymbolPlacementType::Point, shapedText); - ASSERT_EQ(quad.tl.x, -30); - ASSERT_EQ(quad.tl.y, -10); - ASSERT_EQ(quad.tr.x, -10); - ASSERT_EQ(quad.tr.y, -10); - ASSERT_EQ(quad.bl.x, -30); - ASSERT_EQ(quad.bl.y, 30); - ASSERT_EQ(quad.br.x, -10); - ASSERT_EQ(quad.br.y, 30); + EXPECT_EQ(quad.tl.x, -30); + EXPECT_EQ(quad.tl.y, -10); + EXPECT_EQ(quad.tr.x, -10); + EXPECT_EQ(quad.tr.y, -10); + EXPECT_EQ(quad.bl.x, -30); + EXPECT_EQ(quad.bl.y, 30); + EXPECT_EQ(quad.br.x, -10); + EXPECT_EQ(quad.br.y, 30); } // height x textSize @@ -166,14 +162,14 @@ TEST(getIconQuads, style) { SymbolQuad quad = getIconQuad(anchor, shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, shapedText); - ASSERT_EQ(quad.tl.x, -20); - ASSERT_EQ(quad.tl.y, -5); - ASSERT_EQ(quad.tr.x, 0); - ASSERT_EQ(quad.tr.y, -5); - ASSERT_EQ(quad.bl.x, -20); - ASSERT_EQ(quad.bl.y, 15); - ASSERT_EQ(quad.br.x, 0); - ASSERT_EQ(quad.br.y, 15); + EXPECT_EQ(quad.tl.x, -20); + EXPECT_EQ(quad.tl.y, -5); + EXPECT_EQ(quad.tr.x, 0); + EXPECT_EQ(quad.tr.y, -5); + EXPECT_EQ(quad.bl.x, -20); + EXPECT_EQ(quad.bl.y, 15); + EXPECT_EQ(quad.br.x, 0); + EXPECT_EQ(quad.br.y, 15); } // height x textSize + padding @@ -188,14 +184,14 @@ TEST(getIconQuads, style) { SymbolQuad quad = getIconQuad(anchor, shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, shapedText); - ASSERT_EQ(quad.tl.x, -30); - ASSERT_EQ(quad.tl.y, -10); - ASSERT_EQ(quad.tr.x, 10); - ASSERT_EQ(quad.tr.y, -10); - ASSERT_EQ(quad.bl.x, -30); - ASSERT_EQ(quad.bl.y, 20); - ASSERT_EQ(quad.br.x, 10); - ASSERT_EQ(quad.br.y, 20); + EXPECT_EQ(quad.tl.x, -30); + EXPECT_EQ(quad.tl.y, -10); + EXPECT_EQ(quad.tr.x, 10); + EXPECT_EQ(quad.tr.y, -10); + EXPECT_EQ(quad.bl.x, -30); + EXPECT_EQ(quad.bl.y, 20); + EXPECT_EQ(quad.br.x, 10); + EXPECT_EQ(quad.br.y, 20); } // both @@ -206,14 +202,14 @@ TEST(getIconQuads, style) { SymbolQuad quad = getIconQuad(anchor, shapedIcon, line, layout, 24.0f, SymbolPlacementType::Point, shapedText); - ASSERT_EQ(quad.tl.x, -60); - ASSERT_EQ(quad.tl.y, -10); - ASSERT_EQ(quad.tr.x, 20); - ASSERT_EQ(quad.tr.y, -10); - ASSERT_EQ(quad.bl.x, -60); - ASSERT_EQ(quad.bl.y, 30); - ASSERT_EQ(quad.br.x, 20); - ASSERT_EQ(quad.br.y, 30); + EXPECT_EQ(quad.tl.x, -60); + EXPECT_EQ(quad.tl.y, -10); + EXPECT_EQ(quad.tr.x, 20); + EXPECT_EQ(quad.tr.y, -10); + EXPECT_EQ(quad.bl.x, -60); + EXPECT_EQ(quad.bl.y, 30); + EXPECT_EQ(quad.br.x, 20); + EXPECT_EQ(quad.br.y, 30); } // both x textSize @@ -224,14 +220,14 @@ TEST(getIconQuads, style) { SymbolQuad quad = getIconQuad(anchor, shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, shapedText); - ASSERT_EQ(quad.tl.x, -30); - ASSERT_EQ(quad.tl.y, -5); - ASSERT_EQ(quad.tr.x, 10); - ASSERT_EQ(quad.tr.y, -5); - ASSERT_EQ(quad.bl.x, -30); - ASSERT_EQ(quad.bl.y, 15); - ASSERT_EQ(quad.br.x, 10); - ASSERT_EQ(quad.br.y, 15); + EXPECT_EQ(quad.tl.x, -30); + EXPECT_EQ(quad.tl.y, -5); + EXPECT_EQ(quad.tr.x, 10); + EXPECT_EQ(quad.tr.y, -5); + EXPECT_EQ(quad.bl.x, -30); + EXPECT_EQ(quad.bl.y, 15); + EXPECT_EQ(quad.br.x, 10); + EXPECT_EQ(quad.br.y, 15); } // both x textSize + padding @@ -246,14 +242,14 @@ TEST(getIconQuads, style) { SymbolQuad quad = getIconQuad(anchor, shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, shapedText); - ASSERT_EQ(quad.tl.x, -40); - ASSERT_EQ(quad.tl.y, -10); - ASSERT_EQ(quad.tr.x, 20); - ASSERT_EQ(quad.tr.y, -10); - ASSERT_EQ(quad.bl.x, -40); - ASSERT_EQ(quad.bl.y, 20); - ASSERT_EQ(quad.br.x, 20); - ASSERT_EQ(quad.br.y, 20); + EXPECT_EQ(quad.tl.x, -40); + EXPECT_EQ(quad.tl.y, -10); + EXPECT_EQ(quad.tr.x, 20); + EXPECT_EQ(quad.tr.y, -10); + EXPECT_EQ(quad.bl.x, -40); + EXPECT_EQ(quad.bl.y, 20); + EXPECT_EQ(quad.br.x, 20); + EXPECT_EQ(quad.br.y, 20); } // both x textSize + padding t/r/b/l @@ -268,14 +264,14 @@ TEST(getIconQuads, style) { SymbolQuad quad = getIconQuad(anchor, shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, shapedText); - ASSERT_EQ(quad.tl.x, -45); - ASSERT_EQ(quad.tl.y, -5); - ASSERT_EQ(quad.tr.x, 15); - ASSERT_EQ(quad.tr.y, -5); - ASSERT_EQ(quad.bl.x, -45); - ASSERT_EQ(quad.bl.y, 25); - ASSERT_EQ(quad.br.x, 15); - ASSERT_EQ(quad.br.y, 25); + EXPECT_EQ(quad.tl.x, -45); + EXPECT_EQ(quad.tl.y, -5); + EXPECT_EQ(quad.tr.x, 15); + EXPECT_EQ(quad.tr.y, -5); + EXPECT_EQ(quad.bl.x, -45); + EXPECT_EQ(quad.bl.y, 25); + EXPECT_EQ(quad.br.x, 15); + EXPECT_EQ(quad.br.y, 25); } } -- cgit v1.2.1