From 264109b1fc1d8ca2d6df8f644794bdf515130fd2 Mon Sep 17 00:00:00 2001 From: Anand Thakker Date: Tue, 28 Mar 2017 16:17:33 -0400 Subject: [PATCH 01/10] Update gl-js and generate style code --- .../conversion/make_property_setters.hpp | 4 +- include/mbgl/style/layers/symbol_layer.hpp | 12 +- mapbox-gl-js | 2 +- .../style/layers/PropertyFactory.java | 12 +- .../testapp/style/SymbolLayerTest.java | 216 ++++++++++++++++++ platform/darwin/src/MGLSymbolStyleLayer.h | 18 ++ platform/darwin/src/MGLSymbolStyleLayer.mm | 12 +- .../darwin/test/MGLSymbolStyleLayerTests.mm | 60 ++++- src/mbgl/programs/collision_box_program.hpp | 2 +- src/mbgl/programs/line_program.hpp | 2 +- src/mbgl/programs/symbol_program.hpp | 4 +- src/mbgl/shaders/preludes.cpp | 18 +- src/mbgl/shaders/symbol_icon.cpp | 51 ++++- src/mbgl/shaders/symbol_sdf.cpp | 82 +++++-- src/mbgl/style/layers/symbol_layer.cpp | 12 +- .../style/layers/symbol_layer_properties.hpp | 4 +- 16 files changed, 439 insertions(+), 72 deletions(-) diff --git a/include/mbgl/style/conversion/make_property_setters.hpp b/include/mbgl/style/conversion/make_property_setters.hpp index 85bcd44cf39..105cca99d68 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, &SymbolLayer::setIconIgnorePlacement>; result["icon-optional"] = &setLayoutProperty, &SymbolLayer::setIconOptional>; result["icon-rotation-alignment"] = &setLayoutProperty, &SymbolLayer::setIconRotationAlignment>; - result["icon-size"] = &setLayoutProperty, &SymbolLayer::setIconSize>; + result["icon-size"] = &setLayoutProperty, &SymbolLayer::setIconSize>; result["icon-text-fit"] = &setLayoutProperty, &SymbolLayer::setIconTextFit>; result["icon-text-fit-padding"] = &setLayoutProperty>, &SymbolLayer::setIconTextFitPadding>; result["icon-image"] = &setLayoutProperty, &SymbolLayer::setIconImage>; @@ -49,7 +49,7 @@ auto makeLayoutPropertySetters() { result["text-rotation-alignment"] = &setLayoutProperty, &SymbolLayer::setTextRotationAlignment>; result["text-field"] = &setLayoutProperty, &SymbolLayer::setTextField>; result["text-font"] = &setLayoutProperty>, &SymbolLayer::setTextFont>; - result["text-size"] = &setLayoutProperty, &SymbolLayer::setTextSize>; + result["text-size"] = &setLayoutProperty, &SymbolLayer::setTextSize>; result["text-max-width"] = &setLayoutProperty, &SymbolLayer::setTextMaxWidth>; result["text-line-height"] = &setLayoutProperty, &SymbolLayer::setTextLineHeight>; result["text-letter-spacing"] = &setLayoutProperty, &SymbolLayer::setTextLetterSpacing>; diff --git a/include/mbgl/style/layers/symbol_layer.hpp b/include/mbgl/style/layers/symbol_layer.hpp index 853a71bef2e..6e29faa9499 100644 --- a/include/mbgl/style/layers/symbol_layer.hpp +++ b/include/mbgl/style/layers/symbol_layer.hpp @@ -59,9 +59,9 @@ class SymbolLayer : public Layer { PropertyValue getIconRotationAlignment() const; void setIconRotationAlignment(PropertyValue); - static PropertyValue getDefaultIconSize(); - PropertyValue getIconSize() const; - void setIconSize(PropertyValue); + static DataDrivenPropertyValue getDefaultIconSize(); + DataDrivenPropertyValue getIconSize() const; + void setIconSize(DataDrivenPropertyValue); static PropertyValue getDefaultIconTextFit(); PropertyValue getIconTextFit() const; @@ -107,9 +107,9 @@ class SymbolLayer : public Layer { PropertyValue> getTextFont() const; void setTextFont(PropertyValue>); - static PropertyValue getDefaultTextSize(); - PropertyValue getTextSize() const; - void setTextSize(PropertyValue); + static DataDrivenPropertyValue getDefaultTextSize(); + DataDrivenPropertyValue getTextSize() const; + void setTextSize(DataDrivenPropertyValue); static PropertyValue getDefaultTextMaxWidth(); PropertyValue getTextMaxWidth() const; diff --git a/mapbox-gl-js b/mapbox-gl-js index aa329d31f4d..e3b2df28079 160000 --- a/mapbox-gl-js +++ b/mapbox-gl-js @@ -1 +1 @@ -Subproject commit aa329d31f4d750c8481a017b861d72c38d722fe8 +Subproject commit e3b2df28079f350747db177e0707698847d0bcd1 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 269a7770505..e37245000ee 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 static PropertyValue iconSize(Float value) { /** * Scale factor for icon. 1 is original size, 3 triples the size. * - * @param the zoom parameter type - * @param function a wrapper {@link CameraFunction} for Float + * @param the function input type + * @param function a wrapper function for Float * @return property wrapper around a Float function */ - public static PropertyValue> iconSize(CameraFunction function) { + public static PropertyValue> iconSize(Function function) { return new LayoutPropertyValue<>("icon-size", function); } @@ -1802,11 +1802,11 @@ public static PropertyValue textSize(Float value) { /** * Font size. * - * @param the zoom parameter type - * @param function a wrapper {@link CameraFunction} for Float + * @param the function input type + * @param function a wrapper function for Float * @return property wrapper around a Float function */ - public static PropertyValue> textSize(CameraFunction function) { + public static PropertyValue> textSize(Function 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 e8af375d666..d81965f2c9e 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 @@ -382,6 +382,114 @@ public void testIconSizeAsCameraFunction() { } + @Test + public void testIconSizeAsIdentitySourceFunction() { + checkViewIsDisplayed(R.id.mapView); + Timber.i("icon-size"); + assertNotNull(layer); + + // Set + layer.setProperties( + iconSize(property("FeaturePropertyA", Stops.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, Float> stops = + (ExponentialStops, Float>) layer.getIconSize().getFunction().getStops(); + Stop, 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); @@ -1074,6 +1182,114 @@ public void testTextSizeAsCameraFunction() { } + @Test + public void testTextSizeAsIdentitySourceFunction() { + checkViewIsDisplayed(R.id.mapView); + Timber.i("text-size"); + assertNotNull(layer); + + // Set + layer.setProperties( + textSize(property("FeaturePropertyA", Stops.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, Float> stops = + (ExponentialStops, Float>) layer.getTextSize().getFunction().getStops(); + Stop, 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); diff --git a/platform/darwin/src/MGLSymbolStyleLayer.h b/platform/darwin/src/MGLSymbolStyleLayer.h index 2c32b36c315..70406100934 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 *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 *textFontSize; diff --git a/platform/darwin/src/MGLSymbolStyleLayer.mm b/platform/darwin/src/MGLSymbolStyleLayer.mm index c01877f8dc5..0f7953311e7 100644 --- a/platform/darwin/src/MGLSymbolStyleLayer.mm +++ b/platform/darwin/src/MGLSymbolStyleLayer.mm @@ -356,7 +356,7 @@ - (void)setIconRotationAlignment:(MGLStyleValue *)iconRotationAlignme - (void)setIconScale:(MGLStyleValue *)iconScale { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(iconScale); + auto mbglValue = MGLStyleValueTransformer().toDataDrivenPropertyValue(iconScale); self.rawLayer->setIconSize(mbglValue); } @@ -365,9 +365,9 @@ - (void)setIconScale:(MGLStyleValue *)iconScale { auto propertyValue = self.rawLayer->getIconSize(); if (propertyValue.isUndefined()) { - return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultIconSize()); + return MGLStyleValueTransformer().toDataDrivenStyleValue(self.rawLayer->getDefaultIconSize()); } - return MGLStyleValueTransformer().toStyleValue(propertyValue); + return MGLStyleValueTransformer().toDataDrivenStyleValue(propertyValue); } - (void)setIconSize:(MGLStyleValue *)iconSize { @@ -657,7 +657,7 @@ - (void)setTextFont:(MGLStyleValue *> *)textFont { - (void)setTextFontSize:(MGLStyleValue *)textFontSize { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(textFontSize); + auto mbglValue = MGLStyleValueTransformer().toDataDrivenPropertyValue(textFontSize); self.rawLayer->setTextSize(mbglValue); } @@ -666,9 +666,9 @@ - (void)setTextFontSize:(MGLStyleValue *)textFontSize { auto propertyValue = self.rawLayer->getTextSize(); if (propertyValue.isUndefined()) { - return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultTextSize()); + return MGLStyleValueTransformer().toDataDrivenStyleValue(self.rawLayer->getDefaultTextSize()); } - return MGLStyleValueTransformer().toStyleValue(propertyValue); + return MGLStyleValueTransformer().toDataDrivenStyleValue(propertyValue); } - (void)setTextSize:(MGLStyleValue *)textSize { diff --git a/platform/darwin/test/MGLSymbolStyleLayerTests.mm b/platform/darwin/test/MGLSymbolStyleLayerTests.mm index eee61dd5d79..367ebf363c8 100644 --- a/platform/darwin/test/MGLSymbolStyleLayerTests.mm +++ b/platform/darwin/test/MGLSymbolStyleLayerTests.mm @@ -405,7 +405,7 @@ - (void)testProperties { MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; layer.iconScale = constantStyleValue; - mbgl::style::PropertyValue propertyValue = { 0xff }; + mbgl::style::DataDrivenPropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getIconSize(), propertyValue, @"Setting iconScale to a constant value should update icon-size."); XCTAssertEqualObjects(layer.iconScale, constantStyleValue, @@ -422,6 +422,29 @@ - (void)testProperties { XCTAssertEqualObjects(layer.iconScale, functionStyleValue, @"iconScale should round-trip camera functions."); + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil]; + layer.iconScale = functionStyleValue; + + mbgl::style::ExponentialStops exponentialStops = { {{18, 0xff}}, 1.0 }; + propertyValue = mbgl::style::SourceFunction { "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 valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil]; + layer.iconScale = functionStyleValue; + + std::map innerStops { {18, 0xff} }; + mbgl::style::CompositeExponentialStops compositeStops { { {10.0, innerStops} }, 1.0 }; + + propertyValue = mbgl::style::CompositeFunction { "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 @@ - (void)testProperties { @"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 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 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 @@ - (void)testProperties { MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; layer.textFontSize = constantStyleValue; - mbgl::style::PropertyValue propertyValue = { 0xff }; + mbgl::style::DataDrivenPropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getTextSize(), propertyValue, @"Setting textFontSize to a constant value should update text-size."); XCTAssertEqualObjects(layer.textFontSize, constantStyleValue, @@ -969,6 +987,29 @@ - (void)testProperties { XCTAssertEqualObjects(layer.textFontSize, functionStyleValue, @"textFontSize should round-trip camera functions."); + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil]; + layer.textFontSize = functionStyleValue; + + mbgl::style::ExponentialStops exponentialStops = { {{18, 0xff}}, 1.0 }; + propertyValue = mbgl::style::SourceFunction { "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 valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil]; + layer.textFontSize = functionStyleValue; + + std::map innerStops { {18, 0xff} }; + mbgl::style::CompositeExponentialStops compositeStops { { {10.0, innerStops} }, 1.0 }; + + propertyValue = mbgl::style::CompositeFunction { "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 @@ - (void)testProperties { @"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 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 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/programs/collision_box_program.hpp b/src/mbgl/programs/collision_box_program.hpp index 78ed6aa0c99..4bf8f76d92c 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<2, uint8_t>>; class CollisionBoxProgram : public Program< shaders::collision_box, diff --git a/src/mbgl/programs/line_program.hpp b/src/mbgl/programs/line_program.hpp index 842b4cc6023..e2a3e68fef1 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<4, uint8_t>> {}; class LineProgram : public Program< diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp index fdd1aa5c3bb..9b01b8ec5df 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -36,8 +36,8 @@ MBGL_DEFINE_UNIFORM_SCALAR(float, u_gamma_scale); struct SymbolLayoutAttributes : gl::Attributes< attributes::a_pos_offset, - attributes::a_texture_pos, - attributes::a_data<4>> + attributes::a_data<4, uint16_t>, + attributes::a_size> { static Vertex vertex(Point a, Point o, diff --git a/src/mbgl/shaders/preludes.cpp b/src/mbgl/shaders/preludes.cpp index 806e6552855..cca0f3e3f10 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 9adda0ba169..b6fbed428e8 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 7cbc9babf5a..194e6240368 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 bd5cf30ad67..e79a3f967f5 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 value) { impl->layout.unevaluated.get() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "icon-rotation-alignment"); } -PropertyValue SymbolLayer::getDefaultIconSize() { +DataDrivenPropertyValue SymbolLayer::getDefaultIconSize() { return IconSize::defaultValue(); } -PropertyValue SymbolLayer::getIconSize() const { +DataDrivenPropertyValue SymbolLayer::getIconSize() const { return impl->layout.unevaluated.get(); } -void SymbolLayer::setIconSize(PropertyValue value) { +void SymbolLayer::setIconSize(DataDrivenPropertyValue value) { if (value == getIconSize()) return; impl->layout.unevaluated.get() = value; @@ -329,15 +329,15 @@ void SymbolLayer::setTextFont(PropertyValue> value) { impl->layout.unevaluated.get() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "text-font"); } -PropertyValue SymbolLayer::getDefaultTextSize() { +DataDrivenPropertyValue SymbolLayer::getDefaultTextSize() { return TextSize::defaultValue(); } -PropertyValue SymbolLayer::getTextSize() const { +DataDrivenPropertyValue SymbolLayer::getTextSize() const { return impl->layout.unevaluated.get(); } -void SymbolLayer::setTextSize(PropertyValue value) { +void SymbolLayer::setTextSize(DataDrivenPropertyValue value) { if (value == getTextSize()) return; impl->layout.unevaluated.get() = value; diff --git a/src/mbgl/style/layers/symbol_layer_properties.hpp b/src/mbgl/style/layers/symbol_layer_properties.hpp index 4f63ed419aa..42f593890b9 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 { static AlignmentType defaultValue() { return AlignmentType::Auto; } }; -struct IconSize : LayoutProperty { +struct IconSize : DataDrivenLayoutProperty { static constexpr const char * key = "icon-size"; static float defaultValue() { return 1; } }; @@ -105,7 +105,7 @@ struct TextFont : LayoutProperty> { static std::vector defaultValue() { return { "Open Sans Regular", "Arial Unicode MS Regular" }; } }; -struct TextSize : LayoutProperty { +struct TextSize : DataDrivenLayoutProperty { static constexpr const char * key = "text-size"; static float defaultValue() { return 16; } }; From 2dd46a83e24eca612f2426b07ce2ec319fdc5593 Mon Sep 17 00:00:00 2001 From: Anand Thakker Date: Tue, 28 Mar 2017 16:48:28 -0400 Subject: [PATCH 02/10] Factor out packUint8Pair() helper function --- src/mbgl/programs/attributes.hpp | 10 ++++++++++ src/mbgl/programs/symbol_program.hpp | 14 +++++++++----- src/mbgl/style/paint_property_binder.hpp | 10 +++------- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/mbgl/programs/attributes.hpp b/src/mbgl/programs/attributes.hpp index 7d39c043950..e43a87aa2b4 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 +inline uint16_t packUint8Pair(T a, T b) { + return static_cast(a) * 256 + static_cast(b); +} + // Layout attributes MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_pos); diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp index 9b01b8ec5df..060c7fdd5ac 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -57,13 +57,17 @@ struct SymbolLayoutAttributes : gl::Attributes< }}, {{ static_cast(tx / 4), - static_cast(ty / 4) + static_cast(ty / 4), + mbgl::attributes::packUint8Pair( + static_cast(labelminzoom * 10), // 1/10 zoom levels: z16 == 160 + static_cast(labelangle) + ), + mbgl::attributes::packUint8Pair( + static_cast(minzoom * 10), + static_cast(::fmin(maxzoom, 25) * 10) + ) }}, {{ - static_cast(labelminzoom * 10), // 1/10 zoom levels: z16 == 160 - static_cast(labelangle), - static_cast(minzoom * 10), - static_cast(::fmin(maxzoom, 25) * 10) }} }; } diff --git a/src/mbgl/style/paint_property_binder.hpp b/src/mbgl/style/paint_property_binder.hpp index 7e44b509a19..bf98e6ef9aa 100644 --- a/src/mbgl/style/paint_property_binder.hpp +++ b/src/mbgl/style/paint_property_binder.hpp @@ -26,16 +26,12 @@ inline std::array 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 attributeValue(const Color& color) { return {{ - static_cast(static_cast(color.r * 255) * 256 + static_cast(color.g * 255)), - static_cast(static_cast(color.b * 255) * 256 + static_cast(color.a * 255)) + static_cast(mbgl::attributes::packUint8Pair(255 * color.r, 255 * color.g)), + static_cast(mbgl::attributes::packUint8Pair(255 * color.b, 255 * color.a)) }}; } From 7d8d2d84cd723d56994e1624d52b267a17291c28 Mon Sep 17 00:00:00 2001 From: Anand Thakker Date: Thu, 30 Mar 2017 23:39:19 -0400 Subject: [PATCH 03/10] Draft implementation of DDS for {text,icon}-size Ports https://github.com/mapbox/mapbox-gl-js/pull/4455 --- .../mbgl/style/data_driven_property_value.hpp | 9 + .../mbgl/style/function/camera_function.hpp | 18 ++ .../style/function/composite_function.hpp | 14 + src/mbgl/layout/symbol_instance.cpp | 8 +- src/mbgl/layout/symbol_instance.hpp | 1 + src/mbgl/layout/symbol_layout.cpp | 73 +++-- src/mbgl/layout/symbol_layout.hpp | 8 +- src/mbgl/programs/attributes.hpp | 9 +- src/mbgl/programs/collision_box_program.hpp | 2 +- src/mbgl/programs/line_program.hpp | 2 +- src/mbgl/programs/symbol_program.cpp | 71 +++-- src/mbgl/programs/symbol_program.hpp | 250 ++++++++++++++++-- src/mbgl/renderer/painter_symbol.cpp | 17 +- src/mbgl/renderer/symbol_bucket.cpp | 9 +- src/mbgl/renderer/symbol_bucket.hpp | 9 +- src/mbgl/style/layers/symbol_layer_impl.cpp | 6 - src/mbgl/style/layers/symbol_layer_impl.hpp | 1 - src/mbgl/text/quads.cpp | 3 +- src/mbgl/text/quads.hpp | 1 + 19 files changed, 438 insertions(+), 73 deletions(-) diff --git a/include/mbgl/style/data_driven_property_value.hpp b/include/mbgl/style/data_driven_property_value.hpp index 3f9ac694363..5acf800840f 100644 --- a/include/mbgl/style/data_driven_property_value.hpp +++ b/include/mbgl/style/data_driven_property_value.hpp @@ -45,6 +45,15 @@ class DataDrivenPropertyValue { bool isDataDriven() const { return value.template is>() || value.template is>(); } + + bool isZoomConstant() const { + return !value.template is>() && !value.template is>(); + } + + template + auto match(Ts&&... ts) const { + return value.match(std::forward(ts)...); + } template 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 5636b1663c9..0bb5edc873c 100644 --- a/include/mbgl/style/function/camera_function.hpp +++ b/include/mbgl/style/function/camera_function.hpp @@ -28,6 +28,24 @@ class CameraFunction { return s.evaluate(Value(double(zoom))).value_or(T()); }); } + + // TODO: this is duped from composite function; dedupe it. + Range coveringZoomStops(float lowerZoom, float upperZoom) const { + return stops.match( + [&] (const auto& s) { + assert(!s.stops.empty()); + auto minIt = s.stops.lower_bound(lowerZoom); + auto maxIt = s.stops.upper_bound(upperZoom); + if (minIt != s.stops.begin()) { + minIt--; + } + return Range { + minIt == s.stops.end() ? s.stops.rbegin()->first : minIt->first, + maxIt == s.stops.end() ? s.stops.rbegin()->first : maxIt->first + }; + } + ); + } friend bool operator==(const CameraFunction& lhs, const CameraFunction& rhs) { diff --git a/include/mbgl/style/function/composite_function.hpp b/include/mbgl/style/function/composite_function.hpp index 2b4ae504ca5..33e38b308c2 100644 --- a/include/mbgl/style/function/composite_function.hpp +++ b/include/mbgl/style/function/composite_function.hpp @@ -76,6 +76,20 @@ class CompositeFunction { } ); } + + Range coveringZoomStops(float lowerZoom, float upperZoom) const { + return stops.match( + [&] (const auto& s) { + assert(!s.stops.empty()); + auto minIt = s.stops.lower_bound(lowerZoom); + auto maxIt = s.stops.upper_bound(upperZoom); + return Range { + minIt == s.stops.end() ? s.stops.rbegin()->first : minIt->first, + maxIt == s.stops.end() ? s.stops.rbegin()->first : maxIt->first + }; + } + ); + } template Range evaluate(Range coveringStops, diff --git a/src/mbgl/layout/symbol_instance.cpp b/src/mbgl/layout/symbol_instance.cpp index 8bdc528bbbb..2a3bf068c17 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& 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 70ebfeefa29..efe6cb05aa2 100644 --- a/src/mbgl/layout/symbol_instance.hpp +++ b/src/mbgl/layout/symbol_instance.hpp @@ -17,6 +17,7 @@ class SymbolInstance { const std::pair& 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 978caabd70d..7f6cae03116 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()->impl->layout.unevaluated.get()), + iconSize(layers.at(0)->as()->impl->layout.unevaluated.get()) + { const SymbolLayer::Impl& leader = *layers.at(0)->as()->impl; @@ -77,11 +80,6 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, layout.get() = layout.get(); } - textMaxSize = leader.layout.evaluate(PropertyEvaluationParameters(18)); - - layout.get() = leader.layout.evaluate(PropertyEvaluationParameters(zoom + 1)); - layout.get() = leader.layout.evaluate(PropertyEvaluationParameters(zoom + 1)); - const bool hasText = has(layout) && !layout.get().empty(); const bool hasIcon = has(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() / glyphSize; + + const float layoutTextSize = layout.evaluate(zoom + 1, feature); + const float layoutIconSize = layout.evaluate(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(18, feature); + + const float fontScale = layoutTextSize / glyphSize; const float textBoxScale = tilePixelRatio * fontScale; const float textMaxBoxScale = tilePixelRatio * textMaxSize / glyphSize; - const float iconBoxScale = tilePixelRatio * layout.get(); + const float iconBoxScale = tilePixelRatio * layoutIconSize; const float symbolSpacing = tilePixelRatio * layout.get(); const bool avoidEdges = layout.get() && layout.get() != SymbolPlacementType::Line; const float textPadding = layout.get() * tilePixelRatio; @@ -316,7 +323,7 @@ void SymbolLayout::addFeature(const std::size_t index, : layout.get(); 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 SymbolLayout::place(CollisionTile& collisionTile) { - auto bucket = std::make_unique(layout, layerPaintProperties, zoom, sdfIcons, iconsNeedLinear); + auto bucket = std::make_unique(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 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 SymbolLayout::place(CollisionTile& collisionTile) if (glyphScale < collisionTile.maxScale) { for (const auto& symbol : symbolInstance.glyphQuads) { addSymbol( - bucket->text, symbol, placementZoom, + bucket->text, bucket->textSizeData, symbol, feature, textSize, placementZoom, keepUpright, textPlacement, collisionTile.config.angle, symbolInstance.writingModes); } } @@ -497,12 +507,11 @@ std::unique_ptr SymbolLayout::place(CollisionTile& collisionTile) collisionTile.insertFeature(symbolInstance.iconCollisionFeature, iconScale, layout.get()); if (iconScale < collisionTile.maxScale && symbolInstance.iconQuad) { addSymbol( - bucket->icon, *symbolInstance.iconQuad, placementZoom, + bucket->icon, bucket->iconSizeData, *symbolInstance.iconQuad, feature, iconSize, placementZoom, keepUpright, iconPlacement, collisionTile.config.angle, symbolInstance.writingModes); } } - const auto& feature = features.at(symbolInstance.featureIndex); for (auto& pair : bucket->paintPropertyBinders) { pair.second.first.populateVertexVectors(feature, bucket->icon.vertices.vertexSize()); pair.second.second.populateVertexVectors(feature, bucket->text.vertices.vertexSize()); @@ -518,7 +527,10 @@ std::unique_ptr SymbolLayout::place(CollisionTile& collisionTile) template void SymbolLayout::addSymbol(Buffer& buffer, + SymbolSizeData& sizeData, const SymbolQuad& symbol, + const SymbolFeature& feature, + const style::DataDrivenPropertyValue& size, const float placementZoom, const bool keepUpright, const style::SymbolPlacementType placement, @@ -580,6 +592,37 @@ void SymbolLayout::addSymbol(Buffer& buffer, minZoom, maxZoom, placementZoom, glyphAngle)); buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, br, tex.x + tex.w, tex.y + tex.h, minZoom, maxZoom, placementZoom, glyphAngle)); + + size.match( + [&] (const style::CompositeFunction& fn) { + const auto sizeVertex = SymbolSizeAttributes::Vertex { + {{ + static_cast(fn.evaluate(sizeData.coveringZoomStops->min, feature, sizeData.defaultSize) * 10), + static_cast(fn.evaluate(sizeData.coveringZoomStops->max, feature, sizeData.defaultSize) * 10), + static_cast(fn.evaluate(zoom + 1, feature, sizeData.defaultSize) * 10) + }} + }; + auto& vertexVector = sizeData.vertices.get>(); + vertexVector.emplace_back(sizeVertex); + vertexVector.emplace_back(sizeVertex); + vertexVector.emplace_back(sizeVertex); + vertexVector.emplace_back(sizeVertex); + }, + [&] (const style::SourceFunction& fn) { + const auto sizeVertex = SymbolSizeAttributes::SourceFunctionVertex { + {{ static_cast(fn.evaluate(feature, sizeData.defaultSize) * 10) }} + }; + + auto& vertexVector = sizeData.vertices.get>(); + vertexVector.emplace_back(sizeVertex); + vertexVector.emplace_back(sizeVertex); + vertexVector.emplace_back(sizeVertex); + vertexVector.emplace_back(sizeVertex); + }, + [] (const auto&) { + mbgl::Log::Debug(mbgl::Event::General, "feature-constant symbol"); + } + ); // 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 d79ccb3273d..56cfb30f286 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -64,7 +65,8 @@ class SymbolLayout { // Adds placed items to the buffer. template - void addSymbol(Buffer&, const SymbolQuad&, float scale, + void addSymbol(Buffer&, SymbolSizeData& sizeData, const SymbolQuad&, const SymbolFeature& feature, + const style::DataDrivenPropertyValue& size, float scale, const bool keepUpright, const style::SymbolPlacementType, const float placementAngle, WritingModeType writingModes); @@ -75,7 +77,6 @@ class SymbolLayout { 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 +85,9 @@ class SymbolLayout { bool sdfIcons = false; bool iconsNeedLinear = false; + + style::TextSize::UnevaluatedType textSize; + style::IconSize::UnevaluatedType iconSize; std::vector symbolInstances; std::vector features; diff --git a/src/mbgl/programs/attributes.hpp b/src/mbgl/programs/attributes.hpp index e43a87aa2b4..e9ca18927ec 100644 --- a/src/mbgl/programs/attributes.hpp +++ b/src/mbgl/programs/attributes.hpp @@ -25,10 +25,15 @@ MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_extrude); MBGL_DEFINE_ATTRIBUTE(int16_t, 4, a_pos_offset); MBGL_DEFINE_ATTRIBUTE(uint16_t, 2, a_texture_pos); -template +template struct a_data { static auto name() { return "a_data"; } - using Type = gl::Attribute; + using Type = gl::Attribute; +}; + +struct a_size { + static auto name() { return "a_size"; } + using Type = gl::Attribute; }; template diff --git a/src/mbgl/programs/collision_box_program.hpp b/src/mbgl/programs/collision_box_program.hpp index 4bf8f76d92c..89b69484fdb 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, uint8_t>>; + attributes::a_data>; class CollisionBoxProgram : public Program< shaders::collision_box, diff --git a/src/mbgl/programs/line_program.hpp b/src/mbgl/programs/line_program.hpp index e2a3e68fef1..b2e55a4f3b3 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, uint8_t>> + attributes::a_data> {}; class LineProgram : public Program< diff --git a/src/mbgl/programs/symbol_program.cpp b/src/mbgl/programs/symbol_program.cpp index 19fe2bc2f66..8e67c9c63fe 100644 --- a/src/mbgl/programs/symbol_program.cpp +++ b/src/mbgl/programs/symbol_program.cpp @@ -3,6 +3,7 @@ #include #include #include +#include namespace mbgl { @@ -11,51 +12,77 @@ using namespace style; static_assert(sizeof(SymbolLayoutVertex) == 16, "expected SymbolLayoutVertex size"); template -Values makeValues(const style::SymbolPropertyValues& values, +Values makeValues(const bool isText, + const style::SymbolPropertyValues& values, + const SymbolSizeData& sizeData, const Size& texsize, const std::array& pixelsToGLUnits, const RenderTile& tile, const TransformState& state, Args&&... args) { std::array 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); - + float sizeInterpolationT; + float renderSize = sizeData.layoutSize; + float layoutSize = sizeData.layoutSize; + sizeData.sizePropertyValue.match( + [&] (const CompositeFunction&) { + const auto& coveringStops = *sizeData.coveringZoomStops; + const float t = (state.getZoom() - coveringStops.min) / (coveringStops.max - coveringStops.min); + sizeInterpolationT = util::clamp(t, 0.0f, 1.0f); + }, + [&] (const CameraFunction& fn) { + const auto& coveringStops = *sizeData.coveringZoomStops; + const float t = (state.getZoom() - coveringStops.min) / (coveringStops.max - coveringStops.min); + const float lowerValue = fn.evaluate(coveringStops.min); + const float upperValue = fn.evaluate(coveringStops.max); + renderSize = lowerValue + (upperValue - lowerValue) * util::clamp(t, 0.0f, 1.0f); + }, + [&] (const auto&) {} + ); + 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(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 }, + uniforms::u_is_zoom_constant::Value{ sizeData.sizePropertyValue.isZoomConstant() }, + uniforms::u_is_feature_constant::Value{ !sizeData.sizePropertyValue.isDataDriven() }, + uniforms::u_size_t::Value{ sizeInterpolationT }, + uniforms::u_size::Value{ renderSize }, + uniforms::u_layout_size::Value{ layoutSize }, std::forward(args)... }; } SymbolIconProgram::UniformValues -SymbolIconProgram::uniformValues(const style::SymbolPropertyValues& values, +SymbolIconProgram::uniformValues(const bool isText, + const style::SymbolPropertyValues& values, + const SymbolSizeData& sizeData, const Size& texsize, const std::array& pixelsToGLUnits, const RenderTile& tile, const TransformState& state) { return makeValues( + isText, values, + sizeData, texsize, pixelsToGLUnits, tile, @@ -64,26 +91,28 @@ SymbolIconProgram::uniformValues(const style::SymbolPropertyValues& values, } template -typename SymbolSDFProgram::UniformValues SymbolSDFProgram::uniformValues(const style::SymbolPropertyValues& values, - const Size& texsize, - const std::array& pixelsToGLUnits, - const RenderTile& tile, - const TransformState& state, - const SymbolSDFPart part) +typename SymbolSDFProgram::UniformValues SymbolSDFProgram::uniformValues( + const bool isText, + const style::SymbolPropertyValues& values, + const SymbolSizeData& sizeData, + const Size& texsize, + const std::array& 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::UniformValues>( + isText, values, + sizeData, 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 060c7fdd5ac..6c4ee2f496b 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -1,6 +1,16 @@ #pragma once -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + #include #include #include @@ -10,6 +20,7 @@ #include #include + #include #include @@ -30,14 +41,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_zoom_constant); +MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_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_data<4, uint16_t>, - attributes::a_size> + attributes::a_data> { static Vertex vertex(Point a, Point o, @@ -66,14 +82,198 @@ struct SymbolLayoutAttributes : gl::Attributes< static_cast(minzoom * 10), static_cast(::fmin(maxzoom, 25) * 10) ) - }}, - {{ }} }; } }; + +struct SymbolSizeAttributes : gl::Attributes { + using SourceFunctionVertex = gl::detail::Vertex>; + struct monostate {}; + using VertexVector = variant< + monostate, + gl::VertexVector, + gl::VertexVector>; + + using VertexBuffer = variant< + monostate, + gl::VertexBuffer, + gl::VertexBuffer>; + + using Attribute = attributes::a_size::Type; + + static Bindings attributeBindings(const VertexBuffer& buffer) { + return buffer.match( + [&] (const monostate&) { + return Bindings { Attribute::ConstantBinding {{{0, 0, 0}}} }; + }, + [&] (const gl::VertexBuffer& buffer) { + return Bindings { Attribute::variableBinding(buffer, 0, 1) }; + }, + [&] (const gl::VertexBuffer& buffer) { + return Bindings { Attribute::variableBinding(buffer, 0) }; + } + ); + }; +}; -class SymbolIconProgram : public Program< + +class SymbolSizeData { +public: + SymbolSizeData(float tileZoom, const style::DataDrivenPropertyValue& size, float defaultSize_) + : sizePropertyValue(size), + layoutZoom(tileZoom + 1), + defaultSize(defaultSize_) { + size.match( + [&] (float constantSize) { layoutSize = constantSize; }, + [&] (const style::CameraFunction& fn) { + layoutSize = fn.evaluate(layoutZoom); + coveringZoomStops = fn.coveringZoomStops(tileZoom, tileZoom + 1); + }, + [&] (const style::SourceFunction&) { + vertices = gl::VertexVector {}; + }, + [&] (const style::CompositeFunction& fn) { + coveringZoomStops = fn.coveringZoomStops(tileZoom, tileZoom + 1); + vertices = gl::VertexVector {}; + }, + [&] (const auto&) {} + ); + }; + + + void upload(gl::Context& context) { + vertices.match( + // TODO: what's the best way to avoid copying the vertexVector here? + [&] (gl::VertexVector vertexVector) { + // TODO - why does directly assigning vertexBuffer = context.createVertexBuffer(...) fail? + vertexBuffer = SymbolSizeAttributes::VertexBuffer { context.createVertexBuffer(std::move(vertexVector)) }; + }, + [&] (gl::VertexVector vertexVector) { + vertexBuffer = SymbolSizeAttributes::VertexBuffer { context.createVertexBuffer(std::move(vertexVector)) }; + }, + [&] (const auto&) {} + ); + } + + style::DataDrivenPropertyValue sizePropertyValue; + float layoutZoom; + float layoutSize; + float defaultSize; + optional> coveringZoomStops; + SymbolSizeAttributes::VertexVector vertices; + SymbolSizeAttributes::VertexBuffer vertexBuffer; +}; + + +template +class SymbolProgram { +public: + using LayoutAttributes = LayoutAttrs; + using LayoutVertex = typename LayoutAttributes::Vertex; + + using LayoutAndSizeAttributes = gl::ConcatenateAttributes; + + using PaintPropertyBinders = typename PaintProperties::Binders; + using PaintAttributes = typename PaintPropertyBinders::Attributes; + using Attributes = gl::ConcatenateAttributes; + + using UniformValues = typename Uniforms::Values; + using PaintUniforms = typename PaintPropertyBinders::Uniforms; + using AllUniforms = gl::ConcatenateUniforms; + + using ProgramType = gl::Program; + + ProgramType program; + + SymbolProgram(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(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) + }; + }()) { + } + + template + void draw(gl::Context& context, + DrawMode drawMode, + gl::DepthMode depthMode, + gl::StencilMode stencilMode, + gl::ColorMode colorMode, + UniformValues&& uniformValues, + const gl::VertexBuffer& layoutVertexBuffer, + const SymbolSizeAttributes::VertexBuffer& sizeVertexBuffer, + const gl::IndexBuffer& indexBuffer, + const gl::SegmentVector& 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(paintPropertyBinders.uniformValues(currentZoom)), + LayoutAttributes::allVariableBindings(layoutVertexBuffer) + .concat(SymbolSizeAttributes::attributeBindings(sizeVertexBuffer)) + .concat(paintPropertyBinders.attributeBindings(currentProperties)), + indexBuffer, + segments + ); + } +}; + +class SymbolIconProgram : public SymbolProgram< shaders::symbol_icon, gl::Triangle, SymbolLayoutAttributes, @@ -84,13 +284,21 @@ 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, + uniforms::u_is_zoom_constant, + uniforms::u_is_feature_constant, + uniforms::u_size_t, + uniforms::u_size, + uniforms::u_layout_size>, 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 SymbolSizeData& sizeData, const Size& texsize, const std::array& pixelsToGLUnits, const RenderTile&, @@ -103,7 +311,7 @@ enum class SymbolSDFPart { }; template -class SymbolSDFProgram : public Program< +class SymbolSDFProgram : public SymbolProgram< shaders::symbol_sdf, gl::Triangle, SymbolLayoutAttributes, @@ -115,7 +323,12 @@ 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_is_zoom_constant, + uniforms::u_is_feature_constant, + uniforms::u_size_t, + uniforms::u_size, + uniforms::u_layout_size, uniforms::u_gamma_scale, uniforms::u_pitch, uniforms::u_bearing, @@ -125,7 +338,7 @@ class SymbolSDFProgram : public Program< PaintProperties> { public: - using BaseProgram = Program& pixelsToGLUnits, const RenderTile&, diff --git a/src/mbgl/renderer/painter_symbol.cpp b/src/mbgl/renderer/painter_symbol.cpp index 48c2e7ff663..f53b0b986eb 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 SymbolSizeAttributes::VertexBuffer& sizeBuffer, const SymbolPropertyValues& values_, const auto& binders, const auto& paintProperties) @@ -52,6 +53,7 @@ void Painter::renderSymbol(PaintParameters& parameters, colorModeForRenderPass(), std::move(uniformValues), *buffers.vertexBuffer, + sizeBuffer, *buffers.indexBuffer, buffers.segments, binders, @@ -74,8 +76,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, bucket.iconSizeData, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Halo), bucket.icon, + bucket.iconSizeData.vertexBuffer, values, bucket.paintPropertyBinders.at(layer.getID()).first, paintPropertyValues); @@ -83,16 +86,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, bucket.iconSizeData, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Fill), bucket.icon, + bucket.iconSizeData.vertexBuffer, values, bucket.paintPropertyBinders.at(layer.getID()).first, paintPropertyValues); } } else { draw(parameters.programs.symbolIcon, - SymbolIconProgram::uniformValues(values, texsize, pixelsToGLUnits, tile, state), + SymbolIconProgram::uniformValues(false, values, bucket.iconSizeData, texsize, pixelsToGLUnits, tile, state), bucket.icon, + bucket.iconSizeData.vertexBuffer, values, bucket.paintPropertyBinders.at(layer.getID()).first, paintPropertyValues); @@ -109,8 +114,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, bucket.textSizeData, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Halo), bucket.text, + bucket.textSizeData.vertexBuffer, values, bucket.paintPropertyBinders.at(layer.getID()).second, paintPropertyValues); @@ -118,8 +124,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, bucket.textSizeData, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Fill), bucket.text, + bucket.textSizeData.vertexBuffer, 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 b046571740f..768c9c2ed70 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>& layerPaintProperties, + const style::DataDrivenPropertyValue& textSize, + const style::DataDrivenPropertyValue& iconSize, float zoom, bool sdfIcons_, bool iconsNeedLinear_) : layout(std::move(layout_)), sdfIcons(sdfIcons_), - iconsNeedLinear(iconsNeedLinear_) { + iconsNeedLinear(iconsNeedLinear_), + textSizeData(zoom, textSize, TextSize::defaultValue()), + iconSizeData(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)); + textSizeData.upload(context); } if (hasIconData()) { icon.vertexBuffer = context.createVertexBuffer(std::move(icon.vertices)); icon.indexBuffer = context.createIndexBuffer(std::move(icon.triangles)); + iconSizeData.upload(context); } if (!collisionBox.vertices.empty()) { diff --git a/src/mbgl/renderer/symbol_bucket.hpp b/src/mbgl/renderer/symbol_bucket.hpp index 7a498ab17d5..33071d155aa 100644 --- a/src/mbgl/renderer/symbol_bucket.hpp +++ b/src/mbgl/renderer/symbol_bucket.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -18,6 +19,8 @@ class SymbolBucket : public Bucket { public: SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated, const std::map>&, + const style::DataDrivenPropertyValue& textSize, + const style::DataDrivenPropertyValue& iconSize, float zoom, bool sdfIcons, bool iconsNeedLinear); @@ -36,6 +39,8 @@ class SymbolBucket : public Bucket { std::map> paintPropertyBinders; + + SymbolSizeData textSizeData; struct TextBuffer { gl::VertexVector vertices; @@ -45,7 +50,9 @@ class SymbolBucket : public Bucket { optional> vertexBuffer; optional> indexBuffer; } text; - + + SymbolSizeData iconSizeData; + struct IconBuffer { gl::VertexVector vertices; gl::IndexVector triangles; diff --git a/src/mbgl/style/layers/symbol_layer_impl.cpp b/src/mbgl/style/layers/symbol_layer_impl.cpp index c637770c046..004d8d21dbf 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(parameters); - textSize = layout.evaluate(parameters); - auto hasIconOpacity = paint.evaluated.get().constantOr(Color::black()).a > 0 || paint.evaluated.get().constantOr(Color::black()).a > 0; auto hasTextOpacity = paint.evaluated.get().constantOr(Color::black()).a > 0 || @@ -76,7 +72,6 @@ SymbolPropertyValues SymbolLayer::Impl::iconPropertyValues(const SymbolLayoutPro return SymbolPropertyValues { layout_.get(), // icon-pitch-alignment is not yet implemented; inherit the rotation alignment layout_.get(), - layout_.get(), paint.evaluated.get(), paint.evaluated.get(), iconSize, @@ -91,7 +86,6 @@ SymbolPropertyValues SymbolLayer::Impl::textPropertyValues(const SymbolLayoutPro return SymbolPropertyValues { layout_.get(), layout_.get(), - layout_.get(), paint.evaluated.get(), paint.evaluated.get(), textSize, diff --git a/src/mbgl/style/layers/symbol_layer_impl.hpp b/src/mbgl/style/layers/symbol_layer_impl.hpp index db20989f017..f1d4273f0b7 100644 --- a/src/mbgl/style/layers/symbol_layer_impl.hpp +++ b/src/mbgl/style/layers/symbol_layer_impl.hpp @@ -44,7 +44,6 @@ class SymbolPropertyValues { // Layout AlignmentType pitchAlignment; AlignmentType rotationAlignment; - float layoutSize; // Paint std::array translate; diff --git a/src/mbgl/text/quads.cpp b/src/mbgl/text/quads.cpp index b13a6a71e54..188f88655d7 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() != IconTextFitType::None && shapedText) { auto iconWidth = right - left; auto iconHeight = bottom - top; - auto size = layout.get() / 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 f1529d88294..333000627b0 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); From c803b0a03d6de10d42cac56c7389c599ddeaefdc Mon Sep 17 00:00:00 2001 From: Anand Thakker Date: Sat, 1 Apr 2017 18:16:03 -0400 Subject: [PATCH 04/10] Fix text-size/composite-function-line-placement test --- .../mbgl/style/function/composite_function.hpp | 9 ++++++++- src/mbgl/programs/symbol_program.cpp | 4 ++-- src/mbgl/programs/symbol_program.hpp | 17 +++++++++-------- src/mbgl/renderer/painter_symbol.cpp | 5 ++++- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/include/mbgl/style/function/composite_function.hpp b/include/mbgl/style/function/composite_function.hpp index 33e38b308c2..ace2f3a5f9c 100644 --- a/include/mbgl/style/function/composite_function.hpp +++ b/include/mbgl/style/function/composite_function.hpp @@ -82,7 +82,14 @@ class CompositeFunction { [&] (const auto& s) { assert(!s.stops.empty()); auto minIt = s.stops.lower_bound(lowerZoom); - auto maxIt = s.stops.upper_bound(upperZoom); + // minIt is first element >= lowerZoom. If it's >, back up by one. + if (minIt != s.stops.begin() && minIt->first > lowerZoom) { + minIt--; + } + auto maxIt = s.stops.find(upperZoom); + if (maxIt == s.stops.end()) { + maxIt = s.stops.upper_bound(upperZoom); + } return Range { minIt == s.stops.end() ? s.stops.rbegin()->first : minIt->first, maxIt == s.stops.end() ? s.stops.rbegin()->first : maxIt->first diff --git a/src/mbgl/programs/symbol_program.cpp b/src/mbgl/programs/symbol_program.cpp index 8e67c9c63fe..e1f119cef9b 100644 --- a/src/mbgl/programs/symbol_program.cpp +++ b/src/mbgl/programs/symbol_program.cpp @@ -61,8 +61,8 @@ Values makeValues(const bool isText, uniforms::u_texture::Value{ 0 }, uniforms::u_fadetexture::Value{ 1 }, uniforms::u_is_text::Value{ isText }, - uniforms::u_is_zoom_constant::Value{ sizeData.sizePropertyValue.isZoomConstant() }, - uniforms::u_is_feature_constant::Value{ !sizeData.sizePropertyValue.isDataDriven() }, + uniforms::u_is_size_zoom_constant::Value{ sizeData.sizePropertyValue.isZoomConstant() }, + uniforms::u_is_size_feature_constant::Value{ !sizeData.sizePropertyValue.isDataDriven() }, uniforms::u_size_t::Value{ sizeInterpolationT }, uniforms::u_size::Value{ renderSize }, uniforms::u_layout_size::Value{ layoutSize }, diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp index 6c4ee2f496b..c17ce1201f6 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -44,8 +44,8 @@ MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_halo); MBGL_DEFINE_UNIFORM_SCALAR(float, u_gamma_scale); MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_text); -MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_zoom_constant); -MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_feature_constant); +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); @@ -123,6 +123,7 @@ class SymbolSizeData { SymbolSizeData(float tileZoom, const style::DataDrivenPropertyValue& size, float defaultSize_) : sizePropertyValue(size), layoutZoom(tileZoom + 1), + layoutSize(defaultSize_), defaultSize(defaultSize_) { size.match( [&] (float constantSize) { layoutSize = constantSize; }, @@ -286,8 +287,8 @@ class SymbolIconProgram : public SymbolProgram< uniforms::u_texture, uniforms::u_fadetexture, uniforms::u_is_text, - uniforms::u_is_zoom_constant, - uniforms::u_is_feature_constant, + uniforms::u_is_size_zoom_constant, + uniforms::u_is_size_feature_constant, uniforms::u_size_t, uniforms::u_size, uniforms::u_layout_size>, @@ -324,8 +325,8 @@ class SymbolSDFProgram : public SymbolProgram< uniforms::u_texture, uniforms::u_fadetexture, uniforms::u_is_text, - uniforms::u_is_zoom_constant, - uniforms::u_is_feature_constant, + uniforms::u_is_size_zoom_constant, + uniforms::u_is_size_feature_constant, uniforms::u_size_t, uniforms::u_size, uniforms::u_layout_size, @@ -350,8 +351,8 @@ class SymbolSDFProgram : public SymbolProgram< uniforms::u_texture, uniforms::u_fadetexture, uniforms::u_is_text, - uniforms::u_is_zoom_constant, - uniforms::u_is_feature_constant, + uniforms::u_is_size_zoom_constant, + uniforms::u_is_size_feature_constant, uniforms::u_size_t, uniforms::u_size, uniforms::u_layout_size, diff --git a/src/mbgl/renderer/painter_symbol.cpp b/src/mbgl/renderer/painter_symbol.cpp index f53b0b986eb..c306aca5223 100644 --- a/src/mbgl/renderer/painter_symbol.cpp +++ b/src/mbgl/renderer/painter_symbol.cpp @@ -67,7 +67,10 @@ 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 auto iconSize = bucket.iconSizeData.sizePropertyValue; + const bool iconSizeScaled = iconSize.isDataDriven() || !iconSize.isZoomConstant() || + *layout.get().constant() != 1.0; + const bool iconScaled = iconSizeScaled || 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); From e59e1bef9ff43fd1b63f2b25c0df3ab7374064d4 Mon Sep 17 00:00:00 2001 From: Anand Thakker Date: Tue, 4 Apr 2017 08:48:36 -0400 Subject: [PATCH 05/10] Refactor to PaintPropertyBinders-like strategy --- src/mbgl/layout/symbol_layout.cpp | 38 +-- src/mbgl/layout/symbol_layout.hpp | 13 +- src/mbgl/programs/symbol_program.cpp | 45 ++-- src/mbgl/programs/symbol_program.hpp | 269 ++++++++++++++------ src/mbgl/renderer/painter_symbol.cpp | 32 +-- src/mbgl/renderer/symbol_bucket.cpp | 10 +- src/mbgl/renderer/symbol_bucket.hpp | 4 +- src/mbgl/style/layers/symbol_layer_impl.cpp | 2 + src/mbgl/style/layers/symbol_layer_impl.hpp | 1 + 9 files changed, 241 insertions(+), 173 deletions(-) diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index 7f6cae03116..907e60a5983 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -496,7 +496,7 @@ std::unique_ptr SymbolLayout::place(CollisionTile& collisionTile) if (glyphScale < collisionTile.maxScale) { for (const auto& symbol : symbolInstance.glyphQuads) { addSymbol( - bucket->text, bucket->textSizeData, symbol, feature, textSize, placementZoom, + bucket->text, *bucket->textSizeBinder, symbol, feature, placementZoom, keepUpright, textPlacement, collisionTile.config.angle, symbolInstance.writingModes); } } @@ -507,7 +507,7 @@ std::unique_ptr SymbolLayout::place(CollisionTile& collisionTile) collisionTile.insertFeature(symbolInstance.iconCollisionFeature, iconScale, layout.get()); if (iconScale < collisionTile.maxScale && symbolInstance.iconQuad) { addSymbol( - bucket->icon, bucket->iconSizeData, *symbolInstance.iconQuad, feature, iconSize, placementZoom, + bucket->icon, *bucket->iconSizeBinder, *symbolInstance.iconQuad, feature, placementZoom, keepUpright, iconPlacement, collisionTile.config.angle, symbolInstance.writingModes); } } @@ -527,10 +527,9 @@ std::unique_ptr SymbolLayout::place(CollisionTile& collisionTile) template void SymbolLayout::addSymbol(Buffer& buffer, - SymbolSizeData& sizeData, + SymbolSizeBinder& sizeBinder, const SymbolQuad& symbol, const SymbolFeature& feature, - const style::DataDrivenPropertyValue& size, const float placementZoom, const bool keepUpright, const style::SymbolPlacementType placement, @@ -593,36 +592,7 @@ void SymbolLayout::addSymbol(Buffer& buffer, buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, br, tex.x + tex.w, tex.y + tex.h, minZoom, maxZoom, placementZoom, glyphAngle)); - size.match( - [&] (const style::CompositeFunction& fn) { - const auto sizeVertex = SymbolSizeAttributes::Vertex { - {{ - static_cast(fn.evaluate(sizeData.coveringZoomStops->min, feature, sizeData.defaultSize) * 10), - static_cast(fn.evaluate(sizeData.coveringZoomStops->max, feature, sizeData.defaultSize) * 10), - static_cast(fn.evaluate(zoom + 1, feature, sizeData.defaultSize) * 10) - }} - }; - auto& vertexVector = sizeData.vertices.get>(); - vertexVector.emplace_back(sizeVertex); - vertexVector.emplace_back(sizeVertex); - vertexVector.emplace_back(sizeVertex); - vertexVector.emplace_back(sizeVertex); - }, - [&] (const style::SourceFunction& fn) { - const auto sizeVertex = SymbolSizeAttributes::SourceFunctionVertex { - {{ static_cast(fn.evaluate(feature, sizeData.defaultSize) * 10) }} - }; - - auto& vertexVector = sizeData.vertices.get>(); - vertexVector.emplace_back(sizeVertex); - vertexVector.emplace_back(sizeVertex); - vertexVector.emplace_back(sizeVertex); - vertexVector.emplace_back(sizeVertex); - }, - [] (const auto&) { - mbgl::Log::Debug(mbgl::Event::General, "feature-constant symbol"); - } - ); + 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 56cfb30f286..4ec84f0f587 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -65,10 +65,15 @@ class SymbolLayout { // Adds placed items to the buffer. template - void addSymbol(Buffer&, SymbolSizeData& sizeData, const SymbolQuad&, const SymbolFeature& feature, - const style::DataDrivenPropertyValue& size, 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; diff --git a/src/mbgl/programs/symbol_program.cpp b/src/mbgl/programs/symbol_program.cpp index e1f119cef9b..86f61c4ad20 100644 --- a/src/mbgl/programs/symbol_program.cpp +++ b/src/mbgl/programs/symbol_program.cpp @@ -11,10 +11,25 @@ using namespace style; static_assert(sizeof(SymbolLayoutVertex) == 16, "expected SymbolLayoutVertex size"); +std::unique_ptr SymbolSizeBinder::create(const float tileZoom, + const style::DataDrivenPropertyValue& sizeProperty, + const float defaultValue) { + return sizeProperty.match( + [&] (const style::CompositeFunction& function) -> std::unique_ptr { + return std::make_unique(tileZoom, function, defaultValue); + }, + [&] (const style::SourceFunction& function) { + return std::make_unique(tileZoom, function, defaultValue); + }, + [&] (const auto& value) -> std::unique_ptr { + return std::make_unique(tileZoom, value, defaultValue); + } + ); +} + template Values makeValues(const bool isText, const style::SymbolPropertyValues& values, - const SymbolSizeData& sizeData, const Size& texsize, const std::array& pixelsToGLUnits, const RenderTile& tile, @@ -30,25 +45,6 @@ Values makeValues(const bool isText, pixelsToGLUnits[1] * state.getCameraToCenterDistance() }}; } - - float sizeInterpolationT; - float renderSize = sizeData.layoutSize; - float layoutSize = sizeData.layoutSize; - sizeData.sizePropertyValue.match( - [&] (const CompositeFunction&) { - const auto& coveringStops = *sizeData.coveringZoomStops; - const float t = (state.getZoom() - coveringStops.min) / (coveringStops.max - coveringStops.min); - sizeInterpolationT = util::clamp(t, 0.0f, 1.0f); - }, - [&] (const CameraFunction& fn) { - const auto& coveringStops = *sizeData.coveringZoomStops; - const float t = (state.getZoom() - coveringStops.min) / (coveringStops.max - coveringStops.min); - const float lowerValue = fn.evaluate(coveringStops.min); - const float upperValue = fn.evaluate(coveringStops.max); - renderSize = lowerValue + (upperValue - lowerValue) * util::clamp(t, 0.0f, 1.0f); - }, - [&] (const auto&) {} - ); return Values { uniforms::u_matrix::Value{ tile.translatedMatrix(values.translate, @@ -61,11 +57,6 @@ Values makeValues(const bool isText, uniforms::u_texture::Value{ 0 }, uniforms::u_fadetexture::Value{ 1 }, uniforms::u_is_text::Value{ isText }, - uniforms::u_is_size_zoom_constant::Value{ sizeData.sizePropertyValue.isZoomConstant() }, - uniforms::u_is_size_feature_constant::Value{ !sizeData.sizePropertyValue.isDataDriven() }, - uniforms::u_size_t::Value{ sizeInterpolationT }, - uniforms::u_size::Value{ renderSize }, - uniforms::u_layout_size::Value{ layoutSize }, std::forward(args)... }; } @@ -73,7 +64,6 @@ Values makeValues(const bool isText, SymbolIconProgram::UniformValues SymbolIconProgram::uniformValues(const bool isText, const style::SymbolPropertyValues& values, - const SymbolSizeData& sizeData, const Size& texsize, const std::array& pixelsToGLUnits, const RenderTile& tile, @@ -82,7 +72,6 @@ SymbolIconProgram::uniformValues(const bool isText, return makeValues( isText, values, - sizeData, texsize, pixelsToGLUnits, tile, @@ -94,7 +83,6 @@ template typename SymbolSDFProgram::UniformValues SymbolSDFProgram::uniformValues( const bool isText, const style::SymbolPropertyValues& values, - const SymbolSizeData& sizeData, const Size& texsize, const std::array& pixelsToGLUnits, const RenderTile& tile, @@ -108,7 +96,6 @@ typename SymbolSDFProgram::UniformValues SymbolSDFProgram::UniformValues>( isText, values, - sizeData, texsize, pixelsToGLUnits, tile, diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp index c17ce1201f6..a3f5533138c 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -87,83 +88,199 @@ struct SymbolLayoutAttributes : gl::Attributes< } }; -struct SymbolSizeAttributes : gl::Attributes { - using SourceFunctionVertex = gl::detail::Vertex>; - struct monostate {}; - using VertexVector = variant< - monostate, - gl::VertexVector, - gl::VertexVector>; +class SymbolSizeAttributes : public gl::Attributes { +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 create(const float tileZoom, + const style::DataDrivenPropertyValue& sizeProperty, + const float defaultValue); + + virtual SymbolSizeAttributes::Bindings attributeBindings(const style::PossiblyEvaluatedPropertyValue currentValue) const = 0; + virtual void populateVertexVector(const GeometryTileFeature& feature) = 0; + virtual UniformValues uniformValues(float currentZoom) const = 0; + virtual void upload(gl::Context&) = 0; +}; + +class ConstantSymbolSizeBinder : public SymbolSizeBinder { +public: + using PropertyValue = variant>; - using VertexBuffer = variant< - monostate, - gl::VertexBuffer, - gl::VertexBuffer>; + ConstantSymbolSizeBinder(const float /*tileZoom*/, const float& size, const float /*defaultValue*/) + : layoutSize(size) {} - using Attribute = attributes::a_size::Type; + ConstantSymbolSizeBinder(const float /*tileZoom*/, const style::Undefined&, const float defaultValue) + : layoutSize(defaultValue) {} + + ConstantSymbolSizeBinder(const float tileZoom, const style::CameraFunction& function, const float /*defaultValue*/) + : layoutSize(function.evaluate(tileZoom + 1)) { + coveringRanges = std::make_tuple( + function.coveringZoomStops(tileZoom, tileZoom + 1), + Range { function.evaluate(tileZoom), function.evaluate(tileZoom + 1) } + ); + } + + SymbolSizeAttributes::Bindings attributeBindings(const style::PossiblyEvaluatedPropertyValue) const override { + return SymbolSizeAttributes::Bindings { SymbolSizeAttributes::Attribute::ConstantBinding {{{0, 0, 0}}} }; + } + void upload(gl::Context&) override {} + void populateVertexVector(const GeometryTileFeature&) override {}; - static Bindings attributeBindings(const VertexBuffer& buffer) { - return buffer.match( - [&] (const monostate&) { - return Bindings { Attribute::ConstantBinding {{{0, 0, 0}}} }; - }, - [&] (const gl::VertexBuffer& buffer) { - return Bindings { Attribute::variableBinding(buffer, 0, 1) }; - }, - [&] (const gl::VertexBuffer& buffer) { - return Bindings { Attribute::variableBinding(buffer, 0) }; - } - ); + UniformValues uniformValues(float currentZoom) const override { + float size = layoutSize; + bool isZoomConstant = true; + if (coveringRanges) { + const Range& zoomLevels = std::get<0>(*coveringRanges); + const Range& sizeLevels = std::get<1>(*coveringRanges); + // TODO: interpolate properly + const float t = (currentZoom - zoomLevels.min) / (zoomLevels.max - zoomLevels.min); + size = sizeLevels.min + (sizeLevels.max - sizeLevels.min) * util::clamp(t, 0.0f, 1.0f); + isZoomConstant = false; + } + + 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; + optional, Range>> coveringRanges; }; +class SourceFunctionSymbolSizeBinder : public SymbolSizeBinder { +public: + using Vertex = gl::detail::Vertex>; + using VertexVector = gl::VertexVector; + using VertexBuffer = gl::VertexBuffer; + + SourceFunctionSymbolSizeBinder(const float /*tileZoom*/, const style::SourceFunction& function_, const float defaultValue_) + : function(function_), + defaultValue(defaultValue_) { + } -class SymbolSizeData { + SymbolSizeAttributes::Bindings attributeBindings(const style::PossiblyEvaluatedPropertyValue 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(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& function; + const float defaultValue; + + VertexVector vertices; + optional buffer; +}; + +class CompositeFunctionSymbolSizeBinder: public SymbolSizeBinder { public: - SymbolSizeData(float tileZoom, const style::DataDrivenPropertyValue& size, float defaultSize_) - : sizePropertyValue(size), + using Vertex = SymbolSizeAttributes::Vertex; + using VertexVector = gl::VertexVector; + using VertexBuffer = gl::VertexBuffer; + + CompositeFunctionSymbolSizeBinder(const float tileZoom, const style::CompositeFunction& function_, const float defaultValue_) + : function(function_), + defaultValue(defaultValue_), layoutZoom(tileZoom + 1), - layoutSize(defaultSize_), - defaultSize(defaultSize_) { - size.match( - [&] (float constantSize) { layoutSize = constantSize; }, - [&] (const style::CameraFunction& fn) { - layoutSize = fn.evaluate(layoutZoom); - coveringZoomStops = fn.coveringZoomStops(tileZoom, tileZoom + 1); - }, - [&] (const style::SourceFunction&) { - vertices = gl::VertexVector {}; - }, - [&] (const style::CompositeFunction& fn) { - coveringZoomStops = fn.coveringZoomStops(tileZoom, tileZoom + 1); - vertices = gl::VertexVector {}; - }, - [&] (const auto&) {} - ); + coveringZoomStops(function.coveringZoomStops(tileZoom, tileZoom + 1)) { + } + + SymbolSizeAttributes::Bindings attributeBindings(const style::PossiblyEvaluatedPropertyValue 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(function.evaluate(coveringZoomStops.min, feature, defaultValue) * 10), + static_cast(function.evaluate(coveringZoomStops.max, feature, defaultValue) * 10), + static_cast(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; + // TODO: interpolate properly + const float t = (currentZoom - coveringZoomStops.min) / (coveringZoomStops.max - coveringZoomStops.min); + sizeInterpolationT = util::clamp(t, 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) { - vertices.match( - // TODO: what's the best way to avoid copying the vertexVector here? - [&] (gl::VertexVector vertexVector) { - // TODO - why does directly assigning vertexBuffer = context.createVertexBuffer(...) fail? - vertexBuffer = SymbolSizeAttributes::VertexBuffer { context.createVertexBuffer(std::move(vertexVector)) }; - }, - [&] (gl::VertexVector vertexVector) { - vertexBuffer = SymbolSizeAttributes::VertexBuffer { context.createVertexBuffer(std::move(vertexVector)) }; - }, - [&] (const auto&) {} - ); + void upload(gl::Context& context) override { + buffer = VertexBuffer { context.createVertexBuffer(std::move(vertices)) }; } - style::DataDrivenPropertyValue sizePropertyValue; + const style::CompositeFunction& function; + const float defaultValue; float layoutZoom; - float layoutSize; - float defaultSize; - optional> coveringZoomStops; - SymbolSizeAttributes::VertexVector vertices; - SymbolSizeAttributes::VertexBuffer vertexBuffer; + Range coveringZoomStops; + + VertexVector vertices; + optional buffer; }; @@ -184,8 +301,9 @@ class SymbolProgram { using Attributes = gl::ConcatenateAttributes; using UniformValues = typename Uniforms::Values; + using SizeUniforms = typename SymbolSizeBinder::Uniforms; using PaintUniforms = typename PaintPropertyBinders::Uniforms; - using AllUniforms = gl::ConcatenateUniforms; + using AllUniforms = gl::ConcatenateUniforms>; using ProgramType = gl::Program; @@ -251,7 +369,8 @@ class SymbolProgram { gl::ColorMode colorMode, UniformValues&& uniformValues, const gl::VertexBuffer& layoutVertexBuffer, - const SymbolSizeAttributes::VertexBuffer& sizeVertexBuffer, + const SymbolSizeBinder& symbolSizeBinder, + const style::PossiblyEvaluatedPropertyValue& currentSizeValue, const gl::IndexBuffer& indexBuffer, const gl::SegmentVector& segments, const PaintPropertyBinders& paintPropertyBinders, @@ -264,9 +383,10 @@ class SymbolProgram { std::move(stencilMode), std::move(colorMode), uniformValues + .concat(symbolSizeBinder.uniformValues(currentZoom)) .concat(paintPropertyBinders.uniformValues(currentZoom)), LayoutAttributes::allVariableBindings(layoutVertexBuffer) - .concat(SymbolSizeAttributes::attributeBindings(sizeVertexBuffer)) + .concat(symbolSizeBinder.attributeBindings(currentSizeValue)) .concat(paintPropertyBinders.attributeBindings(currentProperties)), indexBuffer, segments @@ -286,12 +406,7 @@ class SymbolIconProgram : public SymbolProgram< uniforms::u_rotate_with_map, uniforms::u_texture, uniforms::u_fadetexture, - uniforms::u_is_text, - uniforms::u_is_size_zoom_constant, - uniforms::u_is_size_feature_constant, - uniforms::u_size_t, - uniforms::u_size, - uniforms::u_layout_size>, + uniforms::u_is_text>, style::IconPaintProperties> { public: @@ -299,7 +414,6 @@ class SymbolIconProgram : public SymbolProgram< static UniformValues uniformValues(const bool isText, const style::SymbolPropertyValues&, - const SymbolSizeData& sizeData, const Size& texsize, const std::array& pixelsToGLUnits, const RenderTile&, @@ -325,11 +439,6 @@ class SymbolSDFProgram : public SymbolProgram< uniforms::u_texture, uniforms::u_fadetexture, uniforms::u_is_text, - uniforms::u_is_size_zoom_constant, - uniforms::u_is_size_feature_constant, - uniforms::u_size_t, - uniforms::u_size, - uniforms::u_layout_size, uniforms::u_gamma_scale, uniforms::u_pitch, uniforms::u_bearing, @@ -351,11 +460,6 @@ class SymbolSDFProgram : public SymbolProgram< uniforms::u_texture, uniforms::u_fadetexture, uniforms::u_is_text, - uniforms::u_is_size_zoom_constant, - uniforms::u_is_size_feature_constant, - uniforms::u_size_t, - uniforms::u_size, - uniforms::u_layout_size, uniforms::u_gamma_scale, uniforms::u_pitch, uniforms::u_bearing, @@ -372,7 +476,6 @@ class SymbolSDFProgram : public SymbolProgram< static UniformValues uniformValues(const bool isText, const style::SymbolPropertyValues&, - const SymbolSizeData& sizeData, const Size& texsize, const std::array& pixelsToGLUnits, const RenderTile&, diff --git a/src/mbgl/renderer/painter_symbol.cpp b/src/mbgl/renderer/painter_symbol.cpp index c306aca5223..d2f492d17aa 100644 --- a/src/mbgl/renderer/painter_symbol.cpp +++ b/src/mbgl/renderer/painter_symbol.cpp @@ -33,7 +33,7 @@ void Painter::renderSymbol(PaintParameters& parameters, auto draw = [&] (auto& program, auto&& uniformValues, const auto& buffers, - const SymbolSizeAttributes::VertexBuffer& sizeBuffer, + const auto& symbolSizeBinder, const SymbolPropertyValues& values_, const auto& binders, const auto& paintProperties) @@ -53,7 +53,8 @@ void Painter::renderSymbol(PaintParameters& parameters, colorModeForRenderPass(), std::move(uniformValues), *buffers.vertexBuffer, - sizeBuffer, + *symbolSizeBinder, + values_.layoutSize, *buffers.indexBuffer, buffers.segments, binders, @@ -67,10 +68,9 @@ void Painter::renderSymbol(PaintParameters& parameters, auto paintPropertyValues = layer.impl->iconPaintProperties(); SpriteAtlas& atlas = *layer.impl->spriteAtlas; - const auto iconSize = bucket.iconSizeData.sizePropertyValue; - const bool iconSizeScaled = iconSize.isDataDriven() || !iconSize.isZoomConstant() || - *layout.get().constant() != 1.0; - const bool iconScaled = iconSizeScaled || frame.pixelRatio != atlas.getPixelRatio() || bucket.iconsNeedLinear; + const bool iconScaled = layout.get().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); @@ -79,9 +79,9 @@ void Painter::renderSymbol(PaintParameters& parameters, if (bucket.sdfIcons) { if (values.hasHalo) { draw(parameters.programs.symbolIconSDF, - SymbolSDFIconProgram::uniformValues(false, values, bucket.iconSizeData, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Halo), + SymbolSDFIconProgram::uniformValues(false, values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Halo), bucket.icon, - bucket.iconSizeData.vertexBuffer, + bucket.iconSizeBinder, values, bucket.paintPropertyBinders.at(layer.getID()).first, paintPropertyValues); @@ -89,18 +89,18 @@ void Painter::renderSymbol(PaintParameters& parameters, if (values.hasFill) { draw(parameters.programs.symbolIconSDF, - SymbolSDFIconProgram::uniformValues(false, values, bucket.iconSizeData, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Fill), + SymbolSDFIconProgram::uniformValues(false, values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Fill), bucket.icon, - bucket.iconSizeData.vertexBuffer, + bucket.iconSizeBinder, values, bucket.paintPropertyBinders.at(layer.getID()).first, paintPropertyValues); } } else { draw(parameters.programs.symbolIcon, - SymbolIconProgram::uniformValues(false, values, bucket.iconSizeData, texsize, pixelsToGLUnits, tile, state), + SymbolIconProgram::uniformValues(false, values, texsize, pixelsToGLUnits, tile, state), bucket.icon, - bucket.iconSizeData.vertexBuffer, + bucket.iconSizeBinder, values, bucket.paintPropertyBinders.at(layer.getID()).first, paintPropertyValues); @@ -117,9 +117,9 @@ void Painter::renderSymbol(PaintParameters& parameters, if (values.hasHalo) { draw(parameters.programs.symbolGlyph, - SymbolSDFTextProgram::uniformValues(true, values, bucket.textSizeData, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Halo), + SymbolSDFTextProgram::uniformValues(true, values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Halo), bucket.text, - bucket.textSizeData.vertexBuffer, + bucket.textSizeBinder, values, bucket.paintPropertyBinders.at(layer.getID()).second, paintPropertyValues); @@ -127,9 +127,9 @@ void Painter::renderSymbol(PaintParameters& parameters, if (values.hasFill) { draw(parameters.programs.symbolGlyph, - SymbolSDFTextProgram::uniformValues(true, values, bucket.textSizeData, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Fill), + SymbolSDFTextProgram::uniformValues(true, values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Fill), bucket.text, - bucket.textSizeData.vertexBuffer, + 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 768c9c2ed70..77a9a75ef1a 100644 --- a/src/mbgl/renderer/symbol_bucket.cpp +++ b/src/mbgl/renderer/symbol_bucket.cpp @@ -18,9 +18,9 @@ SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated layo bool iconsNeedLinear_) : layout(std::move(layout_)), sdfIcons(sdfIcons_), - iconsNeedLinear(iconsNeedLinear_), - textSizeData(zoom, textSize, TextSize::defaultValue()), - iconSizeData(zoom, iconSize, IconSize::defaultValue()) { + 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( @@ -37,13 +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)); - textSizeData.upload(context); + textSizeBinder->upload(context); } if (hasIconData()) { icon.vertexBuffer = context.createVertexBuffer(std::move(icon.vertices)); icon.indexBuffer = context.createIndexBuffer(std::move(icon.triangles)); - iconSizeData.upload(context); + iconSizeBinder->upload(context); } if (!collisionBox.vertices.empty()) { diff --git a/src/mbgl/renderer/symbol_bucket.hpp b/src/mbgl/renderer/symbol_bucket.hpp index 33071d155aa..659d7a37888 100644 --- a/src/mbgl/renderer/symbol_bucket.hpp +++ b/src/mbgl/renderer/symbol_bucket.hpp @@ -40,7 +40,7 @@ class SymbolBucket : public Bucket { SymbolIconProgram::PaintPropertyBinders, SymbolSDFTextProgram::PaintPropertyBinders>> paintPropertyBinders; - SymbolSizeData textSizeData; + std::unique_ptr textSizeBinder; struct TextBuffer { gl::VertexVector vertices; @@ -51,7 +51,7 @@ class SymbolBucket : public Bucket { optional> indexBuffer; } text; - SymbolSizeData iconSizeData; + std::unique_ptr iconSizeBinder; struct IconBuffer { gl::VertexVector vertices; diff --git a/src/mbgl/style/layers/symbol_layer_impl.cpp b/src/mbgl/style/layers/symbol_layer_impl.cpp index 004d8d21dbf..109d1c43e70 100644 --- a/src/mbgl/style/layers/symbol_layer_impl.cpp +++ b/src/mbgl/style/layers/symbol_layer_impl.cpp @@ -72,6 +72,7 @@ SymbolPropertyValues SymbolLayer::Impl::iconPropertyValues(const SymbolLayoutPro return SymbolPropertyValues { layout_.get(), // icon-pitch-alignment is not yet implemented; inherit the rotation alignment layout_.get(), + layout_.get(), paint.evaluated.get(), paint.evaluated.get(), iconSize, @@ -86,6 +87,7 @@ SymbolPropertyValues SymbolLayer::Impl::textPropertyValues(const SymbolLayoutPro return SymbolPropertyValues { layout_.get(), layout_.get(), + layout_.get(), paint.evaluated.get(), paint.evaluated.get(), textSize, diff --git a/src/mbgl/style/layers/symbol_layer_impl.hpp b/src/mbgl/style/layers/symbol_layer_impl.hpp index f1d4273f0b7..3d81ff1f694 100644 --- a/src/mbgl/style/layers/symbol_layer_impl.hpp +++ b/src/mbgl/style/layers/symbol_layer_impl.hpp @@ -44,6 +44,7 @@ class SymbolPropertyValues { // Layout AlignmentType pitchAlignment; AlignmentType rotationAlignment; + PossiblyEvaluatedPropertyValue layoutSize; // Paint std::array translate; From db1cc2862ee7a277d0b3ea5e211f46c82436175e Mon Sep 17 00:00:00 2001 From: Anand Thakker Date: Wed, 5 Apr 2017 12:40:56 -0400 Subject: [PATCH 06/10] Dedupe gl::Program construction --- src/mbgl/gl/program.hpp | 59 ++++++++++++++++++++++++++++ src/mbgl/programs/program.hpp | 55 +++----------------------- src/mbgl/programs/symbol_program.hpp | 55 +++----------------------- 3 files changed, 71 insertions(+), 98 deletions(-) diff --git a/src/mbgl/gl/program.hpp b/src/mbgl/gl/program.hpp index 7d7fca5263a..e032b1dfc6f 100644 --- a/src/mbgl/gl/program.hpp +++ b/src/mbgl/gl/program.hpp @@ -8,6 +8,10 @@ #include #include +#include +#include + + #include namespace mbgl { @@ -37,6 +41,61 @@ class Program { 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 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(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 optional get(Context& context, const std::string& identifier) const { diff --git a/src/mbgl/programs/program.hpp b/src/mbgl/programs/program.hpp index 8925bc75d67..7eec15e7552 100644 --- a/src/mbgl/programs/program.hpp +++ b/src/mbgl/programs/program.hpp @@ -34,55 +34,12 @@ class Program { 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(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 diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp index a3f5533138c..9393f925f92 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -310,55 +310,12 @@ class SymbolProgram { ProgramType program; SymbolProgram(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(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 From 4b884e2cfaa9485e42488cc91792fadf696092cb Mon Sep 17 00:00:00 2001 From: Anand Thakker Date: Wed, 5 Apr 2017 15:52:17 -0400 Subject: [PATCH 07/10] Use exponential function base for interpolation --- src/mbgl/programs/symbol_program.hpp | 61 +++++++++++++++++----------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp index 9393f925f92..7413b236912 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -2,15 +2,8 @@ #include #include -#include -#include -#include -#include -#include -#include -#include #include - +#include #include #include @@ -127,11 +120,19 @@ class ConstantSymbolSizeBinder : public SymbolSizeBinder { ConstantSymbolSizeBinder(const float /*tileZoom*/, const style::Undefined&, const float defaultValue) : layoutSize(defaultValue) {} - ConstantSymbolSizeBinder(const float tileZoom, const style::CameraFunction& function, const float /*defaultValue*/) - : layoutSize(function.evaluate(tileZoom + 1)) { - coveringRanges = std::make_tuple( - function.coveringZoomStops(tileZoom, tileZoom + 1), - Range { function.evaluate(tileZoom), function.evaluate(tileZoom + 1) } + ConstantSymbolSizeBinder(const float tileZoom, const style::CameraFunction& function_, const float /*defaultValue*/) + : layoutSize(function_.evaluate(tileZoom + 1)) { + function_.stops.match( + [&] (const style::ExponentialStops& stops) { + coveringRanges = std::make_tuple( + function_.coveringZoomStops(tileZoom, tileZoom + 1), + Range { function_.evaluate(tileZoom), function_.evaluate(tileZoom + 1) } + ); + functionInterpolationBase = stops.base; + }, + [&] (const style::IntervalStops&) { + function = function_; + } ); } @@ -143,14 +144,22 @@ class ConstantSymbolSizeBinder : public SymbolSizeBinder { UniformValues uniformValues(float currentZoom) const override { float size = layoutSize; - bool isZoomConstant = true; + 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& zoomLevels = std::get<0>(*coveringRanges); const Range& sizeLevels = std::get<1>(*coveringRanges); - // TODO: interpolate properly - const float t = (currentZoom - zoomLevels.min) / (zoomLevels.max - zoomLevels.min); - size = sizeLevels.min + (sizeLevels.max - sizeLevels.min) * util::clamp(t, 0.0f, 1.0f); - isZoomConstant = false; + 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 { @@ -163,7 +172,11 @@ class ConstantSymbolSizeBinder : public SymbolSizeBinder { } float layoutSize; + // used for exponential functions optional, Range>> coveringRanges; + optional functionInterpolationBase; + // used for interval functions + optional> function; }; class SourceFunctionSymbolSizeBinder : public SymbolSizeBinder { @@ -229,8 +242,8 @@ class CompositeFunctionSymbolSizeBinder: public SymbolSizeBinder { : function(function_), defaultValue(defaultValue_), layoutZoom(tileZoom + 1), - coveringZoomStops(function.coveringZoomStops(tileZoom, tileZoom + 1)) { - } + coveringZoomStops(function.coveringZoomStops(tileZoom, tileZoom + 1)) + {} SymbolSizeAttributes::Bindings attributeBindings(const style::PossiblyEvaluatedPropertyValue currentValue) const override { if (currentValue.isConstant()) { @@ -256,10 +269,10 @@ class CompositeFunctionSymbolSizeBinder: public SymbolSizeBinder { }; UniformValues uniformValues(float currentZoom) const override { - float sizeInterpolationT; - // TODO: interpolate properly - const float t = (currentZoom - coveringZoomStops.min) / (coveringZoomStops.max - coveringZoomStops.min); - sizeInterpolationT = util::clamp(t, 0.0f, 1.0f); + float sizeInterpolationT = util::clamp( + util::interpolationFactor(1.0f, coveringZoomStops, currentZoom), + 0.0f, 1.0f + ); return UniformValues { uniforms::u_is_size_zoom_constant::Value{ false }, From 583116e8b00abcc1a05c8741574ff739b7701127 Mon Sep 17 00:00:00 2001 From: Anand Thakker Date: Wed, 5 Apr 2017 17:43:32 -0400 Subject: [PATCH 08/10] Dedupe coveringZoomStops method --- .../mbgl/style/function/camera_function.hpp | 18 -------------- .../style/function/composite_function.hpp | 21 ---------------- src/mbgl/programs/symbol_program.hpp | 24 +++++++++++++++++-- 3 files changed, 22 insertions(+), 41 deletions(-) diff --git a/include/mbgl/style/function/camera_function.hpp b/include/mbgl/style/function/camera_function.hpp index 0bb5edc873c..2e4aac22386 100644 --- a/include/mbgl/style/function/camera_function.hpp +++ b/include/mbgl/style/function/camera_function.hpp @@ -29,24 +29,6 @@ class CameraFunction { }); } - // TODO: this is duped from composite function; dedupe it. - Range coveringZoomStops(float lowerZoom, float upperZoom) const { - return stops.match( - [&] (const auto& s) { - assert(!s.stops.empty()); - auto minIt = s.stops.lower_bound(lowerZoom); - auto maxIt = s.stops.upper_bound(upperZoom); - if (minIt != s.stops.begin()) { - minIt--; - } - return Range { - minIt == s.stops.end() ? s.stops.rbegin()->first : minIt->first, - maxIt == s.stops.end() ? s.stops.rbegin()->first : maxIt->first - }; - } - ); - } - friend bool operator==(const CameraFunction& lhs, const CameraFunction& rhs) { return lhs.stops == rhs.stops; diff --git a/include/mbgl/style/function/composite_function.hpp b/include/mbgl/style/function/composite_function.hpp index ace2f3a5f9c..2b4ae504ca5 100644 --- a/include/mbgl/style/function/composite_function.hpp +++ b/include/mbgl/style/function/composite_function.hpp @@ -76,27 +76,6 @@ class CompositeFunction { } ); } - - Range coveringZoomStops(float lowerZoom, float upperZoom) const { - return stops.match( - [&] (const auto& s) { - assert(!s.stops.empty()); - auto minIt = s.stops.lower_bound(lowerZoom); - // minIt is first element >= lowerZoom. If it's >, back up by one. - if (minIt != s.stops.begin() && minIt->first > lowerZoom) { - minIt--; - } - auto maxIt = s.stops.find(upperZoom); - if (maxIt == s.stops.end()) { - maxIt = s.stops.upper_bound(upperZoom); - } - return Range { - minIt == s.stops.end() ? s.stops.rbegin()->first : minIt->first, - maxIt == s.stops.end() ? s.stops.rbegin()->first : maxIt->first - }; - } - ); - } template Range evaluate(Range coveringStops, diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp index 7413b236912..ae50e790be8 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -110,6 +110,24 @@ class SymbolSizeBinder { virtual void upload(gl::Context&) = 0; }; +// Return the smallest range of stops that covers the interval [lowerZoom, upperZoom] +template +Range 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 { + 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>; @@ -125,7 +143,7 @@ class ConstantSymbolSizeBinder : public SymbolSizeBinder { function_.stops.match( [&] (const style::ExponentialStops& stops) { coveringRanges = std::make_tuple( - function_.coveringZoomStops(tileZoom, tileZoom + 1), + getCoveringStops(stops, tileZoom, tileZoom + 1), Range { function_.evaluate(tileZoom), function_.evaluate(tileZoom + 1) } ); functionInterpolationBase = stops.base; @@ -242,7 +260,9 @@ class CompositeFunctionSymbolSizeBinder: public SymbolSizeBinder { : function(function_), defaultValue(defaultValue_), layoutZoom(tileZoom + 1), - coveringZoomStops(function.coveringZoomStops(tileZoom, tileZoom + 1)) + coveringZoomStops(function.stops.match( + [&] (const auto& stops) { + return getCoveringStops(stops, tileZoom, tileZoom + 1); })) {} SymbolSizeAttributes::Bindings attributeBindings(const style::PossiblyEvaluatedPropertyValue currentValue) const override { From 926a9da5e3507f8d317c8dc4024911dc63742835 Mon Sep 17 00:00:00 2001 From: Anand Thakker Date: Wed, 5 Apr 2017 17:57:56 -0400 Subject: [PATCH 09/10] Fixup tests --- test/gl/bucket.test.cpp | 2 +- test/text/quads.test.cpp | 24 ++++++++++++------------ test/tile/vector_tile.test.cpp | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/test/gl/bucket.test.cpp b/test/gl/bucket.test.cpp index 1ab6623122a..5b66a0987f5 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 42bc0f20483..18fbedc2dd8 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() = 24.0f; layout.get() = 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() = 12.0f; layout.get() = 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()[2] = 5.0f; layout.get()[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() = 24.0f; layout.get() = 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() = 12.0f; layout.get() = 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()[2] = 5.0f; layout.get()[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() = 24.0f; layout.get() = 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() = 12.0f; layout.get() = 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()[2] = 5.0f; layout.get()[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()[2] = 10.0f; layout.get()[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 eb2b89d346f..95d21418fde 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>(), - 0.0f, false, false); + 16.0f, 1.0f, 0.0f, false, false); // Simulate placement of a symbol layer. tile.onPlacement(GeometryTile::PlacementResult { From 10e1fc146b58c923e26fc7b9f0f4e390d75d53af Mon Sep 17 00:00:00 2001 From: Anand Thakker Date: Wed, 5 Apr 2017 18:16:51 -0400 Subject: [PATCH 10/10] Fix CI errors (hidden within #if block) --- src/mbgl/gl/program.hpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/mbgl/gl/program.hpp b/src/mbgl/gl/program.hpp index e032b1dfc6f..1b23abe2b10 100644 --- a/src/mbgl/gl/program.hpp +++ b/src/mbgl/gl/program.hpp @@ -8,6 +8,8 @@ #include #include +#include +#include #include #include @@ -45,28 +47,28 @@ class Program { static Program createProgram(gl::Context& context, const ProgramParameters& programParameters, const char* name, - const char* vertexSource, - const char* fragmentSource) { + 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); + shaders::vertexSource(programParameters, vertexSource_); const std::string fragmentSource = - shaders::fragmentSource(programParameters, fragmentSource); + shaders::fragmentSource(programParameters, fragmentSource_); const std::string cachePath = shaders::programCachePath(programParameters, name); const std::string identifier = - shaders::programIdentifier(vertexSource, fragmentSource); + 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 }; + return Program { context, binaryProgram }; } else { Log::Warning(Event::OpenGL, "Cached program %s changed. Recompilation required.", - Shaders::name); + name); } } } catch (std::runtime_error& error) { @@ -75,7 +77,7 @@ class Program { } // Compile the shader - ProgramType result{ context, vertexSource, fragmentSource }; + Program result{ context, vertexSource, fragmentSource }; try { if (const auto binaryProgram = @@ -92,8 +94,8 @@ class Program { #endif (void)name; return Program { - context, shaders::vertexSource(programParameters, vertexSource), - shaders::fragmentSource(programParameters, fragmentSource) + context, shaders::vertexSource(programParameters, vertexSource_), + shaders::fragmentSource(programParameters, fragmentSource_) }; }