diff options
Diffstat (limited to 'src/mbgl')
-rw-r--r-- | src/mbgl/gl/defines.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/renderer/layers/render_location_indicator_layer.cpp | 74 | ||||
-rw-r--r-- | src/mbgl/style/layers/location_indicator_layer.cpp | 146 | ||||
-rw-r--r-- | src/mbgl/style/layers/location_indicator_layer_properties.hpp | 26 |
4 files changed, 151 insertions, 97 deletions
diff --git a/src/mbgl/gl/defines.hpp b/src/mbgl/gl/defines.hpp index 1d9177d069..52dc92d230 100644 --- a/src/mbgl/gl/defines.hpp +++ b/src/mbgl/gl/defines.hpp @@ -149,6 +149,7 @@ #define GL_TEXTURE_2D 0x0DE1 #define GL_TEXTURE_BINDING_2D 0x8069 #define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE #define GL_TEXTURE_MIN_FILTER 0x2801 #define GL_TEXTURE_WRAP_S 0x2802 #define GL_TEXTURE_WRAP_T 0x2803 @@ -163,7 +164,6 @@ #define GL_VERTEX_SHADER 0x8B31 #define GL_VIEWPORT 0x0BA2 #define GL_ZERO 0 -#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE #ifdef MBGL_USE_GLES2 #define GL_HALF_FLOAT 0x8D61 #else diff --git a/src/mbgl/renderer/layers/render_location_indicator_layer.cpp b/src/mbgl/renderer/layers/render_location_indicator_layer.cpp index 94ac46e216..f3d72f02d1 100644 --- a/src/mbgl/renderer/layers/render_location_indicator_layer.cpp +++ b/src/mbgl/renderer/layers/render_location_indicator_layer.cpp @@ -48,9 +48,9 @@ struct LocationIndicatorRenderParameters { double errorRadiusMeters; mbgl::Color errorRadiusColor{0, 0, 0, 0}; mbgl::Color errorRadiusBorderColor{0, 0, 0, 0}; - int puckSizePx = 0; - int puckHatSizePx = 0; - int puckShadowSizePx = 0; + float puckScale = 0; + float puckHatScale = 0; + float puckShadowScale = 0; float puckLayersDisplacement = 0; float perspectiveCompensation = 0; std::string puckImagePath; @@ -266,7 +266,6 @@ public: ~Texture() { release(); } void release() { MBGL_CHECK_ERROR(glDeleteTextures(1, &texId)); - texId = 0; image = nullptr; } /* @@ -276,10 +275,16 @@ public: if ((img && &img->get()->image == image) || (!img && !image)) return; imageDirty = true; image = (img) ? &img->get()->image : nullptr; - if (img) + width = height = 0; + pixelRatio = 1.0f; + if (img) { sharedImage = *img; // keep reference until uploaded - else + width = image->size.width; + height = image->size.height; + pixelRatio = img->get()->pixelRatio; + } else { sharedImage = nullopt; + } } void upload() { @@ -329,13 +334,21 @@ public: const mbgl::PremultipliedImage* image = nullptr; optional<Immutable<style::Image::Impl>> sharedImage; bool imageDirty = false; + size_t width = 0; + size_t height = 0; + float pixelRatio = 1.0f; }; RenderLocationIndicatorImpl() : ruler(0, mapbox::cheap_ruler::CheapRuler::Meters) {} - static bool hasExtension(const std::string& ext) { - if (const auto* extensions = reinterpret_cast<const char*>(MBGL_CHECK_ERROR(glGetString(GL_EXTENSIONS)))) { - if (strstr(extensions, ext.c_str()) != nullptr) return true; + static bool hasAnisotropicFiltering() { + const auto* extensions = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)); + GLenum error = glGetError(); + if (error != GL_NO_ERROR) { // glGetString(GL_EXTENSIONS) is deprecated in OpenGL Desktop 3.0+. But OpenGL 3.0+ + // has anisotropic filtering. + return true; + } else { + if (strstr(extensions, "GL_EXT_texture_filter_anisotropic") != nullptr) return true; } return false; } @@ -343,7 +356,7 @@ public: // Check if anisotropic filtering is available if (initialized) return; initialized = true; - if (hasExtension("GL_EXT_texture_filter_anisotropic")) anisotropicFilteringAvailable = true; + if (hasAnisotropicFiltering()) anisotropicFilteringAvailable = true; simpleShader.initialize(); texturedShader.initialize(); texCoords = {{{0.0f, 1.0f}, @@ -363,7 +376,7 @@ public: void release() { if (!simpleShader.program) return; - textures.clear(); + for (const auto& t : textures) t.second->release(); buffer.release(); circleBuffer.release(); puckBuffer.release(); @@ -382,16 +395,13 @@ public: } else if (params.puckBearing != oldParams.puckBearing || params.puckLayersDisplacement != oldParams.puckLayersDisplacement || params.perspectiveCompensation != oldParams.perspectiveCompensation || - params.puckSizePx != oldParams.puckSizePx || params.puckHatSizePx != oldParams.puckHatSizePx || - params.puckShadowSizePx != oldParams.puckShadowSizePx) + params.puckScale != oldParams.puckScale || params.puckHatScale != oldParams.puckHatScale || + params.puckShadowScale != oldParams.puckShadowScale) bearingChanged = true; // changes puck geometry but not necessarily the location if (params.errorRadiusMeters != oldParams.errorRadiusMeters) radiusChanged = true; - if (params.puckImagePath != oldParams.puckImagePath) - setTextureFromImageID(params.puckImagePath, texPuck, params); - if (params.puckShadowImagePath != oldParams.puckShadowImagePath) - setTextureFromImageID(params.puckShadowImagePath, texShadow, params); - if (params.puckHatImagePath != oldParams.puckHatImagePath) - setTextureFromImageID(params.puckHatImagePath, texPuckHat, params); + setTextureFromImageID(params.puckImagePath, texPuck, params); + setTextureFromImageID(params.puckShadowImagePath, texShadow, params); + setTextureFromImageID(params.puckHatImagePath, texPuckHat, params); projectionCircle = params.projectionMatrix; const Point<double> positionMercator = project(params.puckPosition, *params.state); @@ -539,10 +549,12 @@ protected: params.perspectiveCompensation; // Compensation factor for the perspective deformation // ^ clamping this to 0.8 to avoid growing the puck too much close to the camera. const double shadowRadius = - params.puckShadowSizePx * M_SQRT2 * 0.5 * + ((texShadow) ? texShadow->width / texShadow->pixelRatio : 0.0) * params.puckShadowScale * M_SQRT2 * 0.5 * horizontalScaleFactor; // Technically it's not the radius, but the half diagonal of the quad. - const double puckRadius = params.puckSizePx * M_SQRT2 * 0.5 * horizontalScaleFactor; - const double hatRadius = params.puckHatSizePx * M_SQRT2 * 0.5 * horizontalScaleFactor; + const double puckRadius = ((texPuck) ? texPuck->width / texPuck->pixelRatio : 0.0) * params.puckScale * + M_SQRT2 * 0.5 * horizontalScaleFactor; + const double hatRadius = ((texPuckHat) ? texPuckHat->width / texPuckHat->pixelRatio : 0.0) * + params.puckHatScale * M_SQRT2 * 0.5 * horizontalScaleFactor; for (unsigned long i = 0; i < 4; ++i) { const auto b = util::wrap<float>(params.puckBearing + bearings[i], 0.0f, 360.0f); @@ -634,6 +646,11 @@ protected: else tx->assign(nullptr); textures[imagePath] = tx; + } else { + const Immutable<style::Image::Impl>* ima = params.imageManager->getSharedImage(imagePath); + const mbgl::PremultipliedImage* img = (ima) ? &ima->get()->image : nullptr; + if (textures.at(imagePath)->image != img) // image for the ID might have changed. + textures.at(imagePath)->assign(ima); } tex = textures.at(imagePath); } @@ -690,7 +707,6 @@ RenderLocationIndicatorLayer::RenderLocationIndicatorLayer(Immutable<style::Loca } RenderLocationIndicatorLayer::~RenderLocationIndicatorLayer() { - assert(gfx::BackendScope::exists()); if (!contextDestroyed) MBGL_CHECK_ERROR(renderImpl->release()); } @@ -711,10 +727,12 @@ void RenderLocationIndicatorLayer::evaluate(const PropertyEvaluationParameters& renderImpl->parameters.errorRadiusColor = evaluated.get<style::AccuracyRadiusColor>(); renderImpl->parameters.errorRadiusBorderColor = evaluated.get<style::AccuracyRadiusBorderColor>(); renderImpl->parameters.errorRadiusMeters = evaluated.get<style::AccuracyRadius>(); - renderImpl->parameters.puckSizePx = evaluated.get<style::BearingImageSize>(); - renderImpl->parameters.puckHatSizePx = evaluated.get<style::TopImageSize>(); - renderImpl->parameters.puckShadowSizePx = evaluated.get<style::ShadowImageSize>(); + renderImpl->parameters.puckScale = evaluated.get<style::BearingImageSize>(); + renderImpl->parameters.puckHatScale = evaluated.get<style::TopImageSize>(); + renderImpl->parameters.puckShadowScale = evaluated.get<style::ShadowImageSize>(); renderImpl->parameters.puckBearing = evaluated.get<style::Bearing>().getAngle(); + renderImpl->parameters.puckLayersDisplacement = evaluated.get<style::ImageTiltDisplacement>(); + renderImpl->parameters.perspectiveCompensation = evaluated.get<style::PerspectiveCompensation>(); const std::array<double, 3> pos = evaluated.get<style::Location>(); renderImpl->parameters.puckPosition = LatLng{pos[0], pos[1]}; @@ -726,10 +744,6 @@ void RenderLocationIndicatorLayer::evaluate(const PropertyEvaluationParameters& renderImpl->parameters.puckShadowImagePath = layout.get<style::ShadowImage>().asConstant().id(); if (!layout.get<style::TopImage>().isUndefined()) renderImpl->parameters.puckHatImagePath = layout.get<style::TopImage>().asConstant().id(); - if (!layout.get<style::ImageTiltDisplacement>().isUndefined()) - renderImpl->parameters.puckLayersDisplacement = layout.get<style::ImageTiltDisplacement>().asConstant(); - if (!layout.get<style::PerspectiveCompensation>().isUndefined()) - renderImpl->parameters.perspectiveCompensation = layout.get<style::PerspectiveCompensation>().asConstant(); evaluatedProperties = std::move(properties); } diff --git a/src/mbgl/style/layers/location_indicator_layer.cpp b/src/mbgl/style/layers/location_indicator_layer.cpp index 178fd104ad..b3590d78e4 100644 --- a/src/mbgl/style/layers/location_indicator_layer.cpp +++ b/src/mbgl/style/layers/location_indicator_layer.cpp @@ -78,36 +78,6 @@ void LocationIndicatorLayer::setBearingImage(const PropertyValue<expression::Ima baseImpl = std::move(impl_); observer->onLayerChanged(*this); } -PropertyValue<float> LocationIndicatorLayer::getDefaultImageTiltDisplacement() { - return ImageTiltDisplacement::defaultValue(); -} - -const PropertyValue<float>& LocationIndicatorLayer::getImageTiltDisplacement() const { - return impl().layout.get<ImageTiltDisplacement>(); -} - -void LocationIndicatorLayer::setImageTiltDisplacement(const PropertyValue<float>& value) { - if (value == getImageTiltDisplacement()) return; - auto impl_ = mutableImpl(); - impl_->layout.get<ImageTiltDisplacement>() = value; - baseImpl = std::move(impl_); - observer->onLayerChanged(*this); -} -PropertyValue<float> LocationIndicatorLayer::getDefaultPerspectiveCompensation() { - return PerspectiveCompensation::defaultValue(); -} - -const PropertyValue<float>& LocationIndicatorLayer::getPerspectiveCompensation() const { - return impl().layout.get<PerspectiveCompensation>(); -} - -void LocationIndicatorLayer::setPerspectiveCompensation(const PropertyValue<float>& value) { - if (value == getPerspectiveCompensation()) return; - auto impl_ = mutableImpl(); - impl_->layout.get<PerspectiveCompensation>() = value; - baseImpl = std::move(impl_); - observer->onLayerChanged(*this); -} PropertyValue<expression::Image> LocationIndicatorLayer::getDefaultShadowImage() { return ShadowImage::defaultValue(); } @@ -250,7 +220,7 @@ TransitionOptions LocationIndicatorLayer::getBearingTransition() const { } PropertyValue<float> LocationIndicatorLayer::getDefaultBearingImageSize() { - return {0}; + return {1}; } const PropertyValue<float>& LocationIndicatorLayer::getBearingImageSize() const { @@ -276,6 +246,33 @@ TransitionOptions LocationIndicatorLayer::getBearingImageSizeTransition() const return impl().paint.template get<BearingImageSize>().options; } +PropertyValue<float> LocationIndicatorLayer::getDefaultImageTiltDisplacement() { + return {0}; +} + +const PropertyValue<float>& LocationIndicatorLayer::getImageTiltDisplacement() const { + return impl().paint.template get<ImageTiltDisplacement>().value; +} + +void LocationIndicatorLayer::setImageTiltDisplacement(const PropertyValue<float>& value) { + if (value == getImageTiltDisplacement()) + return; + auto impl_ = mutableImpl(); + impl_->paint.template get<ImageTiltDisplacement>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +void LocationIndicatorLayer::setImageTiltDisplacementTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<ImageTiltDisplacement>().options = options; + baseImpl = std::move(impl_); +} + +TransitionOptions LocationIndicatorLayer::getImageTiltDisplacementTransition() const { + return impl().paint.template get<ImageTiltDisplacement>().options; +} + PropertyValue<std::array<double, 3>> LocationIndicatorLayer::getDefaultLocation() { return {{{0, 0, 0}}}; } @@ -303,8 +300,35 @@ TransitionOptions LocationIndicatorLayer::getLocationTransition() const { return impl().paint.template get<Location>().options; } +PropertyValue<float> LocationIndicatorLayer::getDefaultPerspectiveCompensation() { + return {0.85}; +} + +const PropertyValue<float>& LocationIndicatorLayer::getPerspectiveCompensation() const { + return impl().paint.template get<PerspectiveCompensation>().value; +} + +void LocationIndicatorLayer::setPerspectiveCompensation(const PropertyValue<float>& value) { + if (value == getPerspectiveCompensation()) + return; + auto impl_ = mutableImpl(); + impl_->paint.template get<PerspectiveCompensation>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +void LocationIndicatorLayer::setPerspectiveCompensationTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<PerspectiveCompensation>().options = options; + baseImpl = std::move(impl_); +} + +TransitionOptions LocationIndicatorLayer::getPerspectiveCompensationTransition() const { + return impl().paint.template get<PerspectiveCompensation>().options; +} + PropertyValue<float> LocationIndicatorLayer::getDefaultShadowImageSize() { - return {0}; + return {1}; } const PropertyValue<float>& LocationIndicatorLayer::getShadowImageSize() const { @@ -331,7 +355,7 @@ TransitionOptions LocationIndicatorLayer::getShadowImageSizeTransition() const { } PropertyValue<float> LocationIndicatorLayer::getDefaultTopImageSize() { - return {0}; + return {1}; } const PropertyValue<float>& LocationIndicatorLayer::getTopImageSize() const { @@ -361,7 +385,7 @@ using namespace conversion; namespace { -constexpr uint8_t kPaintPropertyCount = 16u; +constexpr uint8_t kPaintPropertyCount = 20u; enum class Property : uint8_t { AccuracyRadius, @@ -369,7 +393,9 @@ enum class Property : uint8_t { AccuracyRadiusColor, Bearing, BearingImageSize, + ImageTiltDisplacement, Location, + PerspectiveCompensation, ShadowImageSize, TopImageSize, AccuracyRadiusTransition, @@ -377,12 +403,12 @@ enum class Property : uint8_t { AccuracyRadiusColorTransition, BearingTransition, BearingImageSizeTransition, + ImageTiltDisplacementTransition, LocationTransition, + PerspectiveCompensationTransition, ShadowImageSizeTransition, TopImageSizeTransition, BearingImage = kPaintPropertyCount, - ImageTiltDisplacement, - PerspectiveCompensation, ShadowImage, TopImage, }; @@ -398,7 +424,9 @@ MAPBOX_ETERNAL_CONSTEXPR const auto layerProperties = mapbox::eternal::hash_map< {"accuracy-radius-color", toUint8(Property::AccuracyRadiusColor)}, {"bearing", toUint8(Property::Bearing)}, {"bearing-image-size", toUint8(Property::BearingImageSize)}, + {"image-tilt-displacement", toUint8(Property::ImageTiltDisplacement)}, {"location", toUint8(Property::Location)}, + {"perspective-compensation", toUint8(Property::PerspectiveCompensation)}, {"shadow-image-size", toUint8(Property::ShadowImageSize)}, {"top-image-size", toUint8(Property::TopImageSize)}, {"accuracy-radius-transition", toUint8(Property::AccuracyRadiusTransition)}, @@ -406,12 +434,12 @@ MAPBOX_ETERNAL_CONSTEXPR const auto layerProperties = mapbox::eternal::hash_map< {"accuracy-radius-color-transition", toUint8(Property::AccuracyRadiusColorTransition)}, {"bearing-transition", toUint8(Property::BearingTransition)}, {"bearing-image-size-transition", toUint8(Property::BearingImageSizeTransition)}, + {"image-tilt-displacement-transition", toUint8(Property::ImageTiltDisplacementTransition)}, {"location-transition", toUint8(Property::LocationTransition)}, + {"perspective-compensation-transition", toUint8(Property::PerspectiveCompensationTransition)}, {"shadow-image-size-transition", toUint8(Property::ShadowImageSizeTransition)}, {"top-image-size-transition", toUint8(Property::TopImageSizeTransition)}, {"bearing-image", toUint8(Property::BearingImage)}, - {"image-tilt-displacement", toUint8(Property::ImageTiltDisplacement)}, - {"perspective-compensation", toUint8(Property::PerspectiveCompensation)}, {"shadow-image", toUint8(Property::ShadowImage)}, {"top-image", toUint8(Property::TopImage)}}); @@ -427,8 +455,12 @@ StyleProperty getLayerProperty(const LocationIndicatorLayer& layer, Property pro return makeStyleProperty(layer.getBearing()); case Property::BearingImageSize: return makeStyleProperty(layer.getBearingImageSize()); + case Property::ImageTiltDisplacement: + return makeStyleProperty(layer.getImageTiltDisplacement()); case Property::Location: return makeStyleProperty(layer.getLocation()); + case Property::PerspectiveCompensation: + return makeStyleProperty(layer.getPerspectiveCompensation()); case Property::ShadowImageSize: return makeStyleProperty(layer.getShadowImageSize()); case Property::TopImageSize: @@ -443,18 +475,18 @@ StyleProperty getLayerProperty(const LocationIndicatorLayer& layer, Property pro return makeStyleProperty(layer.getBearingTransition()); case Property::BearingImageSizeTransition: return makeStyleProperty(layer.getBearingImageSizeTransition()); + case Property::ImageTiltDisplacementTransition: + return makeStyleProperty(layer.getImageTiltDisplacementTransition()); case Property::LocationTransition: return makeStyleProperty(layer.getLocationTransition()); + case Property::PerspectiveCompensationTransition: + return makeStyleProperty(layer.getPerspectiveCompensationTransition()); case Property::ShadowImageSizeTransition: return makeStyleProperty(layer.getShadowImageSizeTransition()); case Property::TopImageSizeTransition: return makeStyleProperty(layer.getTopImageSizeTransition()); case Property::BearingImage: return makeStyleProperty(layer.getBearingImage()); - case Property::ImageTiltDisplacement: - return makeStyleProperty(layer.getImageTiltDisplacement()); - case Property::PerspectiveCompensation: - return makeStyleProperty(layer.getPerspectiveCompensation()); case Property::ShadowImage: return makeStyleProperty(layer.getShadowImage()); case Property::TopImage: @@ -491,8 +523,8 @@ optional<Error> LocationIndicatorLayer::setPropertyInternal(const std::string& n auto property = static_cast<Property>(it->second); if (property == Property::AccuracyRadius || property == Property::BearingImageSize || - property == Property::ShadowImageSize || property == Property::TopImageSize || - property == Property::ImageTiltDisplacement || property == Property::PerspectiveCompensation) { + property == Property::ImageTiltDisplacement || property == Property::PerspectiveCompensation || + property == Property::ShadowImageSize || property == Property::TopImageSize) { Error error; const auto& typedValue = convert<PropertyValue<float>>(value, error, false, false); if (!typedValue) { @@ -509,23 +541,23 @@ optional<Error> LocationIndicatorLayer::setPropertyInternal(const std::string& n return nullopt; } - if (property == Property::ShadowImageSize) { - setShadowImageSize(*typedValue); + if (property == Property::ImageTiltDisplacement) { + setImageTiltDisplacement(*typedValue); return nullopt; } - if (property == Property::TopImageSize) { - setTopImageSize(*typedValue); + if (property == Property::PerspectiveCompensation) { + setPerspectiveCompensation(*typedValue); return nullopt; } - if (property == Property::ImageTiltDisplacement) { - setImageTiltDisplacement(*typedValue); + if (property == Property::ShadowImageSize) { + setShadowImageSize(*typedValue); return nullopt; } - if (property == Property::PerspectiveCompensation) { - setPerspectiveCompensation(*typedValue); + if (property == Property::TopImageSize) { + setTopImageSize(*typedValue); return nullopt; } } @@ -620,11 +652,21 @@ optional<Error> LocationIndicatorLayer::setPropertyInternal(const std::string& n return nullopt; } + if (property == Property::ImageTiltDisplacementTransition) { + setImageTiltDisplacementTransition(*transition); + return nullopt; + } + if (property == Property::LocationTransition) { setLocationTransition(*transition); return nullopt; } + if (property == Property::PerspectiveCompensationTransition) { + setPerspectiveCompensationTransition(*transition); + return nullopt; + } + if (property == Property::ShadowImageSizeTransition) { setShadowImageSizeTransition(*transition); return nullopt; diff --git a/src/mbgl/style/layers/location_indicator_layer_properties.hpp b/src/mbgl/style/layers/location_indicator_layer_properties.hpp index d73ce33eb9..065cbe064a 100644 --- a/src/mbgl/style/layers/location_indicator_layer_properties.hpp +++ b/src/mbgl/style/layers/location_indicator_layer_properties.hpp @@ -21,16 +21,6 @@ struct BearingImage : LayoutProperty<expression::Image> { static expression::Image defaultValue() { return {}; } }; -struct ImageTiltDisplacement : LayoutProperty<float> { - static constexpr const char *name() { return "image-tilt-displacement"; } - static float defaultValue() { return 0; } -}; - -struct PerspectiveCompensation : LayoutProperty<float> { - static constexpr const char *name() { return "perspective-compensation"; } - static float defaultValue() { return 0.85; } -}; - struct ShadowImage : LayoutProperty<expression::Image> { static constexpr const char *name() { return "shadow-image"; } static expression::Image defaultValue() { return {}; } @@ -58,6 +48,10 @@ struct Bearing : PaintProperty<Rotation> { }; struct BearingImageSize : PaintProperty<float> { + static float defaultValue() { return 1; } +}; + +struct ImageTiltDisplacement : PaintProperty<float> { static float defaultValue() { return 0; } }; @@ -65,18 +59,20 @@ struct Location : PaintProperty<std::array<double, 3>> { static std::array<double, 3> defaultValue() { return {{0, 0, 0}}; } }; +struct PerspectiveCompensation : PaintProperty<float> { + static float defaultValue() { return 0.85; } +}; + struct ShadowImageSize : PaintProperty<float> { - static float defaultValue() { return 0; } + static float defaultValue() { return 1; } }; struct TopImageSize : PaintProperty<float> { - static float defaultValue() { return 0; } + static float defaultValue() { return 1; } }; class LocationIndicatorLayoutProperties : public Properties< BearingImage, - ImageTiltDisplacement, - PerspectiveCompensation, ShadowImage, TopImage > {}; @@ -87,7 +83,9 @@ class LocationIndicatorPaintProperties : public Properties< AccuracyRadiusColor, Bearing, BearingImageSize, + ImageTiltDisplacement, Location, + PerspectiveCompensation, ShadowImageSize, TopImageSize > {}; |