what the fuck it's 1:30 AM. god
This commit is contained in:
parent
6832c10ed5
commit
2798d4bf66
@ -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<pair<size_t, size_t>> 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<RectU> FramesSpecification::getRect(String const& frame) const {
|
||||
if (auto alias = aliases.ptr(frame)) {
|
||||
return frames.get(*alias);
|
||||
|
@ -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<String> 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 {
|
||||
|
@ -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
|
||||
|
165
source/core/StarAssetPath.cpp
Normal file
165
source/core/StarAssetPath.cpp
Normal file
@ -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<pair<size_t, size_t>> 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;
|
||||
}
|
||||
|
||||
}
|
65
source/core/StarAssetPath.hpp
Normal file
65
source/core/StarAssetPath.hpp
Normal file
@ -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<String> subPath;
|
||||
NestedDirectives directives;
|
||||
|
||||
bool operator==(AssetPath const& rhs) const;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, AssetPath const& rhs);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
154
source/core/StarDirectives.cpp
Normal file
154
source/core/StarDirectives.cpp
Normal file
@ -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<Cell>(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<Cell>(Branches());
|
||||
}
|
||||
else if (m_root->value.is<Branches>())
|
||||
return;
|
||||
|
||||
Leaf& leaf = m_root->value.get<Leaf>();
|
||||
Branches newBranches;
|
||||
newBranches.emplace_back(std::make_shared<Cell const>(move(leaf)));
|
||||
m_root->value = move(newBranches);
|
||||
return m_root->value.get<Branches>();
|
||||
}
|
||||
|
||||
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<Leaf>())
|
||||
for (auto& leafString : leaf->strings) {
|
||||
string += "?";
|
||||
string += leafString;
|
||||
}
|
||||
else {
|
||||
for (auto& branch : value.get<Branches>())
|
||||
branch->buildString(string);
|
||||
}
|
||||
}
|
||||
|
||||
void NestedDirectives::Cell::forEach(LeafCallback& callback) const {
|
||||
if (auto leaf = value.ptr<Leaf>())
|
||||
callback(*leaf);
|
||||
else {
|
||||
for (auto& branch : value.get<Branches>())
|
||||
branch->forEach(callback);
|
||||
}
|
||||
}
|
||||
|
||||
bool NestedDirectives::Cell::forEachAbortable(AbortableLeafCallback& callback) const {
|
||||
if (auto leaf = value.ptr<Leaf>()) {
|
||||
if (!callback(*leaf))
|
||||
return false;
|
||||
} else {
|
||||
for (auto& branch : value.get<Branches>())
|
||||
if (!branch->forEachAbortable(callback))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
78
source/core/StarDirectives.hpp
Normal file
78
source/core/StarDirectives.hpp
Normal file
@ -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<ImageOperation> operations;
|
||||
List<String> strings;
|
||||
|
||||
size_t length() const;
|
||||
};
|
||||
|
||||
typedef function<void(Leaf const&)> LeafCallback;
|
||||
typedef function<void(ImageOperation const&, String const&)> LeafPairCallback;
|
||||
typedef function<bool(Leaf const&)> AbortableLeafCallback;
|
||||
typedef function<bool(ImageOperation const&, String const&)> AbortableLeafPairCallback;
|
||||
|
||||
struct Cell;
|
||||
typedef std::shared_ptr<Cell> Branch;
|
||||
typedef std::shared_ptr<Cell const> ConstBranch;
|
||||
typedef List<ConstBranch> Branches;
|
||||
|
||||
|
||||
struct Cell {
|
||||
Variant<Leaf, Branches> 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
|
@ -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
|
||||
|
@ -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<Branches>().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<Leaf>())
|
||||
string += leaf->string;
|
||||
else {
|
||||
for (auto& branch : cell.value.get<Branches>())
|
||||
buildString(string, *branch);
|
||||
}
|
||||
}
|
||||
|
||||
void NestedDirectives::convertToBranches() {
|
||||
if (m_root.value.is<Branches>())
|
||||
return;
|
||||
|
||||
Leaf& leaf = m_root.value.get<Leaf>();
|
||||
Branches newBranches;
|
||||
newBranches.emplace_back(std::make_shared<Cell const>(move(leaf)));
|
||||
m_root.value = move(newBranches);
|
||||
}
|
||||
|
||||
}
|
@ -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<ImageOperation> operations;
|
||||
String string;
|
||||
};
|
||||
|
||||
struct Cell;
|
||||
typedef std::shared_ptr<Cell const> Branch;
|
||||
typedef List<Branch> Branches;
|
||||
|
||||
struct Cell {
|
||||
Variant<Leaf, Branches> 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
|
@ -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<HueShiftImageOperation>() ||
|
||||
operation.is<SaturationShiftImageOperation>() ||
|
||||
operation.is<BrightnessMultiplyImageOperation>() ||
|
||||
operation.is<FadeToColorImageOperation>() ||
|
||||
operation.is<ScanLinesImageOperation>() ||
|
||||
operation.is<SetColorImageOperation>());
|
||||
});
|
||||
directives.forEachPair([&](ImageOperation const& operation, String const& string) {
|
||||
if (!(operation.is<HueShiftImageOperation>() ||
|
||||
operation.is<SaturationShiftImageOperation>() ||
|
||||
operation.is<BrightnessMultiplyImageOperation>() ||
|
||||
operation.is<FadeToColorImageOperation>() ||
|
||||
operation.is<ScanLinesImageOperation>() ||
|
||||
operation.is<SetColorImageOperation>())) {
|
||||
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user