summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Firebaugh <john.firebaugh@gmail.com>2017-06-08 13:58:46 -0700
committerJohn Firebaugh <john.firebaugh@gmail.com>2017-06-13 10:18:43 -0700
commit3270440f234570f1426c442898c2400e36608ebf (patch)
treedfc2330d74187a2503b244e632592cd984c0d84f
parentf610e9bef969dc8d7ec1ea545e93919a03d98882 (diff)
downloadqtlocation-mapboxgl-3270440f234570f1426c442898c2400e36608ebf.tar.gz
[core] Per-tile glyph/icon atlases
-rw-r--r--include/mbgl/util/image.hpp17
-rw-r--r--src/mbgl/layout/symbol_instance.cpp6
-rw-r--r--src/mbgl/layout/symbol_instance.hpp2
-rw-r--r--src/mbgl/layout/symbol_layout.cpp81
-rw-r--r--src/mbgl/layout/symbol_layout.hpp9
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.cpp2
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.hpp3
-rw-r--r--src/mbgl/renderer/image_atlas.cpp34
-rw-r--r--src/mbgl/renderer/image_manager.cpp9
-rw-r--r--src/mbgl/renderer/painters/painter_symbol.cpp13
-rw-r--r--src/mbgl/text/glyph_atlas.cpp79
-rw-r--r--src/mbgl/text/glyph_atlas.hpp5
-rw-r--r--src/mbgl/text/quads.cpp8
-rw-r--r--src/mbgl/text/quads.hpp2
-rw-r--r--src/mbgl/tile/geometry_tile.cpp18
-rw-r--r--src/mbgl/tile/geometry_tile.hpp14
-rw-r--r--src/mbgl/tile/geometry_tile_worker.cpp14
-rw-r--r--test/tile/annotation_tile.test.cpp18
-rw-r--r--test/tile/vector_tile.test.cpp2
-rw-r--r--test/util/image.test.cpp48
20 files changed, 223 insertions, 161 deletions
diff --git a/include/mbgl/util/image.hpp b/include/mbgl/util/image.hpp
index a41b8462bd..91bf06d727 100644
--- a/include/mbgl/util/image.hpp
+++ b/include/mbgl/util/image.hpp
@@ -78,10 +78,27 @@ public:
std::fill(data.get(), data.get() + bytes(), value);
}
+ void resize(Size size_) {
+ if (size == size_) {
+ return;
+ }
+ Image newImage(size_);
+ newImage.fill(0);
+ copy(*this, newImage, {0, 0}, {0, 0}, {
+ std::min(size.width, size_.width),
+ std::min(size.height, size_.height)
+ });
+ operator=(std::move(newImage));
+ }
+
// Copy image data within `rect` from `src` to the rectangle of the same size at `pt`
// in `dst`. If the specified bounds exceed the bounds of the source or destination,
// throw `std::out_of_range`. Must not be used to move data within a single Image.
static void copy(const Image& srcImg, Image& dstImg, const Point<uint32_t>& srcPt, const Point<uint32_t>& dstPt, const Size& size) {
+ if (size.isEmpty()) {
+ return;
+ }
+
if (!srcImg.valid()) {
throw std::invalid_argument("invalid source for image copy");
}
diff --git a/src/mbgl/layout/symbol_instance.cpp b/src/mbgl/layout/symbol_instance.cpp
index 8816f4c95c..ffb70c7ca2 100644
--- a/src/mbgl/layout/symbol_instance.cpp
+++ b/src/mbgl/layout/symbol_instance.cpp
@@ -19,7 +19,7 @@ SymbolInstance::SymbolInstance(Anchor& anchor,
const float iconBoxScale,
const float iconPadding,
const SymbolPlacementType iconPlacement,
- const GlyphPositions& face,
+ const GlyphPositionMap& positions,
const IndexedSubfeature& indexedFeature,
const std::size_t featureIndex_) :
point(anchor.point),
@@ -38,11 +38,11 @@ SymbolInstance::SymbolInstance(Anchor& anchor,
iconQuad = getIconQuad(anchor, *shapedIcon, line, layout, layoutTextSize, iconPlacement, shapedTextOrientations.first);
}
if (shapedTextOrientations.first) {
- auto quads = getGlyphQuads(anchor, shapedTextOrientations.first, textBoxScale, line, layout, textPlacement, face);
+ auto quads = getGlyphQuads(anchor, shapedTextOrientations.first, textBoxScale, line, layout, textPlacement, positions);
glyphQuads.insert(glyphQuads.end(), quads.begin(), quads.end());
}
if (shapedTextOrientations.second) {
- auto quads = getGlyphQuads(anchor, shapedTextOrientations.second, textBoxScale, line, layout, textPlacement, face);
+ auto quads = getGlyphQuads(anchor, shapedTextOrientations.second, textBoxScale, line, layout, textPlacement, positions);
glyphQuads.insert(glyphQuads.end(), quads.begin(), quads.end());
}
}
diff --git a/src/mbgl/layout/symbol_instance.hpp b/src/mbgl/layout/symbol_instance.hpp
index 6a5d0c7cf3..f199d929df 100644
--- a/src/mbgl/layout/symbol_instance.hpp
+++ b/src/mbgl/layout/symbol_instance.hpp
@@ -26,7 +26,7 @@ public:
const float iconBoxScale,
const float iconPadding,
style::SymbolPlacementType iconPlacement,
- const GlyphPositions& face,
+ const GlyphPositionMap&,
const IndexedSubfeature&,
const std::size_t featureIndex);
diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp
index b64fc4f66e..ed580bcb16 100644
--- a/src/mbgl/layout/symbol_layout.cpp
+++ b/src/mbgl/layout/symbol_layout.cpp
@@ -175,7 +175,8 @@ bool SymbolLayout::hasSymbolInstances() const {
return !symbolInstances.empty();
}
-void SymbolLayout::prepare(const GlyphMap& glyphs, const ImageMap& images) {
+void SymbolLayout::prepare(const GlyphMap& glyphMap, const GlyphPositions& glyphPositions,
+ const ImageMap& imageMap, const ImagePositions& imagePositions) {
float horizontalAlign = 0.5;
float verticalAlign = 0.5;
@@ -220,12 +221,13 @@ void SymbolLayout::prepare(const GlyphMap& glyphs, const ImageMap& images) {
const bool textAlongLine = layout.get<TextRotationAlignment>() == AlignmentType::Map &&
layout.get<SymbolPlacement>() == SymbolPlacementType::Line;
- auto glyphPositionsIt = glyphs.find(layout.get<TextFont>());
- if (glyphPositionsIt != glyphs.end()) {
- glyphAtlas = makeGlyphAtlas(glyphPositionsIt->second);
- }
+ auto glyphMapIt = glyphMap.find(layout.get<TextFont>());
+ const Glyphs& glyphs = glyphMapIt != glyphMap.end()
+ ? glyphMapIt->second : Glyphs();
- imageAtlas = makeImageAtlas(images);
+ auto glyphPositionsIt = glyphPositions.find(layout.get<TextFont>());
+ const GlyphPositionMap& glyphPositionMap = glyphPositionsIt != glyphPositions.end()
+ ? glyphPositionsIt->second : GlyphPositionMap();
for (auto it = features.begin(); it != features.end(); ++it) {
auto& feature = *it;
@@ -236,42 +238,39 @@ void SymbolLayout::prepare(const GlyphMap& glyphs, const ImageMap& images) {
// if feature has text, shape the text
if (feature.text) {
- auto glyphPositions = glyphs.find(layout.get<TextFont>());
- if (glyphPositions != glyphs.end()) { // If there are no glyphs available for this feature, skip shaping
- auto applyShaping = [&] (const std::u16string& text, WritingModeType writingMode) {
- const float oneEm = 24.0f;
- const Shaping result = getShaping(
- /* string */ text,
- /* maxWidth: ems */ layout.get<SymbolPlacement>() != SymbolPlacementType::Line ?
- layout.get<TextMaxWidth>() * oneEm : 0,
- /* lineHeight: ems */ layout.get<TextLineHeight>() * oneEm,
- /* horizontalAlign */ horizontalAlign,
- /* verticalAlign */ verticalAlign,
- /* justify */ justify,
- /* spacing: ems */ util::i18n::allowsLetterSpacing(*feature.text) ? layout.get<TextLetterSpacing>() * oneEm : 0.0f,
- /* translate */ Point<float>(layout.evaluate<TextOffset>(zoom, feature)[0] * oneEm, layout.evaluate<TextOffset>(zoom, feature)[1] * oneEm),
- /* verticalHeight */ oneEm,
- /* writingMode */ writingMode,
- /* bidirectional algorithm object */ bidi,
- /* glyphs */ glyphPositions->second);
-
- return result;
- };
-
- shapedTextOrientations.first = applyShaping(*feature.text, WritingModeType::Horizontal);
-
- if (util::i18n::allowsVerticalWritingMode(*feature.text) && textAlongLine) {
- shapedTextOrientations.second = applyShaping(util::i18n::verticalizePunctuation(*feature.text), WritingModeType::Vertical);
- }
+ auto applyShaping = [&] (const std::u16string& text, WritingModeType writingMode) {
+ const float oneEm = 24.0f;
+ const Shaping result = getShaping(
+ /* string */ text,
+ /* maxWidth: ems */ layout.get<SymbolPlacement>() != SymbolPlacementType::Line ?
+ layout.get<TextMaxWidth>() * oneEm : 0,
+ /* lineHeight: ems */ layout.get<TextLineHeight>() * oneEm,
+ /* horizontalAlign */ horizontalAlign,
+ /* verticalAlign */ verticalAlign,
+ /* justify */ justify,
+ /* spacing: ems */ util::i18n::allowsLetterSpacing(*feature.text) ? layout.get<TextLetterSpacing>() * oneEm : 0.0f,
+ /* translate */ Point<float>(layout.evaluate<TextOffset>(zoom, feature)[0] * oneEm, layout.evaluate<TextOffset>(zoom, feature)[1] * oneEm),
+ /* verticalHeight */ oneEm,
+ /* writingMode */ writingMode,
+ /* bidirectional algorithm object */ bidi,
+ /* glyphs */ glyphs);
+
+ return result;
+ };
+
+ shapedTextOrientations.first = applyShaping(*feature.text, WritingModeType::Horizontal);
+
+ if (util::i18n::allowsVerticalWritingMode(*feature.text) && textAlongLine) {
+ shapedTextOrientations.second = applyShaping(util::i18n::verticalizePunctuation(*feature.text), WritingModeType::Vertical);
}
}
// if feature has icon, get sprite atlas position
if (feature.icon) {
- auto image = images.find(*feature.icon);
- if (image != images.end()) {
+ auto image = imageMap.find(*feature.icon);
+ if (image != imageMap.end()) {
shapedIcon = PositionedIcon::shapeIcon(
- imageAtlas.positions.at(*feature.icon),
+ imagePositions.at(*feature.icon),
layout.evaluate<IconOffset>(zoom, feature),
layout.evaluate<IconRotate>(zoom, feature) * util::DEG2RAD);
if (image->second->sdf) {
@@ -287,7 +286,7 @@ void SymbolLayout::prepare(const GlyphMap& glyphs, const ImageMap& images) {
// if either shapedText or icon position is present, add the feature
if (shapedTextOrientations.first || shapedIcon) {
- addFeature(std::distance(features.begin(), it), feature, shapedTextOrientations, shapedIcon);
+ addFeature(std::distance(features.begin(), it), feature, shapedTextOrientations, shapedIcon, glyphPositionMap);
}
feature.geometry.clear();
@@ -299,7 +298,8 @@ void SymbolLayout::prepare(const GlyphMap& glyphs, const ImageMap& images) {
void SymbolLayout::addFeature(const std::size_t index,
const SymbolFeature& feature,
const std::pair<Shaping, Shaping>& shapedTextOrientations,
- optional<PositionedIcon> shapedIcon) {
+ optional<PositionedIcon> shapedIcon,
+ const GlyphPositionMap& glyphPositionMap) {
const float minScale = 0.5f;
const float glyphSize = 24.0f;
@@ -356,7 +356,7 @@ void SymbolLayout::addFeature(const std::size_t index,
addToBuffers, symbolInstances.size(),
textBoxScale, textPadding, textPlacement,
iconBoxScale, iconPadding, iconPlacement,
- glyphAtlas.positions, indexedFeature, index);
+ glyphPositionMap, indexedFeature, index);
};
const auto& type = feature.getType();
@@ -430,9 +430,6 @@ bool SymbolLayout::anchorIsTooClose(const std::u16string& text, const float repe
std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile) {
auto bucket = std::make_unique<SymbolBucket>(layout, layerPaintProperties, textSize, iconSize, zoom, sdfIcons, iconsNeedLinear);
- bucket->text.atlasImage = glyphAtlas.image.clone();
- bucket->icon.atlasImage = imageAtlas.image.clone();
-
// Calculate which labels can be shown and when they can be shown and
// create the bufers used for rendering.
diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp
index 7d6f2319cd..b22c47c567 100644
--- a/src/mbgl/layout/symbol_layout.hpp
+++ b/src/mbgl/layout/symbol_layout.hpp
@@ -33,7 +33,8 @@ public:
ImageDependencies&,
GlyphDependencies&);
- void prepare(const GlyphMap& glyphs, const ImageMap& icons);
+ void prepare(const GlyphMap&, const GlyphPositions&,
+ const ImageMap&, const ImagePositions&);
std::unique_ptr<SymbolBucket> place(CollisionTile&);
@@ -53,7 +54,8 @@ private:
void addFeature(const size_t,
const SymbolFeature&,
const std::pair<Shaping, Shaping>& shapedTextOrientations,
- optional<PositionedIcon> shapedIcon);
+ optional<PositionedIcon> shapedIcon,
+ const GlyphPositionMap&);
bool anchorIsTooClose(const std::u16string& text, const float repeatDistance, const Anchor&);
std::map<std::u16string, std::vector<Anchor>> compareText;
@@ -93,9 +95,6 @@ private:
std::vector<SymbolInstance> symbolInstances;
std::vector<SymbolFeature> features;
- GlyphAtlas glyphAtlas;
- ImageAtlas imageAtlas;
-
BiDi bidi; // Consider moving this up to geometry tile worker to reduce reinstantiation costs; use of BiDi/ubiditransform object must be constrained to one thread
};
diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp
index 21d463b1fc..cbddade899 100644
--- a/src/mbgl/renderer/buckets/symbol_bucket.cpp
+++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp
@@ -39,14 +39,12 @@ void SymbolBucket::upload(gl::Context& context) {
if (hasTextData()) {
text.vertexBuffer = context.createVertexBuffer(std::move(text.vertices));
text.indexBuffer = context.createIndexBuffer(std::move(text.triangles));
- text.atlasTexture = context.createTexture(std::move(text.atlasImage), 0);
textSizeBinder->upload(context);
}
if (hasIconData()) {
icon.vertexBuffer = context.createVertexBuffer(std::move(icon.vertices));
icon.indexBuffer = context.createIndexBuffer(std::move(icon.triangles));
- icon.atlasTexture = context.createTexture(std::move(icon.atlasImage), 0);
iconSizeBinder->upload(context);
}
diff --git a/src/mbgl/renderer/buckets/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp
index bc9d564aac..002b6e28b3 100644
--- a/src/mbgl/renderer/buckets/symbol_bucket.hpp
+++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp
@@ -46,11 +46,9 @@ public:
gl::VertexVector<SymbolLayoutVertex> vertices;
gl::IndexVector<gl::Triangles> triangles;
gl::SegmentVector<SymbolTextAttributes> segments;
- AlphaImage atlasImage;
optional<gl::VertexBuffer<SymbolLayoutVertex>> vertexBuffer;
optional<gl::IndexBuffer<gl::Triangles>> indexBuffer;
- optional<gl::Texture> atlasTexture;
} text;
std::unique_ptr<SymbolSizeBinder> iconSizeBinder;
@@ -63,7 +61,6 @@ public:
optional<gl::VertexBuffer<SymbolLayoutVertex>> vertexBuffer;
optional<gl::IndexBuffer<gl::Triangles>> indexBuffer;
- optional<gl::Texture> atlasTexture;
} icon;
struct CollisionBoxBuffer {
diff --git a/src/mbgl/renderer/image_atlas.cpp b/src/mbgl/renderer/image_atlas.cpp
index b53c2162ea..9649187175 100644
--- a/src/mbgl/renderer/image_atlas.cpp
+++ b/src/mbgl/renderer/image_atlas.cpp
@@ -23,31 +23,17 @@ ImageAtlas makeImageAtlas(const ImageMap& images) {
options.autoResize = true;
mapbox::ShelfPack pack(0, 0, options);
- std::vector<const style::Image::Impl*> pointers;
- pointers.reserve(images.size());
-
- std::vector<mapbox::Bin> bins;
- bins.reserve(images.size());
-
for (const auto& entry : images) {
const style::Image::Impl& image = *entry.second;
- pointers.emplace_back(&image);
- bins.emplace_back(pointers.size() - 1,
- image.image.size.width + 2 * padding,
- image.image.size.height + 2 * padding);
- }
- mapbox::ShelfPack::PackOptions packOptions;
- packOptions.inPlace = true;
- pack.pack(bins, packOptions);
+ const mapbox::Bin& bin = *pack.packOne(-1,
+ image.image.size.width + 2 * padding,
+ image.image.size.height + 2 * padding);
- result.image = PremultipliedImage({
- static_cast<uint32_t>(pack.width()),
- static_cast<uint32_t>(pack.height())
- });
-
- for (const auto& bin : bins) {
- const style::Image::Impl& image = *pointers.at(bin.id);
+ result.image.resize({
+ static_cast<uint32_t>(pack.width()),
+ static_cast<uint32_t>(pack.height())
+ });
PremultipliedImage::copy(image.image,
result.image,
@@ -62,6 +48,12 @@ ImageAtlas makeImageAtlas(const ImageMap& images) {
ImagePosition { bin, image });
}
+// pack.shrink();
+// result.image.resize({
+// static_cast<uint32_t>(pack.width()),
+// static_cast<uint32_t>(pack.height())
+// });
+
return result;
}
diff --git a/src/mbgl/renderer/image_manager.cpp b/src/mbgl/renderer/image_manager.cpp
index be47004b69..d0a106ede6 100644
--- a/src/mbgl/renderer/image_manager.cpp
+++ b/src/mbgl/renderer/image_manager.cpp
@@ -119,14 +119,7 @@ optional<ImagePosition> ImageManager::getPattern(const std::string& id) {
return {};
}
- if (!atlasImage.valid()) {
- atlasImage = PremultipliedImage(getPixelSize());
- atlasImage.fill(0);
- } else if (atlasImage.size != getPixelSize()) {
- PremultipliedImage newImage(getPixelSize());
- PremultipliedImage::copy(atlasImage, newImage, { 0, 0 }, { 0, 0 }, atlasImage.size);
- atlasImage = std::move(newImage);
- }
+ atlasImage.resize(getPixelSize());
const PremultipliedImage& src = image->image;
diff --git a/src/mbgl/renderer/painters/painter_symbol.cpp b/src/mbgl/renderer/painters/painter_symbol.cpp
index 13baa1a514..58700fc4e8 100644
--- a/src/mbgl/renderer/painters/painter_symbol.cpp
+++ b/src/mbgl/renderer/painters/painter_symbol.cpp
@@ -9,7 +9,7 @@
#include <mbgl/programs/symbol_program.hpp>
#include <mbgl/programs/collision_box_program.hpp>
#include <mbgl/util/math.hpp>
-#include <mbgl/tile/tile.hpp>
+#include <mbgl/tile/geometry_tile.hpp>
#include <cmath>
@@ -62,6 +62,9 @@ void Painter::renderSymbol(PaintParameters& parameters,
);
};
+ assert(dynamic_cast<GeometryTile*>(&tile.tile));
+ GeometryTile& geometryTile = static_cast<GeometryTile&>(tile.tile);
+
if (bucket.hasIconData()) {
auto values = layer.iconPropertyValues(layout);
auto paintPropertyValues = layer.iconPaintProperties();
@@ -69,11 +72,11 @@ void Painter::renderSymbol(PaintParameters& parameters,
const bool iconScaled = layout.get<IconSize>().constantOr(1.0) != 1.0 || bucket.iconsNeedLinear;
const bool iconTransformed = values.rotationAlignment == AlignmentType::Map || state.getPitch() != 0;
- context.bindTexture(*bucket.icon.atlasTexture, 0,
+ context.bindTexture(*geometryTile.iconAtlasTexture, 0,
bucket.sdfIcons || state.isChanging() || iconScaled || iconTransformed
? gl::TextureFilter::Linear : gl::TextureFilter::Nearest);
- const Size texsize = bucket.icon.atlasTexture->size;
+ const Size texsize = geometryTile.iconAtlasTexture->size;
if (bucket.sdfIcons) {
if (values.hasHalo) {
@@ -107,12 +110,12 @@ void Painter::renderSymbol(PaintParameters& parameters,
}
if (bucket.hasTextData()) {
- context.bindTexture(*bucket.text.atlasTexture, 0, gl::TextureFilter::Linear);
+ context.bindTexture(*geometryTile.glyphAtlasTexture, 0, gl::TextureFilter::Linear);
auto values = layer.textPropertyValues(layout);
auto paintPropertyValues = layer.textPaintProperties();
- const Size texsize = bucket.text.atlasTexture->size;
+ const Size texsize = geometryTile.glyphAtlasTexture->size;
if (values.hasHalo) {
draw(parameters.programs.symbolGlyph,
diff --git a/src/mbgl/text/glyph_atlas.cpp b/src/mbgl/text/glyph_atlas.cpp
index a08455ec63..6636c23f34 100644
--- a/src/mbgl/text/glyph_atlas.cpp
+++ b/src/mbgl/text/glyph_atlas.cpp
@@ -6,58 +6,59 @@ namespace mbgl {
static constexpr uint32_t padding = 1;
-GlyphAtlas makeGlyphAtlas(const Glyphs& glyphs) {
+GlyphAtlas makeGlyphAtlas(const GlyphMap& glyphs) {
GlyphAtlas result;
mapbox::ShelfPack::ShelfPackOptions options;
options.autoResize = true;
mapbox::ShelfPack pack(0, 0, options);
- std::vector<mapbox::Bin> bins;
- bins.reserve(glyphs.size());
+ for (const auto& glyphMapEntry : glyphs) {
+ const FontStack& fontStack = glyphMapEntry.first;
+ GlyphPositionMap& positions = result.positions[fontStack];
- for (const auto& entry : glyphs) {
- if (entry.second && (*entry.second)->bitmap.valid()) {
- const Glyph& glyph = **entry.second;
- bins.emplace_back(glyph.id,
- glyph.bitmap.size.width + 2 * padding,
- glyph.bitmap.size.height + 2 * padding);
- }
- }
-
- mapbox::ShelfPack::PackOptions packOptions;
- packOptions.inPlace = true;
- pack.pack(bins, packOptions);
+ for (const auto& entry : glyphMapEntry.second) {
+ if (entry.second && (*entry.second)->bitmap.valid()) {
+ const Glyph& glyph = **entry.second;
- result.image = AlphaImage({
- static_cast<uint32_t>(pack.width()),
- static_cast<uint32_t>(pack.height())
- });
+ const mapbox::Bin& bin = *pack.packOne(-1,
+ glyph.bitmap.size.width + 2 * padding,
+ glyph.bitmap.size.height + 2 * padding);
- for (const auto& bin : bins) {
- const Glyph& glyph = **glyphs.at(bin.id);
+ result.image.resize({
+ static_cast<uint32_t>(pack.width()),
+ static_cast<uint32_t>(pack.height())
+ });
- AlphaImage::copy(glyph.bitmap,
- result.image,
- { 0, 0 },
- {
- bin.x + padding,
- bin.y + padding
- },
- glyph.bitmap.size);
+ AlphaImage::copy(glyph.bitmap,
+ result.image,
+ { 0, 0 },
+ {
+ bin.x + padding,
+ bin.y + padding
+ },
+ glyph.bitmap.size);
- result.positions.emplace(glyph.id,
- GlyphPosition {
- Rect<uint16_t> {
- static_cast<uint16_t>(bin.x),
- static_cast<uint16_t>(bin.y),
- static_cast<uint16_t>(bin.w),
- static_cast<uint16_t>(bin.h)
- },
- glyph.metrics
- });
+ positions.emplace(glyph.id,
+ GlyphPosition {
+ Rect<uint16_t> {
+ static_cast<uint16_t>(bin.x),
+ static_cast<uint16_t>(bin.y),
+ static_cast<uint16_t>(bin.w),
+ static_cast<uint16_t>(bin.h)
+ },
+ glyph.metrics
+ });
+ }
+ }
}
+// pack.shrink();
+// result.image.resize({
+// static_cast<uint32_t>(pack.width()),
+// static_cast<uint32_t>(pack.height())
+// });
+
return result;
}
diff --git a/src/mbgl/text/glyph_atlas.hpp b/src/mbgl/text/glyph_atlas.hpp
index 7a90085642..bb9115e4b4 100644
--- a/src/mbgl/text/glyph_atlas.hpp
+++ b/src/mbgl/text/glyph_atlas.hpp
@@ -11,7 +11,8 @@ struct GlyphPosition {
GlyphMetrics metrics;
};
-using GlyphPositions = std::map<GlyphID, GlyphPosition>;
+using GlyphPositionMap = std::map<GlyphID, GlyphPosition>;
+using GlyphPositions = std::map<FontStack, GlyphPositionMap>;
class GlyphAtlas {
public:
@@ -19,6 +20,6 @@ public:
GlyphPositions positions;
};
-GlyphAtlas makeGlyphAtlas(const Glyphs&);
+GlyphAtlas makeGlyphAtlas(const GlyphMap&);
} // namespace mbgl
diff --git a/src/mbgl/text/quads.cpp b/src/mbgl/text/quads.cpp
index 81827ca32e..ab10c5a6b7 100644
--- a/src/mbgl/text/quads.cpp
+++ b/src/mbgl/text/quads.cpp
@@ -307,18 +307,18 @@ SymbolQuads getGlyphQuads(Anchor& anchor,
const GeometryCoordinates& line,
const SymbolLayoutProperties::Evaluated& layout,
const style::SymbolPlacementType placement,
- const GlyphPositions& face) {
+ const GlyphPositionMap& positions) {
const float textRotate = layout.get<TextRotate>() * util::DEG2RAD;
const bool keepUpright = layout.get<TextKeepUpright>();
SymbolQuads quads;
for (const PositionedGlyph &positionedGlyph: shapedText.positionedGlyphs) {
- auto face_it = face.find(positionedGlyph.glyph);
- if (face_it == face.end())
+ auto positionsIt = positions.find(positionedGlyph.glyph);
+ if (positionsIt == positions.end())
continue;
- const GlyphPosition& glyph = face_it->second;
+ const GlyphPosition& glyph = positionsIt->second;
const Rect<uint16_t>& rect = glyph.rect;
const float centerX = (positionedGlyph.x + glyph.metrics.advance / 2.0f) * boxScale;
diff --git a/src/mbgl/text/quads.hpp b/src/mbgl/text/quads.hpp
index 89df423529..b29f6b0ad3 100644
--- a/src/mbgl/text/quads.hpp
+++ b/src/mbgl/text/quads.hpp
@@ -65,6 +65,6 @@ SymbolQuads getGlyphQuads(Anchor& anchor,
const GeometryCoordinates& line,
const style::SymbolLayoutProperties::Evaluated&,
style::SymbolPlacementType placement,
- const GlyphPositions& face);
+ const GlyphPositionMap& positions);
} // namespace mbgl
diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp
index b7561d677c..4ab11d79fe 100644
--- a/src/mbgl/tile/geometry_tile.cpp
+++ b/src/mbgl/tile/geometry_tile.cpp
@@ -10,6 +10,8 @@
#include <mbgl/renderer/layers/render_custom_layer.hpp>
#include <mbgl/renderer/layers/render_symbol_layer.hpp>
#include <mbgl/renderer/buckets/symbol_bucket.hpp>
+#include <mbgl/text/glyph_atlas.hpp>
+#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/storage/file_source.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/text/collision_tile.hpp>
@@ -135,6 +137,12 @@ void GeometryTile::onPlacement(PlacementResult result) {
}
symbolBuckets = std::move(result.symbolBuckets);
collisionTile = std::move(result.collisionTile);
+ if (result.glyphAtlasImage) {
+ glyphAtlasImage = std::move(*result.glyphAtlasImage);
+ }
+ if (result.iconAtlasImage) {
+ iconAtlasImage = std::move(*result.iconAtlasImage);
+ }
observer->onTileChanged(*this);
}
@@ -175,6 +183,16 @@ void GeometryTile::upload(gl::Context& context) {
for (auto& entry : symbolBuckets) {
upload(*entry.second);
}
+
+ if (glyphAtlasImage) {
+ glyphAtlasTexture = context.createTexture(*glyphAtlasImage, 0);
+ glyphAtlasImage = {};
+ }
+
+ if (iconAtlasImage) {
+ iconAtlasTexture = context.createTexture(*iconAtlasImage, 0);
+ iconAtlasImage = {};
+ }
}
Bucket* GeometryTile::getBucket(const Layer::Impl& layer) const {
diff --git a/src/mbgl/tile/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp
index f2510e317b..77202d20b6 100644
--- a/src/mbgl/tile/geometry_tile.hpp
+++ b/src/mbgl/tile/geometry_tile.hpp
@@ -23,6 +23,8 @@ class RenderStyle;
class RenderLayer;
class SourceQueryOptions;
class TileParameters;
+class GlyphAtlas;
+class ImageAtlas;
class GeometryTile : public Tile, public GlyphRequestor, ImageRequestor {
public:
@@ -47,6 +49,9 @@ public:
void upload(gl::Context&) override;
Bucket* getBucket(const style::Layer::Impl&) const override;
+ Size bindGlyphAtlas(gl::Context&);
+ Size bindIconAtlas(gl::Context&);
+
void queryRenderedFeatures(
std::unordered_map<std::string, std::vector<Feature>>& result,
const GeometryCoordinates& queryGeometry,
@@ -73,6 +78,8 @@ public:
public:
std::unordered_map<std::string, std::shared_ptr<Bucket>> symbolBuckets;
std::unique_ptr<CollisionTile> collisionTile;
+ optional<AlphaImage> glyphAtlasImage;
+ optional<PremultipliedImage> iconAtlasImage;
uint64_t correlationID;
};
void onPlacement(PlacementResult);
@@ -106,10 +113,17 @@ private:
std::unique_ptr<FeatureIndex> featureIndex;
std::unique_ptr<const GeometryTileData> data;
+ optional<AlphaImage> glyphAtlasImage;
+ optional<PremultipliedImage> iconAtlasImage;
+
std::unordered_map<std::string, std::shared_ptr<Bucket>> symbolBuckets;
std::unique_ptr<CollisionTile> collisionTile;
util::Throttler placementThrottler;
+
+public:
+ optional<gl::Texture> glyphAtlasTexture;
+ optional<gl::Texture> iconAtlasTexture;
};
} // namespace mbgl
diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp
index d67cbca76b..a5a82a7920 100644
--- a/src/mbgl/tile/geometry_tile_worker.cpp
+++ b/src/mbgl/tile/geometry_tile_worker.cpp
@@ -386,14 +386,24 @@ void GeometryTileWorker::attemptPlacement() {
auto collisionTile = std::make_unique<CollisionTile>(*placementConfig);
std::unordered_map<std::string, std::shared_ptr<Bucket>> buckets;
+ optional<AlphaImage> glyphAtlasImage;
+ optional<PremultipliedImage> iconAtlasImage;
+
for (auto& symbolLayout : symbolLayouts) {
if (obsolete) {
return;
}
if (symbolLayout->state == SymbolLayout::Pending) {
- symbolLayout->prepare(glyphMap, imageMap);
+ GlyphAtlas glyphAtlas = makeGlyphAtlas(glyphMap);
+ ImageAtlas imageAtlas = makeImageAtlas(imageMap);
+
+ symbolLayout->prepare(glyphMap, glyphAtlas.positions,
+ imageMap, imageAtlas.positions);
symbolLayout->state = SymbolLayout::Placed;
+
+ glyphAtlasImage = std::move(glyphAtlas.image);
+ iconAtlasImage = std::move(imageAtlas.image);
}
if (!symbolLayout->hasSymbolInstances()) {
@@ -409,6 +419,8 @@ void GeometryTileWorker::attemptPlacement() {
parent.invoke(&GeometryTile::onPlacement, GeometryTile::PlacementResult {
std::move(buckets),
std::move(collisionTile),
+ std::move(glyphAtlasImage),
+ std::move(iconAtlasImage),
correlationID
});
}
diff --git a/test/tile/annotation_tile.test.cpp b/test/tile/annotation_tile.test.cpp
index 8aa91b1517..707f118fd5 100644
--- a/test/tile/annotation_tile.test.cpp
+++ b/test/tile/annotation_tile.test.cpp
@@ -55,9 +55,9 @@ TEST(AnnotationTile, Issue8289) {
// Simulate layout and placement of a symbol layer.
tile.onLayout(GeometryTile::LayoutResult {
{},
- std::make_unique<FeatureIndex>(),
- std::move(data),
- 0
+ std::make_unique<FeatureIndex>(),
+ std::move(data),
+ 0
});
auto collisionTile = std::make_unique<CollisionTile>(PlacementConfig());
@@ -69,16 +69,18 @@ TEST(AnnotationTile, Issue8289) {
tile.onPlacement(GeometryTile::PlacementResult {
{},
- std::move(collisionTile),
- 0
+ std::move(collisionTile),
+ {},
+ {},
+ 0
});
// Simulate a second layout with empty data.
tile.onLayout(GeometryTile::LayoutResult {
{},
- std::make_unique<FeatureIndex>(),
- std::make_unique<AnnotationTileData>(),
- 0
+ std::make_unique<FeatureIndex>(),
+ std::make_unique<AnnotationTileData>(),
+ 0
});
std::unordered_map<std::string, std::vector<Feature>> result;
diff --git a/test/tile/vector_tile.test.cpp b/test/tile/vector_tile.test.cpp
index c427a1a869..f24733dc9b 100644
--- a/test/tile/vector_tile.test.cpp
+++ b/test/tile/vector_tile.test.cpp
@@ -81,6 +81,8 @@ TEST(VectorTile, Issue7615) {
symbolBucket
}},
nullptr,
+ {},
+ {},
0
});
diff --git a/test/util/image.test.cpp b/test/util/image.test.cpp
index f4031f1bc1..f4a6473040 100644
--- a/test/util/image.test.cpp
+++ b/test/util/image.test.cpp
@@ -86,33 +86,49 @@ TEST(Image, WebPTile) {
}
#endif // !defined(__ANDROID__) && !defined(__APPLE__) && !defined(QT_IMAGE_DECODERS)
+TEST(Image, Resize) {
+ AlphaImage image({0, 0});
+
+ image.resize({1, 1});
+ EXPECT_EQ(image.size, Size({1, 1}));
+
+ image.fill(100);
+ image.resize({2, 1});
+ EXPECT_EQ(image.size, Size({2, 1}));
+ EXPECT_EQ(image.data[0], 100);
+ EXPECT_EQ(image.data[1], 0);
+
+ image.resize({0, 0});
+ EXPECT_EQ(image.size, Size({0, 0}));
+}
+
TEST(Image, Copy) {
PremultipliedImage src5({5, 5});
PremultipliedImage dst5({5, 5});
PremultipliedImage src10({10, 10});
PremultipliedImage dst10({10, 10});
- EXPECT_THROW(PremultipliedImage::copy(src5, dst10, {0, 0}, {0, 0}, {6, 0}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src5, dst10, {0, 0}, {0, 0}, {0, 6}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src5, dst10, {1, 1}, {0, 0}, {5, 0}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src5, dst10, {1, 1}, {0, 0}, {0, 5}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src5, dst10, {0, 0}, {0, 0}, {6, 1}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src5, dst10, {0, 0}, {0, 0}, {1, 6}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src5, dst10, {1, 1}, {0, 0}, {5, 1}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src5, dst10, {1, 1}, {0, 0}, {1, 5}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src10, dst5, {0, 0}, {0, 0}, {6, 0}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src10, dst5, {0, 0}, {0, 0}, {0, 6}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src10, dst5, {0, 0}, {1, 1}, {5, 0}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src10, dst5, {0, 0}, {1, 1}, {0, 5}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst5, {0, 0}, {0, 0}, {6, 1}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst5, {0, 0}, {0, 0}, {1, 6}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst5, {0, 0}, {1, 1}, {5, 1}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst5, {0, 0}, {1, 1}, {1, 5}), std::out_of_range);
const uint32_t max = std::numeric_limits<uint32_t>::max();
- EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {max, 0}, {0, 0}, {1, 0}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, max}, {0, 0}, {0, 1}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, 0}, {max, 0}, {1, 0}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, 0}, {0, max}, {0, 1}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {max, 0}, {0, 0}, {1, 1}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, max}, {0, 0}, {1, 1}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, 0}, {max, 0}, {1, 1}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, 0}, {0, max}, {1, 1}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {1, 0}, {0, 0}, {max, 0}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, 1}, {0, 0}, {0, max}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, 0}, {1, 0}, {max, 0}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, 0}, {0, 1}, {0, max}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {1, 0}, {0, 0}, {max, 1}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, 1}, {0, 0}, {1, max}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, 0}, {1, 0}, {max, 1}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, 0}, {0, 1}, {1, max}), std::out_of_range);
}
TEST(Image, Move) {