diff --git a/source/base/StarAssets.cpp b/source/base/StarAssets.cpp index aab4468..d0b77f5 100644 --- a/source/base/StarAssets.cpp +++ b/source/base/StarAssets.cpp @@ -1,4 +1,5 @@ #include "StarAssets.hpp" +#include "StarAssetPath.hpp" #include "StarFile.hpp" #include "StarTime.hpp" #include "StarDirectoryAssetSource.hpp" @@ -59,169 +60,6 @@ static void validatePath(AssetPath const& components, bool canContainSubPath, bo throw AssetException::format("Path '%s' cannot contain directives", components); } -// The filename is everything after the last slash (excluding directives) and -// up to the first directive marker. -static Maybe> findFilenameRange(std::string const& pathUtf8) { - size_t firstDirectiveOrSubPath = pathUtf8.find_first_of(":?"); - size_t filenameStart = 0; - while (true) { - size_t find = pathUtf8.find('/', filenameStart); - if (find >= firstDirectiveOrSubPath) - break; - filenameStart = find + 1; - } - - if (filenameStart == NPos) { - return {}; - } else if (firstDirectiveOrSubPath == NPos) { - return {{filenameStart, pathUtf8.size()}}; - } else { - return {{filenameStart, firstDirectiveOrSubPath}}; - } -} - -AssetPath AssetPath::split(String const& path) { - auto i = path.begin(); - auto end = path.end(); - - AssetPath components; - - // base paths cannot have any ':' or '?' characters, stop at the first one. - while (i != end) { - String::Char c = *i; - if (c == ':' || c == '?') - break; - - components.basePath += c; - ++i; - } - - // Sub-paths must immediately follow base paths and must start with a ':', - // after this point any further ':' characters are not special. - if (i != end && *i == ':') { - ++i; - while (i != end) { - String::Char c = *i; - if (c == '?') - break; - - if (!components.subPath) - components.subPath.emplace(); - - *components.subPath += c; - ++i; - } - } - - // Directives must follow the base path and optional sub-path, and each - // directive is separated by one or more '?' characters. - while (i != end && *i == '?') { - ++i; - String directive; - while (i != end) { - String::Char c = *i; - if (c == '?') - break; - - directive += c; - ++i; - } - if (!directive.empty()) - components.directives.append(move(directive)); - } - - starAssert(i == end); - - return components; -} - -String AssetPath::join(AssetPath const& components) { - return toString(components); -} - -String AssetPath::setSubPath(String const& path, String const& subPath) { - auto components = split(path); - components.subPath = subPath; - return join(components); -} - -String AssetPath::removeSubPath(String const& path) { - auto components = split(path); - components.subPath.reset(); - return join(components); -} - -String AssetPath::getDirectives(String const& path) { - size_t firstDirective = path.find('?'); - if (firstDirective == NPos) - return {}; - return path.substr(firstDirective + 1); -} - -String AssetPath::addDirectives(String const& path, String const& directives) { - return String::joinWith("?", path, directives); -} - -String AssetPath::removeDirectives(String const& path) { - size_t firstDirective = path.find('?'); - if (firstDirective == NPos) - return path; - return path.substr(0, firstDirective); -} - -String AssetPath::directory(String const& path) { - if (auto p = findFilenameRange(path.utf8())) { - return String(path.utf8().substr(0, p->first)); - } else { - return String(); - } -} - -String AssetPath::filename(String const& path) { - if (auto p = findFilenameRange(path.utf8())) { - return String(path.utf8().substr(p->first, p->second)); - } else { - return String(); - } -} - -String AssetPath::extension(String const& path) { - auto file = filename(path); - auto lastDot = file.findLast("."); - if (lastDot == NPos) - return ""; - - return file.substr(lastDot + 1); -} - -String AssetPath::relativeTo(String const& sourcePath, String const& givenPath) { - if (!givenPath.empty() && givenPath[0] == '/') - return givenPath; - - auto path = directory(sourcePath); - path.append(givenPath); - return path; -} - -bool AssetPath::operator==(AssetPath const& rhs) const { - return tie(basePath, subPath, directives) == tie(rhs.basePath, rhs.subPath, rhs.directives); -} - -std::ostream& operator<<(std::ostream& os, AssetPath const& rhs) { - os << rhs.basePath; - if (rhs.subPath) { - os << ":"; - os << *rhs.subPath; - } - - for (auto const& directive : rhs.directives) { - os << "?"; - os << directive; - } - - return os; -} - Maybe FramesSpecification::getRect(String const& frame) const { if (auto alias = aliases.ptr(frame)) { return frames.get(*alias); diff --git a/source/base/StarAssets.hpp b/source/base/StarAssets.hpp index 5c47c9e..f6dc70a 100644 --- a/source/base/StarAssets.hpp +++ b/source/base/StarAssets.hpp @@ -7,6 +7,7 @@ #include "StarBiMap.hpp" #include "StarThread.hpp" #include "StarAssetSource.hpp" +#include "StarAssetPath.hpp" namespace Star { @@ -18,61 +19,6 @@ STAR_CLASS(Assets); STAR_EXCEPTION(AssetException, StarException); -// Asset paths are not filesystem paths. '/' is always the directory separator, -// and it is not possible to escape any asset source directory. '\' is never a -// valid directory separator. All asset paths are considered case-insensitive. -// -// In addition to the path portion of the asset path, some asset types may also -// have a sub-path, which is always separated from the path portion of the asset -// by ':'. There can be at most 1 sub-path component. -// -// Image paths may also have a directives portion of the full asset path, which -// must come after the path and optional sub-path comopnent. The directives -// portion of the path starts with a '?', and '?' separates each subsquent -// directive. -struct AssetPath { - static AssetPath split(String const& path); - static String join(AssetPath const& path); - - // Get / modify sub-path directly on a joined path string - static String setSubPath(String const& joinedPath, String const& subPath); - static String removeSubPath(String const& joinedPath); - - // Get / modify directives directly on a joined path string - static String getDirectives(String const& joinedPath); - static String addDirectives(String const& joinedPath, String const& directives); - static String removeDirectives(String const& joinedPath); - - // The base directory name for any given path, including the trailing '/'. - // Ignores sub-path and directives. - static String directory(String const& path); - - // The file part of any given path, ignoring sub-path and directives. Path - // must be a file not a directory. - static String filename(String const& path); - - // The file extension of a given file path, ignoring directives and - // sub-paths. - static String extension(String const& path); - - // Computes an absolute asset path from a relative path relative to another - // asset. The sourcePath must be an absolute path (may point to a directory - // or an asset in a directory, and ignores ':' sub-path or ? directives), - // and the givenPath may be either an absolute *or* a relative path. If it - // is an absolute path, it is returned unchanged. If it is a relative path, - // then it is computed as relative to the directory component of the - // sourcePath. - static String relativeTo(String const& sourcePath, String const& givenPath); - - String basePath; - Maybe subPath; - StringList directives; - - bool operator==(AssetPath const& rhs) const; -}; - -std::ostream& operator<<(std::ostream& os, AssetPath const& rhs); - // The contents of an assets .frames file, which can be associated with one or // more images, and specifies named sub-rects of those images. struct FramesSpecification { diff --git a/source/core/CMakeLists.txt b/source/core/CMakeLists.txt index d0a53b1..6668109 100644 --- a/source/core/CMakeLists.txt +++ b/source/core/CMakeLists.txt @@ -7,6 +7,7 @@ SET (star_core_HEADERS StarAStar.hpp StarAlgorithm.hpp StarArray.hpp + StarAssetPath.hpp StarAtomicSharedPtr.hpp StarAudio.hpp StarBTree.hpp @@ -23,6 +24,7 @@ SET (star_core_HEADERS StarDataStream.hpp StarDataStreamDevices.hpp StarDataStreamExtra.hpp + StarDirectives.hpp StarDynamicLib.hpp StarEither.hpp StarEncode.hpp @@ -121,6 +123,7 @@ SET (star_core_HEADERS SET (star_core_SOURCES StarAudio.cpp + StarAssetPath.cpp StarBTreeDatabase.cpp StarBuffer.cpp StarByteArray.cpp @@ -128,6 +131,7 @@ SET (star_core_SOURCES StarCompression.cpp StarDataStream.cpp StarDataStreamDevices.cpp + StarDirectives.cpp StarEncode.cpp StarFile.cpp StarFont.cpp diff --git a/source/core/StarAssetPath.cpp b/source/core/StarAssetPath.cpp new file mode 100644 index 0000000..3a6a83e --- /dev/null +++ b/source/core/StarAssetPath.cpp @@ -0,0 +1,165 @@ +#include "StarAssetPath.hpp" +#include "StarLexicalCast.hpp" + +namespace Star { + +// The filename is everything after the last slash (excluding directives) and +// up to the first directive marker. +static Maybe> findFilenameRange(std::string const& pathUtf8) { + size_t firstDirectiveOrSubPath = pathUtf8.find_first_of(":?"); + size_t filenameStart = 0; + while (true) { + size_t find = pathUtf8.find('/', filenameStart); + if (find >= firstDirectiveOrSubPath) + break; + filenameStart = find + 1; + } + + if (filenameStart == NPos) { + return {}; + } else if (firstDirectiveOrSubPath == NPos) { + return {{filenameStart, pathUtf8.size()}}; + } else { + return {{filenameStart, firstDirectiveOrSubPath}}; + } +} + +AssetPath AssetPath::split(String const& path) { + auto i = path.begin(); + auto end = path.end(); + + AssetPath components; + + // base paths cannot have any ':' or '?' characters, stop at the first one. + while (i != end) { + String::Char c = *i; + if (c == ':' || c == '?') + break; + + components.basePath += c; + ++i; + } + + // Sub-paths must immediately follow base paths and must start with a ':', + // after this point any further ':' characters are not special. + if (i != end && *i == ':') { + ++i; + while (i != end) { + String::Char c = *i; + if (c == '?') + break; + + if (!components.subPath) + components.subPath.emplace(); + + *components.subPath += c; + ++i; + } + } + + // Directives must follow the base path and optional sub-path, and each + // directive is separated by one or more '?' characters. + while (i != end && *i == '?') { + String directives; + while (i != end) { + directives.append(*i); + ++i; + } + + if (!directives.empty()); + components.directives.append(move(directives)); + } + + starAssert(i == end); + + return components; +} + +String AssetPath::join(AssetPath const& components) { + return toString(components); +} + +String AssetPath::setSubPath(String const& path, String const& subPath) { + auto components = split(path); + components.subPath = subPath; + return join(components); +} + +String AssetPath::removeSubPath(String const& path) { + auto components = split(path); + components.subPath.reset(); + return join(components); +} + +String AssetPath::getDirectives(String const& path) { + size_t firstDirective = path.find('?'); + if (firstDirective == NPos) + return {}; + return path.substr(firstDirective + 1); +} + +String AssetPath::addDirectives(String const& path, String const& directives) { + return String::joinWith("?", path, directives); +} + +String AssetPath::removeDirectives(String const& path) { + size_t firstDirective = path.find('?'); + if (firstDirective == NPos) + return path; + return path.substr(0, firstDirective); +} + +String AssetPath::directory(String const& path) { + if (auto p = findFilenameRange(path.utf8())) { + return String(path.utf8().substr(0, p->first)); + } else { + return String(); + } +} + +String AssetPath::filename(String const& path) { + if (auto p = findFilenameRange(path.utf8())) { + return String(path.utf8().substr(p->first, p->second)); + } else { + return String(); + } +} + +String AssetPath::extension(String const& path) { + auto file = filename(path); + auto lastDot = file.findLast("."); + if (lastDot == NPos) + return ""; + + return file.substr(lastDot + 1); +} + +String AssetPath::relativeTo(String const& sourcePath, String const& givenPath) { + if (!givenPath.empty() && givenPath[0] == '/') + return givenPath; + + auto path = directory(sourcePath); + path.append(givenPath); + return path; +} + +bool AssetPath::operator==(AssetPath const& rhs) const { + return tie(basePath, subPath, directives) == tie(rhs.basePath, rhs.subPath, rhs.directives); +} + +std::ostream& operator<<(std::ostream& os, AssetPath const& rhs) { + os << rhs.basePath; + if (rhs.subPath) { + os << ":"; + os << *rhs.subPath; + } + + rhs.directives.forEach([&](ImageOperation const& operation, String const& string) { + os << "?"; + os << string; + }); + + return os; +} + +} diff --git a/source/core/StarAssetPath.hpp b/source/core/StarAssetPath.hpp new file mode 100644 index 0000000..e51acee --- /dev/null +++ b/source/core/StarAssetPath.hpp @@ -0,0 +1,65 @@ +#ifndef STAR_ASSET_PATH_HPP +#define STAR_ASSET_PATH_HPP + +#include "StarDirectives.hpp" + +namespace Star { + +// Asset paths are not filesystem paths. '/' is always the directory separator, +// and it is not possible to escape any asset source directory. '\' is never a +// valid directory separator. All asset paths are considered case-insensitive. +// +// In addition to the path portion of the asset path, some asset types may also +// have a sub-path, which is always separated from the path portion of the asset +// by ':'. There can be at most 1 sub-path component. +// +// Image paths may also have a directives portion of the full asset path, which +// must come after the path and optional sub-path comopnent. The directives +// portion of the path starts with a '?', and '?' separates each subsquent +// directive. +struct AssetPath { + static AssetPath split(String const& path); + static String join(AssetPath const& path); + + // Get / modify sub-path directly on a joined path string + static String setSubPath(String const& joinedPath, String const& subPath); + static String removeSubPath(String const& joinedPath); + + // Get / modify directives directly on a joined path string + static String getDirectives(String const& joinedPath); + static String addDirectives(String const& joinedPath, String const& directives); + static String removeDirectives(String const& joinedPath); + + // The base directory name for any given path, including the trailing '/'. + // Ignores sub-path and directives. + static String directory(String const& path); + + // The file part of any given path, ignoring sub-path and directives. Path + // must be a file not a directory. + static String filename(String const& path); + + // The file extension of a given file path, ignoring directives and + // sub-paths. + static String extension(String const& path); + + // Computes an absolute asset path from a relative path relative to another + // asset. The sourcePath must be an absolute path (may point to a directory + // or an asset in a directory, and ignores ':' sub-path or ? directives), + // and the givenPath may be either an absolute *or* a relative path. If it + // is an absolute path, it is returned unchanged. If it is a relative path, + // then it is computed as relative to the directory component of the + // sourcePath. + static String relativeTo(String const& sourcePath, String const& givenPath); + + String basePath; + Maybe subPath; + NestedDirectives directives; + + bool operator==(AssetPath const& rhs) const; +}; + +std::ostream& operator<<(std::ostream& os, AssetPath const& rhs); + +} + +#endif \ No newline at end of file diff --git a/source/core/StarDirectives.cpp b/source/core/StarDirectives.cpp new file mode 100644 index 0000000..62a2a49 --- /dev/null +++ b/source/core/StarDirectives.cpp @@ -0,0 +1,154 @@ +#include "StarImage.hpp" +#include "StarImageProcessing.hpp" +#include "StarDirectives.hpp" + +namespace Star { + +NestedDirectives::NestedDirectives() : m_root(nullptr) {} +NestedDirectives::NestedDirectives(String const& directives) { + parseDirectivesIntoLeaf(directives); +} +NestedDirectives::NestedDirectives(String&& directives) { + String mine = move(directives); // most useless move constructor in the world + parseDirectivesIntoLeaf(mine); +} + +void NestedDirectives::parseDirectivesIntoLeaf(String const& directives) { + Leaf leaf; + for (String& op : directives.split('?')) { + if (!op.empty()) { + leaf.operations.append(imageOperationFromString(op)); + leaf.strings.append(move(op)); + } + } + m_root = std::make_shared(move(leaf)); +} + +bool NestedDirectives::empty() const { + return (bool)m_root; +} + +void NestedDirectives::append(const NestedDirectives& other) { + convertToBranches().emplace_back(other.branch()); +} + +String NestedDirectives::toString() const { + String string; + addToString(string); + return string; +} + +void NestedDirectives::addToString(String& string) const { + if (m_root) + m_root->buildString(string); +} + +void NestedDirectives::forEach(LeafCallback callback) const { + if (m_root) + m_root->forEach(callback); +} + +void NestedDirectives::forEachPair(LeafPairCallback callback) const { + if (m_root) { + LeafCallback pairCallback = [&](Leaf const& leaf) { + size_t length = leaf.length(); + for (size_t i = 0; i != length; ++i) + callback(leaf.operations.at(i), leaf.strings.at(i)); + }; + m_root->forEach(pairCallback); + } +} + +bool NestedDirectives::forEachAbortable(AbortableLeafCallback callback) const { + if (!m_root) + return false; + else + return m_root->forEachAbortable(callback); +} + +bool NestedDirectives::forEachPairAbortable(AbortableLeafPairCallback callback) const { + if (!m_root) + return false; + else { + AbortableLeafCallback pairCallback = [&](Leaf const& leaf) -> bool { + size_t length = leaf.length(); + for (size_t i = 0; i != length; ++i) { + if (!callback(leaf.operations.at(i), leaf.strings.at(i))) + return false; + } + + return true; + }; + return m_root->forEachAbortable(pairCallback); + } +} + +Image NestedDirectives::apply(Image& image) const { + Image current = image; + forEach([&](Leaf const& leaf) { + current = processImageOperations(leaf.operations, current); + }); + return current; +} + +NestedDirectives::Branches& NestedDirectives::convertToBranches() { + if (!m_root) { + m_root = std::make_shared(Branches()); + } + else if (m_root->value.is()) + return; + + Leaf& leaf = m_root->value.get(); + Branches newBranches; + newBranches.emplace_back(std::make_shared(move(leaf))); + m_root->value = move(newBranches); + return m_root->value.get(); +} + +size_t NestedDirectives::Leaf::length() const { + if (operations.size() != strings.size()) + throw DirectivesException("NestedDirectives leaf has mismatching operation/string List sizes"); + + return operations.size(); +} + +NestedDirectives::Cell::Cell() : value(Leaf()) {}; +NestedDirectives::Cell::Cell(Leaf&& leaf) : value(move(leaf)) {}; +NestedDirectives::Cell::Cell(Branches&& branches) : value(move(branches)) {}; +NestedDirectives::Cell::Cell(const Leaf& leaf) : value(leaf) {}; +NestedDirectives::Cell::Cell(const Branches& branches) : value(branches) {}; + +void NestedDirectives::Cell::buildString(String& string) const { + if (auto leaf = value.ptr()) + for (auto& leafString : leaf->strings) { + string += "?"; + string += leafString; + } + else { + for (auto& branch : value.get()) + branch->buildString(string); + } +} + +void NestedDirectives::Cell::forEach(LeafCallback& callback) const { + if (auto leaf = value.ptr()) + callback(*leaf); + else { + for (auto& branch : value.get()) + branch->forEach(callback); + } +} + +bool NestedDirectives::Cell::forEachAbortable(AbortableLeafCallback& callback) const { + if (auto leaf = value.ptr()) { + if (!callback(*leaf)) + return false; + } else { + for (auto& branch : value.get()) + if (!branch->forEachAbortable(callback)) + return false; + } + return true; +} + +} \ No newline at end of file diff --git a/source/core/StarDirectives.hpp b/source/core/StarDirectives.hpp new file mode 100644 index 0000000..bc5b78d --- /dev/null +++ b/source/core/StarDirectives.hpp @@ -0,0 +1,78 @@ +#ifndef STAR_DIRECTIVES_HPP +#define STAR_DIRECTIVES_HPP + +#include "StarImageProcessing.hpp" + +namespace Star { + +STAR_CLASS(NestedDirectives); +STAR_EXCEPTION(DirectivesException, StarException); + +// Kae: My attempt at reducing memory allocation and per-frame string parsing for extremely long directives +class NestedDirectives { +public: + struct Leaf { + List operations; + List strings; + + size_t length() const; + }; + + typedef function LeafCallback; + typedef function LeafPairCallback; + typedef function AbortableLeafCallback; + typedef function AbortableLeafPairCallback; + + struct Cell; + typedef std::shared_ptr Branch; + typedef std::shared_ptr ConstBranch; + typedef List Branches; + + + struct Cell { + Variant value; + + Cell(); + Cell(Leaf&& leaf); + Cell(Branches&& branches); + Cell(const Leaf& leaf); + Cell(const Branches& branches); + + void buildString(String& string) const; + void forEach(LeafCallback& callback) const; + bool forEachAbortable(AbortableLeafCallback& callback) const; + }; + + + NestedDirectives(); + NestedDirectives(String const& directives); + NestedDirectives(String&& directives); + + void parseDirectivesIntoLeaf(String const& directives); + + bool empty() const; + void append(const NestedDirectives& other); + + const ConstBranch& branch() const; + + String toString() const; + void addToString(String& string) const; + + void forEach(LeafCallback callback) const; + void forEachPair(LeafPairCallback callback) const; + bool forEachAbortable(AbortableLeafCallback callback) const; + bool forEachPairAbortable(AbortableLeafPairCallback callback) const; + + Image apply(Image& image) const; +private: + void buildString(String& string, const Cell& cell) const; + Branches& convertToBranches(); + + Branch m_root; +}; + +typedef NestedDirectives ImageDirectives; + +} + +#endif diff --git a/source/game/CMakeLists.txt b/source/game/CMakeLists.txt index c7399b1..1ff95ff 100644 --- a/source/game/CMakeLists.txt +++ b/source/game/CMakeLists.txt @@ -38,7 +38,6 @@ SET (star_game_HEADERS StarDamageManager.hpp StarDamageTypes.hpp StarDanceDatabase.hpp - StarDirectives.hpp StarDrawable.hpp StarDungeonGenerator.hpp StarDungeonImagePart.hpp @@ -297,7 +296,6 @@ SET (star_game_SOURCES StarDamageManager.cpp StarDamageTypes.cpp StarDanceDatabase.cpp - StarDirectives.cpp StarDrawable.cpp StarDungeonGenerator.cpp StarDungeonImagePart.cpp diff --git a/source/game/StarDirectives.cpp b/source/game/StarDirectives.cpp deleted file mode 100644 index 4dc661d..0000000 --- a/source/game/StarDirectives.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "StarImage.hpp" -#include "StarImageProcessing.hpp" -#include "StarDirectives.hpp" - -namespace Star { - -NestedDirectives::NestedDirectives() {} -NestedDirectives::NestedDirectives(String const& string) : m_root{ Leaf{ parseImageOperations(string), string} } {} - -void NestedDirectives::addBranch(const Branch& newBranch) { - convertToBranches(); - - m_root.value.get().emplace_back(newBranch); -} - -String NestedDirectives::toString() const { - String string; - buildString(string, m_root); - return string; -} - -void NestedDirectives::forEach() const { - -} - -Image NestedDirectives::apply(Image& image) const { - Image current = image; - - return current; -} - -void NestedDirectives::buildString(String& string, const Cell& cell) const { - if (auto leaf = cell.value.ptr()) - string += leaf->string; - else { - for (auto& branch : cell.value.get()) - buildString(string, *branch); - } -} - -void NestedDirectives::convertToBranches() { - if (m_root.value.is()) - return; - - Leaf& leaf = m_root.value.get(); - Branches newBranches; - newBranches.emplace_back(std::make_shared(move(leaf))); - m_root.value = move(newBranches); -} - -} \ No newline at end of file diff --git a/source/game/StarDirectives.hpp b/source/game/StarDirectives.hpp deleted file mode 100644 index 3540ee1..0000000 --- a/source/game/StarDirectives.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef STAR_DIRECTIVES_HPP -#define STAR_DIRECTIVES_HPP - -#include "StarImageProcessing.hpp" - -namespace Star { - -STAR_CLASS(NestedDirectives); - -// Attempt at reducing memory allocation and per-frame string parsing for extremely long directives -class NestedDirectives { -public: - struct Leaf { - List operations; - String string; - }; - - struct Cell; - typedef std::shared_ptr Branch; - typedef List Branches; - - struct Cell { - Variant value; - - Cell() : value(Leaf()) {}; - Cell(Leaf&& leaf) : value(move(leaf)) {}; - Cell(Branches&& branches) : value(move(branches)) {}; - Cell(const Leaf& leaf) : value(leaf) {}; - Cell(const Branches& branches) : value(branches) {}; - }; - - - NestedDirectives(); - NestedDirectives(String const& string); - - void addBranch(const Branch& newBranch); - const Branch& branch() const; - String toString() const; - void forEach() const; - Image apply(Image& image) const; -private: - void buildString(String& string, const Cell& cell) const; - void convertToBranches(); - - Cell m_root; -}; - -} - -#endif diff --git a/source/game/StarImageMetadataDatabase.cpp b/source/game/StarImageMetadataDatabase.cpp index 613ed1a..1e5c147 100644 --- a/source/game/StarImageMetadataDatabase.cpp +++ b/source/game/StarImageMetadataDatabase.cpp @@ -119,22 +119,20 @@ RectU ImageMetadataDatabase::nonEmptyRegion(String const& path) const { String ImageMetadataDatabase::filterProcessing(String const& path) { AssetPath components = AssetPath::split(path); + auto directives = move(components.directives); + String joined = AssetPath::join(components); - components.directives.filter([](String const& directive) { - ImageOperation operation; - try { - operation = imageOperationFromString(directive); - } catch (StarException const&) { - return true; - } - - return !(operation.is() || - operation.is() || - operation.is() || - operation.is() || - operation.is() || - operation.is()); - }); + directives.forEachPair([&](ImageOperation const& operation, String const& string) { + if (!(operation.is() || + operation.is() || + operation.is() || + operation.is() || + operation.is() || + operation.is())) { + joined += "?"; + joined += string; + } + }); return AssetPath::join(components); } @@ -231,19 +229,18 @@ Vec2U ImageMetadataDatabase::calculateImageSize(String const& path) const { OperationSizeAdjust osa(imageSize); - for (auto const& directive : components.directives) { - ImageOperation operation; - try { - operation = imageOperationFromString(directive); - } catch (StarException const&) { - return fallback(); + bool complete = components.directives.forEachAbortable([&](auto const& leaf) -> bool { + for (const ImageOperation& operation : leaf.operations) { + operation.call(osa); + if (osa.hasError()) + return false; + else + return true; } + }); - operation.call(osa); - if (osa.hasError) { - return fallback(); - } - } + if (!complete) + return fallback(); return imageSize; }