Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
Draft implementation of DDS for {text,icon}-size
Browse files Browse the repository at this point in the history
  • Loading branch information
Anand Thakker committed Mar 31, 2017
1 parent 551828d commit 32f95a9
Show file tree
Hide file tree
Showing 17 changed files with 433 additions and 59 deletions.
9 changes: 9 additions & 0 deletions include/mbgl/style/data_driven_property_value.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ class DataDrivenPropertyValue {
bool isDataDriven() const {
return value.template is<SourceFunction<T>>() || value.template is<CompositeFunction<T>>();
}

bool isZoomConstant() const {
return !value.template is<CameraFunction<T>>() && !value.template is<CompositeFunction<T>>();
}

template <class... Ts>
auto match(Ts&&... ts) const {
return value.match(std::forward<Ts>(ts)...);
}

template <typename Evaluator>
auto evaluate(const Evaluator& evaluator) const {
Expand Down
18 changes: 18 additions & 0 deletions include/mbgl/style/function/camera_function.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,24 @@ class CameraFunction {
return s.evaluate(Value(double(zoom))).value_or(T());
});
}

// TODO: this is duped from composite function; dedupe it.
Range<float> coveringZoomStops(float lowerZoom, float upperZoom) const {
return stops.match(
[&] (const auto& s) {
assert(!s.stops.empty());
auto minIt = s.stops.lower_bound(lowerZoom);
auto maxIt = s.stops.upper_bound(upperZoom);
if (minIt != s.stops.begin()) {
minIt--;
}
return Range<float> {
minIt == s.stops.end() ? s.stops.rbegin()->first : minIt->first,
maxIt == s.stops.end() ? s.stops.rbegin()->first : maxIt->first
};
}
);
}

friend bool operator==(const CameraFunction& lhs,
const CameraFunction& rhs) {
Expand Down
17 changes: 17 additions & 0 deletions include/mbgl/style/function/composite_function.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,23 @@ class CompositeFunction {
}
);
}

Range<float> coveringZoomStops(float lowerZoom, float upperZoom) const {
return stops.match(
[&] (const auto& s) {
assert(!s.stops.empty());
auto minIt = s.stops.lower_bound(lowerZoom);
auto maxIt = s.stops.upper_bound(upperZoom);
if (minIt != s.stops.begin()) {
minIt--;
}
return Range<float> {
minIt == s.stops.end() ? s.stops.rbegin()->first : minIt->first,
maxIt == s.stops.end() ? s.stops.rbegin()->first : maxIt->first
};
}
);
}

template <class Feature>
Range<T> evaluate(Range<InnerStops> coveringStops,
Expand Down
8 changes: 7 additions & 1 deletion src/mbgl/layout/symbol_instance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ SymbolInstance::SymbolInstance(Anchor& anchor,
const std::pair<Shaping, Shaping>& shapedTextOrientations,
const PositionedIcon& shapedIcon,
const SymbolLayoutProperties::Evaluated& layout,
const float layoutTextSize,
const bool addToBuffers,
const uint32_t index_,
const float textBoxScale,
Expand All @@ -26,15 +27,18 @@ SymbolInstance::SymbolInstance(Anchor& anchor,
hasText(shapedTextOrientations.first || shapedTextOrientations.second),
hasIcon(shapedIcon),


// Create the collision features that will be used to check whether this symbol instance can be placed
textCollisionFeature(line, anchor, shapedTextOrientations.second ?: shapedTextOrientations.first, textBoxScale, textPadding, textPlacement, indexedFeature),
iconCollisionFeature(line, anchor, shapedIcon, iconBoxScale, iconPadding, iconPlacement, indexedFeature),
featureIndex(featureIndex_) {



// Create the quads used for rendering the icon and glyphs.
if (addToBuffers) {
if (shapedIcon) {
iconQuad = getIconQuad(anchor, shapedIcon, line, layout, iconPlacement, shapedTextOrientations.first);
iconQuad = getIconQuad(anchor, shapedIcon, line, layout, layoutTextSize, iconPlacement, shapedTextOrientations.first);
}
if (shapedTextOrientations.first) {
auto quads = getGlyphQuads(anchor, shapedTextOrientations.first, textBoxScale, line, layout, textPlacement, face);
Expand All @@ -55,6 +59,8 @@ SymbolInstance::SymbolInstance(Anchor& anchor,
} else {
writingModes = WritingModeType::None;
}


}

} // namespace mbgl
1 change: 1 addition & 0 deletions src/mbgl/layout/symbol_instance.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class SymbolInstance {
const std::pair<Shaping, Shaping>& shapedTextOrientations,
const PositionedIcon& shapedIcon,
const style::SymbolLayoutProperties::Evaluated&,
const float layoutTextSize,
const bool inside,
const uint32_t index,
const float textBoxScale,
Expand Down
75 changes: 59 additions & 16 deletions src/mbgl/layout/symbol_layout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
mode(parameters.mode),
spriteAtlas(spriteAtlas_),
tileSize(util::tileSize * overscaling),
tilePixelRatio(float(util::EXTENT) / tileSize) {
tilePixelRatio(float(util::EXTENT) / tileSize),
textSize(layers.at(0)->as<SymbolLayer>()->impl->layout.unevaluated.get<TextSize>()),
iconSize(layers.at(0)->as<SymbolLayer>()->impl->layout.unevaluated.get<IconSize>())
{

const SymbolLayer::Impl& leader = *layers.at(0)->as<SymbolLayer>()->impl;

Expand All @@ -67,12 +70,7 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
if (layout.get<TextPitchAlignment>() == AlignmentType::Auto) {
layout.get<TextPitchAlignment>() = layout.get<TextRotationAlignment>();
}

textMaxSize = leader.layout.evaluate<TextSize>(PropertyEvaluationParameters(18));

layout.get<IconSize>() = leader.layout.evaluate<IconSize>(PropertyEvaluationParameters(zoom + 1));
layout.get<TextSize>() = leader.layout.evaluate<TextSize>(PropertyEvaluationParameters(zoom + 1));


const bool hasTextField = layout.get<TextField>().match(
[&] (const std::string& s) { return !s.empty(); },
[&] (const auto&) { return true; }
Expand All @@ -92,7 +90,7 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
layer->as<SymbolLayer>()->impl->textPaintProperties()
));
}

// Determine and load glyph ranges
const size_t featureCount = sourceLayer.featureCount();
for (size_t i = 0; i < featureCount; ++i) {
Expand Down Expand Up @@ -307,11 +305,20 @@ void SymbolLayout::addFeature(const std::size_t index,
const GlyphPositions& face) {
const float minScale = 0.5f;
const float glyphSize = 24.0f;

const float fontScale = layout.get<TextSize>() / glyphSize;

const float layoutTextSize = layout.evaluate<TextSize>(zoom + 1, feature);
const float layoutIconSize = layout.evaluate<IconSize>(zoom + 1, feature);

// To reduce the number of labels that jump around when zooming we need
// to use a text-size value that is the same for all zoom levels.
// This calculates text-size at a high zoom level so that all tiles can
// use the same value when calculating anchor positions.
const float textMaxSize = layout.evaluate<TextSize>(18, feature);

const float fontScale = layoutTextSize / glyphSize;
const float textBoxScale = tilePixelRatio * fontScale;
const float textMaxBoxScale = tilePixelRatio * textMaxSize / glyphSize;
const float iconBoxScale = tilePixelRatio * layout.get<IconSize>();
const float iconBoxScale = tilePixelRatio * layoutIconSize;
const float symbolSpacing = tilePixelRatio * layout.get<SymbolSpacing>();
const bool avoidEdges = layout.get<SymbolAvoidEdges>() && layout.get<SymbolPlacement>() != SymbolPlacementType::Line;
const float textPadding = layout.get<TextPadding>() * tilePixelRatio;
Expand All @@ -325,6 +332,8 @@ void SymbolLayout::addFeature(const std::size_t index,
: layout.get<SymbolPlacement>();
const float textRepeatDistance = symbolSpacing / 2;
IndexedSubfeature indexedFeature = {feature.index, sourceLayerName, bucketName, symbolInstances.size()};



auto addSymbolInstance = [&] (const GeometryCoordinates& line, Anchor& anchor) {
// https://github.com/mapbox/vector-tile-spec/tree/master/2.1#41-layers
Expand All @@ -347,7 +356,8 @@ void SymbolLayout::addFeature(const std::size_t index,

const bool addToBuffers = mode == MapMode::Still || withinPlus0;

symbolInstances.emplace_back(anchor, line, shapedTextOrientations, shapedIcon, layout, addToBuffers, symbolInstances.size(),
symbolInstances.emplace_back(anchor, line, shapedTextOrientations, shapedIcon, layout, layoutTextSize,
addToBuffers, symbolInstances.size(),
textBoxScale, textPadding, textPlacement,
iconBoxScale, iconPadding, iconPlacement,
face, indexedFeature, index);
Expand Down Expand Up @@ -422,7 +432,7 @@ 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, zoom, sdfIcons, iconsNeedLinear);
auto bucket = std::make_unique<SymbolBucket>(layout, layerPaintProperties, textSize, iconSize, zoom, sdfIcons, iconsNeedLinear);

// Calculate which labels can be shown and when they can be shown and
// create the bufers used for rendering.
Expand Down Expand Up @@ -486,6 +496,7 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile)
iconScale = util::max(iconScale, glyphScale);
}

const auto& feature = features.at(symbolInstance.featureIndex);

// Insert final placement into collision tree and add glyphs/icons to buffers

Expand All @@ -495,7 +506,7 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile)
if (glyphScale < collisionTile.maxScale) {
for (const auto& symbol : symbolInstance.glyphQuads) {
addSymbol(
bucket->text, symbol, placementZoom,
bucket->text, bucket->textSizeData, symbol, feature, textSize, placementZoom,
keepUpright, textPlacement, collisionTile.config.angle, symbolInstance.writingModes);
}
}
Expand All @@ -506,12 +517,11 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile)
collisionTile.insertFeature(symbolInstance.iconCollisionFeature, iconScale, layout.get<IconIgnorePlacement>());
if (iconScale < collisionTile.maxScale && symbolInstance.iconQuad) {
addSymbol(
bucket->icon, *symbolInstance.iconQuad, placementZoom,
bucket->icon, bucket->iconSizeData, *symbolInstance.iconQuad, feature, iconSize, placementZoom,
keepUpright, iconPlacement, collisionTile.config.angle, symbolInstance.writingModes);
}
}

const auto& feature = features.at(symbolInstance.featureIndex);
for (auto& pair : bucket->paintPropertyBinders) {
pair.second.first.populateVertexVectors(feature, bucket->icon.vertices.vertexSize());
pair.second.second.populateVertexVectors(feature, bucket->text.vertices.vertexSize());
Expand All @@ -527,7 +537,10 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile)

template <typename Buffer>
void SymbolLayout::addSymbol(Buffer& buffer,
SymbolSizeData& sizeData,
const SymbolQuad& symbol,
const SymbolFeature& feature,
const style::DataDrivenPropertyValue<float>& size,
const float placementZoom,
const bool keepUpright,
const style::SymbolPlacementType placement,
Expand Down Expand Up @@ -589,6 +602,36 @@ void SymbolLayout::addSymbol(Buffer& buffer,
minZoom, maxZoom, placementZoom, glyphAngle));
buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, br, tex.x + tex.w, tex.y + tex.h,
minZoom, maxZoom, placementZoom, glyphAngle));


size.match(
[&] (const style::CompositeFunction<float>& fn) {
const auto sizeVertex = SymbolSizeAttributes::Vertex {
{{
static_cast<uint16_t>(fn.evaluate(sizeData.coveringZoomStops->min, feature, sizeData.defaultSize) * 10),
static_cast<uint16_t>(fn.evaluate(sizeData.coveringZoomStops->max, feature, sizeData.defaultSize) * 10),
static_cast<uint16_t>(fn.evaluate(zoom + 1, feature, sizeData.defaultSize) * 10)
}}
};
auto& vertexVector = sizeData.vertices.get<gl::VertexVector<SymbolSizeAttributes::Vertex>>();
vertexVector.emplace_back(sizeVertex);
vertexVector.emplace_back(sizeVertex);
vertexVector.emplace_back(sizeVertex);
vertexVector.emplace_back(sizeVertex);
},
[&] (const style::SourceFunction<float>& fn) {
const auto sizeVertex = SymbolSizeAttributes::SourceFunctionVertex {
{{ static_cast<uint16_t>(fn.evaluate(feature, sizeData.defaultSize) * 10) }}
};

auto& vertexVector = sizeData.vertices.get<gl::VertexVector<SymbolSizeAttributes::SourceFunctionVertex>>();
vertexVector.emplace_back(sizeVertex);
vertexVector.emplace_back(sizeVertex);
vertexVector.emplace_back(sizeVertex);
vertexVector.emplace_back(sizeVertex);
},
[] (const auto&) {}
);

// add the two triangles, referencing the four coordinates we just inserted.
buffer.triangles.emplace_back(index + 0, index + 1, index + 2);
Expand Down
8 changes: 6 additions & 2 deletions src/mbgl/layout/symbol_layout.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <mbgl/layout/symbol_instance.hpp>
#include <mbgl/text/bidi.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <mbgl/programs/symbol_program.hpp>

#include <memory>
#include <map>
Expand Down Expand Up @@ -68,7 +69,8 @@ class SymbolLayout {

// Adds placed items to the buffer.
template <typename Buffer>
void addSymbol(Buffer&, const SymbolQuad&, float scale,
void addSymbol(Buffer&, SymbolSizeData& sizeData, const SymbolQuad&, const SymbolFeature& feature,
const style::DataDrivenPropertyValue<float>& size, float scale,
const bool keepUpright, const style::SymbolPlacementType, const float placementAngle,
WritingModeType writingModes);

Expand All @@ -79,7 +81,6 @@ class SymbolLayout {
const MapMode mode;

style::SymbolLayoutProperties::Evaluated layout;
float textMaxSize;

SpriteAtlas& spriteAtlas;

Expand All @@ -88,6 +89,9 @@ class SymbolLayout {

bool sdfIcons = false;
bool iconsNeedLinear = false;

style::TextSize::UnevaluatedType textSize;
style::IconSize::UnevaluatedType iconSize;

GlyphRangeSet ranges;
std::vector<SymbolInstance> symbolInstances;
Expand Down
9 changes: 7 additions & 2 deletions src/mbgl/programs/attributes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,15 @@ MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_extrude);
MBGL_DEFINE_ATTRIBUTE(int16_t, 4, a_pos_offset);
MBGL_DEFINE_ATTRIBUTE(uint16_t, 2, a_texture_pos);

template <std::size_t N>
template <std::size_t N, typename T>
struct a_data {
static auto name() { return "a_data"; }
using Type = gl::Attribute<uint8_t, N>;
using Type = gl::Attribute<T, N>;
};

struct a_size {
static auto name() { return "a_size"; }
using Type = gl::Attribute<uint16_t, 3>;
};

template <std::size_t N>
Expand Down
Loading

0 comments on commit 32f95a9

Please sign in to comment.