From d5fbcb242acff2ab270b4018b01c2c6be9c4955f Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Wed, 5 Jul 2017 13:59:45 -0700 Subject: [core] Implement circle-pitch-alignment property Closes issue #9349. --- .../style/conversion/make_property_setters.hpp | 2 + include/mbgl/style/layers/circle_layer.hpp | 6 +++ .../mapbox/mapboxsdk/style/layers/CircleLayer.java | 12 ++++++ .../mapbox/mapboxsdk/style/layers/Property.java | 21 ++++++++++ .../mapboxsdk/style/layers/PropertyFactory.java | 22 +++++++++++ .../mapboxsdk/testapp/style/CircleLayerTest.java | 38 ++++++++++++++++++ platform/android/src/style/layers/circle_layer.cpp | 7 ++++ platform/android/src/style/layers/circle_layer.hpp | 2 + platform/darwin/src/MGLCircleStyleLayer.h | 45 ++++++++++++++++++++++ platform/darwin/src/MGLCircleStyleLayer.mm | 32 +++++++++++++++ platform/darwin/test/MGLCircleStyleLayerTests.mm | 42 ++++++++++++++++++++ src/mbgl/programs/circle_program.hpp | 4 +- src/mbgl/programs/symbol_program.hpp | 1 - src/mbgl/programs/uniforms.hpp | 2 + src/mbgl/renderer/painters/painter_circle.cpp | 12 +++--- src/mbgl/shaders/circle.cpp | 28 +++++++++++--- src/mbgl/style/layers/circle_layer.cpp | 27 +++++++++++++ src/mbgl/style/layers/circle_layer_properties.hpp | 5 +++ 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; result["circle-pitch-scale"] = &setProperty, &CircleLayer::setCirclePitchScale>; result["circle-pitch-scale-transition"] = &setTransition; + result["circle-pitch-alignment"] = &setProperty, &CircleLayer::setCirclePitchAlignment>; + result["circle-pitch-alignment-transition"] = &setTransition; result["circle-stroke-width"] = &setProperty, &CircleLayer::setCircleStrokeWidth>; result["circle-stroke-width-transition"] = &setTransition; result["circle-stroke-color"] = &setProperty, &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 getDefaultCirclePitchAlignment(); + PropertyValue getCirclePitchAlignment() const; + void setCirclePitchAlignment(PropertyValue); + void setCirclePitchAlignmentTransition(const TransitionOptions&); + TransitionOptions getCirclePitchAlignmentTransition() const; + static DataDrivenPropertyValue getDefaultCircleStrokeWidth(); DataDrivenPropertyValue getCircleStrokeWidth() const; void setCircleStrokeWidth(DataDrivenPropertyValue); 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 @@ -277,6 +277,16 @@ public class CircleLayer extends Layer { return (PropertyValue) new PropertyValue("circle-pitch-scale", nativeGetCirclePitchScale()); } + /** + * Get the CirclePitchAlignment property + * + * @return property wrapper value around String + */ + @SuppressWarnings("unchecked") + public PropertyValue getCirclePitchAlignment() { + return (PropertyValue) new PropertyValue("circle-pitch-alignment", nativeGetCirclePitchAlignment()); + } + /** * Get the CircleStrokeWidth property * @@ -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 @@ -952,6 +952,28 @@ public class PropertyFactory { return new PaintPropertyValue<>("circle-pitch-scale", function); } + /** + * Orientation of circle when map is pitched. + * + * @param value a String value + * @return property wrapper around String + */ + public static PropertyValue circlePitchAlignment(@Property.CIRCLE_PITCH_ALIGNMENT String value) { + return new PaintPropertyValue<>("circle-pitch-alignment", value); + } + + + /** + * Orientation of circle when map is pitched. + * + * @param the zoom parameter type + * @param function a wrapper {@link CameraFunction} for String + * @return property wrapper around a String function + */ + public static PropertyValue> circlePitchAlignment(CameraFunction function) { + return new PaintPropertyValue<>("circle-pitch-alignment", function); + } + /** * The width of the circle's stroke. Strokes are placed outside of the {@link PropertyFactory#circleRadius}. * 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 @@ -1047,6 +1047,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(); 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(*converted); } + jni::Object CircleLayer::getCirclePitchAlignment(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + Result converted = convert(env, layer.as()->CircleLayer::getCirclePitchAlignment()); + return jni::Object(*converted); + } + jni::Object CircleLayer::getCircleStrokeWidth(jni::JNIEnv& env) { using namespace mbgl::android::conversion; Result converted = convert(env, layer.as()->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 getCirclePitchScale(jni::JNIEnv&); + jni::Object getCirclePitchAlignment(jni::JNIEnv&); + jni::Object getCircleStrokeWidth(jni::JNIEnv&); void setCircleStrokeWidthTransition(jni::JNIEnv&, jlong duration, jlong delay); jni::Object 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 @@ -7,6 +7,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. @@ -220,6 +237,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 *circlePitchAlignment; + /** Circle radius. @@ -490,6 +522,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. 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 *)circlePitchAlignment { + MGLAssertStyleLayerIsValid(); + + auto mbglValue = MGLStyleValueTransformer().toEnumPropertyValue(circlePitchAlignment); + self.rawLayer->setCirclePitchAlignment(mbglValue); +} + +- (MGLStyleValue *)circlePitchAlignment { + MGLAssertStyleLayerIsValid(); + + auto propertyValue = self.rawLayer->getCirclePitchAlignment(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toEnumStyleValue(self.rawLayer->getDefaultCirclePitchAlignment()); + } + return MGLStyleValueTransformer().toEnumStyleValue(propertyValue); +} + - (void)setCircleRadius:(MGLStyleValue *)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 *defaultStyleValue = layer.circlePitchAlignment; + + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLCirclePitchAlignment:MGLCirclePitchAlignmentViewport]]; + layer.circlePitchAlignment = constantStyleValue; + mbgl::style::PropertyValue 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 * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.circlePitchAlignment = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, mbgl::style::AlignmentType::Viewport}} }; + propertyValue = mbgl::style::CameraFunction { 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 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 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() == CirclePitchScaleType::Map; + const bool pitchWithMap = properties.get() == 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 {{ - 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().options; } +PropertyValue CircleLayer::getDefaultCirclePitchAlignment() { + return { AlignmentType::Viewport }; +} + +PropertyValue CircleLayer::getCirclePitchAlignment() const { + return impl().paint.template get().value; +} + +void CircleLayer::setCirclePitchAlignment(PropertyValue value) { + if (value == getCirclePitchAlignment()) + return; + auto impl_ = mutableImpl(); + impl_->paint.template get().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +void CircleLayer::setCirclePitchAlignmentTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get().options = options; + baseImpl = std::move(impl_); +} + +TransitionOptions CircleLayer::getCirclePitchAlignmentTransition() const { + return impl().paint.template get().options; +} + DataDrivenPropertyValue 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 { static CirclePitchScaleType defaultValue() { return CirclePitchScaleType::Map; } }; +struct CirclePitchAlignment : PaintProperty { + static AlignmentType defaultValue() { return AlignmentType::Viewport; } +}; + struct CircleStrokeWidth : DataDrivenPaintProperty { static float defaultValue() { return 0; } }; @@ -60,6 +64,7 @@ class CirclePaintProperties : public Properties< CircleTranslate, CircleTranslateAnchor, CirclePitchScale, + CirclePitchAlignment, CircleStrokeWidth, CircleStrokeColor, CircleStrokeOpacity -- cgit v1.2.1