diff options
author | Kae <80987908+Novaenia@users.noreply.github.com> | 2024-04-23 11:48:51 +1000 |
---|---|---|
committer | Kae <80987908+Novaenia@users.noreply.github.com> | 2024-04-23 11:48:51 +1000 |
commit | 7136c929cea0ddf955ab69a8ff5a4394bedacea8 (patch) | |
tree | d17322f98b5614eadeb086dae70d6fbd81d84934 | |
parent | ed3793ab004e1c6d21225f34c8369d12f6525334 (diff) |
micro-opt NetworkedAnimator drawables
sort before creating drawables
-rw-r--r-- | source/base/StarAnimatedPartSet.cpp | 10 | ||||
-rw-r--r-- | source/base/StarAnimatedPartSet.hpp | 85 | ||||
-rw-r--r-- | source/game/StarNetworkedAnimator.cpp | 174 | ||||
-rw-r--r-- | source/game/StarNetworkedAnimator.hpp | 4 | ||||
-rw-r--r-- | source/game/items/StarActiveItem.cpp | 2 |
5 files changed, 155 insertions, 120 deletions
diff --git a/source/base/StarAnimatedPartSet.cpp b/source/base/StarAnimatedPartSet.cpp index 9133921..5ffc68f 100644 --- a/source/base/StarAnimatedPartSet.cpp +++ b/source/base/StarAnimatedPartSet.cpp @@ -106,7 +106,7 @@ StringList AnimatedPartSet::states(String const& stateTypeName) const { return m_stateTypes.get(stateTypeName).states.keys(); } -StringList AnimatedPartSet::parts() const { +StringList AnimatedPartSet::partNames() const { return m_parts.keys(); } @@ -148,6 +148,14 @@ AnimatedPartSet::ActivePartInformation const& AnimatedPartSet::activePart(String return part.activePart; } +StringMap<AnimatedPartSet::Part> const& AnimatedPartSet::constParts() const { + return m_parts; +} + +StringMap<AnimatedPartSet::Part>& AnimatedPartSet::parts() { + return m_parts; +} + void AnimatedPartSet::forEachActiveState(function<void(String const&, ActiveStateInformation const&)> callback) const { for (auto const& p : m_stateTypes) { const_cast<AnimatedPartSet*>(this)->freshenActiveState(const_cast<StateType&>(p.second)); diff --git a/source/base/StarAnimatedPartSet.hpp b/source/base/StarAnimatedPartSet.hpp index 8cc2ef3..a608924 100644 --- a/source/base/StarAnimatedPartSet.hpp +++ b/source/base/StarAnimatedPartSet.hpp @@ -56,6 +56,46 @@ public: JsonObject properties; }; + enum AnimationMode { + End, + Loop, + Transition + }; + + struct State { + unsigned frames; + float cycle; + AnimationMode animationMode; + String transitionState; + JsonObject stateProperties; + JsonObject stateFrameProperties; + }; + + struct StateType { + float priority; + bool enabled; + String defaultState; + JsonObject stateTypeProperties; + OrderedHashMap<String, shared_ptr<State const>> states; + + ActiveStateInformation activeState; + State const* activeStatePointer; + bool activeStateDirty; + }; + + struct PartState { + JsonObject partStateProperties; + JsonObject partStateFrameProperties; + }; + + struct Part { + JsonObject partProperties; + StringMap<StringMap<PartState>> partStates; + + ActivePartInformation activePart; + bool activePartDirty; + }; + AnimatedPartSet(); AnimatedPartSet(Json config); @@ -71,7 +111,7 @@ public: // Returns the available states for the given state type. StringList states(String const& stateTypeName) const; - StringList parts() const; + StringList partNames() const; // Sets the active state for this state type. If the state is different than // the previously set state, will start the new states animation off at the @@ -86,6 +126,9 @@ public: ActiveStateInformation const& activeState(String const& stateTypeName) const; ActivePartInformation const& activePart(String const& partName) const; + StringMap<Part> const& constParts() const; + StringMap<Part>& parts(); + // Function will be given the name of each state type, and the // ActiveStateInformation for the active state for that state type. void forEachActiveState(function<void(String const&, ActiveStateInformation const&)> callback) const; @@ -108,46 +151,6 @@ public: void finishAnimations(); private: - enum AnimationMode { - End, - Loop, - Transition - }; - - struct State { - unsigned frames; - float cycle; - AnimationMode animationMode; - String transitionState; - JsonObject stateProperties; - JsonObject stateFrameProperties; - }; - - struct StateType { - float priority; - bool enabled; - String defaultState; - JsonObject stateTypeProperties; - OrderedHashMap<String, shared_ptr<State const>> states; - - ActiveStateInformation activeState; - State const* activeStatePointer; - bool activeStateDirty; - }; - - struct PartState { - JsonObject partStateProperties; - JsonObject partStateFrameProperties; - }; - - struct Part { - JsonObject partProperties; - StringMap<StringMap<PartState>> partStates; - - ActivePartInformation activePart; - bool activePartDirty; - }; - static AnimationMode stringToAnimationMode(String const& string); void freshenActiveState(StateType& stateType); diff --git a/source/game/StarNetworkedAnimator.cpp b/source/game/StarNetworkedAnimator.cpp index ccec4fd..a974a3a 100644 --- a/source/game/StarNetworkedAnimator.cpp +++ b/source/game/StarNetworkedAnimator.cpp @@ -307,10 +307,18 @@ String NetworkedAnimator::state(String const& stateType) const { return m_animatedParts.activeState(stateType).stateName; } -StringList NetworkedAnimator::parts() const { +StringMap<AnimatedPartSet::Part> const& NetworkedAnimator::constParts() const { + return m_animatedParts.constParts(); +} + +StringMap<AnimatedPartSet::Part>& NetworkedAnimator::parts() { return m_animatedParts.parts(); } +StringList NetworkedAnimator::partNames() const { + return m_animatedParts.partNames(); +} + Json NetworkedAnimator::stateProperty(String const& stateType, String const& propertyName) const { return m_animatedParts.activeState(stateType).properties.value(propertyName); } @@ -573,6 +581,10 @@ List<Drawable> NetworkedAnimator::drawables(Vec2F const& position) const { } List<pair<Drawable, float>> NetworkedAnimator::drawablesWithZLevel(Vec2F const& position) const { + size_t partCount = m_animatedParts.constParts().size(); + if (!partCount) + return {}; + List<Directives> baseProcessingDirectives = { m_processingDirectives.get() }; for (auto& pair : m_effects) { auto const& effectState = pair.second; @@ -591,93 +603,103 @@ List<pair<Drawable, float>> NetworkedAnimator::drawablesWithZLevel(Vec2F const& } } - List<pair<Drawable, float>> drawables; - + List<tuple<AnimatedPartSet::ActivePartInformation const*, String const*, float>> parts; + parts.reserve(partCount); m_animatedParts.forEachActivePart([&](String const& partName, AnimatedPartSet::ActivePartInformation const& activePart) { - // Make sure we don't copy the original image - String fallback = ""; - Json jImage = activePart.properties.value("image", {}); - String const& image = jImage.isType(Json::Type::String) ? *jImage.stringPtr() : fallback; + Maybe<float> maybeZLevel; + if (m_flipped.get()) { + if (auto maybeFlipped = activePart.properties.value("flippedZLevel").optFloat()) + maybeZLevel = *maybeFlipped; + } + if (!maybeZLevel) + maybeZLevel = activePart.properties.value("zLevel").optFloat(); - bool centered = activePart.properties.value("centered").optBool().value(true); - bool fullbright = activePart.properties.value("fullbright").optBool().value(false); + parts.append(make_tuple(&activePart, &partName, maybeZLevel.value(0.0f))); + }); - auto maybeZLevel = activePart.properties.value("zLevel").optFloat(); - if (m_flipped.get()) - maybeZLevel = activePart.properties.value("flippedZLevel").optFloat().orMaybe(maybeZLevel); - float zLevel = maybeZLevel.value(0.0f); + sort(parts, [](auto const& a, auto const& b) { return get<2>(a) < get<2>(b); }); + + List<pair<Drawable, float>> drawables; + drawables.reserve(partCount); + for (auto& entry : parts) { + auto& activePart = *get<0>(entry); + auto& partName = *get<1>(entry); + // Make sure we don't copy the original image + String fallback = ""; + Json jImage = activePart.properties.value("image", {}); + String const& image = jImage.isType(Json::Type::String) ? *jImage.stringPtr() : fallback; + + bool centered = activePart.properties.value("centered").optBool().value(true); + bool fullbright = activePart.properties.value("fullbright").optBool().value(false); + + size_t originalDirectivesSize = baseProcessingDirectives.size(); + if (auto directives = activePart.properties.value("processingDirectives").optString()) { + baseProcessingDirectives.append(*directives); + } - size_t originalDirectivesSize = baseProcessingDirectives.size(); - if (auto directives = activePart.properties.value("processingDirectives").optString()) { + Maybe<unsigned> frame; + String frameStr; + String frameIndexStr; + if (activePart.activeState) { + unsigned stateFrame = activePart.activeState->frame; + frame = stateFrame; + frameStr = static_cast<String>(toString(stateFrame + 1)); + frameIndexStr = static_cast<String>(toString(stateFrame)); + + if (auto directives = activePart.activeState->properties.value("processingDirectives").optString()) { baseProcessingDirectives.append(*directives); } + } - Maybe<unsigned> frame; - String frameStr; - String frameIndexStr; - if (activePart.activeState) { - unsigned stateFrame = activePart.activeState->frame; - frame = stateFrame; - frameStr = static_cast<String>(toString(stateFrame + 1)); - frameIndexStr = static_cast<String>(toString(stateFrame)); - - if (auto directives = activePart.activeState->properties.value("processingDirectives").optString()) { - baseProcessingDirectives.append(*directives); - } + auto const& partTags = m_partTags.get(partName); + Maybe<String> processedImage = image.maybeLookupTagsView([&](StringView tag) -> StringView { + if (tag == "frame") { + if (frame) + return frameStr; + } else if (tag == "frameIndex") { + if (frame) + return frameIndexStr; + } else if (auto p = partTags.ptr(tag)) { + return StringView(*p); + } else if (auto p = m_globalTags.ptr(tag)) { + return StringView(*p); } - auto const& partTags = m_partTags.get(partName); - Maybe<String> processedImage = image.maybeLookupTagsView([&](StringView tag) -> StringView { - if (tag == "frame") { - if (frame) - return frameStr; - } else if (tag == "frameIndex") { - if (frame) - return frameIndexStr; - } else if (auto p = partTags.ptr(tag)) { - return StringView(*p); - } else if (auto p = m_globalTags.ptr(tag)) { - return StringView(*p); - } - - return StringView("default"); - }); - String const& usedImage = processedImage ? processedImage.get() : image; - - if (!usedImage.empty() && usedImage[0] != ':' && usedImage[0] != '?') { - size_t hash = hashOf(usedImage); - auto find = m_cachedPartDrawables.find(partName); - bool fail = find == m_cachedPartDrawables.end() || find->second.first != hash; - if (fail) { - String relativeImage; - if (usedImage[0] != '/') - relativeImage = AssetPath::relativeTo(m_relativePath, usedImage); - - Drawable drawable = Drawable::makeImage(!relativeImage.empty() ? relativeImage : usedImage, 1.0f / TilePixels, centered, Vec2F()); - if (find == m_cachedPartDrawables.end()) - find = m_cachedPartDrawables.emplace(partName, std::pair{ hash, std::move(drawable) }).first; - else { - find->second.first = hash; - find->second.second = std::move(drawable); - } + return StringView("default"); + }); + String const& usedImage = processedImage ? processedImage.get() : image; + + if (!usedImage.empty() && usedImage[0] != ':' && usedImage[0] != '?') { + size_t hash = hashOf(usedImage); + auto find = m_cachedPartDrawables.find(partName); + if (find == m_cachedPartDrawables.end() || find->second.first != hash) { + String relativeImage; + if (usedImage[0] != '/') + relativeImage = AssetPath::relativeTo(m_relativePath, usedImage); + + Drawable drawable = Drawable::makeImage(!relativeImage.empty() ? relativeImage : usedImage, 1.0f / TilePixels, centered, Vec2F()); + if (find == m_cachedPartDrawables.end()) + find = m_cachedPartDrawables.emplace(partName, std::pair{ hash, std::move(drawable) }).first; + else { + find->second.first = hash; + find->second.second = std::move(drawable); } + } - Drawable drawable = find->second.second; - auto& imagePart = drawable.imagePart(); - for (Directives const& directives : baseProcessingDirectives) - imagePart.addDirectives(directives, centered); - drawable.transform(partTransformation(partName)); - drawable.transform(globalTransformation()); - drawable.fullbright = fullbright; - drawable.translate(position); + Drawable drawable = find->second.second; + auto& imagePart = drawable.imagePart(); + for (Directives const& directives : baseProcessingDirectives) + imagePart.addDirectives(directives, centered); + drawable.transform(partTransformation(partName)); + drawable.transform(globalTransformation()); + drawable.fullbright = fullbright; + drawable.translate(position); - drawables.append({std::move(drawable), zLevel}); - } + drawables.append({std::move(drawable), get<2>(entry)}); + } - baseProcessingDirectives.resize(originalDirectivesSize); - }); - - sort(drawables, [](auto const& a, auto const& b) { return a.second < b.second; }); + baseProcessingDirectives.resize(originalDirectivesSize); + } return drawables; } @@ -981,7 +1003,7 @@ void NetworkedAnimator::setupNetStates() { addNetElement(&m_globalTags); - for (auto const& part : sorted(m_animatedParts.parts())) + for (auto const& part : sorted(m_animatedParts.partNames())) addNetElement(&m_partTags[part]); for (auto& pair : m_stateInfo) { diff --git a/source/game/StarNetworkedAnimator.hpp b/source/game/StarNetworkedAnimator.hpp index feee8bf..8265011 100644 --- a/source/game/StarNetworkedAnimator.hpp +++ b/source/game/StarNetworkedAnimator.hpp @@ -82,7 +82,9 @@ public: bool setState(String const& stateType, String const& state, bool startNew = false); String state(String const& stateType) const; - StringList parts() const; + StringMap<AnimatedPartSet::Part> const& constParts() const; + StringMap<AnimatedPartSet::Part>& parts(); + StringList partNames() const; // Queries, if it exists, a property value from the underlying // AnimatedPartSet for the given state or part. If the property does not diff --git a/source/game/items/StarActiveItem.cpp b/source/game/items/StarActiveItem.cpp index 102ad16..725ea27 100644 --- a/source/game/items/StarActiveItem.cpp +++ b/source/game/items/StarActiveItem.cpp @@ -251,7 +251,7 @@ Maybe<Direction> ActiveItem::facingDirection() const { } List<Drawable> ActiveItem::handDrawables() const { - if (m_itemAnimator.parts().empty()) { + if (m_itemAnimator.constParts().empty()) { auto drawables = Item::iconDrawables(); Drawable::scaleAll(drawables, 1.0f / TilePixels); return drawables; |