[core] move Painter and dependents to new *TileID classes

This commit is contained in:
Konstantin Käfer
2016-03-08 17:18:57 +01:00
parent 5b640fb446
commit dde59eaf76
30 changed files with 138 additions and 670 deletions

View File

@@ -32,9 +32,6 @@ bool ClipIDGenerator::Leaf::operator==(const Leaf& other) const {
return children == other.children;
}
// Instantiate the function for Tile& refs.
template void ClipIDGenerator::update(std::map<UnwrappedTileID, Tile&>&);
std::map<UnwrappedTileID, ClipID> ClipIDGenerator::getStencils() const {
std::map<UnwrappedTileID, ClipID> stencils;

View File

@@ -1,5 +1,5 @@
#include <mbgl/map/transform_state.hpp>
#include <mbgl/map/tile_id.hpp>
#include <mbgl/tile/tile_id.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/interpolate.hpp>
#include <mbgl/util/math.hpp>
@@ -14,12 +14,14 @@ TransformState::TransformState(ConstrainMode constrainMode_)
#pragma mark - Matrix
void TransformState::matrixFor(mat4& matrix, const TileID& id, const int8_t z) const {
const double tile_scale = std::pow(2, z);
double s = worldSize() / tile_scale;
void TransformState::matrixFor(mat4& matrix, const UnwrappedTileID& tileID) const {
const uint64_t tileScale = 1ull << tileID.canonical.z;
const double s = worldSize() / tileScale;
matrix::identity(matrix);
matrix::translate(matrix, matrix, id.x * s, id.y * s, 0);
matrix::translate(matrix, matrix,
static_cast<int64_t>(tileID.canonical.x + tileID.wrap * tileScale) * s,
static_cast<int64_t>(tileID.canonical.y) * s, 0);
matrix::scale(matrix, matrix, s / util::EXTENT, s / util::EXTENT, 1);
}

View File

@@ -12,7 +12,7 @@
namespace mbgl {
class TileID;
class UnwrappedTileID;
class TransformState {
friend class Transform;
@@ -21,7 +21,7 @@ public:
TransformState(ConstrainMode = ConstrainMode::HeightOnly);
// Matrix
void matrixFor(mat4& matrix, const TileID& id, const int8_t z) const;
void matrixFor(mat4&, const UnwrappedTileID&) const;
void getProjMatrix(mat4& matrix) const;
// Dimensions

View File

@@ -15,7 +15,7 @@ namespace mbgl {
class Painter;
class StyleLayer;
class TileID;
class UnwrappedTileID;
class CollisionTile;
namespace gl {
@@ -32,7 +32,7 @@ public:
// Every time this bucket is getting rendered, this function is called. This happens either
// once or twice (for Opaque and Transparent render passes).
virtual void render(Painter&, const StyleLayer&, const TileID&, const mat4&) = 0;
virtual void render(Painter&, const StyleLayer&, const UnwrappedTileID&, const mat4&) = 0;
virtual ~Bucket() = default;

View File

@@ -22,9 +22,9 @@ void CircleBucket::upload(gl::GLObjectStore& glObjectStore) {
void CircleBucket::render(Painter& painter,
const StyleLayer& layer,
const TileID& id,
const UnwrappedTileID& tileID,
const mat4& matrix) {
painter.renderCircle(*this, *layer.as<CircleLayer>(), id, matrix);
painter.renderCircle(*this, *layer.as<CircleLayer>(), tileID, matrix);
}
bool CircleBucket::hasData() const {

View File

@@ -20,7 +20,7 @@ public:
~CircleBucket() override;
void upload(gl::GLObjectStore&) override;
void render(Painter&, const StyleLayer&, const TileID&, const mat4&) override;
void render(Painter&, const StyleLayer&, const UnwrappedTileID&, const mat4&) override;
bool hasData() const override;
bool needsClipping() const override;

View File

@@ -198,9 +198,9 @@ void FillBucket::upload(gl::GLObjectStore& glObjectStore) {
void FillBucket::render(Painter& painter,
const StyleLayer& layer,
const TileID& id,
const UnwrappedTileID& tileID,
const mat4& matrix) {
painter.renderFill(*this, *layer.as<FillLayer>(), id, matrix);
painter.renderFill(*this, *layer.as<FillLayer>(), tileID, matrix);
}
bool FillBucket::hasData() const {

View File

@@ -34,7 +34,7 @@ public:
~FillBucket() override;
void upload(gl::GLObjectStore&) override;
void render(Painter&, const StyleLayer&, const TileID&, const mat4&) override;
void render(Painter&, const StyleLayer&, const UnwrappedTileID&, const mat4&) override;
bool hasData() const override;
bool needsClipping() const override;

View File

@@ -445,9 +445,9 @@ void LineBucket::upload(gl::GLObjectStore& glObjectStore) {
void LineBucket::render(Painter& painter,
const StyleLayer& layer,
const TileID& id,
const UnwrappedTileID& tileID,
const mat4& matrix) {
painter.renderLine(*this, *layer.as<LineLayer>(), id, matrix);
painter.renderLine(*this, *layer.as<LineLayer>(), tileID, matrix);
}
bool LineBucket::hasData() const {

View File

@@ -27,7 +27,7 @@ public:
~LineBucket() override;
void upload(gl::GLObjectStore&) override;
void render(Painter&, const StyleLayer&, const TileID&, const mat4&) override;
void render(Painter&, const StyleLayer&, const UnwrappedTileID&, const mat4&) override;
bool hasData() const override;
bool needsClipping() const override;

View File

@@ -31,6 +31,9 @@
#include <mbgl/shader/box_shader.hpp>
#include <mbgl/shader/circle_shader.hpp>
#include <mbgl/algorithm/generate_clip_ids.hpp>
#include <mbgl/algorithm/generate_clip_ids_impl.hpp>
#include <mbgl/util/constants.hpp>
#if defined(DEBUG)
@@ -144,11 +147,12 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a
MBGL_DEBUG_GROUP("clip");
// Update all clipping IDs.
ClipIDGenerator generator;
algorithm::ClipIDGenerator generator;
for (const auto& source : sources) {
if (source->type == SourceType::Vector || source->type == SourceType::GeoJSON ||
source->type == SourceType::Annotations) {
generator.update(source->getLoadedTiles());
auto renderables = source->getRenderables();
generator.update(renderables);
}
source->updateMatrices(projMatrix, state);
}
@@ -251,7 +255,8 @@ void Painter::renderPass(RenderPass pass_,
if (item.bucket->needsClipping()) {
setClipping(item.tile->clip);
}
item.bucket->render(*this, layer, item.tile->id, item.tile->matrix);
const UnwrappedTileID tileID{ item.tile->id.sourceZ, item.tile->id.x, item.tile->id.y };
item.bucket->render(*this, layer, tileID, item.tile->matrix);
}
}
@@ -260,11 +265,13 @@ void Painter::renderPass(RenderPass pass_,
}
}
mat4 Painter::translatedMatrix(const mat4& matrix, const std::array<float, 2> &translation, const TileID &id, TranslateAnchorType anchor) {
mat4 Painter::translatedMatrix(const mat4& matrix,
const std::array<float, 2>& translation,
const UnwrappedTileID& id,
TranslateAnchorType anchor) {
if (translation[0] == 0 && translation[1] == 0) {
return matrix;
} else {
mat4 vtxMatrix;
if (anchor == TranslateAnchorType::Viewport) {
const double sin_a = std::sin(-state.getAngle());

View File

@@ -3,6 +3,8 @@
#include <mbgl/map/transform_state.hpp>
#include <mbgl/tile/tile_id.hpp>
#include <mbgl/renderer/frame_history.hpp>
#include <mbgl/renderer/bucket.hpp>
@@ -98,23 +100,26 @@ public:
void renderDebugFrame(const mat4 &matrix);
void renderDebugText(TileData&, const mat4&);
void renderFill(FillBucket&, const FillLayer&, const TileID&, const mat4&);
void renderLine(LineBucket&, const LineLayer&, const TileID&, const mat4&);
void renderCircle(CircleBucket&, const CircleLayer&, const TileID&, const mat4&);
void renderSymbol(SymbolBucket&, const SymbolLayer&, const TileID&, const mat4&);
void renderRaster(RasterBucket&, const RasterLayer&, const TileID&, const mat4&);
void renderFill(FillBucket&, const FillLayer&, const UnwrappedTileID&, const mat4&);
void renderLine(LineBucket&, const LineLayer&, const UnwrappedTileID&, const mat4&);
void renderCircle(CircleBucket&, const CircleLayer&, const UnwrappedTileID&, const mat4&);
void renderSymbol(SymbolBucket&, const SymbolLayer&, const UnwrappedTileID&, const mat4&);
void renderRaster(RasterBucket&, const RasterLayer&, const UnwrappedTileID&, const mat4&);
void renderBackground(const BackgroundLayer&);
float saturationFactor(float saturation);
float contrastFactor(float contrast);
std::array<float, 3> spinWeights(float spin_value);
void drawClippingMasks(const std::map<TileID, ClipID>&);
void drawClippingMasks(const std::map<UnwrappedTileID, ClipID>&);
bool needsAnimation() const;
private:
mat4 translatedMatrix(const mat4& matrix, const std::array<float, 2> &translation, const TileID &id, TranslateAnchorType anchor);
mat4 translatedMatrix(const mat4& matrix,
const std::array<float, 2>& translation,
const UnwrappedTileID& id,
TranslateAnchorType anchor);
std::vector<RenderItem> determineRenderOrder(const Style& style);
@@ -126,7 +131,7 @@ private:
void setClipping(const ClipID&);
void renderSDF(SymbolBucket &bucket,
const TileID &id,
const UnwrappedTileID &tileID,
const mat4 &matrixSymbol,
float scaleDivisor,
std::array<float, 2> texsize,

View File

@@ -59,7 +59,8 @@ void Painter::renderBackground(const BackgroundLayer& layer) {
for (auto &id: tileIDs) {
mat4 vtxMatrix;
state.matrixFor(vtxMatrix, id, id.z);
const UnwrappedTileID tileID(id.z, id.x, id.y);
state.matrixFor(vtxMatrix, tileID);
matrix::multiply(vtxMatrix, projMatrix, vtxMatrix);
if (isPatterned) {

View File

@@ -11,7 +11,7 @@ using namespace mbgl;
void Painter::renderCircle(CircleBucket& bucket,
const CircleLayer& layer,
const TileID& id,
const UnwrappedTileID& tileID,
const mat4& matrix) {
// Abort early.
if (pass == RenderPass::Opaque) return;
@@ -23,7 +23,8 @@ void Painter::renderCircle(CircleBucket& bucket,
setDepthSublayer(0);
const CirclePaintProperties& properties = layer.paint;
mat4 vtxMatrix = translatedMatrix(matrix, properties.circleTranslate, id, properties.circleTranslateAnchor);
mat4 vtxMatrix = translatedMatrix(matrix, properties.circleTranslate, tileID,
properties.circleTranslateAnchor);
Color color = properties.circleColor;
color[0] *= properties.circleOpacity;

View File

@@ -2,12 +2,13 @@
#include <mbgl/source/source.hpp>
#include <mbgl/shader/plain_shader.hpp>
#include <mbgl/util/clip_id.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/gl/debugging.hpp>
using namespace mbgl;
void Painter::drawClippingMasks(const std::map<TileID, ClipID>& stencils) {
void Painter::drawClippingMasks(const std::map<UnwrappedTileID, ClipID>& stencils) {
MBGL_DEBUG_GROUP("clipping masks");
mat4 matrix;
@@ -27,8 +28,8 @@ void Painter::drawClippingMasks(const std::map<TileID, ClipID>& stencils) {
const auto& id = stencil.first;
const auto& clip = stencil.second;
MBGL_DEBUG_GROUP(std::string{ "mask: " } + std::string(id));
state.matrixFor(matrix, id, id.z);
MBGL_DEBUG_GROUP(std::string{ "mask: " } + util::toString(id));
state.matrixFor(matrix, id);
matrix::multiply(matrix, projMatrix, matrix);
plainShader->u_matrix = matrix;

View File

@@ -10,9 +10,13 @@
using namespace mbgl;
void Painter::renderFill(FillBucket& bucket, const FillLayer& layer, const TileID& id, const mat4& matrix) {
void Painter::renderFill(FillBucket& bucket,
const FillLayer& layer,
const UnwrappedTileID& tileID,
const mat4& matrix) {
const FillPaintProperties& properties = layer.paint;
mat4 vtxMatrix = translatedMatrix(matrix, properties.fillTranslate, id, properties.fillTranslateAnchor);
mat4 vtxMatrix =
translatedMatrix(matrix, properties.fillTranslate, tileID, properties.fillTranslateAnchor);
Color fill_color = properties.fillColor;
fill_color[0] *= properties.fillOpacity;
@@ -65,7 +69,6 @@ void Painter::renderFill(FillBucket& bucket, const FillLayer& layer, const TileI
// Image fill.
if (pass == RenderPass::Translucent && posA && posB) {
config.program = patternShader->getID();
patternShader->u_matrix = vtxMatrix;
patternShader->u_pattern_tl_a = (*posA).tl;
@@ -85,20 +88,24 @@ void Painter::renderFill(FillBucket& bucket, const FillLayer& layer, const TileI
(int)((*posB).size[1] * properties.fillPattern.value.toScale)
}};
patternShader->u_patternscale_a = {{
1.0f / id.pixelsToTileUnits(imageSizeScaledA[0], state.getIntegerZoom()),
1.0f / id.pixelsToTileUnits(imageSizeScaledB[1], state.getIntegerZoom())
}};
patternShader->u_patternscale_b = {{
1.0f / id.pixelsToTileUnits(imageSizeScaledB[0], state.getIntegerZoom()),
1.0f / id.pixelsToTileUnits(imageSizeScaledB[1], state.getIntegerZoom())
}};
patternShader->u_patternscale_a = {
{ 1.0f / tileID.pixelsToTileUnits(imageSizeScaledA[0], state.getIntegerZoom()),
1.0f / tileID.pixelsToTileUnits(imageSizeScaledB[1], state.getIntegerZoom()) }
};
patternShader->u_patternscale_b = {
{ 1.0f / tileID.pixelsToTileUnits(imageSizeScaledB[0], state.getIntegerZoom()),
1.0f / tileID.pixelsToTileUnits(imageSizeScaledB[1], state.getIntegerZoom()) }
};
float offsetAx = (std::fmod(util::tileSize, imageSizeScaledA[0]) * id.x) / (float)imageSizeScaledA[0];
float offsetAy = (std::fmod(util::tileSize, imageSizeScaledA[1]) * id.y) / (float)imageSizeScaledA[1];
float offsetAx = (std::fmod(util::tileSize, imageSizeScaledA[0]) * tileID.canonical.x) /
(float)imageSizeScaledA[0];
float offsetAy = (std::fmod(util::tileSize, imageSizeScaledA[1]) * tileID.canonical.y) /
(float)imageSizeScaledA[1];
float offsetBx = (std::fmod(util::tileSize, imageSizeScaledB[0]) * id.x) / (float)imageSizeScaledB[0];
float offsetBy = (std::fmod(util::tileSize, imageSizeScaledB[1]) * id.y) / (float)imageSizeScaledB[1];
float offsetBx = (std::fmod(util::tileSize, imageSizeScaledB[0]) * tileID.canonical.x) /
(float)imageSizeScaledB[0];
float offsetBy = (std::fmod(util::tileSize, imageSizeScaledB[1]) * tileID.canonical.y) /
(float)imageSizeScaledB[1];
patternShader->u_offset_a = std::array<float, 2>{{offsetAx, offsetAy}};
patternShader->u_offset_b = std::array<float, 2>{{offsetBx, offsetBy}};

View File

@@ -11,7 +11,10 @@
using namespace mbgl;
void Painter::renderLine(LineBucket& bucket, const LineLayer& layer, const TileID& id, const mat4& matrix) {
void Painter::renderLine(LineBucket& bucket,
const LineLayer& layer,
const UnwrappedTileID& tileID,
const mat4& matrix) {
// Abort early.
if (pass == RenderPass::Opaque) return;
@@ -50,7 +53,7 @@ void Painter::renderLine(LineBucket& bucket, const LineLayer& layer, const TileI
color[2] *= properties.lineOpacity;
color[3] *= properties.lineOpacity;
const float ratio = 1.0 / id.pixelsToTileUnits(1.0, state.getZoom());
const float ratio = 1.0 / tileID.pixelsToTileUnits(1.0, state.getZoom());
mat2 antialiasingMatrix;
matrix::identity(antialiasingMatrix);
@@ -63,7 +66,8 @@ void Painter::renderLine(LineBucket& bucket, const LineLayer& layer, const TileI
float x = state.getHeight() / 2.0f * std::tan(state.getPitch());
float extra = (topedgelength + x) / topedgelength - 1;
mat4 vtxMatrix = translatedMatrix(matrix, properties.lineTranslate, id, properties.lineTranslateAnchor);
mat4 vtxMatrix =
translatedMatrix(matrix, properties.lineTranslate, tileID, properties.lineTranslateAnchor);
setDepthSublayer(0);
@@ -84,9 +88,9 @@ void Painter::renderLine(LineBucket& bucket, const LineLayer& layer, const TileI
const float widthA = posA.width * properties.lineDasharray.value.fromScale * layer.dashLineWidth;
const float widthB = posB.width * properties.lineDasharray.value.toScale * layer.dashLineWidth;
float scaleXA = 1.0 / id.pixelsToTileUnits(widthA, state.getIntegerZoom());
float scaleXA = 1.0 / tileID.pixelsToTileUnits(widthA, state.getIntegerZoom());
float scaleYA = -posA.height / 2.0;
float scaleXB = 1.0 / id.pixelsToTileUnits(widthB, state.getIntegerZoom());
float scaleXB = 1.0 / tileID.pixelsToTileUnits(widthB, state.getIntegerZoom());
float scaleYB = -posB.height / 2.0;
linesdfShader->u_patternscale_a = {{ scaleXA, scaleYA }};
@@ -121,14 +125,14 @@ void Painter::renderLine(LineBucket& bucket, const LineLayer& layer, const TileI
linepatternShader->u_blur = blur;
linepatternShader->u_pattern_size_a = {{
id.pixelsToTileUnits((*imagePosA).size[0] * properties.linePattern.value.fromScale, state.getIntegerZoom()),
tileID.pixelsToTileUnits((*imagePosA).size[0] * properties.linePattern.value.fromScale, state.getIntegerZoom()),
(*imagePosA).size[1]
}};
linepatternShader->u_pattern_tl_a = (*imagePosA).tl;
linepatternShader->u_pattern_br_a = (*imagePosA).br;
linepatternShader->u_pattern_size_b = {{
id.pixelsToTileUnits((*imagePosB).size[0] * properties.linePattern.value.toScale, state.getIntegerZoom()),
tileID.pixelsToTileUnits((*imagePosB).size[0] * properties.linePattern.value.toScale, state.getIntegerZoom()),
(*imagePosB).size[1]
}};
linepatternShader->u_pattern_tl_b = (*imagePosB).tl;

View File

@@ -6,7 +6,10 @@
using namespace mbgl;
void Painter::renderRaster(RasterBucket& bucket, const RasterLayer& layer, const TileID&, const mat4& matrix) {
void Painter::renderRaster(RasterBucket& bucket,
const RasterLayer& layer,
const UnwrappedTileID&,
const mat4& matrix) {
if (pass != RenderPass::Translucent) return;
const RasterPaintProperties& properties = layer.paint;

View File

@@ -14,7 +14,7 @@
using namespace mbgl;
void Painter::renderSDF(SymbolBucket &bucket,
const TileID &id,
const UnwrappedTileID &tileID,
const mat4 &matrix,
float sdfFontSize,
std::array<float, 2> texsize,
@@ -35,7 +35,7 @@ void Painter::renderSDF(SymbolBucket &bucket,
TranslateAnchorType translateAnchor,
float paintSize)
{
mat4 vtxMatrix = translatedMatrix(matrix, translate, id, translateAnchor);
mat4 vtxMatrix = translatedMatrix(matrix, translate, tileID, translateAnchor);
bool skewed = rotationAlignment == RotationAlignmentType::Map;
mat4 exMatrix;
@@ -44,7 +44,7 @@ void Painter::renderSDF(SymbolBucket &bucket,
if (skewed) {
matrix::identity(exMatrix);
s = id.pixelsToTileUnits(1, state.getZoom());
s = tileID.pixelsToTileUnits(1, state.getZoom());
gammaScale = 1.0f / std::cos(state.getPitch());
} else {
exMatrix = extrudeMatrix;
@@ -130,7 +130,10 @@ void Painter::renderSDF(SymbolBucket &bucket,
}
}
void Painter::renderSymbol(SymbolBucket& bucket, const SymbolLayer& layer, const TileID& id, const mat4& matrix) {
void Painter::renderSymbol(SymbolBucket& bucket,
const SymbolLayer& layer,
const UnwrappedTileID& tileID,
const mat4& matrix) {
// Abort early.
if (pass == RenderPass::Opaque) {
return;
@@ -183,7 +186,7 @@ void Painter::renderSymbol(SymbolBucket& bucket, const SymbolLayer& layer, const
if (sdf) {
renderSDF(bucket,
id,
tileID,
matrix,
1.0f,
{{ float(activeSpriteAtlas->getWidth()) / 4.0f, float(activeSpriteAtlas->getHeight()) / 4.0f }},
@@ -200,7 +203,8 @@ void Painter::renderSymbol(SymbolBucket& bucket, const SymbolLayer& layer, const
paint.iconTranslateAnchor,
layer.iconSize);
} else {
mat4 vtxMatrix = translatedMatrix(matrix, paint.iconTranslate, id, paint.iconTranslateAnchor);
mat4 vtxMatrix =
translatedMatrix(matrix, paint.iconTranslate, tileID, paint.iconTranslateAnchor);
bool skewed = layout.iconRotationAlignment == RotationAlignmentType::Map;
mat4 exMatrix;
@@ -208,7 +212,7 @@ void Painter::renderSymbol(SymbolBucket& bucket, const SymbolLayer& layer, const
if (skewed) {
matrix::identity(exMatrix);
s = id.pixelsToTileUnits(1, state.getZoom());
s = tileID.pixelsToTileUnits(1, state.getZoom());
} else {
exMatrix = extrudeMatrix;
matrix::rotate_z(exMatrix, exMatrix, state.getNorthOrientationAngle());
@@ -259,7 +263,7 @@ void Painter::renderSymbol(SymbolBucket& bucket, const SymbolLayer& layer, const
glyphAtlas->bind(glObjectStore);
renderSDF(bucket,
id,
tileID,
matrix,
24.0f,
{{ float(glyphAtlas->width) / 4, float(glyphAtlas->height) / 4 }},
@@ -283,9 +287,10 @@ void Painter::renderSymbol(SymbolBucket& bucket, const SymbolLayer& layer, const
config.program = collisionBoxShader->getID();
collisionBoxShader->u_matrix = matrix;
collisionBoxShader->u_scale = std::pow(2, state.getZoom() - id.z);
// TODO: This was the overscaled z instead of the canonical z.
collisionBoxShader->u_scale = std::pow(2, state.getZoom() - tileID.canonical.z);
collisionBoxShader->u_zoom = state.getZoom() * 10;
collisionBoxShader->u_maxzoom = (id.z + 1) * 10;
collisionBoxShader->u_maxzoom = (tileID.canonical.z + 1) * 10;
config.lineWidth = 1.0f;
setDepthSublayer(0);

View File

@@ -18,9 +18,9 @@ void RasterBucket::upload(gl::GLObjectStore& glObjectStore) {
void RasterBucket::render(Painter& painter,
const StyleLayer& layer,
const TileID& id,
const UnwrappedTileID& tileID,
const mat4& matrix) {
painter.renderRaster(*this, *layer.as<RasterLayer>(), id, matrix);
painter.renderRaster(*this, *layer.as<RasterLayer>(), tileID, matrix);
}
void RasterBucket::setImage(PremultipliedImage image) {

View File

@@ -15,7 +15,7 @@ public:
RasterBucket(gl::TexturePool&);
void upload(gl::GLObjectStore&) override;
void render(Painter&, const StyleLayer&, const TileID&, const mat4&) override;
void render(Painter&, const StyleLayer&, const UnwrappedTileID&, const mat4&) override;
bool hasData() const override;
bool needsClipping() const override;

View File

@@ -0,0 +1,14 @@
#ifndef MBGL_RENDERER_RENDERABLE
#define MBGL_RENDERER_RENDERABLE
#include <mbgl/util/clip_id.hpp>
namespace mbgl {
struct Renderable {
ClipID& clip;
};
} // namespace mbgl
#endif

View File

@@ -87,9 +87,9 @@ void SymbolBucket::upload(gl::GLObjectStore& glObjectStore) {
void SymbolBucket::render(Painter& painter,
const StyleLayer& layer,
const TileID& id,
const UnwrappedTileID& tileID,
const mat4& matrix) {
painter.renderSymbol(*this, *layer.as<SymbolLayer>(), id, matrix);
painter.renderSymbol(*this, *layer.as<SymbolLayer>(), tileID, matrix);
}
bool SymbolBucket::hasData() const { return hasTextData() || hasIconData() || !symbolInstances.empty(); }

View File

@@ -72,7 +72,7 @@ public:
~SymbolBucket() override;
void upload(gl::GLObjectStore&) override;
void render(Painter&, const StyleLayer&, const TileID&, const mat4&) override;
void render(Painter&, const StyleLayer&, const UnwrappedTileID&, const mat4&) override;
bool hasData() const override;
bool hasTextData() const;
bool hasIconData() const;

View File

@@ -162,8 +162,8 @@ void Source::load(FileSource& fileSource) {
void Source::updateMatrices(const mat4 &projMatrix, const TransformState &transform) {
for (const auto& pair : tiles) {
Tile &tile = *pair.second;
transform.matrixFor(tile.matrix, tile.id, std::min(static_cast<uint8_t>(info->maxZoom), tile.id.z));
auto& tile = *pair.second;
transform.matrixFor(tile.matrix, UnwrappedTileID{ tile.id.sourceZ, tile.id.x, tile.id.y });
matrix::multiply(tile.matrix, projMatrix, tile.matrix);
}
}
@@ -175,16 +175,16 @@ void Source::finishRender(Painter &painter) {
}
}
std::forward_list<Tile*> Source::getLoadedTiles() const {
std::forward_list<Tile*> ptrs;
auto it = ptrs.before_begin();
std::map<UnwrappedTileID, Renderable> Source::getRenderables() const {
std::map<UnwrappedTileID, Renderable> renderables;
for (const auto& pair : tiles) {
auto tile = pair.second.get();
if (tile->data->isReady() && tile->data->hasData()) {
it = ptrs.insert_after(it, tile);
auto& tile = *pair.second;
if (tile.data->isReady() && tile.data->hasData()) {
renderables.emplace(UnwrappedTileID{ tile.id.sourceZ, tile.id.x, tile.id.y },
Renderable{ tile.clip });
}
}
return ptrs;
return renderables;
}
const std::vector<Tile*>& Source::getTiles() const {

View File

@@ -1,9 +1,11 @@
#ifndef MBGL_MAP_SOURCE
#define MBGL_MAP_SOURCE
#include <mbgl/tile/tile_id.hpp>
#include <mbgl/tile/tile_data.hpp>
#include <mbgl/tile/tile_cache.hpp>
#include <mbgl/source/source_info.hpp>
#include <mbgl/renderer/renderable.hpp>
#include <mbgl/util/mat4.hpp>
#include <mbgl/util/rapidjson.hpp>
@@ -70,7 +72,7 @@ public:
void updateMatrices(const mat4 &projMatrix, const TransformState &transform);
void finishRender(Painter &painter);
std::forward_list<Tile *> getLoadedTiles() const;
std::map<UnwrappedTileID, Renderable> getRenderables() const;
const std::vector<Tile*>& getTiles() const;
std::unordered_map<std::string, std::vector<Feature>> queryRenderedFeatures(

View File

@@ -1,17 +1,6 @@
#include <mbgl/util/clip_id.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/util/math.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/tile/tile.hpp>
#include <list>
#include <vector>
#include <bitset>
#include <cassert>
#include <iostream>
#include <algorithm>
#include <iterator>
namespace mbgl {
@@ -19,140 +8,4 @@ namespace mbgl {
return os << "mask=" << rhs.mask << ",ref=" << rhs.reference;
}
ClipIDGenerator::Leaf::Leaf(TileID id_, ClipID& clip_) : id(id_), clip(clip_) {}
void ClipIDGenerator::Leaf::add(const TileID &p) {
if (p.isChildOf(id)) {
// Ensure that no already present child is a parent of the new p.
for (const auto& child : children) {
if (p.isChildOf(child))
return;
}
children.push_front(p);
}
}
bool ClipIDGenerator::Leaf::operator==(const Leaf &other) const {
return id == other.id && children == other.children;
}
void ClipIDGenerator::update(std::forward_list<Tile *> tiles) {
tiles.sort([](const Tile *a, const Tile *b) {
return a->id < b->id;
});
std::size_t size = 0;
const auto end = tiles.end();
for (auto it = tiles.begin(); it != end; it++) {
if (!*it) {
// Handle null pointers.
continue;
}
Tile &tile = **it;
// Use the actual zoom level for computing the clipping mask.
Leaf leaf{ TileID{ tile.id.sourceZ, tile.id.x, tile.id.y, tile.id.sourceZ }, tile.clip };
// Try to add all remaining ids as children. We sorted the tile list
// by z earlier, so all preceding items cannot be children of the current
// tile.
for (auto child_it = std::next(it); child_it != end; child_it++) {
// Use the actual zoom level for computing the clipping mask.
const auto& childID = (*child_it)->id;
leaf.add(TileID { childID.sourceZ, childID.x, childID.y, childID.sourceZ });
}
leaf.children.sort();
// Loop through all existing pools and try to find a matching ClipID.
auto existing = std::find(pool.begin(), pool.end(), leaf);
if (existing != pool.end()) {
leaf.clip = existing->clip;
} else {
// We haven't found an existing clip ID
leaf.clip = {};
size++;
}
pool.emplace_back(std::move(leaf));
}
if (size > 0) {
const uint32_t bit_count = util::ceil_log2(size + 1);
const std::bitset<8> mask = uint64_t(((1ul << bit_count) - 1) << bit_offset);
// We are starting our count with 1 since we need at least 1 bit set to distinguish between
// areas without any tiles whatsoever and the current area.
uint8_t count = 1;
for (auto& tile : tiles) {
tile->clip.mask |= mask;
// Assign only to clip IDs that have no value yet.
if (tile->clip.reference.none()) {
tile->clip.reference = uint32_t(count++) << bit_offset;
}
}
bit_offset += bit_count;
}
if (bit_offset > 8) {
Log::Error(Event::OpenGL, "stencil mask overflow");
}
}
template <typename Container>
bool coveredByChildren(const TileID& id, const Container& container) {
for (const auto& child : id.children()) {
const auto lower = container.lower_bound(child);
if (lower == container.end() || lower->first.w != child.w ||
(lower->first != child && !coveredByChildren(child, container))) {
return false;
}
}
// We looked at all four immediate children and verified that they're covered.
return true;
}
std::map<TileID, ClipID> ClipIDGenerator::getStencils() const {
std::map<TileID, ClipID> stencils;
// Merge everything.
for (auto& leaf : pool) {
auto res = stencils.emplace(leaf.id, leaf.clip);
if (!res.second) {
// Merge with the existing ClipID when there was already an element with the
// same tile ID.
res.first->second |= leaf.clip;
}
}
for (auto it = stencils.begin(); it != stencils.end(); ++it) {
auto& childId = it->first;
auto& childClip = it->second;
// Loop through all preceding stencils, and find all parents.
for (auto parentIt = std::reverse_iterator<std::map<TileID, ClipID>::iterator>(it);
parentIt != stencils.rend(); ++parentIt) {
auto& parentId = parentIt->first;
if (childId.isChildOf(parentId)) {
// Once we have a parent, we add the bits that this ID hasn't set yet.
const auto& parentClip = parentIt->second;
const auto mask = ~(childClip.mask & parentClip.mask);
childClip.reference |= mask & parentClip.reference;
childClip.mask |= parentClip.mask;
}
}
}
// Remove tiles that are entirely covered by children.
util::erase_if(stencils, [&] (const auto& stencil) {
return coveredByChildren(stencil.first, stencils);
});
return stencils;
}
} // namespace mbgl

View File

@@ -36,28 +36,6 @@ struct ClipID {
::std::ostream& operator<<(::std::ostream& os, const ClipID& rhs);
class ClipIDGenerator {
private:
struct Leaf {
Leaf(TileID, ClipID&);
void add(const TileID &p);
bool operator==(const Leaf &other) const;
const TileID id;
std::forward_list<TileID> children;
ClipID& clip;
};
uint8_t bit_offset = 0;
std::vector<Leaf> pool;
public:
void update(std::forward_list<Tile *> tiles);
std::map<TileID, ClipID> getStencils() const;
};
} // namespace mbgl
#endif

View File

@@ -20,7 +20,6 @@
'sources': [
'util/assert.cpp',
'util/async_task.cpp',
'util/clip_ids.cpp',
'util/geo.cpp',
'util/image.cpp',
'util/mapbox.cpp',

View File

@@ -1,411 +0,0 @@
#include <iostream>
#include <mbgl/test/util.hpp>
#include <algorithm>
#include <mbgl/util/clip_id.hpp>
#include <mbgl/tile/tile.hpp>
using namespace mbgl;
using Stencil = std::pair<const TileID, ClipID>;
template <typename T> void generate(ClipIDGenerator& generator, const T &sources) {
for (size_t j = 0; j < sources.size(); j++) {
std::forward_list<Tile *> tile_ptrs;
std::transform(sources[j].begin(), sources[j].end(), std::front_inserter(tile_ptrs), [](const std::shared_ptr<Tile> &tile) { return tile.get(); });
generator.update(tile_ptrs);
}
}
void print(const std::vector<std::vector<std::shared_ptr<Tile>>> &sources) {
for (size_t j = 0; j < sources.size(); j++) {
for (size_t i = 0; i < sources[j].size(); i++) {
std::cout << " ASSERT_EQ(ClipID(\"" << sources[j][i]->clip.mask << "\", \"" << sources[j][i]->clip.reference << "\"), sources[" << j << "][" << i << "]->clip);\n";
}
}
}
void print(const std::map<TileID, ClipID>& stencils) {
std::cout << " auto it = stencils.begin();\n";
std::cout << " ASSERT_EQ(" << stencils.size() << ", stencils.size());\n";
for (auto& stencil : stencils) {
std::cout << " ASSERT_EQ(Stencil(TileID{ " << (int)stencil.first.z << ", "
<< stencil.first.x << ", " << stencil.first.y << ", "
<< (int)stencil.first.sourceZ << " }, { \"" << stencil.second.mask.to_string()
<< "\", \"" << stencil.second.reference.to_string() << "\"}), *it++);\n";
}
std::cout << " ASSERT_EQ(stencils.end(), it);\n";
}
TEST(ClipIDs, ParentAndFourChildren) {
const std::vector<std::vector<std::shared_ptr<Tile>>> sources = {
{
std::make_shared<Tile>(TileID { 1, 0, 0, 1 }),
std::make_shared<Tile>(TileID { 1, 0, 1, 1 }),
std::make_shared<Tile>(TileID { 1, 1, 0, 1 }),
std::make_shared<Tile>(TileID { 1, 1, 1, 1 }),
std::make_shared<Tile>(TileID { 0, 0, 0, 0 }),
},
};
ClipIDGenerator generator;
generate(generator, sources);
// print(sources);
ASSERT_EQ(ClipID("00000111", "00000010"), sources[0][0]->clip);
ASSERT_EQ(ClipID("00000111", "00000011"), sources[0][1]->clip);
ASSERT_EQ(ClipID("00000111", "00000100"), sources[0][2]->clip);
ASSERT_EQ(ClipID("00000111", "00000101"), sources[0][3]->clip);
ASSERT_EQ(ClipID("00000111", "00000001"), sources[0][4]->clip);
const auto stencils = generator.getStencils();
// print(stencils);
auto it = stencils.begin();
ASSERT_EQ(4, stencils.size());
ASSERT_EQ(Stencil(TileID{ 1, 0, 0, 1 }, { "00000111", "00000010"}), *it++);
ASSERT_EQ(Stencil(TileID{ 1, 0, 1, 1 }, { "00000111", "00000011"}), *it++);
ASSERT_EQ(Stencil(TileID{ 1, 1, 0, 1 }, { "00000111", "00000100"}), *it++);
ASSERT_EQ(Stencil(TileID{ 1, 1, 1, 1 }, { "00000111", "00000101"}), *it++);
ASSERT_EQ(stencils.end(), it);
}
TEST(ClipIDs, ParentAndFourChildrenNegative) {
const std::vector<std::vector<std::shared_ptr<Tile>>> sources = {
{
std::make_shared<Tile>(TileID { 1, -2, 0, 1 }),
std::make_shared<Tile>(TileID { 1, -2, 1, 1 }),
std::make_shared<Tile>(TileID { 1, -1, 0, 1 }),
std::make_shared<Tile>(TileID { 1, -1, 1, 1 }),
std::make_shared<Tile>(TileID { 0, -1, 0, 0 }),
},
};
ClipIDGenerator generator;
generate(generator, sources);
// print(sources);
ASSERT_EQ(ClipID("00000111", "00000010"), sources[0][0]->clip);
ASSERT_EQ(ClipID("00000111", "00000011"), sources[0][1]->clip);
ASSERT_EQ(ClipID("00000111", "00000100"), sources[0][2]->clip);
ASSERT_EQ(ClipID("00000111", "00000101"), sources[0][3]->clip);
ASSERT_EQ(ClipID("00000111", "00000001"), sources[0][4]->clip);
const auto stencils = generator.getStencils();
// print(stencils);
auto it = stencils.begin();
ASSERT_EQ(4, stencils.size());
ASSERT_EQ(Stencil(TileID{ 1, -2, 0, 1 }, { "00000111", "00000010"}), *it++);
ASSERT_EQ(Stencil(TileID{ 1, -2, 1, 1 }, { "00000111", "00000011"}), *it++);
ASSERT_EQ(Stencil(TileID{ 1, -1, 0, 1 }, { "00000111", "00000100"}), *it++);
ASSERT_EQ(Stencil(TileID{ 1, -1, 1, 1 }, { "00000111", "00000101"}), *it++);
ASSERT_EQ(stencils.end(), it);
}
TEST(ClipIDs, NegativeParentAndMissingLevel) {
const std::vector<std::vector<std::shared_ptr<Tile>>> sources = {
{
std::make_shared<Tile>(TileID { 1, -1, 0, 1 }),
std::make_shared<Tile>(TileID { 2, -1, 0, 2 }),
std::make_shared<Tile>(TileID { 2, -2, 1, 2 }),
std::make_shared<Tile>(TileID { 2, -1, 1, 2 }),
std::make_shared<Tile>(TileID { 2, -2, 0, 2 }),
},
};
ClipIDGenerator generator;
generate(generator, sources);
// print(sources);
ASSERT_EQ(ClipID("00000111", "00000001"), sources[0][0]->clip);
ASSERT_EQ(ClipID("00000111", "00000100"), sources[0][1]->clip);
ASSERT_EQ(ClipID("00000111", "00000011"), sources[0][2]->clip);
ASSERT_EQ(ClipID("00000111", "00000101"), sources[0][3]->clip);
ASSERT_EQ(ClipID("00000111", "00000010"), sources[0][4]->clip);
const auto stencils = generator.getStencils();
// print(stencils);
auto it = stencils.begin();
ASSERT_EQ(4, stencils.size());
ASSERT_EQ(Stencil(TileID{ 2, -2, 0, 2 }, { "00000111", "00000010"}), *it++);
ASSERT_EQ(Stencil(TileID{ 2, -2, 1, 2 }, { "00000111", "00000011"}), *it++);
ASSERT_EQ(Stencil(TileID{ 2, -1, 0, 2 }, { "00000111", "00000100"}), *it++);
ASSERT_EQ(Stencil(TileID{ 2, -1, 1, 2 }, { "00000111", "00000101"}), *it++);
ASSERT_EQ(stencils.end(), it);
}
TEST(ClipIDs, SevenOnSameLevel) {
const std::vector<std::vector<std::shared_ptr<Tile>>> sources = {
{
std::make_shared<Tile>(TileID { 2, 0, 0, 2 }),
std::make_shared<Tile>(TileID { 2, 0, 1, 2 }),
std::make_shared<Tile>(TileID { 2, 0, 2, 2 }),
std::make_shared<Tile>(TileID { 2, 1, 0, 2 }),
std::make_shared<Tile>(TileID { 2, 1, 1, 2 }),
std::make_shared<Tile>(TileID { 2, 1, 2, 2 }),
std::make_shared<Tile>(TileID { 2, 2, 0, 2 }),
},
};
ClipIDGenerator generator;
generate(generator, sources);
// print(sources);
ASSERT_EQ(ClipID("00000111", "00000001"), sources[0][0]->clip);
ASSERT_EQ(ClipID("00000111", "00000010"), sources[0][1]->clip);
ASSERT_EQ(ClipID("00000111", "00000011"), sources[0][2]->clip);
ASSERT_EQ(ClipID("00000111", "00000100"), sources[0][3]->clip);
ASSERT_EQ(ClipID("00000111", "00000101"), sources[0][4]->clip);
ASSERT_EQ(ClipID("00000111", "00000110"), sources[0][5]->clip);
ASSERT_EQ(ClipID("00000111", "00000111"), sources[0][6]->clip);
const auto stencils = generator.getStencils();
// print(stencils);
auto it = stencils.begin();
ASSERT_EQ(7, stencils.size());
ASSERT_EQ(Stencil(TileID{ 2, 0, 0, 2 }, { "00000111", "00000001"}), *it++);
ASSERT_EQ(Stencil(TileID{ 2, 0, 1, 2 }, { "00000111", "00000010"}), *it++);
ASSERT_EQ(Stencil(TileID{ 2, 0, 2, 2 }, { "00000111", "00000011"}), *it++);
ASSERT_EQ(Stencil(TileID{ 2, 1, 0, 2 }, { "00000111", "00000100"}), *it++);
ASSERT_EQ(Stencil(TileID{ 2, 1, 1, 2 }, { "00000111", "00000101"}), *it++);
ASSERT_EQ(Stencil(TileID{ 2, 1, 2, 2 }, { "00000111", "00000110"}), *it++);
ASSERT_EQ(Stencil(TileID{ 2, 2, 0, 2 }, { "00000111", "00000111"}), *it++);
ASSERT_EQ(stencils.end(), it);
}
TEST(ClipIDs, MultipleLevels) {
const std::vector<std::vector<std::shared_ptr<Tile>>> sources = {
{
std::make_shared<Tile>(TileID { 2, 0, 0, 2 }),
std::make_shared<Tile>(TileID { 3, 0, 0, 3 }),
std::make_shared<Tile>(TileID { 3, 0, 1, 3 }),
std::make_shared<Tile>(TileID { 4, 0, 2, 4 }),
std::make_shared<Tile>(TileID { 4, 1, 2, 4 }),
std::make_shared<Tile>(TileID { 4, 0, 3, 4 }),
std::make_shared<Tile>(TileID { 4, 1, 3, 4 }),
std::make_shared<Tile>(TileID { 3, 1, 0, 3 }),
std::make_shared<Tile>(TileID { 3, 1, 1, 3 }),
std::make_shared<Tile>(TileID { 2, 1, 0, 2 }),
std::make_shared<Tile>(TileID { 3, 2, 0, 3 }),
std::make_shared<Tile>(TileID { 3, 2, 1, 3 }),
},
};
ClipIDGenerator generator;
generate(generator, sources);
// print(sources);
ASSERT_EQ(ClipID("00001111", "00000001"), sources[0][0]->clip);
ASSERT_EQ(ClipID("00001111", "00000011"), sources[0][1]->clip);
ASSERT_EQ(ClipID("00001111", "00000100"), sources[0][2]->clip);
ASSERT_EQ(ClipID("00001111", "00001001"), sources[0][3]->clip);
ASSERT_EQ(ClipID("00001111", "00001011"), sources[0][4]->clip);
ASSERT_EQ(ClipID("00001111", "00001010"), sources[0][5]->clip);
ASSERT_EQ(ClipID("00001111", "00001100"), sources[0][6]->clip);
ASSERT_EQ(ClipID("00001111", "00000101"), sources[0][7]->clip);
ASSERT_EQ(ClipID("00001111", "00000110"), sources[0][8]->clip);
ASSERT_EQ(ClipID("00001111", "00000010"), sources[0][9]->clip);
ASSERT_EQ(ClipID("00001111", "00000111"), sources[0][10]->clip);
ASSERT_EQ(ClipID("00001111", "00001000"), sources[0][11]->clip);
const auto stencils = generator.getStencils();
// print(stencils);
auto it = stencils.begin();
ASSERT_EQ(10, stencils.size());
ASSERT_EQ(Stencil(TileID{ 2, 1, 0, 2 }, { "00001111", "00000010"}), *it++);
ASSERT_EQ(Stencil(TileID{ 3, 0, 0, 3 }, { "00001111", "00000011"}), *it++);
ASSERT_EQ(Stencil(TileID{ 3, 1, 0, 3 }, { "00001111", "00000101"}), *it++);
ASSERT_EQ(Stencil(TileID{ 3, 1, 1, 3 }, { "00001111", "00000110"}), *it++);
ASSERT_EQ(Stencil(TileID{ 3, 2, 0, 3 }, { "00001111", "00000111"}), *it++);
ASSERT_EQ(Stencil(TileID{ 3, 2, 1, 3 }, { "00001111", "00001000"}), *it++);
ASSERT_EQ(Stencil(TileID{ 4, 0, 2, 4 }, { "00001111", "00001001"}), *it++);
ASSERT_EQ(Stencil(TileID{ 4, 0, 3, 4 }, { "00001111", "00001010"}), *it++);
ASSERT_EQ(Stencil(TileID{ 4, 1, 2, 4 }, { "00001111", "00001011"}), *it++);
ASSERT_EQ(Stencil(TileID{ 4, 1, 3, 4 }, { "00001111", "00001100"}), *it++);
ASSERT_EQ(stencils.end(), it);
}
TEST(ClipIDs, Bug206) {
const std::vector<std::vector<std::shared_ptr<Tile>>> sources = {
{
std::make_shared<Tile>(TileID { 10, 162, 395, 10 }),
std::make_shared<Tile>(TileID { 10, 162, 396, 10 }),
std::make_shared<Tile>(TileID { 10, 163, 395, 10 }),
std::make_shared<Tile>(TileID { 11, 326, 791, 11 }),
std::make_shared<Tile>(TileID { 12, 654, 1582, 12 }),
std::make_shared<Tile>(TileID { 12, 654, 1583, 12 }),
std::make_shared<Tile>(TileID { 12, 655, 1582, 12 }),
std::make_shared<Tile>(TileID { 12, 655, 1583, 12 }),
std::make_shared<Tile>(TileID { 10, 163, 396, 10 }),
std::make_shared<Tile>(TileID { 10, 164, 395, 10 }),
std::make_shared<Tile>(TileID { 10, 164, 396, 10 }),
},
};
ClipIDGenerator generator;
generate(generator, sources);
// print(sources);
ASSERT_EQ(ClipID("00001111", "00000001"), sources[0][0]->clip);
ASSERT_EQ(ClipID("00001111", "00000010"), sources[0][1]->clip);
ASSERT_EQ(ClipID("00001111", "00000011"), sources[0][2]->clip);
ASSERT_EQ(ClipID("00001111", "00000111"), sources[0][3]->clip);
ASSERT_EQ(ClipID("00001111", "00001000"), sources[0][4]->clip);
ASSERT_EQ(ClipID("00001111", "00001001"), sources[0][5]->clip);
ASSERT_EQ(ClipID("00001111", "00001010"), sources[0][6]->clip);
ASSERT_EQ(ClipID("00001111", "00001011"), sources[0][7]->clip);
ASSERT_EQ(ClipID("00001111", "00000100"), sources[0][8]->clip);
ASSERT_EQ(ClipID("00001111", "00000101"), sources[0][9]->clip);
ASSERT_EQ(ClipID("00001111", "00000110"), sources[0][10]->clip);
const auto stencils = generator.getStencils();
// print(stencils);
auto it = stencils.begin();
ASSERT_EQ(11, stencils.size());
ASSERT_EQ(Stencil(TileID{ 10, 162, 395, 10 }, { "00001111", "00000001"}), *it++);
ASSERT_EQ(Stencil(TileID{ 10, 162, 396, 10 }, { "00001111", "00000010"}), *it++);
ASSERT_EQ(Stencil(TileID{ 10, 163, 395, 10 }, { "00001111", "00000011"}), *it++);
ASSERT_EQ(Stencil(TileID{ 10, 163, 396, 10 }, { "00001111", "00000100"}), *it++);
ASSERT_EQ(Stencil(TileID{ 10, 164, 395, 10 }, { "00001111", "00000101"}), *it++);
ASSERT_EQ(Stencil(TileID{ 10, 164, 396, 10 }, { "00001111", "00000110"}), *it++);
ASSERT_EQ(Stencil(TileID{ 11, 326, 791, 11 }, { "00001111", "00000111"}), *it++);
ASSERT_EQ(Stencil(TileID{ 12, 654, 1582, 12 }, { "00001111", "00001000"}), *it++);
ASSERT_EQ(Stencil(TileID{ 12, 654, 1583, 12 }, { "00001111", "00001001"}), *it++);
ASSERT_EQ(Stencil(TileID{ 12, 655, 1582, 12 }, { "00001111", "00001010"}), *it++);
ASSERT_EQ(Stencil(TileID{ 12, 655, 1583, 12 }, { "00001111", "00001011"}), *it++);
ASSERT_EQ(stencils.end(), it);
}
TEST(ClipIDs, MultipleSources) {
const std::vector<std::vector<std::shared_ptr<Tile>>> sources = {
{
std::make_shared<Tile>(TileID { 0, 0, 0, 0 }),
std::make_shared<Tile>(TileID { 1, 1, 1, 1 }),
std::make_shared<Tile>(TileID { 2, 2, 1, 2 }),
std::make_shared<Tile>(TileID { 2, 2, 2, 2 }),
},
{
std::make_shared<Tile>(TileID { 0, 0, 0, 0 }),
std::make_shared<Tile>(TileID { 1, 1, 1, 1 }),
std::make_shared<Tile>(TileID { 2, 1, 1, 2 }),
std::make_shared<Tile>(TileID { 2, 2, 2, 2 }),
},
{
std::make_shared<Tile>(TileID { 1, 0, 0, 1 }),
std::make_shared<Tile>(TileID { 1, 0, 1, 1 }),
std::make_shared<Tile>(TileID { 1, 1, 0, 1 }),
std::make_shared<Tile>(TileID { 1, 1, 1, 1 }),
std::make_shared<Tile>(TileID { 2, 1, 1, 2 }),
},
};
ClipIDGenerator generator;
generate(generator, sources);
// print(sources);
ASSERT_EQ(ClipID("00000111", "00000001"), sources[0][0]->clip);
ASSERT_EQ(ClipID("00000111", "00000010"), sources[0][1]->clip);
ASSERT_EQ(ClipID("00000111", "00000011"), sources[0][2]->clip);
ASSERT_EQ(ClipID("00000111", "00000100"), sources[0][3]->clip);
ASSERT_EQ(ClipID("00011000", "00001000"), sources[1][0]->clip);
ASSERT_EQ(ClipID("00011111", "00000010"), sources[1][1]->clip);
ASSERT_EQ(ClipID("00011000", "00010000"), sources[1][2]->clip);
ASSERT_EQ(ClipID("00011111", "00000100"), sources[1][3]->clip);
ASSERT_EQ(ClipID("11100000", "00100000"), sources[2][0]->clip);
ASSERT_EQ(ClipID("11100000", "01000000"), sources[2][1]->clip);
ASSERT_EQ(ClipID("11100000", "01100000"), sources[2][2]->clip);
ASSERT_EQ(ClipID("11100000", "10000000"), sources[2][3]->clip);
ASSERT_EQ(ClipID("11111000", "00010000"), sources[2][4]->clip);
const auto stencils = generator.getStencils();
// print(stencils);
auto it = stencils.begin();
ASSERT_EQ(7, stencils.size());
ASSERT_EQ(Stencil(TileID{ 1, 0, 0, 1 }, { "11111111", "00101001"}), *it++);
ASSERT_EQ(Stencil(TileID{ 1, 0, 1, 1 }, { "11111111", "01001001"}), *it++);
ASSERT_EQ(Stencil(TileID{ 1, 1, 0, 1 }, { "11111111", "01101001"}), *it++);
ASSERT_EQ(Stencil(TileID{ 1, 1, 1, 1 }, { "11111111", "10000010"}), *it++);
ASSERT_EQ(Stencil(TileID{ 2, 1, 1, 2 }, { "11111111", "00010001"}), *it++);
ASSERT_EQ(Stencil(TileID{ 2, 2, 1, 2 }, { "11111111", "01101011"}), *it++);
ASSERT_EQ(Stencil(TileID{ 2, 2, 2, 2 }, { "11111111", "10000100"}), *it++);
ASSERT_EQ(stencils.end(), it);
}
TEST(ClipIDs, DuplicateIDs) {
const std::vector<std::vector<std::shared_ptr<Tile>>> sources = {
{
std::make_shared<Tile>(TileID { 2, 0, 0, 2 }),
std::make_shared<Tile>(TileID { 2, 0, 1, 2 }),
},
{
std::make_shared<Tile>(TileID { 2, 0, 0, 2 }),
std::make_shared<Tile>(TileID { 2, 0, 1, 2 }),
std::make_shared<Tile>(TileID { 2, 0, 1, 2 }),
}
};
ClipIDGenerator generator;
generate(generator, sources);
// print(sources);
ASSERT_EQ(ClipID("00000011", "00000001"), sources[0][0]->clip);
ASSERT_EQ(ClipID("00000011", "00000010"), sources[0][1]->clip);
ASSERT_EQ(ClipID("00000011", "00000001"), sources[1][0]->clip);
ASSERT_EQ(ClipID("00000011", "00000010"), sources[1][1]->clip);
ASSERT_EQ(ClipID("00000011", "00000010"), sources[1][2]->clip);
const auto stencils = generator.getStencils();
// print(stencils);
auto it = stencils.begin();
ASSERT_EQ(2, stencils.size());
ASSERT_EQ(Stencil(TileID{ 2, 0, 0, 2 }, { "00000011", "00000001"}), *it++);
ASSERT_EQ(Stencil(TileID{ 2, 0, 1, 2 }, { "00000011", "00000010"}), *it++);
ASSERT_EQ(stencils.end(), it);
}
TEST(ClipIDs, SecondSourceHasParentOfFirstSource) {
const std::vector<std::vector<std::shared_ptr<Tile>>> sources = {
{
std::make_shared<Tile>(TileID { 1, 0, 0, 1 }),
},
{
std::make_shared<Tile>(TileID { 0, 0, 0, 0 }),
std::make_shared<Tile>(TileID { 1, 0, 0, 1 }),
},
{
std::make_shared<Tile>(TileID { 0, 0, 0, 0 }),
}
};
ClipIDGenerator generator;
generate(generator, sources);
// print(sources);
ASSERT_EQ(ClipID("00000001", "00000001"), sources[0][0]->clip);
ASSERT_EQ(ClipID("00000010", "00000010"), sources[1][0]->clip);
ASSERT_EQ(ClipID("00000011", "00000001"), sources[1][1]->clip);
const auto stencils = generator.getStencils();
// print(stencils);
auto it = stencils.begin();
ASSERT_EQ(2, stencils.size());
ASSERT_EQ(Stencil(TileID{ 0, 0, 0, 0 }, { "00000110", "00000110"}), *it++);
ASSERT_EQ(Stencil(TileID{ 1, 0, 0, 1 }, { "00000111", "00000101"}), *it++);
ASSERT_EQ(stencils.end(), it);
}