summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mbgl/style/conversion/make_property_setters.hpp4
-rw-r--r--include/mbgl/style/data_driven_property_value.hpp9
-rw-r--r--include/mbgl/style/function/camera_function.hpp2
-rw-r--r--include/mbgl/style/layers/symbol_layer.hpp12
m---------mapbox-gl-js0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java12
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java216
-rw-r--r--platform/darwin/src/MGLSymbolStyleLayer.h18
-rw-r--r--platform/darwin/src/MGLSymbolStyleLayer.mm12
-rw-r--r--platform/darwin/test/MGLSymbolStyleLayerTests.mm60
-rw-r--r--src/mbgl/gl/program.hpp61
-rw-r--r--src/mbgl/layout/symbol_instance.cpp8
-rw-r--r--src/mbgl/layout/symbol_instance.hpp1
-rw-r--r--src/mbgl/layout/symbol_layout.cpp43
-rw-r--r--src/mbgl/layout/symbol_layout.hpp17
-rw-r--r--src/mbgl/programs/attributes.hpp19
-rw-r--r--src/mbgl/programs/collision_box_program.hpp2
-rw-r--r--src/mbgl/programs/line_program.hpp2
-rw-r--r--src/mbgl/programs/program.hpp55
-rw-r--r--src/mbgl/programs/symbol_program.cpp60
-rw-r--r--src/mbgl/programs/symbol_program.hpp356
-rw-r--r--src/mbgl/renderer/painter_symbol.cpp22
-rw-r--r--src/mbgl/renderer/symbol_bucket.cpp9
-rw-r--r--src/mbgl/renderer/symbol_bucket.hpp9
-rw-r--r--src/mbgl/shaders/preludes.cpp18
-rw-r--r--src/mbgl/shaders/symbol_icon.cpp51
-rw-r--r--src/mbgl/shaders/symbol_sdf.cpp82
-rw-r--r--src/mbgl/style/layers/symbol_layer.cpp12
-rw-r--r--src/mbgl/style/layers/symbol_layer_impl.cpp4
-rw-r--r--src/mbgl/style/layers/symbol_layer_impl.hpp2
-rw-r--r--src/mbgl/style/layers/symbol_layer_properties.hpp4
-rw-r--r--src/mbgl/style/paint_property_binder.hpp10
-rw-r--r--src/mbgl/text/quads.cpp3
-rw-r--r--src/mbgl/text/quads.hpp1
-rw-r--r--test/gl/bucket.test.cpp2
-rw-r--r--test/text/quads.test.cpp24
-rw-r--r--test/tile/vector_tile.test.cpp2
37 files changed, 1007 insertions, 217 deletions
diff --git a/include/mbgl/style/conversion/make_property_setters.hpp b/include/mbgl/style/conversion/make_property_setters.hpp
index 85bcd44cf3..105cca99d6 100644
--- a/include/mbgl/style/conversion/make_property_setters.hpp
+++ b/include/mbgl/style/conversion/make_property_setters.hpp
@@ -37,7 +37,7 @@ auto makeLayoutPropertySetters() {
result["icon-ignore-placement"] = &setLayoutProperty<V, SymbolLayer, PropertyValue<bool>, &SymbolLayer::setIconIgnorePlacement>;
result["icon-optional"] = &setLayoutProperty<V, SymbolLayer, PropertyValue<bool>, &SymbolLayer::setIconOptional>;
result["icon-rotation-alignment"] = &setLayoutProperty<V, SymbolLayer, PropertyValue<AlignmentType>, &SymbolLayer::setIconRotationAlignment>;
- result["icon-size"] = &setLayoutProperty<V, SymbolLayer, PropertyValue<float>, &SymbolLayer::setIconSize>;
+ result["icon-size"] = &setLayoutProperty<V, SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setIconSize>;
result["icon-text-fit"] = &setLayoutProperty<V, SymbolLayer, PropertyValue<IconTextFitType>, &SymbolLayer::setIconTextFit>;
result["icon-text-fit-padding"] = &setLayoutProperty<V, SymbolLayer, PropertyValue<std::array<float, 4>>, &SymbolLayer::setIconTextFitPadding>;
result["icon-image"] = &setLayoutProperty<V, SymbolLayer, DataDrivenPropertyValue<std::string>, &SymbolLayer::setIconImage>;
@@ -49,7 +49,7 @@ auto makeLayoutPropertySetters() {
result["text-rotation-alignment"] = &setLayoutProperty<V, SymbolLayer, PropertyValue<AlignmentType>, &SymbolLayer::setTextRotationAlignment>;
result["text-field"] = &setLayoutProperty<V, SymbolLayer, DataDrivenPropertyValue<std::string>, &SymbolLayer::setTextField>;
result["text-font"] = &setLayoutProperty<V, SymbolLayer, PropertyValue<std::vector<std::string>>, &SymbolLayer::setTextFont>;
- result["text-size"] = &setLayoutProperty<V, SymbolLayer, PropertyValue<float>, &SymbolLayer::setTextSize>;
+ result["text-size"] = &setLayoutProperty<V, SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setTextSize>;
result["text-max-width"] = &setLayoutProperty<V, SymbolLayer, PropertyValue<float>, &SymbolLayer::setTextMaxWidth>;
result["text-line-height"] = &setLayoutProperty<V, SymbolLayer, PropertyValue<float>, &SymbolLayer::setTextLineHeight>;
result["text-letter-spacing"] = &setLayoutProperty<V, SymbolLayer, PropertyValue<float>, &SymbolLayer::setTextLetterSpacing>;
diff --git a/include/mbgl/style/data_driven_property_value.hpp b/include/mbgl/style/data_driven_property_value.hpp
index 3f9ac69436..5acf800840 100644
--- a/include/mbgl/style/data_driven_property_value.hpp
+++ b/include/mbgl/style/data_driven_property_value.hpp
@@ -45,6 +45,15 @@ public:
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 {
diff --git a/include/mbgl/style/function/camera_function.hpp b/include/mbgl/style/function/camera_function.hpp
index 5636b1663c..2e4aac2238 100644
--- a/include/mbgl/style/function/camera_function.hpp
+++ b/include/mbgl/style/function/camera_function.hpp
@@ -28,7 +28,7 @@ public:
return s.evaluate(Value(double(zoom))).value_or(T());
});
}
-
+
friend bool operator==(const CameraFunction& lhs,
const CameraFunction& rhs) {
return lhs.stops == rhs.stops;
diff --git a/include/mbgl/style/layers/symbol_layer.hpp b/include/mbgl/style/layers/symbol_layer.hpp
index 853a71bef2..6e29faa949 100644
--- a/include/mbgl/style/layers/symbol_layer.hpp
+++ b/include/mbgl/style/layers/symbol_layer.hpp
@@ -59,9 +59,9 @@ public:
PropertyValue<AlignmentType> getIconRotationAlignment() const;
void setIconRotationAlignment(PropertyValue<AlignmentType>);
- static PropertyValue<float> getDefaultIconSize();
- PropertyValue<float> getIconSize() const;
- void setIconSize(PropertyValue<float>);
+ static DataDrivenPropertyValue<float> getDefaultIconSize();
+ DataDrivenPropertyValue<float> getIconSize() const;
+ void setIconSize(DataDrivenPropertyValue<float>);
static PropertyValue<IconTextFitType> getDefaultIconTextFit();
PropertyValue<IconTextFitType> getIconTextFit() const;
@@ -107,9 +107,9 @@ public:
PropertyValue<std::vector<std::string>> getTextFont() const;
void setTextFont(PropertyValue<std::vector<std::string>>);
- static PropertyValue<float> getDefaultTextSize();
- PropertyValue<float> getTextSize() const;
- void setTextSize(PropertyValue<float>);
+ static DataDrivenPropertyValue<float> getDefaultTextSize();
+ DataDrivenPropertyValue<float> getTextSize() const;
+ void setTextSize(DataDrivenPropertyValue<float>);
static PropertyValue<float> getDefaultTextMaxWidth();
PropertyValue<float> getTextMaxWidth() const;
diff --git a/mapbox-gl-js b/mapbox-gl-js
-Subproject aa329d31f4d750c8481a017b861d72c38d722fe
+Subproject e3b2df28079f350747db177e0707698847d0bcd
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java
index 269a777050..e37245000e 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java
@@ -1526,11 +1526,11 @@ public class PropertyFactory {
/**
* Scale factor for icon. 1 is original size, 3 triples the size.
*
- * @param <Z> the zoom parameter type
- * @param function a wrapper {@link CameraFunction} for Float
+ * @param <T> the function input type
+ * @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
- public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> iconSize(CameraFunction<Z, Float> function) {
+ public static <T> PropertyValue<Function<T, Float>> iconSize(Function<T, Float> function) {
return new LayoutPropertyValue<>("icon-size", function);
}
@@ -1802,11 +1802,11 @@ public class PropertyFactory {
/**
* Font size.
*
- * @param <Z> the zoom parameter type
- * @param function a wrapper {@link CameraFunction} for Float
+ * @param <T> the function input type
+ * @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
- public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> textSize(CameraFunction<Z, Float> function) {
+ public static <T> PropertyValue<Function<T, Float>> textSize(Function<T, Float> function) {
return new LayoutPropertyValue<>("text-size", function);
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java
index e8af375d66..d81965f2c9 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java
@@ -383,6 +383,114 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
+ public void testIconSizeAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-size");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconSize(property("FeaturePropertyA", Stops.<Float>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getIconSize());
+ assertNotNull(layer.getIconSize().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconSize().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconSize().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getIconSize().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testIconSizeAsExponentialSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-size");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconSize(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(0.3f, iconSize(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconSize());
+ assertNotNull(layer.getIconSize().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconSize().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconSize().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getIconSize().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testIconSizeAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-size");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconSize(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop(1.0f, iconSize(0.3f))
+ )
+ ).withDefaultValue(iconSize(0.3f))
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconSize());
+ assertNotNull(layer.getIconSize().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconSize().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconSize().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getIconSize().getFunction().getStops().getClass());
+ assertNotNull(((SourceFunction) layer.getIconSize().getFunction()).getDefaultValue());
+ assertNotNull(((SourceFunction) layer.getIconSize().getFunction()).getDefaultValue().getValue());
+ assertEquals(0.3f, ((SourceFunction) layer.getIconSize().getFunction()).getDefaultValue().getValue());
+ }
+
+ @Test
+ public void testIconSizeAsCompositeFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-size");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconSize(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, iconSize(0.9f))
+ ).withBase(0.5f)
+ ).withDefaultValue(iconSize(0.3f))
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconSize());
+ assertNotNull(layer.getIconSize().getFunction());
+ assertEquals(CompositeFunction.class, layer.getIconSize().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getIconSize().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getIconSize().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.getIconSize().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getIconSize().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+
+ @Test
public void testIconTextFitAsConstant() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-text-fit");
@@ -1075,6 +1183,114 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
+ public void testTextSizeAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-size");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textSize(property("FeaturePropertyA", Stops.<Float>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getTextSize());
+ assertNotNull(layer.getTextSize().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextSize().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextSize().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getTextSize().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testTextSizeAsExponentialSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-size");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textSize(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(0.3f, textSize(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextSize());
+ assertNotNull(layer.getTextSize().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextSize().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextSize().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getTextSize().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testTextSizeAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-size");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textSize(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop(1.0f, textSize(0.3f))
+ )
+ ).withDefaultValue(textSize(0.3f))
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextSize());
+ assertNotNull(layer.getTextSize().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextSize().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextSize().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getTextSize().getFunction().getStops().getClass());
+ assertNotNull(((SourceFunction) layer.getTextSize().getFunction()).getDefaultValue());
+ assertNotNull(((SourceFunction) layer.getTextSize().getFunction()).getDefaultValue().getValue());
+ assertEquals(0.3f, ((SourceFunction) layer.getTextSize().getFunction()).getDefaultValue().getValue());
+ }
+
+ @Test
+ public void testTextSizeAsCompositeFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-size");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textSize(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, textSize(0.9f))
+ ).withBase(0.5f)
+ ).withDefaultValue(textSize(0.3f))
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextSize());
+ assertNotNull(layer.getTextSize().getFunction());
+ assertEquals(CompositeFunction.class, layer.getTextSize().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getTextSize().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getTextSize().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.getTextSize().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getTextSize().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+
+ @Test
public void testTextMaxWidthAsConstant() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("text-max-width");
diff --git a/platform/darwin/src/MGLSymbolStyleLayer.h b/platform/darwin/src/MGLSymbolStyleLayer.h
index 2c32b36c31..7040610093 100644
--- a/platform/darwin/src/MGLSymbolStyleLayer.h
+++ b/platform/darwin/src/MGLSymbolStyleLayer.h
@@ -537,6 +537,15 @@ MGL_EXPORT
* `MGLCameraStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconScale;
@@ -919,6 +928,15 @@ MGL_EXPORT
* `MGLCameraStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textFontSize;
diff --git a/platform/darwin/src/MGLSymbolStyleLayer.mm b/platform/darwin/src/MGLSymbolStyleLayer.mm
index c01877f8dc..0f7953311e 100644
--- a/platform/darwin/src/MGLSymbolStyleLayer.mm
+++ b/platform/darwin/src/MGLSymbolStyleLayer.mm
@@ -356,7 +356,7 @@ namespace mbgl {
- (void)setIconScale:(MGLStyleValue<NSNumber *> *)iconScale {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(iconScale);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(iconScale);
self.rawLayer->setIconSize(mbglValue);
}
@@ -365,9 +365,9 @@ namespace mbgl {
auto propertyValue = self.rawLayer->getIconSize();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultIconSize());
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconSize());
}
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setIconSize:(MGLStyleValue<NSNumber *> *)iconSize {
@@ -657,7 +657,7 @@ namespace mbgl {
- (void)setTextFontSize:(MGLStyleValue<NSNumber *> *)textFontSize {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(textFontSize);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(textFontSize);
self.rawLayer->setTextSize(mbglValue);
}
@@ -666,9 +666,9 @@ namespace mbgl {
auto propertyValue = self.rawLayer->getTextSize();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextSize());
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextSize());
}
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setTextSize:(MGLStyleValue<NSNumber *> *)textSize {
diff --git a/platform/darwin/test/MGLSymbolStyleLayerTests.mm b/platform/darwin/test/MGLSymbolStyleLayerTests.mm
index eee61dd5d7..367ebf363c 100644
--- a/platform/darwin/test/MGLSymbolStyleLayerTests.mm
+++ b/platform/darwin/test/MGLSymbolStyleLayerTests.mm
@@ -405,7 +405,7 @@
MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.iconScale = constantStyleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getIconSize(), propertyValue,
@"Setting iconScale to a constant value should update icon-size.");
XCTAssertEqualObjects(layer.iconScale, constantStyleValue,
@@ -422,6 +422,29 @@
XCTAssertEqualObjects(layer.iconScale, functionStyleValue,
@"iconScale should round-trip camera functions.");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.iconScale = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getIconSize(), propertyValue,
+ @"Setting iconScale to a source function should update icon-size.");
+ XCTAssertEqualObjects(layer.iconScale, functionStyleValue,
+ @"iconScale should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.iconScale = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getIconSize(), propertyValue,
+ @"Setting iconScale to a composite function should update icon-size.");
+ XCTAssertEqualObjects(layer.iconScale, functionStyleValue,
+ @"iconScale should round-trip composite functions.");
layer.iconScale = nil;
@@ -429,11 +452,6 @@
@"Unsetting iconScale should return icon-size to the default value.");
XCTAssertEqualObjects(layer.iconScale, defaultStyleValue,
@"iconScale should return the default value after being unset.");
-
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconScale = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconScale = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
// icon-text-fit
@@ -952,7 +970,7 @@
MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.textFontSize = constantStyleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextSize(), propertyValue,
@"Setting textFontSize to a constant value should update text-size.");
XCTAssertEqualObjects(layer.textFontSize, constantStyleValue,
@@ -969,6 +987,29 @@
XCTAssertEqualObjects(layer.textFontSize, functionStyleValue,
@"textFontSize should round-trip camera functions.");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.textFontSize = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getTextSize(), propertyValue,
+ @"Setting textFontSize to a source function should update text-size.");
+ XCTAssertEqualObjects(layer.textFontSize, functionStyleValue,
+ @"textFontSize should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.textFontSize = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getTextSize(), propertyValue,
+ @"Setting textFontSize to a composite function should update text-size.");
+ XCTAssertEqualObjects(layer.textFontSize, functionStyleValue,
+ @"textFontSize should round-trip composite functions.");
layer.textFontSize = nil;
@@ -976,11 +1017,6 @@
@"Unsetting textFontSize should return text-size to the default value.");
XCTAssertEqualObjects(layer.textFontSize, defaultStyleValue,
@"textFontSize should return the default value after being unset.");
-
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textFontSize = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textFontSize = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
// text-ignore-placement
diff --git a/src/mbgl/gl/program.hpp b/src/mbgl/gl/program.hpp
index 7d7fca5263..1b23abe2b1 100644
--- a/src/mbgl/gl/program.hpp
+++ b/src/mbgl/gl/program.hpp
@@ -8,6 +8,12 @@
#include <mbgl/gl/attribute.hpp>
#include <mbgl/gl/uniform.hpp>
+#include <mbgl/util/io.hpp>
+#include <mbgl/programs/binary_program.hpp>
+#include <mbgl/programs/program_parameters.hpp>
+#include <mbgl/shaders/shaders.hpp>
+
+
#include <string>
namespace mbgl {
@@ -37,6 +43,61 @@ public:
attributeLocations(Attributes::loadNamedLocations(binaryProgram)),
uniformsState(Uniforms::loadNamedLocations(binaryProgram)) {
}
+
+ static Program createProgram(gl::Context& context,
+ const ProgramParameters& programParameters,
+ const char* name,
+ const char* vertexSource_,
+ const char* fragmentSource_) {
+#if MBGL_HAS_BINARY_PROGRAMS
+ if (!programParameters.cacheDir.empty() && context.supportsProgramBinaries()) {
+ const std::string vertexSource =
+ shaders::vertexSource(programParameters, vertexSource_);
+ const std::string fragmentSource =
+ shaders::fragmentSource(programParameters, fragmentSource_);
+ const std::string cachePath =
+ shaders::programCachePath(programParameters, name);
+ const std::string identifier =
+ shaders::programIdentifier(vertexSource, fragmentSource_);
+
+ try {
+ if (auto cachedBinaryProgram = util::readFile(cachePath)) {
+ const BinaryProgram binaryProgram(std::move(*cachedBinaryProgram));
+ if (binaryProgram.identifier() == identifier) {
+ return Program { context, binaryProgram };
+ } else {
+ Log::Warning(Event::OpenGL,
+ "Cached program %s changed. Recompilation required.",
+ name);
+ }
+ }
+ } catch (std::runtime_error& error) {
+ Log::Warning(Event::OpenGL, "Could not load cached program: %s",
+ error.what());
+ }
+
+ // Compile the shader
+ Program result{ context, vertexSource, fragmentSource };
+
+ try {
+ if (const auto binaryProgram =
+ result.template get<BinaryProgram>(context, identifier)) {
+ util::write_file(cachePath, binaryProgram->serialize());
+ Log::Warning(Event::OpenGL, "Caching program in: %s", cachePath.c_str());
+ }
+ } catch (std::runtime_error& error) {
+ Log::Warning(Event::OpenGL, "Failed to cache program: %s", error.what());
+ }
+
+ return std::move(result);
+ }
+#endif
+ (void)name;
+ return Program {
+ context, shaders::vertexSource(programParameters, vertexSource_),
+ shaders::fragmentSource(programParameters, fragmentSource_)
+ };
+ }
template <class BinaryProgram>
optional<BinaryProgram> get(Context& context, const std::string& identifier) const {
diff --git a/src/mbgl/layout/symbol_instance.cpp b/src/mbgl/layout/symbol_instance.cpp
index 8bdc528bbb..2a3bf068c1 100644
--- a/src/mbgl/layout/symbol_instance.cpp
+++ b/src/mbgl/layout/symbol_instance.cpp
@@ -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,
@@ -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);
@@ -55,6 +59,8 @@ SymbolInstance::SymbolInstance(Anchor& anchor,
} else {
writingModes = WritingModeType::None;
}
+
+
}
} // namespace mbgl
diff --git a/src/mbgl/layout/symbol_instance.hpp b/src/mbgl/layout/symbol_instance.hpp
index 70ebfeefa2..efe6cb05aa 100644
--- a/src/mbgl/layout/symbol_instance.hpp
+++ b/src/mbgl/layout/symbol_instance.hpp
@@ -17,6 +17,7 @@ public:
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,
diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp
index 978caabd70..907e60a598 100644
--- a/src/mbgl/layout/symbol_layout.cpp
+++ b/src/mbgl/layout/symbol_layout.cpp
@@ -50,7 +50,10 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
mode(parameters.mode),
spriteAtlasMapIndex(_spriteAtlasMapIndex),
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;
@@ -77,11 +80,6 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
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 hasText = has<TextField>(layout) && !layout.get<TextFont>().empty();
const bool hasIcon = has<IconImage>(layout);
@@ -298,11 +296,20 @@ void SymbolLayout::addFeature(const std::size_t index,
const GlyphPositions& glyphs) {
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;
@@ -316,7 +323,7 @@ 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
// +-------------------+ Symbols with anchors located on tile edges
@@ -338,7 +345,9 @@ void SymbolLayout::addFeature(const std::size_t index,
const bool addToBuffers = mode == MapMode::Still || withinPlus0;
- symbolInstances.emplace_back(anchor, line, shapedTextOrientations, shapedIcon, layout.evaluate(zoom, feature), addToBuffers, symbolInstances.size(),
+ symbolInstances.emplace_back(anchor, line, shapedTextOrientations, shapedIcon,
+ layout.evaluate(zoom, feature), layoutTextSize,
+ addToBuffers, symbolInstances.size(),
textBoxScale, textPadding, textPlacement,
iconBoxScale, iconPadding, iconPlacement,
glyphs, indexedFeature, index);
@@ -413,7 +422,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.
@@ -477,6 +486,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
@@ -486,7 +496,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->textSizeBinder, symbol, feature, placementZoom,
keepUpright, textPlacement, collisionTile.config.angle, symbolInstance.writingModes);
}
}
@@ -497,12 +507,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->iconSizeBinder, *symbolInstance.iconQuad, feature, 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());
@@ -518,7 +527,9 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile)
template <typename Buffer>
void SymbolLayout::addSymbol(Buffer& buffer,
+ SymbolSizeBinder& sizeBinder,
const SymbolQuad& symbol,
+ const SymbolFeature& feature,
const float placementZoom,
const bool keepUpright,
const style::SymbolPlacementType placement,
@@ -580,6 +591,8 @@ 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));
+
+ sizeBinder.populateVertexVector(feature);
// add the two triangles, referencing the four coordinates we just inserted.
buffer.triangles.emplace_back(index + 0, index + 1, index + 2);
diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp
index d79ccb3273..4ec84f0f58 100644
--- a/src/mbgl/layout/symbol_layout.hpp
+++ b/src/mbgl/layout/symbol_layout.hpp
@@ -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>
@@ -64,9 +65,15 @@ private:
// Adds placed items to the buffer.
template <typename Buffer>
- void addSymbol(Buffer&, const SymbolQuad&, float scale,
- const bool keepUpright, const style::SymbolPlacementType, const float placementAngle,
- WritingModeType writingModes);
+ void addSymbol(Buffer&,
+ SymbolSizeBinder& sizeBinder,
+ const SymbolQuad&,
+ const SymbolFeature& feature,
+ float scale,
+ const bool keepUpright,
+ const style::SymbolPlacementType,
+ const float placementAngle,
+ WritingModeType writingModes);
const std::string sourceLayerName;
const std::string bucketName;
@@ -75,7 +82,6 @@ private:
const MapMode mode;
style::SymbolLayoutProperties::PossiblyEvaluated layout;
- float textMaxSize;
uintptr_t spriteAtlasMapIndex; // Actually a pointer to the SpriteAtlas for this symbol's layer, but don't use it from worker threads!
@@ -84,6 +90,9 @@ private:
bool sdfIcons = false;
bool iconsNeedLinear = false;
+
+ style::TextSize::UnevaluatedType textSize;
+ style::IconSize::UnevaluatedType iconSize;
std::vector<SymbolInstance> symbolInstances;
std::vector<SymbolFeature> features;
diff --git a/src/mbgl/programs/attributes.hpp b/src/mbgl/programs/attributes.hpp
index 7d39c04395..e9ca18927e 100644
--- a/src/mbgl/programs/attributes.hpp
+++ b/src/mbgl/programs/attributes.hpp
@@ -8,6 +8,16 @@
namespace mbgl {
namespace attributes {
+/*
+ * Pack a pair of values, interpreted as uint8's, into a single float.
+ * Used to conserve vertex attributes. Values are unpacked in the vertex
+ * shader using the `unpack_float()` function, defined in _prelude.vertex.glsl.
+ */
+template <typename T>
+inline uint16_t packUint8Pair(T a, T b) {
+ return static_cast<uint16_t>(a) * 256 + static_cast<uint16_t>(b);
+}
+
// Layout attributes
MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_pos);
@@ -15,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 <typename T, std::size_t N>
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>
diff --git a/src/mbgl/programs/collision_box_program.hpp b/src/mbgl/programs/collision_box_program.hpp
index 78ed6aa0c9..89b69484fd 100644
--- a/src/mbgl/programs/collision_box_program.hpp
+++ b/src/mbgl/programs/collision_box_program.hpp
@@ -18,7 +18,7 @@ MBGL_DEFINE_UNIFORM_SCALAR(float, u_maxzoom);
using CollisionBoxAttributes = gl::Attributes<
attributes::a_pos,
attributes::a_extrude,
- attributes::a_data<2>>;
+ attributes::a_data<uint8_t, 2>>;
class CollisionBoxProgram : public Program<
shaders::collision_box,
diff --git a/src/mbgl/programs/line_program.hpp b/src/mbgl/programs/line_program.hpp
index 842b4cc602..b2e55a4f3b 100644
--- a/src/mbgl/programs/line_program.hpp
+++ b/src/mbgl/programs/line_program.hpp
@@ -32,7 +32,7 @@ MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_gl_units_to_pixels);
struct LineLayoutAttributes : gl::Attributes<
attributes::a_pos,
- attributes::a_data<4>>
+ attributes::a_data<uint8_t, 4>>
{};
class LineProgram : public Program<
diff --git a/src/mbgl/programs/program.hpp b/src/mbgl/programs/program.hpp
index 8925bc75d6..7eec15e755 100644
--- a/src/mbgl/programs/program.hpp
+++ b/src/mbgl/programs/program.hpp
@@ -34,55 +34,12 @@ public:
ProgramType program;
Program(gl::Context& context, const ProgramParameters& programParameters)
- : program([&] {
-#if MBGL_HAS_BINARY_PROGRAMS
- if (!programParameters.cacheDir.empty() && context.supportsProgramBinaries()) {
- const std::string vertexSource =
- shaders::vertexSource(programParameters, Shaders::vertexSource);
- const std::string fragmentSource =
- shaders::fragmentSource(programParameters, Shaders::fragmentSource);
- const std::string cachePath =
- shaders::programCachePath(programParameters, Shaders::name);
- const std::string identifier =
- shaders::programIdentifier(vertexSource, fragmentSource);
-
- try {
- if (auto cachedBinaryProgram = util::readFile(cachePath)) {
- const BinaryProgram binaryProgram(std::move(*cachedBinaryProgram));
- if (binaryProgram.identifier() == identifier) {
- return ProgramType{ context, binaryProgram };
- } else {
- Log::Warning(Event::OpenGL,
- "Cached program %s changed. Recompilation required.",
- Shaders::name);
- }
- }
- } catch (std::runtime_error& error) {
- Log::Warning(Event::OpenGL, "Could not load cached program: %s",
- error.what());
- }
-
- // Compile the shader
- ProgramType result{ context, vertexSource, fragmentSource };
-
- try {
- if (const auto binaryProgram =
- result.template get<BinaryProgram>(context, identifier)) {
- util::write_file(cachePath, binaryProgram->serialize());
- Log::Warning(Event::OpenGL, "Caching program in: %s", cachePath.c_str());
- }
- } catch (std::runtime_error& error) {
- Log::Warning(Event::OpenGL, "Failed to cache program: %s", error.what());
- }
-
- return std::move(result);
- }
-#endif
- return ProgramType{
- context, shaders::vertexSource(programParameters, Shaders::vertexSource),
- shaders::fragmentSource(programParameters, Shaders::fragmentSource)
- };
- }()) {
+ : program(ProgramType::createProgram(
+ context,
+ programParameters,
+ Shaders::name,
+ Shaders::vertexSource,
+ Shaders::fragmentSource)) {
}
template <class DrawMode>
diff --git a/src/mbgl/programs/symbol_program.cpp b/src/mbgl/programs/symbol_program.cpp
index 19fe2bc2f6..86f61c4ad2 100644
--- a/src/mbgl/programs/symbol_program.cpp
+++ b/src/mbgl/programs/symbol_program.cpp
@@ -3,6 +3,7 @@
#include <mbgl/map/transform_state.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <mbgl/util/enum.hpp>
+#include <mbgl/math/clamp.hpp>
namespace mbgl {
@@ -10,51 +11,66 @@ using namespace style;
static_assert(sizeof(SymbolLayoutVertex) == 16, "expected SymbolLayoutVertex size");
+std::unique_ptr<SymbolSizeBinder> SymbolSizeBinder::create(const float tileZoom,
+ const style::DataDrivenPropertyValue<float>& sizeProperty,
+ const float defaultValue) {
+ return sizeProperty.match(
+ [&] (const style::CompositeFunction<float>& function) -> std::unique_ptr<SymbolSizeBinder> {
+ return std::make_unique<CompositeFunctionSymbolSizeBinder>(tileZoom, function, defaultValue);
+ },
+ [&] (const style::SourceFunction<float>& function) {
+ return std::make_unique<SourceFunctionSymbolSizeBinder>(tileZoom, function, defaultValue);
+ },
+ [&] (const auto& value) -> std::unique_ptr<SymbolSizeBinder> {
+ return std::make_unique<ConstantSymbolSizeBinder>(tileZoom, value, defaultValue);
+ }
+ );
+}
+
template <class Values, class...Args>
-Values makeValues(const style::SymbolPropertyValues& values,
+Values makeValues(const bool isText,
+ const style::SymbolPropertyValues& values,
const Size& texsize,
const std::array<float, 2>& pixelsToGLUnits,
const RenderTile& tile,
const TransformState& state,
Args&&... args) {
std::array<float, 2> extrudeScale;
-
- const float scale = values.paintSize / values.sdfScale;
if (values.pitchAlignment == AlignmentType::Map) {
- extrudeScale.fill(tile.id.pixelsToTileUnits(1, state.getZoom()) * scale);
+ extrudeScale.fill(tile.id.pixelsToTileUnits(1, state.getZoom()));
} else {
extrudeScale = {{
- pixelsToGLUnits[0] * scale * state.getCameraToCenterDistance(),
- pixelsToGLUnits[1] * scale * state.getCameraToCenterDistance()
+ pixelsToGLUnits[0] * state.getCameraToCenterDistance(),
+ pixelsToGLUnits[1] * state.getCameraToCenterDistance()
}};
}
-
- // adjust min/max zooms for variable font sies
- float zoomAdjust = std::log(values.paintSize / values.layoutSize) / std::log(2);
-
+
return Values {
uniforms::u_matrix::Value{ tile.translatedMatrix(values.translate,
values.translateAnchor,
state) },
uniforms::u_extrude_scale::Value{ extrudeScale },
uniforms::u_texsize::Value{ std::array<float, 2> {{ float(texsize.width) / 4, float(texsize.height) / 4 }} },
- uniforms::u_zoom::Value{ float((state.getZoom() - zoomAdjust) * 10) },
+ uniforms::u_zoom::Value{ float(state.getZoom()) },
uniforms::u_rotate_with_map::Value{ values.rotationAlignment == AlignmentType::Map },
uniforms::u_texture::Value{ 0 },
uniforms::u_fadetexture::Value{ 1 },
+ uniforms::u_is_text::Value{ isText },
std::forward<Args>(args)...
};
}
SymbolIconProgram::UniformValues
-SymbolIconProgram::uniformValues(const style::SymbolPropertyValues& values,
+SymbolIconProgram::uniformValues(const bool isText,
+ const style::SymbolPropertyValues& values,
const Size& texsize,
const std::array<float, 2>& pixelsToGLUnits,
const RenderTile& tile,
const TransformState& state)
{
return makeValues<SymbolIconProgram::UniformValues>(
+ isText,
values,
texsize,
pixelsToGLUnits,
@@ -64,26 +80,26 @@ SymbolIconProgram::uniformValues(const style::SymbolPropertyValues& values,
}
template <class PaintProperties>
-typename SymbolSDFProgram<PaintProperties>::UniformValues SymbolSDFProgram<PaintProperties>::uniformValues(const style::SymbolPropertyValues& values,
- const Size& texsize,
- const std::array<float, 2>& pixelsToGLUnits,
- const RenderTile& tile,
- const TransformState& state,
- const SymbolSDFPart part)
+typename SymbolSDFProgram<PaintProperties>::UniformValues SymbolSDFProgram<PaintProperties>::uniformValues(
+ const bool isText,
+ const style::SymbolPropertyValues& values,
+ const Size& texsize,
+ const std::array<float, 2>& pixelsToGLUnits,
+ const RenderTile& tile,
+ const TransformState& state,
+ const SymbolSDFPart part)
{
- const float scale = values.paintSize / values.sdfScale;
-
- const float gammaScale = scale * (values.pitchAlignment == AlignmentType::Map
+ const float gammaScale = (values.pitchAlignment == AlignmentType::Map
? std::cos(state.getPitch())
: 1.0) * state.getCameraToCenterDistance();
return makeValues<SymbolSDFProgram<PaintProperties>::UniformValues>(
+ isText,
values,
texsize,
pixelsToGLUnits,
tile,
state,
- uniforms::u_font_scale::Value{ scale },
uniforms::u_gamma_scale::Value{ gammaScale },
uniforms::u_pitch::Value{ state.getPitch() },
uniforms::u_bearing::Value{ -1.0f * state.getAngle() },
diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp
index fdd1aa5c3b..ae50e790be 100644
--- a/src/mbgl/programs/symbol_program.hpp
+++ b/src/mbgl/programs/symbol_program.hpp
@@ -1,6 +1,10 @@
#pragma once
-#include <mbgl/programs/program.hpp>
+#include <mbgl/gl/context.hpp>
+#include <mbgl/gl/program.hpp>
+#include <mbgl/math/clamp.hpp>
+#include <mbgl/util/interpolate.hpp>
+
#include <mbgl/programs/attributes.hpp>
#include <mbgl/programs/uniforms.hpp>
#include <mbgl/shaders/symbol_icon.hpp>
@@ -10,6 +14,7 @@
#include <mbgl/style/layers/symbol_layer_properties.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
+
#include <cmath>
#include <array>
@@ -30,14 +35,19 @@ MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_texture);
MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_fadetexture);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_aspect_ratio);
MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_halo);
-MBGL_DEFINE_UNIFORM_SCALAR(float, u_font_scale);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_gamma_scale);
+
+MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_text);
+MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_size_zoom_constant);
+MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_size_feature_constant);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_size_t);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_size);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_layout_size);
} // namespace uniforms
struct SymbolLayoutAttributes : gl::Attributes<
attributes::a_pos_offset,
- attributes::a_texture_pos,
- attributes::a_data<4>>
+ attributes::a_data<uint16_t, 4>>
{
static Vertex vertex(Point<float> a,
Point<float> o,
@@ -57,19 +67,324 @@ struct SymbolLayoutAttributes : gl::Attributes<
}},
{{
static_cast<uint16_t>(tx / 4),
- static_cast<uint16_t>(ty / 4)
- }},
+ static_cast<uint16_t>(ty / 4),
+ mbgl::attributes::packUint8Pair(
+ static_cast<uint8_t>(labelminzoom * 10), // 1/10 zoom levels: z16 == 160
+ static_cast<uint8_t>(labelangle)
+ ),
+ mbgl::attributes::packUint8Pair(
+ static_cast<uint8_t>(minzoom * 10),
+ static_cast<uint8_t>(::fmin(maxzoom, 25) * 10)
+ )
+ }}
+ };
+ }
+};
+
+class SymbolSizeAttributes : public gl::Attributes<attributes::a_size> {
+public:
+ using Attribute = attributes::a_size::Type;
+};
+
+// Mimic the PaintPropertyBinder technique specifically for the {text,icon}-size layout properties
+// in order to provide a 'custom' scheme for encoding the necessary attribute data. As with
+// PaintPropertyBinder, SymbolSizeBinder is an abstract class whose implementations handle the
+// particular attribute & uniform logic needed by each possible type of the {Text,Icon}Size properties.
+class SymbolSizeBinder {
+public:
+ using Uniforms = gl::Uniforms<
+ uniforms::u_is_size_zoom_constant,
+ uniforms::u_is_size_feature_constant,
+ uniforms::u_size_t,
+ uniforms::u_size,
+ uniforms::u_layout_size>;
+ using UniformValues = Uniforms::Values;
+
+ static std::unique_ptr<SymbolSizeBinder> create(const float tileZoom,
+ const style::DataDrivenPropertyValue<float>& sizeProperty,
+ const float defaultValue);
+
+ virtual SymbolSizeAttributes::Bindings attributeBindings(const style::PossiblyEvaluatedPropertyValue<float> currentValue) const = 0;
+ virtual void populateVertexVector(const GeometryTileFeature& feature) = 0;
+ virtual UniformValues uniformValues(float currentZoom) const = 0;
+ virtual void upload(gl::Context&) = 0;
+};
+
+// Return the smallest range of stops that covers the interval [lowerZoom, upperZoom]
+template <class Stops>
+Range<float> getCoveringStops(Stops s, float lowerZoom, float upperZoom) {
+ assert(!s.stops.empty());
+ auto minIt = s.stops.lower_bound(lowerZoom);
+ auto maxIt = s.stops.lower_bound(upperZoom);
+
+ // lower_bound yields first element >= lowerZoom, but we want the *last*
+ // element <= lowerZoom, so if we found a stop > lowerZoom, back up by one.
+ if (minIt != s.stops.begin() && minIt->first > lowerZoom) {
+ minIt--;
+ }
+ return Range<float> {
+ minIt == s.stops.end() ? s.stops.rbegin()->first : minIt->first,
+ maxIt == s.stops.end() ? s.stops.rbegin()->first : maxIt->first
+ };
+}
+
+class ConstantSymbolSizeBinder : public SymbolSizeBinder {
+public:
+ using PropertyValue = variant<float, style::CameraFunction<float>>;
+
+ ConstantSymbolSizeBinder(const float /*tileZoom*/, const float& size, const float /*defaultValue*/)
+ : layoutSize(size) {}
+
+ ConstantSymbolSizeBinder(const float /*tileZoom*/, const style::Undefined&, const float defaultValue)
+ : layoutSize(defaultValue) {}
+
+ ConstantSymbolSizeBinder(const float tileZoom, const style::CameraFunction<float>& function_, const float /*defaultValue*/)
+ : layoutSize(function_.evaluate(tileZoom + 1)) {
+ function_.stops.match(
+ [&] (const style::ExponentialStops<float>& stops) {
+ coveringRanges = std::make_tuple(
+ getCoveringStops(stops, tileZoom, tileZoom + 1),
+ Range<float> { function_.evaluate(tileZoom), function_.evaluate(tileZoom + 1) }
+ );
+ functionInterpolationBase = stops.base;
+ },
+ [&] (const style::IntervalStops<float>&) {
+ function = function_;
+ }
+ );
+ }
+
+ SymbolSizeAttributes::Bindings attributeBindings(const style::PossiblyEvaluatedPropertyValue<float>) const override {
+ return SymbolSizeAttributes::Bindings { SymbolSizeAttributes::Attribute::ConstantBinding {{{0, 0, 0}}} };
+ }
+ void upload(gl::Context&) override {}
+ void populateVertexVector(const GeometryTileFeature&) override {};
+
+ UniformValues uniformValues(float currentZoom) const override {
+ float size = layoutSize;
+ bool isZoomConstant = !(coveringRanges || function);
+ if (coveringRanges) {
+ // Even though we could get the exact value of the camera function
+ // at z = currentZoom, we intentionally do not: instead, we interpolate
+ // between the camera function values at a pair of zoom stops covering
+ // [tileZoom, tileZoom + 1] in order to be consistent with this
+ // restriction on composite functions.
+ const Range<float>& zoomLevels = std::get<0>(*coveringRanges);
+ const Range<float>& sizeLevels = std::get<1>(*coveringRanges);
+ float t = util::clamp(
+ util::interpolationFactor(*functionInterpolationBase, zoomLevels, currentZoom),
+ 0.0f, 1.0f
+ );
+ size = sizeLevels.min + t * (sizeLevels.max - sizeLevels.min);
+ } else if (function) {
+ size = function->evaluate(currentZoom);
+ }
+
+ return UniformValues {
+ uniforms::u_is_size_zoom_constant::Value{ isZoomConstant },
+ uniforms::u_is_size_feature_constant::Value{ true },
+ uniforms::u_size_t::Value{ 0.0f }, // unused
+ uniforms::u_size::Value{ size },
+ uniforms::u_layout_size::Value{ layoutSize }
+ };
+ }
+
+ float layoutSize;
+ // used for exponential functions
+ optional<std::tuple<Range<float>, Range<float>>> coveringRanges;
+ optional<float> functionInterpolationBase;
+ // used for interval functions
+ optional<style::CameraFunction<float>> function;
+};
+
+class SourceFunctionSymbolSizeBinder : public SymbolSizeBinder {
+public:
+ using Vertex = gl::detail::Vertex<gl::Attribute<uint16_t, 1>>;
+ using VertexVector = gl::VertexVector<Vertex>;
+ using VertexBuffer = gl::VertexBuffer<Vertex>;
+
+ SourceFunctionSymbolSizeBinder(const float /*tileZoom*/, const style::SourceFunction<float>& function_, const float defaultValue_)
+ : function(function_),
+ defaultValue(defaultValue_) {
+ }
+
+ SymbolSizeAttributes::Bindings attributeBindings(const style::PossiblyEvaluatedPropertyValue<float> currentValue) const override {
+ if (currentValue.isConstant()) {
+ return SymbolSizeAttributes::Bindings { SymbolSizeAttributes::Attribute::ConstantBinding {{{0, 0, 0}}} };
+ }
+
+ return SymbolSizeAttributes::Bindings { SymbolSizeAttributes::Attribute::variableBinding(*buffer, 0, 1) };
+ }
+
+ void populateVertexVector(const GeometryTileFeature& feature) override {
+ const auto sizeVertex = Vertex {
{{
- static_cast<uint8_t>(labelminzoom * 10), // 1/10 zoom levels: z16 == 160
- static_cast<uint8_t>(labelangle),
- static_cast<uint8_t>(minzoom * 10),
- static_cast<uint8_t>(::fmin(maxzoom, 25) * 10)
+ static_cast<uint16_t>(function.evaluate(feature, defaultValue) * 10)
}}
};
+
+ vertices.emplace_back(sizeVertex);
+ vertices.emplace_back(sizeVertex);
+ vertices.emplace_back(sizeVertex);
+ vertices.emplace_back(sizeVertex);
+ };
+
+ UniformValues uniformValues(float) const override {
+ return UniformValues {
+ uniforms::u_is_size_zoom_constant::Value{ true },
+ uniforms::u_is_size_feature_constant::Value{ false },
+ uniforms::u_size_t::Value{ 0.0f }, // unused
+ uniforms::u_size::Value{ 0.0f }, // unused
+ uniforms::u_layout_size::Value{ 0.0f } // unused
+ };
+ }
+
+ void upload(gl::Context& context) override {
+ buffer = VertexBuffer { context.createVertexBuffer(std::move(vertices)) };
+ }
+
+ const style::SourceFunction<float>& function;
+ const float defaultValue;
+
+ VertexVector vertices;
+ optional<VertexBuffer> buffer;
+};
+
+class CompositeFunctionSymbolSizeBinder: public SymbolSizeBinder {
+public:
+ using Vertex = SymbolSizeAttributes::Vertex;
+ using VertexVector = gl::VertexVector<Vertex>;
+ using VertexBuffer = gl::VertexBuffer<Vertex>;
+
+ CompositeFunctionSymbolSizeBinder(const float tileZoom, const style::CompositeFunction<float>& function_, const float defaultValue_)
+ : function(function_),
+ defaultValue(defaultValue_),
+ layoutZoom(tileZoom + 1),
+ coveringZoomStops(function.stops.match(
+ [&] (const auto& stops) {
+ return getCoveringStops(stops, tileZoom, tileZoom + 1); }))
+ {}
+
+ SymbolSizeAttributes::Bindings attributeBindings(const style::PossiblyEvaluatedPropertyValue<float> currentValue) const override {
+ if (currentValue.isConstant()) {
+ return SymbolSizeAttributes::Bindings { SymbolSizeAttributes::Attribute::ConstantBinding {{{0, 0, 0}}} };
+ }
+
+ return SymbolSizeAttributes::Bindings { SymbolSizeAttributes::Attribute::variableBinding(*buffer, 0) };
+ }
+
+ void populateVertexVector(const GeometryTileFeature& feature) override {
+ const auto sizeVertex = Vertex {
+ {{
+ static_cast<uint16_t>(function.evaluate(coveringZoomStops.min, feature, defaultValue) * 10),
+ static_cast<uint16_t>(function.evaluate(coveringZoomStops.max, feature, defaultValue) * 10),
+ static_cast<uint16_t>(function.evaluate(layoutZoom, feature, defaultValue) * 10)
+ }}
+ };
+
+ vertices.emplace_back(sizeVertex);
+ vertices.emplace_back(sizeVertex);
+ vertices.emplace_back(sizeVertex);
+ vertices.emplace_back(sizeVertex);
+ };
+
+ UniformValues uniformValues(float currentZoom) const override {
+ float sizeInterpolationT = util::clamp(
+ util::interpolationFactor(1.0f, coveringZoomStops, currentZoom),
+ 0.0f, 1.0f
+ );
+
+ return UniformValues {
+ uniforms::u_is_size_zoom_constant::Value{ false },
+ uniforms::u_is_size_feature_constant::Value{ false },
+ uniforms::u_size_t::Value{ sizeInterpolationT },
+ uniforms::u_size::Value{ 0.0f }, // unused
+ uniforms::u_layout_size::Value{ 0.0f } // unused
+ };
+ }
+
+ void upload(gl::Context& context) override {
+ buffer = VertexBuffer { context.createVertexBuffer(std::move(vertices)) };
}
+
+ const style::CompositeFunction<float>& function;
+ const float defaultValue;
+ float layoutZoom;
+ Range<float> coveringZoomStops;
+
+ VertexVector vertices;
+ optional<VertexBuffer> buffer;
};
-class SymbolIconProgram : public Program<
+
+template <class Shaders,
+ class Primitive,
+ class LayoutAttrs,
+ class Uniforms,
+ class PaintProperties>
+class SymbolProgram {
+public:
+ using LayoutAttributes = LayoutAttrs;
+ using LayoutVertex = typename LayoutAttributes::Vertex;
+
+ using LayoutAndSizeAttributes = gl::ConcatenateAttributes<LayoutAttributes, SymbolSizeAttributes>;
+
+ using PaintPropertyBinders = typename PaintProperties::Binders;
+ using PaintAttributes = typename PaintPropertyBinders::Attributes;
+ using Attributes = gl::ConcatenateAttributes<LayoutAndSizeAttributes, PaintAttributes>;
+
+ using UniformValues = typename Uniforms::Values;
+ using SizeUniforms = typename SymbolSizeBinder::Uniforms;
+ using PaintUniforms = typename PaintPropertyBinders::Uniforms;
+ using AllUniforms = gl::ConcatenateUniforms<Uniforms, gl::ConcatenateUniforms<SizeUniforms, PaintUniforms>>;
+
+ using ProgramType = gl::Program<Primitive, Attributes, AllUniforms>;
+
+ ProgramType program;
+
+ SymbolProgram(gl::Context& context, const ProgramParameters& programParameters)
+ : program(ProgramType::createProgram(
+ context,
+ programParameters,
+ Shaders::name,
+ Shaders::vertexSource,
+ Shaders::fragmentSource)) {
+ }
+
+ template <class DrawMode>
+ void draw(gl::Context& context,
+ DrawMode drawMode,
+ gl::DepthMode depthMode,
+ gl::StencilMode stencilMode,
+ gl::ColorMode colorMode,
+ UniformValues&& uniformValues,
+ const gl::VertexBuffer<LayoutVertex>& layoutVertexBuffer,
+ const SymbolSizeBinder& symbolSizeBinder,
+ const style::PossiblyEvaluatedPropertyValue<float>& currentSizeValue,
+ const gl::IndexBuffer<DrawMode>& indexBuffer,
+ const gl::SegmentVector<Attributes>& segments,
+ const PaintPropertyBinders& paintPropertyBinders,
+ const typename PaintProperties::Evaluated& currentProperties,
+ float currentZoom) {
+ program.draw(
+ context,
+ std::move(drawMode),
+ std::move(depthMode),
+ std::move(stencilMode),
+ std::move(colorMode),
+ uniformValues
+ .concat(symbolSizeBinder.uniformValues(currentZoom))
+ .concat(paintPropertyBinders.uniformValues(currentZoom)),
+ LayoutAttributes::allVariableBindings(layoutVertexBuffer)
+ .concat(symbolSizeBinder.attributeBindings(currentSizeValue))
+ .concat(paintPropertyBinders.attributeBindings(currentProperties)),
+ indexBuffer,
+ segments
+ );
+ }
+};
+
+class SymbolIconProgram : public SymbolProgram<
shaders::symbol_icon,
gl::Triangle,
SymbolLayoutAttributes,
@@ -80,13 +395,15 @@ class SymbolIconProgram : public Program<
uniforms::u_zoom,
uniforms::u_rotate_with_map,
uniforms::u_texture,
- uniforms::u_fadetexture>,
+ uniforms::u_fadetexture,
+ uniforms::u_is_text>,
style::IconPaintProperties>
{
public:
- using Program::Program;
+ using SymbolProgram::SymbolProgram;
- static UniformValues uniformValues(const style::SymbolPropertyValues&,
+ static UniformValues uniformValues(const bool isText,
+ const style::SymbolPropertyValues&,
const Size& texsize,
const std::array<float, 2>& pixelsToGLUnits,
const RenderTile&,
@@ -99,7 +416,7 @@ enum class SymbolSDFPart {
};
template <class PaintProperties>
-class SymbolSDFProgram : public Program<
+class SymbolSDFProgram : public SymbolProgram<
shaders::symbol_sdf,
gl::Triangle,
SymbolLayoutAttributes,
@@ -111,7 +428,7 @@ class SymbolSDFProgram : public Program<
uniforms::u_rotate_with_map,
uniforms::u_texture,
uniforms::u_fadetexture,
- uniforms::u_font_scale,
+ uniforms::u_is_text,
uniforms::u_gamma_scale,
uniforms::u_pitch,
uniforms::u_bearing,
@@ -121,7 +438,7 @@ class SymbolSDFProgram : public Program<
PaintProperties>
{
public:
- using BaseProgram = Program<shaders::symbol_sdf,
+ using BaseProgram = SymbolProgram<shaders::symbol_sdf,
gl::Triangle,
SymbolLayoutAttributes,
gl::Uniforms<
@@ -132,7 +449,7 @@ public:
uniforms::u_rotate_with_map,
uniforms::u_texture,
uniforms::u_fadetexture,
- uniforms::u_font_scale,
+ uniforms::u_is_text,
uniforms::u_gamma_scale,
uniforms::u_pitch,
uniforms::u_bearing,
@@ -147,7 +464,8 @@ public:
using BaseProgram::BaseProgram;
- static UniformValues uniformValues(const style::SymbolPropertyValues&,
+ static UniformValues uniformValues(const bool isText,
+ const style::SymbolPropertyValues&,
const Size& texsize,
const std::array<float, 2>& pixelsToGLUnits,
const RenderTile&,
diff --git a/src/mbgl/renderer/painter_symbol.cpp b/src/mbgl/renderer/painter_symbol.cpp
index 48c2e7ff66..d2f492d17a 100644
--- a/src/mbgl/renderer/painter_symbol.cpp
+++ b/src/mbgl/renderer/painter_symbol.cpp
@@ -33,6 +33,7 @@ void Painter::renderSymbol(PaintParameters& parameters,
auto draw = [&] (auto& program,
auto&& uniformValues,
const auto& buffers,
+ const auto& symbolSizeBinder,
const SymbolPropertyValues& values_,
const auto& binders,
const auto& paintProperties)
@@ -52,6 +53,8 @@ void Painter::renderSymbol(PaintParameters& parameters,
colorModeForRenderPass(),
std::move(uniformValues),
*buffers.vertexBuffer,
+ *symbolSizeBinder,
+ values_.layoutSize,
*buffers.indexBuffer,
buffers.segments,
binders,
@@ -65,7 +68,9 @@ void Painter::renderSymbol(PaintParameters& parameters,
auto paintPropertyValues = layer.impl->iconPaintProperties();
SpriteAtlas& atlas = *layer.impl->spriteAtlas;
- const bool iconScaled = values.paintSize != 1.0f || frame.pixelRatio != atlas.getPixelRatio() || bucket.iconsNeedLinear;
+ const bool iconScaled = layout.get<IconSize>().constantOr(1.0) != 1.0 ||
+ frame.pixelRatio != atlas.getPixelRatio() ||
+ bucket.iconsNeedLinear;
const bool iconTransformed = values.rotationAlignment == AlignmentType::Map || state.getPitch() != 0;
atlas.bind(bucket.sdfIcons || state.isChanging() || iconScaled || iconTransformed, context, 0);
@@ -74,8 +79,9 @@ void Painter::renderSymbol(PaintParameters& parameters,
if (bucket.sdfIcons) {
if (values.hasHalo) {
draw(parameters.programs.symbolIconSDF,
- SymbolSDFIconProgram::uniformValues(values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Halo),
+ SymbolSDFIconProgram::uniformValues(false, values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Halo),
bucket.icon,
+ bucket.iconSizeBinder,
values,
bucket.paintPropertyBinders.at(layer.getID()).first,
paintPropertyValues);
@@ -83,16 +89,18 @@ void Painter::renderSymbol(PaintParameters& parameters,
if (values.hasFill) {
draw(parameters.programs.symbolIconSDF,
- SymbolSDFIconProgram::uniformValues(values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Fill),
+ SymbolSDFIconProgram::uniformValues(false, values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Fill),
bucket.icon,
+ bucket.iconSizeBinder,
values,
bucket.paintPropertyBinders.at(layer.getID()).first,
paintPropertyValues);
}
} else {
draw(parameters.programs.symbolIcon,
- SymbolIconProgram::uniformValues(values, texsize, pixelsToGLUnits, tile, state),
+ SymbolIconProgram::uniformValues(false, values, texsize, pixelsToGLUnits, tile, state),
bucket.icon,
+ bucket.iconSizeBinder,
values,
bucket.paintPropertyBinders.at(layer.getID()).first,
paintPropertyValues);
@@ -109,8 +117,9 @@ void Painter::renderSymbol(PaintParameters& parameters,
if (values.hasHalo) {
draw(parameters.programs.symbolGlyph,
- SymbolSDFTextProgram::uniformValues(values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Halo),
+ SymbolSDFTextProgram::uniformValues(true, values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Halo),
bucket.text,
+ bucket.textSizeBinder,
values,
bucket.paintPropertyBinders.at(layer.getID()).second,
paintPropertyValues);
@@ -118,8 +127,9 @@ void Painter::renderSymbol(PaintParameters& parameters,
if (values.hasFill) {
draw(parameters.programs.symbolGlyph,
- SymbolSDFTextProgram::uniformValues(values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Fill),
+ SymbolSDFTextProgram::uniformValues(true, values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Fill),
bucket.text,
+ bucket.textSizeBinder,
values,
bucket.paintPropertyBinders.at(layer.getID()).second,
paintPropertyValues);
diff --git a/src/mbgl/renderer/symbol_bucket.cpp b/src/mbgl/renderer/symbol_bucket.cpp
index b046571740..77a9a75ef1 100644
--- a/src/mbgl/renderer/symbol_bucket.cpp
+++ b/src/mbgl/renderer/symbol_bucket.cpp
@@ -11,12 +11,17 @@ using namespace style;
SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated layout_,
const std::map<std::string, std::pair<
style::IconPaintProperties::Evaluated, style::TextPaintProperties::Evaluated>>& layerPaintProperties,
+ const style::DataDrivenPropertyValue<float>& textSize,
+ const style::DataDrivenPropertyValue<float>& iconSize,
float zoom,
bool sdfIcons_,
bool iconsNeedLinear_)
: layout(std::move(layout_)),
sdfIcons(sdfIcons_),
- iconsNeedLinear(iconsNeedLinear_) {
+ iconsNeedLinear(iconsNeedLinear_ || iconSize.isDataDriven() || !iconSize.isZoomConstant()),
+ textSizeBinder(SymbolSizeBinder::create(zoom, textSize, TextSize::defaultValue())),
+ iconSizeBinder(SymbolSizeBinder::create(zoom, iconSize, IconSize::defaultValue())) {
+
for (const auto& pair : layerPaintProperties) {
paintPropertyBinders.emplace(
std::piecewise_construct,
@@ -32,11 +37,13 @@ void SymbolBucket::upload(gl::Context& context) {
if (hasTextData()) {
text.vertexBuffer = context.createVertexBuffer(std::move(text.vertices));
text.indexBuffer = context.createIndexBuffer(std::move(text.triangles));
+ textSizeBinder->upload(context);
}
if (hasIconData()) {
icon.vertexBuffer = context.createVertexBuffer(std::move(icon.vertices));
icon.indexBuffer = context.createIndexBuffer(std::move(icon.triangles));
+ iconSizeBinder->upload(context);
}
if (!collisionBox.vertices.empty()) {
diff --git a/src/mbgl/renderer/symbol_bucket.hpp b/src/mbgl/renderer/symbol_bucket.hpp
index 7a498ab17d..659d7a3788 100644
--- a/src/mbgl/renderer/symbol_bucket.hpp
+++ b/src/mbgl/renderer/symbol_bucket.hpp
@@ -9,6 +9,7 @@
#include <mbgl/programs/collision_box_program.hpp>
#include <mbgl/text/glyph_range.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
+#include <mbgl/layout/symbol_feature.hpp>
#include <vector>
@@ -18,6 +19,8 @@ class SymbolBucket : public Bucket {
public:
SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated,
const std::map<std::string, std::pair<style::IconPaintProperties::Evaluated, style::TextPaintProperties::Evaluated>>&,
+ const style::DataDrivenPropertyValue<float>& textSize,
+ const style::DataDrivenPropertyValue<float>& iconSize,
float zoom,
bool sdfIcons,
bool iconsNeedLinear);
@@ -36,6 +39,8 @@ public:
std::map<std::string, std::pair<
SymbolIconProgram::PaintPropertyBinders,
SymbolSDFTextProgram::PaintPropertyBinders>> paintPropertyBinders;
+
+ std::unique_ptr<SymbolSizeBinder> textSizeBinder;
struct TextBuffer {
gl::VertexVector<SymbolLayoutVertex> vertices;
@@ -45,7 +50,9 @@ public:
optional<gl::VertexBuffer<SymbolLayoutVertex>> vertexBuffer;
optional<gl::IndexBuffer<gl::Triangles>> indexBuffer;
} text;
-
+
+ std::unique_ptr<SymbolSizeBinder> iconSizeBinder;
+
struct IconBuffer {
gl::VertexVector<SymbolLayoutVertex> vertices;
gl::IndexVector<gl::Triangles> triangles;
diff --git a/src/mbgl/shaders/preludes.cpp b/src/mbgl/shaders/preludes.cpp
index 806e655285..cca0f3e3f1 100644
--- a/src/mbgl/shaders/preludes.cpp
+++ b/src/mbgl/shaders/preludes.cpp
@@ -43,17 +43,25 @@ vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 v
}
}
+// Unpack a pair of values that have been packed into a single float.
+// The packed values are assumed to be 8-bit unsigned integers, and are
+// packed like so:
+// packedValue = floor(input[0]) * 256 + input[1],
+vec2 unpack_float(const float packedValue) {
+ float v0 = floor(packedValue / 256.0);
+ return vec2(v0, packedValue - v0 * 256.0);
+}
+
// To minimize the number of attributes needed in the mapbox-gl-native shaders,
// we encode a 4-component color into a pair of floats (i.e. a vec2) as follows:
// [ floor(color.r * 255) * 256 + color.g * 255,
// floor(color.b * 255) * 256 + color.g * 255 ]
vec4 decode_color(const vec2 encodedColor) {
- float r = floor(encodedColor[0]/256.0)/255.0;
- float g = (encodedColor[0] - r*256.0*255.0)/255.0;
- float b = floor(encodedColor[1]/256.0)/255.0;
- float a = (encodedColor[1] - b*256.0*255.0)/255.0;
- return vec4(r, g, b, a);
+ return vec4(
+ unpack_float(encodedColor[0]) / 255.0,
+ unpack_float(encodedColor[1]) / 255.0
+ );
}
// Unpack a pair of paint values and interpolate between them.
diff --git a/src/mbgl/shaders/symbol_icon.cpp b/src/mbgl/shaders/symbol_icon.cpp
index 9adda0ba16..b6fbed428e 100644
--- a/src/mbgl/shaders/symbol_icon.cpp
+++ b/src/mbgl/shaders/symbol_icon.cpp
@@ -9,9 +9,16 @@ const char* symbol_icon::name = "symbol_icon";
const char* symbol_icon::vertexSource = R"MBGL_SHADER(
attribute vec4 a_pos_offset;
-attribute vec2 a_texture_pos;
attribute vec4 a_data;
+// icon-size data (see symbol_sdf.vertex.glsl for more)
+attribute vec3 a_size;
+uniform bool u_is_size_zoom_constant;
+uniform bool u_is_size_feature_constant;
+uniform mediump float u_size_t; // used to interpolate between zoom stops when size is a composite function
+uniform mediump float u_size; // used when size is both zoom and feature constant
+uniform mediump float u_layout_size; // used when size is feature constant
+
uniform lowp float a_opacity_t;
attribute lowp vec2 a_opacity;
varying lowp float opacity;
@@ -19,6 +26,7 @@ varying lowp float opacity;
// matrix is for the vertex position.
uniform mat4 u_matrix;
+uniform bool u_is_text;
uniform mediump float u_zoom;
uniform bool u_rotate_with_map;
uniform vec2 u_extrude_scale;
@@ -34,16 +42,45 @@ void main() {
vec2 a_pos = a_pos_offset.xy;
vec2 a_offset = a_pos_offset.zw;
- vec2 a_tex = a_texture_pos.xy;
- mediump float a_labelminzoom = a_data[0];
- mediump vec2 a_zoom = a_data.pq;
+ vec2 a_tex = a_data.xy;
+ mediump vec2 label_data = unpack_float(a_data[2]);
+ mediump float a_labelminzoom = label_data[0];
+ mediump vec2 a_zoom = unpack_float(a_data[3]);
mediump float a_minzoom = a_zoom[0];
mediump float a_maxzoom = a_zoom[1];
- // u_zoom is the current zoom level adjusted for the change in font size
- mediump float z = 2.0 - step(a_minzoom, u_zoom) - (1.0 - step(a_maxzoom, u_zoom));
+ float size;
+ // In order to accommodate placing labels around corners in
+ // symbol-placement: line, each glyph in a label could have multiple
+ // "quad"s only one of which should be shown at a given zoom level.
+ // The min/max zoom assigned to each quad is based on the font size at
+ // the vector tile's zoom level, which might be different than at the
+ // currently rendered zoom level if text-size is zoom-dependent.
+ // Thus, we compensate for this difference by calculating an adjustment
+ // based on the scale of rendered text size relative to layout text size.
+ mediump float layoutSize;
+ if (!u_is_size_zoom_constant && !u_is_size_feature_constant) {
+ size = mix(a_size[0], a_size[1], u_size_t) / 10.0;
+ layoutSize = a_size[2] / 10.0;
+ } else if (u_is_size_zoom_constant && !u_is_size_feature_constant) {
+ size = a_size[0] / 10.0;
+ layoutSize = size;
+ } else if (!u_is_size_zoom_constant && u_is_size_feature_constant) {
+ size = u_size;
+ layoutSize = u_layout_size;
+ } else {
+ size = u_size;
+ layoutSize = u_size;
+ }
+
+ float fontScale = u_is_text ? size / 24.0 : size;
+
+ mediump float zoomAdjust = log2(size / layoutSize);
+ mediump float adjustedZoom = (u_zoom - zoomAdjust) * 10.0;
+ // result: z = 0 if a_minzoom <= adjustedZoom < a_maxzoom, and 1 otherwise
+ mediump float z = 2.0 - step(a_minzoom, adjustedZoom) - (1.0 - step(a_maxzoom, adjustedZoom));
- vec2 extrude = u_extrude_scale * (a_offset / 64.0);
+ vec2 extrude = fontScale * u_extrude_scale * (a_offset / 64.0);
if (u_rotate_with_map) {
gl_Position = u_matrix * vec4(a_pos + extrude, 0, 1);
gl_Position.z += z * gl_Position.w;
diff --git a/src/mbgl/shaders/symbol_sdf.cpp b/src/mbgl/shaders/symbol_sdf.cpp
index 7cbc9babf5..194e624036 100644
--- a/src/mbgl/shaders/symbol_sdf.cpp
+++ b/src/mbgl/shaders/symbol_sdf.cpp
@@ -10,9 +10,23 @@ const char* symbol_sdf::vertexSource = R"MBGL_SHADER(
const float PI = 3.141592653589793;
attribute vec4 a_pos_offset;
-attribute vec2 a_texture_pos;
attribute vec4 a_data;
+// contents of a_size vary based on the type of property value
+// used for {text,icon}-size.
+// For constants, a_size is disabled.
+// For source functions, we bind only one value per vertex: the value of {text,icon}-size evaluated for the current feature.
+// For composite functions:
+// [ text-size(lowerZoomStop, feature),
+// text-size(upperZoomStop, feature),
+// layoutSize == text-size(layoutZoomLevel, feature) ]
+attribute vec3 a_size;
+uniform bool u_is_size_zoom_constant;
+uniform bool u_is_size_feature_constant;
+uniform mediump float u_size_t; // used to interpolate between zoom stops when size is a composite function
+uniform mediump float u_size; // used when size is both zoom and feature constant
+uniform mediump float u_layout_size; // used when size is feature constant
+
uniform lowp float a_fill_color_t;
attribute highp vec4 a_fill_color;
varying highp vec4 fill_color;
@@ -32,6 +46,7 @@ varying lowp float halo_blur;
// matrix is for the vertex position.
uniform mat4 u_matrix;
+uniform bool u_is_text;
uniform mediump float u_zoom;
uniform bool u_rotate_with_map;
uniform bool u_pitch_with_map;
@@ -45,6 +60,7 @@ uniform vec2 u_texsize;
varying vec2 v_tex;
varying vec2 v_fade_tex;
varying float v_gamma_scale;
+varying float v_size;
void main() {
fill_color = unpack_mix_vec4(a_fill_color, a_fill_color_t);
@@ -56,24 +72,57 @@ void main() {
vec2 a_pos = a_pos_offset.xy;
vec2 a_offset = a_pos_offset.zw;
- vec2 a_tex = a_texture_pos.xy;
- mediump float a_labelminzoom = a_data[0];
- mediump vec2 a_zoom = a_data.pq;
+ vec2 a_tex = a_data.xy;
+
+ mediump vec2 label_data = unpack_float(a_data[2]);
+ mediump float a_labelminzoom = label_data[0];
+ mediump float a_labelangle = label_data[1];
+
+ mediump vec2 a_zoom = unpack_float(a_data[3]);
mediump float a_minzoom = a_zoom[0];
mediump float a_maxzoom = a_zoom[1];
- // u_zoom is the current zoom level adjusted for the change in font size
- mediump float z = 2.0 - step(a_minzoom, u_zoom) - (1.0 - step(a_maxzoom, u_zoom));
+ // In order to accommodate placing labels around corners in
+ // symbol-placement: line, each glyph in a label could have multiple
+ // "quad"s only one of which should be shown at a given zoom level.
+ // The min/max zoom assigned to each quad is based on the font size at
+ // the vector tile's zoom level, which might be different than at the
+ // currently rendered zoom level if text-size is zoom-dependent.
+ // Thus, we compensate for this difference by calculating an adjustment
+ // based on the scale of rendered text size relative to layout text size.
+ mediump float layoutSize;
+ if (!u_is_size_zoom_constant && !u_is_size_feature_constant) {
+ v_size = mix(a_size[0], a_size[1], u_size_t) / 10.0;
+ layoutSize = a_size[2] / 10.0;
+ } else if (u_is_size_zoom_constant && !u_is_size_feature_constant) {
+ v_size = a_size[0] / 10.0;
+ layoutSize = v_size;
+ } else if (!u_is_size_zoom_constant && u_is_size_feature_constant) {
+ v_size = u_size;
+ layoutSize = u_layout_size;
+ } else {
+ v_size = u_size;
+ layoutSize = u_size;
+ }
+
+ float fontScale = u_is_text ? v_size / 24.0 : v_size;
+
+ mediump float zoomAdjust = log2(v_size / layoutSize);
+ mediump float adjustedZoom = (u_zoom - zoomAdjust) * 10.0;
+ // result: z = 0 if a_minzoom <= adjustedZoom < a_maxzoom, and 1 otherwise
+ // Used below to move the vertex out of the clip space for when the current
+ // zoom is out of the glyph's zoom range.
+ mediump float z = 2.0 - step(a_minzoom, adjustedZoom) - (1.0 - step(a_maxzoom, adjustedZoom));
// pitch-alignment: map
// rotation-alignment: map | viewport
if (u_pitch_with_map) {
- lowp float angle = u_rotate_with_map ? (a_data[1] / 256.0 * 2.0 * PI) : u_bearing;
+ lowp float angle = u_rotate_with_map ? (a_labelangle / 256.0 * 2.0 * PI) : u_bearing;
lowp float asin = sin(angle);
lowp float acos = cos(angle);
mat2 RotationMatrix = mat2(acos, asin, -1.0 * asin, acos);
vec2 offset = RotationMatrix * a_offset;
- vec2 extrude = u_extrude_scale * (offset / 64.0);
+ vec2 extrude = fontScale * u_extrude_scale * (offset / 64.0);
gl_Position = u_matrix * vec4(a_pos + extrude, 0, 1);
gl_Position.z += z * gl_Position.w;
// pitch-alignment: viewport
@@ -84,7 +133,7 @@ void main() {
// it goes from 0% foreshortening to up to around 70% foreshortening
lowp float pitchfactor = 1.0 - cos(u_pitch * sin(u_pitch * 0.75));
- lowp float lineangle = a_data[1] / 256.0 * 2.0 * PI;
+ lowp float lineangle = a_labelangle / 256.0 * 2.0 * PI;
// use the lineangle to position points a,b along the line
// project the points and calculate the label angle in projected space
@@ -97,13 +146,13 @@ void main() {
mat2 RotationMatrix = mat2(acos, -1.0 * asin, asin, acos);
vec2 offset = RotationMatrix * (vec2((1.0-pitchfactor)+(pitchfactor*cos(angle*2.0)), 1.0) * a_offset);
- vec2 extrude = u_extrude_scale * (offset / 64.0);
+ vec2 extrude = fontScale * u_extrude_scale * (offset / 64.0);
gl_Position = u_matrix * vec4(a_pos, 0, 1) + vec4(extrude, 0, 0);
gl_Position.z += z * gl_Position.w;
// pitch-alignment: viewport
// rotation-alignment: viewport
} else {
- vec2 extrude = u_extrude_scale * (a_offset / 64.0);
+ vec2 extrude = fontScale * u_extrude_scale * (a_offset / 64.0);
gl_Position = u_matrix * vec4(a_pos, 0, 1) + vec4(extrude, 0, 0);
}
@@ -127,12 +176,13 @@ varying lowp float halo_blur;
uniform sampler2D u_texture;
uniform sampler2D u_fadetexture;
-uniform lowp float u_font_scale;
uniform highp float u_gamma_scale;
+uniform bool u_is_text;
varying vec2 v_tex;
varying vec2 v_fade_tex;
varying float v_gamma_scale;
+varying float v_size;
void main() {
@@ -141,13 +191,15 @@ void main() {
+ float fontScale = u_is_text ? v_size / 24.0 : v_size;
+
lowp vec4 color = fill_color;
- highp float gamma = EDGE_GAMMA / u_gamma_scale;
+ highp float gamma = EDGE_GAMMA / (fontScale * u_gamma_scale);
lowp float buff = (256.0 - 64.0) / 256.0;
if (u_is_halo) {
color = halo_color;
- gamma = (halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / u_gamma_scale;
- buff = (6.0 - halo_width / u_font_scale) / SDF_PX;
+ gamma = (halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / (fontScale * u_gamma_scale);
+ buff = (6.0 - halo_width / fontScale) / SDF_PX;
}
lowp float dist = texture2D(u_texture, v_tex).a;
diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp
index bd5cf30ad6..e79a3f967f 100644
--- a/src/mbgl/style/layers/symbol_layer.cpp
+++ b/src/mbgl/style/layers/symbol_layer.cpp
@@ -161,15 +161,15 @@ void SymbolLayer::setIconRotationAlignment(PropertyValue<AlignmentType> value) {
impl->layout.unevaluated.get<IconRotationAlignment>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "icon-rotation-alignment");
}
-PropertyValue<float> SymbolLayer::getDefaultIconSize() {
+DataDrivenPropertyValue<float> SymbolLayer::getDefaultIconSize() {
return IconSize::defaultValue();
}
-PropertyValue<float> SymbolLayer::getIconSize() const {
+DataDrivenPropertyValue<float> SymbolLayer::getIconSize() const {
return impl->layout.unevaluated.get<IconSize>();
}
-void SymbolLayer::setIconSize(PropertyValue<float> value) {
+void SymbolLayer::setIconSize(DataDrivenPropertyValue<float> value) {
if (value == getIconSize())
return;
impl->layout.unevaluated.get<IconSize>() = value;
@@ -329,15 +329,15 @@ void SymbolLayer::setTextFont(PropertyValue<std::vector<std::string>> value) {
impl->layout.unevaluated.get<TextFont>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "text-font");
}
-PropertyValue<float> SymbolLayer::getDefaultTextSize() {
+DataDrivenPropertyValue<float> SymbolLayer::getDefaultTextSize() {
return TextSize::defaultValue();
}
-PropertyValue<float> SymbolLayer::getTextSize() const {
+DataDrivenPropertyValue<float> SymbolLayer::getTextSize() const {
return impl->layout.unevaluated.get<TextSize>();
}
-void SymbolLayer::setTextSize(PropertyValue<float> value) {
+void SymbolLayer::setTextSize(DataDrivenPropertyValue<float> value) {
if (value == getTextSize())
return;
impl->layout.unevaluated.get<TextSize>() = value;
diff --git a/src/mbgl/style/layers/symbol_layer_impl.cpp b/src/mbgl/style/layers/symbol_layer_impl.cpp
index c637770c04..109d1c43e7 100644
--- a/src/mbgl/style/layers/symbol_layer_impl.cpp
+++ b/src/mbgl/style/layers/symbol_layer_impl.cpp
@@ -13,10 +13,6 @@ void SymbolLayer::Impl::cascade(const CascadeParameters& parameters) {
bool SymbolLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) {
paint.evaluate(parameters);
- // text-size and icon-size are layout properties but they also need to be evaluated as paint properties:
- iconSize = layout.evaluate<IconSize>(parameters);
- textSize = layout.evaluate<TextSize>(parameters);
-
auto hasIconOpacity = paint.evaluated.get<IconColor>().constantOr(Color::black()).a > 0 ||
paint.evaluated.get<IconHaloColor>().constantOr(Color::black()).a > 0;
auto hasTextOpacity = paint.evaluated.get<TextColor>().constantOr(Color::black()).a > 0 ||
diff --git a/src/mbgl/style/layers/symbol_layer_impl.hpp b/src/mbgl/style/layers/symbol_layer_impl.hpp
index db20989f01..3d81ff1f69 100644
--- a/src/mbgl/style/layers/symbol_layer_impl.hpp
+++ b/src/mbgl/style/layers/symbol_layer_impl.hpp
@@ -44,7 +44,7 @@ public:
// Layout
AlignmentType pitchAlignment;
AlignmentType rotationAlignment;
- float layoutSize;
+ PossiblyEvaluatedPropertyValue<float> layoutSize;
// Paint
std::array<float, 2> translate;
diff --git a/src/mbgl/style/layers/symbol_layer_properties.hpp b/src/mbgl/style/layers/symbol_layer_properties.hpp
index 4f63ed419a..42f593890b 100644
--- a/src/mbgl/style/layers/symbol_layer_properties.hpp
+++ b/src/mbgl/style/layers/symbol_layer_properties.hpp
@@ -45,7 +45,7 @@ struct IconRotationAlignment : LayoutProperty<AlignmentType> {
static AlignmentType defaultValue() { return AlignmentType::Auto; }
};
-struct IconSize : LayoutProperty<float> {
+struct IconSize : DataDrivenLayoutProperty<float> {
static constexpr const char * key = "icon-size";
static float defaultValue() { return 1; }
};
@@ -105,7 +105,7 @@ struct TextFont : LayoutProperty<std::vector<std::string>> {
static std::vector<std::string> defaultValue() { return { "Open Sans Regular", "Arial Unicode MS Regular" }; }
};
-struct TextSize : LayoutProperty<float> {
+struct TextSize : DataDrivenLayoutProperty<float> {
static constexpr const char * key = "text-size";
static float defaultValue() { return 16; }
};
diff --git a/src/mbgl/style/paint_property_binder.hpp b/src/mbgl/style/paint_property_binder.hpp
index 7e44b509a1..bf98e6ef9a 100644
--- a/src/mbgl/style/paint_property_binder.hpp
+++ b/src/mbgl/style/paint_property_binder.hpp
@@ -26,16 +26,12 @@ inline std::array<float, 1> attributeValue(float v) {
uses 8-bit precision for each color component, for each float we use the upper 8
bits for one component (e.g. (color.r * 255) * 256), and the lower 8 for another.
- Also note:
- - Colors come in as floats 0..1, so we scale by 255.
- - Casting the scaled values to ints is important: without doing this, e.g., the
- fractional part of the `r` component would corrupt the lower-8 bits of the encoded
- value, which must be reserved for the `g` component.
+ Also note that colors come in as floats 0..1, so we scale by 255.
*/
inline std::array<float, 2> attributeValue(const Color& color) {
return {{
- static_cast<float>(static_cast<uint16_t>(color.r * 255) * 256 + static_cast<uint16_t>(color.g * 255)),
- static_cast<float>(static_cast<uint16_t>(color.b * 255) * 256 + static_cast<uint16_t>(color.a * 255))
+ static_cast<float>(mbgl::attributes::packUint8Pair(255 * color.r, 255 * color.g)),
+ static_cast<float>(mbgl::attributes::packUint8Pair(255 * color.b, 255 * color.a))
}};
}
diff --git a/src/mbgl/text/quads.cpp b/src/mbgl/text/quads.cpp
index b13a6a71e5..188f88655d 100644
--- a/src/mbgl/text/quads.cpp
+++ b/src/mbgl/text/quads.cpp
@@ -19,6 +19,7 @@ SymbolQuad getIconQuad(const Anchor& anchor,
const PositionedIcon& shapedIcon,
const GeometryCoordinates& line,
const SymbolLayoutProperties::Evaluated& layout,
+ const float layoutTextSize,
const style::SymbolPlacementType placement,
const Shaping& shapedText) {
auto image = *(shapedIcon.image);
@@ -36,7 +37,7 @@ SymbolQuad getIconQuad(const Anchor& anchor,
if (layout.get<IconTextFit>() != IconTextFitType::None && shapedText) {
auto iconWidth = right - left;
auto iconHeight = bottom - top;
- auto size = layout.get<TextSize>() / 24.0f;
+ auto size = layoutTextSize / 24.0f;
auto textLeft = shapedText.left * size;
auto textRight = shapedText.right * size;
auto textTop = shapedText.top * size;
diff --git a/src/mbgl/text/quads.hpp b/src/mbgl/text/quads.hpp
index f1529d8829..333000627b 100644
--- a/src/mbgl/text/quads.hpp
+++ b/src/mbgl/text/quads.hpp
@@ -55,6 +55,7 @@ SymbolQuad getIconQuad(const Anchor& anchor,
const PositionedIcon& shapedIcon,
const GeometryCoordinates& line,
const style::SymbolLayoutProperties::Evaluated&,
+ const float layoutTextSize,
style::SymbolPlacementType placement,
const Shaping& shapedText);
diff --git a/test/gl/bucket.test.cpp b/test/gl/bucket.test.cpp
index 1ab6623122..5b66a0987f 100644
--- a/test/gl/bucket.test.cpp
+++ b/test/gl/bucket.test.cpp
@@ -31,7 +31,7 @@ TEST(Buckets, SymbolBucket) {
bool sdfIcons = false;
bool iconsNeedLinear = false;
- SymbolBucket bucket { layout, {}, 0, sdfIcons, iconsNeedLinear };
+ SymbolBucket bucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear };
ASSERT_FALSE(bucket.hasIconData());
ASSERT_FALSE(bucket.hasTextData());
ASSERT_FALSE(bucket.hasCollisionBoxData());
diff --git a/test/text/quads.test.cpp b/test/text/quads.test.cpp
index 42bc0f2048..18fbedc2dd 100644
--- a/test/text/quads.test.cpp
+++ b/test/text/quads.test.cpp
@@ -23,7 +23,7 @@ TEST(getIconQuads, normal) {
Shaping shapedText;
SymbolQuad quad =
- getIconQuad(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
+ getIconQuad(anchor, shapedIcon, line, layout, 16.0f, SymbolPlacementType::Point, shapedText);
ASSERT_EQ(quad.anchorPoint.x, 2);
ASSERT_EQ(quad.anchorPoint.y, 3);
@@ -61,7 +61,7 @@ TEST(getIconQuads, style) {
{
SymbolLayoutProperties::Evaluated layout;
SymbolQuad quad =
- getIconQuad(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
+ getIconQuad(anchor, shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, shapedText);
ASSERT_EQ(quad.anchorPoint.x, 0);
ASSERT_EQ(quad.anchorPoint.y, 0);
@@ -84,7 +84,7 @@ TEST(getIconQuads, style) {
layout.get<TextSize>() = 24.0f;
layout.get<IconTextFit>() = IconTextFitType::Width;
SymbolQuad quad =
- getIconQuad(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
+ getIconQuad(anchor, shapedIcon, line, layout, 24.0f, SymbolPlacementType::Point, shapedText);
ASSERT_EQ(quad.tl.x, -60);
ASSERT_EQ(quad.tl.y, 0);
@@ -102,7 +102,7 @@ TEST(getIconQuads, style) {
layout.get<TextSize>() = 12.0f;
layout.get<IconTextFit>() = IconTextFitType::Width;
SymbolQuad quad =
- getIconQuad(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
+ getIconQuad(anchor, shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, shapedText);
ASSERT_EQ(quad.tl.x, -30);
ASSERT_EQ(quad.tl.y, -5);
@@ -124,7 +124,7 @@ TEST(getIconQuads, style) {
layout.get<IconTextFitPadding>()[2] = 5.0f;
layout.get<IconTextFitPadding>()[3] = 10.0f;
SymbolQuad quad =
- getIconQuad(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
+ getIconQuad(anchor, shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, shapedText);
ASSERT_EQ(quad.tl.x, -40);
ASSERT_EQ(quad.tl.y, -10);
@@ -142,7 +142,7 @@ TEST(getIconQuads, style) {
layout.get<TextSize>() = 24.0f;
layout.get<IconTextFit>() = IconTextFitType::Height;
SymbolQuad quad =
- getIconQuad(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
+ getIconQuad(anchor, shapedIcon, line, layout, 24.0f, SymbolPlacementType::Point, shapedText);
ASSERT_EQ(quad.tl.x, -30);
ASSERT_EQ(quad.tl.y, -10);
@@ -160,7 +160,7 @@ TEST(getIconQuads, style) {
layout.get<TextSize>() = 12.0f;
layout.get<IconTextFit>() = IconTextFitType::Height;
SymbolQuad quad =
- getIconQuad(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
+ getIconQuad(anchor, shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, shapedText);
ASSERT_EQ(quad.tl.x, -20);
ASSERT_EQ(quad.tl.y, -5);
@@ -182,7 +182,7 @@ TEST(getIconQuads, style) {
layout.get<IconTextFitPadding>()[2] = 5.0f;
layout.get<IconTextFitPadding>()[3] = 10.0f;
SymbolQuad quad =
- getIconQuad(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
+ getIconQuad(anchor, shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, shapedText);
ASSERT_EQ(quad.tl.x, -30);
ASSERT_EQ(quad.tl.y, -10);
@@ -200,7 +200,7 @@ TEST(getIconQuads, style) {
layout.get<TextSize>() = 24.0f;
layout.get<IconTextFit>() = IconTextFitType::Both;
SymbolQuad quad =
- getIconQuad(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
+ getIconQuad(anchor, shapedIcon, line, layout, 24.0f, SymbolPlacementType::Point, shapedText);
ASSERT_EQ(quad.tl.x, -60);
ASSERT_EQ(quad.tl.y, -10);
@@ -218,7 +218,7 @@ TEST(getIconQuads, style) {
layout.get<TextSize>() = 12.0f;
layout.get<IconTextFit>() = IconTextFitType::Both;
SymbolQuad quad =
- getIconQuad(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
+ getIconQuad(anchor, shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, shapedText);
ASSERT_EQ(quad.tl.x, -30);
ASSERT_EQ(quad.tl.y, -5);
@@ -240,7 +240,7 @@ TEST(getIconQuads, style) {
layout.get<IconTextFitPadding>()[2] = 5.0f;
layout.get<IconTextFitPadding>()[3] = 10.0f;
SymbolQuad quad =
- getIconQuad(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
+ getIconQuad(anchor, shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, shapedText);
ASSERT_EQ(quad.tl.x, -40);
ASSERT_EQ(quad.tl.y, -10);
@@ -262,7 +262,7 @@ TEST(getIconQuads, style) {
layout.get<IconTextFitPadding>()[2] = 10.0f;
layout.get<IconTextFitPadding>()[3] = 15.0f;
SymbolQuad quad =
- getIconQuad(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
+ getIconQuad(anchor, shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, shapedText);
ASSERT_EQ(quad.tl.x, -45);
ASSERT_EQ(quad.tl.y, -5);
diff --git a/test/tile/vector_tile.test.cpp b/test/tile/vector_tile.test.cpp
index eb2b89d346..95d21418fd 100644
--- a/test/tile/vector_tile.test.cpp
+++ b/test/tile/vector_tile.test.cpp
@@ -64,7 +64,7 @@ TEST(VectorTile, Issue7615) {
std::map<
std::string,
std::pair<style::IconPaintProperties::Evaluated, style::TextPaintProperties::Evaluated>>(),
- 0.0f, false, false);
+ 16.0f, 1.0f, 0.0f, false, false);
// Simulate placement of a symbol layer.
tile.onPlacement(GeometryTile::PlacementResult {