[core] Extract PaintPropertiesMap
This commit is contained in:
@@ -115,7 +115,6 @@ void AnnotationManager::updateStyle(Style& style) {
|
||||
std::unique_ptr<SymbolLayer> layer = std::make_unique<SymbolLayer>();
|
||||
layer->id = PointLayerID;
|
||||
layer->type = StyleLayerType::Symbol;
|
||||
layer->styles.emplace(ClassID::Default, ClassProperties());
|
||||
|
||||
layer->bucket = std::make_shared<StyleBucket>(layer->type);
|
||||
layer->bucket->name = layer->id;
|
||||
|
||||
@@ -37,7 +37,7 @@ void ShapeAnnotationImpl::updateStyle(Style& style) {
|
||||
paintProperties.set(PropertyKey::LineOpacity, ConstantFunction<float>(properties.opacity));
|
||||
paintProperties.set(PropertyKey::LineWidth, ConstantFunction<float>(properties.width));
|
||||
paintProperties.set(PropertyKey::LineColor, ConstantFunction<Color>(properties.color));
|
||||
layer->styles.emplace(ClassID::Default, std::move(paintProperties));
|
||||
layer->paints.paints.emplace(ClassID::Default, std::move(paintProperties));
|
||||
|
||||
} else if (shape.properties.is<FillPaintProperties>()) {
|
||||
layer = createFillLayer();
|
||||
@@ -47,7 +47,7 @@ void ShapeAnnotationImpl::updateStyle(Style& style) {
|
||||
paintProperties.set(PropertyKey::FillOpacity, ConstantFunction<float>(properties.opacity));
|
||||
paintProperties.set(PropertyKey::FillColor, ConstantFunction<Color>(properties.fill_color));
|
||||
paintProperties.set(PropertyKey::FillOutlineColor, ConstantFunction<Color>(properties.stroke_color));
|
||||
layer->styles.emplace(ClassID::Default, std::move(paintProperties));
|
||||
layer->paints.paints.emplace(ClassID::Default, std::move(paintProperties));
|
||||
|
||||
} else {
|
||||
beforeLayerID = shape.properties.get<std::string>();
|
||||
@@ -68,7 +68,7 @@ void ShapeAnnotationImpl::updateStyle(Style& style) {
|
||||
return;
|
||||
}
|
||||
|
||||
layer->styles = sourceLayer->styles;
|
||||
layer->paints.paints = sourceLayer->paints.paints;
|
||||
layer->bucket->layout = sourceLayer->bucket->layout;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,11 +2,14 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
RenderPass BackgroundLayer::applyStyleProperties(const StyleCalculationParameters& parameters) {
|
||||
applyTransitionedStyleProperty(PropertyKey::BackgroundOpacity, properties.opacity, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::BackgroundColor, properties.color, parameters);
|
||||
applyStyleProperty(PropertyKey::BackgroundImage, properties.image, parameters);
|
||||
return properties.isVisible() ? RenderPass::Translucent : RenderPass::None;
|
||||
void BackgroundLayer::recalculate(const StyleCalculationParameters& parameters) {
|
||||
paints.removeExpiredTransitions(parameters.now);
|
||||
|
||||
paints.calculateTransitioned(PropertyKey::BackgroundOpacity, properties.opacity, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::BackgroundColor, properties.color, parameters);
|
||||
paints.calculate(PropertyKey::BackgroundImage, properties.image, parameters);
|
||||
|
||||
passes = properties.isVisible() ? RenderPass::Translucent : RenderPass::None;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace mbgl {
|
||||
|
||||
class BackgroundLayer : public StyleLayer {
|
||||
public:
|
||||
RenderPass applyStyleProperties(const StyleCalculationParameters&) override;
|
||||
void recalculate(const StyleCalculationParameters&) override;
|
||||
|
||||
BackgroundPaintProperties properties;
|
||||
};
|
||||
|
||||
@@ -2,14 +2,17 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
RenderPass CircleLayer::applyStyleProperties(const StyleCalculationParameters& parameters) {
|
||||
applyTransitionedStyleProperty(PropertyKey::CircleRadius, properties.radius, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::CircleColor, properties.color, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::CircleOpacity, properties.opacity, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::CircleTranslate, properties.translate, parameters);
|
||||
applyStyleProperty(PropertyKey::CircleTranslateAnchor, properties.translateAnchor, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::CircleBlur, properties.blur, parameters);
|
||||
return properties.isVisible() ? RenderPass::Translucent : RenderPass::None;
|
||||
void CircleLayer::recalculate(const StyleCalculationParameters& parameters) {
|
||||
paints.removeExpiredTransitions(parameters.now);
|
||||
|
||||
paints.calculateTransitioned(PropertyKey::CircleRadius, properties.radius, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::CircleColor, properties.color, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::CircleOpacity, properties.opacity, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::CircleTranslate, properties.translate, parameters);
|
||||
paints.calculate(PropertyKey::CircleTranslateAnchor, properties.translateAnchor, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::CircleBlur, properties.blur, parameters);
|
||||
|
||||
passes = properties.isVisible() ? RenderPass::Translucent : RenderPass::None;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace mbgl {
|
||||
|
||||
class CircleLayer : public StyleLayer {
|
||||
public:
|
||||
RenderPass applyStyleProperties(const StyleCalculationParameters&) override;
|
||||
void recalculate(const StyleCalculationParameters&) override;
|
||||
|
||||
CirclePaintProperties properties;
|
||||
};
|
||||
|
||||
@@ -2,28 +2,28 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
RenderPass FillLayer::applyStyleProperties(const StyleCalculationParameters& parameters) {
|
||||
applyStyleProperty(PropertyKey::FillAntialias, properties.antialias, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::FillOpacity, properties.opacity, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::FillColor, properties.fill_color, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::FillOutlineColor, properties.stroke_color, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::FillTranslate, properties.translate, parameters);
|
||||
applyStyleProperty(PropertyKey::FillTranslateAnchor, properties.translateAnchor, parameters);
|
||||
applyStyleProperty(PropertyKey::FillImage, properties.image, parameters);
|
||||
void FillLayer::recalculate(const StyleCalculationParameters& parameters) {
|
||||
paints.removeExpiredTransitions(parameters.now);
|
||||
|
||||
RenderPass result = RenderPass::None;
|
||||
paints.calculate(PropertyKey::FillAntialias, properties.antialias, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::FillOpacity, properties.opacity, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::FillColor, properties.fill_color, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::FillOutlineColor, properties.stroke_color, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::FillTranslate, properties.translate, parameters);
|
||||
paints.calculate(PropertyKey::FillTranslateAnchor, properties.translateAnchor, parameters);
|
||||
paints.calculate(PropertyKey::FillImage, properties.image, parameters);
|
||||
|
||||
passes = RenderPass::None;
|
||||
|
||||
if (properties.antialias) {
|
||||
result |= RenderPass::Translucent;
|
||||
passes |= RenderPass::Translucent;
|
||||
}
|
||||
|
||||
if (!properties.image.from.empty() || (properties.fill_color[3] * properties.opacity) < 1.0f) {
|
||||
result |= RenderPass::Translucent;
|
||||
passes |= RenderPass::Translucent;
|
||||
} else {
|
||||
result |= RenderPass::Opaque;
|
||||
passes |= RenderPass::Opaque;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace mbgl {
|
||||
|
||||
class FillLayer : public StyleLayer {
|
||||
public:
|
||||
RenderPass applyStyleProperties(const StyleCalculationParameters&) override;
|
||||
void recalculate(const StyleCalculationParameters&) override;
|
||||
|
||||
FillPaintProperties properties;
|
||||
};
|
||||
|
||||
@@ -2,23 +2,25 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
RenderPass LineLayer::applyStyleProperties(const StyleCalculationParameters& parameters) {
|
||||
applyTransitionedStyleProperty(PropertyKey::LineOpacity, properties.opacity, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::LineColor, properties.color, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::LineTranslate, properties.translate, parameters);
|
||||
applyStyleProperty(PropertyKey::LineTranslateAnchor, properties.translateAnchor, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::LineWidth, properties.width, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::LineGapWidth, properties.gap_width, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::LineBlur, properties.blur, parameters);
|
||||
applyStyleProperty(PropertyKey::LineDashArray, properties.dash_array, parameters);
|
||||
applyStyleProperty(PropertyKey::LineImage, properties.image, parameters);
|
||||
void LineLayer::recalculate(const StyleCalculationParameters& parameters) {
|
||||
paints.removeExpiredTransitions(parameters.now);
|
||||
|
||||
paints.calculateTransitioned(PropertyKey::LineOpacity, properties.opacity, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::LineColor, properties.color, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::LineTranslate, properties.translate, parameters);
|
||||
paints.calculate(PropertyKey::LineTranslateAnchor, properties.translateAnchor, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::LineWidth, properties.width, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::LineGapWidth, properties.gap_width, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::LineBlur, properties.blur, parameters);
|
||||
paints.calculate(PropertyKey::LineDashArray, properties.dash_array, parameters);
|
||||
paints.calculate(PropertyKey::LineImage, properties.image, parameters);
|
||||
|
||||
// for scaling dasharrays
|
||||
StyleCalculationParameters dashArrayParams = parameters;
|
||||
dashArrayParams.z = std::floor(dashArrayParams.z);
|
||||
applyStyleProperty(PropertyKey::LineWidth, properties.dash_line_width, dashArrayParams);
|
||||
paints.calculate(PropertyKey::LineWidth, properties.dash_line_width, dashArrayParams);
|
||||
|
||||
return properties.isVisible() ? RenderPass::Translucent : RenderPass::None;
|
||||
passes = properties.isVisible() ? RenderPass::Translucent : RenderPass::None;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace mbgl {
|
||||
|
||||
class LineLayer : public StyleLayer {
|
||||
public:
|
||||
RenderPass applyStyleProperties(const StyleCalculationParameters&) override;
|
||||
void recalculate(const StyleCalculationParameters&) override;
|
||||
|
||||
LinePaintProperties properties;
|
||||
};
|
||||
|
||||
@@ -2,15 +2,18 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
RenderPass RasterLayer::applyStyleProperties(const StyleCalculationParameters& parameters) {
|
||||
applyTransitionedStyleProperty(PropertyKey::RasterOpacity, properties.opacity, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::RasterHueRotate, properties.hue_rotate, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::RasterBrightnessLow, properties.brightness[0], parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::RasterBrightnessHigh, properties.brightness[1], parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::RasterSaturation, properties.saturation, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::RasterContrast, properties.contrast, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::RasterFade, properties.fade, parameters);
|
||||
return properties.isVisible() ? RenderPass::Translucent : RenderPass::None;
|
||||
void RasterLayer::recalculate(const StyleCalculationParameters& parameters) {
|
||||
paints.removeExpiredTransitions(parameters.now);
|
||||
|
||||
paints.calculateTransitioned(PropertyKey::RasterOpacity, properties.opacity, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::RasterHueRotate, properties.hue_rotate, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::RasterBrightnessLow, properties.brightness[0], parameters);
|
||||
paints.calculateTransitioned(PropertyKey::RasterBrightnessHigh, properties.brightness[1], parameters);
|
||||
paints.calculateTransitioned(PropertyKey::RasterSaturation, properties.saturation, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::RasterContrast, properties.contrast, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::RasterFade, properties.fade, parameters);
|
||||
|
||||
passes = properties.isVisible() ? RenderPass::Translucent : RenderPass::None;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace mbgl {
|
||||
|
||||
class RasterLayer : public StyleLayer {
|
||||
public:
|
||||
RenderPass applyStyleProperties(const StyleCalculationParameters&) override;
|
||||
void recalculate(const StyleCalculationParameters&) override;
|
||||
|
||||
RasterPaintProperties properties;
|
||||
};
|
||||
|
||||
@@ -4,22 +4,24 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
RenderPass SymbolLayer::applyStyleProperties(const StyleCalculationParameters& parameters) {
|
||||
applyTransitionedStyleProperty(PropertyKey::IconOpacity, properties.icon.opacity, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::IconColor, properties.icon.color, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::IconHaloColor, properties.icon.halo_color, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::IconHaloWidth, properties.icon.halo_width, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::IconHaloBlur, properties.icon.halo_blur, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::IconTranslate, properties.icon.translate, parameters);
|
||||
applyStyleProperty(PropertyKey::IconTranslateAnchor, properties.icon.translate_anchor, parameters);
|
||||
void SymbolLayer::recalculate(const StyleCalculationParameters& parameters) {
|
||||
paints.removeExpiredTransitions(parameters.now);
|
||||
|
||||
applyTransitionedStyleProperty(PropertyKey::TextOpacity, properties.text.opacity, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::TextColor, properties.text.color, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::TextHaloColor, properties.text.halo_color, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::TextHaloWidth, properties.text.halo_width, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::TextHaloBlur, properties.text.halo_blur, parameters);
|
||||
applyTransitionedStyleProperty(PropertyKey::TextTranslate, properties.text.translate, parameters);
|
||||
applyStyleProperty(PropertyKey::TextTranslateAnchor, properties.text.translate_anchor, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::IconOpacity, properties.icon.opacity, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::IconColor, properties.icon.color, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::IconHaloColor, properties.icon.halo_color, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::IconHaloWidth, properties.icon.halo_width, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::IconHaloBlur, properties.icon.halo_blur, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::IconTranslate, properties.icon.translate, parameters);
|
||||
paints.calculate(PropertyKey::IconTranslateAnchor, properties.icon.translate_anchor, parameters);
|
||||
|
||||
paints.calculateTransitioned(PropertyKey::TextOpacity, properties.text.opacity, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::TextColor, properties.text.color, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::TextHaloColor, properties.text.halo_color, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::TextHaloWidth, properties.text.halo_width, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::TextHaloBlur, properties.text.halo_blur, parameters);
|
||||
paints.calculateTransitioned(PropertyKey::TextTranslate, properties.text.translate, parameters);
|
||||
paints.calculate(PropertyKey::TextTranslateAnchor, properties.text.translate_anchor, parameters);
|
||||
|
||||
// text-size and icon-size are layout properties but they also need to be evaluated as paint properties:
|
||||
auto it = bucket->layout.properties.find(PropertyKey::IconSize);
|
||||
@@ -33,7 +35,7 @@ RenderPass SymbolLayer::applyStyleProperties(const StyleCalculationParameters& p
|
||||
properties.text.size = mapbox::util::apply_visitor(evaluator, it->second);
|
||||
}
|
||||
|
||||
return properties.isVisible() ? RenderPass::Translucent : RenderPass::None;
|
||||
passes = properties.isVisible() ? RenderPass::Translucent : RenderPass::None;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace mbgl {
|
||||
|
||||
class SymbolLayer : public StyleLayer {
|
||||
public:
|
||||
RenderPass applyStyleProperties(const StyleCalculationParameters&) override;
|
||||
void recalculate(const StyleCalculationParameters&) override;
|
||||
|
||||
SymbolPaintProperties properties;
|
||||
};
|
||||
|
||||
114
src/mbgl/style/paint_properties_map.cpp
Normal file
114
src/mbgl/style/paint_properties_map.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
#include <mbgl/style/paint_properties_map.hpp>
|
||||
#include <mbgl/style/property_transition.hpp>
|
||||
#include <mbgl/style/property_fallback.hpp>
|
||||
#include <mbgl/style/class_properties.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
void PaintPropertiesMap::cascade(const std::vector<std::string>& classes,
|
||||
const TimePoint& now,
|
||||
const PropertyTransition& defaultTransition) {
|
||||
// Stores all keys that we have already added transitions for.
|
||||
std::set<PropertyKey> alreadyApplied;
|
||||
|
||||
// We only apply the default style values if there are no classes set.
|
||||
if (classes.empty()) {
|
||||
cascadeClass(ClassID::Default, alreadyApplied, now, defaultTransition);
|
||||
return;
|
||||
}
|
||||
|
||||
// Reverse iterate through all class names and apply them last to first.
|
||||
for (auto it = classes.rbegin(); it != classes.rend(); ++it) {
|
||||
// From here on, we're only dealing with IDs to avoid comparing strings all the time.
|
||||
cascadeClass(ClassDictionary::Get().lookup(*it), alreadyApplied, now, defaultTransition);
|
||||
}
|
||||
|
||||
// As the last class, apply the default class.
|
||||
cascadeClass(ClassID::Default, alreadyApplied, now, defaultTransition);
|
||||
|
||||
// Make sure that we also transition to the fallback value for keys that aren't changed by
|
||||
// any applied classes.
|
||||
for (auto& propertyPair : appliedStyle) {
|
||||
const PropertyKey key = propertyPair.first;
|
||||
if (alreadyApplied.find(key) != alreadyApplied.end()) {
|
||||
// This property has already been set by a previous class, so we don't need to
|
||||
// transition to the fallback.
|
||||
continue;
|
||||
}
|
||||
|
||||
AppliedClassPropertyValues &appliedProperties = propertyPair.second;
|
||||
// Make sure that we don't do double transitions to the fallback value.
|
||||
if (appliedProperties.mostRecent() == ClassID::Fallback) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// This property key hasn't been set by a previous class, so we need to add a transition
|
||||
// to the fallback value for that key.
|
||||
const TimePoint begin = now + *defaultTransition.delay;
|
||||
const TimePoint end = begin + *defaultTransition.duration;
|
||||
const PropertyValue &value = PropertyFallbackValue::Get(key);
|
||||
appliedProperties.add(ClassID::Fallback, begin, end, value);
|
||||
}
|
||||
}
|
||||
|
||||
void PaintPropertiesMap::cascadeClass(const ClassID classID,
|
||||
std::set<PropertyKey>& alreadyApplied,
|
||||
const TimePoint& now,
|
||||
const PropertyTransition& defaultTransition) {
|
||||
auto styleIt = paints.find(classID);
|
||||
if (styleIt == paints.end()) {
|
||||
// There is no class in this layer with this class_name.
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop through all the properties in this style, and add transitions to them, if they're
|
||||
// not already the most recent transition.
|
||||
const ClassProperties& classProperties = styleIt->second;
|
||||
for (const auto& propertyPair : classProperties) {
|
||||
PropertyKey key = propertyPair.first;
|
||||
if (alreadyApplied.find(key) != alreadyApplied.end()) {
|
||||
// This property has already been set by a previous class.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Mark this property as written by a previous class, so that subsequent
|
||||
// classes won't override this.
|
||||
alreadyApplied.insert(key);
|
||||
|
||||
// If the most recent transition is not the one with the highest priority, create
|
||||
// a transition.
|
||||
AppliedClassPropertyValues &appliedProperties = appliedStyle[key];
|
||||
if (appliedProperties.mostRecent() != classID) {
|
||||
PropertyTransition transition = classProperties.getTransition(key);
|
||||
Duration delay = transition.delay ? *transition.delay : *defaultTransition.delay;
|
||||
Duration duration = transition.duration ? *transition.duration : *defaultTransition.duration;
|
||||
const TimePoint begin = now + delay;
|
||||
const TimePoint end = begin + duration;
|
||||
const PropertyValue &value = propertyPair.second;
|
||||
appliedProperties.add(classID, begin, end, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PaintPropertiesMap::hasTransitions() const {
|
||||
for (const auto& pair : appliedStyle) {
|
||||
if (pair.second.hasTransitions()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return hasPendingTransitions;
|
||||
}
|
||||
|
||||
void PaintPropertiesMap::removeExpiredTransitions(const TimePoint& now) {
|
||||
for (auto it = appliedStyle.begin(); it != appliedStyle.end();) {
|
||||
AppliedClassPropertyValues& values = it->second;
|
||||
values.cleanup(now);
|
||||
// If the current properties object is empty, remove it from the map entirely.
|
||||
values.empty() ? appliedStyle.erase(it++) : ++it;
|
||||
}
|
||||
|
||||
// Clear the pending transitions flag upon each update.
|
||||
hasPendingTransitions = false;
|
||||
}
|
||||
|
||||
}
|
||||
89
src/mbgl/style/paint_properties_map.hpp
Normal file
89
src/mbgl/style/paint_properties_map.hpp
Normal file
@@ -0,0 +1,89 @@
|
||||
#ifndef MBGL_PAINT_PROPERTIES_MAP
|
||||
#define MBGL_PAINT_PROPERTIES_MAP
|
||||
|
||||
#include <mbgl/style/applied_class_properties.hpp>
|
||||
#include <mbgl/style/property_evaluator.hpp>
|
||||
#include <mbgl/style/class_dictionary.hpp>
|
||||
#include <mbgl/style/property_key.hpp>
|
||||
|
||||
#include <mbgl/util/interpolate.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class ClassProperties;
|
||||
class PropertyTransition;
|
||||
|
||||
class PaintPropertiesMap {
|
||||
public:
|
||||
void cascade(const std::vector<std::string>& classNames,
|
||||
const TimePoint& now,
|
||||
const PropertyTransition& defaultTransition);
|
||||
|
||||
bool hasTransitions() const;
|
||||
void removeExpiredTransitions(const TimePoint& now);
|
||||
|
||||
template <typename T>
|
||||
void calculate(PropertyKey key, T& target, const StyleCalculationParameters& parameters) {
|
||||
auto it = appliedStyle.find(key);
|
||||
if (it != appliedStyle.end()) {
|
||||
AppliedClassPropertyValues &applied = it->second;
|
||||
// Iterate through all properties that we need to apply in order.
|
||||
const PropertyEvaluator<T> evaluator(parameters);
|
||||
for (auto& property : applied.propertyValues) {
|
||||
if (parameters.now >= property.begin) {
|
||||
// We overwrite the current property with the new value.
|
||||
target = mapbox::util::apply_visitor(evaluator, property.value);
|
||||
} else {
|
||||
// Do not apply this property because its transition hasn't begun yet.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void calculateTransitioned(PropertyKey key, T& target, const StyleCalculationParameters& parameters) {
|
||||
auto it = appliedStyle.find(key);
|
||||
if (it != appliedStyle.end()) {
|
||||
AppliedClassPropertyValues &applied = it->second;
|
||||
// Iterate through all properties that we need to apply in order.
|
||||
const PropertyEvaluator<T> evaluator(parameters);
|
||||
for (auto& property : applied.propertyValues) {
|
||||
if (parameters.now >= property.end) {
|
||||
// We overwrite the current property with the new value.
|
||||
target = mapbox::util::apply_visitor(evaluator, property.value);
|
||||
} else if (parameters.now >= property.begin) {
|
||||
// We overwrite the current property partially with the new value.
|
||||
float progress = std::chrono::duration<float>(parameters.now - property.begin) / (property.end - property.begin);
|
||||
target = util::interpolate(target, mapbox::util::apply_visitor(evaluator, property.value), progress);
|
||||
hasPendingTransitions = true;
|
||||
} else {
|
||||
// Do not apply this property because its transition hasn't begun yet.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Raw parsed paint class to property value map.
|
||||
std::map<ClassID, ClassProperties> paints;
|
||||
|
||||
private:
|
||||
// Applies all properties from a class, if they haven't been applied already.
|
||||
void cascadeClass(const ClassID,
|
||||
std::set<PropertyKey>&,
|
||||
const TimePoint&,
|
||||
const PropertyTransition&);
|
||||
|
||||
// For every property, stores a list of applied property values, with
|
||||
// optional transition times.
|
||||
std::map<PropertyKey, AppliedClassPropertyValues> appliedStyle;
|
||||
|
||||
// Stores whether there are pending transitions to be done on each update.
|
||||
bool hasPendingTransitions = false;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -121,9 +121,9 @@ void Style::update(const TransformState& transform,
|
||||
|
||||
void Style::cascade() {
|
||||
for (const auto& layer : layers) {
|
||||
layer->setClasses(data.getClasses(),
|
||||
data.getAnimationTime(),
|
||||
PropertyTransition { data.getDefaultTransitionDuration(), data.getDefaultTransitionDelay() });
|
||||
layer->cascade(data.getClasses(),
|
||||
data.getAnimationTime(),
|
||||
PropertyTransition { data.getDefaultTransitionDuration(), data.getDefaultTransitionDelay() });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +142,8 @@ void Style::recalculate(float z) {
|
||||
data.getDefaultFadeDuration());
|
||||
|
||||
for (const auto& layer : layers) {
|
||||
layer->updateProperties(parameters);
|
||||
layer->recalculate(parameters);
|
||||
|
||||
if (!layer->bucket) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#include <mbgl/style/style_layer.hpp>
|
||||
#include <mbgl/style/property_fallback.hpp>
|
||||
|
||||
#include <mbgl/layer/fill_layer.hpp>
|
||||
#include <mbgl/layer/line_layer.hpp>
|
||||
#include <mbgl/layer/circle_layer.hpp>
|
||||
@@ -29,122 +27,18 @@ std::unique_ptr<StyleLayer> StyleLayer::create(StyleLayerType type) {
|
||||
}
|
||||
}
|
||||
|
||||
void StyleLayer::cascade(const std::vector<std::string>& classes,
|
||||
const TimePoint& now,
|
||||
const PropertyTransition& defaultTransition) {
|
||||
paints.cascade(classes, now, defaultTransition);
|
||||
}
|
||||
|
||||
bool StyleLayer::hasTransitions() const {
|
||||
return paints.hasTransitions();
|
||||
}
|
||||
|
||||
bool StyleLayer::hasRenderPass(RenderPass pass) const {
|
||||
return bool(passes & pass);
|
||||
}
|
||||
|
||||
void StyleLayer::setClasses(const std::vector<std::string> &class_names, const TimePoint& now,
|
||||
const PropertyTransition &defaultTransition) {
|
||||
// Stores all keys that we have already added transitions for.
|
||||
std::set<PropertyKey> already_applied;
|
||||
|
||||
// We only apply the default style values if there are no classes set.
|
||||
if (class_names.empty()) {
|
||||
applyClassProperties(ClassID::Default, already_applied, now, defaultTransition);
|
||||
return;
|
||||
}
|
||||
|
||||
// Reverse iterate through all class names and apply them last to first.
|
||||
for (auto it = class_names.rbegin(); it != class_names.rend(); ++it) {
|
||||
const std::string &class_name = *it;
|
||||
// From here on, we're only dealing with IDs to avoid comparing strings all the time.
|
||||
const ClassID class_id = ClassDictionary::Get().lookup(class_name);
|
||||
applyClassProperties(class_id, already_applied, now, defaultTransition);
|
||||
}
|
||||
|
||||
// As the last class, apply the default class.
|
||||
applyClassProperties(ClassID::Default, already_applied, now, defaultTransition);
|
||||
|
||||
// Make sure that we also transition to the fallback value for keys that aren't changed by
|
||||
// any applied classes.
|
||||
for (auto& property_pair : appliedStyle) {
|
||||
const PropertyKey key = property_pair.first;
|
||||
if (already_applied.find(key) != already_applied.end()) {
|
||||
// This property has already been set by a previous class, so we don't need to
|
||||
// transition to the fallback.
|
||||
continue;
|
||||
}
|
||||
|
||||
AppliedClassPropertyValues &appliedProperties = property_pair.second;
|
||||
// Make sure that we don't do double transitions to the fallback value.
|
||||
if (appliedProperties.mostRecent() == ClassID::Fallback) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// This property key hasn't been set by a previous class, so we need to add a transition
|
||||
// to the fallback value for that key.
|
||||
const TimePoint begin = now + *defaultTransition.delay;
|
||||
const TimePoint end = begin + *defaultTransition.duration;
|
||||
const PropertyValue &value = PropertyFallbackValue::Get(key);
|
||||
appliedProperties.add(ClassID::Fallback, begin, end, value);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function for applying all properties of a a single class that haven't been applied yet.
|
||||
void StyleLayer::applyClassProperties(const ClassID class_id,
|
||||
std::set<PropertyKey> &already_applied, const TimePoint& now,
|
||||
const PropertyTransition &defaultTransition) {
|
||||
auto style_it = styles.find(class_id);
|
||||
if (style_it == styles.end()) {
|
||||
// There is no class in this layer with this class_name.
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop through all the properties in this style, and add transitions to them, if they're
|
||||
// not already the most recent transition.
|
||||
const ClassProperties &class_properties = style_it->second;
|
||||
for (const auto& property_pair : class_properties) {
|
||||
PropertyKey key = property_pair.first;
|
||||
if (already_applied.find(key) != already_applied.end()) {
|
||||
// This property has already been set by a previous class.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Mark this property as written by a previous class, so that subsequent
|
||||
// classes won't override this.
|
||||
already_applied.insert(key);
|
||||
|
||||
// If the most recent transition is not the one with the highest priority, create
|
||||
// a transition.
|
||||
AppliedClassPropertyValues &appliedProperties = appliedStyle[key];
|
||||
if (appliedProperties.mostRecent() != class_id) {
|
||||
PropertyTransition transition = class_properties.getTransition(key);
|
||||
Duration delay = transition.delay ? *transition.delay : *defaultTransition.delay;
|
||||
Duration duration = transition.duration ? *transition.duration : *defaultTransition.duration;
|
||||
const TimePoint begin = now + delay;
|
||||
const TimePoint end = begin + duration;
|
||||
const PropertyValue &value = property_pair.second;
|
||||
appliedProperties.add(class_id, begin, end, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StyleLayer::updateProperties(const StyleCalculationParameters& parameters) {
|
||||
cleanupAppliedStyleProperties(parameters.now);
|
||||
|
||||
// Clear the pending transitions flag upon each update.
|
||||
hasPendingTransitions = false;
|
||||
|
||||
// Update the render passes when this layer is visible.
|
||||
passes = applyStyleProperties(parameters);
|
||||
}
|
||||
|
||||
bool StyleLayer::hasTransitions() const {
|
||||
for (const auto& pair : appliedStyle) {
|
||||
if (pair.second.hasTransitions()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return hasPendingTransitions;
|
||||
}
|
||||
|
||||
void StyleLayer::cleanupAppliedStyleProperties(const TimePoint& now) {
|
||||
for (auto it = appliedStyle.begin(); it != appliedStyle.end();) {
|
||||
AppliedClassPropertyValues& values = it->second;
|
||||
values.cleanup(now);
|
||||
// If the current properties object is empty, remove it from the map entirely.
|
||||
values.empty() ? appliedStyle.erase(it++) : ++it;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,26 +3,23 @@
|
||||
|
||||
#include <mbgl/style/class_dictionary.hpp>
|
||||
#include <mbgl/style/class_properties.hpp>
|
||||
#include <mbgl/style/applied_class_properties.hpp>
|
||||
#include <mbgl/style/zoom_history.hpp>
|
||||
#include <mbgl/style/property_evaluator.hpp>
|
||||
#include <mbgl/style/style_calculation_parameters.hpp>
|
||||
#include <mbgl/style/paint_properties_map.hpp>
|
||||
|
||||
#include <mbgl/renderer/render_pass.hpp>
|
||||
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
#include <mbgl/util/interpolate.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class StyleBucket;
|
||||
class StyleCalculationParameters;
|
||||
class PropertyTransition;
|
||||
|
||||
class StyleLayer : public util::noncopyable {
|
||||
public:
|
||||
@@ -30,97 +27,35 @@ public:
|
||||
|
||||
virtual ~StyleLayer() = default;
|
||||
|
||||
// Partially evaluate paint properties based on a set of classes.
|
||||
void cascade(const std::vector<std::string>& classNames,
|
||||
const TimePoint& now,
|
||||
const PropertyTransition& defaultTransition);
|
||||
|
||||
// Fully evaluate cascaded paint properties based on a zoom level.
|
||||
virtual void recalculate(const StyleCalculationParameters&) = 0;
|
||||
|
||||
// Checks whether this layer has any active paint properties with transitions.
|
||||
bool hasTransitions() const;
|
||||
|
||||
// Checks whether this layer needs to be rendered in the given render pass.
|
||||
bool hasRenderPass(RenderPass) const;
|
||||
|
||||
// Updates the StyleProperties information in this layer by evaluating all
|
||||
// pending transitions and applied classes in order.
|
||||
void updateProperties(const StyleCalculationParameters&);
|
||||
|
||||
// Sets the list of classes and creates transitions to the currently applied values.
|
||||
void setClasses(const std::vector<std::string> &class_names, const TimePoint& now,
|
||||
const PropertyTransition &defaultTransition);
|
||||
|
||||
bool hasTransitions() const;
|
||||
|
||||
public:
|
||||
// The name of this layer.
|
||||
std::string id;
|
||||
|
||||
StyleLayerType type = StyleLayerType::Unknown;
|
||||
|
||||
// Bucket information, telling the renderer how to generate the geometries
|
||||
// for this layer (feature property filters, tessellation instructions, ...).
|
||||
util::ptr<StyleBucket> bucket;
|
||||
|
||||
// Contains all style classes that can be applied to this layer.
|
||||
std::map<ClassID, ClassProperties> styles;
|
||||
// Contains all paint classes that can be applied to this layer.
|
||||
PaintPropertiesMap paints;
|
||||
|
||||
protected:
|
||||
// TODO: extract
|
||||
template <typename T>
|
||||
void applyStyleProperty(PropertyKey key, T& target, const StyleCalculationParameters& parameters) {
|
||||
auto it = appliedStyle.find(key);
|
||||
if (it != appliedStyle.end()) {
|
||||
AppliedClassPropertyValues &applied = it->second;
|
||||
// Iterate through all properties that we need to apply in order.
|
||||
const PropertyEvaluator<T> evaluator(parameters);
|
||||
for (auto& property : applied.propertyValues) {
|
||||
if (parameters.now >= property.begin) {
|
||||
// We overwrite the current property with the new value.
|
||||
target = mapbox::util::apply_visitor(evaluator, property.value);
|
||||
} else {
|
||||
// Do not apply this property because its transition hasn't begun yet.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void applyTransitionedStyleProperty(PropertyKey key, T& target, const StyleCalculationParameters& parameters) {
|
||||
auto it = appliedStyle.find(key);
|
||||
if (it != appliedStyle.end()) {
|
||||
AppliedClassPropertyValues &applied = it->second;
|
||||
// Iterate through all properties that we need to apply in order.
|
||||
const PropertyEvaluator<T> evaluator(parameters);
|
||||
for (auto& property : applied.propertyValues) {
|
||||
if (parameters.now >= property.end) {
|
||||
// We overwrite the current property with the new value.
|
||||
target = mapbox::util::apply_visitor(evaluator, property.value);
|
||||
} else if (parameters.now >= property.begin) {
|
||||
// We overwrite the current property partially with the new value.
|
||||
float progress = std::chrono::duration<float>(parameters.now - property.begin) / (property.end - property.begin);
|
||||
target = util::interpolate(target, mapbox::util::apply_visitor(evaluator, property.value), progress);
|
||||
hasPendingTransitions = true;
|
||||
} else {
|
||||
// Do not apply this property because its transition hasn't begun yet.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Applies all properties from a class, if they haven't been applied already.
|
||||
void applyClassProperties(ClassID class_id, std::set<PropertyKey> &already_applied,
|
||||
const TimePoint& now, const PropertyTransition &defaultTransition);
|
||||
|
||||
// Sets the properties of this object by evaluating all pending transitions and
|
||||
// aplied classes in order.
|
||||
virtual RenderPass applyStyleProperties(const StyleCalculationParameters&) = 0;
|
||||
|
||||
// Removes all expired style transitions.
|
||||
void cleanupAppliedStyleProperties(const TimePoint& now);
|
||||
|
||||
// For every property, stores a list of applied property values, with
|
||||
// optional transition times.
|
||||
std::map<PropertyKey, AppliedClassPropertyValues> appliedStyle;
|
||||
|
||||
// Stores what render passes this layer is currently enabled for. This depends on the
|
||||
// evaluated StyleProperties object and is updated accordingly.
|
||||
RenderPass passes = RenderPass::None;
|
||||
|
||||
// Stores whether there are pending transitions to be done on each update.
|
||||
bool hasPendingTransitions = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -798,7 +798,7 @@ void StyleParser::parseLayer(const std::string& id, JSVal value, util::ptr<Style
|
||||
|
||||
std::map<ClassID, ClassProperties> paints;
|
||||
parsePaints(value, paints);
|
||||
layer->styles = std::move(paints);
|
||||
layer->paints.paints = std::move(paints);
|
||||
}
|
||||
|
||||
#pragma mark - Parse Styles
|
||||
|
||||
Reference in New Issue
Block a user