diff options
18 files changed, 296 insertions, 12 deletions
diff --git a/include/mbgl/style/conversion/make_property_setters.hpp b/include/mbgl/style/conversion/make_property_setters.hpp index eaea2e89dc..1c26aeb5e4 100644 --- a/include/mbgl/style/conversion/make_property_setters.hpp +++ b/include/mbgl/style/conversion/make_property_setters.hpp @@ -155,6 +155,8 @@ auto makePaintPropertySetters() { result["circle-translate-anchor-transition"] = &setTransition<V, CircleLayer, &CircleLayer::setCircleTranslateAnchorTransition>; result["circle-pitch-scale"] = &setProperty<V, CircleLayer, PropertyValue<CirclePitchScaleType>, &CircleLayer::setCirclePitchScale>; result["circle-pitch-scale-transition"] = &setTransition<V, CircleLayer, &CircleLayer::setCirclePitchScaleTransition>; + result["circle-pitch-alignment"] = &setProperty<V, CircleLayer, PropertyValue<AlignmentType>, &CircleLayer::setCirclePitchAlignment>; + result["circle-pitch-alignment-transition"] = &setTransition<V, CircleLayer, &CircleLayer::setCirclePitchAlignmentTransition>; result["circle-stroke-width"] = &setProperty<V, CircleLayer, DataDrivenPropertyValue<float>, &CircleLayer::setCircleStrokeWidth>; result["circle-stroke-width-transition"] = &setTransition<V, CircleLayer, &CircleLayer::setCircleStrokeWidthTransition>; result["circle-stroke-color"] = &setProperty<V, CircleLayer, DataDrivenPropertyValue<Color>, &CircleLayer::setCircleStrokeColor>; diff --git a/include/mbgl/style/layers/circle_layer.hpp b/include/mbgl/style/layers/circle_layer.hpp index 275a2e67a5..942dd67503 100644 --- a/include/mbgl/style/layers/circle_layer.hpp +++ b/include/mbgl/style/layers/circle_layer.hpp @@ -78,6 +78,12 @@ public: void setCirclePitchScaleTransition(const TransitionOptions&); TransitionOptions getCirclePitchScaleTransition() const; + static PropertyValue<AlignmentType> getDefaultCirclePitchAlignment(); + PropertyValue<AlignmentType> getCirclePitchAlignment() const; + void setCirclePitchAlignment(PropertyValue<AlignmentType>); + void setCirclePitchAlignmentTransition(const TransitionOptions&); + TransitionOptions getCirclePitchAlignmentTransition() const; + static DataDrivenPropertyValue<float> getDefaultCircleStrokeWidth(); DataDrivenPropertyValue<float> getCircleStrokeWidth() const; void setCircleStrokeWidth(DataDrivenPropertyValue<float>); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java index 1a7df06031..10663142b5 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java @@ -278,6 +278,16 @@ public class CircleLayer extends Layer { } /** + * Get the CirclePitchAlignment property + * + * @return property wrapper value around String + */ + @SuppressWarnings("unchecked") + public PropertyValue<String> getCirclePitchAlignment() { + return (PropertyValue<String>) new PropertyValue("circle-pitch-alignment", nativeGetCirclePitchAlignment()); + } + + /** * Get the CircleStrokeWidth property * * @return property wrapper value around Float @@ -411,6 +421,8 @@ public class CircleLayer extends Layer { private native Object nativeGetCirclePitchScale(); + private native Object nativeGetCirclePitchAlignment(); + private native Object nativeGetCircleStrokeWidth(); private native TransitionOptions nativeGetCircleStrokeWidthTransition(); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java index 5e345268f9..d3d0e060dc 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java @@ -446,6 +446,27 @@ public final class Property { @Retention(RetentionPolicy.SOURCE) public @interface CIRCLE_PITCH_SCALE {} + // CIRCLE_PITCH_ALIGNMENT: Orientation of circle when map is pitched. + + /** + * The circle is aligned to the plane of the map. + */ + public static final String CIRCLE_PITCH_ALIGNMENT_MAP = "map"; + /** + * The circle is aligned to the plane of the viewport. + */ + public static final String CIRCLE_PITCH_ALIGNMENT_VIEWPORT = "viewport"; + + /** + * Orientation of circle when map is pitched. + */ + @StringDef({ + CIRCLE_PITCH_ALIGNMENT_MAP, + CIRCLE_PITCH_ALIGNMENT_VIEWPORT, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface CIRCLE_PITCH_ALIGNMENT {} + // FILL_EXTRUSION_TRANSLATE_ANCHOR: Controls the translation reference point. /** 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 73896b7901..c12d6b7133 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 @@ -953,6 +953,28 @@ public class PropertyFactory { } /** + * Orientation of circle when map is pitched. + * + * @param value a String value + * @return property wrapper around String + */ + public static PropertyValue<String> circlePitchAlignment(@Property.CIRCLE_PITCH_ALIGNMENT String value) { + return new PaintPropertyValue<>("circle-pitch-alignment", value); + } + + + /** + * Orientation of circle when map is pitched. + * + * @param <Z> the zoom parameter type + * @param function a wrapper {@link CameraFunction} for String + * @return property wrapper around a String function + */ + public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> circlePitchAlignment(CameraFunction<Z, String> function) { + return new PaintPropertyValue<>("circle-pitch-alignment", function); + } + + /** * The width of the circle's stroke. Strokes are placed outside of the {@link PropertyFactory#circleRadius}. * * @param value a Float value diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java index c8f9640433..84f4c16801 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java @@ -1048,6 +1048,44 @@ public class CircleLayerTest extends BaseActivityTest { } @Test + public void testCirclePitchAlignmentAsConstant() { + validateTestSetup(); + setupLayer(); + Timber.i("circle-pitch-alignment"); + assertNotNull(layer); + + // Set and Get + layer.setProperties(circlePitchAlignment(CIRCLE_PITCH_ALIGNMENT_MAP)); + assertEquals((String) layer.getCirclePitchAlignment().getValue(), (String) CIRCLE_PITCH_ALIGNMENT_MAP); + } + + @Test + public void testCirclePitchAlignmentAsCameraFunction() { + validateTestSetup(); + setupLayer(); + Timber.i("circle-pitch-alignment"); + assertNotNull(layer); + + // Set + layer.setProperties( + circlePitchAlignment( + zoom( + interval( + stop(2, circlePitchAlignment(CIRCLE_PITCH_ALIGNMENT_MAP)) + ) + ) + ) + ); + + // Verify + assertNotNull(layer.getCirclePitchAlignment()); + assertNotNull(layer.getCirclePitchAlignment().getFunction()); + assertEquals(CameraFunction.class, layer.getCirclePitchAlignment().getFunction().getClass()); + assertEquals(IntervalStops.class, layer.getCirclePitchAlignment().getFunction().getStops().getClass()); + assertEquals(1, ((IntervalStops) layer.getCirclePitchAlignment().getFunction().getStops()).size()); + } + + @Test public void testCircleStrokeWidthTransition() { validateTestSetup(); setupLayer(); diff --git a/platform/android/src/style/layers/circle_layer.cpp b/platform/android/src/style/layers/circle_layer.cpp index 96a9356679..4c7f69e956 100644 --- a/platform/android/src/style/layers/circle_layer.cpp +++ b/platform/android/src/style/layers/circle_layer.cpp @@ -142,6 +142,12 @@ namespace android { return jni::Object<jni::ObjectTag>(*converted); } + jni::Object<jni::ObjectTag> CircleLayer::getCirclePitchAlignment(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::CircleLayer>()->CircleLayer::getCirclePitchAlignment()); + return jni::Object<jni::ObjectTag>(*converted); + } + jni::Object<jni::ObjectTag> CircleLayer::getCircleStrokeWidth(jni::JNIEnv& env) { using namespace mbgl::android::conversion; Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::CircleLayer>()->CircleLayer::getCircleStrokeWidth()); @@ -236,6 +242,7 @@ namespace android { METHOD(&CircleLayer::getCircleTranslate, "nativeGetCircleTranslate"), METHOD(&CircleLayer::getCircleTranslateAnchor, "nativeGetCircleTranslateAnchor"), METHOD(&CircleLayer::getCirclePitchScale, "nativeGetCirclePitchScale"), + METHOD(&CircleLayer::getCirclePitchAlignment, "nativeGetCirclePitchAlignment"), METHOD(&CircleLayer::getCircleStrokeWidthTransition, "nativeGetCircleStrokeWidthTransition"), METHOD(&CircleLayer::setCircleStrokeWidthTransition, "nativeSetCircleStrokeWidthTransition"), METHOD(&CircleLayer::getCircleStrokeWidth, "nativeGetCircleStrokeWidth"), diff --git a/platform/android/src/style/layers/circle_layer.hpp b/platform/android/src/style/layers/circle_layer.hpp index 81737e8996..9d323e92bb 100644 --- a/platform/android/src/style/layers/circle_layer.hpp +++ b/platform/android/src/style/layers/circle_layer.hpp @@ -53,6 +53,8 @@ public: jni::Object<jni::ObjectTag> getCirclePitchScale(jni::JNIEnv&); + jni::Object<jni::ObjectTag> getCirclePitchAlignment(jni::JNIEnv&); + jni::Object<jni::ObjectTag> getCircleStrokeWidth(jni::JNIEnv&); void setCircleStrokeWidthTransition(jni::JNIEnv&, jlong duration, jlong delay); jni::Object<TransitionOptions> getCircleStrokeWidthTransition(jni::JNIEnv&); diff --git a/platform/darwin/src/MGLCircleStyleLayer.h b/platform/darwin/src/MGLCircleStyleLayer.h index 789ff7a258..ea95f6beef 100644 --- a/platform/darwin/src/MGLCircleStyleLayer.h +++ b/platform/darwin/src/MGLCircleStyleLayer.h @@ -8,6 +8,23 @@ NS_ASSUME_NONNULL_BEGIN /** + Orientation of circle when map is pitched. + + Values of this type are used in the `MGLCircleStyleLayer.circlePitchAlignment` + property. + */ +typedef NS_ENUM(NSUInteger, MGLCirclePitchAlignment) { + /** + The circle is aligned to the plane of the map. + */ + MGLCirclePitchAlignmentMap, + /** + The circle is aligned to the plane of the viewport. + */ + MGLCirclePitchAlignmentViewport, +}; + +/** Controls the scaling behavior of the circle when the map is pitched. Values of this type are used in the `MGLCircleStyleLayer.circleScaleAlignment` @@ -221,6 +238,21 @@ MGL_EXPORT @property (nonatomic) MGLTransition circleOpacityTransition; /** + Orientation of circle when map is pitched. + + The default value of this property is an `MGLStyleValue` object containing an + `NSValue` object containing `MGLCirclePitchAlignmentViewport`. Set this + property to `nil` to reset it to the default value. + + You can set this property to an instance of: + + * `MGLConstantStyleValue` + * `MGLCameraStyleFunction` with an interpolation mode of + `MGLInterpolationModeInterval` + */ +@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circlePitchAlignment; + +/** Circle radius. This property is measured in points. @@ -491,6 +523,19 @@ MGL_EXPORT #pragma mark Working with Circle Style Layer Attribute Values /** + Creates a new value object containing the given `MGLCirclePitchAlignment` enumeration. + + @param circlePitchAlignment The value for the new object. + @return A new value object that contains the enumeration value. + */ ++ (instancetype)valueWithMGLCirclePitchAlignment:(MGLCirclePitchAlignment)circlePitchAlignment; + +/** + The `MGLCirclePitchAlignment` enumeration representation of the value. + */ +@property (readonly) MGLCirclePitchAlignment MGLCirclePitchAlignmentValue; + +/** Creates a new value object containing the given `MGLCircleScaleAlignment` enumeration. @param circleScaleAlignment The value for the new object. diff --git a/platform/darwin/src/MGLCircleStyleLayer.mm b/platform/darwin/src/MGLCircleStyleLayer.mm index 42961f2e12..71ae37035e 100644 --- a/platform/darwin/src/MGLCircleStyleLayer.mm +++ b/platform/darwin/src/MGLCircleStyleLayer.mm @@ -13,6 +13,11 @@ namespace mbgl { + MBGL_DEFINE_ENUM(MGLCirclePitchAlignment, { + { MGLCirclePitchAlignmentMap, "map" }, + { MGLCirclePitchAlignmentViewport, "viewport" }, + }); + MBGL_DEFINE_ENUM(MGLCircleScaleAlignment, { { MGLCircleScaleAlignmentMap, "map" }, { MGLCircleScaleAlignmentViewport, "viewport" }, @@ -187,6 +192,23 @@ namespace mbgl { return transition; } +- (void)setCirclePitchAlignment:(MGLStyleValue<NSValue *> *)circlePitchAlignment { + MGLAssertStyleLayerIsValid(); + + auto mbglValue = MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLCirclePitchAlignment>().toEnumPropertyValue(circlePitchAlignment); + self.rawLayer->setCirclePitchAlignment(mbglValue); +} + +- (MGLStyleValue<NSValue *> *)circlePitchAlignment { + MGLAssertStyleLayerIsValid(); + + auto propertyValue = self.rawLayer->getCirclePitchAlignment(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLCirclePitchAlignment>().toEnumStyleValue(self.rawLayer->getDefaultCirclePitchAlignment()); + } + return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLCirclePitchAlignment>().toEnumStyleValue(propertyValue); +} + - (void)setCircleRadius:(MGLStyleValue<NSNumber *> *)circleRadius { MGLAssertStyleLayerIsValid(); @@ -421,6 +443,16 @@ namespace mbgl { @implementation NSValue (MGLCircleStyleLayerAdditions) ++ (NSValue *)valueWithMGLCirclePitchAlignment:(MGLCirclePitchAlignment)circlePitchAlignment { + return [NSValue value:&circlePitchAlignment withObjCType:@encode(MGLCirclePitchAlignment)]; +} + +- (MGLCirclePitchAlignment)MGLCirclePitchAlignmentValue { + MGLCirclePitchAlignment circlePitchAlignment; + [self getValue:&circlePitchAlignment]; + return circlePitchAlignment; +} + + (NSValue *)valueWithMGLCircleScaleAlignment:(MGLCircleScaleAlignment)circleScaleAlignment { return [NSValue value:&circleScaleAlignment withObjCType:@encode(MGLCircleScaleAlignment)]; } diff --git a/platform/darwin/test/MGLCircleStyleLayerTests.mm b/platform/darwin/test/MGLCircleStyleLayerTests.mm index 2a2e9f2d4a..c0c503153a 100644 --- a/platform/darwin/test/MGLCircleStyleLayerTests.mm +++ b/platform/darwin/test/MGLCircleStyleLayerTests.mm @@ -246,6 +246,45 @@ XCTAssertEqual(circleOpacityTransition.duration, transitionTest.duration); } + // circle-pitch-alignment + { + XCTAssertTrue(rawLayer->getCirclePitchAlignment().isUndefined(), + @"circle-pitch-alignment should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.circlePitchAlignment; + + MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLCirclePitchAlignment:MGLCirclePitchAlignmentViewport]]; + layer.circlePitchAlignment = constantStyleValue; + mbgl::style::PropertyValue<mbgl::style::AlignmentType> propertyValue = { mbgl::style::AlignmentType::Viewport }; + XCTAssertEqual(rawLayer->getCirclePitchAlignment(), propertyValue, + @"Setting circlePitchAlignment to a constant value should update circle-pitch-alignment."); + XCTAssertEqualObjects(layer.circlePitchAlignment, constantStyleValue, + @"circlePitchAlignment should round-trip constant values."); + + MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.circlePitchAlignment = functionStyleValue; + + mbgl::style::IntervalStops<mbgl::style::AlignmentType> intervalStops = { {{18, mbgl::style::AlignmentType::Viewport}} }; + propertyValue = mbgl::style::CameraFunction<mbgl::style::AlignmentType> { intervalStops }; + + XCTAssertEqual(rawLayer->getCirclePitchAlignment(), propertyValue, + @"Setting circlePitchAlignment to a camera function should update circle-pitch-alignment."); + XCTAssertEqualObjects(layer.circlePitchAlignment, functionStyleValue, + @"circlePitchAlignment should round-trip camera functions."); + + + + layer.circlePitchAlignment = nil; + XCTAssertTrue(rawLayer->getCirclePitchAlignment().isUndefined(), + @"Unsetting circlePitchAlignment should return circle-pitch-alignment to the default value."); + XCTAssertEqualObjects(layer.circlePitchAlignment, defaultStyleValue, + @"circlePitchAlignment should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil]; + XCTAssertThrowsSpecificNamed(layer.circlePitchAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it"); + functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil]; + XCTAssertThrowsSpecificNamed(layer.circlePitchAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it"); + } + // circle-radius { XCTAssertTrue(rawLayer->getCircleRadius().isUndefined(), @@ -638,6 +677,7 @@ [self testPropertyName:@"circle-blur" isBoolean:NO]; [self testPropertyName:@"circle-color" isBoolean:NO]; [self testPropertyName:@"circle-opacity" isBoolean:NO]; + [self testPropertyName:@"circle-pitch-alignment" isBoolean:NO]; [self testPropertyName:@"circle-radius" isBoolean:NO]; [self testPropertyName:@"circle-scale-alignment" isBoolean:NO]; [self testPropertyName:@"circle-stroke-color" isBoolean:NO]; @@ -648,6 +688,8 @@ } - (void)testValueAdditions { + XCTAssertEqual([NSValue valueWithMGLCirclePitchAlignment:MGLCirclePitchAlignmentMap].MGLCirclePitchAlignmentValue, MGLCirclePitchAlignmentMap); + XCTAssertEqual([NSValue valueWithMGLCirclePitchAlignment:MGLCirclePitchAlignmentViewport].MGLCirclePitchAlignmentValue, MGLCirclePitchAlignmentViewport); XCTAssertEqual([NSValue valueWithMGLCircleScaleAlignment:MGLCircleScaleAlignmentMap].MGLCircleScaleAlignmentValue, MGLCircleScaleAlignmentMap); XCTAssertEqual([NSValue valueWithMGLCircleScaleAlignment:MGLCircleScaleAlignmentViewport].MGLCircleScaleAlignmentValue, MGLCircleScaleAlignmentViewport); XCTAssertEqual([NSValue valueWithMGLCircleTranslationAnchor:MGLCircleTranslationAnchorMap].MGLCircleTranslationAnchorValue, MGLCircleTranslationAnchorMap); diff --git a/src/mbgl/programs/circle_program.hpp b/src/mbgl/programs/circle_program.hpp index 8f056048b1..3590acbeef 100644 --- a/src/mbgl/programs/circle_program.hpp +++ b/src/mbgl/programs/circle_program.hpp @@ -21,7 +21,9 @@ class CircleProgram : public Program< gl::Uniforms< uniforms::u_matrix, uniforms::u_scale_with_map, - uniforms::u_extrude_scale>, + uniforms::u_extrude_scale, + uniforms::u_camera_to_center_distance, + uniforms::u_pitch_with_map>, style::CirclePaintProperties> { public: diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp index e7c428034b..c11e0b5ca1 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -30,7 +30,6 @@ class TransformState; namespace uniforms { MBGL_DEFINE_UNIFORM_SCALAR(bool, u_rotate_with_map); -MBGL_DEFINE_UNIFORM_SCALAR(bool, u_pitch_with_map); MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_texture); MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_fadetexture); MBGL_DEFINE_UNIFORM_SCALAR(float, u_aspect_ratio); diff --git a/src/mbgl/programs/uniforms.hpp b/src/mbgl/programs/uniforms.hpp index f1b2c2fb54..c8f8684ba1 100644 --- a/src/mbgl/programs/uniforms.hpp +++ b/src/mbgl/programs/uniforms.hpp @@ -33,6 +33,8 @@ MBGL_DEFINE_UNIFORM_SCALAR(float, u_gapwidth); MBGL_DEFINE_UNIFORM_SCALAR(float, u_offset); MBGL_DEFINE_UNIFORM_SCALAR(Size, u_world); MBGL_DEFINE_UNIFORM_SCALAR(Size, u_texsize); +MBGL_DEFINE_UNIFORM_SCALAR(bool, u_pitch_with_map); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_camera_to_center_distance); MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_extrude_scale); diff --git a/src/mbgl/renderer/painters/painter_circle.cpp b/src/mbgl/renderer/painters/painter_circle.cpp index 58e384979d..a077f557fc 100644 --- a/src/mbgl/renderer/painters/painter_circle.cpp +++ b/src/mbgl/renderer/painters/painter_circle.cpp @@ -22,6 +22,7 @@ void Painter::renderCircle(PaintParameters& parameters, const CirclePaintProperties::PossiblyEvaluated& properties = layer.evaluated; const bool scaleWithMap = properties.get<CirclePitchScale>() == CirclePitchScaleType::Map; + const bool pitchWithMap = properties.get<CirclePitchAlignment>() == AlignmentType::Map; parameters.programs.circle.get(properties).draw( context, @@ -38,12 +39,13 @@ void Painter::renderCircle(PaintParameters& parameters, state) }, uniforms::u_scale_with_map::Value{ scaleWithMap }, - uniforms::u_extrude_scale::Value{ scaleWithMap + uniforms::u_extrude_scale::Value{ pitchWithMap ? std::array<float, 2> {{ - pixelsToGLUnits[0] * state.getCameraToCenterDistance(), - pixelsToGLUnits[1] * state.getCameraToCenterDistance() - }} - : pixelsToGLUnits } + tile.id.pixelsToTileUnits(1, state.getZoom()), + tile.id.pixelsToTileUnits(1, state.getZoom()) }} + : pixelsToGLUnits }, + uniforms::u_camera_to_center_distance::Value{ state.getCameraToCenterDistance() }, + uniforms::u_pitch_with_map::Value{ pitchWithMap } }, *bucket.vertexBuffer, *bucket.indexBuffer, diff --git a/src/mbgl/shaders/circle.cpp b/src/mbgl/shaders/circle.cpp index 2e0c76122c..953e750776 100644 --- a/src/mbgl/shaders/circle.cpp +++ b/src/mbgl/shaders/circle.cpp @@ -9,7 +9,9 @@ const char* circle::name = "circle"; const char* circle::vertexSource = R"MBGL_SHADER( uniform mat4 u_matrix; uniform bool u_scale_with_map; +uniform bool u_pitch_with_map; uniform vec2 u_extrude_scale; +uniform highp float u_camera_to_center_distance; attribute vec2 a_pos; @@ -121,12 +123,28 @@ void main(void) { // multiply a_pos by 0.5, since we had it * 2 in order to sneak // in extrusion data - gl_Position = u_matrix * vec4(floor(a_pos * 0.5), 0, 1); - - if (u_scale_with_map) { - gl_Position.xy += extrude * (radius + stroke_width) * u_extrude_scale; + vec2 circle_center = floor(a_pos * 0.5); + if (u_pitch_with_map) { + vec2 corner_position = circle_center; + if (u_scale_with_map) { + corner_position += extrude * (radius + stroke_width) * u_extrude_scale; + } else { + // Pitching the circle with the map effectively scales it with the map + // To counteract the effect for pitch-scale: viewport, we rescale the + // whole circle based on the pitch scaling effect at its central point + vec4 projected_center = u_matrix * vec4(circle_center, 0, 1); + corner_position += extrude * (radius + stroke_width) * u_extrude_scale * (projected_center.w / u_camera_to_center_distance); + } + + gl_Position = u_matrix * vec4(corner_position, 0, 1); } else { - gl_Position.xy += extrude * (radius + stroke_width) * u_extrude_scale * gl_Position.w; + gl_Position = u_matrix * vec4(circle_center, 0, 1); + + if (u_scale_with_map) { + gl_Position.xy += extrude * (radius + stroke_width) * u_extrude_scale * u_camera_to_center_distance; + } else { + gl_Position.xy += extrude * (radius + stroke_width) * u_extrude_scale * gl_Position.w; + } } // This is a minimum blur distance that serves as a faux-antialiasing for diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp index 3bba135c84..9854932699 100644 --- a/src/mbgl/style/layers/circle_layer.cpp +++ b/src/mbgl/style/layers/circle_layer.cpp @@ -283,6 +283,33 @@ TransitionOptions CircleLayer::getCirclePitchScaleTransition() const { return impl().paint.template get<CirclePitchScale>().options; } +PropertyValue<AlignmentType> CircleLayer::getDefaultCirclePitchAlignment() { + return { AlignmentType::Viewport }; +} + +PropertyValue<AlignmentType> CircleLayer::getCirclePitchAlignment() const { + return impl().paint.template get<CirclePitchAlignment>().value; +} + +void CircleLayer::setCirclePitchAlignment(PropertyValue<AlignmentType> value) { + if (value == getCirclePitchAlignment()) + return; + auto impl_ = mutableImpl(); + impl_->paint.template get<CirclePitchAlignment>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +void CircleLayer::setCirclePitchAlignmentTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<CirclePitchAlignment>().options = options; + baseImpl = std::move(impl_); +} + +TransitionOptions CircleLayer::getCirclePitchAlignmentTransition() const { + return impl().paint.template get<CirclePitchAlignment>().options; +} + DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleStrokeWidth() { return { 0 }; } diff --git a/src/mbgl/style/layers/circle_layer_properties.hpp b/src/mbgl/style/layers/circle_layer_properties.hpp index 73b7028465..bc0c961e75 100644 --- a/src/mbgl/style/layers/circle_layer_properties.hpp +++ b/src/mbgl/style/layers/circle_layer_properties.hpp @@ -40,6 +40,10 @@ struct CirclePitchScale : PaintProperty<CirclePitchScaleType> { static CirclePitchScaleType defaultValue() { return CirclePitchScaleType::Map; } }; +struct CirclePitchAlignment : PaintProperty<AlignmentType> { + static AlignmentType defaultValue() { return AlignmentType::Viewport; } +}; + struct CircleStrokeWidth : DataDrivenPaintProperty<float, attributes::a_stroke_width, uniforms::u_stroke_width> { static float defaultValue() { return 0; } }; @@ -60,6 +64,7 @@ class CirclePaintProperties : public Properties< CircleTranslate, CircleTranslateAnchor, CirclePitchScale, + CirclePitchAlignment, CircleStrokeWidth, CircleStrokeColor, CircleStrokeOpacity |