diff options
Diffstat (limited to 'src/mbgl/style')
-rw-r--r-- | src/mbgl/style/paint_properties_map.cpp | 114 | ||||
-rw-r--r-- | src/mbgl/style/paint_properties_map.hpp | 89 | ||||
-rw-r--r-- | src/mbgl/style/style.cpp | 9 | ||||
-rw-r--r-- | src/mbgl/style/style_layer.cpp | 120 | ||||
-rw-r--r-- | src/mbgl/style/style_layer.hpp | 97 | ||||
-rw-r--r-- | src/mbgl/style/style_parser.cpp | 2 |
6 files changed, 232 insertions, 199 deletions
diff --git a/src/mbgl/style/paint_properties_map.cpp b/src/mbgl/style/paint_properties_map.cpp new file mode 100644 index 0000000000..18f6867457 --- /dev/null +++ b/src/mbgl/style/paint_properties_map.cpp @@ -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; +} + +} diff --git a/src/mbgl/style/paint_properties_map.hpp b/src/mbgl/style/paint_properties_map.hpp new file mode 100644 index 0000000000..14ed33fe4d --- /dev/null +++ b/src/mbgl/style/paint_properties_map.hpp @@ -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 diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index 84640be259..b68ce496b8 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -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; } diff --git a/src/mbgl/style/style_layer.cpp b/src/mbgl/style/style_layer.cpp index 5b87377608..eab8777d83 100644 --- a/src/mbgl/style/style_layer.cpp +++ b/src/mbgl/style/style_layer.cpp @@ -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) { } } -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); +void StyleLayer::cascade(const std::vector<std::string>& classes, + const TimePoint& now, + const PropertyTransition& defaultTransition) { + paints.cascade(classes, now, defaultTransition); } bool StyleLayer::hasTransitions() const { - for (const auto& pair : appliedStyle) { - if (pair.second.hasTransitions()) { - return true; - } - } - return hasPendingTransitions; + return paints.hasTransitions(); } -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; - } +bool StyleLayer::hasRenderPass(RenderPass pass) const { + return bool(passes & pass); } } diff --git a/src/mbgl/style/style_layer.hpp b/src/mbgl/style/style_layer.hpp index b6ff6ae8f7..43d595bb38 100644 --- a/src/mbgl/style/style_layer.hpp +++ b/src/mbgl/style/style_layer.hpp @@ -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; - // 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&); + // Partially evaluate paint properties based on a set of classes. + void cascade(const std::vector<std::string>& classNames, + const TimePoint& now, + const PropertyTransition& defaultTransition); - // 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); + // 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; + 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; }; } diff --git a/src/mbgl/style/style_parser.cpp b/src/mbgl/style/style_parser.cpp index 391f6b0e21..3aecfa51eb 100644 --- a/src/mbgl/style/style_parser.cpp +++ b/src/mbgl/style/style_parser.cpp @@ -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 |