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 "StarAssets.hpp"
|
||||||
|
#include "StarAssetPath.hpp"
|
||||||
#include "StarFile.hpp"
|
#include "StarFile.hpp"
|
||||||
#include "StarTime.hpp"
|
#include "StarTime.hpp"
|
||||||
#include "StarDirectoryAssetSource.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);
|
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 {
|
Maybe<RectU> FramesSpecification::getRect(String const& frame) const {
|
||||||
if (auto alias = aliases.ptr(frame)) {
|
if (auto alias = aliases.ptr(frame)) {
|
||||||
return frames.get(*alias);
|
return frames.get(*alias);
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "StarBiMap.hpp"
|
#include "StarBiMap.hpp"
|
||||||
#include "StarThread.hpp"
|
#include "StarThread.hpp"
|
||||||
#include "StarAssetSource.hpp"
|
#include "StarAssetSource.hpp"
|
||||||
|
#include "StarAssetPath.hpp"
|
||||||
|
|
||||||
namespace Star {
|
namespace Star {
|
||||||
|
|
||||||
@ -18,61 +19,6 @@ STAR_CLASS(Assets);
|
|||||||
|
|
||||||
STAR_EXCEPTION(AssetException, StarException);
|
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
|
// The contents of an assets .frames file, which can be associated with one or
|
||||||
// more images, and specifies named sub-rects of those images.
|
// more images, and specifies named sub-rects of those images.
|
||||||
struct FramesSpecification {
|
struct FramesSpecification {
|
||||||
|
@ -7,6 +7,7 @@ SET (star_core_HEADERS
|
|||||||
StarAStar.hpp
|
StarAStar.hpp
|
||||||
StarAlgorithm.hpp
|
StarAlgorithm.hpp
|
||||||
StarArray.hpp
|
StarArray.hpp
|
||||||
|
StarAssetPath.hpp
|
||||||
StarAtomicSharedPtr.hpp
|
StarAtomicSharedPtr.hpp
|
||||||
StarAudio.hpp
|
StarAudio.hpp
|
||||||
StarBTree.hpp
|
StarBTree.hpp
|
||||||
@ -23,6 +24,7 @@ SET (star_core_HEADERS
|
|||||||
StarDataStream.hpp
|
StarDataStream.hpp
|
||||||
StarDataStreamDevices.hpp
|
StarDataStreamDevices.hpp
|
||||||
StarDataStreamExtra.hpp
|
StarDataStreamExtra.hpp
|
||||||
|
StarDirectives.hpp
|
||||||
StarDynamicLib.hpp
|
StarDynamicLib.hpp
|
||||||
StarEither.hpp
|
StarEither.hpp
|
||||||
StarEncode.hpp
|
StarEncode.hpp
|
||||||
@ -121,6 +123,7 @@ SET (star_core_HEADERS
|
|||||||
|
|
||||||
SET (star_core_SOURCES
|
SET (star_core_SOURCES
|
||||||
StarAudio.cpp
|
StarAudio.cpp
|
||||||
|
StarAssetPath.cpp
|
||||||
StarBTreeDatabase.cpp
|
StarBTreeDatabase.cpp
|
||||||
StarBuffer.cpp
|
StarBuffer.cpp
|
||||||
StarByteArray.cpp
|
StarByteArray.cpp
|
||||||
@ -128,6 +131,7 @@ SET (star_core_SOURCES
|
|||||||
StarCompression.cpp
|
StarCompression.cpp
|
||||||
StarDataStream.cpp
|
StarDataStream.cpp
|
||||||
StarDataStreamDevices.cpp
|
StarDataStreamDevices.cpp
|
||||||
|
StarDirectives.cpp
|
||||||
StarEncode.cpp
|
StarEncode.cpp
|
||||||
StarFile.cpp
|
StarFile.cpp
|
||||||
StarFont.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
|
StarDamageManager.hpp
|
||||||
StarDamageTypes.hpp
|
StarDamageTypes.hpp
|
||||||
StarDanceDatabase.hpp
|
StarDanceDatabase.hpp
|
||||||
StarDirectives.hpp
|
|
||||||
StarDrawable.hpp
|
StarDrawable.hpp
|
||||||
StarDungeonGenerator.hpp
|
StarDungeonGenerator.hpp
|
||||||
StarDungeonImagePart.hpp
|
StarDungeonImagePart.hpp
|
||||||
@ -297,7 +296,6 @@ SET (star_game_SOURCES
|
|||||||
StarDamageManager.cpp
|
StarDamageManager.cpp
|
||||||
StarDamageTypes.cpp
|
StarDamageTypes.cpp
|
||||||
StarDanceDatabase.cpp
|
StarDanceDatabase.cpp
|
||||||
StarDirectives.cpp
|
|
||||||
StarDrawable.cpp
|
StarDrawable.cpp
|
||||||
StarDungeonGenerator.cpp
|
StarDungeonGenerator.cpp
|
||||||
StarDungeonImagePart.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) {
|
String ImageMetadataDatabase::filterProcessing(String const& path) {
|
||||||
AssetPath components = AssetPath::split(path);
|
AssetPath components = AssetPath::split(path);
|
||||||
|
auto directives = move(components.directives);
|
||||||
|
String joined = AssetPath::join(components);
|
||||||
|
|
||||||
components.directives.filter([](String const& directive) {
|
directives.forEachPair([&](ImageOperation const& operation, String const& string) {
|
||||||
ImageOperation operation;
|
if (!(operation.is<HueShiftImageOperation>() ||
|
||||||
try {
|
operation.is<SaturationShiftImageOperation>() ||
|
||||||
operation = imageOperationFromString(directive);
|
operation.is<BrightnessMultiplyImageOperation>() ||
|
||||||
} catch (StarException const&) {
|
operation.is<FadeToColorImageOperation>() ||
|
||||||
return true;
|
operation.is<ScanLinesImageOperation>() ||
|
||||||
}
|
operation.is<SetColorImageOperation>())) {
|
||||||
|
joined += "?";
|
||||||
return !(operation.is<HueShiftImageOperation>() ||
|
joined += string;
|
||||||
operation.is<SaturationShiftImageOperation>() ||
|
}
|
||||||
operation.is<BrightnessMultiplyImageOperation>() ||
|
});
|
||||||
operation.is<FadeToColorImageOperation>() ||
|
|
||||||
operation.is<ScanLinesImageOperation>() ||
|
|
||||||
operation.is<SetColorImageOperation>());
|
|
||||||
});
|
|
||||||
|
|
||||||
return AssetPath::join(components);
|
return AssetPath::join(components);
|
||||||
}
|
}
|
||||||
@ -231,19 +229,18 @@ Vec2U ImageMetadataDatabase::calculateImageSize(String const& path) const {
|
|||||||
|
|
||||||
OperationSizeAdjust osa(imageSize);
|
OperationSizeAdjust osa(imageSize);
|
||||||
|
|
||||||
for (auto const& directive : components.directives) {
|
bool complete = components.directives.forEachAbortable([&](auto const& leaf) -> bool {
|
||||||
ImageOperation operation;
|
for (const ImageOperation& operation : leaf.operations) {
|
||||||
try {
|
operation.call(osa);
|
||||||
operation = imageOperationFromString(directive);
|
if (osa.hasError())
|
||||||
} catch (StarException const&) {
|
return false;
|
||||||
return fallback();
|
else
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
operation.call(osa);
|
if (!complete)
|
||||||
if (osa.hasError) {
|
return fallback();
|
||||||
return fallback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return imageSize;
|
return imageSize;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user