port sprite atlas pollution fix

fixes #1398

js: 212760981493460b438f1cc117001825773fad91
https://github.com/mapbox/mapbox-gl-js/pull/1195

The sprite atlas already had two empty pixels between each each icon.
But the icon's real boundary isn't used for drawing. Drawing uses an
icon's box rounded up to the nearest multiple of four. Sometimes this
rounded boundary was directly on the edge of another icon. When the icon
was sampled with linear interpolation it's edge would get polluted with
values from the other icon.

This commit shifts all icons and glyphs by 1px so that there is padding
on all sides of the box being drawn. The quads used for drawing are
shifted in the opposite direction by 1px to compensate for this.
This commit is contained in:
Ansis Brammanis
2015-05-19 09:52:01 -04:00
committed by John Firebaugh
parent d7bd429619
commit 03d5e2da80
3 changed files with 17 additions and 10 deletions

View File

@@ -69,8 +69,9 @@ Rect<uint16_t> GlyphAtlas::addGlyph(uintptr_t tileUID,
uint16_t buffered_height = glyph.metrics.height + buffer * 2;
// Add a 1px border around every image.
uint16_t pack_width = buffered_width;
uint16_t pack_height = buffered_height;
const uint16_t padding = 1;
uint16_t pack_width = buffered_width + 2 * padding;
uint16_t pack_height = buffered_height + 2 * padding;
// Increase to next number divisible by 4, but at least 1.
// This is so we can scale down the texture coordinates and pack them
@@ -92,7 +93,7 @@ Rect<uint16_t> GlyphAtlas::addGlyph(uintptr_t tileUID,
// Copy the bitmap
const uint8_t* source = reinterpret_cast<const uint8_t*>(glyph.bitmap.data());
for (uint32_t y = 0; y < buffered_height; y++) {
uint32_t y1 = width * (rect.y + y) + rect.x;
uint32_t y1 = width * (rect.y + y + padding) + rect.x + padding;
uint32_t y2 = buffered_width * y;
for (uint32_t x = 0; x < buffered_width; x++) {
data[y1 + x] = source[y2 + x];

View File

@@ -127,10 +127,12 @@ SpriteAtlasPosition SpriteAtlas::getPosition(const std::string& name, bool repea
rect.h = pos.height / pos.pixelRatio;
}
const float padding = 1;
return SpriteAtlasPosition {
{{ float(rect.w), float(rect.h) }},
{{ float(rect.x) / width, float(rect.y) / height }},
{{ float(rect.x + rect.w) / width, float(rect.y + rect.h) / height }}
{{ float(rect.x + padding) / width, float(rect.y + padding) / height }},
{{ float(rect.x + padding + rect.w) / width, float(rect.y + padding + rect.h) / height }}
};
}
@@ -151,12 +153,14 @@ void SpriteAtlas::copy(const Rect<dimension>& dst, const SpritePosition& src, co
const vec2<uint32_t> srcSize { sprite->raster->getWidth(), sprite->raster->getHeight() };
const Rect<uint32_t> srcPos { src.x, src.y, src.width, src.height };
const int offset = 1;
allocate();
uint32_t *const dstData = data.get();
const vec2<uint32_t> dstSize { static_cast<unsigned int>(width * pixelRatio),
static_cast<unsigned int>(height * pixelRatio) };
const Rect<uint32_t> dstPos { static_cast<uint32_t>(dst.x * pixelRatio),
static_cast<uint32_t>(dst.y * pixelRatio),
const Rect<uint32_t> dstPos { static_cast<uint32_t>((offset + dst.x) * pixelRatio),
static_cast<uint32_t>((offset + dst.y) * pixelRatio),
static_cast<uint32_t>(dst.originalW * pixelRatio),
static_cast<uint32_t>(dst.originalH * pixelRatio) };

View File

@@ -135,11 +135,12 @@ GlyphBox getMergedBoxes(const GlyphBoxes &glyphs, const Anchor &anchor) {
Placement Placement::getIcon(Anchor &anchor, const Rect<uint16_t> &image, float boxScale,
const std::vector<Coordinate> &line, const StyleLayoutSymbol &layout) {
const float padding = 1.0f;
const float dx = layout.icon.offset[0];
const float dy = layout.icon.offset[1];
float x1 = dx - image.originalW / 2.0f;
float x1 = dx - image.originalW / 2.0f - padding;
float x2 = x1 + image.w;
float y1 = dy - image.originalH / 2.0f;
float y1 = dy - image.originalH / 2.0f - padding;
float y2 = y1 + image.h;
vec2<float> tl{x1, y1};
@@ -212,7 +213,8 @@ Placement Placement::getGlyphs(Anchor &anchor, const vec2<float> &origin, const
Placement placement;
const uint32_t buffer = 3;
const uint32_t glyphPadding = 1;
const uint32_t buffer = 3 + glyphPadding;
for (const auto& shape : shaping) {
auto face_it = face.find(shape.glyph);