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

Commit 32f95a9

Browse files
author
Anand Thakker
committed
Draft implementation of DDS for {text,icon}-size
Ports mapbox/mapbox-gl-js#4455
1 parent 551828d commit 32f95a9

17 files changed

+433
-59
lines changed

include/mbgl/style/data_driven_property_value.hpp

+9
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,15 @@ class DataDrivenPropertyValue {
4545
bool isDataDriven() const {
4646
return value.template is<SourceFunction<T>>() || value.template is<CompositeFunction<T>>();
4747
}
48+
49+
bool isZoomConstant() const {
50+
return !value.template is<CameraFunction<T>>() && !value.template is<CompositeFunction<T>>();
51+
}
52+
53+
template <class... Ts>
54+
auto match(Ts&&... ts) const {
55+
return value.match(std::forward<Ts>(ts)...);
56+
}
4857

4958
template <typename Evaluator>
5059
auto evaluate(const Evaluator& evaluator) const {

include/mbgl/style/function/camera_function.hpp

+18
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,24 @@ class CameraFunction {
2828
return s.evaluate(Value(double(zoom))).value_or(T());
2929
});
3030
}
31+
32+
// TODO: this is duped from composite function; dedupe it.
33+
Range<float> coveringZoomStops(float lowerZoom, float upperZoom) const {
34+
return stops.match(
35+
[&] (const auto& s) {
36+
assert(!s.stops.empty());
37+
auto minIt = s.stops.lower_bound(lowerZoom);
38+
auto maxIt = s.stops.upper_bound(upperZoom);
39+
if (minIt != s.stops.begin()) {
40+
minIt--;
41+
}
42+
return Range<float> {
43+
minIt == s.stops.end() ? s.stops.rbegin()->first : minIt->first,
44+
maxIt == s.stops.end() ? s.stops.rbegin()->first : maxIt->first
45+
};
46+
}
47+
);
48+
}
3149

3250
friend bool operator==(const CameraFunction& lhs,
3351
const CameraFunction& rhs) {

include/mbgl/style/function/composite_function.hpp

+17
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,23 @@ class CompositeFunction {
7272
}
7373
);
7474
}
75+
76+
Range<float> coveringZoomStops(float lowerZoom, float upperZoom) const {
77+
return stops.match(
78+
[&] (const auto& s) {
79+
assert(!s.stops.empty());
80+
auto minIt = s.stops.lower_bound(lowerZoom);
81+
auto maxIt = s.stops.upper_bound(upperZoom);
82+
if (minIt != s.stops.begin()) {
83+
minIt--;
84+
}
85+
return Range<float> {
86+
minIt == s.stops.end() ? s.stops.rbegin()->first : minIt->first,
87+
maxIt == s.stops.end() ? s.stops.rbegin()->first : maxIt->first
88+
};
89+
}
90+
);
91+
}
7592

7693
template <class Feature>
7794
Range<T> evaluate(Range<InnerStops> coveringStops,

src/mbgl/layout/symbol_instance.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ SymbolInstance::SymbolInstance(Anchor& anchor,
1010
const std::pair<Shaping, Shaping>& shapedTextOrientations,
1111
const PositionedIcon& shapedIcon,
1212
const SymbolLayoutProperties::Evaluated& layout,
13+
const float layoutTextSize,
1314
const bool addToBuffers,
1415
const uint32_t index_,
1516
const float textBoxScale,
@@ -26,15 +27,18 @@ SymbolInstance::SymbolInstance(Anchor& anchor,
2627
hasText(shapedTextOrientations.first || shapedTextOrientations.second),
2728
hasIcon(shapedIcon),
2829

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

3438
// Create the quads used for rendering the icon and glyphs.
3539
if (addToBuffers) {
3640
if (shapedIcon) {
37-
iconQuad = getIconQuad(anchor, shapedIcon, line, layout, iconPlacement, shapedTextOrientations.first);
41+
iconQuad = getIconQuad(anchor, shapedIcon, line, layout, layoutTextSize, iconPlacement, shapedTextOrientations.first);
3842
}
3943
if (shapedTextOrientations.first) {
4044
auto quads = getGlyphQuads(anchor, shapedTextOrientations.first, textBoxScale, line, layout, textPlacement, face);
@@ -55,6 +59,8 @@ SymbolInstance::SymbolInstance(Anchor& anchor,
5559
} else {
5660
writingModes = WritingModeType::None;
5761
}
62+
63+
5864
}
5965

6066
} // namespace mbgl

src/mbgl/layout/symbol_instance.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class SymbolInstance {
1717
const std::pair<Shaping, Shaping>& shapedTextOrientations,
1818
const PositionedIcon& shapedIcon,
1919
const style::SymbolLayoutProperties::Evaluated&,
20+
const float layoutTextSize,
2021
const bool inside,
2122
const uint32_t index,
2223
const float textBoxScale,

src/mbgl/layout/symbol_layout.cpp

+59-16
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
4141
mode(parameters.mode),
4242
spriteAtlas(spriteAtlas_),
4343
tileSize(util::tileSize * overscaling),
44-
tilePixelRatio(float(util::EXTENT) / tileSize) {
44+
tilePixelRatio(float(util::EXTENT) / tileSize),
45+
textSize(layers.at(0)->as<SymbolLayer>()->impl->layout.unevaluated.get<TextSize>()),
46+
iconSize(layers.at(0)->as<SymbolLayer>()->impl->layout.unevaluated.get<IconSize>())
47+
{
4548

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

@@ -67,12 +70,7 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
6770
if (layout.get<TextPitchAlignment>() == AlignmentType::Auto) {
6871
layout.get<TextPitchAlignment>() = layout.get<TextRotationAlignment>();
6972
}
70-
71-
textMaxSize = leader.layout.evaluate<TextSize>(PropertyEvaluationParameters(18));
72-
73-
layout.get<IconSize>() = leader.layout.evaluate<IconSize>(PropertyEvaluationParameters(zoom + 1));
74-
layout.get<TextSize>() = leader.layout.evaluate<TextSize>(PropertyEvaluationParameters(zoom + 1));
75-
73+
7674
const bool hasTextField = layout.get<TextField>().match(
7775
[&] (const std::string& s) { return !s.empty(); },
7876
[&] (const auto&) { return true; }
@@ -92,7 +90,7 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
9290
layer->as<SymbolLayer>()->impl->textPaintProperties()
9391
));
9492
}
95-
93+
9694
// Determine and load glyph ranges
9795
const size_t featureCount = sourceLayer.featureCount();
9896
for (size_t i = 0; i < featureCount; ++i) {
@@ -307,11 +305,20 @@ void SymbolLayout::addFeature(const std::size_t index,
307305
const GlyphPositions& face) {
308306
const float minScale = 0.5f;
309307
const float glyphSize = 24.0f;
310-
311-
const float fontScale = layout.get<TextSize>() / glyphSize;
308+
309+
const float layoutTextSize = layout.evaluate<TextSize>(zoom + 1, feature);
310+
const float layoutIconSize = layout.evaluate<IconSize>(zoom + 1, feature);
311+
312+
// To reduce the number of labels that jump around when zooming we need
313+
// to use a text-size value that is the same for all zoom levels.
314+
// This calculates text-size at a high zoom level so that all tiles can
315+
// use the same value when calculating anchor positions.
316+
const float textMaxSize = layout.evaluate<TextSize>(18, feature);
317+
318+
const float fontScale = layoutTextSize / glyphSize;
312319
const float textBoxScale = tilePixelRatio * fontScale;
313320
const float textMaxBoxScale = tilePixelRatio * textMaxSize / glyphSize;
314-
const float iconBoxScale = tilePixelRatio * layout.get<IconSize>();
321+
const float iconBoxScale = tilePixelRatio * layoutIconSize;
315322
const float symbolSpacing = tilePixelRatio * layout.get<SymbolSpacing>();
316323
const bool avoidEdges = layout.get<SymbolAvoidEdges>() && layout.get<SymbolPlacement>() != SymbolPlacementType::Line;
317324
const float textPadding = layout.get<TextPadding>() * tilePixelRatio;
@@ -325,6 +332,8 @@ void SymbolLayout::addFeature(const std::size_t index,
325332
: layout.get<SymbolPlacement>();
326333
const float textRepeatDistance = symbolSpacing / 2;
327334
IndexedSubfeature indexedFeature = {feature.index, sourceLayerName, bucketName, symbolInstances.size()};
335+
336+
328337

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

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

350-
symbolInstances.emplace_back(anchor, line, shapedTextOrientations, shapedIcon, layout, addToBuffers, symbolInstances.size(),
359+
symbolInstances.emplace_back(anchor, line, shapedTextOrientations, shapedIcon, layout, layoutTextSize,
360+
addToBuffers, symbolInstances.size(),
351361
textBoxScale, textPadding, textPlacement,
352362
iconBoxScale, iconPadding, iconPlacement,
353363
face, indexedFeature, index);
@@ -422,7 +432,7 @@ bool SymbolLayout::anchorIsTooClose(const std::u16string& text, const float repe
422432
}
423433

424434
std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile) {
425-
auto bucket = std::make_unique<SymbolBucket>(layout, layerPaintProperties, zoom, sdfIcons, iconsNeedLinear);
435+
auto bucket = std::make_unique<SymbolBucket>(layout, layerPaintProperties, textSize, iconSize, zoom, sdfIcons, iconsNeedLinear);
426436

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

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

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

@@ -495,7 +506,7 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile)
495506
if (glyphScale < collisionTile.maxScale) {
496507
for (const auto& symbol : symbolInstance.glyphQuads) {
497508
addSymbol(
498-
bucket->text, symbol, placementZoom,
509+
bucket->text, bucket->textSizeData, symbol, feature, textSize, placementZoom,
499510
keepUpright, textPlacement, collisionTile.config.angle, symbolInstance.writingModes);
500511
}
501512
}
@@ -506,12 +517,11 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile)
506517
collisionTile.insertFeature(symbolInstance.iconCollisionFeature, iconScale, layout.get<IconIgnorePlacement>());
507518
if (iconScale < collisionTile.maxScale && symbolInstance.iconQuad) {
508519
addSymbol(
509-
bucket->icon, *symbolInstance.iconQuad, placementZoom,
520+
bucket->icon, bucket->iconSizeData, *symbolInstance.iconQuad, feature, iconSize, placementZoom,
510521
keepUpright, iconPlacement, collisionTile.config.angle, symbolInstance.writingModes);
511522
}
512523
}
513524

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

528538
template <typename Buffer>
529539
void SymbolLayout::addSymbol(Buffer& buffer,
540+
SymbolSizeData& sizeData,
530541
const SymbolQuad& symbol,
542+
const SymbolFeature& feature,
543+
const style::DataDrivenPropertyValue<float>& size,
531544
const float placementZoom,
532545
const bool keepUpright,
533546
const style::SymbolPlacementType placement,
@@ -589,6 +602,36 @@ void SymbolLayout::addSymbol(Buffer& buffer,
589602
minZoom, maxZoom, placementZoom, glyphAngle));
590603
buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, br, tex.x + tex.w, tex.y + tex.h,
591604
minZoom, maxZoom, placementZoom, glyphAngle));
605+
606+
607+
size.match(
608+
[&] (const style::CompositeFunction<float>& fn) {
609+
const auto sizeVertex = SymbolSizeAttributes::Vertex {
610+
{{
611+
static_cast<uint16_t>(fn.evaluate(sizeData.coveringZoomStops->min, feature, sizeData.defaultSize) * 10),
612+
static_cast<uint16_t>(fn.evaluate(sizeData.coveringZoomStops->max, feature, sizeData.defaultSize) * 10),
613+
static_cast<uint16_t>(fn.evaluate(zoom + 1, feature, sizeData.defaultSize) * 10)
614+
}}
615+
};
616+
auto& vertexVector = sizeData.vertices.get<gl::VertexVector<SymbolSizeAttributes::Vertex>>();
617+
vertexVector.emplace_back(sizeVertex);
618+
vertexVector.emplace_back(sizeVertex);
619+
vertexVector.emplace_back(sizeVertex);
620+
vertexVector.emplace_back(sizeVertex);
621+
},
622+
[&] (const style::SourceFunction<float>& fn) {
623+
const auto sizeVertex = SymbolSizeAttributes::SourceFunctionVertex {
624+
{{ static_cast<uint16_t>(fn.evaluate(feature, sizeData.defaultSize) * 10) }}
625+
};
626+
627+
auto& vertexVector = sizeData.vertices.get<gl::VertexVector<SymbolSizeAttributes::SourceFunctionVertex>>();
628+
vertexVector.emplace_back(sizeVertex);
629+
vertexVector.emplace_back(sizeVertex);
630+
vertexVector.emplace_back(sizeVertex);
631+
vertexVector.emplace_back(sizeVertex);
632+
},
633+
[] (const auto&) {}
634+
);
592635

593636
// add the two triangles, referencing the four coordinates we just inserted.
594637
buffer.triangles.emplace_back(index + 0, index + 1, index + 2);

src/mbgl/layout/symbol_layout.hpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <mbgl/layout/symbol_instance.hpp>
77
#include <mbgl/text/bidi.hpp>
88
#include <mbgl/style/layers/symbol_layer_impl.hpp>
9+
#include <mbgl/programs/symbol_program.hpp>
910

1011
#include <memory>
1112
#include <map>
@@ -68,7 +69,8 @@ class SymbolLayout {
6869

6970
// Adds placed items to the buffer.
7071
template <typename Buffer>
71-
void addSymbol(Buffer&, const SymbolQuad&, float scale,
72+
void addSymbol(Buffer&, SymbolSizeData& sizeData, const SymbolQuad&, const SymbolFeature& feature,
73+
const style::DataDrivenPropertyValue<float>& size, float scale,
7274
const bool keepUpright, const style::SymbolPlacementType, const float placementAngle,
7375
WritingModeType writingModes);
7476

@@ -79,7 +81,6 @@ class SymbolLayout {
7981
const MapMode mode;
8082

8183
style::SymbolLayoutProperties::Evaluated layout;
82-
float textMaxSize;
8384

8485
SpriteAtlas& spriteAtlas;
8586

@@ -88,6 +89,9 @@ class SymbolLayout {
8889

8990
bool sdfIcons = false;
9091
bool iconsNeedLinear = false;
92+
93+
style::TextSize::UnevaluatedType textSize;
94+
style::IconSize::UnevaluatedType iconSize;
9195

9296
GlyphRangeSet ranges;
9397
std::vector<SymbolInstance> symbolInstances;

src/mbgl/programs/attributes.hpp

+7-2
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,15 @@ MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_extrude);
2525
MBGL_DEFINE_ATTRIBUTE(int16_t, 4, a_pos_offset);
2626
MBGL_DEFINE_ATTRIBUTE(uint16_t, 2, a_texture_pos);
2727

28-
template <std::size_t N>
28+
template <std::size_t N, typename T>
2929
struct a_data {
3030
static auto name() { return "a_data"; }
31-
using Type = gl::Attribute<uint8_t, N>;
31+
using Type = gl::Attribute<T, N>;
32+
};
33+
34+
struct a_size {
35+
static auto name() { return "a_size"; }
36+
using Type = gl::Attribute<uint16_t, 3>;
3237
};
3338

3439
template <std::size_t N>

0 commit comments

Comments
 (0)